30

The Problem

JavaFX's default way of getting an image from the Windows clipboard,

Clipboard.getSystemClipboard().getImage();

, appears to be broken.

Something seems to go wrong with the transparency of the image. Set on a black background, the image appears fine, but set on a white background, nothing shows at all.

Showing the JavaFX image transparency issue by changing the background of the application from dark to light.

You can test the clipboard using this Minimal, Complete, Verifiable example.

Environment: Windows 7, Java 8 update 202

What I Know

Below, I'll describe the things I already know.

There are Other People who Have Asked Similar Questions:

Yet, no one has gotten at the heart of the problem or received an answer.

No Official Bug

I can't seem to find a bug regarding this issue in the Java Bug Database.

No Problem for AWT

This problem with images doesn't occur on the AWT clipboard, but I want a solution that uses the JavaFX clipboard.

On the right is the image from AWT's clipboard, on the left is the same image from JavaFX's clipboard.

The Clipboard Contains Multiple Formats

I know that the Windows clipboard contains multiple versions of the same thing, just in different formats. This is easy to see using InsideClipboard or Free Clipboard Viewer.

A screenshot of InsideClipboard, showing the CF_DIB format.

The JavaFX Clipboard recognizes certain formats; sometimes it has different names for them. application/x-java-rawimage is what Java considers an image; in code you refer to this as DataFormat.IMAGE.

I suspect that the DIB clipboard format in Windows matches up with Java's application/x-java-rawimage, but can't find proof of that in the source code.

The Problem is Wide-Spread

Problem Applications

JavaFX seems to have this same transparency problem with various applications that copy an image to the clipboard:

Applications Without The Issue

I've also found some applications that copy an image to the clipboard and JavaFX can pull it out using the default method no problem:

  • Paint.net
  • The PrtScn button
  • The Windows Snipping Tool
  • Google Chrome 72.0.3626.121 (copying the Google.com logo)

Answering The Question

An adequate answer should

  • explain simply, specifically, and with examples why the problem occurs with some applications, but not others, and
  • figure out where things go wrong in the JDK implementation and show specifically how to fix said implementation for the majority of the problem applications without breaking it for the applications that already work.
    • If it's not feasible to change the JDK's implementation, an adequate answer will provide a Minimal, Complete, and Verifiable example showing JavaFX code that produces an Image from the JavaFX clipboard when an image is copied from Adobe Reader.

If you can't help, but think this is a well researched question, consider voting, or sharing it with a friend.

Brad Turek
  • 2,472
  • 3
  • 30
  • 56
  • I can't reproduce this with the code on Windows 10 Java 8 202. It may be a Windows 7 specific bug. – Deckerz Apr 15 '19 at 13:54
  • @Deckerz thanks for the info. Which application did you copy your image from? – Brad Turek Apr 15 '19 at 14:54
  • I copied from firefox. the google.com logo – Deckerz Apr 15 '19 at 15:24
  • Note, the hypothesis in [this comment to your gist](https://gist.github.com/TurekBot/f639f327747e7f76639a806333756d30#gistcomment-2888989) seems plausible. – Slaw Apr 15 '19 at 21:26
  • @Slaw, I hadn't seen that comment for some reason. Thanks for pointing it out. – Brad Turek Apr 16 '19 at 00:49
  • 2
    Messing around with this some more, I do believe the problem is the opacity. Checking the `PixelReader` of the image, the pixels that should have color have an opacity of `0`. In fact, all the pixels appear to have `0` opacity when the problem occurs—so I'm not even sure how anything shows up at all. I couldn't find a JavaFX-only solution, so the best workaround currently is the one described in the comment to your gist (using `BufferedImage`). – Slaw Apr 17 '19 at 23:53
  • 3
    You should submit a bug report. Note, the only program from your list I could reproduce the problem with (and had access to) was Paint on Windows 10. Initially, Firefox also caused the problem but it updated mid-testing and the problem appears to have gone away. Also, using the latest JavaFX version (12) did not appear to help. – Slaw Apr 17 '19 at 23:55
  • 2
    I was able to reproduce it using Lightshot and Google Chrome. The workaround i gave you in the gist will reduce the image quality so i wouldnt recommended it. Until they fix it you should only use the awt clipboard insead of javafx ( sadly ). – JKostikiadis Apr 18 '19 at 12:56
  • 3
    Upvoted for excellent research, good formatting, and possibly spotting out a bug. I wish more questions were written to this standard. Is this worth putting a bounty on, so we can get an answer here? – Austin Schaefer Jul 11 '19 at 09:10
  • @AustinSchäfer, you're very kind—I try my best. I _did_ put a 300 point bounty on this question a month or so after writing it, but no answer was discovered and hence no bounty awarded. – Brad Turek Jul 11 '19 at 21:25
  • [This](https://stackoverflow.com/questions/44287407/text-erased-from-screenshot-after-using-clipboard-getimage-on-windows-10/46400011#46400011) post seems to answer your question. It's Windows' fault, not JavaFX – Mordechai Dec 24 '19 at 16:24
  • Thanks, @Mordechai! If you're able to show that in an answer, I'd definitely consider it. – Brad Turek Dec 24 '19 at 23:18
  • @SergeyGrinev, thanks for putting up the bounty; if I could augment it with my own points, I would. Surely we'll find an answer. – Brad Turek Feb 20 '20 at 17:23

1 Answers1

4

In both of your loading methods, the resulting JavaFx Image supports transparency when it shouldn't. However, the AWT loading method uses an intermediate Transferable that uses a non-transparent DirectColorModel to create the Image. As a result the AWT image appears to be correct despite the underlying image still supporting transparency.

Unfortunately this issue stems from a deeper issue that will probably not be fixed, see: https://bugs.openjdk.java.net/browse/JDK-8041459

When java saves image with alpha channel it encode image as YCbCr plus 4th alpha channel. The problem that other applications recognize 4 channels jpeg as RGB or CMYK image, that's why we have wrong color in image. The best solution is to convert image to other color type without alpha channel and only then save it it can't be fixed, the jpeg's spec doesn't specify this moment, it says that color space is application dependent, java decided to code alpha channel as YCbCrA, that's it.

Rather than trying to manually manipulate Image data, an easier fix is probably to blend the Image with a Rectangle and use a Group instead of an ImageView to display it. Here is an example:

private void loadImageFromJavaFXClipboard(final Group group) {
    System.out.println("Adding an image from the JavaFX Clipboard...");
    final Clipboard clipboard = Clipboard.getSystemClipboard();

    if (clipboard.hasImage()) {
        final Image image = clipboard.getImage();

        setupImageFixingGroup(group, image);
    } else {
        new Alert(Alert.AlertType.INFORMATION, "No image detected on the Clipboard!").show();
        group.getChildren().clear();
    }
}

private void setupImageFixingGroup(Group group, Image image) {
    final ImageView view = new ImageView(image);
    view.setBlendMode(BlendMode.LIGHTEN);

    final Rectangle blend = new Rectangle(image.getWidth(), image.getHeight(), Color.BLACK);
    blend.widthProperty().bind(image.widthProperty());
    blend.heightProperty().bind(image.heightProperty());

    group.getChildren().clear();
    group.getChildren().addAll(blend, view);
}

Here is a working version of your Minimal, Verifiable, Complete example: https://pastebin.com/rzhzMui5. I tested it with a number of images including the one in your gif, but have not explicitly tested it against every case you included.

user2815708
  • 193
  • 3
  • Thanks for figuring so much out. Do you think you could explain a little more about why the problem occurs with some applications, but not others? Once you do that, and I can give your solution a try, I'll likely accept your answer. – Brad Turek Feb 24 '20 at 22:43