Mercurial > projects > dwt-mac
comparison dwt/internal/image/PNGFileFormat.d @ 34:5123b17c98ef
Ported dwt.events.*, dwt.graphics.GC, Region, dwt.internal.image.*
author | Jacob Carlborg <doob@me.com> <jacob.carlborg@gmail.com> |
---|---|
date | Sun, 14 Sep 2008 01:45:57 +0200 |
parents | e831403a80a9 |
children | d8635bb48c7c |
comparison
equal
deleted
inserted
replaced
33:965ac0a77267 | 34:5123b17c98ef |
---|---|
1 /******************************************************************************* | 1 /******************************************************************************* |
2 * Copyright (c) 2000, 2006 IBM Corporation and others. | 2 * Copyright (c) 2000, 2008 IBM Corporation and others. |
3 * All rights reserved. This program and the accompanying materials | 3 * All rights reserved. This program and the accompanying materials |
4 * are made available under the terms of the Eclipse Public License v1.0 | 4 * are made available under the terms of the Eclipse Public License v1.0 |
5 * which accompanies this distribution, and is available at | 5 * which accompanies this distribution, and is available at |
6 * http://www.eclipse.org/legal/epl-v10.html | 6 * http://www.eclipse.org/legal/epl-v10.html |
7 * | 7 * |
8 * Contributors: | 8 * Contributors: |
9 * IBM Corporation - initial API and implementation | 9 * IBM Corporation - initial API and implementation |
10 * Port to the D programming language: | |
11 * Frank Benoit <benoit@tionex.de> | |
10 *******************************************************************************/ | 12 *******************************************************************************/ |
11 module dwt.internal.image; | 13 module dwt.internal.image.PNGFileFormat; |
12 | 14 |
13 | |
14 import java.io.IOException; | |
15 import java.io.InputStream; | |
16 | 15 |
17 import dwt.DWT; | 16 import dwt.DWT; |
18 import dwt.graphics.ImageData; | 17 import dwt.graphics.ImageData; |
18 import dwt.graphics.ImageLoaderEvent; | |
19 import dwt.graphics.ImageLoader; | 19 import dwt.graphics.ImageLoader; |
20 import dwt.graphics.ImageLoaderEvent; | |
21 import dwt.graphics.PaletteData; | 20 import dwt.graphics.PaletteData; |
22 import dwt.internal.Compatibility; | 21 import dwt.internal.Compatibility; |
23 | 22 import dwt.internal.image.FileFormat; |
24 public final class PNGFileFormat : FileFormat { | 23 import dwt.internal.image.PngIhdrChunk; |
24 import dwt.internal.image.PngPlteChunk; | |
25 import dwt.internal.image.PngChunkReader; | |
26 import dwt.internal.image.PngChunk; | |
27 import dwt.internal.image.PngTrnsChunk; | |
28 import dwt.internal.image.PngIdatChunk; | |
29 import dwt.internal.image.PngEncoder; | |
30 import dwt.internal.image.PngInputStream; | |
31 import dwt.internal.image.PngDecodingDataStream; | |
32 import dwt.dwthelper.utils; | |
33 | |
34 import dwt.dwthelper.BufferedInputStream; | |
35 | |
36 import tango.core.Exception; | |
37 | |
38 final class PNGFileFormat : FileFormat { | |
25 static final int SIGNATURE_LENGTH = 8; | 39 static final int SIGNATURE_LENGTH = 8; |
26 static final int PRIME = 65521; | 40 static final int PRIME = 65521; |
27 PngIhdrChunk headerChunk; | 41 PngIhdrChunk headerChunk; |
28 PngPlteChunk paletteChunk; | 42 PngPlteChunk paletteChunk; |
29 ImageData imageData; | 43 ImageData imageData; |
33 byte headerByte2; | 47 byte headerByte2; |
34 int adler; | 48 int adler; |
35 | 49 |
36 /** | 50 /** |
37 * Skip over signature data. This has already been | 51 * Skip over signature data. This has already been |
38 * verified in isFileFormat(). | 52 * verified in isFileFormat(). |
39 */ | 53 */ |
40 void readSignature() { | 54 void readSignature() { |
41 byte[] signature = new byte[SIGNATURE_LENGTH]; | 55 byte[] signature = new byte[SIGNATURE_LENGTH]; |
42 inputStream.read(signature); | 56 inputStream.read(signature); |
43 } | 57 } |
44 /** | 58 /** |
45 * Load the PNG image from the byte stream. | 59 * Load the PNG image from the byte stream. |
46 */ | 60 */ |
47 ImageData[] loadFromByteStream() { | 61 override ImageData[] loadFromByteStream() { |
48 try { | 62 try { |
49 readSignature(); | 63 readSignature(); |
50 PngChunkReader chunkReader = new PngChunkReader(inputStream); | 64 PngChunkReader chunkReader = new PngChunkReader(inputStream); |
51 headerChunk = chunkReader.getIhdrChunk(); | 65 headerChunk = chunkReader.getIhdrChunk(); |
52 int width = headerChunk.getWidth(), height = headerChunk.getHeight(); | 66 int width = headerChunk.getWidth(), height = headerChunk.getHeight(); |
53 if (width <= 0 || height <= 0) DWT.error(DWT.ERROR_INVALID_IMAGE); | 67 if (width <= 0 || height <= 0) DWT.error(DWT.ERROR_INVALID_IMAGE); |
54 int imageSize = getAlignedBytesPerRow() * height; | 68 int imageSize = getAlignedBytesPerRow() * height; |
55 data = new byte[imageSize]; | 69 data = new byte[imageSize]; |
56 imageData = ImageData.internal_new( | 70 imageData = ImageData.internal_new( |
57 width, | 71 width, |
58 height, | 72 height, |
59 headerChunk.getSwtBitsPerPixel(), | 73 headerChunk.getSwtBitsPerPixel(), |
60 new PaletteData(0, 0, 0), | 74 new PaletteData(0, 0, 0), |
67 -1, | 81 -1, |
68 DWT.IMAGE_PNG, | 82 DWT.IMAGE_PNG, |
69 0, | 83 0, |
70 0, | 84 0, |
71 0, | 85 0, |
72 0); | 86 0); |
73 | 87 |
74 if (headerChunk.usesDirectColor()) { | 88 if (headerChunk.usesDirectColor()) { |
75 imageData.palette = headerChunk.getPaletteData(); | 89 imageData.palette = headerChunk.getPaletteData(); |
76 } | 90 } |
77 | 91 |
78 // Read and process chunks until the IEND chunk is encountered. | 92 // Read and process chunks until the IEND chunk is encountered. |
79 while (chunkReader.hasMoreChunks()) { | 93 while (chunkReader.hasMoreChunks()) { |
80 readNextChunk(chunkReader); | 94 readNextChunk(chunkReader); |
81 } | 95 } |
82 | 96 |
83 return new ImageData[] {imageData}; | 97 return [imageData]; |
84 } catch (IOException e) { | 98 } catch (IOException e) { |
85 DWT.error(DWT.ERROR_INVALID_IMAGE); | 99 DWT.error(DWT.ERROR_INVALID_IMAGE); |
86 return null; | 100 return null; |
87 } | 101 } |
88 } | 102 } |
89 /** | 103 /** |
90 * Read and handle the next chunk of data from the | 104 * Read and handle the next chunk of data from the |
91 * PNG file. | 105 * PNG file. |
92 */ | 106 */ |
93 void readNextChunk(PngChunkReader chunkReader) { | 107 void readNextChunk(PngChunkReader chunkReader) { |
94 PngChunk chunk = chunkReader.readNextChunk(); | 108 PngChunk chunk = chunkReader.readNextChunk(); |
95 switch (chunk.getChunkType()) { | 109 switch (chunk.getChunkType()) { |
96 case PngChunk.CHUNK_IEND: | 110 case PngChunk.CHUNK_IEND: |
97 break; | 111 break; |
98 case PngChunk.CHUNK_PLTE: | 112 case PngChunk.CHUNK_PLTE: |
99 if (!headerChunk.usesDirectColor()) { | 113 if (!headerChunk.usesDirectColor()) { |
100 paletteChunk = cast(PngPlteChunk) chunk; | 114 paletteChunk = cast(PngPlteChunk) chunk; |
101 imageData.palette = paletteChunk.getPaletteData(); | 115 imageData.palette = paletteChunk.getPaletteData(); |
102 } | 116 } |
103 break; | 117 break; |
104 case PngChunk.CHUNK_tRNS: | 118 case PngChunk.CHUNK_tRNS: |
105 PngTrnsChunk trnsChunk = cast(PngTrnsChunk) chunk; | 119 PngTrnsChunk trnsChunk = cast(PngTrnsChunk) chunk; |
106 if (trnsChunk.getTransparencyType(headerChunk) is | 120 if (trnsChunk.getTransparencyType(headerChunk) is |
107 PngTrnsChunk.TRANSPARENCY_TYPE_PIXEL) | 121 PngTrnsChunk.TRANSPARENCY_TYPE_PIXEL) |
108 { | 122 { |
109 imageData.transparentPixel = | 123 imageData.transparentPixel = |
110 trnsChunk.getSwtTransparentPixel(headerChunk); | 124 trnsChunk.getSwtTransparentPixel(headerChunk); |
111 } else { | 125 } else { |
112 alphaPalette = trnsChunk.getAlphaValues(headerChunk, paletteChunk); | 126 alphaPalette = trnsChunk.getAlphaValues(headerChunk, paletteChunk); |
113 int transparentCount = 0, transparentPixel = -1; | 127 int transparentCount = 0, transparentPixel = -1; |
114 for (int i = 0; i < alphaPalette.length; i++) { | 128 for (int i = 0; i < alphaPalette.length; i++) { |
132 // been read and another IDAT block is encountered, | 146 // been read and another IDAT block is encountered, |
133 // then this is an invalid image. | 147 // then this is an invalid image. |
134 DWT.error(DWT.ERROR_INVALID_IMAGE); | 148 DWT.error(DWT.ERROR_INVALID_IMAGE); |
135 } else { | 149 } else { |
136 // Read in the pixel data for the image. This should | 150 // Read in the pixel data for the image. This should |
137 // go through all the image's IDAT chunks. | 151 // go through all the image's IDAT chunks. |
138 PngIdatChunk dataChunk = cast(PngIdatChunk) chunk; | 152 PngIdatChunk dataChunk = cast(PngIdatChunk) chunk; |
139 readPixelData(dataChunk, chunkReader); | 153 readPixelData(dataChunk, chunkReader); |
140 } | 154 } |
141 break; | 155 break; |
142 default: | 156 default: |
143 if (chunk.isCritical()) { | 157 if (chunk.isCritical()) { |
144 // All critical chunks must be supported. | 158 // All critical chunks must be supported. |
145 DWT.error(DWT.ERROR_NOT_IMPLEMENTED); | 159 DWT.error(DWT.ERROR_NOT_IMPLEMENTED); |
146 } | 160 } |
147 } | 161 } |
148 } | 162 } |
149 void unloadIntoByteStream(ImageLoader loader) { | 163 override void unloadIntoByteStream(ImageLoader loader) { |
150 PngEncoder encoder = new PngEncoder(loader); | 164 PngEncoder encoder = new PngEncoder(loader); |
151 encoder.encode(outputStream); | 165 encoder.encode(outputStream); |
152 } | 166 } |
153 bool isFileFormat(LEDataInputStream stream) { | 167 override bool isFileFormat(LEDataInputStream stream) { |
154 try { | 168 try { |
155 byte[] signature = new byte[SIGNATURE_LENGTH]; | 169 byte[] signature = new byte[SIGNATURE_LENGTH]; |
156 stream.read(signature); | 170 stream.read(signature); |
157 stream.unread(signature); | 171 stream.unread(signature); |
158 if ((signature[0] & 0xFF) !is 137) return false; //137 | 172 if ((signature[0] & 0xFF) !is 137) return false; //137 |
160 if ((signature[2] & 0xFF) !is 78) return false; //N | 174 if ((signature[2] & 0xFF) !is 78) return false; //N |
161 if ((signature[3] & 0xFF) !is 71) return false; //G | 175 if ((signature[3] & 0xFF) !is 71) return false; //G |
162 if ((signature[4] & 0xFF) !is 13) return false; //<RETURN> | 176 if ((signature[4] & 0xFF) !is 13) return false; //<RETURN> |
163 if ((signature[5] & 0xFF) !is 10) return false; //<LINEFEED> | 177 if ((signature[5] & 0xFF) !is 10) return false; //<LINEFEED> |
164 if ((signature[6] & 0xFF) !is 26) return false; //<CTRL/Z> | 178 if ((signature[6] & 0xFF) !is 26) return false; //<CTRL/Z> |
165 if ((signature[7] & 0xFF) !is 10) return false; //<LINEFEED> | 179 if ((signature[7] & 0xFF) !is 10) return false; //<LINEFEED> |
166 return true; | 180 return true; |
167 } catch (Exception e) { | 181 } catch (Exception e) { |
168 return false; | 182 return false; |
169 } | 183 } |
170 } | 184 } |
254 } | 268 } |
255 } | 269 } |
256 imageData.data = rgbData; | 270 imageData.data = rgbData; |
257 imageData.alphaData = alphaData; | 271 imageData.alphaData = alphaData; |
258 break; | 272 break; |
259 } | 273 } |
260 case PngIhdrChunk.COLOR_TYPE_RGB: | 274 case PngIhdrChunk.COLOR_TYPE_RGB: |
261 imageData.data = data; | 275 imageData.data = data; |
262 break; | 276 break; |
263 case PngIhdrChunk.COLOR_TYPE_PALETTE: | 277 case PngIhdrChunk.COLOR_TYPE_PALETTE: |
264 imageData.data = data; | 278 imageData.data = data; |
277 imageData.data = data; | 291 imageData.data = data; |
278 break; | 292 break; |
279 } | 293 } |
280 } | 294 } |
281 /** | 295 /** |
282 * PNG supports some color types and bit depths that are | 296 * PNG supports some color types and bit depths that are |
283 * unsupported by DWT. If the image uses an unsupported | 297 * unsupported by DWT. If the image uses an unsupported |
284 * color type (either of the gray scale types) or bit | 298 * color type (either of the gray scale types) or bit |
285 * depth (16), convert the data to an DWT-supported | 299 * depth (16), convert the data to an DWT-supported |
286 * format. Then assign the data into the ImageData given. | 300 * format. Then assign the data into the ImageData given. |
287 */ | 301 */ |
291 } | 305 } |
292 /** | 306 /** |
293 * Read the image data from the data stream. This must handle | 307 * Read the image data from the data stream. This must handle |
294 * decoding the data, filtering, and interlacing. | 308 * decoding the data, filtering, and interlacing. |
295 */ | 309 */ |
296 void readPixelData(PngIdatChunk chunk, PngChunkReader chunkReader) { | 310 void readPixelData(PngIdatChunk chunk, PngChunkReader chunkReader) { |
297 InputStream stream = new PngInputStream(chunk, chunkReader); | 311 InputStream stream = new PngInputStream(chunk, chunkReader); |
298 //TEMPORARY CODE | 312 //TEMPORARY CODE |
299 bool use3_2 = System.getProperty("dwt.internal.image.PNGFileFormat_3.2") !is null; | 313 //PORTING_FIXME |
314 bool use3_2 = true;//System.getProperty("dwt.internal.image.PNGFileFormat_3.2") !is null; | |
300 InputStream inflaterStream = use3_2 ? null : Compatibility.newInflaterInputStream(stream); | 315 InputStream inflaterStream = use3_2 ? null : Compatibility.newInflaterInputStream(stream); |
301 if (inflaterStream !is null) { | 316 if (inflaterStream !is null) { |
302 stream = inflaterStream; | 317 stream = inflaterStream; |
303 } else { | 318 } else { |
304 stream = new PngDecodingDataStream(stream); | 319 stream = new PngDecodingDataStream(stream); |
333 return getBytesPerRow(headerChunk.getWidth()); | 348 return getBytesPerRow(headerChunk.getWidth()); |
334 } | 349 } |
335 /** | 350 /** |
336 * Answer the number of bytes needed to represent a pixel. | 351 * Answer the number of bytes needed to represent a pixel. |
337 * This value depends on the image's color type and bit | 352 * This value depends on the image's color type and bit |
338 * depth. | 353 * depth. |
339 * Note that this method rounds up if an image's pixel size | 354 * Note that this method rounds up if an image's pixel size |
340 * isn't byte-aligned. | 355 * isn't byte-aligned. |
341 */ | 356 */ |
342 int getBytesPerPixel() { | 357 int getBytesPerPixel() { |
343 int bitsPerPixel = headerChunk.getBitsPerPixel(); | 358 int bitsPerPixel = headerChunk.getBitsPerPixel(); |
344 return (bitsPerPixel + 7) / 8; | 359 return (bitsPerPixel + 7) / 8; |
345 } | 360 } |
346 /** | 361 /** |
347 * Answer the number of bytes in a row of the given pixel | 362 * Answer the number of bytes in a row of the given pixel |
348 * width. Each row is byte-aligned, so images with bit | 363 * width. Each row is byte-aligned, so images with bit |
349 * depths less than a byte may have unused bits at the | 364 * depths less than a byte may have unused bits at the |
370 { | 385 { |
371 int width = headerChunk.getWidth(); | 386 int width = headerChunk.getWidth(); |
372 int alignedBytesPerRow = getAlignedBytesPerRow(); | 387 int alignedBytesPerRow = getAlignedBytesPerRow(); |
373 int height = headerChunk.getHeight(); | 388 int height = headerChunk.getHeight(); |
374 if (startRow >= height || startColumn >= width) return; | 389 if (startRow >= height || startColumn >= width) return; |
375 | 390 |
376 int pixelsPerRow = (width - startColumn + columnInterval - 1) / columnInterval; | 391 int pixelsPerRow = (width - startColumn + columnInterval - 1) / columnInterval; |
377 int bytesPerRow = getBytesPerRow(pixelsPerRow); | 392 int bytesPerRow = getBytesPerRow(pixelsPerRow); |
378 byte[] row1 = new byte[bytesPerRow]; | 393 byte[] row1 = new byte[bytesPerRow]; |
379 byte[] row2 = new byte[bytesPerRow]; | 394 byte[] row2 = new byte[bytesPerRow]; |
380 byte[] currentRow = row1; | 395 byte[] currentRow = row1; |
381 byte[] lastRow = row2; | 396 byte[] lastRow = row2; |
382 for (int row = startRow; row < height; row += rowInterval) { | 397 for (int row = startRow; row < height; row += rowInterval) { |
383 byte filterType = cast(byte)inputStream.read(); | 398 byte filterType = cast(byte)inputStream.read(); |
384 int read = 0; | 399 int read = 0; |
385 while (read !is bytesPerRow) { | 400 while (read !is bytesPerRow) { |
386 read += inputStream.read(currentRow, read, bytesPerRow - read); | 401 read += inputStream.read(currentRow, read, bytesPerRow - read); |
407 } | 422 } |
408 int maxShift = 8 - bitsPerPixel; | 423 int maxShift = 8 - bitsPerPixel; |
409 for (int byteOffset = 0; byteOffset < currentRow.length; byteOffset++) { | 424 for (int byteOffset = 0; byteOffset < currentRow.length; byteOffset++) { |
410 for (int bitOffset = maxShift; bitOffset >= 0; bitOffset -= bitsPerPixel) { | 425 for (int bitOffset = maxShift; bitOffset >= 0; bitOffset -= bitsPerPixel) { |
411 if (column < width) { | 426 if (column < width) { |
412 int dataOffset = rowBase + (column * bitsPerPixel / 8); | 427 int dataOffset = rowBase + (column * bitsPerPixel / 8); |
413 int value = (currentRow[byteOffset] >> bitOffset) & valueMask; | 428 int value = (currentRow[byteOffset] >> bitOffset) & valueMask; |
414 int dataShift = maxShift - (bitsPerPixel * (column % pixelsPerByte)); | 429 int dataShift = maxShift - (bitsPerPixel * (column % pixelsPerByte)); |
415 data[dataOffset] |= value << dataShift; | 430 data[dataOffset] |= value << dataShift; |
416 } | 431 } |
417 column += columnInterval; | 432 column += columnInterval; |
426 } | 441 } |
427 /** | 442 /** |
428 * Read the pixel data for an interlaced image from the | 443 * Read the pixel data for an interlaced image from the |
429 * data stream. | 444 * data stream. |
430 */ | 445 */ |
431 void readInterlacedImage(InputStream inputStream) { | 446 void readInterlacedImage(InputStream inputStream) { |
432 readInterlaceFrame(inputStream, 8, 8, 0, 0, 0); | 447 readInterlaceFrame(inputStream, 8, 8, 0, 0, 0); |
433 readInterlaceFrame(inputStream, 8, 8, 0, 4, 1); | 448 readInterlaceFrame(inputStream, 8, 8, 0, 4, 1); |
434 readInterlaceFrame(inputStream, 8, 4, 4, 0, 2); | 449 readInterlaceFrame(inputStream, 8, 4, 4, 0, 2); |
435 readInterlaceFrame(inputStream, 4, 4, 0, 2, 3); | 450 readInterlaceFrame(inputStream, 4, 4, 0, 2, 3); |
436 readInterlaceFrame(inputStream, 4, 2, 2, 0, 4); | 451 readInterlaceFrame(inputStream, 4, 2, 2, 0, 4); |
437 readInterlaceFrame(inputStream, 2, 2, 0, 1, 5); | 452 readInterlaceFrame(inputStream, 2, 2, 0, 1, 5); |
438 readInterlaceFrame(inputStream, 2, 1, 1, 0, 6); | 453 readInterlaceFrame(inputStream, 2, 1, 1, 0, 6); |
439 } | 454 } |
440 /** | 455 /** |
441 * Fire an event to let listeners know that an interlaced | 456 * Fire an event to let listeners know that an interlaced |
442 * frame has been loaded. | 457 * frame has been loaded. |
453 /** | 468 /** |
454 * Read the pixel data for a non-interlaced image from the | 469 * Read the pixel data for a non-interlaced image from the |
455 * data stream. | 470 * data stream. |
456 * Update the imageData to reflect the new data. | 471 * Update the imageData to reflect the new data. |
457 */ | 472 */ |
458 void readNonInterlacedImage(InputStream inputStream) { | 473 void readNonInterlacedImage(InputStream inputStream) { |
459 int dataOffset = 0; | 474 int dataOffset = 0; |
460 int alignedBytesPerRow = getAlignedBytesPerRow(); | 475 int alignedBytesPerRow = getAlignedBytesPerRow(); |
461 int bytesPerRow = getBytesPerRow(); | 476 int bytesPerRow = getBytesPerRow(); |
462 byte[] row1 = new byte[bytesPerRow]; | 477 byte[] row1 = new byte[bytesPerRow]; |
463 byte[] row2 = new byte[bytesPerRow]; | 478 byte[] row2 = new byte[bytesPerRow]; |
464 byte[] currentRow = row1; | 479 byte[] currentRow = row1; |
465 byte[] lastRow = row2; | 480 byte[] lastRow = row2; |
466 int height = headerChunk.getHeight(); | 481 int height = headerChunk.getHeight(); |
467 for (int row = 0; row < height; row++) { | 482 for (int row = 0; row < height; row++) { |
468 byte filterType = cast(byte)inputStream.read(); | 483 byte filterType = cast(byte)inputStream.read(); |
469 int read = 0; | 484 int read = 0; |
488 * byte of the 16-bit value. | 503 * byte of the 16-bit value. |
489 */ | 504 */ |
490 static void compress16BitDepthTo8BitDepth( | 505 static void compress16BitDepthTo8BitDepth( |
491 byte[] source, | 506 byte[] source, |
492 int sourceOffset, | 507 int sourceOffset, |
493 byte[] destination, | 508 byte[] destination, |
494 int destinationOffset, | 509 int destinationOffset, |
495 int numberOfValues) | 510 int numberOfValues) |
496 { | 511 { |
497 //double multiplier = (Compatibility.pow2(8) - 1) / (Compatibility.pow2(16) - 1); | 512 //double multiplier = (Compatibility.pow2(8) - 1) / (Compatibility.pow2(16) - 1); |
498 for (int i = 0; i < numberOfValues; i++) { | 513 for (int i = 0; i < numberOfValues; i++) { |
499 int sourceIndex = sourceOffset + (2 * i); | 514 int sourceIndex = sourceOffset + (2 * i); |
500 int destinationIndex = destinationOffset + i; | 515 int destinationIndex = destinationOffset + i; |
501 //int value = (source[sourceIndex] << 8) | source[sourceIndex + 1]; | 516 //int value = (source[sourceIndex] << 8) | source[sourceIndex + 1]; |
502 //byte compressedValue = cast(byte)(value * multiplier); | 517 //byte compressedValue = (byte)(value * multiplier); |
503 byte compressedValue = source[sourceIndex]; | 518 byte compressedValue = source[sourceIndex]; |
504 destination[destinationIndex] = compressedValue; | 519 destination[destinationIndex] = compressedValue; |
505 } | 520 } |
506 } | 521 } |
507 /** | 522 /** |
513 * The fast way to do this is just to drop the low | 528 * The fast way to do this is just to drop the low |
514 * byte of the 16-bit value. | 529 * byte of the 16-bit value. |
515 */ | 530 */ |
516 static int compress16BitDepthTo8BitDepth(int value) { | 531 static int compress16BitDepthTo8BitDepth(int value) { |
517 //double multiplier = (Compatibility.pow2(8) - 1) / (Compatibility.pow2(16) - 1); | 532 //double multiplier = (Compatibility.pow2(8) - 1) / (Compatibility.pow2(16) - 1); |
518 //byte compressedValue = cast(byte)(value * multiplier); | 533 //byte compressedValue = (byte)(value * multiplier); |
519 return value >> 8; | 534 return value >> 8; |
520 } | 535 } |
521 /** | 536 /** |
522 * PNG supports four filtering types. These types are applied | 537 * PNG supports four filtering types. These types are applied |
523 * per row of image data. This method unfilters the given row | 538 * per row of image data. This method unfilters the given row |
536 } | 551 } |
537 break; | 552 break; |
538 case PngIhdrChunk.FILTER_UP: | 553 case PngIhdrChunk.FILTER_UP: |
539 for (int i = 0; i < row.length; i++) { | 554 for (int i = 0; i < row.length; i++) { |
540 int current = row[i] & 0xFF; | 555 int current = row[i] & 0xFF; |
541 int above = previousRow[i] & 0xFF; | 556 int above = previousRow[i] & 0xFF; |
542 row[i] = cast(byte)((current + above) & 0xFF); | 557 row[i] = cast(byte)((current + above) & 0xFF); |
543 } | 558 } |
544 break; | 559 break; |
545 case PngIhdrChunk.FILTER_AVERAGE: | 560 case PngIhdrChunk.FILTER_AVERAGE: |
546 for (int i = 0; i < row.length; i++) { | 561 for (int i = 0; i < row.length; i++) { |
553 case PngIhdrChunk.FILTER_PAETH: | 568 case PngIhdrChunk.FILTER_PAETH: |
554 for (int i = 0; i < row.length; i++) { | 569 for (int i = 0; i < row.length; i++) { |
555 int left = (i < byteOffset) ? 0 : row[i - byteOffset] & 0xFF; | 570 int left = (i < byteOffset) ? 0 : row[i - byteOffset] & 0xFF; |
556 int aboveLeft = (i < byteOffset) ? 0 : previousRow[i - byteOffset] & 0xFF; | 571 int aboveLeft = (i < byteOffset) ? 0 : previousRow[i - byteOffset] & 0xFF; |
557 int above = previousRow[i] & 0xFF; | 572 int above = previousRow[i] & 0xFF; |
558 | 573 |
559 int a = Math.abs(above - aboveLeft); | 574 int a = Math.abs(above - aboveLeft); |
560 int b = Math.abs(left - aboveLeft); | 575 int b = Math.abs(left - aboveLeft); |
561 int c = Math.abs(left - aboveLeft + above - aboveLeft); | 576 int c = Math.abs(left - aboveLeft + above - aboveLeft); |
562 | 577 |
563 int preductor = 0; | 578 int preductor = 0; |
564 if (a <= b && a <= c) { | 579 if (a <= b && a <= c) { |
565 preductor = left; | 580 preductor = left; |
566 } else if (b <= c) { | 581 } else if (b <= c) { |
567 preductor = above; | 582 preductor = above; |
568 } else { | 583 } else { |
569 preductor = aboveLeft; | 584 preductor = aboveLeft; |
570 } | 585 } |
571 | 586 |
572 int currentValue = row[i] & 0xFF; | 587 int currentValue = row[i] & 0xFF; |
573 row[i] = cast(byte) ((currentValue + preductor) & 0xFF); | 588 row[i] = cast(byte) ((currentValue + preductor) & 0xFF); |
574 } | 589 } |
575 break; | 590 break; |
576 } | 591 default: |
577 } | 592 } |
578 | 593 } |
579 } | 594 |
595 } |