modules/swing/src/main/java/javafx/embed/swing/SwingFXUtils.java

Print this page

        

@@ -28,12 +28,10 @@
 import java.awt.AlphaComposite;
 import java.awt.EventQueue;
 import java.awt.Graphics2D;
 import java.awt.SecondaryLoop;
 import java.awt.image.BufferedImage;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
 import java.nio.IntBuffer;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.Set;
 import java.util.HashSet;

@@ -106,11 +104,11 @@
             if (iw < bw || ih < bh) {
                 wimg = null;
             } else if (bw < iw || bh < ih) {
                 int empty[] = new int[iw];
                 PixelWriter pw = wimg.getPixelWriter();
-                PixelFormat pf = PixelFormat.getIntArgbPreInstance();
+                PixelFormat<IntBuffer> pf = PixelFormat.getIntArgbPreInstance();
                 if (bw < iw) {
                     pw.setPixels(bw, 0, iw-bw, bh, pf, empty, 0, 0);
                 }
                 if (bh < ih) {
                     pw.setPixels(0, bh, iw, ih-bh, pf, empty, 0, 0);

@@ -131,10 +129,82 @@
         pw.setPixels(0, 0, bw, bh, pf, data, offset, scan);
         return wimg;
     }
 
     /**
+     * Determine the optimal BufferedImage type to use for the specified
+     * {@code fxFormat} allowing for the specified {@code bimg} to be used
+     * as a potential default storage space if it is not null and is compatible.
+     * 
+     * @param fxFormat the PixelFormat of the source FX Image
+     * @param bimg an optional existing {@code BufferedImage} to be used
+     *             for storage if it is compatible, or null
+     * @return 
+     */
+    private static int
+        getBestBufferedImageType(PixelFormat<?> fxFormat, BufferedImage bimg)
+    {
+        if (bimg != null) {
+            int bimgType = bimg.getType();
+            if (bimgType == BufferedImage.TYPE_INT_ARGB ||
+                bimgType == BufferedImage.TYPE_INT_ARGB_PRE)
+            {
+                // We will allow the caller to give us a BufferedImage
+                // that has an alpha channel, but we might not otherwise
+                // construct one ourselves.
+                // We will also allow them to choose their own premultiply
+                // type which may not match the image.
+                // If left to our own devices we might choose a more specific
+                // format as indicated by the choices below.
+                return bimgType;
+            }
+        }
+        switch (fxFormat.getType()) {
+            default:
+            case BYTE_BGRA_PRE:
+            case INT_ARGB_PRE:
+                return BufferedImage.TYPE_INT_ARGB_PRE;
+            case BYTE_BGRA:
+            case INT_ARGB:
+                return BufferedImage.TYPE_INT_ARGB;
+            case BYTE_RGB:
+                return BufferedImage.TYPE_INT_RGB;
+            case BYTE_INDEXED:
+                return (fxFormat.isPremultiplied()
+                        ? BufferedImage.TYPE_INT_ARGB_PRE
+                        : BufferedImage.TYPE_INT_ARGB);
+        }
+    }
+
+    /**
+     * Determine the appropriate {@link WritablePixelFormat} type that can
+     * be used to transfer data into the indicated BufferedImage.
+     * 
+     * @param bimg the BufferedImage that will be used as a destination for
+     *             a {@code PixelReader<IntBuffer>#getPixels()} operation.
+     * @return 
+     */
+    private static WritablePixelFormat<IntBuffer>
+        getAssociatedPixelFormat(BufferedImage bimg)
+    {
+        switch (bimg.getType()) {
+            // We lie here for xRGB, but we vetted that the src data was opaque
+            // so we can ignore the alpha.  We use ArgbPre instead of Argb
+            // just to get a loop that does not have divides in it if the
+            // PixelReader happens to not know the data is opaque.
+            case BufferedImage.TYPE_INT_RGB:
+            case BufferedImage.TYPE_INT_ARGB_PRE:
+                return PixelFormat.getIntArgbPreInstance();
+            case BufferedImage.TYPE_INT_ARGB:
+                return PixelFormat.getIntArgbInstance();
+            default:
+                // Should not happen...
+                throw new InternalError("Failed to validate BufferedImage type");
+        }
+    }
+
+    /**
      * Snapshots the specified JavaFX {@link Image} object and stores a
      * copy of its pixels into a {@link BufferedImage} object, creating
      * a new object if needed.
      * The method will only convert a JavaFX {@code Image} that is readable
      * as per the conditions on the

@@ -166,36 +236,31 @@
         if (pr == null) {
             return null;
         }
         int iw = (int) img.getWidth();
         int ih = (int) img.getHeight();
+        int prefBimgType = getBestBufferedImageType(pr.getPixelFormat(), bimg);
         if (bimg != null) {
-            int type = bimg.getType();
             int bw = bimg.getWidth();
             int bh = bimg.getHeight();
-            if (bw < iw || bh < ih ||
-                (type != BufferedImage.TYPE_INT_ARGB &&
-                 type != BufferedImage.TYPE_INT_ARGB_PRE))
-            {
+            if (bw < iw || bh < ih || bimg.getType() != prefBimgType) {
                 bimg = null;
             } else if (iw < bw || ih < bh) {
                 Graphics2D g2d = bimg.createGraphics();
                 g2d.setComposite(AlphaComposite.Clear);
                 g2d.fillRect(0, 0, bw, bh);
                 g2d.dispose();
             }
         }
         if (bimg == null) {
-            bimg = new BufferedImage(iw, ih, BufferedImage.TYPE_INT_ARGB_PRE);
+            bimg = new BufferedImage(iw, ih, prefBimgType);
         }
         IntegerComponentRaster icr = (IntegerComponentRaster) bimg.getRaster();
         int offset = icr.getDataOffset(0);
         int scan = icr.getScanlineStride();
         int data[] = icr.getDataStorage();
-        WritablePixelFormat<IntBuffer> pf = (bimg.isAlphaPremultiplied() ?
-                                             PixelFormat.getIntArgbPreInstance() :
-                                             PixelFormat.getIntArgbInstance());
+        WritablePixelFormat<IntBuffer> pf = getAssociatedPixelFormat(bimg);
         pr.getPixels(0, 0, iw, ih, pf, data, offset, scan);
         return bimg;
     }
 
     /**