1 11 package org.eclipse.swt.internal.image; 12 13 import java.io.ByteArrayOutputStream ; 14 import java.io.IOException ; 15 import org.eclipse.swt.SWT; 16 import org.eclipse.swt.graphics.ImageData; 17 import org.eclipse.swt.graphics.ImageLoader; 18 import org.eclipse.swt.graphics.RGB; 19 20 final class PngEncoder extends Object { 21 22 static final byte SIGNATURE[] = {(byte) '\211', (byte) 'P', (byte) 'N', (byte) 'G', (byte) '\r', (byte) '\n', (byte) '\032', (byte) '\n'}; 23 static final byte TAG_IHDR[] = {(byte) 'I', (byte) 'H', (byte) 'D', (byte) 'R'}; 24 static final byte TAG_PLTE[] = {(byte) 'P', (byte) 'L', (byte) 'T', (byte) 'E'}; 25 static final byte TAG_TRNS[] = {(byte) 't', (byte) 'R', (byte) 'N', (byte) 'S'}; 26 static final byte TAG_IDAT[] = {(byte) 'I', (byte) 'D', (byte) 'A', (byte) 'T'}; 27 static final byte TAG_IEND[] = {(byte) 'I', (byte) 'E', (byte) 'N', (byte) 'D'}; 28 29 ByteArrayOutputStream bytes = new ByteArrayOutputStream (1024); 30 PngChunk chunk; 31 32 ImageLoader loader; 33 ImageData data; 34 int transparencyType; 35 36 int width, height, bitDepth, colorType; 37 38 int compressionMethod = 0; 39 int filterMethod = 0; 40 int interlaceMethod = 0; 41 42 public PngEncoder(ImageLoader loader) { 43 44 this.loader = loader; 45 this.data = loader.data[0]; 46 this.transparencyType = data.getTransparencyType(); 47 48 this.width = data.width; 49 this.height = data.height; 50 51 this.bitDepth = 8; 52 53 this.colorType = 2; 54 55 if (data.palette.isDirect) { 56 if (transparencyType == SWT.TRANSPARENCY_ALPHA) { 57 this.colorType = 6; 58 } 59 } 60 else { 61 this.colorType = 3; 62 } 63 64 if (!(colorType == 2 || colorType == 3 || colorType == 6)) SWT.error(SWT.ERROR_INVALID_IMAGE); 65 66 } 67 68 void writeShort(ByteArrayOutputStream baos, int theShort) { 69 70 byte byte1 = (byte) ((theShort >> 8) & 0xff); 71 byte byte2 = (byte) (theShort & 0xff); 72 byte[] temp = {byte1, byte2}; 73 baos.write(temp, 0, 2); 74 75 } 76 77 void writeInt(ByteArrayOutputStream baos, int theInt) { 78 79 byte byte1 = (byte) ((theInt >> 24) & 0xff); 80 byte byte2 = (byte) ((theInt >> 16) & 0xff); 81 byte byte3 = (byte) ((theInt >> 8) & 0xff); 82 byte byte4 = (byte) (theInt & 0xff); 83 byte[] temp = {byte1, byte2, byte3, byte4}; 84 baos.write(temp, 0, 4); 85 86 } 87 88 void writeChunk(byte[] tag, byte[] buffer) { 89 90 int bufferLength = (buffer != null) ? buffer.length : 0; 91 92 chunk = new PngChunk(bufferLength); 93 94 writeInt(bytes, bufferLength); 95 bytes.write(tag, 0, 4); 96 chunk.setType(tag); 97 if (bufferLength != 0) { 98 bytes.write(buffer, 0, bufferLength); 99 chunk.setData(buffer); 100 } 101 else { 102 chunk.setCRC(chunk.computeCRC()); 103 } 104 writeInt(bytes, chunk.getCRC()); 105 106 } 107 108 void writeSignature() { 109 110 bytes.write(SIGNATURE, 0, 8); 111 112 } 113 114 void writeHeader() { 115 116 ByteArrayOutputStream baos = new ByteArrayOutputStream (13); 117 118 writeInt(baos, width); 119 writeInt(baos, height); 120 baos.write(bitDepth); 121 baos.write(colorType); 122 baos.write(compressionMethod); 123 baos.write(filterMethod); 124 baos.write(interlaceMethod); 125 126 writeChunk(TAG_IHDR, baos.toByteArray()); 127 128 } 129 130 void writePalette() { 131 132 RGB[] RGBs = data.palette.getRGBs(); 133 134 if (RGBs.length > 256) SWT.error(SWT.ERROR_INVALID_IMAGE); 135 136 ByteArrayOutputStream baos = new ByteArrayOutputStream (RGBs.length); 137 138 for (int i = 0; i < RGBs.length; i++) { 139 140 baos.write((byte) RGBs[i].red); 141 baos.write((byte) RGBs[i].green); 142 baos.write((byte) RGBs[i].blue); 143 144 } 145 146 writeChunk(TAG_PLTE, baos.toByteArray()); 147 148 } 149 150 void writeTransparency() { 151 152 ByteArrayOutputStream baos = new ByteArrayOutputStream (); 153 154 switch (transparencyType) { 155 156 case SWT.TRANSPARENCY_ALPHA: 157 158 int pixelValue, alphaValue; 159 160 byte[] alphas = new byte[data.palette.getRGBs().length]; 161 162 for (int y = 0; y < height; y++) { 163 164 for (int x = 0; x < width; x++) { 165 166 pixelValue = data.getPixel(x, y); 167 alphaValue = data.getAlpha(x, y); 168 169 alphas[pixelValue] = (byte) alphaValue; 170 171 } 172 173 } 174 175 baos.write(alphas, 0, alphas.length); 176 177 break; 178 179 case SWT.TRANSPARENCY_PIXEL: 180 181 int pixel = data.transparentPixel; 182 183 if (colorType == 2) { 184 185 int redMask = data.palette.redMask; 186 int redShift = data.palette.redShift; 187 int greenMask = data.palette.greenMask; 188 int greenShift = data.palette.greenShift; 189 int blueShift = data.palette.blueShift; 190 int blueMask = data.palette.blueMask; 191 192 int r = pixel & redMask; 193 r = (redShift < 0) ? r >>> -redShift : r << redShift; 194 int g = pixel & greenMask; 195 g = (greenShift < 0) ? g >>> -greenShift : g << greenShift; 196 int b = pixel & blueMask; 197 b = (blueShift < 0) ? b >>> -blueShift : b << blueShift; 198 199 writeShort(baos, r); 200 writeShort(baos, g); 201 writeShort(baos, b); 202 203 } 204 205 if (colorType == 3) { 206 207 byte[] padding = new byte[pixel + 1]; 208 209 for (int i = 0; i < pixel; i++) { 210 211 padding[i] = (byte) 255; 212 213 } 214 215 padding[pixel] = (byte) 0; 216 217 baos.write(padding, 0, padding.length); 218 219 } 220 221 break; 222 223 } 224 225 writeChunk(TAG_TRNS, baos.toByteArray()); 226 227 } 228 229 void writeImageData() { 230 231 ByteArrayOutputStream baos = new ByteArrayOutputStream (1024); 232 233 if (colorType == 3) { 234 235 int[] lineData = new int[width]; 236 237 for (int y = 0; y < height; y++) { 238 239 byte filter[] = {0}; 240 baos.write(filter, 0, 1); 241 242 data.getPixels(0, y, width, lineData, 0); 243 244 for (int x = 0; x < lineData.length; x++) { 245 246 baos.write((byte) lineData[x]); 247 248 } 249 250 } 251 252 } 253 254 else { 255 256 int[] lineData = new int[width]; 257 byte[] alphaData = new byte[width]; 258 259 int redMask = data.palette.redMask; 260 int redShift = data.palette.redShift; 261 int greenMask = data.palette.greenMask; 262 int greenShift = data.palette.greenShift; 263 int blueShift = data.palette.blueShift; 264 int blueMask = data.palette.blueMask; 265 266 for (int y = 0; y < height; y++) { 267 268 byte filter[] = {0}; 269 baos.write(filter, 0, 1); 270 271 data.getPixels(0, y, width, lineData, 0); 272 273 if (colorType == 6) { 274 data.getAlphas(0, y, width, alphaData, 0); 275 } 276 277 for (int x = 0; x < lineData.length; x++) { 278 279 int pixel = lineData[x]; 280 281 int r = pixel & redMask; 282 r = (redShift < 0) ? r >>> -redShift : r << redShift; 283 int g = pixel & greenMask; 284 g = (greenShift < 0) ? g >>> -greenShift : g << greenShift; 285 int b = pixel & blueMask; 286 b = (blueShift < 0) ? b >>> -blueShift : b << blueShift; 287 288 byte pixels[] = {(byte) r, (byte) g, (byte) b}; 289 baos.write(pixels, 0, 3); 290 291 if (colorType == 6) { 292 293 byte alpha[] = {alphaData[x]}; 294 baos.write(alpha, 0, 1); 295 296 } 297 298 } 299 300 } 301 302 } 303 304 PngDeflater deflater = new PngDeflater(); 305 byte[] compressed = deflater.deflate(baos.toByteArray()); 306 307 writeChunk(TAG_IDAT, compressed); 308 309 } 310 311 void writeEnd() { 312 313 writeChunk(TAG_IEND, null); 314 315 } 316 317 public void encode(LEDataOutputStream outputStream) { 318 319 try { 320 321 writeSignature(); 322 writeHeader(); 323 324 if (colorType == 3) { 325 writePalette(); 326 } 327 328 boolean transparencyAlpha = (transparencyType == SWT.TRANSPARENCY_ALPHA); 329 boolean transparencyPixel = (transparencyType == SWT.TRANSPARENCY_PIXEL); 330 boolean type2Transparency = (colorType == 2 && transparencyPixel); 331 boolean type3Transparency = (colorType == 3 && (transparencyAlpha || transparencyPixel)); 332 333 if (type2Transparency || type3Transparency) { 334 writeTransparency(); 335 } 336 337 writeImageData(); 338 writeEnd(); 339 340 outputStream.write(bytes.toByteArray()); 341 342 } 343 344 catch (IOException e) { 345 346 SWT.error(SWT.ERROR_IO, e); 347 348 } 349 350 } 351 352 } 353 | Popular Tags |