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