Sunday, September 20, 2009

Copy image of applet to clipboard

Apparently this can only be done if you have a signed applet, because otherwise the Security Manager blocks the call to Clipboard.setContents. There are several steps to getting this to work:

First we add a PopupMenu to the applet's init() method:

popup = new PopupMenu();
popup.add("Copy to clipboard");
popup.addActionListener( new PopupActionListener(this) );
addMouseListener( new RightMouseListener(this) );
add( popup );

Here we create a popup menu with a single entry that says "Copy to Clipboard". There's also a listener for the right mouse button, which for historical reasons is button number 3:

public class RightMouseListener extends MouseAdapter
{
 Monitor applet;
 public RightMouseListener( Monitor applet )
 {
  this.applet = applet;
 }
 public void mouseClicked( MouseEvent e )
 {
  int button = e.getButton();
  if ( button==MouseEvent.BUTTON3 )
  {
   applet.popup.show( this.applet, e.getX(), e.getY() );
  }
 }
}

Pretty simple. This just shows the popup menu whenever the user clicks the right mouse button. Here's the PopupActionListener class, which fires when any item is selected:

public class PopupActionListener implements ActionListener
{
 Monitor applet;
 PopupActionListener( Monitor applet )
 {
  this.applet = applet;
 }
 public void actionPerformed( ActionEvent e )
 {
  BufferedImage image = new BufferedImage( applet.getWidth(), 
   applet.getHeight(), BufferedImage.TYPE_INT_RGB );
  Graphics g = image.getGraphics();
  applet.paint( g );
  Clipboard clipboard =
   Toolkit.getDefaultToolkit().getSystemClipboard();
  ImageSelection imageSelection = new ImageSelection( image );
                clipboard.setContents( imageSelection, null );
 }
 class ImageSelection extends TransferHandler implements Transferable 
 {
  private static final long serialVersionUID = 1L;
  Image image;
  ImageSelection( Image image )
  {
   this.image = image;
  }
  public Object getTransferData( DataFlavor flavor ) 
   throws UnsupportedFlavorException, IOException
  {
   return image;
  }
  public DataFlavor[] getTransferDataFlavors() 
  {
   DataFlavor[] flavors = new DataFlavor[1];
   flavors[0] = DataFlavor.imageFlavor;
   return flavors;
  }
  public boolean isDataFlavorSupported( DataFlavor flavor ) 
  {
   return flavor == DataFlavor.imageFlavor;
  }
 }
}

Here's where it gets slightly interesting. We create a buffered image the same size as the Applet. Then we get the image's Graphics object, and use it to call the Applet's paint method. Then we just call setContents on the system clipboard. The ImageSelection class is required boilerplate. We just subclass TransferHandler.

Now paste the image into a graphics program like GIMP and you have your image. Et voilĂ !

No comments:

Post a Comment