KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > batik > ext > awt > image > codec > PNGImageDecoder


1 /*
2
3    Copyright 2001,2003 The Apache Software Foundation
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16
17  */

18 package org.apache.batik.ext.awt.image.codec;
19
20 import java.awt.Color JavaDoc;
21 import java.awt.Point JavaDoc;
22 import java.awt.Transparency JavaDoc;
23 import java.awt.color.ColorSpace JavaDoc;
24 import java.awt.image.ColorModel JavaDoc;
25 import java.awt.image.ComponentColorModel JavaDoc;
26 import java.awt.image.DataBuffer JavaDoc;
27 import java.awt.image.DataBufferByte JavaDoc;
28 import java.awt.image.DataBufferUShort JavaDoc;
29 import java.awt.image.IndexColorModel JavaDoc;
30 import java.awt.image.Raster JavaDoc;
31 import java.awt.image.RenderedImage JavaDoc;
32 import java.awt.image.SampleModel JavaDoc;
33 import java.awt.image.WritableRaster JavaDoc;
34 import java.io.BufferedInputStream JavaDoc;
35 import java.io.ByteArrayInputStream JavaDoc;
36 import java.io.DataInputStream JavaDoc;
37 import java.io.IOException JavaDoc;
38 import java.io.InputStream JavaDoc;
39 import java.io.SequenceInputStream JavaDoc;
40 import java.util.Date JavaDoc;
41 import java.util.GregorianCalendar JavaDoc;
42 import java.util.TimeZone JavaDoc;
43 import java.util.Vector JavaDoc;
44 import java.util.zip.Inflater JavaDoc;
45 import java.util.zip.InflaterInputStream JavaDoc;
46
47 /**
48  */

49 public class PNGImageDecoder extends ImageDecoderImpl {
50
51     public PNGImageDecoder(InputStream JavaDoc input,
52                            PNGDecodeParam param) {
53         super(input, param);
54     }
55
56     public RenderedImage JavaDoc decodeAsRenderedImage(int page) throws IOException JavaDoc {
57         if (page != 0) {
58             throw new IOException JavaDoc(PropertyUtil.getString("PNGImageDecoder19"));
59         }
60         return new PNGImage(input, (PNGDecodeParam)param);
61     }
62 }
63
64 class PNGChunk {
65     int length;
66     int type;
67     byte[] data;
68     int crc;
69
70     String JavaDoc typeString;
71
72     public PNGChunk(int length, int type, byte[] data, int crc) {
73         this.length = length;
74         this.type = type;
75         this.data = data;
76         this.crc = crc;
77
78         typeString = new String JavaDoc();
79         typeString += (char)(type >> 24);
80         typeString += (char)((type >> 16) & 0xff);
81         typeString += (char)((type >> 8) & 0xff);
82         typeString += (char)(type & 0xff);
83     }
84
85     public int getLength() {
86         return length;
87     }
88
89     public int getType() {
90         return type;
91     }
92
93     public String JavaDoc getTypeString() {
94         return typeString;
95     }
96
97     public byte[] getData() {
98         return data;
99     }
100
101     public byte getByte(int offset) {
102         return data[offset];
103     }
104
105     public int getInt1(int offset) {
106         return data[offset] & 0xff;
107     }
108
109     public int getInt2(int offset) {
110         return ((data[offset] & 0xff) << 8) |
111             (data[offset + 1] & 0xff);
112     }
113
114     public int getInt4(int offset) {
115         return ((data[offset] & 0xff) << 24) |
116             ((data[offset + 1] & 0xff) << 16) |
117             ((data[offset + 2] & 0xff) << 8) |
118             (data[offset + 3] & 0xff);
119     }
120
121     public String JavaDoc getString4(int offset) {
122         String JavaDoc s = new String JavaDoc();
123         s += (char)data[offset];
124         s += (char)data[offset + 1];
125         s += (char)data[offset + 2];
126         s += (char)data[offset + 3];
127         return s;
128     }
129
130     public boolean isType(String JavaDoc typeName) {
131         return typeString.equals(typeName);
132     }
133 }
134
135 /**
136  * TO DO:
137  *
138  * zTXt chunks
139  *
140  */

141 class PNGImage extends SimpleRenderedImage {
142
143     public static final int PNG_COLOR_GRAY = 0;
144     public static final int PNG_COLOR_RGB = 2;
145     public static final int PNG_COLOR_PALETTE = 3;
146     public static final int PNG_COLOR_GRAY_ALPHA = 4;
147     public static final int PNG_COLOR_RGB_ALPHA = 6;
148
149     private static final String JavaDoc[] colorTypeNames = {
150         "Grayscale", "Error", "Truecolor", "Index",
151         "Grayscale with alpha", "Error", "Truecolor with alpha"
152     };
153
154     public static final int PNG_FILTER_NONE = 0;
155     public static final int PNG_FILTER_SUB = 1;
156     public static final int PNG_FILTER_UP = 2;
157     public static final int PNG_FILTER_AVERAGE = 3;
158     public static final int PNG_FILTER_PAETH = 4;
159
160     private static final int RED_OFFSET = 2;
161     private static final int GREEN_OFFSET = 1;
162     private static final int BLUE_OFFSET = 0;
163
164     private int[][] bandOffsets = {
165         null,
166         { 0 }, // G
167
{ 0, 1 }, // GA in GA order
168
{ 0, 1, 2 }, // RGB in RGB order
169
{ 0, 1, 2, 3 } // RGBA in RGBA order
170
};
171
172     private int bitDepth;
173     private int colorType;
174
175     private int compressionMethod;
176     private int filterMethod;
177     private int interlaceMethod;
178     
179     private int paletteEntries;
180     private byte[] redPalette;
181     private byte[] greenPalette;
182     private byte[] bluePalette;
183     private byte[] alphaPalette;
184
185     private int bkgdRed;
186     private int bkgdGreen;
187     private int bkgdBlue;
188
189     private int grayTransparentAlpha;
190     private int redTransparentAlpha;
191     private int greenTransparentAlpha;
192     private int blueTransparentAlpha;
193
194     private int maxOpacity;
195
196     private int[] significantBits = null;
197
198     private boolean hasBackground = false;
199
200     // Parameter information
201

202     // If true, the user wants destination alpha where applicable.
203
private boolean suppressAlpha = false;
204
205     // If true, perform palette lookup internally
206
private boolean expandPalette = false;
207     
208     // If true, output < 8 bit gray images in 8 bit components format
209
private boolean output8BitGray = false;
210
211     // Create an alpha channel in the destination color model.
212
private boolean outputHasAlphaPalette = false;
213
214     // Perform gamma correction on the image
215
private boolean performGammaCorrection = false;
216
217     // Expand GA to GGGA for compatbility with Java2D
218
private boolean expandGrayAlpha = false;
219
220     // Produce an instance of PNGEncodeParam
221
private boolean generateEncodeParam = false;
222
223     // PNGDecodeParam controlling decode process
224
private PNGDecodeParam decodeParam = null;
225
226     // PNGEncodeParam to store file details in
227
private PNGEncodeParam encodeParam = null;
228
229     private boolean emitProperties = true;
230
231     private float fileGamma = 45455/100000.0F;
232
233     private float userExponent = 1.0F;
234
235     private float displayExponent = 2.2F;
236
237     private float[] chromaticity = null;
238
239     private int sRGBRenderingIntent = -1;
240
241     // Post-processing step implied by above parameters
242
private int postProcess = POST_NONE;
243
244     // Possible post-processing steps
245

246     // Do nothing
247
private static final int POST_NONE = 0;
248
249     // Gamma correct only
250
private static final int POST_GAMMA = 1;
251
252     // Push gray values through grayLut to expand to 8 bits
253
private static final int POST_GRAY_LUT = 2;
254
255     // Push gray values through grayLut to expand to 8 bits, add alpha
256
private static final int POST_GRAY_LUT_ADD_TRANS = 3;
257
258     // Push palette value through R,G,B lookup tables
259
private static final int POST_PALETTE_TO_RGB = 4;
260
261     // Push palette value through R,G,B,A lookup tables
262
private static final int POST_PALETTE_TO_RGBA = 5;
263
264     // Add transparency to a given gray value (w/ optional gamma)
265
private static final int POST_ADD_GRAY_TRANS = 6;
266
267     // Add transparency to a given RGB value (w/ optional gamma)
268
private static final int POST_ADD_RGB_TRANS = 7;
269
270     // Remove the alpha channel from a gray image (w/ optional gamma)
271
private static final int POST_REMOVE_GRAY_TRANS = 8;
272
273     // Remove the alpha channel from an RGB image (w/optional gamma)
274
private static final int POST_REMOVE_RGB_TRANS = 9;
275
276     // Mask to add expansion of GA -> GGGA
277
private static final int POST_EXP_MASK = 16;
278
279     // Expand gray to G/G/G
280
private static final int POST_GRAY_ALPHA_EXP =
281         POST_NONE | POST_EXP_MASK;
282
283     // Expand gray to G/G/G through a gamma lut
284
private static final int POST_GAMMA_EXP =
285         POST_GAMMA | POST_EXP_MASK;
286
287     // Push gray values through grayLut to expand to 8 bits, expand, add alpha
288
private static final int POST_GRAY_LUT_ADD_TRANS_EXP =
289         POST_GRAY_LUT_ADD_TRANS | POST_EXP_MASK;
290
291     // Add transparency to a given gray value, expand
292
private static final int POST_ADD_GRAY_TRANS_EXP =
293         POST_ADD_GRAY_TRANS | POST_EXP_MASK;
294
295     private Vector JavaDoc streamVec = new Vector JavaDoc();
296     private DataInputStream JavaDoc dataStream;
297
298     private int bytesPerPixel; // number of bytes per input pixel
299
private int inputBands;
300     private int outputBands;
301
302     // Number of private chunks
303
private int chunkIndex = 0;
304
305     private Vector JavaDoc textKeys = new Vector JavaDoc();
306     private Vector JavaDoc textStrings = new Vector JavaDoc();
307
308     private Vector JavaDoc ztextKeys = new Vector JavaDoc();
309     private Vector JavaDoc ztextStrings = new Vector JavaDoc();
310
311     private WritableRaster JavaDoc theTile;
312
313     private int[] gammaLut = null;
314
315     private void initGammaLut(int bits) {
316         double exp = (double)userExponent/(fileGamma*displayExponent);
317         int numSamples = 1 << bits;
318         int maxOutSample = (bits == 16) ? 65535 : 255;
319
320         gammaLut = new int[numSamples];
321         for (int i = 0; i < numSamples; i++) {
322             double gbright = (double)i/(numSamples - 1);
323             double gamma = Math.pow(gbright, exp);
324             int igamma = (int)(gamma*maxOutSample + 0.5);
325             if (igamma > maxOutSample) {
326                 igamma = maxOutSample;
327             }
328             gammaLut[i] = igamma;
329         }
330     }
331
332     private final byte[][] expandBits = {
333         null,
334         { (byte)0x00, (byte)0xff },
335         { (byte)0x00, (byte)0x55, (byte)0xaa, (byte)0xff },
336         null,
337         { (byte)0x00, (byte)0x11, (byte)0x22, (byte)0x33,
338           (byte)0x44, (byte)0x55, (byte)0x66, (byte)0x77,
339           (byte)0x88, (byte)0x99, (byte)0xaa, (byte)0xbb,
340           (byte)0xcc, (byte)0xdd, (byte)0xee, (byte)0xff }
341     };
342
343     private int[] grayLut = null;
344
345     private void initGrayLut(int bits) {
346         int len = 1 << bits;
347         grayLut = new int[len];
348
349         if (performGammaCorrection) {
350             for (int i = 0; i < len; i++) {
351                 grayLut[i] = gammaLut[i];
352             }
353         } else {
354             for (int i = 0; i < len; i++) {
355                 grayLut[i] = expandBits[bits][i];
356             }
357         }
358     }
359
360     public PNGImage(InputStream JavaDoc stream, PNGDecodeParam decodeParam)
361         throws IOException JavaDoc {
362
363         if (!stream.markSupported()) {
364             stream = new BufferedInputStream JavaDoc(stream);
365         }
366         DataInputStream JavaDoc distream = new DataInputStream JavaDoc(stream);
367
368         if (decodeParam == null) {
369             decodeParam = new PNGDecodeParam();
370         }
371         this.decodeParam = decodeParam;
372
373         // Get parameter values
374
this.suppressAlpha = decodeParam.getSuppressAlpha();
375         this.expandPalette = decodeParam.getExpandPalette();
376         this.output8BitGray = decodeParam.getOutput8BitGray();
377         this.expandGrayAlpha = decodeParam.getExpandGrayAlpha();
378         if (decodeParam.getPerformGammaCorrection()) {
379             this.userExponent = decodeParam.getUserExponent();
380             this.displayExponent = decodeParam.getDisplayExponent();
381             performGammaCorrection = true;
382             output8BitGray = true;
383         }
384         this.generateEncodeParam = decodeParam.getGenerateEncodeParam();
385         
386         if (emitProperties) {
387             properties.put("file_type", "PNG v. 1.0");
388         }
389
390         try {
391             long magic = distream.readLong();
392             if (magic != 0x89504e470d0a1a0aL) {
393                 String JavaDoc msg = PropertyUtil.getString("PNGImageDecoder0");
394                 throw new RuntimeException JavaDoc(msg);
395             }
396         } catch (Exception JavaDoc e) {
397             e.printStackTrace();
398             String JavaDoc msg = PropertyUtil.getString("PNGImageDecoder1");
399             throw new RuntimeException JavaDoc(msg);
400         }
401             
402         do {
403             try {
404                 PNGChunk chunk;
405                 
406                 String JavaDoc chunkType = getChunkType(distream);
407                 if (chunkType.equals("IHDR")) {
408                     chunk = readChunk(distream);
409                     parse_IHDR_chunk(chunk);
410                 } else if (chunkType.equals("PLTE")) {
411                     chunk = readChunk(distream);
412                     parse_PLTE_chunk(chunk);
413                 } else if (chunkType.equals("IDAT")) {
414                     chunk = readChunk(distream);
415                     streamVec.add(new ByteArrayInputStream JavaDoc(chunk.getData()));
416                 } else if (chunkType.equals("IEND")) {
417                     chunk = readChunk(distream);
418                     parse_IEND_chunk(chunk);
419                     break; // fall through to the bottom
420
} else if (chunkType.equals("bKGD")) {
421                     chunk = readChunk(distream);
422                     parse_bKGD_chunk(chunk);
423                 } else if (chunkType.equals("cHRM")) {
424                     chunk = readChunk(distream);
425                     parse_cHRM_chunk(chunk);
426                 } else if (chunkType.equals("gAMA")) {
427                     chunk = readChunk(distream);
428                     parse_gAMA_chunk(chunk);
429                 } else if (chunkType.equals("hIST")) {
430                     chunk = readChunk(distream);
431                     parse_hIST_chunk(chunk);
432                 } else if (chunkType.equals("iCCP")) {
433                     chunk = readChunk(distream);
434                     parse_iCCP_chunk(chunk);
435                 } else if (chunkType.equals("pHYs")) {
436                     chunk = readChunk(distream);
437                     parse_pHYs_chunk(chunk);
438                 } else if (chunkType.equals("sBIT")) {
439                     chunk = readChunk(distream);
440                     parse_sBIT_chunk(chunk);
441                 } else if (chunkType.equals("sRGB")) {
442                     chunk = readChunk(distream);
443                     parse_sRGB_chunk(chunk);
444                 } else if (chunkType.equals("tEXt")) {
445                     chunk = readChunk(distream);
446                     parse_tEXt_chunk(chunk);
447                 } else if (chunkType.equals("tIME")) {
448                     chunk = readChunk(distream);
449                     parse_tIME_chunk(chunk);
450                 } else if (chunkType.equals("tRNS")) {
451                     chunk = readChunk(distream);
452                     parse_tRNS_chunk(chunk);
453                 } else if (chunkType.equals("zTXt")) {
454                     chunk = readChunk(distream);
455                     parse_zTXt_chunk(chunk);
456                 } else {
457                     chunk = readChunk(distream);
458                     // Output the chunk data in raw form
459

460                     String JavaDoc type = chunk.getTypeString();
461                     byte[] data = chunk.getData();
462                     if (encodeParam != null) {
463                         encodeParam.addPrivateChunk(type, data);
464                     }
465                     if (emitProperties) {
466                         String JavaDoc key = "chunk_" + chunkIndex++ + ":" + type;
467                         properties.put(key.toLowerCase(), data);
468                     }
469                 }
470             } catch (Exception JavaDoc e) {
471                 e.printStackTrace();
472                 String JavaDoc msg = PropertyUtil.getString("PNGImageDecoder2");
473                 throw new RuntimeException JavaDoc(msg);
474             }
475         } while (true);
476
477         // Final post-processing
478

479         if (significantBits == null) {
480             significantBits = new int[inputBands];
481             for (int i = 0; i < inputBands; i++) {
482                 significantBits[i] = bitDepth;
483             }
484
485             if (emitProperties) {
486                 properties.put("significant_bits", significantBits);
487             }
488         }
489     }
490
491     private static String JavaDoc getChunkType(DataInputStream JavaDoc distream) {
492         try {
493             distream.mark(8);
494             /* int length = */ distream.readInt();
495             int type = distream.readInt();
496             distream.reset();
497
498             String JavaDoc typeString = new String JavaDoc();
499             typeString += (char)(type >> 24);
500             typeString += (char)((type >> 16) & 0xff);
501             typeString += (char)((type >> 8) & 0xff);
502             typeString += (char)(type & 0xff);
503             return typeString;
504         } catch (Exception JavaDoc e) {
505             e.printStackTrace();
506             return null;
507         }
508     }
509
510     private static PNGChunk readChunk(DataInputStream JavaDoc distream) {
511         try {
512             int length = distream.readInt();
513             int type = distream.readInt();
514             byte[] data = new byte[length];
515             distream.readFully(data);
516             int crc = distream.readInt();
517             
518             return new PNGChunk(length, type, data, crc);
519         } catch (Exception JavaDoc e) {
520             e.printStackTrace();
521             return null;
522         }
523     }
524
525     private void parse_IHDR_chunk(PNGChunk chunk) {
526         tileWidth = width = chunk.getInt4(0);
527         tileHeight = height = chunk.getInt4(4);
528
529         bitDepth = chunk.getInt1(8);
530         
531         if ((bitDepth != 1) && (bitDepth != 2) && (bitDepth != 4) &&
532             (bitDepth != 8) && (bitDepth != 16)) {
533             // Error -- bad bit depth
534
String JavaDoc msg = PropertyUtil.getString("PNGImageDecoder3");
535             throw new RuntimeException JavaDoc(msg);
536         }
537         maxOpacity = (1 << bitDepth) - 1;
538
539         colorType = chunk.getInt1(9);
540         if ((colorType != PNG_COLOR_GRAY) &&
541             (colorType != PNG_COLOR_RGB) &&
542             (colorType != PNG_COLOR_PALETTE) &&
543             (colorType != PNG_COLOR_GRAY_ALPHA) &&
544             (colorType != PNG_COLOR_RGB_ALPHA)) {
545             System.out.println(PropertyUtil.getString("PNGImageDecoder4"));
546         }
547
548         if ((colorType == PNG_COLOR_RGB) && (bitDepth < 8)) {
549             // Error -- RGB images must have 8 or 16 bits
550
String JavaDoc msg = PropertyUtil.getString("PNGImageDecoder5");
551             throw new RuntimeException JavaDoc(msg);
552         }
553
554         if ((colorType == PNG_COLOR_PALETTE) && (bitDepth == 16)) {
555             // Error -- palette images must have < 16 bits
556
String JavaDoc msg = PropertyUtil.getString("PNGImageDecoder6");
557             throw new RuntimeException JavaDoc(msg);
558         }
559
560         if ((colorType == PNG_COLOR_GRAY_ALPHA) && (bitDepth < 8)) {
561             // Error -- gray/alpha images must have >= 8 bits
562
String JavaDoc msg = PropertyUtil.getString("PNGImageDecoder7");
563             throw new RuntimeException JavaDoc(msg);
564         }
565
566         if ((colorType == PNG_COLOR_RGB_ALPHA) && (bitDepth < 8)) {
567             // Error -- RGB/alpha images must have >= 8 bits
568
String JavaDoc msg = PropertyUtil.getString("PNGImageDecoder8");
569             throw new RuntimeException JavaDoc(msg);
570         }
571
572         if (emitProperties) {
573             properties.put("color_type", colorTypeNames[colorType]);
574         }
575
576         if (generateEncodeParam) {
577             if (colorType == PNG_COLOR_PALETTE) {
578                 encodeParam = new PNGEncodeParam.Palette();
579             } else if (colorType == PNG_COLOR_GRAY ||
580                        colorType == PNG_COLOR_GRAY_ALPHA) {
581                 encodeParam = new PNGEncodeParam.Gray();
582             } else {
583                 encodeParam = new PNGEncodeParam.RGB();
584             }
585             decodeParam.setEncodeParam(encodeParam);
586         }
587
588         if (encodeParam != null) {
589             encodeParam.setBitDepth(bitDepth);
590         }
591         if (emitProperties) {
592             properties.put("bit_depth", new Integer JavaDoc(bitDepth));
593         }
594
595         if (performGammaCorrection) {
596             // Assume file gamma is 1/2.2 unless we get a gAMA chunk
597
float gamma = (1.0F/2.2F)*(displayExponent/userExponent);
598             if (encodeParam != null) {
599                 encodeParam.setGamma(gamma);
600             }
601             if (emitProperties) {
602                 properties.put("gamma", new Float JavaDoc(gamma));
603             }
604         }
605
606         compressionMethod = chunk.getInt1(10);
607         if (compressionMethod != 0) {
608             // Error -- only know about compression method 0
609
String JavaDoc msg = PropertyUtil.getString("PNGImageDecoder9");
610             throw new RuntimeException JavaDoc(msg);
611         }
612
613         filterMethod = chunk.getInt1(11);
614         if (filterMethod != 0) {
615             // Error -- only know about filter method 0
616
String JavaDoc msg = PropertyUtil.getString("PNGImageDecoder10");
617             throw new RuntimeException JavaDoc(msg);
618         }
619
620         interlaceMethod = chunk.getInt1(12);
621         if (interlaceMethod == 0) {
622             if (encodeParam != null) {
623                 encodeParam.setInterlacing(false);
624             }
625             if (emitProperties) {
626                 properties.put("interlace_method", "None");
627             }
628         } else if (interlaceMethod == 1) {
629             if (encodeParam != null) {
630                 encodeParam.setInterlacing(true);
631             }
632             if (emitProperties) {
633                 properties.put("interlace_method", "Adam7");
634             }
635         } else {
636             // Error -- only know about Adam7 interlacing
637
String JavaDoc msg = PropertyUtil.getString("PNGImageDecoder11");
638             throw new RuntimeException JavaDoc(msg);
639         }
640         
641         bytesPerPixel = (bitDepth == 16) ? 2 : 1;
642
643         switch (colorType) {
644         case PNG_COLOR_GRAY:
645             inputBands = 1;
646             outputBands = 1;
647
648             if (output8BitGray && (bitDepth < 8)) {
649                 postProcess = POST_GRAY_LUT;
650             } else if (performGammaCorrection) {
651                 postProcess = POST_GAMMA;
652             } else {
653                 postProcess = POST_NONE;
654             }
655             break;
656
657         case PNG_COLOR_RGB:
658             inputBands = 3;
659             bytesPerPixel *= 3;
660             outputBands = 3;
661
662             if (performGammaCorrection) {
663                 postProcess = POST_GAMMA;
664             } else {
665                 postProcess = POST_NONE;
666             }
667             break;
668
669         case PNG_COLOR_PALETTE:
670             inputBands = 1;
671             bytesPerPixel = 1;
672             outputBands = expandPalette ? 3 : 1;
673
674             if (expandPalette) {
675                 postProcess = POST_PALETTE_TO_RGB;
676             } else {
677                 postProcess = POST_NONE;
678             }
679             break;
680
681         case PNG_COLOR_GRAY_ALPHA:
682             inputBands = 2;
683             bytesPerPixel *= 2;
684
685             if (suppressAlpha) {
686                 outputBands = 1;
687                 postProcess = POST_REMOVE_GRAY_TRANS;
688             } else {
689                 if (performGammaCorrection) {
690                     postProcess = POST_GAMMA;
691                 } else {
692                     postProcess = POST_NONE;
693                 }
694                 if (expandGrayAlpha) {
695                     postProcess |= POST_EXP_MASK;
696                     outputBands = 4;
697                 } else {
698                     outputBands = 2;
699                 }
700             }
701             break;
702
703         case PNG_COLOR_RGB_ALPHA:
704             inputBands = 4;
705             bytesPerPixel *= 4;
706             outputBands = (!suppressAlpha) ? 4 : 3;
707
708             if (suppressAlpha) {
709                 postProcess = POST_REMOVE_RGB_TRANS;
710             } else if (performGammaCorrection) {
711                 postProcess = POST_GAMMA;
712             } else {
713                 postProcess = POST_NONE;
714             }
715             break;
716         }
717     }
718
719     private void parse_IEND_chunk(PNGChunk chunk) throws Exception JavaDoc {
720         // Store text strings
721
int textLen = textKeys.size();
722         String JavaDoc[] textArray = new String JavaDoc[2*textLen];
723         for (int i = 0; i < textLen; i++) {
724             String JavaDoc key = (String JavaDoc)textKeys.elementAt(i);
725             String JavaDoc val = (String JavaDoc)textStrings.elementAt(i);
726             textArray[2*i] = key;
727             textArray[2*i + 1] = val;
728             if (emitProperties) {
729                 String JavaDoc uniqueKey = "text_" + i + ":" + key;
730                 properties.put(uniqueKey.toLowerCase(), val);
731             }
732         }
733         if (encodeParam != null) {
734             encodeParam.setText(textArray);
735         }
736
737         // Store compressed text strings
738
int ztextLen = ztextKeys.size();
739         String JavaDoc[] ztextArray = new String JavaDoc[2*ztextLen];
740 <