1 /* 2 * Copyright (c) 2012, 2013, 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 javafx.scene.image.Image; 33 import javafx.scene.image.PixelFormat; 34 import javafx.scene.image.PixelReader; 35 import javafx.scene.image.PixelWriter; 36 import javafx.scene.image.WritableImage; 37 import javafx.scene.image.WritablePixelFormat; 38 import sun.awt.image.IntegerComponentRaster; 39 40 /** 41 * This class provides utility methods for converting data types between 42 * Swing/AWT and JavaFX formats. 43 */ 44 public class SwingFXUtils { 45 private SwingFXUtils() {} // no instances 46 47 /** 48 * Snapshots the specified {@link BufferedImage} and stores a copy of 49 * its pixels into a JavaFX {@link Image} object, creating a new 50 * object if needed. 51 * The returned {@code Image} will be a static snapshot of the state 52 * of the pixels in the {@code BufferedImage} at the time the method 53 * completes. Further changes to the {@code BufferedImage} will not 54 * be reflected in the {@code Image}. 55 * <p> 56 * The optional JavaFX {@link WritableImage} parameter may be reused 57 * to store the copy of the pixels. 58 * A new {@code Image} will be created if the supplied object is null, 59 * is too small or of a type which the image pixels cannot be easily 60 * converted into. 61 * 62 * @param bimg the {@code BufferedImage} object to be converted 63 * @param wimg an optional {@code WritableImage} object that can be 64 * used to store the returned pixel data 65 * @return an {@code Image} object representing a snapshot of the 66 * current pixels in the {@code BufferedImage}. 67 * @since 2.2 68 */ 69 public static WritableImage toFXImage(BufferedImage bimg, WritableImage wimg) { 70 int bw = bimg.getWidth(); 71 int bh = bimg.getHeight(); 72 switch (bimg.getType()) { 73 case BufferedImage.TYPE_INT_ARGB: 74 case BufferedImage.TYPE_INT_ARGB_PRE: 75 break; 76 default: 77 BufferedImage converted = 78 new BufferedImage(bw, bh, BufferedImage.TYPE_INT_ARGB_PRE); 79 Graphics2D g2d = converted.createGraphics(); 80 g2d.drawImage(bimg, 0, 0, null); 81 g2d.dispose(); 82 bimg = converted; 83 break; 84 } 85 // assert(bimg.getType == TYPE_INT_ARGB[_PRE]); 86 if (wimg != null) { 87 int iw = (int) wimg.getWidth(); 88 int ih = (int) wimg.getHeight(); 89 if (iw < bw || ih < bh) { 90 wimg = null; 91 } else if (bw < iw || bh < ih) { 92 int empty[] = new int[iw]; 93 PixelWriter pw = wimg.getPixelWriter(); 94 PixelFormat pf = PixelFormat.getIntArgbPreInstance(); 95 if (bw < iw) { 96 pw.setPixels(bw, 0, iw-bw, bh, pf, empty, 0, 0); 97 } 98 if (bh < ih) { 99 pw.setPixels(0, bh, iw, ih-bh, pf, empty, 0, 0); 100 } 101 } 102 } 103 if (wimg == null) { 104 wimg = new WritableImage(bw, bh); 105 } 106 PixelWriter pw = wimg.getPixelWriter(); 107 IntegerComponentRaster icr = (IntegerComponentRaster) bimg.getRaster(); 108 int data[] = icr.getDataStorage(); 109 int offset = icr.getDataOffset(0); 110 int scan = icr.getScanlineStride(); 111 PixelFormat<IntBuffer> pf = (bimg.isAlphaPremultiplied() ? 112 PixelFormat.getIntArgbPreInstance() : 113 PixelFormat.getIntArgbInstance()); 114 pw.setPixels(0, 0, bw, bh, pf, data, offset, scan); 115 return wimg; 116 } 117 118 /** 119 * Snapshots the specified JavaFX {@link Image} object and stores a 120 * copy of its pixels into a {@link BufferedImage} object, creating 121 * a new object if needed. 122 * The method will only convert a JavaFX {@code Image} that is readable 123 * as per the conditions on the 124 * {@link Image#getPixelReader() Image.getPixelReader()} 125 * method. 126 * If the {@code Image} is not readable, as determined by its 127 * {@code getPixelReader()} method, then this method will return null. 128 * If the {@code Image} is a writable, or other dynamic image, then 129 * the {@code BufferedImage} will only be set to the current state of 130 * the pixels in the image as determined by its {@link PixelReader}. 131 * Further changes to the pixels of the {@code Image} will not be 132 * reflected in the returned {@code BufferedImage}. 133 * <p> 134 * The optional {@code BufferedImage} parameter may be reused to store 135 * the copy of the pixels. 136 * A new {@code BufferedImage} will be created if the supplied object 137 * is null, is too small or of a type which the image pixels cannot 138 * be easily converted into. 139 * 140 * @param img the JavaFX {@code Image} to be converted 141 * @param bimg an optional {@code BufferedImage} object that may be 142 * used to store the returned pixel data 143 * @return a {@code BufferedImage} containing a snapshot of the JavaFX 144 * {@code Image}, or null if the {@code Image} is not readable. 145 * @since 2.2 146 */ 147 public static BufferedImage fromFXImage(Image img, BufferedImage bimg) { 148 PixelReader pr = img.getPixelReader(); 149 if (pr == null) { 150 return null; 151 } 152 int iw = (int) img.getWidth(); 153 int ih = (int) img.getHeight(); 154 if (bimg != null) { 155 int type = bimg.getType(); 156 int bw = bimg.getWidth(); 157 int bh = bimg.getHeight(); 158 if (bw < iw || bh < ih || 159 (type != BufferedImage.TYPE_INT_ARGB && 160 type != BufferedImage.TYPE_INT_ARGB_PRE)) 161 { 162 bimg = null; 163 } else if (iw < bw || ih < bh) { 164 Graphics2D g2d = bimg.createGraphics(); 165 g2d.setComposite(AlphaComposite.Clear); 166 g2d.fillRect(0, 0, bw, bh); 167 g2d.dispose(); 168 } 169 } 170 if (bimg == null) { 171 bimg = new BufferedImage(iw, ih, BufferedImage.TYPE_INT_ARGB_PRE); 172 } 173 IntegerComponentRaster icr = (IntegerComponentRaster) bimg.getRaster(); 174 int offset = icr.getDataOffset(0); 175 int scan = icr.getScanlineStride(); 176 int data[] = icr.getDataStorage(); 177 WritablePixelFormat<IntBuffer> pf = (bimg.isAlphaPremultiplied() ? 178 PixelFormat.getIntArgbPreInstance() : 179 PixelFormat.getIntArgbInstance()); 180 pr.getPixels(0, 0, iw, ih, pf, data, offset, scan); 181 return bimg; 182 } 183 }