2

I am developing an Eclipse RCP Application which includes JFreeChart. One of its features is to copy graphs to the clipboard in order to paste them into other applications but it does not work on Linux,

There is a SWT sample where you can find a snippet that does not work in Linux.

On the other hand JFreeChart implemented this on AWT as:

Clipboard systemClipboard
            = Toolkit.getDefaultToolkit().getSystemClipboard();
    Insets insets = getInsets();
    int w = getWidth() - insets.left - insets.right;
    int h = getHeight() - insets.top - insets.bottom;
    ChartTransferable selection = new ChartTransferable(this.chart, w, h,
            getMinimumDrawWidth(), getMinimumDrawHeight(),
            getMaximumDrawWidth(), getMaximumDrawHeight(), true);
    systemClipboard.setContents(selection, null);

Howewer both examples fail on Linux 64bit. Is there a way to implement it??

Thanks in advance!

EDIT:

Code that copy the JFreeChart graphic into a file but not into the Clipboard

final org.eclipse.swt.dnd.Clipboard clipboard = new org.eclipse.swt.dnd.Clipboard(menu.getDisplay());
                    Insets insets = source.getInsets();
                    int w = source.getWidth() - insets.left - insets.right;
                    int h = source.getHeight() - insets.top - insets.bottom;
                    ChartTransferable selection = new ChartTransferable(source
                            .getChart(), w, h, source.getMinimumDrawWidth(), source.getMinimumDrawHeight(), source
                            .getMaximumDrawWidth(), source.getMaximumDrawHeight(), true);

                    Image image = new Image(menu.getDisplay(),ImageUtils.convertToSWT(selection.getBufferedImage()));
                    if (image != null) {
                        ImageLoader imageLoader = new ImageLoader(); 
                        imageLoader.data = new ImageData[] { image.getImageData() }; 
                        imageLoader.save("/tmp/graph.jpg", SWT.IMAGE_JPEG); // fails 
                        ImageTransfer imageTransfer = ImageTransfer.getInstance();
                        clipboard.setContents(new Object[]{image.getImageData()}, 
                                new Transfer[]{imageTransfer}, DND.CLIPBOARD | DND.SELECTION_CLIPBOARD);
                    }
Kasas
  • 1,216
  • 2
  • 18
  • 28
  • 1
    I am using Linux and the code snippet in the link you provided works. Start -> Open image -> copy -> open gimp -> paste -> success. That doesn't work for you? – Baz Oct 03 '12 at 11:45
  • It is not correct to use this method:The method setContents(Transferable, ClipboardOwner) in the type Clipboard is not applicable for the arguments (ChartTransferable, ChartTransferable) – Kasas Oct 03 '12 at 12:11
  • So the code snippet itself works, but you cannot use it for your purpose? – Baz Oct 03 '12 at 12:13
  • I am using Ubuntu 11.04 64bit Edition and both examples don't work for me. In the AWT example I get a javax.imageio.IIOException: Invalid argument to native writeImage. BTW I am working with J2SE6 – Kasas Oct 03 '12 at 12:22
  • I have read it is probably a 64bit problem, which distribution are you using? – Kasas Oct 03 '12 at 12:23

2 Answers2

2

Copying images to clipboard does not work with SWT on Linux 64, an issue exists on Eclipse tracker since 2009.

I Made a workaround SWT Transfer implementation that copies the image as PNG.
It works on Ubuntu 64, not tested on other platforms .

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UncheckedIOException;

import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.ByteArrayTransfer;
import org.eclipse.swt.dnd.TransferData;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.ImageLoader;

/**
 * Custom clipboard transfer to work around SWT bug 283960 that make copy image to clipboard not working on Linux 64.
 *  
 * @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=283960
 */
public class PngTransfer extends ByteArrayTransfer {

    private static final String IMAGE_PNG = "image/png";
    private static final int ID = registerType(IMAGE_PNG);

    private static PngTransfer _instance = new PngTransfer();

    private PngTransfer() {}

    public static PngTransfer getInstance () {
        return _instance;
    }

    @Override
    protected String[] getTypeNames() {
        return new String[]{IMAGE_PNG};
    }

    @Override
    protected int[] getTypeIds() {
        return new int[]{ID};
    }

    @Override
    protected void javaToNative(Object object, TransferData transferData) {
        if (object == null || !(object instanceof ImageData)) {
            return;
        }

        if (isSupportedType(transferData)) {
            ImageData image = (ImageData) object;
            try (ByteArrayOutputStream out = new ByteArrayOutputStream();){
                // write data to a byte array and then ask super to convert to pMedium

                ImageLoader imgLoader = new ImageLoader();
                imgLoader.data = new ImageData[] { image };
                imgLoader.save(out, SWT.IMAGE_PNG);

                byte[] buffer = out.toByteArray();
                out.close();

                super.javaToNative(buffer, transferData);
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
        }
    }

    @Override
    protected Object nativeToJava(TransferData transferData) {
        if (isSupportedType(transferData)) {

            byte[] buffer = (byte[])super.nativeToJava(transferData);
            if (buffer == null) {
                return null;
            }

            try (ByteArrayInputStream in = new ByteArrayInputStream(buffer)){
                return new ImageData(in);
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
        }

        return null;
    }

}
Cédric
  • 334
  • 2
  • 8
0

Try this code:

JFreeChart chart = YOUR_CHART_HERE;
ChartComposite chartComposite = new ChartComposite(shell, SWT.NONE, chart, true);

Image image = new Image(Display.getDefault(), chartComposite.getBounds());
GC gc = new GC(image);
chartComposite.print(gc);
gc.dispose();

ImageTransfer imageTransfer = ImageTransfer.getInstance();
clipboard.setContents(new Object[] {image.getImageData()}, new Transfer[]{imageTransfer});
Baz
  • 36,440
  • 11
  • 68
  • 94
  • I am using the SWT_AWT bridge, because SWT experimental JFreeChart is not showing labels on the charts I am using, so I decided to work with AWT... However I put my code on my question on you will see its near the same code, I have store the imagedata into a file and it worked perfectly, but clipboard is still not working... – Kasas Oct 03 '12 at 15:03
  • @Kasas Maybe try this: [Can't copy from clipboard to any Java applet](http://askubuntu.com/questions/42122/cant-copy-from-clipboard-to-any-java-applet). Moreover, try changing the line in my edited answer. – Baz Oct 03 '12 at 15:37
  • Where did you find the ImageTransferable object? I cannot find it anywhere...I will see that Java options to see if that is the problem ;) – Kasas Oct 04 '12 at 07:48
  • @Kasas My apologies, I added the class to my answer. – Baz Oct 04 '12 at 07:54
  • ImageTransferable is not a subclass of ImageTransfer, so you cannot assign it to imageTransfer... However I have used the ChartTransferable that creates a BufferedImage without luck... – Kasas Oct 04 '12 at 08:17
  • On the other hand, it is not a permission problem, when I use awt i get the following error: javax.imageio.IIOException: Invalid argument to native writeImage – Kasas Oct 04 '12 at 08:20
  • @Kasas Seems hopeless... Have you tried if it works on 32bit? – Baz Oct 04 '12 at 08:21
  • My client decision is to work without the copy element, it is a multiplatform application so my client wants the application to be the same for all platforms. Thanks anyway @Baz ;) – Kasas Oct 04 '12 at 08:23
  • @Kasas Fair enough, sorry I couldn't really help. – Baz Oct 04 '12 at 08:25