Copy Image to Clipboard not working on Linux (Java AWT & SWT)
Asked Answered
H

2

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);
                    }
Harrier answered 3/10, 2012 at 11:4 Comment(5)
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?Epidaurus
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)Harrier
So the code snippet itself works, but you cannot use it for your purpose?Epidaurus
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 J2SE6Harrier
I have read it is probably a 64bit problem, which distribution are you using?Harrier
A
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;
    }

}
Aquavit answered 22/8, 2017 at 13:45 Comment(0)
E
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});
Epidaurus answered 3/10, 2012 at 11:28 Comment(9)
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...Harrier
@Harrier Maybe try this: Can't copy from clipboard to any Java applet. Moreover, try changing the line in my edited answer.Epidaurus
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 ;)Harrier
@Harrier My apologies, I added the class to my answer.Epidaurus
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...Harrier
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 writeImageHarrier
@Harrier Seems hopeless... Have you tried if it works on 32bit?Epidaurus
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 @Epidaurus ;)Harrier
@Harrier Fair enough, sorry I couldn't really help.Epidaurus

© 2022 - 2024 — McMap. All rights reserved.