/******************************************************************************* * Copyright (c) 2006-2012 * Software Technology Group, Dresden University of Technology * DevBoost GmbH, Berlin, Amtsgericht Charlottenburg, HRB 140026 * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Software Technology Group - TU Dresden, Germany; * DevBoost GmbH - Berlin, Germany * - initial API and implementation ******************************************************************************/ /** * @(#)PictImageInputFormat.java 1.1 2008-05-24 * * Copyright (c) 2008 by the original authors of JHotDraw * and all its contributors. * All rights reserved. * * The copyright of this software is owned by the authors and * contributors of the JHotDraw project ("the copyright holders"). * You may not use, copy or modify this software, except in * accordance with the license agreement you entered into with * the copyright holders. For details see accompanying license terms. */ package org.jhotdraw.draw; import java.awt.*; import java.awt.datatransfer.*; import java.awt.geom.*; import java.awt.image.*; import java.io.*; import java.lang.reflect.*; import javax.swing.*; import org.jhotdraw.io.*; import org.jhotdraw.util.Images; /** * An input format for importing drawings using the image/x-pict format from the * Mac OS X clipboard. * <p> * This class uses the prototype design pattern. A ImageHolderFigure figure is used * as a prototype for creating a figure that holds the imported image. * <p> * XXX - This class uses the deprecated Cocoa-Java bridge. * * @author Werner Randelshofer * @version 1.1 2008-05-24 Adapted to changes in InputFormat. * <br>1.0 Mar 18, 2008 Created. */ public class PictImageInputFormat implements InputFormat { /** * The prototype for creating a figure that holds the imported image. */ private ImageHolderFigure prototype; /** * Format description used for the file filter. */ private String description; /** * File name extension used for the file filter. */ private String fileExtension; /** * Image IO image format name. */ private String formatName; /** * The image type must match the output format, for example, PNG supports * BufferedImage.TYPE_INT_ARGB whereas GIF needs BufferedImage.TYPE_ */ private int imageType; /** * The image/x-pict data flavor is used by the Mac OS X clipboard. */ public final static DataFlavor PICT_FLAVOR; static { try { PICT_FLAVOR = new DataFlavor("image/x-pict"); } catch (ClassNotFoundException e) { throw new InternalError("Unable to create data flavor image/x-pict"); } } /** Creates a new image output format for Portable Network Graphics PNG. */ public PictImageInputFormat(ImageHolderFigure prototype) { this(prototype, "PICT", "PICT (pct)", "pct", BufferedImage.TYPE_INT_ARGB); } /** Creates a new image output format for the specified image format. * * @param formatName The format name for the javax.imageio.ImageIO object. * @param description The format description to be used for the file filter. * @param fileExtension The file extension to be used for file filter. * @param bufferedImageType The BufferedImage type used to produce the image. * The value of this parameter must match with the format name. */ private PictImageInputFormat(ImageHolderFigure prototype, String formatName, String description, String fileExtension, int bufferedImageType) { this.prototype = prototype; this.formatName = formatName; this.description = description; this.fileExtension = fileExtension; this.imageType = bufferedImageType; } public javax.swing.filechooser.FileFilter getFileFilter() { return new ExtensionFileFilter(description, fileExtension); } public String getFileExtension() { return fileExtension; } public JComponent getInputFormatAccessory() { return null; } public void read(File file, Drawing drawing) throws IOException { read(file, drawing, true); } public void read(File file, Drawing drawing, boolean replace) throws IOException { InputStream in = null; try { in = new BufferedInputStream(new FileInputStream(file)); Image img = getImageFromPictStream(in); if (img == null) { throw new IOException("Couldn't read pict image"); } ImageHolderFigure figure = (ImageHolderFigure) prototype.clone(); figure.setBufferedImage(Images.toBufferedImage(img)); figure.setBounds( new Point2D.Double(0, 0), new Point2D.Double( figure.getBufferedImage().getWidth(), figure.getBufferedImage().getHeight())); if (replace) { drawing.removeAllChildren(); } drawing.basicAdd(figure); } finally { in.close(); } } public void read(InputStream in, Drawing drawing, boolean replace) throws IOException { try { Image img = getImageFromPictStream(in); if (img == null) { throw new IOException("Couldn't read pict image"); } ImageHolderFigure figure = (ImageHolderFigure) prototype.clone(); figure.setBufferedImage(Images.toBufferedImage(img)); figure.setBounds( new Point2D.Double(0, 0), new Point2D.Double( figure.getBufferedImage().getWidth(), figure.getBufferedImage().getHeight())); if (replace) { drawing.removeAllChildren(); } drawing.basicAdd(figure); } finally { in.close(); } } public ImageHolderFigure createImageHolder(InputStream in) throws IOException { ImageHolderFigure figure = (ImageHolderFigure) prototype.clone(); figure.setBufferedImage(Images.toBufferedImage(getImageFromPictStream(in))); figure.setBounds( new Point2D.Double(0, 0), new Point2D.Double( figure.getBufferedImage().getWidth(), figure.getBufferedImage().getHeight())); return figure; } public boolean isDataFlavorSupported(DataFlavor flavor) { return flavor.equals(PICT_FLAVOR); } public void read(Transferable t, Drawing drawing, boolean replace) throws UnsupportedFlavorException, IOException { Object data = t.getTransferData(PICT_FLAVOR); if (data instanceof InputStream) { InputStream in = null; try { in = (InputStream) data; Image img = getImageFromPictStream(in); if (img == null) { throw new IOException("Couldn't read pict image"); } ImageHolderFigure figure = (ImageHolderFigure) prototype.clone(); figure.setBufferedImage(Images.toBufferedImage(img)); figure.setBounds( new Point2D.Double(0, 0), new Point2D.Double( figure.getBufferedImage().getWidth(), figure.getBufferedImage().getHeight())); if (replace) { drawing.removeAllChildren(); } drawing.add(figure); } finally { in.close(); } } } /* * Converts a PICT to an AWT image using QuickTime for Java. * This code was contributed by Gord Peters. * * XXX - This code performs extremly slow. We should replace it by JNI * code which directly accesses the native clipboard. */ @SuppressWarnings("unchecked") private static Image getImageFromPictStream(InputStream is) throws IOException { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); // We need to strip the header from the data because a PICT file // has a 512 byte header and then the data, but in our case we only // need the data. --GP byte[] header = new byte[512]; byte[] buf = new byte[4096]; int retval = 0, size = 0; baos.write(header, 0, 512); while ((retval = is.read(buf, 0, 4096)) > 0) { baos.write(buf, 0, retval); } baos.close(); size = baos.size(); //IJ.log("size: "+size); IJ.wait(2000); if (size <= 0) { return null; } byte[] imgBytes = baos.toByteArray(); // Again with the uglyness. Here we need to use the Quicktime // for Java code in order to create an Image object from // the PICT data we received on the clipboard. However, in // order to get this to compile on other platforms, we use // the Java reflection API. // // For reference, here is the equivalent code without // reflection: // // // if (QTSession.isInitialized() == false) { // QTSession.open(); // } // QTHandle handle= new QTHandle(imgBytes); // GraphicsImporter gi= // new GraphicsImporter(QTUtils.toOSType("PICT")); // gi.setDataHandle(handle); // QDRect qdRect= gi.getNaturalBounds(); // GraphicsImporterDrawer gid= new GraphicsImporterDrawer(gi); // QTImageProducer qip= new QTImageProducer(gid, // new Dimension(qdRect.getWidth(), // qdRect.getHeight())); // return(Toolkit.getDefaultToolkit().createImage(qip)); // // --GP //IJ.log("quicktime.QTSession"); Class c = Class.forName("quicktime.QTSession"); Method m = c.getMethod("isInitialized"); Boolean b = (Boolean) m.invoke(null, (Object[]) null); if (b.booleanValue() == false) { m = c.getMethod("open"); m.invoke(null); } c = Class.forName("quicktime.util.QTHandle"); Constructor con = c.getConstructor(new Class[]{imgBytes.getClass()}); Object handle = con.newInstance(new Object[]{imgBytes}); String s = new String("PICT"); c = Class.forName("quicktime.util.QTUtils"); m = c.getMethod("toOSType", new Class[]{s.getClass()}); Integer type = (Integer) m.invoke(null, new Object[]{s}); c = Class.forName("quicktime.std.image.GraphicsImporter"); con = c.getConstructor(new Class[]{type.TYPE}); Object importer = con.newInstance(new Object[]{type}); m = c.getMethod("setDataHandle", new Class[]{Class.forName("quicktime.util." + "QTHandleRef")}); m.invoke(importer, new Object[]{handle}); m = c.getMethod("getNaturalBounds"); Object rect = m.invoke(importer); c = Class.forName("quicktime.app.view.GraphicsImporterDrawer"); con = c.getConstructor(new Class[]{importer.getClass()}); Object iDrawer = con.newInstance(new Object[]{importer}); m = rect.getClass().getMethod("getWidth"); Integer width = (Integer) m.invoke(rect); m = rect.getClass().getMethod("getHeight"); Integer height = (Integer) m.invoke(rect); Dimension d = new Dimension(width.intValue(), height.intValue()); c = Class.forName("quicktime.app.view.QTImageProducer"); con = c.getConstructor(new Class[]{iDrawer.getClass(), d.getClass()}); Object producer = con.newInstance(new Object[]{iDrawer, d}); if (producer instanceof ImageProducer) { return (Toolkit.getDefaultToolkit().createImage((ImageProducer) producer)); } } catch (Exception e) { IOException error = new IOException("Couldn't read PICT image"); error.initCause(e); throw error; } IOException error = new IOException("Couldn't read PICT image"); throw error; } }