001    /*
002     * Morena 7 - Image Acquisition Framework
003     *
004     * Copyright (c) 1999-2011 Gnome spol. s r.o. All Rights Reserved.
005     *
006     * This software is the confidential and proprietary information of
007     * Gnome spol. s r.o. You shall not disclose such Confidential
008     * Information and shall use it only in accordance with the terms
009     * of the license agreement you entered into with Gnome.
010     */
011    
012    /**
013     *  SimpleExample demonstrates use of the Morena Framework in both
014     *  application and applet environment. Upload action cant be used
015     *  if it is invoked from local filesystem.
016     *  
017     *  Requirements:
018     *  1. Java2 1.5 or newer
019     *  2. Morena7 for image acquisition
020     *  
021     */
022    
023    import java.awt.BorderLayout;
024    import java.awt.Color;
025    import java.awt.Container;
026    import java.awt.Graphics;
027    import java.awt.GridLayout;
028    import java.awt.Insets;
029    import java.awt.event.ActionEvent;
030    import java.awt.event.MouseAdapter;
031    import java.awt.event.MouseEvent;
032    import java.awt.event.WindowAdapter;
033    import java.awt.event.WindowEvent;
034    import java.awt.image.BufferedImage;
035    import java.io.ByteArrayOutputStream;
036    import java.io.File;
037    import java.io.InputStream;
038    import java.io.OutputStream;
039    import java.net.HttpURLConnection;
040    import java.net.URL;
041    import java.util.Date;
042    import java.util.logging.Level;
043    
044    import javax.imageio.ImageIO;
045    import javax.swing.AbstractAction;
046    import javax.swing.JApplet;
047    import javax.swing.JFileChooser;
048    import javax.swing.JFrame;
049    import javax.swing.JOptionPane;
050    import javax.swing.JPanel;
051    import javax.swing.JTextField;
052    import javax.swing.JToolBar;
053    import javax.swing.WindowConstants;
054    import javax.swing.border.LineBorder;
055    import javax.swing.filechooser.FileFilter;
056    
057    import eu.gnome.morena.Configuration;
058    import eu.gnome.morena.Device;
059    import eu.gnome.morena.DeviceListChangeListener;
060    import eu.gnome.morena.Manager;
061    import eu.gnome.morena.Scanner;
062    import eu.gnome.morena.TransferListener;
063    
064    @SuppressWarnings("serial")
065    public class MorenaStudio extends JApplet {
066      static private Manager manager;
067    
068      static {
069        System.err.println("MorenaStudio started at "+(new Date()));
070      }
071      
072      
073      private static class MainPanel extends JPanel implements DeviceListChangeListener {
074    
075        private JTextField status = new JTextField();
076        private ImagePanel selected = null;
077        private SaveImageAction saveImageAction;
078        private CancelAction cancelAction;
079        private UploadImageAction uploadImageAction;
080        private MouseListener mouseListener = new MouseListener();
081        private boolean hasServer = false;
082        private URL documentBase = null;
083        private Scanner scanner = null;
084    
085        
086        private class RemoveAllAction extends AbstractAction implements Runnable {
087          RemoveAllAction() {
088            super("remove all");
089          }
090    
091          public synchronized void actionPerformed(ActionEvent event) {
092            new Thread(this).start();
093          }
094    
095          public synchronized void run() {
096            removeAll();
097            select(null);
098            repaint();
099          }
100        }
101    
102        private class AcquireImageAction extends AbstractAction implements TransferListener {
103          AcquireImageAction() {
104            super("acquire image");
105          }
106    
107          public synchronized void actionPerformed(ActionEvent event) {
108            try {
109              status.setText("Working ...");
110              Device device = manager.selectDevice(MainPanel.this);
111              if (device != null) {
112                if (device instanceof Scanner) {
113                  scanner = (Scanner) device;
114                  if (scanner.setupDevice(MainPanel.this)) {
115                    setEnabled(false);
116                    cancelAction.setEnabled(true);
117                    scanner.startTransfer(this);
118                  }
119                } else {
120                  scanner = null;
121                  device.startTransfer(this);
122                }
123                status.setText("Selected " + device + "  ...");
124              } else
125                status.setText("Failed, try again ...");
126            } catch (Throwable exception) {
127              JOptionPane.showMessageDialog(MainPanel.this, exception.toString(), "Error", JOptionPane.ERROR_MESSAGE);
128              exception.printStackTrace();
129              status.setText("Failed, try again ...");
130              setEnabled(true);
131              cancelAction.setEnabled(false);
132            }
133          }
134    
135          public void transferDone(File file) {
136            try {
137              BufferedImage image = ImageIO.read(file);
138              if (image!=null) {
139                ImagePanel imagePanel = new ImagePanel(image);
140                MainPanel.this.add(imagePanel);
141                select(imagePanel);
142                int size = (int) Math.round(Math.sqrt(getComponentCount()));
143                setLayout(new GridLayout(size, size));
144                status.setText("Done [" + file.getAbsolutePath() + "]...");
145                validate();
146              }
147              else
148                status.setText("Done [" + file.getAbsolutePath() + "] - can not display this image type");
149            } catch (Exception exception) {
150              exception.printStackTrace();
151            }
152            setEnabled(true);
153            cancelAction.setEnabled(false);
154          }
155    
156          public void transferFailed(int code, String message) {
157            status.setText(message + " [0x" + Integer.toHexString(code) + "]");
158            setEnabled(true);
159            cancelAction.setEnabled(false);
160          }
161    
162          public void transferProgress(int percent) {
163            status.setText(percent + "%");
164          }
165        }
166    
167        private class CancelAction extends AbstractAction {
168          CancelAction() {
169            super("cancel");
170            setEnabled(false);
171          }
172    
173          public synchronized void actionPerformed(ActionEvent event) {
174            scanner.cancelTransfer();
175          }
176        }
177    
178        private class SaveImageAction extends AbstractAction implements Runnable {
179          private class Filter extends FileFilter {
180            String type;
181    
182            Filter(String type) {
183              this.type = type;
184            }
185    
186            public boolean accept(File file) {
187              return file.getName().endsWith(type);
188            }
189    
190            public String getDescription() {
191              return type + " Files";
192            }
193          }
194    
195          SaveImageAction() {
196            super("save to file");
197          }
198    
199          public void actionPerformed(ActionEvent event) {
200            new Thread(this).start();
201          }
202    
203          public synchronized void run() {
204            try {
205              status.setText("Working ...");
206              BufferedImage bufferedImage = selected.getImage();
207              JFileChooser chooser = new JFileChooser();
208              String e[] = ImageIO.getWriterFormatNames();
209              for (int i = 0; i < e.length; i++)
210                chooser.addChoosableFileFilter(new Filter(e[i]));
211              int result = chooser.showSaveDialog(MainPanel.this);
212              if (result == JFileChooser.APPROVE_OPTION) {
213                String ext = chooser.getFileFilter().getDescription();
214                ext = ext.substring(0, ext.indexOf(' ')).toLowerCase();
215                File file = chooser.getSelectedFile();
216                String name = file.getName();
217                if (!name.endsWith(ext))
218                  file = new File(file.getParentFile(), name + "." + ext);
219                ImageIO.write(bufferedImage, ext, file);
220                status.setText("Done - image is saved to " + file + "  ...");
221              } else
222                status.setText("Canceled  ...");
223            } catch (Throwable exception) {
224              JOptionPane.showMessageDialog(MainPanel.this, exception.toString(), "Error", JOptionPane.ERROR_MESSAGE);
225              exception.printStackTrace();
226              status.setText("Failed, try again ...");
227            }
228          }
229    
230          public boolean isEnabled() {
231            return selected != null;
232          }
233        }
234    
235        private class UploadImageAction extends AbstractAction implements Runnable {
236          
237          UploadImageAction() {
238            super("upload to server");
239          }
240    
241          public void actionPerformed(ActionEvent event) {
242            new Thread(this).start();
243          }
244    
245          public synchronized void run() {
246            try {
247              status.setText("Working ...");
248              BufferedImage bufferedImage = selected.getImage();
249              ByteArrayOutputStream tmp = new ByteArrayOutputStream();
250              ImageIO.write(bufferedImage, "jpg", tmp);
251              tmp.close();
252              int contentLength = tmp.size();
253              if (contentLength > 1024 * 1024)
254                throw new Exception("Image is too big to upload");
255              URL uploadURL = new URL(documentBase, "upload.php");
256              HttpURLConnection connection = (HttpURLConnection) uploadURL.openConnection();
257              connection.setRequestMethod("POST");
258              connection.setDoOutput(true);
259              connection.setUseCaches(false);
260              connection.setDefaultUseCaches(false);
261              connection.setRequestProperty("content-type", "img/jpeg");
262              connection.setRequestProperty("content-length", String.valueOf(contentLength));
263              OutputStream out = connection.getOutputStream();
264              out.write(tmp.toByteArray());
265              out.close();
266              InputStream in = connection.getInputStream();
267              int c;
268              while ((c = in.read()) != -1)
269                System.err.write(c);
270              in.close();
271              URL imageURL = new URL(documentBase, connection.getHeaderField("file-name"));
272              status.setText("Done - image is uploaded to " + imageURL + " (for at least 5 minutes) ...");
273            } catch (Throwable exception) {
274              JOptionPane.showMessageDialog(MainPanel.this, exception.toString(), "Error", JOptionPane.ERROR_MESSAGE);
275              exception.printStackTrace();
276              status.setText("Failed, try again ...");
277            }
278          }
279    
280          public boolean isEnabled() {
281            return hasServer && selected != null;
282          }
283        }
284    
285        private class MouseListener extends MouseAdapter {
286          public void mouseClicked(MouseEvent event) {
287            select((ImagePanel) event.getComponent());
288          }
289        }
290    
291        private class ImagePanel extends JPanel {
292          private BufferedImage image;
293          int imageWidth;
294          int imageHeight;
295    
296          ImagePanel(BufferedImage image) {
297            this.image = image;
298            imageWidth = image.getWidth();
299            imageHeight = image.getHeight();
300            addMouseListener(mouseListener);
301          }
302    
303          public BufferedImage getImage() {
304            return image;
305          }
306    
307          public void paint(Graphics g) {
308            super.paint(g);
309            int panelWidth = getWidth() - 6;
310            int panelHeight = getHeight() - 6;
311            double horizontalRatio = (double) panelWidth / imageWidth;
312            double verticalRatio = (double) panelHeight / imageHeight;
313            if (horizontalRatio > verticalRatio)
314              g.drawImage(image, (int) (panelWidth - imageWidth * verticalRatio) / 2 + 3, 3, (int) (imageWidth * verticalRatio), (int) (imageHeight * verticalRatio), this);
315            else
316              g.drawImage(image, 3, 3, (int) (imageWidth * horizontalRatio), (int) (imageHeight * horizontalRatio), this);
317          }
318    
319        }
320    
321        private class ToolBar extends JToolBar {
322          ToolBar() {
323    //        List<Device> devices=manager.listDevices();
324    //        add(deviceCombo = new JComboBox<Device>(devices.toArray(new Device[devices.size()])));
325            addSeparator();
326            add(new AcquireImageAction());
327            addSeparator();
328            add(cancelAction = new CancelAction());
329            addSeparator();
330            add(saveImageAction = new SaveImageAction());
331            saveImageAction.setEnabled(false);
332            addSeparator();
333            add(uploadImageAction = new UploadImageAction());
334            uploadImageAction.setEnabled(false);
335            addSeparator();
336            add(new RemoveAllAction());
337            setMargin(new Insets(4, 2, 2, 2));
338          }
339        }
340    
341        void select(ImagePanel image) {
342          if (selected != null)
343            selected.setBorder(null);
344          selected = image;
345          if (selected != null) {
346            selected.setBorder(new LineBorder(Color.blue, 1));
347            saveImageAction.setEnabled(true);
348            uploadImageAction.setEnabled(hasServer);
349          } else {
350            saveImageAction.setEnabled(false);
351            uploadImageAction.setEnabled(false);
352          }
353        }
354    
355        public void listChanged() {
356       // deprecated      
357        }
358    
359    //    @Override
360        public void deviceConnected(Device device) {
361          status.setText("device connected : " + device);
362    //      deviceCombo.addItem(device);
363        }
364    
365    //    @Override
366        public void deviceDisconnected(Device device) {
367          status.setText("device disconnected : " + device);
368    //      deviceCombo.removeItem(device);
369        }
370    
371        MainPanel(Container container, URL documentBase) {
372          this.documentBase = documentBase;
373          status.setEditable(false);
374          hasServer = documentBase != null && documentBase.getProtocol().indexOf("http") != -1;
375          container.add(new ToolBar(), BorderLayout.NORTH);
376          container.add(this, BorderLayout.CENTER);
377          container.add(status, BorderLayout.SOUTH);
378          setLayout(new GridLayout(1, 1));
379          manager.addDeviceListChangeListener(this);
380        }
381    
382      }
383    
384      public void init() {
385        manager = Manager.getInstance();
386        new MainPanel(getContentPane(), getDocumentBase());
387      }
388    
389      @Override
390      public void start() {
391        System.err.println("Morena is available " + manager.available());
392      }
393    
394      @Override
395      public void stop() {
396        manager.close();
397      }
398    
399      public static void main(String args[]) {
400        boolean nativeUI=false;
401        if (args!=null && args.length>0)
402          if (args.length>=1)
403            nativeUI=Boolean.parseBoolean(args[0]);
404        System.err.println("Configuration: native UI - "+nativeUI);
405        JFrame frame = new JFrame("Morena Studio");
406    // -- Configuration settings      
407    //    Configuration.setLogLevel(Level.ALL);
408    //    Configuration.addDeviceType(".*fficejet.*", true);
409        if (nativeUI)
410          Configuration.setMode(Configuration.MODE_NATIVE_UI);
411    
412     // -- Manager instantiation    
413        manager = Manager.getInstance();
414        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
415        frame.addWindowListener(new WindowAdapter()
416        { @Override
417          public void windowClosing(WindowEvent e)
418          { manager.close();
419          } 
420        });
421        new MainPanel(frame.getContentPane(), null);
422        frame.setBounds(100, 100, 600, 400);
423        frame.setVisible(true);
424      }
425    }