jdk/src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageMetadata.java
changeset 34416 68c0d866db5d
child 36448 a07e108d5722
equal deleted inserted replaced
34415:098d54b4051d 34416:68c0d866db5d
       
     1 /*
       
     2  * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 package com.sun.imageio.plugins.tiff;
       
    26 
       
    27 import java.io.IOException;
       
    28 import java.lang.reflect.InvocationTargetException;
       
    29 import java.lang.reflect.Method;
       
    30 import java.util.ArrayList;
       
    31 import java.util.Arrays;
       
    32 import java.util.HashMap;
       
    33 import java.util.Iterator;
       
    34 import java.util.List;
       
    35 import java.util.Map;
       
    36 import java.util.StringTokenizer;
       
    37 import javax.imageio.metadata.IIOMetadata;
       
    38 import javax.imageio.metadata.IIOInvalidTreeException;
       
    39 import javax.imageio.metadata.IIOMetadataFormatImpl;
       
    40 import javax.imageio.metadata.IIOMetadataNode;
       
    41 import javax.imageio.stream.ImageInputStream;
       
    42 import org.w3c.dom.NamedNodeMap;
       
    43 import org.w3c.dom.Node;
       
    44 import org.w3c.dom.NodeList;
       
    45 import javax.imageio.plugins.tiff.BaselineTIFFTagSet;
       
    46 import javax.imageio.plugins.tiff.ExifParentTIFFTagSet;
       
    47 import javax.imageio.plugins.tiff.TIFFField;
       
    48 import javax.imageio.plugins.tiff.TIFFTag;
       
    49 import javax.imageio.plugins.tiff.TIFFTagSet;
       
    50 
       
    51 public class TIFFImageMetadata extends IIOMetadata {
       
    52 
       
    53     // package scope
       
    54 
       
    55     public static final String NATIVE_METADATA_FORMAT_NAME =
       
    56         "javax_imageio_tiff_image_1.0";
       
    57 
       
    58     public static final String NATIVE_METADATA_FORMAT_CLASS_NAME =
       
    59         "javax.imageio.plugins.tiff.TIFFImageMetadataFormat";
       
    60 
       
    61     private List<TIFFTagSet> tagSets;
       
    62 
       
    63     TIFFIFD rootIFD;
       
    64 
       
    65     public TIFFImageMetadata(List<TIFFTagSet> tagSets) {
       
    66         super(true,
       
    67               NATIVE_METADATA_FORMAT_NAME,
       
    68               NATIVE_METADATA_FORMAT_CLASS_NAME,
       
    69               null, null);
       
    70 
       
    71         this.tagSets = tagSets;
       
    72         this.rootIFD = new TIFFIFD(tagSets);
       
    73     }
       
    74 
       
    75     public TIFFImageMetadata(TIFFIFD ifd) {
       
    76         super(true,
       
    77               NATIVE_METADATA_FORMAT_NAME,
       
    78               NATIVE_METADATA_FORMAT_CLASS_NAME,
       
    79               null, null);
       
    80         this.tagSets = ifd.getTagSetList();
       
    81         this.rootIFD = ifd;
       
    82     }
       
    83 
       
    84     public void initializeFromStream(ImageInputStream stream,
       
    85                                      boolean ignoreUnknownFields)
       
    86         throws IOException {
       
    87         rootIFD.initialize(stream, true, ignoreUnknownFields);
       
    88     }
       
    89 
       
    90     public void addShortOrLongField(int tagNumber, int value) {
       
    91         TIFFField field = new TIFFField(rootIFD.getTag(tagNumber), value);
       
    92         rootIFD.addTIFFField(field);
       
    93     }
       
    94 
       
    95     public boolean isReadOnly() {
       
    96         return false;
       
    97     }
       
    98 
       
    99     private Node getIFDAsTree(TIFFIFD ifd,
       
   100                               String parentTagName, int parentTagNumber) {
       
   101         IIOMetadataNode IFDRoot = new IIOMetadataNode("TIFFIFD");
       
   102         if (parentTagNumber != 0) {
       
   103             IFDRoot.setAttribute("parentTagNumber",
       
   104                                  Integer.toString(parentTagNumber));
       
   105         }
       
   106         if (parentTagName != null) {
       
   107             IFDRoot.setAttribute("parentTagName", parentTagName);
       
   108         }
       
   109 
       
   110         List<TIFFTagSet> tagSets = ifd.getTagSetList();
       
   111         if (tagSets.size() > 0) {
       
   112             Iterator<TIFFTagSet> iter = tagSets.iterator();
       
   113             StringBuilder tagSetNames = new StringBuilder();
       
   114             while (iter.hasNext()) {
       
   115                 TIFFTagSet tagSet = iter.next();
       
   116                 tagSetNames.append(tagSet.getClass().getName());
       
   117                 if (iter.hasNext()) {
       
   118                     tagSetNames.append(",");
       
   119                 }
       
   120             }
       
   121 
       
   122             IFDRoot.setAttribute("tagSets", tagSetNames.toString());
       
   123         }
       
   124 
       
   125         Iterator<TIFFField> iter = ifd.iterator();
       
   126         while (iter.hasNext()) {
       
   127             TIFFField f = iter.next();
       
   128             int tagNumber = f.getTagNumber();
       
   129             TIFFTag tag = TIFFIFD.getTag(tagNumber, tagSets);
       
   130 
       
   131             Node node = null;
       
   132             if (tag == null) {
       
   133                 node = f.getAsNativeNode();
       
   134             } else if (tag.isIFDPointer() && f.hasDirectory()) {
       
   135                 TIFFIFD subIFD = (TIFFIFD)f.getDirectory();
       
   136 
       
   137                 // Recurse
       
   138                 node = getIFDAsTree(subIFD, tag.getName(), tag.getNumber());
       
   139             } else {
       
   140                 node = f.getAsNativeNode();
       
   141             }
       
   142 
       
   143             if (node != null) {
       
   144                 IFDRoot.appendChild(node);
       
   145             }
       
   146         }
       
   147 
       
   148         return IFDRoot;
       
   149     }
       
   150 
       
   151     public Node getAsTree(String formatName) {
       
   152         if (formatName.equals(nativeMetadataFormatName)) {
       
   153             return getNativeTree();
       
   154         } else if (formatName.equals
       
   155                    (IIOMetadataFormatImpl.standardMetadataFormatName)) {
       
   156             return getStandardTree();
       
   157         } else {
       
   158             throw new IllegalArgumentException("Not a recognized format!");
       
   159         }
       
   160     }
       
   161 
       
   162     private Node getNativeTree() {
       
   163         IIOMetadataNode root = new IIOMetadataNode(nativeMetadataFormatName);
       
   164 
       
   165         Node IFDNode = getIFDAsTree(rootIFD, null, 0);
       
   166         root.appendChild(IFDNode);
       
   167 
       
   168         return root;
       
   169     }
       
   170 
       
   171     private static final String[] colorSpaceNames = {
       
   172         "GRAY", // WhiteIsZero
       
   173         "GRAY", // BlackIsZero
       
   174         "RGB", // RGB
       
   175         "RGB", // PaletteColor
       
   176         "GRAY", // TransparencyMask
       
   177         "CMYK", // CMYK
       
   178         "YCbCr", // YCbCr
       
   179         "Lab", // CIELab
       
   180         "Lab", // ICCLab
       
   181     };
       
   182 
       
   183     public IIOMetadataNode getStandardChromaNode() {
       
   184         IIOMetadataNode chroma_node = new IIOMetadataNode("Chroma");
       
   185         IIOMetadataNode node = null; // scratch node
       
   186 
       
   187         TIFFField f;
       
   188 
       
   189         // Set the PhotometricInterpretation and the palette color flag.
       
   190         int photometricInterpretation = -1;
       
   191         boolean isPaletteColor = false;
       
   192         f = getTIFFField(BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION);
       
   193         if (f != null) {
       
   194             photometricInterpretation = f.getAsInt(0);
       
   195 
       
   196             isPaletteColor =
       
   197                 photometricInterpretation ==
       
   198                 BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_PALETTE_COLOR;
       
   199         }
       
   200 
       
   201         // Determine the number of channels.
       
   202         int numChannels = -1;
       
   203         if(isPaletteColor) {
       
   204             numChannels = 3;
       
   205         } else {
       
   206             f = getTIFFField(BaselineTIFFTagSet.TAG_SAMPLES_PER_PIXEL);
       
   207             if (f != null) {
       
   208                 numChannels = f.getAsInt(0);
       
   209             } else { // f == null
       
   210                 f = getTIFFField(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE);
       
   211                 if(f != null) {
       
   212                     numChannels = f.getCount();
       
   213                 }
       
   214             }
       
   215         }
       
   216 
       
   217         if(photometricInterpretation != -1) {
       
   218             if (photometricInterpretation >= 0 &&
       
   219                 photometricInterpretation < colorSpaceNames.length) {
       
   220                 node = new IIOMetadataNode("ColorSpaceType");
       
   221                 String csName;
       
   222                 if(photometricInterpretation ==
       
   223                    BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_CMYK &&
       
   224                    numChannels == 3) {
       
   225                     csName = "CMY";
       
   226                 } else {
       
   227                     csName = colorSpaceNames[photometricInterpretation];
       
   228                 }
       
   229                 node.setAttribute("name", csName);
       
   230                 chroma_node.appendChild(node);
       
   231             }
       
   232 
       
   233             node = new IIOMetadataNode("BlackIsZero");
       
   234             node.setAttribute("value",
       
   235                               (photometricInterpretation ==
       
   236                    BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO)
       
   237                               ? "FALSE" : "TRUE");
       
   238             chroma_node.appendChild(node);
       
   239         }
       
   240 
       
   241         if(numChannels != -1) {
       
   242             node = new IIOMetadataNode("NumChannels");
       
   243             node.setAttribute("value", Integer.toString(numChannels));
       
   244             chroma_node.appendChild(node);
       
   245         }
       
   246 
       
   247         f = getTIFFField(BaselineTIFFTagSet.TAG_COLOR_MAP);
       
   248         if (f != null) {
       
   249             // NOTE: The presence of hasAlpha is vestigial: there is
       
   250             // no way in TIFF to represent an alpha component in a palette
       
   251             // color image. See bug 5086341.
       
   252             boolean hasAlpha = false;
       
   253 
       
   254             node = new IIOMetadataNode("Palette");
       
   255             int len = f.getCount()/(hasAlpha ? 4 : 3);
       
   256             for (int i = 0; i < len; i++) {
       
   257                 IIOMetadataNode entry =
       
   258                     new IIOMetadataNode("PaletteEntry");
       
   259                 entry.setAttribute("index", Integer.toString(i));
       
   260 
       
   261                 int r = (f.getAsInt(i)*255)/65535;
       
   262                 int g = (f.getAsInt(len + i)*255)/65535;
       
   263                 int b = (f.getAsInt(2*len + i)*255)/65535;
       
   264 
       
   265                 entry.setAttribute("red", Integer.toString(r));
       
   266                 entry.setAttribute("green", Integer.toString(g));
       
   267                 entry.setAttribute("blue", Integer.toString(b));
       
   268                 if (hasAlpha) {
       
   269                     int alpha = 0;
       
   270                     entry.setAttribute("alpha", Integer.toString(alpha));
       
   271                 }
       
   272                 node.appendChild(entry);
       
   273             }
       
   274             chroma_node.appendChild(node);
       
   275         }
       
   276 
       
   277         return chroma_node;
       
   278     }
       
   279 
       
   280     public IIOMetadataNode getStandardCompressionNode() {
       
   281         IIOMetadataNode compression_node = new IIOMetadataNode("Compression");
       
   282         IIOMetadataNode node = null; // scratch node
       
   283 
       
   284         TIFFField f;
       
   285 
       
   286         f = getTIFFField(BaselineTIFFTagSet.TAG_COMPRESSION);
       
   287         if (f != null) {
       
   288             String compressionTypeName = null;
       
   289             int compression = f.getAsInt(0);
       
   290             boolean isLossless = true; // obligate initialization.
       
   291             if(compression == BaselineTIFFTagSet.COMPRESSION_NONE) {
       
   292                 compressionTypeName = "None";
       
   293                 isLossless = true;
       
   294             } else {
       
   295                 int[] compressionNumbers = TIFFImageWriter.compressionNumbers;
       
   296                 for(int i = 0; i < compressionNumbers.length; i++) {
       
   297                     if(compression == compressionNumbers[i]) {
       
   298                         compressionTypeName =
       
   299                             TIFFImageWriter.compressionTypes[i];
       
   300                         isLossless =
       
   301                             TIFFImageWriter.isCompressionLossless[i];
       
   302                         break;
       
   303                     }
       
   304                 }
       
   305             }
       
   306 
       
   307             if (compressionTypeName != null) {
       
   308                 node = new IIOMetadataNode("CompressionTypeName");
       
   309                 node.setAttribute("value", compressionTypeName);
       
   310                 compression_node.appendChild(node);
       
   311 
       
   312                 node = new IIOMetadataNode("Lossless");
       
   313                 node.setAttribute("value", isLossless ? "TRUE" : "FALSE");
       
   314                 compression_node.appendChild(node);
       
   315             }
       
   316         }
       
   317 
       
   318         node = new IIOMetadataNode("NumProgressiveScans");
       
   319         node.setAttribute("value", "1");
       
   320         compression_node.appendChild(node);
       
   321 
       
   322         return compression_node;
       
   323     }
       
   324 
       
   325     private String repeat(String s, int times) {
       
   326         if (times == 1) {
       
   327             return s;
       
   328         }
       
   329         StringBuffer sb = new StringBuffer((s.length() + 1)*times - 1);
       
   330         sb.append(s);
       
   331         for (int i = 1; i < times; i++) {
       
   332             sb.append(" ");
       
   333             sb.append(s);
       
   334         }
       
   335         return sb.toString();
       
   336     }
       
   337 
       
   338     public IIOMetadataNode getStandardDataNode() {
       
   339         IIOMetadataNode data_node = new IIOMetadataNode("Data");
       
   340         IIOMetadataNode node = null; // scratch node
       
   341 
       
   342         TIFFField f;
       
   343 
       
   344         boolean isPaletteColor = false;
       
   345         f = getTIFFField(BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION);
       
   346         if (f != null) {
       
   347             isPaletteColor =
       
   348                 f.getAsInt(0) ==
       
   349                 BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_PALETTE_COLOR;
       
   350         }
       
   351 
       
   352         f = getTIFFField(BaselineTIFFTagSet.TAG_PLANAR_CONFIGURATION);
       
   353         String planarConfiguration = "PixelInterleaved";
       
   354         if (f != null &&
       
   355             f.getAsInt(0) == BaselineTIFFTagSet.PLANAR_CONFIGURATION_PLANAR) {
       
   356             planarConfiguration = "PlaneInterleaved";
       
   357         }
       
   358 
       
   359         node = new IIOMetadataNode("PlanarConfiguration");
       
   360         node.setAttribute("value", planarConfiguration);
       
   361         data_node.appendChild(node);
       
   362 
       
   363         f = getTIFFField(BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION);
       
   364         if (f != null) {
       
   365             int photometricInterpretation = f.getAsInt(0);
       
   366             String sampleFormat = "UnsignedIntegral";
       
   367 
       
   368             if (photometricInterpretation ==
       
   369                 BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_PALETTE_COLOR) {
       
   370                 sampleFormat = "Index";
       
   371             } else {
       
   372                 f = getTIFFField(BaselineTIFFTagSet.TAG_SAMPLE_FORMAT);
       
   373                 if (f != null) {
       
   374                     int format = f.getAsInt(0);
       
   375                     if (format ==
       
   376                         BaselineTIFFTagSet.SAMPLE_FORMAT_SIGNED_INTEGER) {
       
   377                         sampleFormat = "SignedIntegral";
       
   378                     } else if (format ==
       
   379                         BaselineTIFFTagSet.SAMPLE_FORMAT_UNSIGNED_INTEGER) {
       
   380                         sampleFormat = "UnsignedIntegral";
       
   381                     } else if (format ==
       
   382                                BaselineTIFFTagSet.SAMPLE_FORMAT_FLOATING_POINT) {
       
   383                         sampleFormat = "Real";
       
   384                     } else {
       
   385                         sampleFormat = null; // don't know
       
   386                     }
       
   387                 }
       
   388             }
       
   389             if (sampleFormat != null) {
       
   390                 node = new IIOMetadataNode("SampleFormat");
       
   391                 node.setAttribute("value", sampleFormat);
       
   392                 data_node.appendChild(node);
       
   393             }
       
   394         }
       
   395 
       
   396         f = getTIFFField(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE);
       
   397         int[] bitsPerSample = null;
       
   398         if(f != null) {
       
   399             bitsPerSample = f.getAsInts();
       
   400         } else {
       
   401             f = getTIFFField(BaselineTIFFTagSet.TAG_COMPRESSION);
       
   402             int compression = f != null ?
       
   403                 f.getAsInt(0) : BaselineTIFFTagSet.COMPRESSION_NONE;
       
   404             if(getTIFFField(ExifParentTIFFTagSet.TAG_EXIF_IFD_POINTER) !=
       
   405                null ||
       
   406                compression == BaselineTIFFTagSet.COMPRESSION_JPEG ||
       
   407                compression == BaselineTIFFTagSet.COMPRESSION_OLD_JPEG ||
       
   408                getTIFFField(BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT) !=
       
   409                null) {
       
   410                 f = getTIFFField(BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION);
       
   411                 if(f != null &&
       
   412                    (f.getAsInt(0) ==
       
   413                     BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO ||
       
   414                     f.getAsInt(0) ==
       
   415                     BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO)) {
       
   416                     bitsPerSample = new int[] {8};
       
   417                 } else {
       
   418                     bitsPerSample = new int[] {8, 8, 8};
       
   419                 }
       
   420             } else {
       
   421                 bitsPerSample = new int[] {1};
       
   422             }
       
   423         }
       
   424         StringBuffer sb = new StringBuffer();
       
   425         for (int i = 0; i < bitsPerSample.length; i++) {
       
   426             if (i > 0) {
       
   427                 sb.append(" ");
       
   428             }
       
   429             sb.append(Integer.toString(bitsPerSample[i]));
       
   430         }
       
   431         node = new IIOMetadataNode("BitsPerSample");
       
   432         if(isPaletteColor) {
       
   433             node.setAttribute("value", repeat(sb.toString(), 3));
       
   434         } else {
       
   435             node.setAttribute("value", sb.toString());
       
   436         }
       
   437         data_node.appendChild(node);
       
   438 
       
   439             // SampleMSB
       
   440         f = getTIFFField(BaselineTIFFTagSet.TAG_FILL_ORDER);
       
   441         int fillOrder = f != null ?
       
   442             f.getAsInt(0) : BaselineTIFFTagSet.FILL_ORDER_LEFT_TO_RIGHT;
       
   443         sb = new StringBuffer();
       
   444         for (int i = 0; i < bitsPerSample.length; i++) {
       
   445             if (i > 0) {
       
   446                 sb.append(" ");
       
   447             }
       
   448             int maxBitIndex = bitsPerSample[i] == 1 ?
       
   449                 7 : bitsPerSample[i] - 1;
       
   450             int msb =
       
   451                 fillOrder == BaselineTIFFTagSet.FILL_ORDER_LEFT_TO_RIGHT ?
       
   452                 maxBitIndex : 0;
       
   453             sb.append(Integer.toString(msb));
       
   454         }
       
   455         node = new IIOMetadataNode("SampleMSB");
       
   456         if(isPaletteColor) {
       
   457             node.setAttribute("value", repeat(sb.toString(), 3));
       
   458         } else {
       
   459             node.setAttribute("value", sb.toString());
       
   460         }
       
   461         data_node.appendChild(node);
       
   462 
       
   463         return data_node;
       
   464     }
       
   465 
       
   466     private static final String[] orientationNames = {
       
   467         null,
       
   468         "Normal",
       
   469         "FlipH",
       
   470         "Rotate180",
       
   471         "FlipV",
       
   472         "FlipHRotate90",
       
   473         "Rotate270",
       
   474         "FlipVRotate90",
       
   475         "Rotate90",
       
   476     };
       
   477 
       
   478     public IIOMetadataNode getStandardDimensionNode() {
       
   479         IIOMetadataNode dimension_node = new IIOMetadataNode("Dimension");
       
   480         IIOMetadataNode node = null; // scratch node
       
   481 
       
   482         TIFFField f;
       
   483 
       
   484         long[] xres = null;
       
   485         long[] yres = null;
       
   486 
       
   487         f = getTIFFField(BaselineTIFFTagSet.TAG_X_RESOLUTION);
       
   488         if (f != null) {
       
   489             xres = f.getAsRational(0).clone();
       
   490         }
       
   491 
       
   492         f = getTIFFField(BaselineTIFFTagSet.TAG_Y_RESOLUTION);
       
   493         if (f != null) {
       
   494             yres = f.getAsRational(0).clone();
       
   495         }
       
   496 
       
   497         if (xres != null && yres != null) {
       
   498             node = new IIOMetadataNode("PixelAspectRatio");
       
   499 
       
   500             // Compute (1/xres)/(1/yres)
       
   501             // (xres_denom/xres_num)/(yres_denom/yres_num) =
       
   502             // (xres_denom/xres_num)*(yres_num/yres_denom) =
       
   503             // (xres_denom*yres_num)/(xres_num*yres_denom)
       
   504             float ratio = (float)((double)xres[1]*yres[0])/(xres[0]*yres[1]);
       
   505             node.setAttribute("value", Float.toString(ratio));
       
   506             dimension_node.appendChild(node);
       
   507         }
       
   508 
       
   509         if (xres != null || yres != null) {
       
   510             // Get unit field.
       
   511             f = getTIFFField(BaselineTIFFTagSet.TAG_RESOLUTION_UNIT);
       
   512 
       
   513             // Set resolution unit.
       
   514             int resolutionUnit = f != null ?
       
   515                 f.getAsInt(0) : BaselineTIFFTagSet.RESOLUTION_UNIT_INCH;
       
   516 
       
   517             // Have size if either centimeters or inches.
       
   518             boolean gotPixelSize =
       
   519                 resolutionUnit != BaselineTIFFTagSet.RESOLUTION_UNIT_NONE;
       
   520 
       
   521             // Convert pixels/inch to pixels/centimeter.
       
   522             if (resolutionUnit == BaselineTIFFTagSet.RESOLUTION_UNIT_INCH) {
       
   523                 // Divide xres by 2.54
       
   524                 if (xres != null) {
       
   525                     xres[0] *= 100;
       
   526                     xres[1] *= 254;
       
   527                 }
       
   528 
       
   529                 // Divide yres by 2.54
       
   530                 if (yres != null) {
       
   531                     yres[0] *= 100;
       
   532                     yres[1] *= 254;
       
   533                 }
       
   534             }
       
   535 
       
   536             if (gotPixelSize) {
       
   537                 if (xres != null) {
       
   538                     float horizontalPixelSize = (float)(10.0*xres[1]/xres[0]);
       
   539                     node = new IIOMetadataNode("HorizontalPixelSize");
       
   540                     node.setAttribute("value",
       
   541                                       Float.toString(horizontalPixelSize));
       
   542                     dimension_node.appendChild(node);
       
   543                 }
       
   544 
       
   545                 if (yres != null) {
       
   546                     float verticalPixelSize = (float)(10.0*yres[1]/yres[0]);
       
   547                     node = new IIOMetadataNode("VerticalPixelSize");
       
   548                     node.setAttribute("value",
       
   549                                       Float.toString(verticalPixelSize));
       
   550                     dimension_node.appendChild(node);
       
   551                 }
       
   552             }
       
   553         }
       
   554 
       
   555         f = getTIFFField(BaselineTIFFTagSet.TAG_RESOLUTION_UNIT);
       
   556         int resolutionUnit = f != null ?
       
   557             f.getAsInt(0) : BaselineTIFFTagSet.RESOLUTION_UNIT_INCH;
       
   558         if(resolutionUnit == BaselineTIFFTagSet.RESOLUTION_UNIT_INCH ||
       
   559            resolutionUnit == BaselineTIFFTagSet.RESOLUTION_UNIT_CENTIMETER) {
       
   560             f = getTIFFField(BaselineTIFFTagSet.TAG_X_POSITION);
       
   561             if(f != null) {
       
   562                 long[] xpos = f.getAsRational(0);
       
   563                 float xPosition = (float)xpos[0]/(float)xpos[1];
       
   564                 // Convert to millimeters.
       
   565                 if(resolutionUnit == BaselineTIFFTagSet.RESOLUTION_UNIT_INCH) {
       
   566                     xPosition *= 254F;
       
   567                 } else {
       
   568                     xPosition *= 10F;
       
   569                 }
       
   570                 node = new IIOMetadataNode("HorizontalPosition");
       
   571                 node.setAttribute("value",
       
   572                                   Float.toString(xPosition));
       
   573                 dimension_node.appendChild(node);
       
   574             }
       
   575 
       
   576             f = getTIFFField(BaselineTIFFTagSet.TAG_Y_POSITION);
       
   577             if(f != null) {
       
   578                 long[] ypos = f.getAsRational(0);
       
   579                 float yPosition = (float)ypos[0]/(float)ypos[1];
       
   580                 // Convert to millimeters.
       
   581                 if(resolutionUnit == BaselineTIFFTagSet.RESOLUTION_UNIT_INCH) {
       
   582                     yPosition *= 254F;
       
   583                 } else {
       
   584                     yPosition *= 10F;
       
   585                 }
       
   586                 node = new IIOMetadataNode("VerticalPosition");
       
   587                 node.setAttribute("value",
       
   588                                   Float.toString(yPosition));
       
   589                 dimension_node.appendChild(node);
       
   590             }
       
   591         }
       
   592 
       
   593         f = getTIFFField(BaselineTIFFTagSet.TAG_ORIENTATION);
       
   594         if (f != null) {
       
   595             int o = f.getAsInt(0);
       
   596             if (o >= 0 && o < orientationNames.length) {
       
   597                 node = new IIOMetadataNode("ImageOrientation");
       
   598                 node.setAttribute("value", orientationNames[o]);
       
   599                 dimension_node.appendChild(node);
       
   600             }
       
   601         }
       
   602 
       
   603         return dimension_node;
       
   604     }
       
   605 
       
   606     public IIOMetadataNode getStandardDocumentNode() {
       
   607         IIOMetadataNode document_node = new IIOMetadataNode("Document");
       
   608         IIOMetadataNode node = null; // scratch node
       
   609 
       
   610         TIFFField f;
       
   611 
       
   612         node = new IIOMetadataNode("FormatVersion");
       
   613         node.setAttribute("value", "6.0");
       
   614         document_node.appendChild(node);
       
   615 
       
   616         f = getTIFFField(BaselineTIFFTagSet.TAG_NEW_SUBFILE_TYPE);
       
   617         if(f != null) {
       
   618             int newSubFileType = f.getAsInt(0);
       
   619             String value = null;
       
   620             if((newSubFileType &
       
   621                 BaselineTIFFTagSet.NEW_SUBFILE_TYPE_TRANSPARENCY) != 0) {
       
   622                 value = "TransparencyMask";
       
   623             } else if((newSubFileType &
       
   624                        BaselineTIFFTagSet.NEW_SUBFILE_TYPE_REDUCED_RESOLUTION) != 0) {
       
   625                 value = "ReducedResolution";
       
   626             } else if((newSubFileType &
       
   627                        BaselineTIFFTagSet.NEW_SUBFILE_TYPE_SINGLE_PAGE) != 0) {
       
   628                 value = "SinglePage";
       
   629             }
       
   630             if(value != null) {
       
   631                 node = new IIOMetadataNode("SubimageInterpretation");
       
   632                 node.setAttribute("value", value);
       
   633                 document_node.appendChild(node);
       
   634             }
       
   635         }
       
   636 
       
   637         f = getTIFFField(BaselineTIFFTagSet.TAG_DATE_TIME);
       
   638         if (f != null) {
       
   639             String s = f.getAsString(0);
       
   640 
       
   641             // DateTime should be formatted as "YYYY:MM:DD hh:mm:ss".
       
   642             if(s.length() == 19) {
       
   643                 node = new IIOMetadataNode("ImageCreationTime");
       
   644 
       
   645                 // Files with incorrect DateTime format have been
       
   646                 // observed so anticipate an exception from substring()
       
   647                 // and only add the node if the format is presumably
       
   648                 // correct.
       
   649                 boolean appendNode;
       
   650                 try {
       
   651                     node.setAttribute("year", s.substring(0, 4));
       
   652                     node.setAttribute("month", s.substring(5, 7));
       
   653                     node.setAttribute("day", s.substring(8, 10));
       
   654                     node.setAttribute("hour", s.substring(11, 13));
       
   655                     node.setAttribute("minute", s.substring(14, 16));
       
   656                     node.setAttribute("second", s.substring(17, 19));
       
   657                     appendNode = true;
       
   658                 } catch(IndexOutOfBoundsException e) {
       
   659                     appendNode = false;
       
   660                 }
       
   661 
       
   662                 if(appendNode) {
       
   663                     document_node.appendChild(node);
       
   664                 }
       
   665             }
       
   666         }
       
   667 
       
   668         return document_node;
       
   669     }
       
   670 
       
   671     public IIOMetadataNode getStandardTextNode() {
       
   672         IIOMetadataNode text_node = null;
       
   673         IIOMetadataNode node = null; // scratch node
       
   674 
       
   675         TIFFField f;
       
   676 
       
   677         int[] textFieldTagNumbers = new int[] {
       
   678             BaselineTIFFTagSet.TAG_DOCUMENT_NAME,
       
   679             BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION,
       
   680             BaselineTIFFTagSet.TAG_MAKE,
       
   681             BaselineTIFFTagSet.TAG_MODEL,
       
   682             BaselineTIFFTagSet.TAG_PAGE_NAME,
       
   683             BaselineTIFFTagSet.TAG_SOFTWARE,
       
   684             BaselineTIFFTagSet.TAG_ARTIST,
       
   685             BaselineTIFFTagSet.TAG_HOST_COMPUTER,
       
   686             BaselineTIFFTagSet.TAG_INK_NAMES,
       
   687             BaselineTIFFTagSet.TAG_COPYRIGHT
       
   688         };
       
   689 
       
   690         for(int i = 0; i < textFieldTagNumbers.length; i++) {
       
   691             f = getTIFFField(textFieldTagNumbers[i]);
       
   692             if(f != null) {
       
   693                 String value = f.getAsString(0);
       
   694                 if(text_node == null) {
       
   695                     text_node = new IIOMetadataNode("Text");
       
   696                 }
       
   697                 node = new IIOMetadataNode("TextEntry");
       
   698                 node.setAttribute("keyword", f.getTag().getName());
       
   699                 node.setAttribute("value", value);
       
   700                 text_node.appendChild(node);
       
   701             }
       
   702         }
       
   703 
       
   704         return text_node;
       
   705     }
       
   706 
       
   707     public IIOMetadataNode getStandardTransparencyNode() {
       
   708         IIOMetadataNode transparency_node =
       
   709             new IIOMetadataNode("Transparency");
       
   710         IIOMetadataNode node = null; // scratch node
       
   711 
       
   712         TIFFField f;
       
   713 
       
   714         node = new IIOMetadataNode("Alpha");
       
   715         String value = "none";
       
   716 
       
   717         f = getTIFFField(BaselineTIFFTagSet.TAG_EXTRA_SAMPLES);
       
   718         if(f != null) {
       
   719             int[] extraSamples = f.getAsInts();
       
   720             for(int i = 0; i < extraSamples.length; i++) {
       
   721                 if(extraSamples[i] ==
       
   722                    BaselineTIFFTagSet.EXTRA_SAMPLES_ASSOCIATED_ALPHA) {
       
   723                     value = "premultiplied";
       
   724                     break;
       
   725                 } else if(extraSamples[i] ==
       
   726                           BaselineTIFFTagSet.EXTRA_SAMPLES_UNASSOCIATED_ALPHA) {
       
   727                     value = "nonpremultiplied";
       
   728                     break;
       
   729                 }
       
   730             }
       
   731         }
       
   732 
       
   733         node.setAttribute("value", value);
       
   734         transparency_node.appendChild(node);
       
   735 
       
   736         return transparency_node;
       
   737     }
       
   738 
       
   739     // Shorthand for throwing an IIOInvalidTreeException
       
   740     private static void fatal(Node node, String reason)
       
   741         throws IIOInvalidTreeException {
       
   742         throw new IIOInvalidTreeException(reason, node);
       
   743     }
       
   744 
       
   745     private int[] listToIntArray(String list) {
       
   746         StringTokenizer st = new StringTokenizer(list, " ");
       
   747         ArrayList<Integer> intList = new ArrayList<Integer>();
       
   748         while (st.hasMoreTokens()) {
       
   749             String nextInteger = st.nextToken();
       
   750             Integer nextInt = Integer.valueOf(nextInteger);
       
   751             intList.add(nextInt);
       
   752         }
       
   753 
       
   754         int[] intArray = new int[intList.size()];
       
   755         for(int i = 0; i < intArray.length; i++) {
       
   756             intArray[i] = intList.get(i);
       
   757         }
       
   758 
       
   759         return intArray;
       
   760     }
       
   761 
       
   762     private char[] listToCharArray(String list) {
       
   763         StringTokenizer st = new StringTokenizer(list, " ");
       
   764         ArrayList<Integer> intList = new ArrayList<Integer>();
       
   765         while (st.hasMoreTokens()) {
       
   766             String nextInteger = st.nextToken();
       
   767             Integer nextInt = Integer.valueOf(nextInteger);
       
   768             intList.add(nextInt);
       
   769         }
       
   770 
       
   771         char[] charArray = new char[intList.size()];
       
   772         for(int i = 0; i < charArray.length; i++) {
       
   773             charArray[i] = (char)(intList.get(i).intValue());
       
   774         }
       
   775 
       
   776         return charArray;
       
   777     }
       
   778 
       
   779     private void mergeStandardTree(Node root)
       
   780         throws IIOInvalidTreeException {
       
   781         TIFFField f;
       
   782         TIFFTag tag;
       
   783 
       
   784         Node node = root;
       
   785         if (!node.getNodeName()
       
   786             .equals(IIOMetadataFormatImpl.standardMetadataFormatName)) {
       
   787             fatal(node, "Root must be " +
       
   788                   IIOMetadataFormatImpl.standardMetadataFormatName);
       
   789         }
       
   790 
       
   791         // Obtain the sample format and set the palette flag if appropriate.
       
   792         String sampleFormat = null;
       
   793         Node dataNode = getChildNode(root, "Data");
       
   794         boolean isPaletteColor = false;
       
   795         if(dataNode != null) {
       
   796             Node sampleFormatNode = getChildNode(dataNode, "SampleFormat");
       
   797             if(sampleFormatNode != null) {
       
   798                 sampleFormat = getAttribute(sampleFormatNode, "value");
       
   799                 isPaletteColor = sampleFormat.equals("Index");
       
   800             }
       
   801         }
       
   802 
       
   803         // If palette flag not set check for palette.
       
   804         if(!isPaletteColor) {
       
   805             Node chromaNode = getChildNode(root, "Chroma");
       
   806             if(chromaNode != null &&
       
   807                getChildNode(chromaNode, "Palette") != null) {
       
   808                 isPaletteColor = true;
       
   809             }
       
   810         }
       
   811 
       
   812         node = node.getFirstChild();
       
   813         while (node != null) {
       
   814             String name = node.getNodeName();
       
   815 
       
   816             if (name.equals("Chroma")) {
       
   817                 String colorSpaceType = null;
       
   818                 String blackIsZero = null;
       
   819                 boolean gotPalette = false;
       
   820                 Node child = node.getFirstChild();
       
   821                 while (child != null) {
       
   822                     String childName = child.getNodeName();
       
   823                     if (childName.equals("ColorSpaceType")) {
       
   824                         colorSpaceType = getAttribute(child, "name");
       
   825                     } else if (childName.equals("NumChannels")) {
       
   826                         tag = rootIFD.getTag(BaselineTIFFTagSet.TAG_SAMPLES_PER_PIXEL);
       
   827                         int samplesPerPixel = isPaletteColor ?
       
   828                             1 : Integer.parseInt(getAttribute(child, "value"));
       
   829                         f = new TIFFField(tag, samplesPerPixel);
       
   830                         rootIFD.addTIFFField(f);
       
   831                     } else if (childName.equals("BlackIsZero")) {
       
   832                         blackIsZero = getAttribute(child, "value");
       
   833                     } else if (childName.equals("Palette")) {
       
   834                         Node entry = child.getFirstChild();
       
   835                         HashMap<Integer,char[]> palette = new HashMap<>();
       
   836                         int maxIndex = -1;
       
   837                         while(entry != null) {
       
   838                             String entryName = entry.getNodeName();
       
   839                             if(entryName.equals("PaletteEntry")) {
       
   840                                 String idx = getAttribute(entry, "index");
       
   841                                 int id = Integer.parseInt(idx);
       
   842                                 if(id > maxIndex) {
       
   843                                     maxIndex = id;
       
   844                                 }
       
   845                                 char red =
       
   846                                     (char)Integer.parseInt(getAttribute(entry,
       
   847                                                                         "red"));
       
   848                                 char green =
       
   849                                     (char)Integer.parseInt(getAttribute(entry,
       
   850                                                                         "green"));
       
   851                                 char blue =
       
   852                                     (char)Integer.parseInt(getAttribute(entry,
       
   853                                                                         "blue"));
       
   854                                 palette.put(Integer.valueOf(id),
       
   855                                             new char[] {red, green, blue});
       
   856 
       
   857                                 gotPalette = true;
       
   858                             }
       
   859                             entry = entry.getNextSibling();
       
   860                         }
       
   861 
       
   862                         if(gotPalette) {
       
   863                             int mapSize = maxIndex + 1;
       
   864                             int paletteLength = 3*mapSize;
       
   865                             char[] paletteEntries = new char[paletteLength];
       
   866                             Iterator<Map.Entry<Integer,char[]>> paletteIter
       
   867                                 = palette.entrySet().iterator();
       
   868                             while(paletteIter.hasNext()) {
       
   869                                 Map.Entry<Integer,char[]> paletteEntry
       
   870                                     = paletteIter.next();
       
   871                                 int index = paletteEntry.getKey();
       
   872                                 char[] rgb = paletteEntry.getValue();
       
   873                                 paletteEntries[index] =
       
   874                                     (char)((rgb[0]*65535)/255);
       
   875                                 paletteEntries[mapSize + index] =
       
   876                                     (char)((rgb[1]*65535)/255);
       
   877                                 paletteEntries[2*mapSize + index] =
       
   878                                     (char)((rgb[2]*65535)/255);
       
   879                             }
       
   880 
       
   881                             tag = rootIFD.getTag(BaselineTIFFTagSet.TAG_COLOR_MAP);
       
   882                             f = new TIFFField(tag, TIFFTag.TIFF_SHORT,
       
   883                                               paletteLength, paletteEntries);
       
   884                             rootIFD.addTIFFField(f);
       
   885                         }
       
   886                     }
       
   887 
       
   888                     child = child.getNextSibling();
       
   889                 }
       
   890 
       
   891                 int photometricInterpretation = -1;
       
   892                 if((colorSpaceType == null || colorSpaceType.equals("GRAY")) &&
       
   893                    blackIsZero != null &&
       
   894                    blackIsZero.equalsIgnoreCase("FALSE")) {
       
   895                     photometricInterpretation =
       
   896                         BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO;
       
   897                 } else if(colorSpaceType != null) {
       
   898                     if(colorSpaceType.equals("GRAY")) {
       
   899                         boolean isTransparency = false;
       
   900                         if(root instanceof IIOMetadataNode) {
       
   901                             IIOMetadataNode iioRoot = (IIOMetadataNode)root;
       
   902                             NodeList siNodeList =
       
   903                                 iioRoot.getElementsByTagName("SubimageInterpretation");
       
   904                             if(siNodeList.getLength() == 1) {
       
   905                                 Node siNode = siNodeList.item(0);
       
   906                                 String value = getAttribute(siNode, "value");
       
   907                                 if(value.equals("TransparencyMask")) {
       
   908                                     isTransparency = true;
       
   909                                 }
       
   910                             }
       
   911                         }
       
   912                         if(isTransparency) {
       
   913                             photometricInterpretation =
       
   914                                 BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_TRANSPARENCY_MASK;
       
   915                         } else {
       
   916                             photometricInterpretation =
       
   917                                 BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO;
       
   918                         }
       
   919                     } else if(colorSpaceType.equals("RGB")) {
       
   920                         photometricInterpretation =
       
   921                             gotPalette ?
       
   922                             BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_PALETTE_COLOR :
       
   923                             BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_RGB;
       
   924                     } else if(colorSpaceType.equals("YCbCr")) {
       
   925                         photometricInterpretation =
       
   926                             BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_Y_CB_CR;
       
   927                     } else if(colorSpaceType.equals("CMYK")) {
       
   928                         photometricInterpretation =
       
   929                             BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_CMYK;
       
   930                     } else if(colorSpaceType.equals("Lab")) {
       
   931                         photometricInterpretation =
       
   932                             BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_CIELAB;
       
   933                     }
       
   934                 }
       
   935 
       
   936                 if(photometricInterpretation != -1) {
       
   937                     tag = rootIFD.getTag(BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION);
       
   938                     f = new TIFFField(tag, photometricInterpretation);
       
   939                     rootIFD.addTIFFField(f);
       
   940                 }
       
   941             } else if (name.equals("Compression")) {
       
   942                 Node child = node.getFirstChild();
       
   943                 while (child != null) {
       
   944                     String childName = child.getNodeName();
       
   945                     if (childName.equals("CompressionTypeName")) {
       
   946                         int compression = -1;
       
   947                         String compressionTypeName =
       
   948                             getAttribute(child, "value");
       
   949                         if(compressionTypeName.equalsIgnoreCase("None")) {
       
   950                             compression =
       
   951                                 BaselineTIFFTagSet.COMPRESSION_NONE;
       
   952                         } else {
       
   953                             String[] compressionNames =
       
   954                                 TIFFImageWriter.compressionTypes;
       
   955                             for(int i = 0; i < compressionNames.length; i++) {
       
   956                                 if(compressionNames[i].equalsIgnoreCase(compressionTypeName)) {
       
   957                                     compression =
       
   958                                         TIFFImageWriter.compressionNumbers[i];
       
   959                                     break;
       
   960                                 }
       
   961                             }
       
   962                         }
       
   963 
       
   964                         if(compression != -1) {
       
   965                             tag = rootIFD.getTag(BaselineTIFFTagSet.TAG_COMPRESSION);
       
   966                             f = new TIFFField(tag, compression);
       
   967                             rootIFD.addTIFFField(f);
       
   968 
       
   969                             // Lossless is irrelevant.
       
   970                         }
       
   971                     }
       
   972 
       
   973                     child = child.getNextSibling();
       
   974                 }
       
   975             } else if (name.equals("Data")) {
       
   976                 Node child = node.getFirstChild();
       
   977                 while (child != null) {
       
   978                     String childName = child.getNodeName();
       
   979 
       
   980                     if (childName.equals("PlanarConfiguration")) {
       
   981                         String pc = getAttribute(child, "value");
       
   982                         int planarConfiguration = -1;
       
   983                         if(pc.equals("PixelInterleaved")) {
       
   984                             planarConfiguration =
       
   985                                 BaselineTIFFTagSet.PLANAR_CONFIGURATION_CHUNKY;
       
   986                         } else if(pc.equals("PlaneInterleaved")) {
       
   987                             planarConfiguration =
       
   988                                 BaselineTIFFTagSet.PLANAR_CONFIGURATION_PLANAR;
       
   989                         }
       
   990                         if(planarConfiguration != -1) {
       
   991                             tag = rootIFD.getTag(BaselineTIFFTagSet.TAG_PLANAR_CONFIGURATION);
       
   992                             f = new TIFFField(tag, planarConfiguration);
       
   993                             rootIFD.addTIFFField(f);
       
   994                         }
       
   995                     } else if (childName.equals("BitsPerSample")) {
       
   996                         String bps = getAttribute(child, "value");
       
   997                         char[] bitsPerSample = listToCharArray(bps);
       
   998                         tag = rootIFD.getTag(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE);
       
   999                         if(isPaletteColor) {
       
  1000                             f = new TIFFField(tag, TIFFTag.TIFF_SHORT, 1,
       
  1001                                               new char[] {bitsPerSample[0]});
       
  1002                         } else {
       
  1003                             f = new TIFFField(tag, TIFFTag.TIFF_SHORT,
       
  1004                                               bitsPerSample.length,
       
  1005                                               bitsPerSample);
       
  1006                         }
       
  1007                         rootIFD.addTIFFField(f);
       
  1008                     } else if (childName.equals("SampleMSB")) {
       
  1009                         // Add FillOrder only if lsb-to-msb (right to left)
       
  1010                         // for all bands, i.e., SampleMSB is zero for all
       
  1011                         // channels.
       
  1012                         String sMSB = getAttribute(child, "value");
       
  1013                         int[] sampleMSB = listToIntArray(sMSB);
       
  1014                         boolean isRightToLeft = true;
       
  1015                         for(int i = 0; i < sampleMSB.length; i++) {
       
  1016                             if(sampleMSB[i] != 0) {
       
  1017                                 isRightToLeft = false;
       
  1018                                 break;
       
  1019                             }
       
  1020                         }
       
  1021                         int fillOrder = isRightToLeft ?
       
  1022                             BaselineTIFFTagSet.FILL_ORDER_RIGHT_TO_LEFT :
       
  1023                             BaselineTIFFTagSet.FILL_ORDER_LEFT_TO_RIGHT;
       
  1024                         tag =
       
  1025                             rootIFD.getTag(BaselineTIFFTagSet.TAG_FILL_ORDER);
       
  1026                         f = new TIFFField(tag, fillOrder);
       
  1027                         rootIFD.addTIFFField(f);
       
  1028                     }
       
  1029 
       
  1030                     child = child.getNextSibling();
       
  1031                 }
       
  1032             } else if (name.equals("Dimension")) {
       
  1033                 float pixelAspectRatio = -1.0f;
       
  1034                 boolean gotPixelAspectRatio = false;
       
  1035 
       
  1036                 float horizontalPixelSize = -1.0f;
       
  1037                 boolean gotHorizontalPixelSize = false;
       
  1038 
       
  1039                 float verticalPixelSize = -1.0f;
       
  1040                 boolean gotVerticalPixelSize = false;
       
  1041 
       
  1042                 boolean sizeIsAbsolute = false;
       
  1043 
       
  1044                 float horizontalPosition = -1.0f;
       
  1045                 boolean gotHorizontalPosition = false;
       
  1046 
       
  1047                 float verticalPosition = -1.0f;
       
  1048                 boolean gotVerticalPosition = false;
       
  1049 
       
  1050                 Node child = node.getFirstChild();
       
  1051                 while (child != null) {
       
  1052                     String childName = child.getNodeName();
       
  1053                     if (childName.equals("PixelAspectRatio")) {
       
  1054                         String par = getAttribute(child, "value");
       
  1055                         pixelAspectRatio = Float.parseFloat(par);
       
  1056                         gotPixelAspectRatio = true;
       
  1057                     } else if (childName.equals("ImageOrientation")) {
       
  1058                         String orientation = getAttribute(child, "value");
       
  1059                         for (int i = 0; i < orientationNames.length; i++) {
       
  1060                             if (orientation.equals(orientationNames[i])) {
       
  1061                                 char[] oData = new char[1];
       
  1062                                 oData[0] = (char)i;
       
  1063 
       
  1064                                 f = new TIFFField(
       
  1065                             rootIFD.getTag(BaselineTIFFTagSet.TAG_ORIENTATION),
       
  1066                             TIFFTag.TIFF_SHORT,
       
  1067                             1,
       
  1068                             oData);
       
  1069 
       
  1070                                 rootIFD.addTIFFField(f);
       
  1071                                 break;
       
  1072                             }
       
  1073                         }
       
  1074 
       
  1075                     } else if (childName.equals("HorizontalPixelSize")) {
       
  1076                         String hps = getAttribute(child, "value");
       
  1077                         horizontalPixelSize = Float.parseFloat(hps);
       
  1078                         gotHorizontalPixelSize = true;
       
  1079                     } else if (childName.equals("VerticalPixelSize")) {
       
  1080                         String vps = getAttribute(child, "value");
       
  1081                         verticalPixelSize = Float.parseFloat(vps);
       
  1082                         gotVerticalPixelSize = true;
       
  1083                     } else if (childName.equals("HorizontalPosition")) {
       
  1084                         String hp = getAttribute(child, "value");
       
  1085                         horizontalPosition = Float.parseFloat(hp);
       
  1086                         gotHorizontalPosition = true;
       
  1087                     } else if (childName.equals("VerticalPosition")) {
       
  1088                         String vp = getAttribute(child, "value");
       
  1089                         verticalPosition = Float.parseFloat(vp);
       
  1090                         gotVerticalPosition = true;
       
  1091                     }
       
  1092 
       
  1093                     child = child.getNextSibling();
       
  1094                 }
       
  1095 
       
  1096                 sizeIsAbsolute = gotHorizontalPixelSize ||
       
  1097                     gotVerticalPixelSize;
       
  1098 
       
  1099                 // Fill in pixel size data from aspect ratio
       
  1100                 if (gotPixelAspectRatio) {
       
  1101                     if (gotHorizontalPixelSize && !gotVerticalPixelSize) {
       
  1102                         verticalPixelSize =
       
  1103                             horizontalPixelSize/pixelAspectRatio;
       
  1104                         gotVerticalPixelSize = true;
       
  1105                     } else if (gotVerticalPixelSize &&
       
  1106                                !gotHorizontalPixelSize) {
       
  1107                         horizontalPixelSize =
       
  1108                             verticalPixelSize*pixelAspectRatio;
       
  1109                         gotHorizontalPixelSize = true;
       
  1110                     } else if (!gotHorizontalPixelSize &&
       
  1111                                !gotVerticalPixelSize) {
       
  1112                         horizontalPixelSize = pixelAspectRatio;
       
  1113                         verticalPixelSize = 1.0f;
       
  1114                         gotHorizontalPixelSize = true;
       
  1115                         gotVerticalPixelSize = true;
       
  1116                     }
       
  1117                 }
       
  1118 
       
  1119                 // Compute pixels/centimeter
       
  1120                 if (gotHorizontalPixelSize) {
       
  1121                     float xResolution =
       
  1122                         (sizeIsAbsolute ? 10.0f : 1.0f)/horizontalPixelSize;
       
  1123                     long[][] hData = new long[1][2];
       
  1124                     hData[0] = new long[2];
       
  1125                     hData[0][0] = (long)(xResolution*10000.0f);
       
  1126                     hData[0][1] = (long)10000;
       
  1127 
       
  1128                     f = new TIFFField(
       
  1129                            rootIFD.getTag(BaselineTIFFTagSet.TAG_X_RESOLUTION),
       
  1130                            TIFFTag.TIFF_RATIONAL,
       
  1131                            1,
       
  1132                            hData);
       
  1133                     rootIFD.addTIFFField(f);
       
  1134                 }
       
  1135 
       
  1136                 if (gotVerticalPixelSize) {
       
  1137                     float yResolution =
       
  1138                         (sizeIsAbsolute ? 10.0f : 1.0f)/verticalPixelSize;
       
  1139                     long[][] vData = new long[1][2];
       
  1140                     vData[0] = new long[2];
       
  1141                     vData[0][0] = (long)(yResolution*10000.0f);
       
  1142                     vData[0][1] = (long)10000;
       
  1143 
       
  1144                     f = new TIFFField(
       
  1145                            rootIFD.getTag(BaselineTIFFTagSet.TAG_Y_RESOLUTION),
       
  1146                            TIFFTag.TIFF_RATIONAL,
       
  1147                            1,
       
  1148                            vData);
       
  1149                     rootIFD.addTIFFField(f);
       
  1150                 }
       
  1151 
       
  1152                 // Emit ResolutionUnit tag
       
  1153                 char[] res = new char[1];
       
  1154                 res[0] = (char)(sizeIsAbsolute ?
       
  1155                                 BaselineTIFFTagSet.RESOLUTION_UNIT_CENTIMETER :
       
  1156                                 BaselineTIFFTagSet.RESOLUTION_UNIT_NONE);
       
  1157 
       
  1158                 f = new TIFFField(
       
  1159                         rootIFD.getTag(BaselineTIFFTagSet.TAG_RESOLUTION_UNIT),
       
  1160                         TIFFTag.TIFF_SHORT,
       
  1161                         1,
       
  1162                         res);
       
  1163                 rootIFD.addTIFFField(f);
       
  1164 
       
  1165                 // Position
       
  1166                 if(sizeIsAbsolute) {
       
  1167                     if(gotHorizontalPosition) {
       
  1168                         // Convert from millimeters to centimeters via
       
  1169                         // numerator multiplier = denominator/10.
       
  1170                         long[][] hData = new long[1][2];
       
  1171                         hData[0][0] = (long)(horizontalPosition*10000.0f);
       
  1172                         hData[0][1] = (long)100000;
       
  1173 
       
  1174                         f = new TIFFField(
       
  1175                            rootIFD.getTag(BaselineTIFFTagSet.TAG_X_POSITION),
       
  1176                            TIFFTag.TIFF_RATIONAL,
       
  1177                            1,
       
  1178                            hData);
       
  1179                         rootIFD.addTIFFField(f);
       
  1180                     }
       
  1181 
       
  1182                     if(gotVerticalPosition) {
       
  1183                         // Convert from millimeters to centimeters via
       
  1184                         // numerator multiplier = denominator/10.
       
  1185                         long[][] vData = new long[1][2];
       
  1186                         vData[0][0] = (long)(verticalPosition*10000.0f);
       
  1187                         vData[0][1] = (long)100000;
       
  1188 
       
  1189                         f = new TIFFField(
       
  1190                            rootIFD.getTag(BaselineTIFFTagSet.TAG_Y_POSITION),
       
  1191                            TIFFTag.TIFF_RATIONAL,
       
  1192                            1,
       
  1193                            vData);
       
  1194                         rootIFD.addTIFFField(f);
       
  1195                     }
       
  1196                 }
       
  1197             } else if (name.equals("Document")) {
       
  1198                 Node child = node.getFirstChild();
       
  1199                 while (child != null) {
       
  1200                     String childName = child.getNodeName();
       
  1201 
       
  1202                     if (childName.equals("SubimageInterpretation")) {
       
  1203                         String si = getAttribute(child, "value");
       
  1204                         int newSubFileType = -1;
       
  1205                         if(si.equals("TransparencyMask")) {
       
  1206                             newSubFileType =
       
  1207                                 BaselineTIFFTagSet.NEW_SUBFILE_TYPE_TRANSPARENCY;
       
  1208                         } else if(si.equals("ReducedResolution")) {
       
  1209                             newSubFileType =
       
  1210                                 BaselineTIFFTagSet.NEW_SUBFILE_TYPE_REDUCED_RESOLUTION;
       
  1211                         } else if(si.equals("SinglePage")) {
       
  1212                             newSubFileType =
       
  1213                                 BaselineTIFFTagSet.NEW_SUBFILE_TYPE_SINGLE_PAGE;
       
  1214                         }
       
  1215                         if(newSubFileType != -1) {
       
  1216                             tag =
       
  1217                                 rootIFD.getTag(BaselineTIFFTagSet.TAG_NEW_SUBFILE_TYPE);
       
  1218                             f = new TIFFField(tag, newSubFileType);
       
  1219                             rootIFD.addTIFFField(f);
       
  1220                         }
       
  1221                     }
       
  1222 
       
  1223                     if (childName.equals("ImageCreationTime")) {
       
  1224                         String year = getAttribute(child, "year");
       
  1225                         String month = getAttribute(child, "month");
       
  1226                         String day = getAttribute(child, "day");
       
  1227                         String hour = getAttribute(child, "hour");
       
  1228                         String minute = getAttribute(child, "minute");
       
  1229                         String second = getAttribute(child, "second");
       
  1230 
       
  1231                         StringBuffer sb = new StringBuffer();
       
  1232                         sb.append(year);
       
  1233                         sb.append(":");
       
  1234                         if(month.length() == 1) {
       
  1235                             sb.append("0");
       
  1236                         }
       
  1237                         sb.append(month);
       
  1238                         sb.append(":");
       
  1239                         if(day.length() == 1) {
       
  1240                             sb.append("0");
       
  1241                         }
       
  1242                         sb.append(day);
       
  1243                         sb.append(" ");
       
  1244                         if(hour.length() == 1) {
       
  1245                             sb.append("0");
       
  1246                         }
       
  1247                         sb.append(hour);
       
  1248                         sb.append(":");
       
  1249                         if(minute.length() == 1) {
       
  1250                             sb.append("0");
       
  1251                         }
       
  1252                         sb.append(minute);
       
  1253                         sb.append(":");
       
  1254                         if(second.length() == 1) {
       
  1255                             sb.append("0");
       
  1256                         }
       
  1257                         sb.append(second);
       
  1258 
       
  1259                         String[] dt = new String[1];
       
  1260                         dt[0] = sb.toString();
       
  1261 
       
  1262                         f = new TIFFField(
       
  1263                               rootIFD.getTag(BaselineTIFFTagSet.TAG_DATE_TIME),
       
  1264                               TIFFTag.TIFF_ASCII,
       
  1265                               1,
       
  1266                               dt);
       
  1267                         rootIFD.addTIFFField(f);
       
  1268                     }
       
  1269 
       
  1270                     child = child.getNextSibling();
       
  1271                 }
       
  1272             } else if (name.equals("Text")) {
       
  1273                 Node child = node.getFirstChild();
       
  1274                 String theAuthor = null;
       
  1275                 String theDescription = null;
       
  1276                 String theTitle = null;
       
  1277                 while (child != null) {
       
  1278                     String childName = child.getNodeName();
       
  1279                     if(childName.equals("TextEntry")) {
       
  1280                         int tagNumber = -1;
       
  1281                         NamedNodeMap childAttrs = child.getAttributes();
       
  1282                         Node keywordNode = childAttrs.getNamedItem("keyword");
       
  1283                         if(keywordNode != null) {
       
  1284                             String keyword = keywordNode.getNodeValue();
       
  1285                             String value = getAttribute(child, "value");
       
  1286                             if(!keyword.equals("") && !value.equals("")) {
       
  1287                                 if(keyword.equalsIgnoreCase("DocumentName")) {
       
  1288                                     tagNumber =
       
  1289                                         BaselineTIFFTagSet.TAG_DOCUMENT_NAME;
       
  1290                                 } else if(keyword.equalsIgnoreCase("ImageDescription")) {
       
  1291                                     tagNumber =
       
  1292                                         BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION;
       
  1293                                 } else if(keyword.equalsIgnoreCase("Make")) {
       
  1294                                     tagNumber =
       
  1295                                         BaselineTIFFTagSet.TAG_MAKE;
       
  1296                                 } else if(keyword.equalsIgnoreCase("Model")) {
       
  1297                                     tagNumber =
       
  1298                                         BaselineTIFFTagSet.TAG_MODEL;
       
  1299                                 } else if(keyword.equalsIgnoreCase("PageName")) {
       
  1300                                     tagNumber =
       
  1301                                         BaselineTIFFTagSet.TAG_PAGE_NAME;
       
  1302                                 } else if(keyword.equalsIgnoreCase("Software")) {
       
  1303                                     tagNumber =
       
  1304                                         BaselineTIFFTagSet.TAG_SOFTWARE;
       
  1305                                 } else if(keyword.equalsIgnoreCase("Artist")) {
       
  1306                                     tagNumber =
       
  1307                                         BaselineTIFFTagSet.TAG_ARTIST;
       
  1308                                 } else if(keyword.equalsIgnoreCase("HostComputer")) {
       
  1309                                     tagNumber =
       
  1310                                         BaselineTIFFTagSet.TAG_HOST_COMPUTER;
       
  1311                                 } else if(keyword.equalsIgnoreCase("InkNames")) {
       
  1312                                     tagNumber =
       
  1313                                         BaselineTIFFTagSet.TAG_INK_NAMES;
       
  1314                                 } else if(keyword.equalsIgnoreCase("Copyright")) {
       
  1315                                     tagNumber =
       
  1316                                         BaselineTIFFTagSet.TAG_COPYRIGHT;
       
  1317                                 } else if(keyword.equalsIgnoreCase("author")) {
       
  1318                                     theAuthor = value;
       
  1319                                 } else if(keyword.equalsIgnoreCase("description")) {
       
  1320                                     theDescription = value;
       
  1321                                 } else if(keyword.equalsIgnoreCase("title")) {
       
  1322                                     theTitle = value;
       
  1323                                 }
       
  1324                                 if(tagNumber != -1) {
       
  1325                                     f = new TIFFField(rootIFD.getTag(tagNumber),
       
  1326                                                       TIFFTag.TIFF_ASCII,
       
  1327                                                       1,
       
  1328                                                       new String[] {value});
       
  1329                                     rootIFD.addTIFFField(f);
       
  1330                                 }
       
  1331                             }
       
  1332                         }
       
  1333                     }
       
  1334                     child = child.getNextSibling();
       
  1335                 } // child != null
       
  1336                 if(theAuthor != null &&
       
  1337                    getTIFFField(BaselineTIFFTagSet.TAG_ARTIST) == null) {
       
  1338                     f = new TIFFField(rootIFD.getTag(BaselineTIFFTagSet.TAG_ARTIST),
       
  1339                                       TIFFTag.TIFF_ASCII,
       
  1340                                       1,
       
  1341                                       new String[] {theAuthor});
       
  1342                     rootIFD.addTIFFField(f);
       
  1343                 }
       
  1344                 if(theDescription != null &&
       
  1345                    getTIFFField(BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION) == null) {
       
  1346                     f = new TIFFField(rootIFD.getTag(BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION),
       
  1347                                       TIFFTag.TIFF_ASCII,
       
  1348                                       1,
       
  1349                                       new String[] {theDescription});
       
  1350                     rootIFD.addTIFFField(f);
       
  1351                 }
       
  1352                 if(theTitle != null &&
       
  1353                    getTIFFField(BaselineTIFFTagSet.TAG_DOCUMENT_NAME) == null) {
       
  1354                     f = new TIFFField(rootIFD.getTag(BaselineTIFFTagSet.TAG_DOCUMENT_NAME),
       
  1355                                       TIFFTag.TIFF_ASCII,
       
  1356                                       1,
       
  1357                                       new String[] {theTitle});
       
  1358                     rootIFD.addTIFFField(f);
       
  1359                 }
       
  1360             } else if (name.equals("Transparency")) {
       
  1361                  Node child = node.getFirstChild();
       
  1362                  while (child != null) {
       
  1363                      String childName = child.getNodeName();
       
  1364 
       
  1365                      if (childName.equals("Alpha")) {
       
  1366                          String alpha = getAttribute(child, "value");
       
  1367 
       
  1368                          f = null;
       
  1369                          if (alpha.equals("premultiplied")) {
       
  1370                              f = new TIFFField(
       
  1371                           rootIFD.getTag(BaselineTIFFTagSet.TAG_EXTRA_SAMPLES),
       
  1372                           BaselineTIFFTagSet.EXTRA_SAMPLES_ASSOCIATED_ALPHA);
       
  1373                          } else if (alpha.equals("nonpremultiplied")) {
       
  1374                              f = new TIFFField(
       
  1375                           rootIFD.getTag(BaselineTIFFTagSet.TAG_EXTRA_SAMPLES),
       
  1376                           BaselineTIFFTagSet.EXTRA_SAMPLES_UNASSOCIATED_ALPHA);
       
  1377                          }
       
  1378                          if (f != null) {
       
  1379                              rootIFD.addTIFFField(f);
       
  1380                          }
       
  1381                      }
       
  1382 
       
  1383                     child = child.getNextSibling();
       
  1384                  }
       
  1385             }
       
  1386 
       
  1387             node = node.getNextSibling();
       
  1388         }
       
  1389 
       
  1390         // Set SampleFormat.
       
  1391         if(sampleFormat != null) {
       
  1392             // Derive the value.
       
  1393             int sf = -1;
       
  1394             if(sampleFormat.equals("SignedIntegral")) {
       
  1395                 sf = BaselineTIFFTagSet.SAMPLE_FORMAT_SIGNED_INTEGER;
       
  1396             } else if(sampleFormat.equals("UnsignedIntegral")) {
       
  1397                 sf = BaselineTIFFTagSet.SAMPLE_FORMAT_UNSIGNED_INTEGER;
       
  1398             } else if(sampleFormat.equals("Real")) {
       
  1399                 sf = BaselineTIFFTagSet.SAMPLE_FORMAT_FLOATING_POINT;
       
  1400             } else if(sampleFormat.equals("Index")) {
       
  1401                 sf = BaselineTIFFTagSet.SAMPLE_FORMAT_UNSIGNED_INTEGER;
       
  1402             }
       
  1403 
       
  1404             if(sf != -1) {
       
  1405                 // Derive the count.
       
  1406                 int count = 1;
       
  1407 
       
  1408                 // Try SamplesPerPixel first.
       
  1409                 f = getTIFFField(BaselineTIFFTagSet.TAG_SAMPLES_PER_PIXEL);
       
  1410                 if(f != null) {
       
  1411                     count = f.getAsInt(0);
       
  1412                 } else {
       
  1413                     // Try BitsPerSample.
       
  1414                     f = getTIFFField(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE);
       
  1415                     if(f != null) {
       
  1416                         count = f.getCount();
       
  1417                     }
       
  1418                 }
       
  1419 
       
  1420                 char[] sampleFormatArray = new char[count];
       
  1421                 Arrays.fill(sampleFormatArray, (char)sf);
       
  1422 
       
  1423                 // Add SampleFormat.
       
  1424                 tag = rootIFD.getTag(BaselineTIFFTagSet.TAG_SAMPLE_FORMAT);
       
  1425                 f = new TIFFField(tag, TIFFTag.TIFF_SHORT,
       
  1426                                   sampleFormatArray.length, sampleFormatArray);
       
  1427                 rootIFD.addTIFFField(f);
       
  1428             }
       
  1429         }
       
  1430     }
       
  1431 
       
  1432     private static String getAttribute(Node node, String attrName) {
       
  1433         NamedNodeMap attrs = node.getAttributes();
       
  1434         Node attr = attrs.getNamedItem(attrName);
       
  1435         return attr != null ? attr.getNodeValue() : null;
       
  1436     }
       
  1437 
       
  1438     private Node getChildNode(Node node, String childName) {
       
  1439         Node childNode = null;
       
  1440         if(node.hasChildNodes()) {
       
  1441             NodeList childNodes = node.getChildNodes();
       
  1442             int length = childNodes.getLength();
       
  1443             for(int i = 0; i < length; i++) {
       
  1444                 Node item = childNodes.item(i);
       
  1445                 if(item.getNodeName().equals(childName)) {
       
  1446                     childNode = item;
       
  1447                     break;
       
  1448                 }
       
  1449             }
       
  1450         }
       
  1451         return childNode;
       
  1452     }
       
  1453 
       
  1454     public static TIFFIFD parseIFD(Node node) throws IIOInvalidTreeException {
       
  1455         if (!node.getNodeName().equals("TIFFIFD")) {
       
  1456             fatal(node, "Expected \"TIFFIFD\" node");
       
  1457         }
       
  1458 
       
  1459         String tagSetNames = getAttribute(node, "tagSets");
       
  1460         List<TIFFTagSet> tagSets = new ArrayList<TIFFTagSet>(5);
       
  1461 
       
  1462         if (tagSetNames != null) {
       
  1463             StringTokenizer st = new StringTokenizer(tagSetNames, ",");
       
  1464             while (st.hasMoreTokens()) {
       
  1465                 String className = st.nextToken();
       
  1466 
       
  1467                 Object o = null;
       
  1468                 try {
       
  1469                     Class<?> setClass = Class.forName(className);
       
  1470                     Method getInstanceMethod =
       
  1471                         setClass.getMethod("getInstance", (Class[])null);
       
  1472                     o = getInstanceMethod.invoke(null, (Object[])null);
       
  1473                 } catch (NoSuchMethodException e) {
       
  1474                     throw new RuntimeException(e);
       
  1475                 } catch (IllegalAccessException e) {
       
  1476                     throw new RuntimeException(e);
       
  1477                 } catch (InvocationTargetException e) {
       
  1478                     throw new RuntimeException(e);
       
  1479                 } catch (ClassNotFoundException e) {
       
  1480                     throw new RuntimeException(e);
       
  1481                 }
       
  1482 
       
  1483                 if (!(o instanceof TIFFTagSet)) {
       
  1484                     fatal(node, "Specified tag set class \"" +
       
  1485                           className +
       
  1486                           "\" is not an instance of TIFFTagSet");
       
  1487                 } else {
       
  1488                     tagSets.add((TIFFTagSet)o);
       
  1489                 }
       
  1490             }
       
  1491         }
       
  1492 
       
  1493         TIFFIFD ifd = new TIFFIFD(tagSets);
       
  1494 
       
  1495         node = node.getFirstChild();
       
  1496         while (node != null) {
       
  1497             String name = node.getNodeName();
       
  1498 
       
  1499             TIFFField f = null;
       
  1500             if (name.equals("TIFFIFD")) {
       
  1501                 TIFFIFD subIFD = parseIFD(node);
       
  1502                 String parentTagName = getAttribute(node, "parentTagName");
       
  1503                 String parentTagNumber = getAttribute(node, "parentTagNumber");
       
  1504                 TIFFTag tag = null;
       
  1505                 if(parentTagName != null) {
       
  1506                     tag = TIFFIFD.getTag(parentTagName, tagSets);
       
  1507                 } else if(parentTagNumber != null) {
       
  1508                     int tagNumber = Integer.parseUnsignedInt(parentTagNumber);
       
  1509                     tag = TIFFIFD.getTag(tagNumber, tagSets);
       
  1510                 }
       
  1511 
       
  1512                 int type;
       
  1513                 if (tag == null) {
       
  1514                     type = TIFFTag.TIFF_LONG;
       
  1515                     tag = new TIFFTag(TIFFTag.UNKNOWN_TAG_NAME, 0, 1 << type);
       
  1516                 } else {
       
  1517                     if (tag.isDataTypeOK(TIFFTag.TIFF_IFD_POINTER)) {
       
  1518                         type = TIFFTag.TIFF_IFD_POINTER;
       
  1519                     } else if (tag.isDataTypeOK(TIFFTag.TIFF_LONG)) {
       
  1520                         type = TIFFTag.TIFF_LONG;
       
  1521                     } else {
       
  1522                         for (type = TIFFTag.MAX_DATATYPE;
       
  1523                             type >= TIFFTag.MIN_DATATYPE;
       
  1524                             type--) {
       
  1525                             if (tag.isDataTypeOK(type)) {
       
  1526                                 break;
       
  1527                             }
       
  1528                         }
       
  1529                     }
       
  1530                 }
       
  1531 
       
  1532                 f = new TIFFField(tag, type, 1L, subIFD);
       
  1533             } else if (name.equals("TIFFField")) {
       
  1534                 int number = Integer.parseInt(getAttribute(node, "number"));
       
  1535 
       
  1536                 TIFFTagSet tagSet = null;
       
  1537                 Iterator<TIFFTagSet> iter = tagSets.iterator();
       
  1538                 while (iter.hasNext()) {
       
  1539                     TIFFTagSet t = iter.next();
       
  1540                     if (t.getTag(number) != null) {
       
  1541                         tagSet = t;
       
  1542                         break;
       
  1543                     }
       
  1544                 }
       
  1545 
       
  1546                 f = TIFFField.createFromMetadataNode(tagSet, node);
       
  1547             } else {
       
  1548                 fatal(node,
       
  1549                       "Expected either \"TIFFIFD\" or \"TIFFField\" node, got "
       
  1550                       + name);
       
  1551             }
       
  1552 
       
  1553             ifd.addTIFFField(f);
       
  1554             node = node.getNextSibling();
       
  1555         }
       
  1556 
       
  1557         return ifd;
       
  1558     }
       
  1559 
       
  1560     private void mergeNativeTree(Node root) throws IIOInvalidTreeException {
       
  1561         Node node = root;
       
  1562         if (!node.getNodeName().equals(nativeMetadataFormatName)) {
       
  1563             fatal(node, "Root must be " + nativeMetadataFormatName);
       
  1564         }
       
  1565 
       
  1566         node = node.getFirstChild();
       
  1567         if (node == null || !node.getNodeName().equals("TIFFIFD")) {
       
  1568             fatal(root, "Root must have \"TIFFIFD\" child");
       
  1569         }
       
  1570         TIFFIFD ifd = parseIFD(node);
       
  1571 
       
  1572         List<TIFFTagSet> rootIFDTagSets = rootIFD.getTagSetList();
       
  1573         Iterator<TIFFTagSet> tagSetIter = ifd.getTagSetList().iterator();
       
  1574         while(tagSetIter.hasNext()) {
       
  1575             Object o = tagSetIter.next();
       
  1576             if(o instanceof TIFFTagSet && !rootIFDTagSets.contains(o)) {
       
  1577                 rootIFD.addTagSet((TIFFTagSet)o);
       
  1578             }
       
  1579         }
       
  1580 
       
  1581         Iterator<TIFFField> ifdIter = ifd.iterator();
       
  1582         while(ifdIter.hasNext()) {
       
  1583             TIFFField field = ifdIter.next();
       
  1584             rootIFD.addTIFFField(field);
       
  1585         }
       
  1586     }
       
  1587 
       
  1588     public void mergeTree(String formatName, Node root)
       
  1589         throws IIOInvalidTreeException{
       
  1590         if (formatName.equals(nativeMetadataFormatName)) {
       
  1591             if (root == null) {
       
  1592                 throw new NullPointerException("root == null!");
       
  1593             }
       
  1594             mergeNativeTree(root);
       
  1595         } else if (formatName.equals
       
  1596                    (IIOMetadataFormatImpl.standardMetadataFormatName)) {
       
  1597             if (root == null) {
       
  1598                 throw new NullPointerException("root == null!");
       
  1599             }
       
  1600             mergeStandardTree(root);
       
  1601         } else {
       
  1602             throw new IllegalArgumentException("Not a recognized format!");
       
  1603         }
       
  1604     }
       
  1605 
       
  1606     public void reset() {
       
  1607         rootIFD = new TIFFIFD(tagSets);
       
  1608     }
       
  1609 
       
  1610     public TIFFIFD getRootIFD() {
       
  1611         return rootIFD;
       
  1612     }
       
  1613 
       
  1614     public TIFFField getTIFFField(int tagNumber) {
       
  1615         return rootIFD.getTIFFField(tagNumber);
       
  1616     }
       
  1617 
       
  1618     public void removeTIFFField(int tagNumber) {
       
  1619         rootIFD.removeTIFFField(tagNumber);
       
  1620     }
       
  1621 
       
  1622     /**
       
  1623      * Returns a <code>TIFFImageMetadata</code> wherein all fields in the
       
  1624      * root IFD from the <code>BaselineTIFFTagSet</code> are copied by value
       
  1625      * and all other fields copied by reference.
       
  1626      */
       
  1627     public TIFFImageMetadata getShallowClone() {
       
  1628         return new TIFFImageMetadata(rootIFD.getShallowClone());
       
  1629     }
       
  1630 }