1 /* 2 * Copyright (c) 2007, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.jemmy.image; 24 25 import java.awt.AWTException; 26 import java.awt.Rectangle; 27 import java.awt.Robot; 28 import java.awt.Toolkit; 29 30 import java.awt.image.BufferedImage; 31 32 import java.io.BufferedOutputStream; 33 import java.io.ByteArrayOutputStream; 34 import java.io.File; 35 import java.io.FileNotFoundException; 36 import java.io.IOException; 37 import java.io.FileOutputStream; 38 import java.io.OutputStream; 39 40 import java.util.zip.CRC32; 41 import java.util.zip.Deflater; 42 import java.util.zip.DeflaterOutputStream; 43 import org.jemmy.control.ScreenArea; 44 45 /** This class allows to encode BufferedImage into B/W, greyscale or true color PNG 46 * image format with maximum compression.<br> 47 * It also provides complete functionality for capturing full screen, part of 48 * screen or single component, encoding and saving captured image info PNG file. 49 * @author Adam Sotona 50 * @version 1.0 */ 51 public class PNGEncoder extends Object { 52 53 /** black and white image mode. */ 54 public static final byte BW_MODE = 0; 55 /** grey scale image mode. */ 56 public static final byte GREYSCALE_MODE = 1; 57 /** full color image mode. */ 58 public static final byte COLOR_MODE = 2; 59 60 OutputStream out; 61 CRC32 crc; 62 byte mode; 63 64 /** 65 * 66 * @param file 67 * @throws java.io.FileNotFoundException 68 */ 69 public PNGEncoder(File file) throws FileNotFoundException { 70 this(new FileOutputStream(file)); 71 } 72 /** public constructor of PNGEncoder class with greyscale mode by default. 73 * @param out output stream for PNG image format to write into 74 */ 75 public PNGEncoder(OutputStream out) { 76 this(out, GREYSCALE_MODE); 77 } 78 79 /** public constructor of PNGEncoder class. 80 * @param out output stream for PNG image format to write into 81 * @param mode BW_MODE, GREYSCALE_MODE or COLOR_MODE 82 */ 83 public PNGEncoder(OutputStream out, byte mode) { 84 crc=new CRC32(); 85 this.out = out; 86 if (mode<0 || mode>2) 87 throw new IllegalArgumentException("Unknown color mode"); 88 this.mode = mode; 89 } 90 91 void write(int i) throws IOException { 92 byte b[]={(byte)((i>>24)&0xff),(byte)((i>>16)&0xff),(byte)((i>>8)&0xff),(byte)(i&0xff)}; 93 write(b); 94 } 95 96 void write(byte b[]) throws IOException { 97 out.write(b); 98 crc.update(b); 99 } 100 101 /** main encoding method (stays blocked till encoding is finished). 102 * @param image BufferedImage to encode 103 * @throws IOException IOException 104 */ 105 public void encode(BufferedImage image) throws IOException { 106 encode(image, true); 107 } 108 109 /** main encoding method (stays blocked till encoding is finished). 110 * @param image BufferedImage to encode 111 * @param closeStream requests method to close the stream after the image is written 112 * @throws IOException IOException 113 */ 114 public void encode(BufferedImage image, boolean closeStream) throws IOException { 115 int width = image.getWidth(null); 116 int height = image.getHeight(null); 117 final byte id[] = {-119, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13}; 118 write(id); 119 crc.reset(); 120 write("IHDR".getBytes()); 121 write(width); 122 write(height); 123 byte head[]=null; 124 switch (mode) { 125 case BW_MODE: head=new byte[]{1, 0, 0, 0, 0}; break; 126 case GREYSCALE_MODE: head=new byte[]{8, 0, 0, 0, 0}; break; 127 case COLOR_MODE: head=new byte[]{8, 2, 0, 0, 0}; break; 128 } 129 write(head); 130 write((int) crc.getValue()); 131 ByteArrayOutputStream compressed = new ByteArrayOutputStream(65536); 132 BufferedOutputStream bos = new BufferedOutputStream( new DeflaterOutputStream(compressed, new Deflater(9))); 133 int pixel; 134 int color; 135 int colorset; 136 switch (mode) { 137 case BW_MODE: 138 int rest=width%8; 139 int bytes=width/8; 140 for (int y=0;y<height;y++) { 141 bos.write(0); 142 for (int x=0;x<bytes;x++) { 143 colorset=0; 144 for (int sh=0; sh<8; sh++) { 145 pixel=image.getRGB(x*8+sh,y); 146 color=((pixel >> 16) & 0xff); 147 color+=((pixel >> 8) & 0xff); 148 color+=(pixel & 0xff); 149 colorset<<=1; 150 if (color>=3*128) 151 colorset|=1; 152 } 153 bos.write((byte)colorset); 154 } 155 if (rest>0) { 156 colorset=0; 157 for (int sh=0; sh<width%8; sh++) { 158 pixel=image.getRGB(bytes*8+sh,y); 159 color=((pixel >> 16) & 0xff); 160 color+=((pixel >> 8) & 0xff); 161 color+=(pixel & 0xff); 162 colorset<<=1; 163 if (color>=3*128) 164 colorset|=1; 165 } 166 colorset<<=8-rest; 167 bos.write((byte)colorset); 168 } 169 } 170 break; 171 case GREYSCALE_MODE: 172 for (int y=0;y<height;y++) { 173 bos.write(0); 174 for (int x=0;x<width;x++) { 175 pixel=image.getRGB(x,y); 176 color=((pixel >> 16) & 0xff); 177 color+=((pixel >> 8) & 0xff); 178 color+=(pixel & 0xff); 179 bos.write((byte)(color/3)); 180 } 181 } 182 break; 183 case COLOR_MODE: 184 for (int y=0;y<height;y++) { 185 bos.write(0); 186 for (int x=0;x<width;x++) { 187 pixel=image.getRGB(x,y); 188 bos.write((byte)((pixel >> 16) & 0xff)); 189 bos.write((byte)((pixel >> 8) & 0xff)); 190 bos.write((byte)(pixel & 0xff)); 191 } 192 } 193 break; 194 } 195 bos.close(); 196 write(compressed.size()); 197 crc.reset(); 198 write("IDAT".getBytes()); 199 write(compressed.toByteArray()); 200 write((int) crc.getValue()); 201 write(0); 202 crc.reset(); 203 write("IEND".getBytes()); 204 write((int) crc.getValue()); 205 out.flush(); 206 if (closeStream) { 207 out.close(); 208 } 209 } 210 211 /** Static method performing screen capture into PNG image format file with given fileName. 212 * @param rect Rectangle of screen to be captured 213 * @param fileName file name for screen capture PNG image file */ 214 public static void captureScreen(Rectangle rect, String fileName) { 215 captureScreen(rect, fileName, GREYSCALE_MODE); 216 } 217 218 /** Static method performing screen capture into PNG image format file with given fileName. 219 * @param rect Rectangle of screen to be captured 220 * @param mode image color mode 221 * @param fileName file name for screen capture PNG image file */ 222 public static void captureScreen(Rectangle rect, String fileName, byte mode) { 223 try { 224 BufferedImage capture=new Robot().createScreenCapture(rect); 225 BufferedOutputStream file=new BufferedOutputStream(new FileOutputStream(fileName)); 226 PNGEncoder encoder=new PNGEncoder(file, mode); 227 encoder.encode(capture); 228 } catch (AWTException awte) { 229 awte.printStackTrace(); 230 } catch (IOException ioe) { 231 ioe.printStackTrace(); 232 } 233 } 234 235 /** Static method performing one component screen capture into PNG image format file with given fileName. 236 * @param comp Component to be captured 237 * @param fileName String image target filename */ 238 public static void captureScreen(ScreenArea comp, String fileName) { 239 captureScreen(comp, fileName, GREYSCALE_MODE); 240 } 241 242 /** Static method performing one component screen capture into PNG image format file with given fileName. 243 * @param comp Component to be captured 244 * @param fileName String image target filename 245 * @param mode image color mode */ 246 public static void captureScreen(ScreenArea comp, String fileName, byte mode) { 247 captureScreen(Utils.convert(comp.getScreenBounds()), 248 fileName, mode); 249 } 250 251 252 /** Static method performing whole screen capture into PNG image format file with given fileName. 253 * @param fileName String image target filename */ 254 public static void captureScreen(String fileName) { 255 captureScreen(fileName, GREYSCALE_MODE); 256 } 257 258 /** Static method performing whole screen capture into PNG image format file with given fileName. 259 * @param fileName String image target filename 260 * @param mode image color mode */ 261 public static void captureScreen(String fileName, byte mode) { 262 captureScreen(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()), fileName, mode); 263 } 264 }