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 }