javafx.embed.swt.SWTFXUtils Maven / Gradle / Ivy
Show all versions of openjfx-78-backport Show documentation
/*
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javafx.embed.swt;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.graphics.RGB;
import java.lang.reflect.Method;
import java.lang.reflect.Field;
import javafx.scene.image.PixelFormat;
import javafx.scene.image.PixelReader;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.image.Image;
import javafx.scene.image.WritablePixelFormat;
/**
* This class provides utility methods for converting data types between
* SWT and JavaFX formats.
* @since JavaFX 2.2
*/
public class SWTFXUtils {
private SWTFXUtils() {} // no instances
/**
* Snapshots the specified {@link ImageData} and stores a copy of
* its pixels into a JavaFX {@link Image} object, creating a new
* object if needed.
* The returned {@code Image} will be a static snapshot of the state
* of the pixels in the {@code ImageData} at the time the method
* completes. Further changes to the {@code ImageData} will not
* be reflected in the {@code Image}.
*
* The optional JavaFX {@link WritableImage} parameter may be reused
* to store the copy of the pixels.
* A new {@code Image} will be created if the supplied object is null,
* is too small or of a type which the image pixels cannot be easily
* converted into.
*
* @param imageData the {@code ImageData} object to be converted
* @param image an optional {@code WritableImage} object that can be
* used to store the returned pixel data
* @return an {@code Image} object representing a snapshot of the
* current pixels in the {@code ImageData}, or null if
* the {@code Image} is not readable.
*/
public static WritableImage toFXImage(ImageData imageData,
WritableImage image) {
byte[] data = convertImage(imageData);
if (data == null) return null;
int width = imageData.width;
int height = imageData.height;
if (image != null) {
int iw = (int) image.getWidth();
int ih = (int) image.getHeight();
if (iw < width || ih < height) {
image = null;
} else if (width < iw || height < ih) {
int empty[] = new int[iw];
PixelWriter pw = image.getPixelWriter();
PixelFormat pf = PixelFormat.getIntArgbPreInstance();
if (width < iw) {
pw.setPixels(width, 0, iw-width, height, pf, empty, 0, 0);
}
if (height < ih) {
pw.setPixels(0, height, iw, ih-height, pf, empty, 0, 0);
}
}
}
if (image == null) {
image = new WritableImage(width, height);
}
PixelWriter pw = image.getPixelWriter();
int scan = width * 4;
PixelFormat pf = PixelFormat.getByteBgraInstance();
pw.setPixels(0, 0, width, height, pf, data, 0, scan);
return image;
}
/**
* Snapshots the specified JavaFX {@link Image} object and stores a
* copy of its pixels into a new {@link ImageData} object.
* The method will only convert a JavaFX {@code Image} that is readable
* as per the conditions on the
* {@link Image#getPixelReader() Image.getPixelReader()}
* method.
* If the {@code Image} is not readable, as determined by its
* {@code getPixelReader()} method, then this method will return null.
* If the {@code Image} is a writable, or other dynamic image, then
* the {@code ImageData} will only be set to the current state of
* the pixels in the image as determined by its {@link PixelReader}.
* Further changes to the pixels of the {@code Image} will not be
* reflected in the returned {@code ImageData}.
*
* The optional {@code ImageData} parameter may be reused to store
* the copy of the pixels.
* A new {@code ImageData} will be created if the supplied object
* is null, is too small or of a type which the image pixels cannot
* be easily converted into.
*
* @param image the JavaFX {@code Image} to be converted
* @param imageData an optional {@code ImageData} object that may be
* used to store the returned pixel data
* @return a {@code ImageData} containing a snapshot of the JavaFX
* {@code Image}, or null if the {@code Image} is not readable.
*/
public static ImageData fromFXImage(Image image, ImageData imageData) {
PixelReader pr = image.getPixelReader();
if (pr == null) {
return null;
}
int width = (int) image.getWidth();
int height = (int) image.getHeight();
int bpr = width * 4;
int dataSize = bpr * height;
byte[] buffer = new byte[dataSize];
WritablePixelFormat pf = PixelFormat.getByteBgraInstance();
pr.getPixels(0, 0, width, height, pf, buffer, 0, bpr);
byte[] alphaData = new byte[width * height];
for (int y = 0, offset = 0, alphaOffset = 0; y < height; y++) {
for (int x = 0; x < width; x++, offset += 4) {
byte alpha = buffer[offset+3];
buffer[offset+3] = 0;
alphaData[alphaOffset++] = alpha;
}
}
PaletteData palette = new PaletteData(0xFF00, 0xFF0000, 0xFF000000);
imageData = new ImageData(width, height, 32, palette, 4, buffer);
imageData.alphaData = alphaData;
return imageData;
}
private static int blitSrc;
private static boolean blitSrcCache;
private static int BLIT_SRC() throws Exception {
if (!blitSrcCache) {
blitSrc = readValue("BLIT_SRC");
blitSrcCache = true;
}
return blitSrc;
}
private static int alphaOpaque;
private static boolean alphaOpaqueCache;
private static int ALPHA_OPAQUE() throws Exception {
if (!alphaOpaqueCache) {
alphaOpaque = readValue("ALPHA_OPAQUE");
alphaOpaqueCache = true;
}
return alphaOpaque;
}
private static int msbFirst;
private static boolean msbFirstCache;
private static int MSB_FIRST() throws Exception {
if (!msbFirstCache) {
msbFirst = readValue("MSB_FIRST");
msbFirstCache = true;
}
return msbFirst;
}
private static int readValue(final String name) throws Exception {
final Class> clazz = ImageData.class;
return AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public Integer run() throws Exception {
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
return field.getInt(clazz);
}
});
}
private static Method blitDirect;
private static void blit(int op,
byte[] srcData, int srcDepth, int srcStride, int srcOrder,
int srcX, int srcY, int srcWidth, int srcHeight,
int srcRedMask, int srcGreenMask, int srcBlueMask,
int alphaMode, byte[] alphaData, int alphaStride,
int alphaX, int alphaY,
byte[] destData, int destDepth, int destStride, int destOrder,
int destX, int destY, int destWidth, int destHeight,
int destRedMask, int destGreenMask, int destBlueMask,
boolean flipX, boolean flipY) throws Exception {
final Class> clazz = ImageData.class;
if (blitDirect == null) {
Class> I = Integer.TYPE, B = Boolean.TYPE, BA = byte[].class;
final Class>[] argClasses = {I,
BA, I, I, I,
I, I, I, I,
I, I, I,
I, BA, I, I, I,
BA, I, I, I,
I, I, I, I,
I, I, I, B, B};
blitDirect = AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public Method run() throws Exception {
Method method = clazz.
getDeclaredMethod("blit", argClasses);
method.setAccessible(true);
return method;
}
});
}
if (blitDirect != null) {
blitDirect.invoke(clazz, op,
srcData, srcDepth, srcStride, srcOrder,
srcX, srcY, srcWidth, srcHeight,
srcRedMask, srcGreenMask, srcBlueMask,
alphaMode, alphaData, alphaStride, alphaX, alphaY,
destData, destDepth, destStride, destOrder,
destX, destY, destWidth, destHeight,
destRedMask, destGreenMask, destBlueMask,
flipX, flipY);
}
}
private static Method blitPalette;
private static void blit(int op,
byte[] srcData, int srcDepth, int srcStride, int srcOrder,
int srcX, int srcY, int srcWidth, int srcHeight,
byte[] srcReds, byte[] srcGreens, byte[] srcBlues,
int alphaMode, byte[] alphaData, int alphaStride,
int alphaX, int alphaY,
byte[] destData, int destDepth, int destStride, int destOrder,
int destX, int destY, int destWidth, int destHeight,
int destRedMask, int destGreenMask, int destBlueMask,
boolean flipX, boolean flipY) throws Exception {
final Class> clazz = ImageData.class;
if (blitPalette == null) {
Class> I = Integer.TYPE, B = Boolean.TYPE, BA = byte[].class;
final Class>[] argClasses = {I,
BA, I, I, I,
I, I, I, I,
BA, BA, BA,
I, BA, I, I, I,
BA, I, I, I,
I, I, I, I,
I, I, I, B, B};
blitPalette = AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public Method run() throws Exception {
Method method = clazz.
getDeclaredMethod("blit", argClasses);
method.setAccessible(true);
return method;
}
});
}
if (blitPalette != null) {
blitPalette.invoke(clazz, op,
srcData, srcDepth, srcStride, srcOrder,
srcX, srcY, srcWidth, srcHeight,
srcReds, srcGreens, srcBlues,
alphaMode, alphaData, alphaStride, alphaX, alphaY,
destData, destDepth, destStride, destOrder,
destX, destY, destWidth, destHeight,
destRedMask, destGreenMask, destBlueMask,
flipX, flipY);
}
}
private static Method getByteOrderMethod;
private static int getByteOrder(ImageData image) throws Exception {
final Class> clazz = ImageData.class;
if (getByteOrderMethod != null) {
getByteOrderMethod = AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public Method run() throws Exception {
Method method = clazz.getDeclaredMethod("getByteOrder");
method.setAccessible(true);
return method;
}
});
}
if (getByteOrderMethod != null) {
return (Integer)getByteOrderMethod.invoke(image);
}
return MSB_FIRST();
}
private static byte[] convertImage(ImageData image) {
byte[] buffer = null;
try {
PaletteData palette = image.palette;
if (!(((image.depth == 1 || image.depth == 2 ||
image.depth == 4 || image.depth == 8) &&
!palette.isDirect) ||
((image.depth == 8) || (image.depth == 16 ||
image.depth == 24 || image.depth == 32)
&& palette.isDirect))) {
return null;
}
final int BLIT_SRC = BLIT_SRC();
final int ALPHA_OPAQUE = ALPHA_OPAQUE();
final int MSB_FIRST = MSB_FIRST();
int width = image.width;
int height = image.height;
int byteOrder = getByteOrder(image);
int ao = 3;
int redMask = 0xFF00;
int greenMask = 0xFF0000;
int blueMask = 0xFF000000;
int dataSize = width * height * 4;
int bpr = width * 4;
buffer = new byte[dataSize];
if (palette.isDirect) {
blit(BLIT_SRC,
image.data, image.depth, image.bytesPerLine, byteOrder,
0, 0, width, height,
palette.redMask, palette.greenMask, palette.blueMask,
ALPHA_OPAQUE, null, 0, 0, 0,
buffer, 32, bpr, MSB_FIRST, 0, 0, width, height,
redMask, greenMask, blueMask,
false, false);
} else {
RGB[] rgbs = palette.getRGBs();
int length = rgbs.length;
byte[] srcReds = new byte[length];
byte[] srcGreens = new byte[length];
byte[] srcBlues = new byte[length];
for (int i = 0; i < rgbs.length; i++) {
RGB rgb = rgbs[i];
if (rgb == null) continue;
srcReds[i] = (byte)rgb.red;
srcGreens[i] = (byte)rgb.green;
srcBlues[i] = (byte)rgb.blue;
}
blit(BLIT_SRC,
image.data, image.depth, image.bytesPerLine, byteOrder,
0, 0, width, height, srcReds, srcGreens, srcBlues,
ALPHA_OPAQUE, null, 0, 0, 0,
buffer, 32, bpr, MSB_FIRST, 0, 0, width, height,
redMask, greenMask, blueMask,
false, false);
}
/* Initialize transparency */
int transparency = image.getTransparencyType();
boolean hasAlpha = transparency != SWT.TRANSPARENCY_NONE;
if (transparency == SWT.TRANSPARENCY_MASK ||
image.transparentPixel != -1) {
ImageData maskImage = image.getTransparencyMask();
byte[] maskData = maskImage.data;
int maskBpl = maskImage.bytesPerLine;
int offset = 0, maskOffset = 0;
for (int y = 0; y> 3)];
int v = 1 << (7 - (x & 0x7));
buffer[offset + ao] = (m & v) != 0 ? (byte)0xff : 0;
offset += 4;
}
maskOffset += maskBpl;
}
} else {
if (image.alpha != -1) {
hasAlpha = true;
int alpha = image.alpha;
byte a = (byte)alpha;
for (int offset=0; offset