KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openlaszlo > iv > flash > util > PNGHelper


1 /*
2  * $Id: PNGHelper.java,v 1.3 2002/06/27 21:49:17 awason Exp $
3  *
4  * ===========================================================================
5  *
6  * The JGenerator Software License, Version 1.0
7  *
8  * Copyright (c) 2000 Dmitry Skavish (skavish@usa.net). All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in
18  * the documentation and/or other materials provided with the
19  * distribution.
20  *
21  * 3. The end-user documentation included with the redistribution, if
22  * any, must include the following acknowlegement:
23  * "This product includes software developed by Dmitry Skavish
24  * (skavish@usa.net, http://www.flashgap.com/)."
25  * Alternately, this acknowlegement may appear in the software itself,
26  * if and wherever such third-party acknowlegements normally appear.
27  *
28  * 4. The name "The JGenerator" must not be used to endorse or promote
29  * products derived from this software without prior written permission.
30  * For written permission, please contact skavish@usa.net.
31  *
32  * 5. Products derived from this software may not be called "The JGenerator"
33  * nor may "The JGenerator" appear in their names without prior written
34  * permission of Dmitry Skavish.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL DMITRY SKAVISH OR THE OTHER
40  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  *
49  */

50
51 package org.openlaszlo.iv.flash.util;
52
53 import java.io.EOFException JavaDoc;
54 import java.io.IOException JavaDoc;
55 import java.io.InputStream JavaDoc;
56 import java.io.DataInputStream JavaDoc;
57 import java.io.BufferedInputStream JavaDoc;
58 import java.io.ByteArrayInputStream JavaDoc;
59 import java.util.zip.InflaterInputStream JavaDoc;
60 import java.util.zip.Deflater JavaDoc;
61 import java.util.zip.CRC32 JavaDoc;
62 import java.util.Hashtable JavaDoc;
63 import org.openlaszlo.iv.flash.parser.DataMarker;
64
65 /**
66  * Helper class to decode PNG images.
67  * Does read but not support gAMA chunk (yet :-)
68  * @author Patrick Talbot
69  */

70 public class PNGHelper
71 {
72     /** header chunk */
73     private static final int CHUNK_IHDR = 0x49484452;
74     /** palette chunk */
75     private static final int CHUNK_PLTE = 0x504c5445;
76     /** data chunk */
77     private static final int CHUNK_IDAT = 0x49444154;
78     /** end of file chunk */
79     private static final int CHUNK_IEND = 0x49454e44;
80     /** transparency chunk */
81     private static final int CHUNK_tRNS = 0x74524e53;
82
83     /** background (ignored) chunk */
84     private static final int CHUNK_bKGD = 0x624b4744;
85     /** chromaticities (ignored) chunk */
86     private static final int CHUNK_cHRM = 0x6348524d;
87     /** fractal image parameters (ignored) chunk */
88     private static final int CHUNK_fRAc = 0x66524163;
89     /** gamma (ignored) chunk */
90     private static final int CHUNK_gAMA = 0x67414d41;
91     /** GIF graphic control (ignored) chunk */
92     private static final int CHUNK_gIFg = 0x67494667;
93     /** GIF plain text (ignored) chunk */
94     private static final int CHUNK_gIFt = 0x67494674;
95     /** GIF application (ignored) chunk */
96     private static final int CHUNK_gIFx = 0x67494678;
97     /** histogram (ignored) chunk */
98     private static final int CHUNK_hIST = 0x68495354;
99     /** embedded ICC profile (ignored) chunk */
100     private static final int CHUNK_iCCP = 0x69434350;
101     /** unicode UTF-8 text (ignored) chunk */
102     private static final int CHUNK_iTXt = 0x69545874;
103     /** image offset (ignored) chunk */
104     private static final int CHUNK_oFFs = 0x6f464673;
105     /** calibration (ignored) chunk */
106     private static final int CHUNK_pCAL = 0x7043414c;
107     /** physical pixel dimension (ignored) chunk */
108     private static final int CHUNK_pHYs = 0x70485973;
109     /** significant bits (ignored) chunk */
110     private static final int CHUNK_sBIT = 0x73424954;
111     /** physical scale (ignored) chunk */
112     private static final int CHUNK_sCAL = 0x7343414c;
113     /** suggested palette (ignored) chunk */
114     private static final int CHUNK_sPLT = 0x73504c54;
115     /** standard RGB colour space (ignored) chunk */
116     private static final int CHUNK_sRGB = 0x73524742;
117     /** normal text (ignored) chunk */
118     private static final int CHUNK_tEXt = 0x74455874;
119     /** time stamp (ignored) chunk */
120     private static final int CHUNK_tIME = 0x74494d45;
121     /** compressed text (ignored) chunk */
122     private static final int CHUNK_zTXt = 0x7a545874;
123
124     /** PNG Signature */
125     private static final int[] PNG_SIGN = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };
126
127     /** a flag to test if the header chunk has been encountered */
128     private boolean flagIHDR = false;
129     /** a flag to test if data chunks have been encountered */
130     private boolean flagIDAT = false;
131     /** a flag to test if the palette chunk has been encountered */
132     private boolean flagPLTE = false;
133
134     /** flag used to indicate that further computing is need to manage transparency */
135     private boolean tRNSPassRequired = false;
136     /** transparency color for colorType 0 and 2 */
137     private RGB tRNSKeyColor = null;
138     /** used to determine if transparency chunk exists */
139     private boolean flagtRNS = false;
140
141     /** number of bytes used per pixel */
142     private int colorType_components= -1;
143
144     /** compression method should always be 0 = deflate/inflate, */
145     private int compressionMethod = -1;
146     /** filter method can be
147     * 0 = none
148     * 1 = sub
149     * 2 = up
150     * 3 = average
151     * 4 = paeth
152     */

153     private int filterMethod = -1;
154     /** interlace method can be
155     * 0 = not interlace
156     * 1 = Adam7 interlacing
157     */

158     private int interlaceMethod = -1;
159
160     /** width of image*/
161     private int width = -1;
162     /** height of image */
163     private int height = -1;
164     /** pixels bit depth can be 1,2,4,8,16 */
165     private int bitDepth = -1;
166
167     /** gamma value of image, set to default value */
168     private long gamma = 45455;
169
170     /** color type can be
171     * 0 = gray
172     * 2 = RGB
173     * 3 = paletted
174     * 4 = gray + alpha
175     * 6 = RGB + alpha
176     */

177     private int colorType = -1;
178
179     /** flag set if palette is used */
180     private boolean colorType_hasPalette= false;
181     /** flag set if alpha channel exists for colorType = 4 or 6 */
182     private boolean colorType_hasAlpha = false;
183     /** flag set if not gray */
184     private boolean colorType_hasColor = false;
185
186     /** RGB Palette */
187     private RGB[] palette;
188
189     /** size of the palette */
190     private int colorsUsed = 0;
191
192     /** main IDAT buffer */
193     private byte[] buffer;
194
195     /** main filters per row buffer */
196     //private int[] filters;
197

198     /** Stream to read data from */
199     private CRCInputStream source;
200
201         /**
202          * A private input stream class used to read multi-byte integer values
203          * while maintaining CRC code for read bytes.
204          * Provides utility methods to read multi-byte integer values
205          * in both little- and bit-endian orders.
206          */

207         //private
208
public class CRCInputStream extends DataInputStream JavaDoc
209         {
210             /** crc checker */
211             private CRC32 JavaDoc crc = new CRC32 JavaDoc();
212
213             /**
214             * Constructor
215             * @param inputStream java.io.InputStream
216             */

217             public CRCInputStream(InputStream JavaDoc inputStream)
218             {
219                 super(inputStream);
220             }
221
222             /**
223             * Return the crc value
224             * @return long
225             */

226             public long getCRC()
227             {
228                 return crc.getValue();
229             }
230
231             /**
232             * Reset the crc checker
233             */

234             public void reset()
235             {
236                 crc.reset();
237             }
238
239             /**
240             * Read one int and ensure the crc is updated
241             * @return int
242             */

243             public int read() throws IOException JavaDoc
244             {
245                 int x = super.read();
246                 crc.update(x);
247                 return x;
248             }
249
250             /**
251             * Read two ints
252             * @return int
253             */

254             public int read2() throws IOException JavaDoc, EOFException JavaDoc
255             {
256                 int a = read();
257                 int b = read();
258                 return a | b << 8;
259             }
260
261             /**
262             * Read two ints in reverse order
263             * @return int
264             */

265             public int read2n() throws IOException JavaDoc, EOFException JavaDoc
266             {
267                 int b = read();
268                 int a = read();
269                 return a | b << 8;
270             }
271
272             /**
273             * Read a long in reverse order
274             * @return long
275             */

276             public long read4n() throws IOException JavaDoc, EOFException JavaDoc
277             {
278                 long b = (long)read2n();
279                 long a = (long)read2n();
280                 return a | b << 16;
281             }
282         }
283
284
285         /**
286          * Private wrapper class for colors in RGBA float format
287          * Provides utilities to set Color from different input format
288          * And utilities to retrive them accordingly
289          */

290         //private
291
public class RGB
292         {
293             /** represents 15 bits format */
294             private static final int FORMAT_RGB5 = 0x8050;
295             /** represents 24 bits format */
296             private static final int FORMAT_RGB8 = 0x8051;
297             /** represents 16 bits format */
298             private static final int FORMAT_RGB5_A1 = 0x8057;
299             /** represents 32 bits format */
300             private static final int FORMAT_RGBA8 = 0x8058;
301
302             /** used to define color without alpha information */
303             private static final int NO_ALPHA = -1;
304
305             /** default alpha value */
306             private static final float DEFAULT_ALPHA = 1.0f;
307             /** used to define color with default format */
308             private static final float DEFAULT_FORMAT = 255.0f;
309
310             /** red value */
311             private float red;
312             /** green value */
313             private float green;
314             /** blue value */
315             private float blue;
316             /** alpha value */
317             private float alpha;
318
319             /**
320             * float gray constructor
321             * @param gray float
322             */

323             public RGB(float gray)
324             {
325                 set(gray, gray, gray, DEFAULT_ALPHA);
326             }
327
328             /**
329             * int gray constructor
330             * @param gray int
331             */

332             public RGB(int gray)
333             {
334                 set(gray, gray, gray, NO_ALPHA, NO_ALPHA);
335             }
336
337             /**
338             * int gray + alpha constructor
339             * @param gray int
340             * @param a int
341             */

342             public RGB(int gray, int a)
343             {
344                 set(gray, gray, gray, a, DEFAULT_FORMAT);
345             }
346
347             /**
348             * float gray + alpha constructor
349             * @param gray float
350             * @param a float
351             */

352             public RGB(float gray, float a)
353             {
354                 set(gray, gray, gray, a);
355             }
356
357             /**
358             * float r,g,b constructor
359             * @param r float
360             * @param g float
361             * @param b float
362             */

363             public RGB(float r, float g, float b)
364             {
365                 set(r, g, b, DEFAULT_ALPHA);
366             }
367
368             /**
369             * int r,g,b constructor
370             * @param r int
371             * @param g int
372             * @param b int
373             */

374             public RGB(int r, int g, int b)
375             {
376                 set(r, g, b, NO_ALPHA, NO_ALPHA);
377             }
378
379             /**
380             * int r,g,b + alpha constructor
381             * @param r int
382             * @param g int
383             * @param b int
384             * @param a int
385             */

386             public RGB(int r, int g, int b, int a)
387             {
388                 set((float)r / DEFAULT_FORMAT, (float)g / DEFAULT_FORMAT, (float)b / DEFAULT_FORMAT, (float) a/ DEFAULT_FORMAT);
389             }
390
391             /**
392             * float r,g,b + alpha constructor
393             * @param r float
394             * @param g float
395             * @param b float
396             * @param a float
397             */

398             public RGB(float r, float g, float b, float a)
399             {
400                 set(r, g, b, a);
401             }
402
403             /**
404             * general float r,g,b + alpha setter
405             * @param r float
406             * @param g float
407             * @param b float
408             * @param a float
409             */

410             public void set(float r, float g, float b, float a)
411             {
412                 red = r > 1.0f ? 1.0f : (r < 0.0f ? 0.0f : r);
413                 green = g > 1.0f ? 1.0f : (g < 0.0f ? 0.0f : g);
414                 blue = b > 1.0f ? 1.0f : (b < 0.0f ? 0.0f : b);
415                 alpha = a > 1.0f ? 1.0f : (a < 0.0f ? 0.0f : a);
416             }
417
418             /**
419             * general int r,g,b + alpha setter
420             * @param r int
421             * @param g int
422             * @param b int
423             * @param a int
424             * @param format float
425             */

426             public void set(int r, int g, int b, int a, float format)
427             {
428                 set((float)r / DEFAULT_FORMAT, (float)g / DEFAULT_FORMAT, (float)b / DEFAULT_FORMAT,
429                 format == NO_ALPHA ? DEFAULT_ALPHA : (float)a / format);
430             }
431
432             /**
433              * Return an int array of color packed in the requested format
434              * @param format int
435              * @return int[]
436              */

437             public int[] getPacked(int format)
438             {
439                 int r;
440                 int g;
441                 int b;
442                 switch(format)
443                 {
444                     case FORMAT_RGB5:
445                         r = (int)(red * 32.0f);
446                         g = (int)(green * 32.0f);
447                         b = (int)(blue * 32.0f);
448                         return new int[]
449                         {
450                             r + (g & 0x07) << 5,
451                             (g & 0x18) >> 3 + (b & 0x1f) << 2
452                         };
453                     case FORMAT_RGB8:
454                         return new int[]
455                         {
456                             (int)(red * 255.0f),
457                             (int)(green * 255.0f),
458                             (int)(blue * 255.0f)
459                         };
460                     case FORMAT_RGB5_A1:
461                         r = (int)(red * 32.0f);
462                         g = (int)(green * 32.0f);
463                         b = (int)(blue * 32.0f);
464                         return new int[]
465                         {
466                             r + (g & 0x07) << 5,
467                             (g & 0x18) >> 3 + (b & 0x1f) << 2 + (alpha > 0.5f ? 128 : 0)
468                         };
469                     case FORMAT_RGBA8:
470                         return new int[]
471                         {
472                             (int)(red * 255.0f),
473                             (int)(green * 255.0f),
474                             (int)(blue * 255.0f),
475                             (int)(alpha * 255.0f)
476                         };
477                     default:
478                         throw new IllegalArgumentException JavaDoc("Unknown color format "+format);
479                 }
480             }
481
482             /*
483             * get the red value as a float
484             * @return float
485             */

486             public float getRed()
487             {
488                 return red;
489             }
490
491             /*
492             * get the green value as a float
493             * @return float
494             */

495             public float getGreen()
496             {
497                 return green;
498             }
499
500             /*
501             * get the blue value as a float
502             * @return float
503             */

504             public float getBlue()
505             {
506                 return blue;
507             }
508
509             /*
510             * get the alpha value as a float
511             * @return float
512             */

513             public float getAlpha()
514             {
515                 return alpha;
516             }
517
518             /**
519             * Set the alpha value as a float
520             * @param alpha float
521             */

522             public void setAlpha(float alpha)
523             {
524                 this.alpha = alpha;
525             }
526
527             /*
528             * Compare to RGB colors (with or without alpha)
529             * @param rgb RGB the color to compare to
530             * @param compareAlpha boolean (use or not alpha in the comparison)
531             * @return boolean
532             */

533             public boolean compareTo(RGB rgb, boolean compareAlpha)
534             {
535                 if (rgb.getRed() == red && rgb.getGreen() == green && rgb.getBlue() == blue)
536                     if (!compareAlpha || (compareAlpha && rgb.getAlpha() == alpha))
537                         return true;
538                 return false;
539             }
540         }
541
542     /*
543     * Default constructor does nothing
544     * You need to use the setInputStream method to set the input
545     * before attempting to get the zlib buffer and info
546     */

547     public PNGHelper()
548     { }
549
550     /*
551     * Constructor. Allocates a Buffered Input Stream to optimises reading
552     * @param inputBuffer byte[]
553     */

554     public PNGHelper(byte[] inputBuffer)
555     {
556         setInputBuffer(inputBuffer);
557     }
558
559     /**
560      * Set the main inputStream and construct the CRCInputStream to read to
561      *
562      * @param inputBuffer buffer to read from
563      */

564     public void setInputBuffer(byte[] inputBuffer)
565     {
566         source = new CRCInputStream(new ByteArrayInputStream JavaDoc(inputBuffer));
567     }
568
569     /**
570      * Set the main inputStream and construct the CRCInputStream to read to
571      *
572      * @param fob buffer to read from
573      */

574     public void setInputBuffer(FlashBuffer fob)
575     {
576         //source = new CRCInputStream(new ByteArrayInputStream(fob.getBuf(),0,fob.getSize()));
577
source = new CRCInputStream(fob.getInputStream());
578     }
579
580     /**
581      * Return the width of the image
582      * @return width of the image
583      */

584     public int getWidth()
585     {
586         return width;
587     }
588
589     /**
590      * Return the height of the image
591      *
592      * @return height of the image
593      */

594     public int getHeight()
595     {
596         return height;
597     }
598
599     /*
600     * Return the palette size (= -1 if none)
601     * @return int
602     */

603     public int getColorTableSize()
604     {
605         return (colorsUsed -1);
606     }
607
608     /*
609     * Return transparency
610     * if colorType = 4 or 6, the image uses Alpha Channel
611     * Otherwise if a tRNS chunk has been seen
612     * @return boolean
613     */

614     public boolean hasTransparency()
615     {
616         return (colorType>3 || flagtRNS);
617     }
618
619     /*
620     * Return a color format compatible with Flash expectancy
621     * 3 = 8 bits; 4 = 16 bits; 5 = 32 bits
622     * Based on the colorType_components value
623     * And the bitDepth of image
624     * @return int
625     */

626     public int getFormat()
627     {
628         int format;
629         switch (colorType_components)
630         {
631             case 1:
632                 format = 3; // 8 bits
633
if (colorType == 0)
634                     format = 5;
635                 if (bitDepth == 16)
636                     format = 5;
637                 break;
638             //case 2:
639
//format = 4; // 16 bits : forget about it
640
//break;
641
default:
642                 format = 5; // 32 bits
643
break;
644         }
645         return format;
646     }
647
648     /*
649     * Return the zLib compressed Image data.
650     * We should be able to send back the IDAT buffer... unfortunately,
651     * its format is not recognised as such by Flash Player !
652     * So basically we need to compute our own zLib compression
653     * on data compatible with Flash
654     * This can be time consuming !
655     * @return DataMarker the zlibDatas
656     * @exception java.io.IOException
657     * @exception java.io.EOFException
658     */

659     public DataMarker getZlibData() throws IOException JavaDoc,EOFException JavaDoc,IVException
660     {
661         RGB[][] rgb = read();
662         boolean transparency = hasTransparency();
663         int format = getFormat();
664         int mult = 1;
665         switch (format)
666         {
667             case 4:
668                 mult = 2;
669                 break;
670             case 5:
671                 mult = 4;
672         }
673         byte[] tempData;
674         int plus = 3;
675         int[] pixel;
676         int idx = 0;
677         int falsewidth = width;
678         int added = 0;
679         int maxpixels = width * height;
680         // calculate padding (if needed)
681
if ((mult == 1) && (width % 4 > 0))
682         {
683             while (falsewidth % 4 > 0)
684             {
685                 falsewidth++;
686                 added++;
687             }
688             maxpixels = falsewidth * height;
689         }
690
691         if (colorType_hasPalette)
692         {
693             if (transparency) // Use RGBA palette
694
plus++;
695
696             tempData = new byte[(maxpixels) + (colorsUsed*plus)]; // Index + Palette RGB(A)
697
for (int i = 0; i < colorsUsed; i++)
698             {
699                 if (transparency)
700                     pixel = palette[i].getPacked(RGB.FORMAT_RGBA8);
701                 else
702                     pixel = palette[i].getPacked(RGB.FORMAT_RGB8);
703
704                 if (transparency && pixel[3] == 0x00) // the color itself should be 0
705
{
706                     tempData[idx++] = 0;
707                     tempData[idx++] = 0;
708                     tempData[idx++] = 0;
709                 }
710                 else
711                 {
712                     tempData[idx++] = (byte) ((pixel[0]));
713                     tempData[idx++] = (byte) ((pixel[1]));
714                     tempData[idx++] = (byte) ((pixel[2]));
715                 }
716                 if (transparency)
717                     tempData[idx++] = (byte) ((pixel[3]));
718             }
719         }
720         else
721         {
722             if (transparency)
723                 mult = 4;
724             tempData = new byte[(maxpixels * mult)]; // RGB (+ Alpha)
725
}
726
727         for (int y = 0; y < height; y++)
728         {
729             for (int x = 0; x < width; x++)
730             {
731                 if (colorType_hasPalette)
732                 {
733                     if (transparency)
734                         pixel = rgb[y][x].getPacked(RGB.FORMAT_RGBA8);
735                     else
736                         pixel = rgb[y][x].getPacked(RGB.FORMAT_RGB8);
737                     int b = 0;
738                     for (int i = 0; i < palette.length; i++)
739                     {
740                         if (palette[i].compareTo(rgb[y][x],false))
741                         {
742                             b = i;
743                             break;
744                         }
745                     }
746                     tempData[idx++] = (byte) b;
747                 }
748                 else
749                 {
750                     if (mult == 4)
751                         pixel = rgb[y][x].getPacked(RGB.FORMAT_RGBA8);
752                     else if (mult == 2)
753                         pixel = rgb[y][x].getPacked(RGB.FORMAT_RGB5_A1);
754                     else
755                         pixel = rgb[y][x].getPacked(RGB.FORMAT_RGB8);
756
757                     if (pixel != null)
758                     {
759                         if (mult == 4)
760                             tempData[idx++] = (byte) ((pixel[3]));
761                         tempData[idx++] = (byte) ((pixel[0]));
762                         if (mult > 1)
763                             tempData[idx++] = (byte) ((pixel[1]));
764                         if (mult == 4)
765                             tempData[idx++] = (byte) ((pixel[2]));
766                     }
767                 }
768             }
769             if (added > 0) // 32 bits padding for 8 bits image
770
{
771                 for (int i = 0; i < added; i++)
772                 {
773                     tempData[idx++] = 0x00;
774                 }
775             }
776         }
777         Deflater JavaDoc deflater = new Deflater JavaDoc(9); // MAXIMUM Compression
778
deflater.setInput(tempData);
779         byte[] data = new byte[(maxpixels * mult) + (colorsUsed*plus)];
780         deflater.finish();
781         int defsize = deflater.deflate(data);
782         byte[] buff = new byte[defsize];
783         System.arraycopy(data,0,buff,0,defsize);
784         DataMarker zlibDatas = new DataMarker(buff,0,defsize);
785         return zlibDatas;
786     }
787
788     /***********************************************************************************
789     ** PRIVATE IMPLEMENTATION **
790     ***********************************************************************************/

791
792     /*
793     * Reads the actual datas, return a multiDimentionnal RGB array : the pixels
794     * @return RGB[][]
795     * @exception java.io.IOException
796     * @exception java.io.EOFException
797     */

798     private RGB[][] read() throws IOException JavaDoc,EOFException JavaDoc,IVException
799     {
800         if (source == null)
801             throw new IOException JavaDoc("Null input stream");
802         source.mark(Integer.MAX_VALUE);
803         buffer = new byte[0];
804         try
805         {
806             for (int i = 0; i < 8; i++)
807                 if (source.read() != PNG_SIGN[i])
808                     throw new IOException JavaDoc("Not a valid PNG file");
809
810             int length;
811             int id;
812             while(true)
813             {
814                 length = (int)source.read4n();
815                 source.reset();
816                 id = (int)source.read4n();
817                 switch(id)
818                 {
819                     // Critical chunks
820
case CHUNK_IHDR: readChunk_IHDR(length); break;
821                     case CHUNK_PLTE: readChunk_PLTE(length); break;
822                     case CHUNK_tRNS: readChunk_tRNS(length); break;
823                     case CHUNK_IDAT: readChunk_IDAT(length); break;
824                     case CHUNK_IEND:
825                         if (!flagIHDR || !flagIDAT)
826                             throw new IOException JavaDoc("No header or data chunk found");
827                         return decode(buffer);
828
829                     // known, ignored chunks
830
case CHUNK_gAMA: readChunk_gAMA(length); break; // read only for now
831
case CHUNK_bKGD:
832                     case CHUNK_cHRM: // we might need this one later for advanced color handling
833
case CHUNK_fRAc:
834                     case CHUNK_gIFg:
835                     case CHUNK_gIFt:
836                     case CHUNK_gIFx:
837                     case CHUNK_hIST:
838                     case CHUNK_iCCP: // we might need this one later for advanced color handling
839
case CHUNK_iTXt:
840                     case CHUNK_oFFs:
841                     case CHUNK_pCAL:
842                     case CHUNK_pHYs:
843                     case CHUNK_sBIT:
844                     case CHUNK_sCAL:
845                     case CHUNK_sPLT: // we might need this one later for advanced color handling
846
case CHUNK_sRGB: // we might need this one later for advanced color handling
847
case CHUNK_tEXt:
848                     case CHUNK_tIME:
849                     case CHUNK_zTXt:
850                         source.skipBytes(length + 4); // skip it and its CRC code
851
break;
852                     default:
853                         // unknown chunk...
854
if ( (id & 0x20000000) == 0)
855                             // if critical we throw...
856
throw new IOException JavaDoc("Unknown critical chunk "+
857                                 (char)((id >> 24) & 0xff) + (char)((id >> 16) & 0xff) +
858                                 (char)((id >> 8) & 0xff) + (char)(id & 0xff));
859                             // otherwise, skip that chunk and its CRC code
860
source.skipBytes(length + 4);
861                 }
862             }
863         }
864         catch (EOFException JavaDoc eofe)
865         {
866             throw new EOFException JavaDoc("Reached unexpected EOF");
867         }
868         catch(IOException JavaDoc ioe)
869         {
870             throw new IOException JavaDoc("Error while reading file");
871         }
872     }
873
874     /**
875     * Deal with the gamma chunk
876     * @param length int the length of the chunk to read
877     * @exception java.io.IOException
878     */

879     private void readChunk_gAMA(int length) throws IOException JavaDoc
880     {
881         if (flagIDAT || flagPLTE)
882             throw new IOException JavaDoc("gAMA chunk must precede IDAT and PLTE chunks");
883
884         if (length != 4)
885             throw new IOException JavaDoc("Invalid length " + length + " for gAMA chunk");
886
887         gamma = source.read4n(); // the float value will be : (val / 100000)
888

889         long okCRC = source.getCRC();
890         if (source.read4n() != okCRC)
891             throw new IOException JavaDoc("Invalid CRC for gAMA chunk " + length);
892     }
893
894     /**
895     * Deal with the transparency chunk
896     * @param length int the length of the chunk to read
897     * @exception java.io.IOException
898     */

899     private void readChunk_tRNS(int length) throws IOException JavaDoc
900     {
901         if (!flagIHDR || flagIDAT)
902             throw new IOException JavaDoc("Misplaced transparency chunk");
903
904         switch(colorType)
905         {
906             case 0: // grayscale
907
int tmp1 = source.read();
908                 int tmp2 = source.read();
909
910                 if (bitDepth < 16)
911                 {
912                     int max = 1;
913                     switch (bitDepth)
914                     {
915                         case 1:
916                             max = 256;
917                             break;
918                         case 2:
919                             max = 256/4;
920                             break;
921                         case 4:
922                             max = 256/16;
923                             break;
924                     }
925                     if (bitDepth == 1) // (0x00 or 0xff)
926
tRNSKeyColor = new RGB(tmp2*max);
927                     else
928                     {
929                         tmp1 = ((tmp2 + 1) * max) - 1;
930                         tmp1 = (tmp1 < 0) ? 0 : tmp1;
931                         tRNSKeyColor = new RGB(tmp1);
932                     }
933                 }
934                 else
935                     tRNSKeyColor = new RGB((float)(tmp1 << 8 | tmp2) / 65535.0f);
936
937                 tRNSKeyColor.setAlpha(0.0f);
938                 tRNSPassRequired = true;
939                 break;
940             case 2: // RGB
941
int tmp;
942                 int cr1 = source.read();
943                 int cr2 = source.read();
944                 int cg1 = source.read();
945                 int cg2 = source.read();
946                 int cb1 = source.read();
947                 int cb2 = source.read();
948                 if (bitDepth < 16)
949                 {
950                     tRNSKeyColor = new RGB(cr2, cg2, cb2);
951                 }
952                 else
953                     tRNSKeyColor = new RGB((float)(cr1 << 8 | cr2) / 65535.0f,
954                         (float)(cg1 << 8 | cg2) / 65535.0f, (float)(cb1 << 8 | cb2) / 65535.0f);
955                 tRNSKeyColor.setAlpha(0.0f);
956                 tRNSPassRequired = true;
957                 break;
958             case 3: // paletted
959
// update palette entries with alpha information
960
for (int i = 0; i < length; i++)
961                     palette[i].setAlpha((float)source.read() / 255.0f);
962                 break;
963             default: // 4 and 6 colorType should not have tranparency chunk, they have Alpha channel instead
964
throw new IOException JavaDoc("Unexpected transparency chunk");
965         }
966         flagtRNS = true;
967
968         long okCRC = source.getCRC();
969         if (source.read4n() != okCRC)
970             throw new IOException JavaDoc("Invalid CRC for tRNS chunk " + length);
971     }
972
973     /**
974     * Deal with the palette chunk
975     * @param length int the length of the chunk to read
976     * @exception java.io.IOException
977     */

978     private void readChunk_PLTE(int length) throws IOException JavaDoc
979     {
980         if (!flagIHDR || flagIDAT)
981             throw new IOException JavaDoc("Misplaced palette chunk");
982
983         if (length % 3 != 0)
984             throw new IOException JavaDoc("Invalid palette size: "+ length +" bytes");
985         if (colorType != 3)
986         {
987             // throw new IOException("Palette must not appear in grayscale or RGB images");
988
// eat the entries
989
int tmp;
990             for (int i = 0; i < length; i++)
991                 tmp = source.read();
992         }
993         else
994         {
995             flagPLTE = true;
996             int entries = length / 3;
997             colorsUsed = entries;
998             palette = new RGB[entries];
999             for (int i = 0; i < entries; i++)
1000                palette[i] = new RGB(source.read(), source.read(), source.read());
1001        }
1002        long okCRC = source.getCRC();
1003        if (source.read4n() != okCRC)
1004                throw new IOException JavaDoc("Invalid CRC for PLTE chunk");
1005    }
1006
1007    /**
1008    * Deal with the header chunk
1009    * @param length int the length of the chunk to read
1010    * @exception java.io.IOException
1011    */

1012    private void readChunk_IHDR(int length) throws IOException JavaDoc
1013    {
1014        if (flagIHDR)
1015            throw new IOException JavaDoc("Duplicate header chunks");
1016        flagIHDR = true;
1017
1018        width = (int)source.read4n();
1019        height = (int)source.read4n();
1020        bitDepth = source.read();
1021        colorType = source.read();
1022        compressionMethod = source.read();
1023        filterMethod = source.read();
1024        interlaceMethod = source.read();
1025
1026        if ( (width == 0) || (height == 0) )
1027            throw new IOException JavaDoc("Invalid image size: "+width+"x"+height);
1028        switch(colorType)
1029        {
1030            case 0: // grayscale: 1, 2, 4, 8, 16
1031
if ( (bitDepth != 1) && (bitDepth != 2) && (bitDepth != 4) &&
1032                    (bitDepth != 8) && (bitDepth != 16) )
1033                    throw new IOException JavaDoc
1034                        ("Invalid bit depth: "+ bitDepth +" for color type: grayscale");
1035                colorType_components = 1;
1036                //colorType_hasPalette = false;
1037
//colorType_hasColor = false;
1038
//colorType_hasAlpha = false;
1039
break;
1040            case 3: // paletted: 1, 2, 4, 8
1041
if ( (bitDepth != 1) && (bitDepth != 2) && (bitDepth != 4) && (bitDepth != 8) )
1042                    throw new IOException JavaDoc
1043                        ("Invalid bit depth: "+ bitDepth +" for color type: paletted");
1044                colorType_components = 1;
1045                colorType_hasPalette = true;
1046                colorType_hasColor = true;
1047                //colorType_hasAlpha = false;
1048
break;
1049            case 2: // RGB: 8, 16
1050
if ( (bitDepth != 8) && (bitDepth != 16) )
1051                    throw new IOException JavaDoc
1052                        ("Invalid bit depth: "+ bitDepth +" for color type: RGB");
1053                colorType_components = 3;
1054                //colorType_hasPalette = false;
1055
colorType_hasColor = true;
1056                //colorType_hasAlpha = false;
1057
break;
1058            case 4: // gray + alpha: 8, 16
1059
if ( (bitDepth != 8) && (bitDepth != 16) )
1060                    throw new IOException JavaDoc
1061                        ("Invalid bit depth: "+ bitDepth +" for color type: gray + alpha");
1062                colorType_components = 2;
1063                //colorType_hasPalette = false;
1064
//colorType_hasColor = false;
1065
colorType_hasAlpha = true;
1066                break;
1067            case 6: // RGB + alpha: 8, 16
1068
if ( (bitDepth != 8) && (bitDepth != 16) )
1069                    throw new IOException JavaDoc
1070                        ("Invalid bit depth: "+ bitDepth +" for color type: RGB + alpha");
1071                colorType_components = 4;
1072                //colorType_hasPalette = false;
1073
colorType_hasColor = true;
1074                colorType_hasAlpha = true;
1075                break;
1076            default:
1077                throw new IOException JavaDoc("Invalid color type: "+ colorType);
1078        }
1079        if (compressionMethod != 0)
1080            throw new IOException JavaDoc
1081                ("Unsupported compression method: "+ compressionMethod);
1082        if (filterMethod != 0)
1083            throw new IOException JavaDoc("Unsupported filter method: "+ compressionMethod);
1084        if ( (interlaceMethod != 0) && (interlaceMethod != 1) )
1085            throw new IOException JavaDoc("Unsupported interlace method: "+ interlaceMethod);
1086
1087        long okCRC = source.getCRC();
1088        if (source.read4n() != okCRC)
1089            throw new IOException JavaDoc("Invalid CRC for IHDR chunk");
1090    }
1091
1092    /**
1093    * Deal with data chunks
1094    * @param length int the length of the chunk to read
1095    * @exception java.io.IOException
1096    */

1097    private void readChunk_IDAT(int length) throws IOException JavaDoc
1098    {
1099        if (!flagIHDR)
1100            throw new IOException JavaDoc("Data chunks before header");
1101        if ( (colorType == 3) && (!flagPLTE) )
1102            throw new IOException JavaDoc("Missing palette");
1103        flagIDAT = true;
1104
1105        int oldLength = buffer.length;
1106        int newLength = oldLength + length;
1107        byte[] zlibNew = new byte[newLength];
1108        System.arraycopy(buffer, 0, zlibNew, 0, oldLength);
1109
1110        for (int i = oldLength; i < newLength; i++)
1111            zlibNew[i] = (byte)source.read();
1112
1113        buffer = zlibNew;
1114
1115        long okCRC = source.getCRC();
1116        if (source.read4n() != okCRC)
1117            throw new IOException JavaDoc("Invalid CRC for IDAT chunk");
1118    }
1119
1120    /*
1121    * Decodes the zLib buffer according to compression/filtering
1122    * and return an array of pixel computed based on the colorType/bitDepth
1123    * need to take interlaced method (Adam7) into account
1124    * @param zlibStream byte[]
1125    * @return RGB[][]
1126    * @exception java.io.IOException
1127    */

1128    private RGB[][] decode(byte[] zlibStream) throws IOException JavaDoc
1129    {
1130        InflaterInputStream JavaDoc inflater = new InflaterInputStream JavaDoc(
1131                    new java.io.ByteArrayInputStream JavaDoc(zlibStream));
1132
1133        int bytesPerScanline = (int)( (float)width *
1134                                    (float)bitDepth *
1135                                    (float)colorType_components / 8.0f );
1136
1137        // add 1 byte of padding for paletted colors of less than 8 bit depth
1138
if (colorType==3)
1139        {
1140            // width/bitdepth
1141
switch (bitDepth)
1142            {
1143                case 1:
1144                    if ((width%8)>0)
1145                        bytesPerScanline++;
1146                        break;
1147                case 2:
1148                    if ((width%4)>0)
1149                        bytesPerScanline++;
1150                    break;
1151                case 4:
1152                    if ((width%2)>0)
1153                        bytesPerScanline++;
1154                    break;
1155            }
1156        }
1157
1158        RGB[][] rgb = new RGB[height][width];
1159
1160        // decompressing // deinterlacing (if needed) and process color (if needed)
1161
if (interlaceMethod == 1 && bitDepth < 8)
1162        {
1163            // special case with padding involved, colors will already be decoded
1164
rgb = deCompressSpecial(rgb, inflater);
1165        }
1166        else
1167        {
1168            int bytesPerPixel = bitDepth * colorType_components / 8;
1169            bytesPerPixel = (bytesPerPixel == 0) ? 1 : bytesPerPixel;
1170
1171            int[][] scanlines = new int[height][bytesPerScanline];
1172            scanlines = deCompress(scanlines, inflater, bytesPerPixel);
1173
1174            // decoding byte values to pixel values
1175
int b, bb; // temp
1176
int cr, cg, cb, ca;
1177            switch(colorType)
1178            {
1179
1180                case 0: // grayscale: 1, 2, 4, 8, 16
1181
switch(bitDepth)
1182                    {
1183                        case 1:
1184                            for (int y = 0; y < height; y++)
1185                            {
1186                                int scanX = 0;
1187                                for (int x = 0; x < width;)
1188                                {
1189                                    b = scanlines[y][scanX++];
1190                                    for (int z = 7; ((x < width) && (z > -1)) ; z--)
1191                                    {
1192                                        bb = ((b >> z) & 0x01) * 256;
1193                                        RGB color = new RGB(bb, bb, bb);
1194                                        if (tRNSPassRequired) // Apply transparency
1195
{
1196                                            if (color.compareTo(tRNSKeyColor,false)) // on the right color
1197
{
1198                                                color = new RGB(0);
1199                                                color.setAlpha(0.0f);
1200                                            }
1201                                        }
1202                                        rgb[y][x++] = color;
1203                                    }
1204                                }
1205                            }
1206                            break;
1207                        case 2:
1208                            for (int y = 0; y < height; y++)
1209                            {
1210                                int scanX = 0;
1211                                for (int x = 0; x < width;)
1212                                {
1213                                    b = scanlines[y][scanX++];
1214                                    for (int z = 6; ((x < width) && (z > -1)) ; z -= 2)
1215                                    {
1216                                        bb = ((((b >> z) & 0x03) + 1) * 64) - 1;
1217                                        bb = (bb < 0) ? 0 : bb;
1218                                        RGB color = new RGB(bb, bb, bb);
1219                                        if (tRNSPassRequired) // Apply transparency
1220
{
1221                                            if (color.compareTo(tRNSKeyColor,false)) // on the right color
1222
{
1223                                                color = new RGB(0);
1224                                                color.setAlpha(0.0f);
1225                                            }
1226                                        }
1227                                        rgb[y][x++] = color;
1228                                    }
1229                                }
1230                            }
1231                            break;
1232                        case 4:
1233                            for (int y = 0; y < height; y++)
1234                            {
1235                                int scanX = 0;
1236                                for (int x = 0; x < width;)
1237                                {
1238                                    b = scanlines[y][scanX++];
1239                                    bb = ((((b >> 4) & 0x0f) + 1) * 16) - 1;
1240                                    bb = (bb < 0) ? 0 : bb;
1241                                    RGB color = new RGB(bb, bb, bb);
1242                                    if (tRNSPassRequired) // Apply transparency
1243
{
1244                                        if (color.compareTo(tRNSKeyColor,false)) // on the right color
1245
{
1246                                            color = new RGB(0);
1247                                            color.setAlpha(0.0f);
1248                                        }
1249                                    }
1250                                    rgb[y][x++] = color;
1251                                    if (x < width)
1252                                    {
1253                                        bb = ((( b & 0x0f) + 1) * 16) -1;
1254                                        bb = (bb < 0) ? 0 : bb;
1255                                        color = new RGB(bb, bb, bb);
1256                                        if (tRNSPassRequired) // Apply transparency
1257
{
1258                                            if (color.compareTo(tRNSKeyColor,false)) // on the right color
1259
{
1260                                                color = new RGB(0);
1261                                                color.setAlpha(0.0f);
1262                                            }
1263                                        }
1264                                        rgb[y][x++] = color;
1265                                    }
1266                                }
1267                            }
1268                            break;
1269                        case 8:
1270                            for (int y = 0; y < height; y++)
1271                            {
1272                                for (int x = 0; x < width; x++)
1273                                {
1274                                    RGB color = new RGB(scanlines[y][x]);
1275                                    if (tRNSPassRequired) // Apply transparency
1276
{
1277                                        if (color.compareTo(tRNSKeyColor,false)) // on the right color
1278
{
1279                                            color = new RGB(0);
1280                                            color.setAlpha(0.0f);
1281                                        }
1282                                    }
1283                                    rgb[y][x] = color;
1284                                }
1285                            }
1286                            break;
1287                        case 16:
1288                            for (int y = 0; y < height; y++)
1289                            {
1290                                int scanX = 0;
1291                                for (int x = 0; x < width; x++)
1292                                {
1293                                    RGB color = new RGB ((float)(scanlines[y][scanX++] << 8 |
1294                                                        scanlines[y][scanX++]) / 65535.0f);
1295                                    if (tRNSPassRequired) // Apply transparency
1296
{
1297                                        if (color.compareTo(tRNSKeyColor,false)) // on the right color
1298
{
1299                                            color = new RGB(0);
1300                                            color.setAlpha(0.0f);
1301                                        }
1302                                    }
1303                                    rgb[y][x] = color;
1304                                }
1305                            }
1306                            break;
1307                    }
1308                    break;
1309
1310                case 2: // RGB: 8, 16
1311
switch(bitDepth)
1312                    {
1313                        case 8:
1314                            for (int y = 0; y < height; y++)
1315                            {
1316                                int scanX = 0;
1317                                for (int x = 0; x < width; x++)
1318                                {
1319                                    RGB color = new RGB(scanlines[y][scanX++],
1320                                                        scanlines[y][scanX++],
1321                                                        scanlines[y][scanX++]);
1322                                    if (tRNSPassRequired) // Apply transparency
1323
{
1324                                        if (color.compareTo(tRNSKeyColor,false)) // on the right color
1325
{
1326                                            color = new RGB(0);
1327                                            color.setAlpha(0.0f);
1328                                        }
1329                                    }
1330                                    rgb[y][x] = color;
1331                                }
1332                            }
1333                            break;
1334                        case 16:
1335                            // this one is really weird, further tests will be required
1336
for (int y = 0; y < height; y++)
1337                            {
1338                                int scanX = 0;
1339                                for (int x = 0; x < width; x++)
1340                                {
1341                                    float aa = (float)(scanlines[y][scanX++] << 8 |
1342                                                        scanlines[y][scanX++]) / 65535.0f;
1343                                    float ab = (float)(scanlines[y][scanX++] << 8 |
1344                                                        scanlines[y][scanX++]) / 65535.0f;
1345                                    float ac = (float)(scanlines[y][scanX++] << 8 |
1346                                                        scanlines[y][scanX++]) / 65535.0f;
1347                                    RGB color = new RGB(aa, ab, ac);
1348
1349                                    if (tRNSPassRequired) // Apply transparency
1350
{
1351                                        if (color.compareTo(tRNSKeyColor,false)) // on the right color
1352
{
1353                                            color = new RGB(0);
1354                                            color.setAlpha(0.0f);
1355                                        }
1356                                    }
1357                                    rgb[x][y] = color;
1358                                }
1359                            }
1360                            break;
1361                    }
1362                    break;
1363                case 3: // paletted: 1, 2, 4, 8
1364
switch(bitDepth)
1365                    {
1366                        case 1:
1367                            for (int y = 0; y < height; y++)
1368                            {
1369                                int scanX = 0;
1370                                for (int x = 0; x < width;)
1371                                {
1372                                    if (scanX < bytesPerScanline)
1373                                    {
1374                                        b = scanlines[y][scanX++];
1375                                        for (int z = 7; ((x < width) && (z > -1)) ; z--)
1376                                        {
1377                                            bb = (b >> z) & 0x01;
1378                                            rgb[y][x++] = palette[bb];
1379                                        }
1380                                    }
1381                                    else
1382                                        break;
1383                                }
1384                            }
1385                            break;
1386                        case 2:
1387                            for (int y = 0; y < height; y++)
1388                            {
1389                                int scanX = 0;
1390                                for (int x = 0; x < width;)
1391                                {
1392                                    if (scanX < bytesPerScanline)
1393                                    {
1394                                        b = scanlines[y][scanX++];
1395                                        for (int z = 6; ((x < width) && (z > -1)) ; z -= 2)
1396                                        {
1397                                            bb = (b >> z) & 0x03;
1398                                            rgb[y][x++] = palette[bb];
1399                                        }
1400                                    }
1401                                    else
1402                                        break;
1403                                }
1404                            }
1405                            break;
1406                        case 4:
1407                            for (int y = 0; y < height; y++)
1408                            {
1409                                int scanX = 0;
1410                                for (int x = 0; x < width;)
1411                                {
1412                                    if (scanX <= bytesPerScanline)
1413                                    {
1414                                        b = scanlines[y][scanX++];
1415                                        bb = (b >> 4) & 0x0f;
1416                                        rgb[y][x++] = palette[bb];
1417                                        if (x < width)
1418                                        {
1419                                            bb = b & 0x0f;
1420                                            rgb[y][x++] = palette[bb];
1421                                        }
1422                                    }
1423                                    else
1424                                        break;
1425                                }
1426                            }
1427                            break;
1428                        case 8:
1429                            for (int y = 0; y < height; y++)
1430                            {
1431                                for (int x = 0; x < width; x++)
1432                                {
1433                                    b = scanlines[y][x];
1434                                    // to be on the safe side
1435
b = (b < palette.length) ? b : 0;
1436                                    rgb[y][x] = palette[b];
1437                                }
1438                            }
1439                            break;
1440                    }
1441                    break;
1442                case 4: // gray + alpha: 8, 16
1443
switch(bitDepth)
1444                    {
1445                        case 8:
1446                            for (int y = 0; y < height; y++)
1447                            {
1448                                int scanX = 0;
1449                                for (int x = 0; x < width; x++)
1450                                {
1451                                    // cr used as 'gray'
1452
cr = scanlines[y][scanX++];
1453                                    ca = scanlines[y][scanX++];
1454
1455                                    // apply alpha
1456
float fa = (float)ca/255.0f;
1457                                    cr = (int)(cr*fa);
1458
1459                                    rgb[y][x] = new RGB(cr, ca);
1460                                }
1461                            }
1462                            break;
1463                        case 16:
1464                            for (int y = 0; y < height; y++)
1465                            {
1466                                int scanX = 0;
1467                                for (int x = 0; x < width; x++)
1468                                {
1469                                    // aa used as 'gray'
1470
float aa = (float)(scanlines[y][scanX++] << 8 |
1471                                                        scanlines[y][scanX++]) / 65535.0f;
1472                                    float ab = (float)(scanlines[y][scanX++] << 8 |
1473                                                        scanlines[y][scanX++]) / 65535.0f;
1474
1475                                    // apply alpha
1476
aa *= ab;
1477
1478                                    rgb[y][x] = new RGB(aa, ab);
1479                                }
1480                            }
1481                            break;
1482                    }
1483                    break;
1484                case 6: // RGB + alpha: 8, 16
1485
switch(bitDepth)
1486                    {
1487                        case 8:
1488                            int idx = 0;
1489                            for (int y = 0; y < height; y++)
1490                            {
1491                                int scanX = 0;
1492                                for (int x = 0; x < width; x++)
1493                                {
1494                                    cr = scanlines[y][scanX++];
1495                                    cg = scanlines[y][scanX++];
1496                                    cb = scanlines[y][scanX++];
1497                                    ca = scanlines[y][scanX++];
1498
1499                                    // apply alpha
1500
if (ca == 0) {
1501                                        cr = cg = cb = 0;
1502                                    } else {
1503                                        float fa = (float)ca/255.0f;
1504                                        cr = (int)((cr)*fa);
1505                                        cg = (int)((cg)*fa);
1506                                        cb = (int)((cb)*fa);
1507                                    }
1508
1509                                    rgb[y][x] = new RGB(cr, cg, cb, ca);
1510                                }
1511                            }
1512                            break;
1513                        case 16:
1514                            for (int y = 0; y < height; y++)
1515                            {
1516                                int scanX = 0;
1517                                for (int x = 0; x < width; x++)
1518                                {
1519                                    float aa = (float)(scanlines[y][scanX++] << 8 |
1520                                                        scanlines[y][scanX++]) / 65535.0f;
1521                                    float ab = (float)(scanlines[y][scanX++] << 8 |
1522                                                        scanlines[y][scanX++]) / 65535.0f;
1523                                    float ac = (float)(scanlines[y][scanX++] << 8 |
1524                                                        scanlines[y][scanX++]) / 65535.0f;
1525                                    float ad = (float)(scanlines[y][scanX++] << 8 |
1526                                                        scanlines[y][scanX++]) / 65535.0f;
1527
1528                                    // apply alpha
1529
aa *= ad;
1530                                    ab *= ad;
1531                                    ac *= ad;
1532
1533                                    rgb[y][x] = new RGB(aa, ab, ac, ad);
1534                                }
1535                            }
1536                            break;
1537                    }
1538            }
1539        }
1540        return rgb;
1541    }
1542
1543    /**
1544    * get the previous row value of the pass
1545    * @param row int the current row
1546    * @param pass int the current pass
1547    * @return int
1548    */

1549    private int getPreviousRow(int row, int pass)
1550    {
1551        if (interlaceMethod == 1)
1552        {
1553            int[] starting_Row = { 0, 0, 4, 0, 2, 0, 1 };
1554            int[] row_Increment = { 8, 8, 8, 4, 4, 2, 2 };
1555            int currentPassMin = starting_Row[pass];
1556            if (row == currentPassMin)
1557                return 0;
1558            else
1559                return ((row > (row - row_Increment[pass])) ? (row - row_Increment[pass]) : 0);
1560        }
1561        else
1562        {
1563            return ((row > 0) ? (row - 1) : 0);
1564        }
1565    }
1566
1567    /**
1568    * get the previous column value of the pass
1569    * @param col int the current column
1570    * @param pass int the current pass
1571    * @return int
1572    */

1573    private int getPreviousCol(int col, int pass)
1574    {
1575        if (interlaceMethod == 1)
1576        {
1577            int[] starting_Col = { 0, 4, 0, 2, 0, 1, 0 };
1578            int[] col_Increment = { 8, 8, 4, 4, 2, 2, 1 };
1579            int currentPassMin = starting_Col[pass];
1580            if (col == currentPassMin)
1581                return 0;
1582            else
1583                return ((col > (col - col_Increment[pass])) ? (col - col_Increment[pass]) : 0);
1584        }
1585        else
1586        {
1587            return ((col > 0) ? (col - 1) : 0);
1588        }
1589    }
1590
1591    /**
1592    * Decompress, deinterlace, unfilter and set the pixels colors
1593    * Used for special interlaced images of less than 8 bit depth (padding involved)
1594    * @param rgb RGB[][] the RGB colors of pixels
1595    * @param inflater InputStream the inflater InputStream to read the zlib data from
1596    * @return RGB[][] the RGB colors of pixels set
1597    * @Exception java.io.IOException
1598    */

1599    private RGB[][] deCompressSpecial(RGB[][] rgb, InputStream JavaDoc inflater) throws IOException JavaDoc
1600    {
1601        int[] starting_Row = { 0, 0, 4, 0, 2, 0, 1 };
1602        int[] starting_Col = { 0, 4, 0, 2, 0, 1, 0 };
1603        int[] row_Increment = { 8, 8, 8, 4, 4, 2, 2 };
1604        int[] col_Increment = { 8, 8, 4, 4, 2, 2, 1 };
1605        int[] block_Height = { 8, 8, 4, 4, 2, 2, 1 };
1606        int[] block_Width = { 8, 4, 4, 2, 2, 1, 1 };
1607
1608        int row, col, filter;
1609
1610        int [][] pixels = new int[height][width];
1611
1612        int a, b, c, pa, pb, pc, p; // for paeth filter
1613

1614        for (int pass = 0; pass < 7; pass++)
1615        {
1616            row = starting_Row[pass];
1617            while (row < height)
1618            {
1619                int minHeight = (block_Height[pass] < (height - row)) ? block_Height[pass] : (height - row);
1620                b = inflater.read();
1621                if (b > -1)
1622                {
1623                    filter = (b >> 4) & 0x03;
1624
1625                    col = starting_Col[pass];
1626                    while (col < width)
1627                    {
1628                        int minWidth = (block_Width[pass] < (width - col)) ? block_Width[pass] : (width - col);
1629                        b = inflater.read();
1630                        if (b > -1)
1631                        {
1632                            switch (bitDepth)
1633                            {
1634                                case 1:
1635                                    for (int i = 7; i > -1; i--)
1636                                    {
1637                                        if (col < width)
1638                                        {
1639                                            a = (b >> i) & 0x01;
1640                                            for (int x = 0; x < minHeight; x++)
1641                                            {
1642                                                int rowx = row + x;
1643                                                if (rowx < height)
1644                                                {
1645                                                    for (int y = 0; y < minWidth; y++)
1646                                                    {
1647                                                        int coly = col + y;
1648                                                        if (coly < width)
1649                                                            pixels[rowx][coly] = a;
1650                                                        else
1651                                                            break;
1652                                                    }
1653                                                }
1654                                                else
1655                                                    break;
1656                                            }
1657                                        }
1658                                        else
1659                                            break;
1660                                        col += col_Increment[pass];
1661                                    }
1662                                    break;
1663                                case 2:
1664                                    for (int i = 6; i > -1; i -= 2)
1665                                    {
1666                                        if (col < width)
1667                                        {
1668                                            a = (b >> i) & 0x03;
1669                                            for (int x = 0; x < minHeight; x++)
1670                                            {
1671                                                int rowx = row + x;
1672                                                if (rowx < height)
1673                                                {
1674                                                    for (int y = 0; y < minWidth; y++)
1675                                                    {
1676                                                        int coly = col + y;
1677                                                        if (coly < width)
1678                                                            pixels[rowx][coly] = a;
1679                                                        else
1680                                                            break;
1681                                                    }
1682                                                }
1683                                                else
1684                                                    break;
1685                                            }
1686                                        }
1687                                        else
1688                                            break;
1689                                        col += col_Increment[pass];
1690                                    }
1691                                    break;
1692                                case 4:
1693                                    for (int i = 4; i > -1; i -= 4)
1694                                    {
1695                                        if (col < width)
1696                                        {
1697                                            a = (b >> i) & 0x0f;
1698                                            for (int x = 0; x < minHeight; x++)
1699                                            {
1700                                                int rowx = row + x;
1701                                                if (rowx < height)
1702                                                {
1703                                                    for (int y = 0; y < minWidth; y++)
1704                                                    {
1705                                                        int coly = col + y;
1706                                                        if (coly < width)
1707                                                            pixels[rowx][coly] = a;
1708                                                        else
1709                                                            break;
1710                                                    }
1711                                                }
1712                                                else
1713                                                    break;
1714                                            }
1715                                        }
1716                                        else
1717                                            break;
1718                                        col += col_Increment[pass];
1719                                    }
1720                                    break;
1721                            }
1722                        }
1723                        else
1724                            break;
1725                    }
1726
1727                    // Cast to byte when filtering to use modulo 256 arithmetic
1728
int nbboucle = 8/bitDepth;
1729                    switch(filter)
1730                    {
1731                        case 0:
1732                            // no filtering
1733
break;
1734                        case 1: // sub
1735
col = starting_Col[pass] + col_Increment[pass];
1736                            while (col < width)
1737                            {
1738                                for (int i = 0; i < nbboucle; i++)
1739                                {
1740                                    if (col < width)
1741                                    {
1742                                        pixels[row][col] = (byte)(pixels[row][col] +
1743                                                        pixels[row][getPreviousCol(col,pass)])
1744                                                        & 0xff;
1745                                    }
1746                                    col += col_Increment[pass];
1747                                }
1748                            }
1749                            break;
1750                        case 2: // up
1751
if (row == 0)
1752                                break;
1753                            col = starting_Col[pass];
1754                            while (col < width)
1755                            {
1756                                for (int i = 0; i < nbboucle; i++)
1757                                {
1758                                    if (col < width)
1759                                    {
1760                                        pixels[row][col] = (byte)(pixels[row][col] +
1761                                                        pixels[getPreviousRow(row,pass)][col])
1762                                                        & 0xff;
1763                                    }
1764                                    col += col_Increment[pass];
1765                                }
1766                            }
1767                            break;
1768                        case 3: // average
1769
col = starting_Col[pass];
1770                            pixels[row][col] = (byte)(pixels[row][col] + (((row == 0) ? 0 : pixels[getPreviousRow(row,pass)][col]) / 2) ) & 0xff;
1771                            col += col_Increment[pass];
1772                            while (col < width)
1773                            {
1774                                pixels[row][col] = (byte)(pixels[row][col] +
1775                                                (pixels[row][getPreviousCol(col,pass)] +
1776                                                ((row == 0) ? 0 : pixels[getPreviousRow(row,pass)][col])) / 2) & 0xff;
1777
1778                                col += col_Increment[pass];
1779                            }
1780                            break;
1781                        case 4: // paeth
1782
if (row == 0)
1783                            {
1784                                col = starting_Col[pass];
1785                                pixels[row][col] = 0xff & pixels[row][col];
1786                                col += col_Increment[pass];
1787
1788                                while (col < width)
1789                                {
1790                                    p = pixels[row][getPreviousCol(col,pass)];
1791                                    pixels[row][col] = 0xff & (byte)(p + pixels[row][col]);
1792                                    col += col_Increment[pass];
1793                                }
1794                            }
1795                            else
1796                            {
1797                                col = starting_Col[pass];
1798                                pixels[row][col] = 0xff & (byte)(pixels[getPreviousRow(row,pass)][col] + pixels[row][col]);
1799                                col += col_Increment[pass];
1800
1801                                while (col < width)
1802                                {
1803                                    a = pixels[row][getPreviousCol(col,pass)]; // left
1804
b = pixels[getPreviousRow(row,pass)][col]; // above
1805
c = pixels[getPreviousRow(row,pass)][getPreviousCol(col,pass)]; // upper left
1806

1807                                    // Paeth tests
1808
p = (a + b) - c; // initial estimate
1809
pa = p > a ? p - a : a - p; // nearest distance to a
1810
pb = p > b ? p - b : b - p; // nearest distance to b
1811
pc = p > c ? p - c : c - p; // nearest distance to c
1812

1813                                    if ((pa <= pb) && (pa <= pc))
1814                                        p = a;
1815                                    else if (pb <= pc)
1816                                        p = b;
1817                                    else
1818                                        p = c;
1819
1820                                    pixels[row][col] = 0xff & (byte)(p + pixels[row][col]);
1821
1822                                    col += col_Increment[pass];
1823                                }
1824                            }
1825                            break;
1826                    }
1827                }
1828                row += row_Increment[pass];
1829            }
1830        }
1831
1832        p = 256/(bitDepth*bitDepth); // gray multiplier
1833
row = 0;
1834        while (row < height)
1835        {
1836            col = 0;
1837            while (col < width)
1838            {
1839                if (colorType == 0) // gray
1840
{
1841                    RGB color;
1842                    if (bitDepth == 1)
1843                        color = new RGB(pixels[row][col] * p);
1844                    else
1845                        color = new RGB(((pixels[row][col] + 1) * p) -1);
1846                    if (tRNSPassRequired) // Apply transparency
1847
{
1848                        if (color.compareTo(tRNSKeyColor,false)) // on the right color
1849
{
1850                            color = new RGB(0);
1851                            color.setAlpha(0.0f);
1852                        }
1853                    }
1854                    rgb[row][col] = color;
1855                }
1856                else // paletted
1857
// transparency is already integrated in the palette
1858
rgb[row][col] = palette[pixels[row][col]];
1859                col++;
1860            }
1861            row++;
1862        }
1863
1864        return rgb;
1865    }
1866
1867    /**
1868    * Decompress, deinterlace, and unfilter the scanlines
1869    * Used for special interlaced images of less than 8 bit depth (padding involved)
1870    * @param scanlines int[][] the scanlines to decode into
1871    * @param inflater InputStream the inflater InputStream to read the zlib data from
1872    * @param bytesPerPixel int the number of bytes per pixel of scanlines
1873    * @return int[][] the scanlines decoded
1874    * @Exception java.io.IOException
1875    */

1876    private int[][] deCompress(int[][] scanlines, InputStream JavaDoc inflater, int bytesPerPixel) throws IOException JavaDoc
1877    {
1878        int[] starting_Row = { 0, 0, 4, 0, 2, 0, 1 };
1879        int[] starting_Col = { 0, 4, 0, 2, 0, 1, 0 };
1880        int[] row_Increment = { 8, 8, 8, 4, 4, 2, 2 };
1881        int[] col_Increment = { 8, 8, 4, 4, 2, 2, 1 };
1882
1883        int a, b, c, pa, pb, pc, p; // for paeth filter
1884
int maxPass = 7;
1885        if (interlaceMethod==0)
1886            maxPass = 1;
1887
1888        int row, col;
1889        for (int pass = 0; pass < maxPass; pass++)
1890        {
1891            if (interlaceMethod == 1)
1892                row = starting_Row[pass];
1893            else
1894                row = 0;
1895
1896            while (row < height)
1897            {
1898                int filter = inflater.read();
1899                if (interlaceMethod == 1)
1900                    col = starting_Col[pass];
1901                else
1902                    col = 0;
1903                while (col < width)
1904                {
1905                    for (int i = 0; i < bytesPerPixel; i++)
1906                    {
1907                        int bitcol = (col*bytesPerPixel)+i;
1908                        if (bitcol < scanlines[row].length)
1909                            scanlines[row][bitcol] = inflater.read();
1910                    }
1911                    if (interlaceMethod == 1)
1912                        col += col_Increment[pass];
1913                    else
1914                        col++;
1915                }
1916
1917                // Cast to byte when filtering to use modulo 256 arithmetic
1918
switch(filter)
1919                {
1920                    case 0:
1921                        // no filtering
1922
break;
1923                    case 1: // sub
1924
if (interlaceMethod == 1)
1925                            col = starting_Col[pass] + col_Increment[pass];
1926                        else
1927                            col = 1;
1928                        while (col < width)
1929                        {
1930                            for (int i = 0; i < bytesPerPixel; i++)
1931                            {
1932                                int bitcol = (col*bytesPerPixel)+i;
1933                                if (bitcol < scanlines[row].length)
1934                                {
1935                                    scanlines[row][bitcol] = (byte)(scanlines[row][bitcol] +
1936                                                        scanlines[row][(getPreviousCol(col,pass)*bytesPerPixel)+i])
1937                                                            & 0xff;
1938                                }
1939                            }
1940                            if (interlaceMethod == 1)
1941                                col += col_Increment[pass];
1942                            else
1943                                col++;
1944                        }
1945                        break;
1946                    case 2: // up
1947
if (row == 0)
1948                            break;
1949                        if (interlaceMethod == 1)
1950                            col = starting_Col[pass];
1951                        else
1952                            col = 0;
1953                        while (col < width)
1954                        {
1955                            for (int i = 0; i < bytesPerPixel; i++)
1956                            {
1957                                int bitcol = (col*bytesPerPixel)+i;
1958                                if (bitcol < scanlines[row].length)
1959                                {
1960                                    scanlines[row][bitcol] = (byte)(scanlines[row][bitcol] +
1961                                                    scanlines[getPreviousRow(row,pass)][bitcol])
1962                                                        & 0xff;
1963                                }
1964                            }
1965                            if (interlaceMethod == 1)
1966                                col += col_Increment[pass];
1967                            else
1968                                col++;
1969                        }
1970                        break;
1971                    case 3: // average
1972
if (interlaceMethod == 1)
1973                            col = starting_Col[pass];
1974                        else
1975                            col = 0;
1976                        if (row > 0)
1977                        {
1978                            for (int i = 0; i < bytesPerPixel; i++)
1979                            {
1980                                int bitcol = (col*bytesPerPixel)+i;
1981                                if (bitcol < scanlines[row].length)
1982                                {
1983                                    scanlines[row][bitcol] = (byte)(scanlines[row][bitcol] + (scanlines[getPreviousRow(row,pass)][bitcol] / 2) ) & 0xff;
1984                                }
1985                            }
1986                        }
1987                        if (interlaceMethod == 1)
1988                            col += col_Increment[pass];
1989                        else
1990                            col++;
1991                        while (col < width)
1992                        {
1993                            for (int i = 0; i < bytesPerPixel; i++)
1994                            {
1995                                int bitcol = (col*bytesPerPixel)+i;
1996                                if (bitcol < scanlines[row].length)
1997                                {
1998                                    scanlines[row][bitcol] = (byte)(scanlines[row][bitcol] +
1999                                        (scanlines[row][(getPreviousCol(col,pass)*bytesPerPixel)+i] +
2000                                            ((row == 0) ? 0 : scanlines[getPreviousRow(row,pass)][bitcol])) / 2) & 0xff;
2001                                }
2002                            }
2003                            if (interlaceMethod == 1)
2004                                col += col_Increment[pass];
2005                            else
2006                                col++;
2007                        }
2008                        break;
2009                    case 4: // paeth
2010
if (row == 0)
2011                        {
2012                            if (interlaceMethod == 1)
2013                                col = starting_Col[pass];
2014                            else
2015                                col = 0;
2016                            for (int i = 0; i < bytesPerPixel; i++)
2017                            {
2018                                int bitcol = (col*bytesPerPixel)+i;
2019                                if (bitcol < scanlines[row].length)
2020                                    scanlines[row][bitcol] = 0xff & scanlines[row][bitcol];
2021                            }
2022                            if (interlaceMethod == 1)
2023                                col += col_Increment[pass];
2024                            else
2025                                col++;
2026
2027                            while (col < width)
2028                            {
2029                                for (int i = 0; i < bytesPerPixel; i++)
2030                                {
2031                                    int bitcol = (col*bytesPerPixel)+i;
2032                                    if (bitcol < scanlines[row].length)
2033                                    {
2034                                        p = scanlines[row][(getPreviousCol(col,pass)*bytesPerPixel)+i];
2035                                        scanlines[row][bitcol] = 0xff & (byte)(p + scanlines[row][bitcol]);
2036                                    }
2037                                }
2038                                if (interlaceMethod == 1)
2039                                    col += col_Increment[pass];
2040                                else
2041                                    col++;
2042                            }
2043                        }
2044                        else
2045                        {
2046                            if (interlaceMethod == 1)
2047                                col = starting_Col[pass];
2048                            else
2049                                col = 0;
2050                            for (int i = 0; i < bytesPerPixel; i++)
2051                            {
2052                                int bitcol = (col*bytesPerPixel)+i;
2053                                if (bitcol < scanlines[row].length)
2054                                    scanlines[row][bitcol] = 0xff & (byte)(scanlines[getPreviousRow(row,pass)][bitcol] + scanlines[row][bitcol]);
2055                            }
2056                            if (interlaceMethod == 1)
2057                                col += col_Increment[pass];
2058                            else
2059                                col++;
2060
2061                            while (col < width)
2062                            {
2063                                for (int i = 0; i < bytesPerPixel; i++)
2064                                {
2065                                    int bitcol = (col*bytesPerPixel)+i;
2066                                    if (bitcol < scanlines[row].length)
2067                                    {
2068                                        a = scanlines[row][(getPreviousCol(col,pass)*bytesPerPixel)+i]; // left
2069
b = scanlines[getPreviousRow(row,pass)][bitcol]; // above
2070
c = scanlines[getPreviousRow(row,pass)][(getPreviousCol(col,pass)*bytesPerPixel)+i]; // upper left
2071

2072                                        // Paeth tests
2073
p = (a + b) - c; // initial estimate
2074
pa = p > a ? p - a : a - p; // nearest distance to a
2075
pb = p > b ? p - b : b - p; // nearest distance to b
2076
pc = p > c ? p - c : c - p; // nearest distance to c
2077

2078                                        if ((pa <= pb) && (pa <= pc))
2079                                            p = a;
2080                                        else if (pb <= pc)
2081                                            p = b;
2082                                        else
2083                                            p = c;
2084
2085                                        scanlines[row][bitcol] = 0xff & (byte)(p + scanlines[row][bitcol]);
2086                                    }
2087                                }
2088                                if (interlaceMethod == 1)
2089                                    col += col_Increment[pass];
2090                                else
2091                                    col++;
2092                            }
2093                        }
2094                        break;
2095                }
2096                if (interlaceMethod == 1)
2097                    row += row_Increment[pass];
2098                else
2099                    row++;
2100            }
2101        }
2102        return scanlines;
2103    }
2104}
2105
Popular Tags