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 26 package org.jemmy.image.pixel; 27 28 import java.io.IOException; 29 import java.io.InputStream; 30 import java.util.Arrays; 31 import java.util.zip.DataFormatException; 32 import java.util.zip.Inflater; 33 import org.jemmy.JemmyException; 34 import org.jemmy.image.pixel.Raster.Component; 35 36 /** 37 * Allows to load PNG graphical file. 38 * @author Alexandre Iline 39 */ 40 public abstract class PNGLoader { 41 42 InputStream in; 43 44 /** 45 * Constructs a PNGDecoder object. 46 * @param in input stream to read PNG image from. 47 */ 48 public PNGLoader(InputStream in) { 49 this.in = in; 50 } 51 52 byte read() throws IOException { 53 byte b = (byte)in.read(); 54 return(b); 55 } 56 57 int readInt() throws IOException { 58 byte b[] = read(4); 59 return(((b[0]&0xff)<<24) + 60 ((b[1]&0xff)<<16) + 61 ((b[2]&0xff)<<8) + 62 ((b[3]&0xff))); 63 } 64 65 byte[] read(int count) throws IOException { 66 byte[] result = new byte[count]; 67 for(int i = 0; i < count; i++) { 68 result[i] = read(); 69 } 70 return(result); 71 } 72 73 void checkEquality(byte[] b1, byte[] b2) { 74 if(!Arrays.equals(b1, b2)) { 75 throw(new JemmyException("Format error")); 76 } 77 } 78 79 /** 80 * Decodes image from an input stream passed into constructor. 81 * @return a BufferedImage object 82 * @throws IOException 83 */ 84 public Raster decode() throws IOException { 85 return decode(true); 86 } 87 88 protected abstract WriteableRaster createRaster(int width, int height); 89 90 /** 91 * Decodes image from an input stream passed into constructor. 92 * @return a BufferedImage object 93 * @param closeStream requests method to close the stream after the image is read 94 * @throws IOException 95 */ 96 public Raster decode(boolean closeStream) throws IOException { 97 98 byte[] id = read(12); 99 checkEquality(id, new byte[] {-119, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13}); 100 101 byte[] ihdr = read(4); 102 checkEquality(ihdr, "IHDR".getBytes()); 103 104 int width = readInt(); 105 int height = readInt(); 106 107 WriteableRaster result = createRaster(width, height); 108 109 byte[] head = read(5); 110 int mode; 111 if(Arrays.equals(head, new byte[]{1, 0, 0, 0, 0})) { 112 mode = PNGSaver.BW_MODE; 113 } else if(Arrays.equals(head, new byte[]{8, 0, 0, 0, 0})) { 114 mode = PNGSaver.GREYSCALE_MODE; 115 } else if(Arrays.equals(head, new byte[]{8, 2, 0, 0, 0})) { 116 mode = PNGSaver.COLOR_MODE; 117 } else { 118 throw(new JemmyException("Format error")); 119 } 120 121 readInt();//!!crc 122 123 int size = readInt(); 124 125 byte[] idat = read(4); 126 checkEquality(idat, "IDAT".getBytes()); 127 128 byte[] data = read(size); 129 130 131 Inflater inflater = new Inflater(); 132 inflater.setInput(data, 0, size); 133 134 int[] colors = new int[3]; 135 int[] black = new int[] {0, 0, 0}; 136 int[] white = new int[] {1, 1, 1}; 137 138 try { 139 switch (mode) { 140 case PNGSaver.BW_MODE: 141 { 142 int bytes = (int)(width / 8); 143 if((width % 8) != 0) { 144 bytes++; 145 } 146 byte colorset; 147 byte[] row = new byte[bytes]; 148 for (int y = 0; y < height; y++) { 149 inflater.inflate(new byte[1]); 150 inflater.inflate(row); 151 for (int x = 0; x < bytes; x++) { 152 colorset = row[x]; 153 for (int sh = 0; sh < 8; sh++) { 154 if(x * 8 + sh >= width) { 155 break; 156 } 157 if((colorset & 0x80) == 0x80) { 158 setColors(result, x * 8 + sh, y, white); 159 } else { 160 setColors(result, x * 8 + sh, y, black); 161 } 162 colorset <<= 1; 163 } 164 } 165 } 166 } 167 break; 168 case PNGSaver.GREYSCALE_MODE: 169 { 170 byte[] row = new byte[width]; 171 for (int y = 0; y < height; y++) { 172 inflater.inflate(new byte[1]); 173 inflater.inflate(row); 174 for (int x = 0; x < width; x++) { 175 colors[0] = row[x]; 176 colors[1] = colors[0]; 177 colors[2] = colors[0]; 178 setColors(result, x, y, colors); 179 } 180 } 181 } 182 break; 183 case PNGSaver.COLOR_MODE: 184 { 185 byte[] row = new byte[width * 3]; 186 for (int y = 0; y < height; y++) { 187 inflater.inflate(new byte[1]); 188 inflater.inflate(row); 189 for (int x = 0; x < width; x++) { 190 colors[0] = (row[x * 3 + 0]&0xff); 191 colors[1] = (row[x * 3 + 1]&0xff); 192 colors[2] = (row[x * 3 + 2]&0xff); 193 setColors(result, x, y, colors); 194 } 195 } 196 } 197 } 198 } catch(DataFormatException e) { 199 throw(new JemmyException("ZIP error", e)); 200 } 201 202 readInt();//!!crc 203 readInt();//0 204 205 byte[] iend = read(4); 206 checkEquality(iend, "IEND".getBytes()); 207 208 readInt();//!!crc 209 if (closeStream) { 210 in.close(); 211 } 212 213 return(result); 214 } 215 216 private void setColors(WriteableRaster raster, int x, int y, int[] colors) { 217 Component[] supported = raster.getSupported(); 218 double[] imageColors = new double[supported.length]; 219 for (int i = 0; i < supported.length; i++) { 220 if(supported[i] == Component.ALPHA) { 221 imageColors[i] = 1; 222 } else { 223 imageColors[i] = (double)colors[ 224 PixelImageComparator.arrayIndexOf(PNGSaver.RGB, supported[i])]/0xFF; 225 } 226 } 227 raster.setColors(x, y, imageColors); 228 } 229 230 }