Spec-Zone .ru
спецификации, руководства, описания, API
|
001/* 002 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Oracle designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Oracle in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022 * or visit www.oracle.com if you need additional information or have any 023 * questions. 024 */ 025 026package javafx.embed.swt; 027 028import java.nio.ByteBuffer; 029import java.nio.IntBuffer; 030import java.security.AccessController; 031import java.security.PrivilegedExceptionAction; 032 033import org.eclipse.swt.SWT; 034import org.eclipse.swt.graphics.ImageData; 035import org.eclipse.swt.graphics.PaletteData; 036import org.eclipse.swt.graphics.RGB; 037 038import java.lang.reflect.Method; 039import java.lang.reflect.Field; 040 041import javafx.scene.image.PixelFormat; 042import javafx.scene.image.PixelReader; 043import javafx.scene.image.PixelWriter; 044import javafx.scene.image.WritableImage; 045import javafx.scene.image.Image; 046import javafx.scene.image.WritablePixelFormat; 047 048/** 049 * This class provides utility methods for converting data types between 050 * SWT and JavaFX formats. 051 */ 052public class SWTFXUtils { 053 private SWTFXUtils() {} // no instances 054 055 /** 056 * Snapshots the specified {@link ImageData} and stores a copy of 057 * its pixels into a JavaFX {@link Image} object, creating a new 058 * object if needed. 059 * The returned {@code Image} will be a static snapshot of the state 060 * of the pixels in the {@code ImageData} at the time the method 061 * completes. Further changes to the {@code ImageData} will not 062 * be reflected in the {@code Image}. 063 * <p> 064 * The optional JavaFX {@link WritableImage} parameter may be reused 065 * to store the copy of the pixels. 066 * A new {@code Image} will be created if the supplied object is null, 067 * is too small or of a type which the image pixels cannot be easily 068 * converted into. 069 * 070 * @param imageData the {@code ImageData} object to be converted 071 * @param image an optional {@code WritableImage} object that can be 072 * used to store the returned pixel data 073 * @return an {@code Image} object representing a snapshot of the 074 * current pixels in the {@code ImageData}, or null if 075 * the {@code Image} is not readable. 076 */ 077 public static WritableImage toFXImage(ImageData imageData, 078 WritableImage image) { 079 byte[] data = convertImage(imageData); 080 if (data == null) return null; 081 int width = imageData.width; 082 int height = imageData.height; 083 if (image != null) { 084 int iw = (int) image.getWidth(); 085 int ih = (int) image.getHeight(); 086 if (iw < width || ih < height) { 087 image = null; 088 } else if (width < iw || height < ih) { 089 int empty[] = new int[iw]; 090 PixelWriter pw = image.getPixelWriter(); 091 PixelFormat<IntBuffer> pf = PixelFormat.getIntArgbPreInstance(); 092 if (width < iw) { 093 pw.setPixels(width, 0, iw-width, height, pf, empty, 0, 0); 094 } 095 if (height < ih) { 096 pw.setPixels(0, height, iw, ih-height, pf, empty, 0, 0); 097 } 098 } 099 } 100 if (image == null) { 101 image = new WritableImage(width, height); 102 } 103 PixelWriter pw = image.getPixelWriter(); 104 int scan = width * 4; 105 PixelFormat<ByteBuffer> pf = PixelFormat.getByteBgraInstance(); 106 pw.setPixels(0, 0, width, height, pf, data, 0, scan); 107 return image; 108 } 109 110 /** 111 * Snapshots the specified JavaFX {@link Image} object and stores a 112 * copy of its pixels into a new {@link ImageData} object. 113 * The method will only convert a JavaFX {@code Image} that is readable 114 * as per the conditions on the 115 * {@link Image#getPixelReader() Image.getPixelReader()} 116 * method. 117 * If the {@code Image} is not readable, as determined by its 118 * {@code getPixelReader()} method, then this method will return null. 119 * If the {@code Image} is a writable, or other dynamic image, then 120 * the {@code ImageData} will only be set to the current state of 121 * the pixels in the image as determined by its {@link PixelReader}. 122 * Further changes to the pixels of the {@code Image} will not be 123 * reflected in the returned {@code ImageData}. 124 * <p> 125 * The optional {@code ImageData} parameter may be reused to store 126 * the copy of the pixels. 127 * A new {@code ImageData} will be created if the supplied object 128 * is null, is too small or of a type which the image pixels cannot 129 * be easily converted into. 130 * 131 * @param image the JavaFX {@code Image} to be converted 132 * @param imageData an optional {@code ImageData} object that may be 133 * used to store the returned pixel data 134 * @return a {@code ImageData} containing a snapshot of the JavaFX 135 * {@code Image}, or null if the {@code Image} is not readable. 136 */ 137 public static ImageData fromFXImage(Image image, ImageData imageData) { 138 PixelReader pr = image.getPixelReader(); 139 if (pr == null) { 140 return null; 141 } 142 int width = (int) image.getWidth(); 143 int height = (int) image.getHeight(); 144 int bpr = width * 4; 145 int dataSize = bpr * height; 146 byte[] buffer = new byte[dataSize]; 147 WritablePixelFormat<ByteBuffer> pf = PixelFormat.getByteBgraInstance(); 148 pr.getPixels(0, 0, width, height, pf, buffer, 0, bpr); 149 byte[] alphaData = new byte[width * height]; 150 for (int y = 0, offset = 0, alphaOffset = 0; y < height; y++) { 151 for (int x = 0; x < width; x++, offset += 4) { 152 byte alpha = buffer[offset+3]; 153 buffer[offset+3] = 0; 154 alphaData[alphaOffset++] = alpha; 155 } 156 } 157 PaletteData palette = new PaletteData(0xFF00, 0xFF0000, 0xFF000000); 158 imageData = new ImageData(width, height, 32, palette, 4, buffer); 159 imageData.alphaData = alphaData; 160 return imageData; 161 } 162 163 private static int blitSrc; 164 private static boolean blitSrcCache; 165 private static int BLIT_SRC() throws Exception { 166 if (!blitSrcCache) { 167 blitSrc = readValue("BLIT_SRC"); 168 blitSrcCache = true; 169 } 170 return blitSrc; 171 } 172 173 private static int alphaOpaque; 174 private static boolean alphaOpaqueCache; 175 private static int ALPHA_OPAQUE() throws Exception { 176 if (!alphaOpaqueCache) { 177 alphaOpaque = readValue("ALPHA_OPAQUE"); 178 alphaOpaqueCache = true; 179 } 180 return alphaOpaque; 181 } 182 183 private static int msbFirst; 184 private static boolean msbFirstCache; 185 private static int MSB_FIRST() throws Exception { 186 if (!msbFirstCache) { 187 msbFirst = readValue("MSB_FIRST"); 188 msbFirstCache = true; 189 } 190 return msbFirst; 191 } 192 193 private static int readValue(final String name) throws Exception { 194 final Class<?> clazz = ImageData.class; 195 return AccessController.doPrivileged( 196 new PrivilegedExceptionAction<Integer>() { 197 public Integer run() throws Exception { 198 Field field = clazz.getDeclaredField(name); 199 field.setAccessible(true); 200 return field.getInt(clazz); 201 } 202 }); 203 } 204 205 private static Method blitDirect; 206 private static void blit(int op, 207 byte[] srcData, int srcDepth, int srcStride, int srcOrder, 208 int srcX, int srcY, int srcWidth, int srcHeight, 209 int srcRedMask, int srcGreenMask, int srcBlueMask, 210 int alphaMode, byte[] alphaData, int alphaStride, 211 int alphaX, int alphaY, 212 byte[] destData, int destDepth, int destStride, int destOrder, 213 int destX, int destY, int destWidth, int destHeight, 214 int destRedMask, int destGreenMask, int destBlueMask, 215 boolean flipX, boolean flipY) throws Exception { 216 final Class<?> clazz = ImageData.class; 217 if (blitDirect == null) { 218 Class<?> I = Integer.TYPE, B = Boolean.TYPE, BA = byte[].class; 219 final Class<?>[] argClasses = {I, 220 BA, I, I, I, 221 I, I, I, I, 222 I, I, I, 223 I, BA, I, I, I, 224 BA, I, I, I, 225 I, I, I, I, 226 I, I, I, B, B}; 227 blitDirect = AccessController.doPrivileged( 228 new PrivilegedExceptionAction<Method>() { 229 public Method run() throws Exception { 230 Method method = clazz. 231 getDeclaredMethod("blit", argClasses); 232 method.setAccessible(true); 233 return method; 234 } 235 }); 236 } 237 if (blitDirect != null) { 238 blitDirect.invoke(clazz, op, 239 srcData, srcDepth, srcStride, srcOrder, 240 srcX, srcY, srcWidth, srcHeight, 241 srcRedMask, srcGreenMask, srcBlueMask, 242 alphaMode, alphaData, alphaStride, alphaX, alphaY, 243 destData, destDepth, destStride, destOrder, 244 destX, destY, destWidth, destHeight, 245 destRedMask, destGreenMask, destBlueMask, 246 flipX, flipY); 247 } 248 } 249 250 private static Method blitPalette; 251 private static void blit(int op, 252 byte[] srcData, int srcDepth, int srcStride, int srcOrder, 253 int srcX, int srcY, int srcWidth, int srcHeight, 254 byte[] srcReds, byte[] srcGreens, byte[] srcBlues, 255 int alphaMode, byte[] alphaData, int alphaStride, 256 int alphaX, int alphaY, 257 byte[] destData, int destDepth, int destStride, int destOrder, 258 int destX, int destY, int destWidth, int destHeight, 259 int destRedMask, int destGreenMask, int destBlueMask, 260 boolean flipX, boolean flipY) throws Exception { 261 final Class<?> clazz = ImageData.class; 262 if (blitPalette == null) { 263 Class<?> I = Integer.TYPE, B = Boolean.TYPE, BA = byte[].class; 264 final Class<?>[] argClasses = {I, 265 BA, I, I, I, 266 I, I, I, I, 267 BA, BA, BA, 268 I, BA, I, I, I, 269 BA, I, I, I, 270 I, I, I, I, 271 I, I, I, B, B}; 272 blitPalette = AccessController.doPrivileged( 273 new PrivilegedExceptionAction<Method>() { 274 public Method run() throws Exception { 275 Method method = clazz. 276 getDeclaredMethod("blit", argClasses); 277 method.setAccessible(true); 278 return method; 279 } 280 }); 281 } 282 if (blitPalette != null) { 283 blitPalette.invoke(clazz, op, 284 srcData, srcDepth, srcStride, srcOrder, 285 srcX, srcY, srcWidth, srcHeight, 286 srcReds, srcGreens, srcBlues, 287 alphaMode, alphaData, alphaStride, alphaX, alphaY, 288 destData, destDepth, destStride, destOrder, 289 destX, destY, destWidth, destHeight, 290 destRedMask, destGreenMask, destBlueMask, 291 flipX, flipY); 292 } 293 } 294 295 private static Method getByteOrderMethod; 296 private static int getByteOrder(ImageData image) throws Exception { 297 final Class<?> clazz = ImageData.class; 298 if (getByteOrderMethod != null) { 299 getByteOrderMethod = AccessController.doPrivileged( 300 new PrivilegedExceptionAction<Method>() { 301 public Method run() throws Exception { 302 Method method = clazz.getDeclaredMethod("getByteOrder"); 303 method.setAccessible(true); 304 return method; 305 } 306 }); 307 } 308 if (getByteOrderMethod != null) { 309 return (Integer)getByteOrderMethod.invoke(image); 310 } 311 return MSB_FIRST(); 312 } 313 314 private static byte[] convertImage(ImageData image) { 315 byte[] buffer = null; 316 try { 317 PaletteData palette = image.palette; 318 if (!(((image.depth == 1 || image.depth == 2 || 319 image.depth == 4 || image.depth == 8) && 320 !palette.isDirect) || 321 ((image.depth == 8) || (image.depth == 16 || 322 image.depth == 24 || image.depth == 32) 323 && palette.isDirect))) { 324 return null; 325 } 326 327 final int BLIT_SRC = BLIT_SRC(); 328 final int ALPHA_OPAQUE = ALPHA_OPAQUE(); 329 final int MSB_FIRST = MSB_FIRST(); 330 331 int width = image.width; 332 int height = image.height; 333 int byteOrder = getByteOrder(image); 334 int ao = 3; 335 int redMask = 0xFF00; 336 int greenMask = 0xFF0000; 337 int blueMask = 0xFF000000; 338 int dataSize = width * height * 4; 339 int bpr = width * 4; 340 buffer = new byte[dataSize]; 341 342 if (palette.isDirect) { 343 blit(BLIT_SRC, 344 image.data, image.depth, image.bytesPerLine, byteOrder, 345 0, 0, width, height, 346 palette.redMask, palette.greenMask, palette.blueMask, 347 ALPHA_OPAQUE, null, 0, 0, 0, 348 buffer, 32, bpr, MSB_FIRST, 0, 0, width, height, 349 redMask, greenMask, blueMask, 350 false, false); 351 } else { 352 RGB[] rgbs = palette.getRGBs(); 353 int length = rgbs.length; 354 byte[] srcReds = new byte[length]; 355 byte[] srcGreens = new byte[length]; 356 byte[] srcBlues = new byte[length]; 357 for (int i = 0; i < rgbs.length; i++) { 358 RGB rgb = rgbs[i]; 359 if (rgb == null) continue; 360 srcReds[i] = (byte)rgb.red; 361 srcGreens[i] = (byte)rgb.green; 362 srcBlues[i] = (byte)rgb.blue; 363 } 364 blit(BLIT_SRC, 365 image.data, image.depth, image.bytesPerLine, byteOrder, 366 0, 0, width, height, srcReds, srcGreens, srcBlues, 367 ALPHA_OPAQUE, null, 0, 0, 0, 368 buffer, 32, bpr, MSB_FIRST, 0, 0, width, height, 369 redMask, greenMask, blueMask, 370 false, false); 371 } 372 373 /* Initialize transparency */ 374 int transparency = image.getTransparencyType(); 375 boolean hasAlpha = transparency != SWT.TRANSPARENCY_NONE; 376 if (transparency == SWT.TRANSPARENCY_MASK || 377 image.transparentPixel != -1) { 378 ImageData maskImage = image.getTransparencyMask(); 379 byte[] maskData = maskImage.data; 380 int maskBpl = maskImage.bytesPerLine; 381 int offset = 0, maskOffset = 0; 382 for (int y = 0; y<height; y++) { 383 for (int x = 0; x<width; x++) { 384 int m = maskData[maskOffset + (x >> 3)]; 385 int v = 1 << (7 - (x & 0x7)); 386 buffer[offset + ao] = (m & v) != 0 ? (byte)0xff : 0; 387 offset += 4; 388 } 389 maskOffset += maskBpl; 390 } 391 } else { 392 if (image.alpha != -1) { 393 hasAlpha = true; 394 int alpha = image.alpha; 395 byte a = (byte)alpha; 396 for (int offset=0; offset<buffer.length; offset+=4) { 397 buffer[offset + ao] = a; 398 } 399 } else if (image.alphaData != null) { 400 hasAlpha = true; 401 byte[] alphaData = new byte[image.alphaData.length]; 402 System.arraycopy(image.alphaData, 0, 403 alphaData, 0, alphaData.length); 404 int offset = 0, alphaOffset = 0; 405 for (int y = 0; y<height; y++) { 406 for (int x = 0; x<width; x++) { 407 buffer[offset + ao] = alphaData[alphaOffset]; 408 offset += 4; 409 alphaOffset += 1; 410 } 411 } 412 } 413 } 414 if (!hasAlpha) { 415 for (int offset=0; offset<buffer.length; offset+=4) { 416 buffer[offset + ao] = (byte)0xFF; 417 } 418 } 419 } catch (Exception e) { 420 return null; 421 } 422 return buffer; 423 } 424}