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

SwingFXUtils.fromFXImage seems to have a bug inside

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P4 P4
    • 10
    • 8u45
    • javafx
    • x86
    • windows_8

      FULL PRODUCT VERSION :
      java version "1.8.0_45"
      Java(TM) SE Runtime Environment (build 1.8.0_45-b15)
      Java HotSpot(TM) Client VM (build 25.45-b02, mixed mode, sharing)

      And JDK the same

      ADDITIONAL OS VERSION INFORMATION :
      Microsoft Windows [Version 6.3.9600]

      A DESCRIPTION OF THE PROBLEM :
      I want to save a snapshot image of a JavaFX Application ImageView to file as type jpg. It seems that there is a bug with jpg (I need jpg, png is not an alternative to me).

      Maybe the PixelWriter and PixelFormat seems to me wrong, even if I try to do a PixelFormat<ByteBuffer> format = PixelFormat.getRGBInstance(). But the RGB Format is fully ignored.

      If you try the following code, it will show the problem:

      import java.awt.image.BufferedImage;
      import java.io.File;
      import java.io.FileInputStream;
      import java.io.IOException;
      import java.nio.IntBuffer;
      import java.util.Arrays;
      import java.util.logging.Level;
      import java.util.logging.Logger;
      import javafx.application.Application;
      import javafx.embed.swing.SwingFXUtils;
      import javafx.scene.Scene;
      import javafx.scene.SnapshotParameters;
      import javafx.scene.control.ScrollPane;
      import javafx.scene.control.SplitPane;
      import javafx.scene.image.Image;
      import javafx.scene.image.ImageView;
      import javafx.scene.image.PixelReader;
      import javafx.scene.image.PixelWriter;
      import javafx.scene.image.WritableImage;
      import javafx.scene.image.WritablePixelFormat;
      import javafx.scene.paint.Color;
      import javafx.stage.Stage;
      import javax.imageio.ImageIO;

      public class WritableImageDemo extends Application {

        private Image src;
        private int width;
        private int height;
        ImageView srcView;
        ImageView srcView2;
        ImageView srcView3;

        @Override
        public void start(Stage primaryStage) {
          primaryStage.setTitle("Image");

          src = new Image("http://www.gnu.org/graphics/gnu-head.jpg");
          width = (int) src.getWidth();
          height = (int) src.getHeight();

          srcView = new ImageView(src);
          srcView2 = new ImageView();
          srcView3 = new ImageView();

          ScrollPane scrollPane = new ScrollPane();
          ScrollPane scrollPane2 = new ScrollPane();
          ScrollPane scrollPane3 = new ScrollPane();

          scrollPane.setContent(srcView);
          scrollPane2.setContent(srcView2);
          scrollPane3.setContent(srcView3);

          SplitPane root = new SplitPane(scrollPane, scrollPane2, scrollPane3);

          primaryStage.setScene(new Scene(root, 800, 600));
          primaryStage.show();

          srcView2.setImage(writeToFile());
        }

        private WritableImage writeToFile() {
          WritableImage insert = new WritableImage(width, height);
          WritableImage newimage = new WritableImage(width, height);

          SnapshotParameters parameters = new SnapshotParameters();
          parameters.setFill(Color.TRANSPARENT);
          // make a snapshot
          srcView.snapshot(parameters, insert);

          PixelReader reader = insert.getPixelReader();
          PixelWriter writer = newimage.getPixelWriter();
          WritablePixelFormat<IntBuffer> format = WritablePixelFormat.getIntArgbInstance();

          System.out.println("WritablePixelFormat.getType(): " + format.getType());
          // the following normally creates an exact copy of the original
          for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
              int recWidth = 1;
              int recHeight = 1;

              int[] buffer = new int[recWidth * recHeight];
              reader.getPixels(x, y, recWidth, recHeight, format, buffer, 0, recWidth);

              int alpha = 0;
              int red = 0;
              int green = 0;
              int blue = 0;

              for (int color : buffer) {
                alpha += (color >>> 24);
                red += (color >>> 16 & 0xFF);
                green += (color >>> 8 & 0xFF);
                blue += (color & 0xFF);
              }
              alpha = alpha / recWidth / recHeight;
              red = red / recWidth / recHeight;
              green = green / recWidth / recHeight;
              blue = blue / recWidth / recHeight;

              int color = (alpha << 24) + (red << 16) + (green << 8) + blue;
              Arrays.fill(buffer, color);

              writer.setPixels(x, y, recWidth, recHeight, format, buffer, 0, recWidth);
            }

          }
          System.out.println("Reader Type: " + reader.getPixelFormat().getType());
          System.out.println("Writer Type: " + writer.getPixelFormat().getType());

          try {
            BufferedImage b = new BufferedImage(width + 1, height + 1, BufferedImage.OPAQUE);
            BufferedImage bf = SwingFXUtils.fromFXImage(newimage, b);

            ImageIO.write(bf, "jpg", new File("C:\\temp\\test1.jpg"));
          } catch (IOException ex) {
            Logger.getLogger(WritableImageDemo.class.getName()).
                    log(Level.SEVERE, null, ex);
          }
          try {
            Image img = new Image(new FileInputStream(new File("C:\\temp\\test1.jpg")));
            srcView3.setImage(img);
          } catch (IOException ex) {
            Logger.getLogger(WritableImageDemo.class.getName()).log(Level.SEVERE, null, ex);
          }
          return newimage;
        }

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




      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Run the code

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      A jpg file that looks like the original file.
      ACTUAL -
      A red background fade in color is set.

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import java.awt.image.BufferedImage;
      import java.io.File;
      import java.io.FileInputStream;
      import java.io.IOException;
      import java.nio.IntBuffer;
      import java.util.Arrays;
      import java.util.logging.Level;
      import java.util.logging.Logger;
      import javafx.application.Application;
      import javafx.embed.swing.SwingFXUtils;
      import javafx.scene.Scene;
      import javafx.scene.SnapshotParameters;
      import javafx.scene.control.ScrollPane;
      import javafx.scene.control.SplitPane;
      import javafx.scene.image.Image;
      import javafx.scene.image.ImageView;
      import javafx.scene.image.PixelReader;
      import javafx.scene.image.PixelWriter;
      import javafx.scene.image.WritableImage;
      import javafx.scene.image.WritablePixelFormat;
      import javafx.scene.paint.Color;
      import javafx.stage.Stage;
      import javax.imageio.ImageIO;

      public class WritableImageDemo extends Application {

        private Image src;
        private int width;
        private int height;
        ImageView srcView;
        ImageView srcView2;
        ImageView srcView3;

        @Override
        public void start(Stage primaryStage) {
          primaryStage.setTitle("Image");

          src = new Image("http://www.gnu.org/graphics/gnu-head.jpg");
          width = (int) src.getWidth();
          height = (int) src.getHeight();

          srcView = new ImageView(src);
          srcView2 = new ImageView();
          srcView3 = new ImageView();

          ScrollPane scrollPane = new ScrollPane();
          ScrollPane scrollPane2 = new ScrollPane();
          ScrollPane scrollPane3 = new ScrollPane();

          scrollPane.setContent(srcView);
          scrollPane2.setContent(srcView2);
          scrollPane3.setContent(srcView3);

          SplitPane root = new SplitPane(scrollPane, scrollPane2, scrollPane3);

          primaryStage.setScene(new Scene(root, 800, 600));
          primaryStage.show();

          srcView2.setImage(writeToFile());
        }

        private WritableImage writeToFile() {
          WritableImage insert = new WritableImage(width, height);
          WritableImage newimage = new WritableImage(width, height);

          SnapshotParameters parameters = new SnapshotParameters();
          parameters.setFill(Color.TRANSPARENT);
          // make a snapshot
          srcView.snapshot(parameters, insert);

          PixelReader reader = insert.getPixelReader();
          PixelWriter writer = newimage.getPixelWriter();
          WritablePixelFormat<IntBuffer> format = WritablePixelFormat.getIntArgbInstance();
          
          System.out.println("WritablePixelFormat.getType(): " + format.getType());
          // the following normally creates an exact copy of the original
          for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
              int recWidth = 1;
              int recHeight = 1;

              int[] buffer = new int[recWidth * recHeight];
              reader.getPixels(x, y, recWidth, recHeight, format, buffer, 0, recWidth);

              int alpha = 0;
              int red = 0;
              int green = 0;
              int blue = 0;

              for (int color : buffer) {
                alpha += (color >>> 24);
                red += (color >>> 16 & 0xFF);
                green += (color >>> 8 & 0xFF);
                blue += (color & 0xFF);
              }
              alpha = alpha / recWidth / recHeight;
              red = red / recWidth / recHeight;
              green = green / recWidth / recHeight;
              blue = blue / recWidth / recHeight;

              int color = (alpha << 24) + (red << 16) + (green << 8) + blue;
              Arrays.fill(buffer, color);

              writer.setPixels(x, y, recWidth, recHeight, format, buffer, 0, recWidth);
            }

          }
          System.out.println("Reader Type: " + reader.getPixelFormat().getType());
          System.out.println("Writer Type: " + writer.getPixelFormat().getType());

          try {
            BufferedImage b = new BufferedImage(width + 1, height + 1, BufferedImage.OPAQUE);
            BufferedImage bf = SwingFXUtils.fromFXImage(newimage, b);

            ImageIO.write(bf, "jpg", new File("C:\\temp\\test1.jpg"));
          } catch (IOException ex) {
            Logger.getLogger(WritableImageDemo.class.getName()).
                    log(Level.SEVERE, null, ex);
          }
          try {
            Image img = new Image(new FileInputStream(new File("C:\\temp\\test1.jpg")));
            srcView3.setImage(img);
          } catch (IOException ex) {
            Logger.getLogger(WritableImageDemo.class.getName()).log(Level.SEVERE, null, ex);
          }
          return newimage;
        }

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

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

      CUSTOMER SUBMITTED WORKAROUND :
      Haven't found anything. I was not able to set the Pixelformat.type of the writer.

            psadhukhan Prasanta Sadhukhan
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            6 Start watching this issue

              Created:
              Updated:
              Resolved: