KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > imageio > plugins > png > PNGMetadata


1 /*
2  * @(#)PNGMetadata.java 1.42 07/09/10
3  *
4  * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package com.sun.imageio.plugins.png;
9
10 import java.awt.image.ColorModel JavaDoc;
11 import java.awt.image.IndexColorModel JavaDoc;
12 import java.awt.image.SampleModel JavaDoc;
13 import java.util.ArrayList JavaDoc;
14 import java.util.Iterator JavaDoc;
15 import java.util.StringTokenizer JavaDoc;
16 import javax.imageio.ImageTypeSpecifier JavaDoc;
17 import javax.imageio.metadata.IIOInvalidTreeException JavaDoc;
18 import javax.imageio.metadata.IIOMetadata JavaDoc;
19 import javax.imageio.metadata.IIOMetadataFormat JavaDoc;
20 import javax.imageio.metadata.IIOMetadataFormatImpl JavaDoc;
21 import javax.imageio.metadata.IIOMetadataNode JavaDoc;
22 import org.w3c.dom.Node JavaDoc;
23
24 /**
25  * @version 0.5
26  */

27 public class PNGMetadata extends IIOMetadata JavaDoc implements Cloneable JavaDoc {
28
29     // package scope
30
public static final String JavaDoc
31         nativeMetadataFormatName = "javax_imageio_png_1.0";
32
33     protected static final String JavaDoc nativeMetadataFormatClassName
34         = "com.sun.imageio.plugins.png.PNGMetadataFormat";
35
36     // Color types for IHDR chunk
37
public static final String JavaDoc[] IHDR_colorTypeNames = {
38         "Grayscale", null, "RGB", "Palette",
39         "GrayAlpha", null, "RGBAlpha"
40     };
41
42     public static final int[] IHDR_numChannels = {
43         1, 0, 3, 3, 2, 0, 4
44     };
45
46     // Bit depths for IHDR chunk
47
public static final String JavaDoc[] IHDR_bitDepths = {
48         "1", "2", "4", "8", "16"
49     };
50
51     // Compression methods for IHDR chunk
52
public static final String JavaDoc[] IHDR_compressionMethodNames = {
53         "deflate"
54     };
55
56     // Filter methods for IHDR chunk
57
public static final String JavaDoc[] IHDR_filterMethodNames = {
58         "adaptive"
59     };
60
61     // Interlace methods for IHDR chunk
62
public static final String JavaDoc[] IHDR_interlaceMethodNames = {
63         "none", "adam7"
64     };
65
66     // Compression methods for iCCP chunk
67
public static final String JavaDoc[] iCCP_compressionMethodNames = {
68         "deflate"
69     };
70
71     // Compression methods for zTXt chunk
72
public static final String JavaDoc[] zTXt_compressionMethodNames = {
73         "deflate"
74     };
75
76     // "Unknown" unit for pHYs chunk
77
public static final int PHYS_UNIT_UNKNOWN = 0;
78
79     // "Meter" unit for pHYs chunk
80
public static final int PHYS_UNIT_METER = 1;
81
82     // Unit specifiers for pHYs chunk
83
public static final String JavaDoc[] unitSpecifierNames = {
84         "unknown", "meter"
85     };
86
87     // Rendering intents for sRGB chunk
88
public static final String JavaDoc[] renderingIntentNames = {
89         "Perceptual", // 0
90
"Relative colorimetric", // 1
91
"Saturation", // 2
92
"Absolute colorimetric" // 3
93

94     };
95
96     // Color space types for Chroma->ColorSpaceType node
97
public static final String JavaDoc[] colorSpaceTypeNames = {
98         "GRAY", null, "RGB", "RGB",
99         "GRAY", null, "RGB"
100     };
101
102     // IHDR chunk
103
public boolean IHDR_present;
104     public int IHDR_width;
105     public int IHDR_height;
106     public int IHDR_bitDepth;
107     public int IHDR_colorType;
108     public int IHDR_compressionMethod;
109     public int IHDR_filterMethod;
110     public int IHDR_interlaceMethod; // 0 == none, 1 == adam7
111

112     // PLTE chunk
113
public boolean PLTE_present;
114     public byte[] PLTE_red;
115     public byte[] PLTE_green;
116     public byte[] PLTE_blue;
117
118     // If non-null, used to reorder palette entries during encoding in
119
// order to minimize the size of the tRNS chunk. Thus an index of
120
// 'i' in the source should be encoded as index 'PLTE_order[i]'.
121
// PLTE_order will be null unless 'initialize' is called with an
122
// IndexColorModel image type.
123
public int[] PLTE_order = null;
124
125     // bKGD chunk
126
// If external (non-PNG sourced) data has red = green = blue,
127
// always store it as gray and promote when writing
128
public boolean bKGD_present;
129     public int bKGD_colorType; // PNG_COLOR_GRAY, _RGB, or _PALETTE
130
public int bKGD_index;
131     public int bKGD_gray;
132     public int bKGD_red;
133     public int bKGD_green;
134     public int bKGD_blue;
135
136     // cHRM chunk
137
public boolean cHRM_present;
138     public int cHRM_whitePointX;
139     public int cHRM_whitePointY;
140     public int cHRM_redX;
141     public int cHRM_redY;
142     public int cHRM_greenX;
143     public int cHRM_greenY;
144     public int cHRM_blueX;
145     public int cHRM_blueY;
146
147     // gAMA chunk
148
public boolean gAMA_present;
149     public int gAMA_gamma;
150
151     // hIST chunk
152
public boolean hIST_present;
153     public char[] hIST_histogram;
154
155     // iCCP chunk
156
public boolean iCCP_present;
157     public String JavaDoc iCCP_profileName;
158     public int iCCP_compressionMethod;
159     public byte[] iCCP_compressedProfile;
160
161     // iTXt chunk
162
public ArrayList JavaDoc iTXt_keyword = new ArrayList JavaDoc(); // Strings
163
public ArrayList JavaDoc iTXt_compressionFlag = new ArrayList JavaDoc(); // Integers
164
public ArrayList JavaDoc iTXt_compressionMethod = new ArrayList JavaDoc(); // Integers
165
public ArrayList JavaDoc iTXt_languageTag = new ArrayList JavaDoc(); // Strings
166
public ArrayList JavaDoc iTXt_translatedKeyword = new ArrayList JavaDoc(); // Strings
167
public ArrayList JavaDoc iTXt_text = new ArrayList JavaDoc(); // Strings
168

169     // pHYs chunk
170
public boolean pHYs_present;
171     public int pHYs_pixelsPerUnitXAxis;
172     public int pHYs_pixelsPerUnitYAxis;
173     public int pHYs_unitSpecifier; // 0 == unknown, 1 == meter
174

175     // sBIT chunk
176
public boolean sBIT_present;
177     public int sBIT_colorType; // PNG_COLOR_GRAY, _GRAY_ALPHA, _RGB, _RGB_ALPHA
178
public int sBIT_grayBits;
179     public int sBIT_redBits;
180     public int sBIT_greenBits;
181     public int sBIT_blueBits;
182     public int sBIT_alphaBits;
183     
184     // sPLT chunk
185
public boolean sPLT_present;
186     public String JavaDoc sPLT_paletteName; // 1-79 characters
187
public int sPLT_sampleDepth; // 8 or 16
188
public int[] sPLT_red;
189     public int[] sPLT_green;
190     public int[] sPLT_blue;
191     public int[] sPLT_alpha;
192     public int[] sPLT_frequency;
193
194     // sRGB chunk
195
public boolean sRGB_present;
196     public int sRGB_renderingIntent;
197
198     // tEXt chunk
199
public ArrayList JavaDoc tEXt_keyword = new ArrayList JavaDoc(); // 1-79 char Strings
200
public ArrayList JavaDoc tEXt_text = new ArrayList JavaDoc(); // Strings
201

202     // tIME chunk
203
public boolean tIME_present;
204     public int tIME_year;
205     public int tIME_month;
206     public int tIME_day;
207     public int tIME_hour;
208     public int tIME_minute;
209     public int tIME_second;
210
211     // tRNS chunk
212
// If external (non-PNG sourced) data has red = green = blue,
213
// always store it as gray and promote when writing
214
public boolean tRNS_present;
215     public int tRNS_colorType; // PNG_COLOR_GRAY, _RGB, or _PALETTE
216
public byte[] tRNS_alpha; // May have fewer entries than PLTE_red, etc.
217
public int tRNS_gray;
218     public int tRNS_red;
219     public int tRNS_green;
220     public int tRNS_blue;
221
222     // zTXt chunk
223
public ArrayList JavaDoc zTXt_keyword = new ArrayList JavaDoc(); // Strings
224
public ArrayList JavaDoc zTXt_compressionMethod = new ArrayList JavaDoc(); // Integers
225
public ArrayList JavaDoc zTXt_text = new ArrayList JavaDoc(); // Strings
226

227     // Unknown chunks
228
public ArrayList JavaDoc unknownChunkType = new ArrayList JavaDoc(); // Strings
229
public ArrayList JavaDoc unknownChunkData = new ArrayList JavaDoc(); // byte arrays
230

231     public PNGMetadata() {
232         super(true,
233               nativeMetadataFormatName,
234               nativeMetadataFormatClassName,
235               null, null);
236     }
237     
238     public PNGMetadata(IIOMetadata JavaDoc metadata) {
239         // TODO -- implement
240
}
241
242     /**
243      * Sets the IHDR_bitDepth and IHDR_colorType variables.
244      * The <code>numBands</code> parameter is necessary since
245      * we may only be writing a subset of the image bands.
246      */

247     public void initialize(ImageTypeSpecifier JavaDoc imageType, int numBands) {
248         ColorModel JavaDoc colorModel = imageType.getColorModel();
249         SampleModel JavaDoc sampleModel = imageType.getSampleModel();
250
251         // Initialize IHDR_bitDepth
252
int[] sampleSize = sampleModel.getSampleSize();
253         int bitDepth = sampleSize[0];
254         // Choose max bit depth over all channels
255
// Fixes bug 4413109
256
for (int i = 1; i < sampleSize.length; i++) {
257             if (sampleSize[i] > bitDepth) {
258         bitDepth = sampleSize[i];
259             }
260         }
261     // Multi-channel images must have a bit depth of 8 or 16
262
if (sampleSize.length > 1 && bitDepth < 8) {
263         bitDepth = 8;
264     }
265         
266         // Round bit depth up to a power of 2
267
if (bitDepth > 2 && bitDepth < 4) {
268             bitDepth = 4;
269         } else if (bitDepth > 4 && bitDepth < 8) {
270             bitDepth = 8;
271         } else if (bitDepth > 8 && bitDepth < 16) {
272             bitDepth = 16;
273         } else if (bitDepth > 16) {
274             throw new RuntimeException JavaDoc("bitDepth > 16!");
275         }
276         IHDR_bitDepth = bitDepth;
277
278         // Initialize IHDR_colorType
279
if (colorModel instanceof IndexColorModel JavaDoc) {
280             IndexColorModel JavaDoc icm = (IndexColorModel JavaDoc)colorModel;
281             int size = icm.getMapSize();
282
283             byte[] reds = new byte[size];
284             icm.getReds(reds);
285             byte[] greens = new byte[size];
286             icm.getGreens(greens);
287             byte[] blues = new byte[size];
288             icm.getBlues(blues);
289
290             // Determine whether the color tables are actually a gray ramp
291
// if the color type has not been set previously
292
boolean isGray = false;
293             if (!IHDR_present ||
294                 (IHDR_colorType != PNGImageReader.PNG_COLOR_PALETTE)) {
295                 isGray = true;
296                 int scale = 255/((1 << IHDR_bitDepth) - 1);
297                 for (int i = 0; i < size; i++) {
298                     byte red = reds[i];
299                     if ((red != (byte)(i*scale)) ||
300                         (red != greens[i]) ||
301                         (red != blues[i])) {
302                         isGray = false;
303                         break;
304                     }
305                 }
306             }
307
308             // Determine whether transparency exists
309
boolean hasAlpha = colorModel.hasAlpha();
310
311             byte[] alpha = null;
312             if (hasAlpha) {
313                 alpha = new byte[size];
314                 icm.getAlphas(alpha);
315             }
316
317             /*
318              * NB: PNG_COLOR_GRAY_ALPHA color type may be not optimal for images
319              * containing more than 1024 pixels (or even more than 768 pixels in
320              * case of single transparent pixel in palette).
321              * For such images alpha samples in raster will occupy more space than
322              * it is required to store palette so it could be reasonable to
323              * use PNG_COLOR_PALETTE color type for large images.
324              */

325
326             if (isGray && hasAlpha && (bitDepth == 8 || bitDepth == 16)) {
327                 IHDR_colorType = PNGImageReader.PNG_COLOR_GRAY_ALPHA;
328             } else if (isGray && !hasAlpha) {
329                 IHDR_colorType = PNGImageReader.PNG_COLOR_GRAY;
330             } else {
331                 IHDR_colorType = PNGImageReader.PNG_COLOR_PALETTE;
332                 PLTE_present = true;
333                 PLTE_order = null;
334                 PLTE_red = (byte[])reds.clone();
335                 PLTE_green = (byte[])greens.clone();
336                 PLTE_blue = (byte[])blues.clone();
337
338                 if (hasAlpha) {
339                     tRNS_present = true;
340                     tRNS_colorType = PNGImageReader.PNG_COLOR_PALETTE;
341
342                     PLTE_order = new int[alpha.length];
343
344                     // Reorder the palette so that non-opaque entries
345
// come first. Since the tRNS chunk does not have
346
// to store trailing 255's, this can save a
347
// considerable amount of space when encoding
348
// images with only one transparent pixel value,
349
// e.g., images from GIF sources.
350

351                     byte[] newAlpha = new byte[alpha.length];
352
353                     // Scan for non-opaque entries and assign them
354
// positions starting at 0.
355
int newIndex = 0;
356                     for (int i = 0; i < alpha.length; i++) {
357                         if (alpha[i] != (byte)255) {
358                             PLTE_order[i] = newIndex;
359                             newAlpha[newIndex] = alpha[i];
360                             ++newIndex;
361                         }
362                     }
363                     int numTransparent = newIndex;
364
365                     // Scan for opaque entries and assign them
366
// positions following the non-opaque entries.
367
for (int i = 0; i < alpha.length; i++) {
368                         if (alpha[i] == (byte)255) {
369                             PLTE_order[i] = newIndex++;
370                         }
371                     }
372
373                     // Reorder the palettes
374
byte[] oldRed = PLTE_red;
375                     byte[] oldGreen = PLTE_green;
376                     byte[] oldBlue = PLTE_blue;
377                     int len = oldRed.length; // All have the same length
378
PLTE_red = new byte[len];
379                     PLTE_green = new byte[len];
380                     PLTE_blue = new byte[len];
381                     for (int i = 0; i < len; i++) {
382                         PLTE_red[PLTE_order[i]] = oldRed[i];
383                         PLTE_green[PLTE_order[i]] = oldGreen[i];
384                         PLTE_blue[PLTE_order[i]] = oldBlue[i];
385                     }
386
387                     // Copy only the transparent entries into tRNS_alpha
388
tRNS_alpha = new byte[numTransparent];
389                     System.arraycopy(newAlpha, 0,
390                                      tRNS_alpha, 0, numTransparent);
391                 }
392             }
393         } else {
394             if (numBands == 1) {
395                 IHDR_colorType = PNGImageReader.PNG_COLOR_GRAY;
396             } else if (numBands == 2) {
397                 IHDR_colorType = PNGImageReader.PNG_COLOR_GRAY_ALPHA;
398             } else if (numBands == 3) {
399                 IHDR_colorType = PNGImageReader.PNG_COLOR_RGB;
400             } else if (numBands == 4) {
401                 IHDR_colorType = PNGImageReader.PNG_COLOR_RGB_ALPHA;
402             } else {
403                 throw new RuntimeException JavaDoc("Number of bands not 1-4!");
404             }
405         }
406
407         IHDR_present = true;
408     }
409
410     public boolean isReadOnly() {
411         return false;
412     }
413
414     private ArrayList JavaDoc cloneBytesArrayList(ArrayList JavaDoc in) {
415         if (in == null) {
416             return null;
417         } else {
418             ArrayList JavaDoc list = new ArrayList JavaDoc(in.size());
419             Iterator JavaDoc iter = in.iterator();
420             while (iter.hasNext()) {
421                 Object JavaDoc o = iter.next();
422                 if (o == null) {
423                     list.add(null);
424                 } else {
425                     list.add(((byte[])o).clone());
426                 }
427             }
428
429             return list;
430         }
431     }
432
433     // Deep clone
434
public Object JavaDoc clone() {
435         PNGMetadata metadata;
436         try {
437             metadata = (PNGMetadata)super.clone();
438         } catch (CloneNotSupportedException JavaDoc e) {
439             return null;
440         }
441         
442         // unknownChunkData needs deep clone
443
metadata.unknownChunkData =
444             cloneBytesArrayList(this.unknownChunkData);
445
446         return metadata;
447     }
448
449     public Node JavaDoc getAsTree(String JavaDoc formatName) {
450         if (formatName.equals(nativeMetadataFormatName)) {
451             return getNativeTree();
452         } else if (formatName.equals
453                    (IIOMetadataFormatImpl.standardMetadataFormatName)) {
454             return getStandardTree();
455         } else {
456             throw new IllegalArgumentException JavaDoc("Not a recognized format!");
457         }
458     }
459
460     private Node JavaDoc getNativeTree() {
461         IIOMetadataNode JavaDoc node = null; // scratch node
462
IIOMetadataNode JavaDoc root = new IIOMetadataNode JavaDoc(nativeMetadataFormatName);
463         
464         // IHDR
465
if (IHDR_present) {
466             IIOMetadataNode JavaDoc IHDR_node = new IIOMetadataNode JavaDoc("IHDR");
467             IHDR_node.setAttribute("width", Integer.toString(IHDR_width));
468             IHDR_node.setAttribute("height", Integer.toString(IHDR_height));
469             IHDR_node.setAttribute("bitDepth",
470                                    Integer.toString(IHDR_bitDepth));
471             IHDR_node.setAttribute("colorType",
472                                    IHDR_colorTypeNames[IHDR_colorType]);
473             // IHDR_compressionMethod must be 0 in PNG 1.1
474
IHDR_node.setAttribute("compressionMethod",
475                           IHDR_compressionMethodNames[IHDR_compressionMethod]);
476             // IHDR_filterMethod must be 0 in PNG 1.1
477
IHDR_node.setAttribute("filterMethod",
478                                     IHDR_filterMethodNames[IHDR_filterMethod]);
479             IHDR_node.setAttribute("interlaceMethod",
480                               IHDR_interlaceMethodNames[IHDR_interlaceMethod]);
481             root.appendChild(IHDR_node);
482         }
483
484         // PLTE
485
if (PLTE_present) {
486             IIOMetadataNode JavaDoc PLTE_node = new IIOMetadataNode JavaDoc("PLTE");
487             int numEntries = PLTE_red.length;
488             for (int i = 0; i < numEntries; i++) {
489                 IIOMetadataNode JavaDoc entry = new IIOMetadataNode JavaDoc("PLTEEntry");
490                 entry.setAttribute("index", Integer.toString(i));
491                 entry.setAttribute("red",
492                                    Integer.toString(PLTE_red[i] & 0xff));
493                 entry.setAttribute("green",
494                                    Integer.toString(PLTE_green[i] & 0xff));
495                 entry.setAttribute("blue",
496                                    Integer.toString(PLTE_blue[i] & 0xff));
497                 PLTE_node.appendChild(entry);
498             }
499
500             root.appendChild(PLTE_node);
501         }
502
503         // bKGD
504
if (bKGD_present) {
505             IIOMetadataNode JavaDoc bKGD_node = new IIOMetadataNode JavaDoc("bKGD");
506             
507             if (bKGD_colorType == PNGImageReader.PNG_COLOR_PALETTE) {
508                 node = new IIOMetadataNode JavaDoc("bKGD_Palette");
509                 node.setAttribute("index", Integer.toString(bKGD_index));
510             } else if (bKGD_colorType == PNGImageReader.PNG_COLOR_GRAY) {
511                 node = new IIOMetadataNode JavaDoc("bKGD_Grayscale");
512                 node.setAttribute("gray", Integer.toString(bKGD_gray));
513             } else if (bKGD_colorType == PNGImageReader.PNG_COLOR_RGB) {
514                 node = new IIOMetadataNode JavaDoc("bKGD_RGB");
515                 node.setAttribute("red", Integer.toString(bKGD_red));
516                 node.setAttribute("green", Integer.toString(bKGD_green));
517                 node.setAttribute("blue", Integer.toString(bKGD_blue));
518             }
519             bKGD_node.appendChild(node);
520
521             root.appendChild(bKGD_node);
522         }
523
524         // cHRM
525
if (cHRM_present) {
526             IIOMetadataNode JavaDoc cHRM_node = new IIOMetadataNode JavaDoc("cHRM");
527             cHRM_node.setAttribute("whitePointX",
528                               Integer.toString(cHRM_whitePointX));
529             cHRM_node.setAttribute("whitePointY",
530                               Integer.toString(cHRM_whitePointY));
531             cHRM_node.setAttribute("redX", Integer.toString(cHRM_redX));
532             cHRM_node.setAttribute("redY", Integer.toString(cHRM_redY));
533             cHRM_node.setAttribute("greenX", Integer.toString(cHRM_greenX));
534             cHRM_node.setAttribute("greenY", Integer.toString(cHRM_greenY));
535             cHRM_node.setAttribute("blueX", Integer.toString(cHRM_blueX));
536             cHRM_node.setAttribute("blueY", Integer.toString(cHRM_blueY));
537
538             root.appendChild(cHRM_node);
539         }
540
541         // gAMA
542
if (gAMA_present) {
543             IIOMetadataNode JavaDoc gAMA_node = new IIOMetadataNode JavaDoc("gAMA");
544             gAMA_node.setAttribute("value", Integer.toString(gAMA_gamma));
545
546             root.appendChild(gAMA_node);
547         }
548
549         // hIST
550
if (hIST_present) {
551             IIOMetadataNode JavaDoc hIST_node = new IIOMetadataNode JavaDoc("hIST");
552
553             for (int i = 0; i < hIST_histogram.length; i++) {
554                 IIOMetadataNode JavaDoc hist =
555                     new IIOMetadataNode JavaDoc("hISTEntry");
556                 hist.setAttribute("index", Integer.toString(i));
557                 hist.setAttribute("value",
558                                   Integer.toString(hIST_histogram[i]));
559                 hIST_node.appendChild(hist);
560             }
561
562             root.appendChild(hIST_node);
563         }
564
565         // iCCP
566
if (iCCP_present) {
567             IIOMetadataNode JavaDoc iCCP_node = new IIOMetadataNode JavaDoc("iCCP");
568             iCCP_node.setAttribute("profileName", iCCP_profileName);
569             iCCP_node.setAttribute("compressionMethod",
570                           iCCP_compressionMethodNames[iCCP_compressionMethod]);
571
572             Object JavaDoc profile = iCCP_compressedProfile;
573             if (profile != null) {
574                 profile = ((byte[])profile).clone();
575             }
576             iCCP_node.setUserObject(profile);
577
578             root.appendChild(iCCP_node);
579         }
580
581         // iTXt
582
if (iTXt_keyword.size() > 0) {
583             IIOMetadataNode JavaDoc iTXt_parent = new IIOMetadataNode JavaDoc("iTXt");
584             for (int i = 0; i < iTXt_keyword.size(); i++) {
585                 Integer JavaDoc val;
586                 
587                 IIOMetadataNode JavaDoc iTXt_node = new IIOMetadataNode JavaDoc("iTXtEntry");
588                 iTXt_node.setAttribute("keyword", (String JavaDoc)iTXt_keyword.get(i));
589                 val = (Integer JavaDoc)iTXt_compressionFlag.get(i);
590                 iTXt_node.setAttribute("compressionFlag", val.toString());
591                 val = (Integer JavaDoc)iTXt_compressionMethod.get(i);
592                 iTXt_node.setAttribute("compressionMethod", val.toString());
593                 iTXt_node.setAttribute("languageTag",
594                                        (String JavaDoc)iTXt_languageTag.get(i));
595                 iTXt_node.setAttribute("translatedKeyword",
596                                        (String JavaDoc)iTXt_translatedKeyword.get(i));
597                 iTXt_node.setAttribute("text", (String JavaDoc)iTXt_text.get(i));
598                 
599                 iTXt_parent.appendChild(iTXt_node);
600             }
601             
602             root.appendChild(iTXt_parent);
603         }
604
605         // pHYs
606
if (pHYs_present) {
607             IIOMetadataNode JavaDoc pHYs_node = new IIOMetadataNode JavaDoc("pHYs");
608             pHYs_node.setAttribute("pixelsPerUnitXAxis",
609                               Integer.toString(pHYs_pixelsPerUnitXAxis));
610             pHYs_node.setAttribute("pixelsPerUnitYAxis",
611                                    Integer.toString(pHYs_pixelsPerUnitYAxis));
612             pHYs_node.setAttribute("unitSpecifier",
613                                    unitSpecifierNames[pHYs_unitSpecifier]);
614
615             root.appendChild(pHYs_node);
616         }
617
618         // sBIT
619
if (sBIT_present) {
620             IIOMetadataNode JavaDoc sBIT_node = new IIOMetadataNode JavaDoc("sBIT");
621
622             if (sBIT_colorType == PNGImageReader.PNG_COLOR_GRAY) {
623                 node = new IIOMetadataNode JavaDoc("sBIT_Grayscale");
624                 node.setAttribute("gray",
625                                   Integer.toString(sBIT_grayBits));
626             } else if (sBIT_colorType == PNGImageReader.PNG_COLOR_GRAY_ALPHA) {
627                 node = new IIOMetadataNode JavaDoc("sBIT_GrayAlpha");
628                 node.setAttribute("gray",
629                                   Integer.toString(sBIT_grayBits));
630                 node.setAttribute("alpha",
631                                   Integer.toString(sBIT_alphaBits));
632             } else if (sBIT_colorType == PNGImageReader.PNG_COLOR_RGB) {
633                 node = new IIOMetadataNode JavaDoc("sBIT_RGB");
634                 node.setAttribute("red",
635                                   Integer.toString(sBIT_redBits));
636                 node.setAttribute("green",
637                                   Integer.toString(sBIT_greenBits));
638                 node.setAttribute("blue",
639                                   Integer.toString(sBIT_blueBits));
640             } else if (sBIT_colorType == PNGImageReader.PNG_COLOR_RGB_ALPHA) {
641                 node = new IIOMetadataNode JavaDoc("sBIT_RGBAlpha");
642                 node.setAttribute("red",
643                                   Integer.toString(sBIT_redBits));
644                 node.setAttribute("green",
645                                   Integer.toString(sBIT_greenBits));
646                 node.setAttribute("blue",
647                                   Integer.toString(sBIT_blueBits));
648                 node.setAttribute("alpha",
649                                   Integer.toString(sBIT_alphaBits));
650             } else if (sBIT_colorType == PNGImageReader.PNG_COLOR_PALETTE) {
651                 node = new IIOMetadataNode JavaDoc("sBIT_Palette");
652                 node.setAttribute("red",
653                                   Integer.toString(sBIT_redBits));
654                 node.setAttribute("green",
655                                   Integer.toString(sBIT_greenBits));
656                 node.setAttribute("blue",
657                                   Integer.toString(sBIT_blueBits));
658             }
659             sBIT_node.appendChild(node);
660                 
661             root.appendChild(sBIT_node);
662         }
663
664         // sPLT
665
if (sPLT_present) {
666             IIOMetadataNode JavaDoc sPLT_node = new IIOMetadataNode JavaDoc("sPLT");
667
668             sPLT_node.setAttribute("name", sPLT_paletteName);
669             sPLT_node.setAttribute("sampleDepth",
670                                    Integer.toString(sPLT_sampleDepth));
671
672             int numEntries = sPLT_red.length;
673             for (int i = 0; i < numEntries; i++) {
674                 IIOMetadataNode JavaDoc entry = new IIOMetadataNode JavaDoc("sPLTEntry");
675                 entry.setAttribute("index", Integer.toString(i));
676                 entry.setAttribute("red", Integer.toString(sPLT_red[i]));
677                 entry.setAttribute("green", Integer.toString(sPLT_green[i]));
678                 entry.setAttribute("blue", Integer.toString(sPLT_blue[i]));
679                 entry.setAttribute("alpha", Integer.toString(sPLT_alpha[i]));
680                 entry.setAttribute("frequency",
681                                   Integer.toString(sPLT_frequency[i]));
682                 sPLT_node.appendChild(entry);
683             }
684
685             root.appendChild(sPLT_node);
686         }
687
688         // sRGB
689
if (sRGB_present) {
690             IIOMetadataNode JavaDoc sRGB_node = new IIOMetadataNode JavaDoc("sRGB");
691             sRGB_node.setAttribute("renderingIntent",
692                                    renderingIntentNames[sRGB_renderingIntent]);
693
694             root.appendChild(sRGB_node);
695         }
696
697         // tEXt
698
if (tEXt_keyword.size() > 0) {
699             IIOMetadataNode JavaDoc tEXt_parent = new IIOMetadataNode JavaDoc("tEXt");
700             for (int i = 0; i < tEXt_keyword.size(); i++) {
701                 IIOMetadataNode JavaDoc tEXt_node = new IIOMetadataNode JavaDoc("tEXtEntry");
702                 tEXt_node.setAttribute("keyword" , (String JavaDoc)tEXt_keyword.get(i));
703                 tEXt_node.setAttribute("value" , (String JavaDoc)tEXt_text.get(i));
704                 
705                 tEXt_parent.appendChild(tEXt_node);
706             }
707                 
708             root.appendChild(tEXt_parent);
709         }
710
711         // tIME
712
if (tIME_present) {
713             IIOMetadataNode JavaDoc tIME_node = new IIOMetadataNode JavaDoc("tIME");
714             tIME_node.setAttribute("year", Integer.toString(tIME_year));
715             tIME_node.setAttribute("month", Integer.toString(tIME_month));
716             tIME_node.setAttribute("day", Integer.toString(tIME_day));
717             tIME_node.setAttribute("hour", Integer.toString(tIME_hour));
718             tIME_node.setAttribute("minute", Integer.toString(tIME_minute));
719             tIME_node.setAttribute("second", Integer.toString(tIME_second));
720
721             root.appendChild(tIME_node);
722         }
723
724         // tRNS
725
if (tRNS_present) {
726             IIOMetadataNode JavaDoc tRNS_node = new IIOMetadataNode JavaDoc("tRNS");
727
728             if (tRNS_colorType == PNGImageReader.PNG_COLOR_PALETTE) {
729                 node = new IIOMetadataNode JavaDoc("tRNS_Palette");
730                 
731                 for (int i = 0; i < tRNS_alpha.length; i++) {
732                     IIOMetadataNode JavaDoc entry =
733                         new IIOMetadataNode JavaDoc("tRNS_PaletteEntry");
734                     entry.setAttribute("index", Integer.toString(i));
735                     entry.setAttribute("alpha",
736                                        Integer.toString(tRNS_alpha[i] & 0xff));
737                     node.appendChild(entry);
738                 }
739             } else if (tRNS_colorType == PNGImageReader.PNG_COLOR_GRAY) {
740                 node = new IIOMetadataNode JavaDoc("tRNS_Grayscale");
741                 node.setAttribute("gray", Integer.toString(tRNS_gray));
742             } else if (tRNS_colorType == PNGImageReader.PNG_COLOR_RGB) {
743                 node = new IIOMetadataNode JavaDoc("tRNS_RGB");
744                 node.setAttribute("red", Integer.toString(tRNS_red));
745                 node.setAttribute("green", Integer.toString(tRNS_green));
746                 node.setAttribute("blue", Integer.toString(tRNS_blue));
747             }
748             tRNS_node.appendChild(node);
749             
750             root.appendChild(tRNS_node);
751         }
752
753         // zTXt
754
if (zTXt_keyword.size() > 0) {
755             IIOMetadataNode JavaDoc zTXt_parent = new IIOMetadataNode JavaDoc("zTXt");
756             for (int i = 0; i < zTXt_keyword.size(); i++) {
757                 IIOMetadataNode JavaDoc zTXt_node = new IIOMetadataNode JavaDoc("zTXtEntry");
758                 zTXt_node.setAttribute("keyword", (String JavaDoc)zTXt_keyword.get(i));
759
760                 int cm = ((Integer JavaDoc)zTXt_compressionMethod.get(i)).intValue();
761                 zTXt_node.setAttribute("compressionMethod",
762                                        zTXt_compressionMethodNames[cm]);
763
764                 zTXt_node.setAttribute("text", (String JavaDoc)zTXt_text.get(i));
765
766                 zTXt_parent.appendChild(zTXt_node);
767             }
768
769             root.appendChild(zTXt_parent);
770         }
771         
772         // Unknown chunks
773
if (unknownChunkType.size() > 0) {
774             IIOMetadataNode JavaDoc unknown_parent =
775                 new IIOMetadataNode JavaDoc("UnknownChunks");
776             for (int i = 0; i < unknownChunkType.size(); i++) {
777                 IIOMetadataNode JavaDoc unknown_node =
778                     new IIOMetadataNode JavaDoc("UnknownChunk");
779                 unknown_node.setAttribute("type",
780                                           (String JavaDoc)unknownChunkType.get(i));
781                 unknown_node.setUserObject((byte[])unknownChunkData.get(i));
782                 
783                 unknown_parent.appendChild(unknown_node);
784             }
785             
786             root.appendChild(unknown_parent);
787         }
788
789         return root;
790     }
791
792     private int getNumChannels() {
793         // Determine number of channels
794
// Be careful about palette color with transparency
795
int numChannels = IHDR_numChannels[IHDR_colorType];
796         if (IHDR_colorType == PNGImageReader.PNG_COLOR_PALETTE &&
797             tRNS_present && tRNS_colorType == IHDR_colorType) {
798             numChannels = 4;
799         }
800         return numChannels;
801     }
802
803     public IIOMetadataNode JavaDoc getStandardChromaNode() {
804         IIOMetadataNode JavaDoc chroma_node = new IIOMetadataNode JavaDoc("Chroma");
805         IIOMetadataNode JavaDoc node = null; // scratch node
806

807         node = new IIOMetadataNode JavaDoc("ColorSpaceType");
808         node.setAttribute("name", colorSpaceTypeNames[IHDR_colorType]);
809         chroma_node.appendChild(node);
810
811         node = new IIOMetadataNode JavaDoc("NumChannels");
812         node.setAttribute("value", Integer.toString(getNumChannels()));
813         chroma_node.appendChild(node);
814
815         if (gAMA_present) {
816             node = new IIOMetadataNode JavaDoc("Gamma");
817             node.setAttribute("value", Float.toString(gAMA_gamma*1.0e-5F));
818             chroma_node.appendChild(node);
819         }
820
821         node = new IIOMetadataNode JavaDoc("BlackIsZero");
822         node.setAttribute("value", "true");
823         chroma_node.appendChild(node);
824
825         if (PLTE_present) {
826             boolean hasAlpha = tRNS_present &&
827                 (tRNS_colorType == PNGImageReader.PNG_COLOR_PALETTE);
828
829             node = new IIOMetadataNode JavaDoc("Palette");
830             for (int i = 0; i < PLTE_red.length; i++) {
831                 IIOMetadataNode JavaDoc entry =
832                     new IIOMetadataNode JavaDoc("PaletteEntry");
833                 entry.setAttribute("index", Integer.toString(i));
834                 entry.setAttribute("red",
835                                    Integer.toString(PLTE_red[i] & 0xff));
836                 entry.setAttribute("green",
837                                    Integer.toString(PLTE_green[i] & 0xff));
838                 entry.setAttribute("blue",
839                                    Integer.toString(PLTE_blue[i] & 0xff));
840                 if (hasAlpha) {
841             int alpha = (i < tRNS_alpha.length) ?
842             (tRNS_alpha[i] & 0xff) : 255;
843                     entry.setAttribute("alpha", Integer.toString(alpha));
844                 }
845                 node.appendChild(entry);
846             }
847             chroma_node.appendChild(node);
848         }
849
850         if (bKGD_present) {
851             if (bKGD_colorType == PNGImageReader.PNG_COLOR_PALETTE) {
852                 node = new IIOMetadataNode JavaDoc("BackgroundIndex");
853                 node.setAttribute("value", Integer.toString(bKGD_index));
854             } else {
855                 node = new IIOMetadataNode JavaDoc("BackgroundColor");
856                 int r, g, b;
857
858                 if (bKGD_colorType == PNGImageReader.PNG_COLOR_GRAY) {
859                     r = g = b = bKGD_gray;
860                 } else {
861                     r = bKGD_red;
862                     g = bKGD_green;
863                     b = bKGD_blue;
864                 }
865                 node.setAttribute("red", Integer.toString(r));
866                 node.setAttribute("green", Integer.toString(g));
867                 node.setAttribute("blue", Integer.toString(b));
868             }
869             chroma_node.appendChild(node);
870         }
871
872         return chroma_node;
873     }
874
875     public IIOMetadataNode JavaDoc getStandardCompressionNode() {
876         IIOMetadataNode JavaDoc compression_node = new IIOMetadataNode JavaDoc("Compression");
877         IIOMetadataNode JavaDoc node = null; // scratch node
878

879         node = new IIOMetadataNode JavaDoc("CompressionTypeName");
880         node.setAttribute("value", "deflate");
881         compression_node.appendChild(node);
882
883         node = new IIOMetadataNode JavaDoc("Lossless");
884         node.setAttribute("value", "true");
885         compression_node.appendChild(node);
886
887         node = new IIOMetadataNode JavaDoc("NumProgressiveScans");
888         node.setAttribute("value",
889                           (IHDR_interlaceMethod == 0) ? "1" : "7");
890         compression_node.appendChild(node);
891
892         return compression_node;
893     }
894
895     private String JavaDoc repeat(String JavaDoc s, int times) {
896         if (times == 1) {
897             return s;
898         }
899         StringBuffer JavaDoc sb = new StringBuffer JavaDoc((s.length() + 1)*times - 1);
900         sb.append(s);
901         for (int i = 1; i < times; i++) {
902             sb.append(" ");
903             sb.append(s);
904         }
905         return sb.toString();
906     }
907
908     public IIOMetadataNode JavaDoc getStandardDataNode() {
909         IIOMetadataNode JavaDoc data_node = new IIOMetadataNode JavaDoc("Data");
910         IIOMetadataNode JavaDoc node = null; // scratch node
911

912         node = new IIOMetadataNode JavaDoc("PlanarConfiguration");
913         node.setAttribute("value", "PixelInterleaved");
914         data_node.appendChild(node);
915
916         node = new IIOMetadataNode JavaDoc("SampleFormat");
917         node.setAttribute("value",
918                           IHDR_colorType == PNGImageReader.PNG_COLOR_PALETTE ?
919                           "Index" : "UnsignedIntegral");
920         data_node.appendChild(node);
921
922         String JavaDoc bitDepth = Integer.toString(IHDR_bitDepth);
923         node = new IIOMetadataNode JavaDoc("BitsPerSample");
924         node.setAttribute("value", repeat(bitDepth, getNumChannels()));
925         data_node.appendChild(node);
926
927         if (sBIT_present) {
928             node = new IIOMetadataNode JavaDoc("SignificantBitsPerSample");
929             String JavaDoc sbits;
930             if (sBIT_colorType == PNGImageReader.PNG_COLOR_GRAY ||
931                 sBIT_colorType == PNGImageReader.PNG_COLOR_GRAY_ALPHA) {
932                 sbits = Integer.toString(sBIT_grayBits);
933             } else { // sBIT_colorType == PNGImageReader.PNG_COLOR_RGB ||
934
// sBIT_colorType == PNGImageReader.PNG_COLOR_RGB_ALPHA
935
sbits = Integer.toString(sBIT_redBits) + " " +
936                     Integer.toString(sBIT_greenBits) + " " +
937                     Integer.toString(sBIT_blueBits);
938             }
939
940             if (sBIT_colorType == PNGImageReader.PNG_COLOR_GRAY_ALPHA ||
941                 sBIT_colorType == PNGImageReader.PNG_COLOR_RGB_ALPHA) {
942                 sbits += " " + Integer.toString(sBIT_alphaBits);
943             }
944             
945             node.setAttribute("value", sbits);
946             data_node.appendChild(node);
947         }
948
949         // SampleMSB
950

951         return data_node;
952     }
953
954     public IIOMetadataNode JavaDoc getStandardDimensionNode() {
955         IIOMetadataNode JavaDoc dimension_node = new IIOMetadataNode JavaDoc("Dimension");
956         IIOMetadataNode JavaDoc node = null; // scratch node
957

958         node = new IIOMetadataNode JavaDoc("PixelAspectRatio");
959         float ratio = pHYs_present ?
960             (float)pHYs_pixelsPerUnitXAxis/pHYs_pixelsPerUnitYAxis : 1.0F;
961         node.setAttribute("value", Float.toString(ratio));
962         dimension_node.appendChild(node);
963         
964         node = new IIOMetadataNode JavaDoc("ImageOrientation");
965         node.setAttribute("value", "Normal");
966         dimension_node.appendChild(node);
967         
968         if (pHYs_present && pHYs_unitSpecifier == PHYS_UNIT_METER) {
969             node = new IIOMetadataNode JavaDoc("HorizontalPixelSize");
970             node.setAttribute("value",
971                               Float.toString(1000.0F/pHYs_pixelsPerUnitXAxis));
972             dimension_node.appendChild(node);
973
974             node = new IIOMetadataNode JavaDoc("VerticalPixelSize");
975             node.setAttribute("value",
976                               Float.toString(1000.0F/pHYs_pixelsPerUnitYAxis));
977             dimension_node.appendChild(node);
978         }
979
980         return dimension_node;
981     }
982
983     public IIOMetadataNode JavaDoc getStandardDocumentNode() {
984         if (!tIME_present) {
985             return null;
986         }
987
988         IIOMetadataNode JavaDoc document_node = new IIOMetadataNode JavaDoc("Document");
989         IIOMetadataNode JavaDoc node = null; // scratch node
990

991         node = new IIOMetadataNode JavaDoc("ImageModificationTime");
992         node.setAttribute("year", Integer.toString(tIME_year));
993         node.setAttribute("month", Integer.toString(tIME_month));
994         node.setAttribute("day", Integer.toString(tIME_day));
995         node.setAttribute("hour", Integer.toString(tIME_hour));
996         node.setAttribute("minute", Integer.toString(tIME_minute));
997         node.setAttribute("second", Integer.toString(tIME_second));
998         document_node.appendChild(node);
999
1000        return document_node;
1001    }
1002
1003    public IIOMetadataNode JavaDoc getStandardTextNode() {
1004        int numEntries = tEXt_keyword.size() +
1005            iTXt_keyword.size() + zTXt_keyword.size();
1006        if (numEntries == 0) {
1007            return null;
1008        }
1009
1010        IIOMetadataNode JavaDoc text_node = new IIOMetadataNode JavaDoc("Text");
1011        IIOMetadataNode JavaDoc node = null; // scratch node
1012

1013        for (int i = 0; i < tEXt_keyword.size(); i++) {
1014            node = new IIOMetadataNode JavaDoc("TextEntry");
1015            node.setAttribute("keyword", (String JavaDoc)tEXt_keyword.get(i));
1016            node.setAttribute("value", (String JavaDoc)tEXt_text.get(i));
1017            node.setAttribute("encoding", "ISO-8859-1");
1018            node.setAttribute("compression", "none");
1019            
1020            text_node.appendChild(node);
1021        }
1022
1023        for (int i = 0; i < iTXt_keyword.size(); i++) {
1024            node = new IIOMetadataNode JavaDoc("TextEntry");
1025            node.setAttribute("keyword", (String JavaDoc)iTXt_keyword.get(i));
1026            node.setAttribute("value", (String JavaDoc)iTXt_text.get(i));
1027            node.setAttribute("language",
1028                              (String JavaDoc)iTXt_languageTag.get(i));
1029            if (((Integer JavaDoc)iTXt_compressionFlag.get(i)).intValue() == 1) {
1030                node.setAttribute("compression", "deflate");
1031            } else {
1032                node.setAttribute("compression", "none");
1033            }
1034            
1035            text_node.appendChild(node);
1036        }
1037
1038        for (int i = 0; i < zTXt_keyword.size(); i++) {
1039            node = new IIOMetadataNode JavaDoc("TextEntry");
1040            node.setAttribute("keyword", (String JavaDoc)zTXt_keyword.get(i));
1041            node.setAttribute("value", (String JavaDoc)zTXt_text.get(i));
1042            node.setAttribute("compression", "deflate");
1043            
1044            text_node.appendChild(node);
1045        }
1046
1047        return text_node;
1048    }
1049
1050    public IIOMetadataNode JavaDoc getStandardTransparencyNode() {
1051        IIOMetadataNode JavaDoc transparency_node =
1052            new IIOMetadataNode JavaDoc("Transparency");
1053        IIOMetadataNode JavaDoc node = null; // scratch node
1054

1055        node = new IIOMetadataNode JavaDoc("Alpha");
1056        boolean hasAlpha =
1057            (IHDR_colorType == PNGImageReader.PNG_COLOR_RGB_ALPHA) ||
1058            (IHDR_colorType == PNGImageReader.PNG_COLOR_GRAY_ALPHA) ||
1059            (IHDR_colorType == PNGImageReader.PNG_COLOR_PALETTE &&
1060             tRNS_present &&
1061             (tRNS_colorType == IHDR_colorType) &&
1062             (tRNS_alpha != null));
1063        node.setAttribute("value", hasAlpha ? "nonpremultipled" : "none");
1064        transparency_node.appendChild(node);
1065
1066        if (tRNS_present) {
1067            node = new IIOMetadataNode JavaDoc("TransparentColor");
1068            if (tRNS_colorType == PNGImageReader.PNG_COLOR_RGB) {
1069                node.setAttribute("value",
1070                                  Integer.toString(tRNS_red) + " " +
1071                                  Integer.toString(tRNS_green) + " " +
1072                                  Integer.toString(tRNS_blue));
1073            } else if (tRNS_colorType == PNGImageReader.PNG_COLOR_GRAY) {
1074                node.setAttribute("value", Integer.toString(tRNS_gray));
1075            }
1076            transparency_node.appendChild(node);
1077        }
1078
1079        return transparency_node;
1080    }
1081
1082    // Shorthand for throwing an IIOInvalidTreeException
1083
private void fatal(Node JavaDoc node, String JavaDoc reason)
1084        throws IIOInvalidTreeException JavaDoc {
1085        throw new IIOInvalidTreeException JavaDoc(reason, node);
1086    }
1087
1088    // Get an integer-valued attribute
1089
private String JavaDoc getStringAttribute(Node JavaDoc node, String JavaDoc name,
1090                                      String JavaDoc defaultValue, boolean required)
1091        throws IIOInvalidTreeException JavaDoc {
1092        Node JavaDoc attr = node.getAttributes().getNamedItem(name);
1093        if (attr == null) {
1094            if (!required) {
1095                return defaultValue;
1096            } else {
1097                fatal(node, "Required attribute " + name + " not present!");
1098            }
1099        }
1100        return attr.getNodeValue();
1101    }
1102
1103
1104    // Get an integer-valued attribute
1105
private int getIntAttribute(Node JavaDoc node, String JavaDoc name,
1106                                int defaultValue, boolean required)
1107        throws IIOInvalidTreeException JavaDoc {
1108        String JavaDoc value = getStringAttribute(node, name, null, required);
1109        if (value == null) {
1110            return defaultValue;
1111        }
1112        return Integer.parseInt(value);
1113    }
1114
1115    // Get a float-valued attribute
1116
private float getFloatAttribute(Node JavaDoc node, String JavaDoc name,
1117                                    float defaultValue, boolean required)
1118        throws IIOInvalidTreeException JavaDoc {
1119        String JavaDoc value = getStringAttribute(node, name, null, required);
1120        if (value == null) {
1121            return defaultValue;
1122        }
1123        return Float.parseFloat(value);
1124    }
1125
1126    // Get a required integer-valued attribute
1127
private int getIntAttribute(Node JavaDoc node, String JavaDoc name)
1128        throws IIOInvalidTreeException JavaDoc {
1129        return getIntAttribute(node, name, -1, true);
1130    }
1131
1132    // Get a required float-valued attribute
1133
private float getFloatAttribute(Node JavaDoc node, String JavaDoc name)
1134        throws IIOInvalidTreeException JavaDoc {
1135        return getFloatAttribute(node, name, -1.0F, true);
1136    }
1137
1138    // Get a boolean-valued attribute
1139
private boolean getBooleanAttribute(Node JavaDoc node, String JavaDoc name,
1140                                        boolean defaultValue,
1141                                        boolean required)
1142        throws IIOInvalidTreeException JavaDoc {
1143        Node JavaDoc attr = node.getAttributes().getNamedItem(name);
1144        if (attr == null) {
1145            if (!required) {
1146                return defaultValue;
1147            } else {
1148                fatal(node, "Required attribute " + name + " not present!");
1149            }
1150        }
1151        String JavaDoc value = attr.getNodeValue();
1152        if (value.equals("true")) {
1153            return true;
1154        } else if (value.equals("false")) {
1155            return false;
1156        } else {
1157            fatal(node, "Attribute " + name + " must be 'true' or 'false'!");
1158            return false;
1159        }
1160    }
1161
1162    // Get a required boolean-valued attribute
1163
private boolean getBooleanAttribute(Node JavaDoc node, String JavaDoc name)
1164        throws IIOInvalidTreeException JavaDoc {
1165        return getBooleanAttribute(node, name, false, true);
1166    }
1167
1168    // Get an enumerated attribute as an index into a String array
1169
private int getEnumeratedAttribute(Node JavaDoc node,
1170                                       String JavaDoc name, String JavaDoc[] legalNames,
1171                                       int defaultValue, boolean required)
1172        throws IIOInvalidTreeException JavaDoc {
1173        Node JavaDoc attr = node.getAttributes().getNamedItem(name);
1174        if (attr == null) {
1175            if (!required) {
1176                return defaultValue;
1177            } else {
1178                fatal(node, "Required attribute " + name + " not present!");
1179            }
1180        }
1181        String JavaDoc value = attr.getNodeValue();
1182        for (int i = 0; i < legalNames.length; i++) {
1183            if (value.equals(legalNames[i])) {
1184                return i;
1185            }
1186        }
1187
1188        fatal(node, "Illegal value for attribute " + name + "!");
1189        return -1;
1190    }
1191
1192    // Get a required enumerated attribute as an index into a String array
1193
private int getEnumeratedAttribute(Node JavaDoc node,
1194                                       String JavaDoc name, String JavaDoc[] legalNames)
1195        throws IIOInvalidTreeException JavaDoc {
1196        return getEnumeratedAttribute(node, name, legalNames, -1, true);
1197    }
1198
1199    // Get a String-valued attribute
1200
private String JavaDoc getAttribute(Node JavaDoc node, String JavaDoc name,
1201                                String JavaDoc defaultValue, boolean required)
1202        throws IIOInvalidTreeException JavaDoc {
1203        Node JavaDoc attr = node.getAttributes().getNamedItem(name);
1204        if (attr == null) {
1205            if (!required) {
1206                return defaultValue;
1207            } else {
1208                fatal(node, "Required attribute " + name + " not present!");
1209            }
1210        }
1211        return attr.getNodeValue();
1212    }
1213
1214    // Get a required String-valued attribute
1215
private String JavaDoc getAttribute(Node JavaDoc node, String JavaDoc name)
1216        throws IIOInvalidTreeException JavaDoc {
1217            return getAttribute(node, name, null, true);
1218    }
1219
1220    public void mergeTree(String JavaDoc formatName, Node JavaDoc root)
1221        throws IIOInvalidTreeException JavaDoc {
1222        if (formatName.equals(nativeMetadataFormatName)) {
1223            if (root == null) {
1224                throw new IllegalArgumentException JavaDoc("root == null!");
1225            }
1226            mergeNativeTree(root);
1227        } else if (formatName.equals
1228                   (IIOMetadataFormatImpl.standardMetadataFormatName)) {
1229            if (root == null) {
1230                throw new IllegalArgumentException JavaDoc("root == null!");
1231            }
1232            mergeStandardTree(root);
1233        } else {
1234            throw new IllegalArgumentException JavaDoc("Not a recognized format!");
1235        }
1236    }
1237
1238    private void mergeNativeTree(Node JavaDoc root)
1239        throws IIOInvalidTreeException JavaDoc {
1240        Node JavaDoc node = root;
1241        if (!node.getNodeName().equals(nativeMetadataFormatName)) {
1242            fatal(node, "Root must be " + nativeMetadataFormatName);
1243        }
1244        
1245        node = node.getFirstChild();
1246        while (node != null) {
1247            String JavaDoc name = node.getNodeName();
1248            
1249            if (name.equals("IHDR")) {
1250                IHDR_width = getIntAttribute(node, "width");
1251                IHDR_height = getIntAttribute(node, "height");
1252                IHDR_bitDepth = getEnumeratedAttribute(node, "bitDepth",
1253                                                       IHDR_bitDepths);
1254                IHDR_colorType = getEnumeratedAttribute(node, "colorType",
1255                                                        IHDR_colorTypeNames);
1256                IHDR_compressionMethod =
1257                    getEnumeratedAttribute(node, "compressionMethod",
1258                                           IHDR_compressionMethodNames);
1259                IHDR_filterMethod =
1260                    getEnumeratedAttribute(node,
1261                                           "filterMethod",
1262                                           IHDR_filterMethodNames);
1263                IHDR_interlaceMethod =
1264                    getEnumeratedAttribute(node, "interlaceMethod",
1265                                           IHDR_interlaceMethodNames);
1266                IHDR_present = true;
1267            } else if (name.equals("PLTE")) {
1268                byte[] red = new byte[256];
1269                byte[] green = new byte[256];
1270                byte[] blue = new byte[256];
1271                int maxindex = -1;
1272                
1273                Node JavaDoc PLTE_entry = node.getFirstChild();
1274                if (PLTE_entry == null) {
1275                    fatal(node, "Palette has no entries!");
1276                }
1277
1278                while (PLTE_entry != null) {
1279                    if (!PLTE_entry.getNodeName().equals("PLTEEntry")) {
1280                        fatal(node,
1281                              "Only a PLTEEntry may be a child of a PLTE!");
1282                    }
1283                    
1284                    int index = getIntAttribute(PLTE_entry, "index");
1285                    if (index < 0 || index > 255) {
1286                        fatal(node,
1287                              "Bad value for PLTEEntry attribute index!");
1288                    }
1289                    if (index > maxindex) {
1290                        maxindex = index;
1291                    }
1292                    red[index] =
1293                        (byte)getIntAttribute(PLTE_entry, "red");
1294                    green[index] =
1295                        (byte)getIntAttribute(PLTE_entry, "green");
1296                    blue[index] =
1297                        (byte)getIntAttribute(PLTE_entry, "blue");
1298                    
1299                    PLTE_entry = PLTE_entry.getNextSibling();
1300                }
1301                
1302                int numEntries = maxindex + 1;
1303                PLTE_red = new byte[numEntries];
1304                PLTE_green = new byte[numEntries];
1305                PLTE_blue = new byte[numEntries];
1306                System.arraycopy(red, 0, PLTE_red, 0, numEntries);
1307                System.arraycopy(green, 0, PLTE_green, 0, numEntries);
1308                System.arraycopy(blue, 0, PLTE_blue, 0, numEntries);
1309                PLTE_present = true;
1310            } else if (name.equals("bKGD")) {
1311                bKGD_present = false; // Guard against partial overwrite
1312
Node JavaDoc bKGD_node = node.getFirstChild();
1313                if (bKGD_node == null) {
1314                    fatal(node, "bKGD node has no children!");
1315                }
1316                String JavaDoc bKGD_name = bKGD_node.getNodeName();
1317                if (bKGD_name.equals("bKGD_Palette")) {
1318                    bKGD_index = getIntAttribute(bKGD_node, "index");
1319                    bKGD_colorType = PNGImageReader.PNG_COLOR_PALETTE;
1320                } else if (bKGD_name.equals("bKGD_Grayscale")) {
1321                    bKGD_gray = getIntAttribute(bKGD_node, "gray");
1322                    bKGD_colorType = PNGImageReader.PNG_COLOR_GRAY;
1323                } else if (bKGD_name.equals("bKGD_RGB")) {
1324                    bKGD_red = getIntAttribute(bKGD_node, "red");
1325                    bKGD_green = getIntAttribute(bKGD_node, "green");
1326                    bKGD_blue = getIntAttribute(bKGD_node, "blue");
1327                    bKGD_colorType = PNGImageReader.PNG_COLOR_RGB;
1328                } else {
1329                    fatal(node, "Bad child of a bKGD node!");
1330                }
1331                if (bKGD_node.getNextSibling() != null) {
1332                    fatal(node, "bKGD node has more than one child!");
1333                }
1334
1335                bKGD_present = true;
1336            } else if (name.equals("cHRM")) {
1337                cHRM_whitePointX = getIntAttribute(node, "whitePointX");
1338                cHRM_whitePointY = getIntAttribute(node, "whitePointY");
1339                cHRM_redX = getIntAttribute(node, "redX");
1340                cHRM_redY = getIntAttribute(node, "redY");
1341                cHRM_greenX = getIntAttribute(node, "greenX");
1342                cHRM_greenY = getIntAttribute(node, "greenY");
1343                cHRM_blueX = getIntAttribute(node, "blueX");
1344                cHRM_blueY = getIntAttribute(node, "blueY");
1345                
1346                cHRM_present = true;
1347            } else if (name.equals("gAMA")) {
1348                gAMA_gamma = getIntAttribute(node, "value");
1349                gAMA_present = true;
1350            } else if (name.equals("hIST")) {
1351                char[] hist = new char[256];
1352                int maxindex = -1;
1353                
1354                Node JavaDoc hIST_entry = node.getFirstChild();
1355                if (hIST_entry == null) {
1356                    fatal(node, "hIST node has no children!");
1357                }
1358
1359                while (hIST_entry != null) {
1360                    if (!hIST_entry.getNodeName().equals("hISTEntry")) {
1361                        fatal(node,
1362                              "Only a hISTEntry may be a child of a hIST!");
1363                    }
1364                    
1365                    int index = getIntAttribute(hIST_entry, "index");
1366                    if (index < 0 || index > 255) {
1367                        fatal(node,
1368                              "Bad value for histEntry attribute index!");
1369                    }
1370                    if (index > maxindex) {
1371                        maxindex = index;
1372                    }
1373                    hist[index] =
1374                        (char)getIntAttribute(hIST_entry, "value");
1375                    
1376                    hIST_entry = hIST_entry.getNextSibling();
1377                }
1378                
1379                int numEntries = maxindex + 1;
1380                hIST_histogram = new char[numEntries];
1381                System.arraycopy(hist, 0, hIST_histogram, 0, numEntries);
1382                
1383                hIST_present = true;
1384            } else if (name.equals("iCCP")) {
1385                iCCP_profileName = getAttribute(node, "profileName");
1386                iCCP_compressionMethod =
1387                    getEnumeratedAttribute(node, "compressionMethod",
1388                                           iCCP_compressionMethodNames);
1389                Object JavaDoc compressedProfile =
1390                    ((IIOMetadataNode JavaDoc)node).getUserObject();
1391                if (compressedProfile == null) {
1392                    fatal(node, "No ICCP profile present in user object!");
1393                }
1394                if (!(compressedProfile instanceof byte[])) {
1395                    fatal(node, "User object not a byte array!");
1396                }
1397                
1398                iCCP_compressedProfile =
1399                    (byte[])((byte[])compressedProfile).clone();
1400                
1401                iCCP_present = true;
1402            } else if (name.equals("iTXt")) {
1403                Node JavaDoc iTXt_node = node.getFirstChild();
1404                while (iTXt_node != null) {
1405                    if (!iTXt_node.getNodeName().equals("iTXtEntry")) {
1406                        fatal(node,
1407                              "Only an iTXtEntry may be a child of an iTXt!");
1408                    }
1409                    
1410                    String JavaDoc keyword = getAttribute(iTXt_node, "keyword");
1411                    iTXt_keyword.add(keyword);
1412                    
1413                    boolean compressionFlag =
1414                        getBooleanAttribute(iTXt_node, "compressionFlag");
1415                    iTXt_compressionFlag.add(new Boolean JavaDoc(compressionFlag));
1416                    
1417                    String JavaDoc compressionMethod =
1418                        getAttribute(iTXt_node, "compressionMethod");
1419                    iTXt_compressionMethod.add(compressionMethod);
1420                    
1421                    String JavaDoc languageTag =
1422                        getAttribute(iTXt_node, "languageTag");
1423                    iTXt_languageTag.add(languageTag);
1424                    
1425                    String JavaDoc translatedKeyword =
1426                        getAttribute(iTXt_node, "translatedKeyword");
1427                    iTXt_translatedKeyword.add(translatedKeyword);
1428                    
1429                    String JavaDoc text = getAttribute(iTXt_node, "text");
1430                    iTXt_text.add(text);
1431                    
1432                    iTXt_node = iTXt_node.getNextSibling();
1433                }
1434            } else if (name.equals("pHYs")) {
1435                pHYs_pixelsPerUnitXAxis =
1436                    getIntAttribute(node, "pixelsPerUnitXAxis");
1437                pHYs_pixelsPerUnitYAxis =
1438                    getIntAttribute(node, "pixelsPerUnitYAxis");
1439                pHYs_unitSpecifier =
1440                    getEnumeratedAttribute(node, "unitSpecifier",
1441                                           unitSpecifierNames);
1442                
1443                pHYs_present = true;
1444            } else if (name.equals("sBIT")) {
1445                sBIT_present = false; // Guard against partial overwrite
1446
Node JavaDoc sBIT_node = node.getFirstChild();
1447                if (sBIT_node == null) {
1448                    fatal(node, "sBIT node has no children!");
1449                }
1450                String JavaDoc sBIT_name = sBIT_node.getNodeName();
1451                if (sBIT_name.equals("sBIT_Grayscale")) {
1452                    sBIT_grayBits = getIntAttribute(sBIT_node, "gray");
1453                    sBIT_colorType = PNGImageReader.PNG_COLOR_GRAY;
1454                } else if (sBIT_name.equals("sBIT_GrayAlpha")) {
1455                    sBIT_grayBits = getIntAttribute(sBIT_node, "gray");
1456                    sBIT_alphaBits = getIntAttribute(sBIT_node, "alpha");
1457                    sBIT_colorType = PNGImageReader.PNG_COLOR_GRAY_ALPHA;
1458                } else if (sBIT_name.equals("sBIT_RGB")) {
1459                    sBIT_redBits = getIntAttribute(sBIT_node, "red");
1460                    sBIT_greenBits = getIntAttribute(sBIT_node, "green");
1461                    sBIT_blueBits = getIntAttribute(sBIT_node, "blue");
1462                    sBIT_colorType = PNGImageReader.PNG_COLOR_RGB;
1463                } else if (sBIT_name.equals("sBIT_RGBAlpha")) {
1464                    sBIT_redBits = getIntAttribute(sBIT_node, "red");
1465                    sBIT_greenBits = getIntAttribute(sBIT_node, "green");
1466                    sBIT_blueBits = getIntAttribute(sBIT_node, "blue");
1467                    sBIT_alphaBits = getIntAttribute(sBIT_node, "alpha");
1468                    sBIT_colorType = PNGImageReader.PNG_COLOR_RGB_ALPHA;
1469                } else if (sBIT_name.equals("sBIT_Palette")) {
1470                    sBIT_redBits = getIntAttribute(sBIT_node, "red");
1471                    sBIT_greenBits = getIntAttribute(sBIT_node, "green");
1472                    sBIT_blueBits = getIntAttribute(sBIT_node, "blue");
1473                    sBIT_colorType = PNGImageReader.PNG_COLOR_PALETTE;
1474                } else {
1475                    fatal(node, "Bad child of an sBIT node!");
1476                }
1477                if (sBIT_node.getNextSibling() != null) {
1478                    fatal(node, "sBIT node has more than one child!");
1479                }
1480
1481                sBIT_present = true;
1482            } else if (name.equals("sPLT")) {
1483                sPLT_paletteName = getAttribute(node, "name");
1484                sPLT_sampleDepth = getIntAttribute(node, "sampleDepth");
1485                
1486                int[] red = new int[256];
1487                int[] green = new int[256];
1488                int[] blue = new int[256];
1489                int[] alpha = new int[256];
1490                int[] frequency = new int[256];
1491                int maxindex = -1;
1492                
1493                Node JavaDoc sPLT_entry = node.getFirstChild();
1494                if (sPLT_entry == null) {
1495                    fatal(node, "sPLT node has no children!");
1496                }
1497
1498                while (sPLT_entry != null) {
1499                    if (!sPLT_entry.getNodeName().equals("sPLTEntry")) {
1500                        fatal(node,
1501                              "Only an sPLTEntry may be a child of an sPLT!");
1502                    }
1503                    
1504                    int index = getIntAttribute(sPLT_entry, "index");
1505                    if (index < 0 || index > 255) {
1506                        fatal(node,
1507                              "Bad value for PLTEEntry attribute index!");
1508                    }
1509                    if (index > maxindex) {
1510                        maxindex = index;
1511                    }
1512                    red[index] = getIntAttribute(sPLT_entry, "red");
1513                    green[index] = getIntAttribute(sPLT_entry, "green");
1514                    blue[index] = getIntAttribute(sPLT_entry, "blue");
1515                    alpha[index] = getIntAttribute(sPLT_entry, "alpha");
1516                    frequency[index] =
1517                        getIntAttribute(sPLT_entry, "frequency");
1518                    
1519                    sPLT_entry = sPLT_entry.getNextSibling();
1520                }
1521                
1522                int numEntries = maxindex + 1;
1523                sPLT_red = new int[numEntries];
1524                sPLT_green = new int[numEntries];
1525                sPLT_blue = new int[numEntries];
1526                sPLT_alpha = new int[numEntries];
1527                sPLT_frequency = new int[numEntries];
1528                System.arraycopy(red, 0, sPLT_red, 0, numEntries);
1529                System.arraycopy(green, 0, sPLT_green, 0, numEntries);
1530                System.arraycopy(blue, 0, sPLT_blue, 0, numEntries);
1531                System.arraycopy(alpha, 0, sPLT_alpha, 0, numEntries);
1532                System.arraycopy(frequency, 0,
1533                                 sPLT_frequency, 0, numEntries);
1534                
1535                sPLT_present = true;
1536            } else if (name.equals("sRGB")) {
1537                sRGB_renderingIntent =
1538                    getEnumeratedAttribute(node, "renderingIntent",
1539                                           renderingIntentNames);
1540                
1541                sRGB_present = true;
1542            } else if (name.equals("tEXt")) {
1543                Node JavaDoc tEXt_node = node.getFirstChild();
1544                while (tEXt_node != null) {
1545                    if (!tEXt_node.getNodeName().equals("tEXtEntry")) {
1546                        fatal(node,
1547                              "Only an tEXtEntry may be a child of an tEXt!");
1548                    }
1549                    
1550                    String JavaDoc keyword = getAttribute(tEXt_node, "keyword");
1551                    tEXt_keyword.add(keyword);
1552                    
1553                    String JavaDoc text = getAttribute(tEXt_node, "value");
1554                    tEXt_text.add(text);
1555                    
1556                    tEXt_node = tEXt_node.getNextSibling();
1557                }
1558            } else if (name.equals("tIME")) {
1559                tIME_year = getIntAttribute(node, "year");
1560                tIME_month = getIntAttribute(node, "month");
1561                tIME_day = getIntAttribute(node, "day");
1562                tIME_hour = getIntAttribute(node, "hour");
1563                tIME_minute = getIntAttribute(node, "minute");
1564                tIME_second = getIntAttribute(node, "second");
1565                
1566                tIME_present = true;
1567            } else if (name.equals("tRNS")) {
1568                tRNS_present = false; // Guard against partial overwrite
1569
Node JavaDoc tRNS_node = node.getFirstChild();
1570                if (tRNS_node == null) {
1571                    fatal(node, "tRNS node has no children!");
1572                }
1573                String JavaDoc tRNS_name = tRNS_node.getNodeName();
1574                if (tRNS_name.equals("tRNS_Palette")) {
1575                    byte[] alpha = new byte[256];
1576                    int maxindex = -1;
1577                    
1578                    Node JavaDoc tRNS_paletteEntry = tRNS_node.getFirstChild();
1579                    if (tRNS_paletteEntry == null) {
1580                        fatal(node, "tRNS_Palette node has no children!");
1581                    }
1582                    while (tRNS_paletteEntry != null) {
1583                        if (!tRNS_paletteEntry.getNodeName().equals(
1584                                                        "tRNS_PaletteEntry")) {
1585                            fatal(node,
1586                 "Only a tRNS_PaletteEntry may be a child of a tRNS_Palette!");
1587                        }
1588                        int index =
1589                            getIntAttribute(tRNS_paletteEntry, "index");
1590                        if (index < 0 || index > 255) {
1591                            fatal(node,
1592                           "Bad value for tRNS_PaletteEntry attribute index!");
1593                        }
1594                        if (index > maxindex) {
1595                            maxindex = index;
1596                        }
1597                        alpha[index] =
1598                            (byte)getIntAttribute(tRNS_paletteEntry,
1599                                                  "alpha");
1600                        
1601                        tRNS_paletteEntry =
1602                            tRNS_paletteEntry.getNextSibling();
1603                    }
1604                    
1605                    int numEntries = maxindex + 1;
1606                    tRNS_alpha = new byte[numEntries];
1607                    tRNS_colorType = PNGImageReader.PNG_COLOR_PALETTE;
1608                    System.arraycopy(alpha, 0, tRNS_alpha, 0, numEntries);
1609                } else if (tRNS_name.equals("tRNS_Grayscale")) {
1610                    tRNS_gray = getIntAttribute(tRNS_node, "gray");
1611                    tRNS_colorType = PNGImageReader.PNG_COLOR_GRAY;
1612                } else if (tRNS_name.equals("tRNS_RGB")) {
1613                    tRNS_red = getIntAttribute(tRNS_node, "red");
1614                    tRNS_green = getIntAttribute(tRNS_node, "green");
1615                    tRNS_blue = getIntAttribute(tRNS_node, "blue");
1616                    tRNS_colorType = PNGImageReader.PNG_COLOR_RGB;
1617                } else {
1618                    fatal(node, "Bad child of a tRNS node!");
1619                }
1620                if (tRNS_node.getNextSibling() != null) {
1621                    fatal(node, "tRNS node has more than one child!");
1622                }
1623                
1624                tRNS_present = true;
1625            } else if (name.equals("zTXt")) {
1626                Node JavaDoc zTXt_node = node.getFirstChild();
1627                while (zTXt_node != null) {
1628                    if (!zTXt_node.getNodeName().equals("zTXtEntry")) {
1629                        fatal(node,
1630                              "Only an zTXtEntry may be a child of an zTXt!");
1631                    }
1632                    
1633                    String JavaDoc keyword = getAttribute(zTXt_node, "keyword");
1634                    zTXt_keyword.add(keyword);
1635                    
1636                    int compressionMethod =
1637                        getEnumeratedAttribute(zTXt_node, "compressionMethod",
1638                                               zTXt_compressionMethodNames);
1639                    zTXt_compressionMethod.add(new Integer JavaDoc(compressionMethod));
1640                    
1641                    String JavaDoc text = getAttribute(zTXt_node, "text");
1642                    zTXt_text.add(text);
1643                    
1644                    zTXt_node = zTXt_node.getNextSibling();
1645                }
1646            } else if (name.equals("UnknownChunks")) {
1647                Node JavaDoc unknown_node = node.getFirstChild();
1648                while (unknown_node != null) {
1649                    if (!unknown_node.getNodeName().equals("UnknownChunk")) {
1650                        fatal(node,
1651                   "Only an UnknownChunk may be a child of an UnknownChunks!");
1652                    }
1653                    String JavaDoc chunkType = getAttribute(unknown_node, "type");
1654                    Object JavaDoc chunkData =
1655                        ((IIOMetadataNode JavaDoc)unknown_node).getUserObject();
1656                    
1657                    if (chunkType.length() != 4) {
1658                        fatal(unknown_node,
1659                              "Chunk type must be 4 characters!");
1660                    }
1661                    if (chunkData == null) {
1662                        fatal(unknown_node,
1663                              "No chunk data present in user object!");
1664                    }
1665                    if (!(chunkData instanceof byte[])) {
1666                        fatal(unknown_node,
1667                              "User object not a byte array!");
1668                    }
1669                    unknownChunkType.add(chunkType);
1670                    unknownChunkData.add(((byte[])chunkData).clone());
1671                    
1672                    unknown_node = unknown_node.getNextSibling();
1673                }
1674            } else {
1675                fatal(node, "Unknown child of root node!");
1676            }
1677            
1678            node = node.getNextSibling();
1679        }
1680    }
1681
1682    private boolean isISOLatin(String JavaDoc s) {
1683        int len = s.length();
1684        for (int i = 0; i < len; i++) {
1685            if (s.charAt(i) > 255) {
1686                return false;
1687            }
1688        }
1689        return true;
1690    }
1691
1692    private void mergeStandardTree(Node JavaDoc root)
1693        throws IIOInvalidTreeException JavaDoc {
1694        Node JavaDoc node = root;
1695        if (!node.getNodeName()
1696            .equals(IIOMetadataFormatImpl.standardMetadataFormatName)) {
1697            fatal(node, "Root must be " +
1698                  IIOMetadataFormatImpl.standardMetadataFormatName);
1699        }
1700        
1701        node = node.getFirstChild();
1702        while (node != null) {
1703            String JavaDoc name = node.getNodeName();
1704
1705            if (name.equals("Chroma")) {
1706                Node JavaDoc child = node.getFirstChild();
1707                while (child != null) {
1708                    String JavaDoc childName = child.getNodeName();
1709                    if (childName.equals("Gamma")) {
1710                        float gamma = getFloatAttribute(child, "value");
1711                        gAMA_present = true;
1712                        gAMA_gamma = (int)(gamma*100000 + 0.5);
1713                    } else if (childName.equals("Palette")) {
1714                        byte[] red = new byte[256];
1715                        byte[] green = new byte[256];
1716                        byte[] blue = new byte[256];
1717                        int maxindex = -1;
1718
1719                        Node JavaDoc entry = child.getFirstChild();
1720                        while (entry != null) {
1721                            int index = getIntAttribute(entry, "index");
1722                            if (index >= 0 && index <= 255) {
1723                                red[index] =
1724                                    (byte)getIntAttribute(entry, "red");
1725                                green[index] =
1726                                    (byte)getIntAttribute(entry, "green");
1727                                blue[index] =
1728                                    (byte)getIntAttribute(entry, "blue");
1729                                if (index > maxindex) {
1730                                    maxindex = index;
1731                                }
1732                            }
1733                            entry = entry.getNextSibling();
1734                        }
1735                        
1736                        int numEntries = maxindex + 1;
1737                        PLTE_red = new byte[numEntries];
1738                        PLTE_green = new byte[numEntries];
1739                        PLTE_blue = new byte[numEntries];
1740                        System.arraycopy(red, 0, PLTE_red, 0, numEntries);
1741                        System.arraycopy(green, 0, PLTE_green, 0, numEntries);
1742                        System.arraycopy(blue, 0, PLTE_blue, 0, numEntries);
1743                        PLTE_present = true;
1744                    } else if (childName.equals("BackgroundIndex")) {
1745                        bKGD_present = true;
1746                        bKGD_colorType = PNGImageReader.PNG_COLOR_PALETTE;
1747                        bKGD_index = getIntAttribute(child, "value");
1748                    } else if (childName.equals("BackgroundColor")) {
1749                        int red = getIntAttribute(child, "red");
1750                        int green = getIntAttribute(child, "green");
1751                        int blue = getIntAttribute(child, "blue");
1752                        if (red == green && red == blue) {
1753                            bKGD_colorType = PNGImageReader.PNG_COLOR_GRAY;
1754                            bKGD_gray = red;
1755                        } else {
1756                            bKGD_red = red;
1757                            bKGD_green = green;
1758                            bKGD_blue = blue;
1759                        }
1760                        bKGD_present = true;
1761                    }
1762// } else if (childName.equals("ColorSpaceType")) {
1763
// } else if (childName.equals("NumChannels")) {
1764

1765                    child = child.getNextSibling();
1766                }
1767            } else if (name.equals("Compression")) {
1768                Node JavaDoc child = node.getFirstChild();
1769                while (child != null) {
1770                    String JavaDoc childName = child.getNodeName();
1771                    if (childName.equals("NumProgressiveScans")) {
1772                        // Use Adam7 if NumProgressiveScans > 1
1773
int scans = getIntAttribute(child, "value");
1774                        IHDR_interlaceMethod = (scans > 1) ? 1 : 0;
1775// } else if (childName.equals("CompressionTypeName")) {
1776
// } else if (childName.equals("Lossless")) {
1777
// } else if (childName.equals("BitRate")) {
1778
}
1779                    child = child.getNextSibling();
1780                }
1781            } else if (name.equals("Data")) {
1782                Node JavaDoc child = node.getFirstChild();
1783                while (child != null) {
1784                    String JavaDoc childName = child.getNodeName();
1785                    if (childName.equals("BitsPerSample")) {
1786                        String JavaDoc s = getAttribute(child, "value");
1787                        StringTokenizer JavaDoc t = new StringTokenizer JavaDoc(s);
1788                        int maxBits = -1;
1789                        while (t.hasMoreTokens()) {
1790                            int bits = Integer.parseInt(t.nextToken());
1791                            if (bits > maxBits) {
1792                                maxBits = bits;
1793                            }
1794                        }
1795                        if (maxBits < 1) {
1796                            maxBits = 1;
1797                        }
1798                        if (maxBits == 3) maxBits = 4;
1799                        if (maxBits > 4 || maxBits < 8) {
1800                            maxBits = 8;
1801                        }
1802                        if (maxBits > 8) {
1803                            maxBits = 16;
1804                        }
1805                        IHDR_bitDepth = maxBits;
1806                    } else if (childName.equals("SignificantBitsPerSample")) {
1807                        String JavaDoc s = getAttribute(child, "value");
1808                        StringTokenizer JavaDoc t = new StringTokenizer JavaDoc(s);
1809                        int numTokens = t.countTokens();
1810                        if (numTokens == 1) {
1811                            sBIT_colorType = PNGImageReader.PNG_COLOR_GRAY;
1812                            sBIT_grayBits = Integer.parseInt(t.nextToken());
1813                        } else if (numTokens == 2) {
1814                            sBIT_colorType =
1815                              PNGImageReader.PNG_COLOR_GRAY_ALPHA;
1816                            sBIT_grayBits = Integer.parseInt(t.nextToken());
1817                            sBIT_alphaBits = Integer.parseInt(t.nextToken());
1818                        } else if (numTokens == 3) {
1819                            sBIT_colorType = PNGImageReader.PNG_COLOR_RGB;
1820                            sBIT_redBits = Integer.parseInt(t.nextToken());
1821                            sBIT_greenBits = Integer.parseInt(t.nextToken());
1822                            sBIT_blueBits = Integer.parseInt(t.nextToken());
1823                        } else if (numTokens == 4) {
1824                            sBIT_colorType =
1825                              PNGImageReader.PNG_COLOR_RGB_ALPHA;
1826                            sBIT_redBits = Integer.parseInt(t.nextToken());
1827                            sBIT_greenBits = Integer.parseInt(t.nextToken());
1828                            sBIT_blueBits = Integer.parseInt(t.nextToken());
1829                            sBIT_alphaBits = Integer.parseInt(t.nextToken());
1830                        }
1831                        if (numTokens >= 1 && numTokens <= 4) {
1832                            sBIT_present = true;
1833                        }
1834// } else if (childName.equals("PlanarConfiguration")) {
1835
// } else if (childName.equals("SampleFormat")) {
1836
// } else if (childName.equals("SampleMSB")) {
1837
}
1838                    child = child.getNextSibling();
1839                }
1840            } else if (name.equals("Dimension")) {
1841                boolean gotWidth = false;
1842                boolean gotHeight = false;
1843                boolean gotAspectRatio = false;
1844
1845                float width = -1.0F;
1846                float height = -1.0F;
1847                float aspectRatio = -1.0F;
1848                
1849                Node JavaDoc child = node.getFirstChild();
1850                while (child != null) {
1851                    String JavaDoc childName = child.getNodeName();
1852                    if (childName.equals("PixelAspectRatio")) {
1853                        aspectRatio = getFloatAttribute(child, "value");
1854                        gotAspectRatio = true;
1855                    } else if (childName.equals("HorizontalPixelSize")) {
1856                        width = getFloatAttribute(child, "value");
1857                        gotWidth = true;
1858                    } else if (childName.equals("VerticalPixelSize")) {
1859                        height = getFloatAttribute(child, "value");
1860                        gotHeight = true;
1861// } else if (childName.equals("ImageOrientation")) {
1862
// } else if
1863
// (childName.equals("HorizontalPhysicalPixelSpacing")) {
1864
// } else if
1865
// (childName.equals("VerticalPhysicalPixelSpacing")) {
1866
// } else if (childName.equals("HorizontalPosition")) {
1867
// } else if (childName.equals("VerticalPosition")) {
1868
// } else if (childName.equals("HorizontalPixelOffset")) {
1869
// } else if (childName.equals("VerticalPixelOffset")) {
1870
}
1871                    child = child.getNextSibling();
1872                }
1873
1874                if (gotWidth && gotHeight) {
1875                    pHYs_present = true;
1876                    pHYs_unitSpecifier = 1;
1877                    pHYs_pixelsPerUnitXAxis = (int)(width*1000 + 0.5F);
1878                    pHYs_pixelsPerUnitYAxis = (int)(height*1000 + 0.5F);
1879                } else if (gotAspectRatio) {
1880                    pHYs_present = true;
1881                    pHYs_unitSpecifier = 0;
1882
1883                    // Find a reasonable rational approximation
1884
int denom = 1;
1885                    for (; denom < 100; denom++) {
1886                        int num = (int)(aspectRatio*denom);
1887                        if (Math.abs(num/denom - aspectRatio) < 0.001) {
1888                            break;
1889                        }
1890                    }
1891                    pHYs_pixelsPerUnitXAxis = (int)(aspectRatio*denom);
1892                    pHYs_pixelsPerUnitYAxis = denom;
1893                }
1894            } else if (name.equals("Document")) {
1895                Node JavaDoc child = node.getFirstChild();
1896                while (child != null) {
1897                    String JavaDoc childName = child.getNodeName();
1898                    if (childName.equals("ImageModificationTime")) {
1899                        tIME_present = true;
1900                        tIME_year = getIntAttribute(child, "year");
1901                        tIME_month = getIntAttribute(child, "month");
1902                        tIME_day = getIntAttribute(child, "day");
1903                        tIME_hour =
1904                            getIntAttribute(child, "hour", 0, false);
1905                        tIME_minute =
1906                            getIntAttribute(child, "minute", 0, false);
1907                        tIME_second =
1908                            getIntAttribute(child, "second", 0, false);
1909// } else if (childName.equals("SubimageInterpretation")) {
1910
// } else if (childName.equals("ImageCreationTime")) {
1911
}
1912                    child = child.getNextSibling();
1913                }
1914            } else if (name.equals("Text")) {
1915                Node JavaDoc child = node.getFirstChild();
1916                while (child != null) {
1917                    String JavaDoc childName = child.getNodeName();
1918                    if (childName.equals("TextEntry")) {
1919                        String JavaDoc keyword = getAttribute(child, "keyword");
1920                        String JavaDoc value = getAttribute(child, "value");
1921                        String JavaDoc encoding = getAttribute(child, "encoding");
1922                        String JavaDoc language = getAttribute(child, "language");
1923                        String JavaDoc compression =
1924                            getAttribute(child, "compression");
1925
1926                        if (isISOLatin(value)) {
1927                            if (compression.equals("zip")) {
1928                                // Use a zTXt node
1929
zTXt_keyword.add(keyword);
1930                                zTXt_text.add(value);
1931                                zTXt_compressionMethod.add(new Integer JavaDoc(0));
1932                            } else {
1933                                // Use a tEXt node
1934
tEXt_keyword.add(keyword);
1935                                tEXt_text.add(value);
1936                            }
1937                        } else {
1938                            int flag = compression.equals("zip") ?
1939                                1 : 0;
1940
1941                            // Use an iTXt node
1942
iTXt_keyword.add(keyword);
1943                            iTXt_compressionFlag.add(new Integer JavaDoc(flag));
1944                            iTXt_compressionMethod.add(new Integer JavaDoc(0));
1945                            iTXt_languageTag.add(language);
1946                            iTXt_translatedKeyword.add(keyword); // fake it
1947
iTXt_text.add(value);
1948                        }
1949                    }
1950                    child = child.getNextSibling();
1951                }
1952// } else if (name.equals("Transparency")) {
1953
// Node child = node.getFirstChild();
1954
// while (child != null) {
1955
// String childName = child.getNodeName();
1956
// if (childName.equals("Alpha")) {
1957
// } else if (childName.equals("TransparentIndex")) {
1958
// } else if (childName.equals("TransparentColor")) {
1959
// } else if (childName.equals("TileTransparencies")) {
1960
// } else if (childName.equals("TileOpacities")) {
1961
// }
1962
// child = child.getNextSibling();
1963
// }
1964
// } else {
1965
// // fatal(node, "Unknown child of root node!");
1966
}
1967            
1968            node = node.getNextSibling();
1969        }
1970    }
1971
1972    // Reset all instance variables to their initial state
1973
public void reset() {
1974        IHDR_present = false;
1975        PLTE_present = false;
1976        bKGD_present = false;
1977        cHRM_present = false;
1978        gAMA_present = false;
1979        hIST_present = false;
1980        iCCP_present = false;
1981        iTXt_keyword = new ArrayList JavaDoc();
1982        iTXt_compressionFlag = new ArrayList JavaDoc();
1983        iTXt_compressionMethod = new ArrayList JavaDoc();
1984        iTXt_languageTag = new ArrayList JavaDoc();
1985        iTXt_translatedKeyword = new ArrayList JavaDoc();
1986        iTXt_text = new ArrayList JavaDoc();
1987        pHYs_present = false;
1988        sBIT_present = false;
1989        sPLT_present = false;
1990        sRGB_present = false;
1991        tEXt_keyword = new ArrayList JavaDoc();
1992        tEXt_text = new ArrayList JavaDoc();
1993        tIME_present = false;
1994        tRNS_present = false;
1995        zTXt_keyword = new ArrayList JavaDoc();
1996        zTXt_compressionMethod = new ArrayList JavaDoc();
1997        zTXt_text = new ArrayList JavaDoc();
1998        unknownChunkType = new ArrayList JavaDoc();
1999        unknownChunkData = new ArrayList JavaDoc();
2000    }
2001}
2002
Popular Tags