Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8271398

GTK3 drag view image swaps red and blue color channels

    XMLWordPrintable

    Details

      Description

      ADDITIONAL SYSTEM INFORMATION :
      Tested with JavaFX 16, JDK 16 on Ubuntu 20.04 and Fedora 34.

      A DESCRIPTION OF THE PROBLEM :
      When setting an image as drag view during drag and drop it will be shown with incorrect colors. The red and blue color channels will be swapped.
      Does not happen in JavaFX 13, happens in 14 and later. Most likely related to this change: https://bugs.openjdk.java.net/browse/JDK-8225571 - "Port Linux glass drag source (DND) to use gtk instead of gdk".

      REGRESSION : Last worked in version 13

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. Create a draggable control.
      2. At drag start, set an image as drag view.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Drag view image displayed with correct colors.
      ACTUAL -
      Drag view image displayed with incorrect colors, red and blue channels are swapped.

      ---------- BEGIN SOURCE ----------
      package com.example.bug;

      import javafx.application.Application;
      import javafx.embed.swing.SwingFXUtils;
      import javafx.geometry.Pos;
      import javafx.scene.Scene;
      import javafx.scene.control.CheckBox;
      import javafx.scene.control.Label;
      import javafx.scene.image.Image;
      import javafx.scene.image.ImageView;
      import javafx.scene.input.ClipboardContent;
      import javafx.scene.input.Dragboard;
      import javafx.scene.input.TransferMode;
      import javafx.scene.layout.VBox;
      import javafx.stage.Stage;

      import java.awt.image.BufferedImage;

      /**
       * Example code for JavaFX bug "GTK3 drag view image swaps red and blue color channels".
       *
       * Does not happen in JavaFX 13, happens in 14 and later.
       * Most likely related to this change: https://bugs.openjdk.java.net/browse/JDK-8225571 - "Port Linux glass drag source
       * (DND) to use gtk instead of gdk".
       *
       * Workaround:
       * #1: Swap red and blue color channels before setting drag view image, see code.
       * #2: Use JavaFX 13.
       * #3: Use GTK2 at runtime with JVM argument "-Djdk.gtk.version=2".
       *
       * Tested with JavaFX 16, JDK 16 on Ubuntu 20.04 and Fedora 34.
       */
      public class Main extends Application {
          Image image = createImage(240, 240);
          CheckBox workaround = new CheckBox("Workaround");

          public static void main(String[] args) {
              launch(args);
          }

          @Override
          public void start(Stage stage) {
              ImageView imageView = new ImageView(image);
              imageView.setOnDragDetected(event -> {
                  ClipboardContent content = new ClipboardContent();
                  content.putImage(image);
                  Dragboard dragboard = imageView.startDragAndDrop(TransferMode.ANY);
                  dragboard.setContent(content);
                  if (workaround.isSelected()) {
                      dragboard.setDragView(swapRedAndBlueColorChannels(image));
                  } else {
                      dragboard.setDragView(image);
                  }
              });

              VBox vBox = new VBox(new Label("Drag image"), imageView, workaround);
              vBox.setSpacing(5.0);
              vBox.setAlignment(Pos.CENTER);
              stage.setScene(new Scene(vBox, 480, 480));
              stage.setTitle("GTK3 Drag View Image Wrong Colors");
              stage.show();
          }

          private static Image createImage(int width, int height) {
              BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
              for (int y=0; y<height; y++) {
                  for (int x=0; x<width; x++) {
                      if (x < width * 0.33) {
                          image.setRGB(x, y, 0xFF0000);
                      } else if (x < width * 0.66) {
                          image.setRGB(x, y, 0x00FF00);
                      } else {
                          image.setRGB(x, y, 0x0000FF);
                      }
                  }
              }
              return SwingFXUtils.toFXImage(image, null);
          }

          private static Image swapRedAndBlueColorChannels(Image image) {
              BufferedImage bufferedImage = SwingFXUtils.fromFXImage(image, null);
              int width = bufferedImage.getWidth();
              int height = bufferedImage.getHeight();
              for (int y=0; y<height; y++) {
                  for (int x=0; x<width; x++) {
                      int p = bufferedImage.getRGB(x, y);
                      int a = (p>>24) & 0xFF;
                      int r = (p>>16) & 0xFF;
                      int g = (p>>8) & 0xFF;
                      int b = p & 0xFF;
                      p = (a<<24) | (b<<16) | (g<<8) | r; // Swap red and blue values.
                      bufferedImage.setRGB(x, y, p);
                  }
              }
              return SwingFXUtils.toFXImage(bufferedImage, null);
          }
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      #1: Swap red and blue color channels before setting drag view image, see code.
      #2: Use JavaFX 13.
      #3: Use GTK2 at runtime with JVM argument "-Djdk.gtk.version=2".

      FREQUENCY : always


        Attachments

        1. Capture_11.PNG
          Capture_11.PNG
          55 kB
        2. Capture_17.PNG
          Capture_17.PNG
          56 kB
        3. Main.java
          4 kB

          Issue Links

            Activity

              People

              Assignee:
              tsayao Thiago Sayao
              Reporter:
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              6 Start watching this issue

                Dates

                Created:
                Updated:
                Resolved: