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 }