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 }
|
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 java.util.Set;
36 import java.util.HashSet;
37 import javafx.application.Platform;
38 import javafx.scene.image.Image;
39 import javafx.scene.image.PixelFormat;
40 import javafx.scene.image.PixelReader;
41 import javafx.scene.image.PixelWriter;
42 import javafx.scene.image.WritableImage;
43 import javafx.scene.image.WritablePixelFormat;
44 import javafx.scene.paint.Color;
45 import com.sun.javafx.tk.Toolkit;
46 import javax.swing.SwingUtilities;
47
48 /**
49 * This class provides utility methods for converting data types between
50 * Swing/AWT and JavaFX formats.
51 * @since JavaFX 2.2
52 */
53 public class SwingFXUtils {
54 private SwingFXUtils() {} // no instances
55
56 /**
57 * Snapshots the specified {@link BufferedImage} and stores a copy of
58 * its pixels into a JavaFX {@link Image} object, creating a new
59 * object if needed.
60 * The returned {@code Image} will be a static snapshot of the state
61 * of the pixels in the {@code BufferedImage} at the time the method
62 * completes. Further changes to the {@code BufferedImage} will not
63 * be reflected in the {@code Image}.
64 * <p>
65 * The optional JavaFX {@link WritableImage} parameter may be reused
66 * to store the copy of the pixels.
96 int iw = (int) wimg.getWidth();
97 int ih = (int) wimg.getHeight();
98 if (iw < bw || ih < bh) {
99 wimg = null;
100 } else if (bw < iw || bh < ih) {
101 int empty[] = new int[iw];
102 PixelWriter pw = wimg.getPixelWriter();
103 PixelFormat<IntBuffer> pf = PixelFormat.getIntArgbPreInstance();
104 if (bw < iw) {
105 pw.setPixels(bw, 0, iw-bw, bh, pf, empty, 0, 0);
106 }
107 if (bh < ih) {
108 pw.setPixels(0, bh, iw, ih-bh, pf, empty, 0, 0);
109 }
110 }
111 }
112 if (wimg == null) {
113 wimg = new WritableImage(bw, bh);
114 }
115 PixelWriter pw = wimg.getPixelWriter();
116 DataBufferInt db = (DataBufferInt)bimg.getRaster().getDataBuffer();
117 int data[] = db.getData();
118 int offset = bimg.getRaster().getDataBuffer().getOffset();
119 int scan = 0;
120 SampleModel sm = bimg.getRaster().getSampleModel();
121 if (sm instanceof SinglePixelPackedSampleModel) {
122 scan = ((SinglePixelPackedSampleModel)sm).getScanlineStride();
123 }
124
125 PixelFormat<IntBuffer> pf = (bimg.isAlphaPremultiplied() ?
126 PixelFormat.getIntArgbPreInstance() :
127 PixelFormat.getIntArgbInstance());
128 pw.setPixels(0, 0, bw, bh, pf, data, offset, scan);
129 return wimg;
130 }
131
132 /**
133 * Determine the optimal BufferedImage type to use for the specified
134 * {@code fxFormat} allowing for the specified {@code bimg} to be used
135 * as a potential default storage space if it is not null and is compatible.
136 *
137 * @param fxFormat the PixelFormat of the source FX Image
138 * @param bimg an optional existing {@code BufferedImage} to be used
139 * for storage if it is compatible, or null
140 * @return
141 */
142 static int
143 getBestBufferedImageType(PixelFormat<?> fxFormat, BufferedImage bimg,
144 boolean isOpaque)
271 case BYTE_RGB:
272 srcPixelsAreOpaque = true;
273 break;
274 }
275 int prefBimgType = getBestBufferedImageType(pr.getPixelFormat(), bimg, srcPixelsAreOpaque);
276 if (bimg != null) {
277 int bw = bimg.getWidth();
278 int bh = bimg.getHeight();
279 if (bw < iw || bh < ih || bimg.getType() != prefBimgType) {
280 bimg = null;
281 } else if (iw < bw || ih < bh) {
282 Graphics2D g2d = bimg.createGraphics();
283 g2d.setComposite(AlphaComposite.Clear);
284 g2d.fillRect(0, 0, bw, bh);
285 g2d.dispose();
286 }
287 }
288 if (bimg == null) {
289 bimg = new BufferedImage(iw, ih, prefBimgType);
290 }
291 DataBufferInt db = (DataBufferInt)bimg.getRaster().getDataBuffer();
292 int data[] = db.getData();
293 int offset = bimg.getRaster().getDataBuffer().getOffset();
294 int scan = 0;
295 SampleModel sm = bimg.getRaster().getSampleModel();
296 if (sm instanceof SinglePixelPackedSampleModel) {
297 scan = ((SinglePixelPackedSampleModel)sm).getScanlineStride();
298 }
299
300 WritablePixelFormat<IntBuffer> pf = getAssociatedPixelFormat(bimg);
301 pr.getPixels(0, 0, iw, ih, pf, data, offset, scan);
302 return bimg;
303 }
304 }
|