1 /* 2 * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javafx.embed.swing; 27 28 import java.awt.AlphaComposite; 29 import java.awt.Graphics2D; 30 import java.awt.image.BufferedImage; 31 import java.nio.IntBuffer; 32 import java.util.Set; 33 import java.util.HashSet; 34 import javafx.application.Platform; 35 import javafx.scene.image.Image; 36 import javafx.scene.image.PixelFormat; 37 import javafx.scene.image.PixelReader; 38 import javafx.scene.image.PixelWriter; 39 import javafx.scene.image.WritableImage; 40 import javafx.scene.image.WritablePixelFormat; 41 import javafx.scene.paint.Color; 42 import com.sun.javafx.tk.Toolkit; 43 import javax.swing.SwingUtilities; 44 import sun.awt.image.IntegerComponentRaster; 45 46 /** 47 * This class provides utility methods for converting data types between 48 * Swing/AWT and JavaFX formats. 49 * @since JavaFX 2.2 50 */ 51 public class SwingFXUtils { 52 private SwingFXUtils() {} // no instances 53 54 /** 55 * Snapshots the specified {@link BufferedImage} and stores a copy of 56 * its pixels into a JavaFX {@link Image} object, creating a new 57 * object if needed. 58 * The returned {@code Image} will be a static snapshot of the state 59 * of the pixels in the {@code BufferedImage} at the time the method 60 * completes. Further changes to the {@code BufferedImage} will not 61 * be reflected in the {@code Image}. 62 * <p> 63 * The optional JavaFX {@link WritableImage} parameter may be reused 64 * to store the copy of the pixels. 94 int iw = (int) wimg.getWidth(); 95 int ih = (int) wimg.getHeight(); 96 if (iw < bw || ih < bh) { 97 wimg = null; 98 } else if (bw < iw || bh < ih) { 99 int empty[] = new int[iw]; 100 PixelWriter pw = wimg.getPixelWriter(); 101 PixelFormat<IntBuffer> pf = PixelFormat.getIntArgbPreInstance(); 102 if (bw < iw) { 103 pw.setPixels(bw, 0, iw-bw, bh, pf, empty, 0, 0); 104 } 105 if (bh < ih) { 106 pw.setPixels(0, bh, iw, ih-bh, pf, empty, 0, 0); 107 } 108 } 109 } 110 if (wimg == null) { 111 wimg = new WritableImage(bw, bh); 112 } 113 PixelWriter pw = wimg.getPixelWriter(); 114 IntegerComponentRaster icr = (IntegerComponentRaster) bimg.getRaster(); 115 int data[] = icr.getDataStorage(); 116 int offset = icr.getDataOffset(0); 117 int scan = icr.getScanlineStride(); 118 PixelFormat<IntBuffer> pf = (bimg.isAlphaPremultiplied() ? 119 PixelFormat.getIntArgbPreInstance() : 120 PixelFormat.getIntArgbInstance()); 121 pw.setPixels(0, 0, bw, bh, pf, data, offset, scan); 122 return wimg; 123 } 124 125 /** 126 * Determine the optimal BufferedImage type to use for the specified 127 * {@code fxFormat} allowing for the specified {@code bimg} to be used 128 * as a potential default storage space if it is not null and is compatible. 129 * 130 * @param fxFormat the PixelFormat of the source FX Image 131 * @param bimg an optional existing {@code BufferedImage} to be used 132 * for storage if it is compatible, or null 133 * @return 134 */ 135 static int 136 getBestBufferedImageType(PixelFormat<?> fxFormat, BufferedImage bimg, 137 boolean isOpaque) 264 case BYTE_RGB: 265 srcPixelsAreOpaque = true; 266 break; 267 } 268 int prefBimgType = getBestBufferedImageType(pr.getPixelFormat(), bimg, srcPixelsAreOpaque); 269 if (bimg != null) { 270 int bw = bimg.getWidth(); 271 int bh = bimg.getHeight(); 272 if (bw < iw || bh < ih || bimg.getType() != prefBimgType) { 273 bimg = null; 274 } else if (iw < bw || ih < bh) { 275 Graphics2D g2d = bimg.createGraphics(); 276 g2d.setComposite(AlphaComposite.Clear); 277 g2d.fillRect(0, 0, bw, bh); 278 g2d.dispose(); 279 } 280 } 281 if (bimg == null) { 282 bimg = new BufferedImage(iw, ih, prefBimgType); 283 } 284 IntegerComponentRaster icr = (IntegerComponentRaster) bimg.getRaster(); 285 int offset = icr.getDataOffset(0); 286 int scan = icr.getScanlineStride(); 287 int data[] = icr.getDataStorage(); 288 WritablePixelFormat<IntBuffer> pf = getAssociatedPixelFormat(bimg); 289 pr.getPixels(0, 0, iw, ih, pf, data, offset, scan); 290 return bimg; 291 } 292 293 /** 294 * If called from the FX Application Thread 295 * invokes a runnable directly blocking the calling code 296 * Otherwise 297 * uses Platform.runLater without blocking 298 */ 299 static void runOnFxThread(Runnable runnable) { 300 if (Platform.isFxApplicationThread()) { 301 runnable.run(); 302 } else { 303 Platform.runLater(runnable); 304 } 305 } 306 307 /** 308 * If called from the event dispatch thread 309 * invokes a runnable directly blocking the calling code 310 * Otherwise 311 * uses SwingUtilities.invokeLater without blocking 312 */ 313 static void runOnEDT(final Runnable r) { 314 if (SwingUtilities.isEventDispatchThread()) { 315 r.run(); 316 } else { 317 SwingUtilities.invokeLater(r); 318 } 319 } 320 321 private static final Set<Object> eventLoopKeys = new HashSet<>(); 322 323 /** 324 * The runnable is responsible for leaving the nested event loop. 325 */ 326 static void runOnEDTAndWait(Object nestedLoopKey, Runnable r) { 327 Toolkit.getToolkit().checkFxUserThread(); 328 329 if (SwingUtilities.isEventDispatchThread()) { 330 r.run(); 331 } else { 332 eventLoopKeys.add(nestedLoopKey); 333 SwingUtilities.invokeLater(r); 334 Toolkit.getToolkit().enterNestedEventLoop(nestedLoopKey); 335 } 336 } 337 338 static void leaveFXNestedLoop(Object nestedLoopKey) { 339 if (!eventLoopKeys.contains(nestedLoopKey)) return; 340 341 if (Platform.isFxApplicationThread()) { 342 Toolkit.getToolkit().exitNestedEventLoop(nestedLoopKey, null); 343 } else { 344 Platform.runLater(() -> { 345 Toolkit.getToolkit().exitNestedEventLoop(nestedLoopKey, null); 346 }); 347 } 348 349 eventLoopKeys.remove(nestedLoopKey); 350 } 351 352 } | 1 /* 2 * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javafx.embed.swing; 27 28 import java.awt.AlphaComposite; 29 import java.awt.Graphics2D; 30 import java.awt.image.BufferedImage; 31 import java.awt.image.DataBufferInt; 32 import java.awt.image.SampleModel; 33 import java.awt.image.SinglePixelPackedSampleModel; 34 import java.nio.IntBuffer; 35 import javafx.scene.image.Image; 36 import javafx.scene.image.PixelFormat; 37 import javafx.scene.image.PixelReader; 38 import javafx.scene.image.PixelWriter; 39 import javafx.scene.image.WritableImage; 40 import javafx.scene.image.WritablePixelFormat; 41 import javafx.scene.paint.Color; 42 43 /** 44 * This class provides utility methods for converting data types between 45 * Swing/AWT and JavaFX formats. 46 * @since JavaFX 2.2 47 */ 48 public class SwingFXUtils { 49 private SwingFXUtils() {} // no instances 50 51 /** 52 * Snapshots the specified {@link BufferedImage} and stores a copy of 53 * its pixels into a JavaFX {@link Image} object, creating a new 54 * object if needed. 55 * The returned {@code Image} will be a static snapshot of the state 56 * of the pixels in the {@code BufferedImage} at the time the method 57 * completes. Further changes to the {@code BufferedImage} will not 58 * be reflected in the {@code Image}. 59 * <p> 60 * The optional JavaFX {@link WritableImage} parameter may be reused 61 * to store the copy of the pixels. 91 int iw = (int) wimg.getWidth(); 92 int ih = (int) wimg.getHeight(); 93 if (iw < bw || ih < bh) { 94 wimg = null; 95 } else if (bw < iw || bh < ih) { 96 int empty[] = new int[iw]; 97 PixelWriter pw = wimg.getPixelWriter(); 98 PixelFormat<IntBuffer> pf = PixelFormat.getIntArgbPreInstance(); 99 if (bw < iw) { 100 pw.setPixels(bw, 0, iw-bw, bh, pf, empty, 0, 0); 101 } 102 if (bh < ih) { 103 pw.setPixels(0, bh, iw, ih-bh, pf, empty, 0, 0); 104 } 105 } 106 } 107 if (wimg == null) { 108 wimg = new WritableImage(bw, bh); 109 } 110 PixelWriter pw = wimg.getPixelWriter(); 111 DataBufferInt db = (DataBufferInt)bimg.getRaster().getDataBuffer(); 112 int data[] = db.getData(); 113 int offset = bimg.getRaster().getDataBuffer().getOffset(); 114 int scan = 0; 115 SampleModel sm = bimg.getRaster().getSampleModel(); 116 if (sm instanceof SinglePixelPackedSampleModel) { 117 scan = ((SinglePixelPackedSampleModel)sm).getScanlineStride(); 118 } 119 120 PixelFormat<IntBuffer> pf = (bimg.isAlphaPremultiplied() ? 121 PixelFormat.getIntArgbPreInstance() : 122 PixelFormat.getIntArgbInstance()); 123 pw.setPixels(0, 0, bw, bh, pf, data, offset, scan); 124 return wimg; 125 } 126 127 /** 128 * Determine the optimal BufferedImage type to use for the specified 129 * {@code fxFormat} allowing for the specified {@code bimg} to be used 130 * as a potential default storage space if it is not null and is compatible. 131 * 132 * @param fxFormat the PixelFormat of the source FX Image 133 * @param bimg an optional existing {@code BufferedImage} to be used 134 * for storage if it is compatible, or null 135 * @return 136 */ 137 static int 138 getBestBufferedImageType(PixelFormat<?> fxFormat, BufferedImage bimg, 139 boolean isOpaque) 266 case BYTE_RGB: 267 srcPixelsAreOpaque = true; 268 break; 269 } 270 int prefBimgType = getBestBufferedImageType(pr.getPixelFormat(), bimg, srcPixelsAreOpaque); 271 if (bimg != null) { 272 int bw = bimg.getWidth(); 273 int bh = bimg.getHeight(); 274 if (bw < iw || bh < ih || bimg.getType() != prefBimgType) { 275 bimg = null; 276 } else if (iw < bw || ih < bh) { 277 Graphics2D g2d = bimg.createGraphics(); 278 g2d.setComposite(AlphaComposite.Clear); 279 g2d.fillRect(0, 0, bw, bh); 280 g2d.dispose(); 281 } 282 } 283 if (bimg == null) { 284 bimg = new BufferedImage(iw, ih, prefBimgType); 285 } 286 DataBufferInt db = (DataBufferInt)bimg.getRaster().getDataBuffer(); 287 int data[] = db.getData(); 288 int offset = bimg.getRaster().getDataBuffer().getOffset(); 289 int scan = 0; 290 SampleModel sm = bimg.getRaster().getSampleModel(); 291 if (sm instanceof SinglePixelPackedSampleModel) { 292 scan = ((SinglePixelPackedSampleModel)sm).getScanlineStride(); 293 } 294 295 WritablePixelFormat<IntBuffer> pf = getAssociatedPixelFormat(bimg); 296 pr.getPixels(0, 0, iw, ih, pf, data, offset, scan); 297 return bimg; 298 } 299 } |