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;
}
/**