| /* |
| * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| package com.sun.imageio.plugins.tiff; |
| |
| import java.io.IOException; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.StringTokenizer; |
| import javax.imageio.metadata.IIOMetadata; |
| import javax.imageio.metadata.IIOInvalidTreeException; |
| import javax.imageio.metadata.IIOMetadataFormatImpl; |
| import javax.imageio.metadata.IIOMetadataNode; |
| import javax.imageio.stream.ImageInputStream; |
| import org.w3c.dom.NamedNodeMap; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NodeList; |
| import javax.imageio.plugins.tiff.BaselineTIFFTagSet; |
| import javax.imageio.plugins.tiff.ExifParentTIFFTagSet; |
| import javax.imageio.plugins.tiff.TIFFField; |
| import javax.imageio.plugins.tiff.TIFFTag; |
| import javax.imageio.plugins.tiff.TIFFTagSet; |
| |
| public class TIFFImageMetadata extends IIOMetadata { |
| |
| // package scope |
| |
| public static final String NATIVE_METADATA_FORMAT_NAME = |
| "javax_imageio_tiff_image_1.0"; |
| |
| public static final String NATIVE_METADATA_FORMAT_CLASS_NAME = |
| "javax.imageio.plugins.tiff.TIFFImageMetadataFormat"; |
| |
| private List<TIFFTagSet> tagSets; |
| |
| TIFFIFD rootIFD; |
| |
| public TIFFImageMetadata(List<TIFFTagSet> tagSets) { |
| super(true, |
| NATIVE_METADATA_FORMAT_NAME, |
| NATIVE_METADATA_FORMAT_CLASS_NAME, |
| null, null); |
| |
| this.tagSets = tagSets; |
| this.rootIFD = new TIFFIFD(tagSets); |
| } |
| |
| public TIFFImageMetadata(TIFFIFD ifd) { |
| super(true, |
| NATIVE_METADATA_FORMAT_NAME, |
| NATIVE_METADATA_FORMAT_CLASS_NAME, |
| null, null); |
| this.tagSets = ifd.getTagSetList(); |
| this.rootIFD = ifd; |
| } |
| |
| public void initializeFromStream(ImageInputStream stream, |
| boolean ignoreMetadata, |
| boolean readUnknownTags) |
| throws IOException { |
| rootIFD.initialize(stream, true, ignoreMetadata, readUnknownTags); |
| } |
| |
| public void addShortOrLongField(int tagNumber, long value) { |
| TIFFField field = new TIFFField(rootIFD.getTag(tagNumber), value); |
| rootIFD.addTIFFField(field); |
| } |
| |
| public boolean isReadOnly() { |
| return false; |
| } |
| |
| private Node getIFDAsTree(TIFFIFD ifd, |
| String parentTagName, int parentTagNumber) { |
| IIOMetadataNode IFDRoot = new IIOMetadataNode("TIFFIFD"); |
| if (parentTagNumber != 0) { |
| IFDRoot.setAttribute("parentTagNumber", |
| Integer.toString(parentTagNumber)); |
| } |
| if (parentTagName != null) { |
| IFDRoot.setAttribute("parentTagName", parentTagName); |
| } |
| |
| List<TIFFTagSet> tagSets = ifd.getTagSetList(); |
| if (tagSets.size() > 0) { |
| Iterator<TIFFTagSet> iter = tagSets.iterator(); |
| StringBuilder tagSetNames = new StringBuilder(); |
| while (iter.hasNext()) { |
| TIFFTagSet tagSet = iter.next(); |
| tagSetNames.append(tagSet.getClass().getName()); |
| if (iter.hasNext()) { |
| tagSetNames.append(","); |
| } |
| } |
| |
| IFDRoot.setAttribute("tagSets", tagSetNames.toString()); |
| } |
| |
| Iterator<TIFFField> iter = ifd.iterator(); |
| while (iter.hasNext()) { |
| TIFFField f = iter.next(); |
| int tagNumber = f.getTagNumber(); |
| TIFFTag tag = TIFFIFD.getTag(tagNumber, tagSets); |
| |
| Node node = null; |
| if (tag == null) { |
| node = f.getAsNativeNode(); |
| } else if (tag.isIFDPointer() && f.hasDirectory()) { |
| TIFFIFD subIFD = TIFFIFD.getDirectoryAsIFD(f.getDirectory()); |
| |
| // Recurse |
| node = getIFDAsTree(subIFD, tag.getName(), tag.getNumber()); |
| } else { |
| node = f.getAsNativeNode(); |
| } |
| |
| if (node != null) { |
| IFDRoot.appendChild(node); |
| } |
| } |
| |
| return IFDRoot; |
| } |
| |
| public Node getAsTree(String formatName) { |
| if (formatName.equals(nativeMetadataFormatName)) { |
| return getNativeTree(); |
| } else if (formatName.equals |
| (IIOMetadataFormatImpl.standardMetadataFormatName)) { |
| return getStandardTree(); |
| } else { |
| throw new IllegalArgumentException("Not a recognized format!"); |
| } |
| } |
| |
| private Node getNativeTree() { |
| IIOMetadataNode root = new IIOMetadataNode(nativeMetadataFormatName); |
| |
| Node IFDNode = getIFDAsTree(rootIFD, null, 0); |
| root.appendChild(IFDNode); |
| |
| return root; |
| } |
| |
| private static final String[] colorSpaceNames = { |
| "GRAY", // WhiteIsZero |
| "GRAY", // BlackIsZero |
| "RGB", // RGB |
| "RGB", // PaletteColor |
| "GRAY", // TransparencyMask |
| "CMYK", // CMYK |
| "YCbCr", // YCbCr |
| "Lab", // CIELab |
| "Lab", // ICCLab |
| }; |
| |
| public IIOMetadataNode getStandardChromaNode() { |
| IIOMetadataNode chroma_node = new IIOMetadataNode("Chroma"); |
| IIOMetadataNode node = null; // scratch node |
| |
| TIFFField f; |
| |
| // Set the PhotometricInterpretation and the palette color flag. |
| int photometricInterpretation = -1; |
| boolean isPaletteColor = false; |
| f = getTIFFField(BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION); |
| if (f != null) { |
| photometricInterpretation = f.getAsInt(0); |
| |
| isPaletteColor = |
| photometricInterpretation == |
| BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_PALETTE_COLOR; |
| } |
| |
| // Determine the number of channels. |
| int numChannels = -1; |
| if(isPaletteColor) { |
| numChannels = 3; |
| } else { |
| f = getTIFFField(BaselineTIFFTagSet.TAG_SAMPLES_PER_PIXEL); |
| if (f != null) { |
| numChannels = f.getAsInt(0); |
| } else { // f == null |
| f = getTIFFField(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE); |
| if(f != null) { |
| numChannels = f.getCount(); |
| } |
| } |
| } |
| |
| if(photometricInterpretation != -1) { |
| if (photometricInterpretation >= 0 && |
| photometricInterpretation < colorSpaceNames.length) { |
| node = new IIOMetadataNode("ColorSpaceType"); |
| String csName; |
| if(photometricInterpretation == |
| BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_CMYK && |
| numChannels == 3) { |
| csName = "CMY"; |
| } else { |
| csName = colorSpaceNames[photometricInterpretation]; |
| } |
| node.setAttribute("name", csName); |
| chroma_node.appendChild(node); |
| } |
| |
| node = new IIOMetadataNode("BlackIsZero"); |
| node.setAttribute("value", |
| (photometricInterpretation == |
| BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO) |
| ? "FALSE" : "TRUE"); |
| chroma_node.appendChild(node); |
| } |
| |
| if(numChannels != -1) { |
| node = new IIOMetadataNode("NumChannels"); |
| node.setAttribute("value", Integer.toString(numChannels)); |
| chroma_node.appendChild(node); |
| } |
| |
| f = getTIFFField(BaselineTIFFTagSet.TAG_COLOR_MAP); |
| if (f != null) { |
| // NOTE: The presence of hasAlpha is vestigial: there is |
| // no way in TIFF to represent an alpha component in a palette |
| // color image. See bug 5086341. |
| boolean hasAlpha = false; |
| |
| node = new IIOMetadataNode("Palette"); |
| int len = f.getCount()/(hasAlpha ? 4 : 3); |
| for (int i = 0; i < len; i++) { |
| IIOMetadataNode entry = |
| new IIOMetadataNode("PaletteEntry"); |
| entry.setAttribute("index", Integer.toString(i)); |
| |
| int r = (f.getAsInt(i)*255)/65535; |
| int g = (f.getAsInt(len + i)*255)/65535; |
| int b = (f.getAsInt(2*len + i)*255)/65535; |
| |
| entry.setAttribute("red", Integer.toString(r)); |
| entry.setAttribute("green", Integer.toString(g)); |
| entry.setAttribute("blue", Integer.toString(b)); |
| if (hasAlpha) { |
| int alpha = 0; |
| entry.setAttribute("alpha", Integer.toString(alpha)); |
| } |
| node.appendChild(entry); |
| } |
| chroma_node.appendChild(node); |
| } |
| |
| return chroma_node; |
| } |
| |
| public IIOMetadataNode getStandardCompressionNode() { |
| IIOMetadataNode compression_node = new IIOMetadataNode("Compression"); |
| IIOMetadataNode node = null; // scratch node |
| |
| TIFFField f; |
| |
| f = getTIFFField(BaselineTIFFTagSet.TAG_COMPRESSION); |
| if (f != null) { |
| String compressionTypeName = null; |
| int compression = f.getAsInt(0); |
| boolean isLossless = true; // obligate initialization. |
| if(compression == BaselineTIFFTagSet.COMPRESSION_NONE) { |
| compressionTypeName = "None"; |
| isLossless = true; |
| } else { |
| int[] compressionNumbers = TIFFImageWriter.compressionNumbers; |
| for(int i = 0; i < compressionNumbers.length; i++) { |
| if(compression == compressionNumbers[i]) { |
| compressionTypeName = |
| TIFFImageWriter.compressionTypes[i]; |
| isLossless = |
| TIFFImageWriter.isCompressionLossless[i]; |
| break; |
| } |
| } |
| } |
| |
| if (compressionTypeName != null) { |
| node = new IIOMetadataNode("CompressionTypeName"); |
| node.setAttribute("value", compressionTypeName); |
| compression_node.appendChild(node); |
| |
| node = new IIOMetadataNode("Lossless"); |
| node.setAttribute("value", isLossless ? "TRUE" : "FALSE"); |
| compression_node.appendChild(node); |
| } |
| } |
| |
| node = new IIOMetadataNode("NumProgressiveScans"); |
| node.setAttribute("value", "1"); |
| compression_node.appendChild(node); |
| |
| return compression_node; |
| } |
| |
| private String repeat(String s, int times) { |
| if (times == 1) { |
| return s; |
| } |
| StringBuffer sb = new StringBuffer((s.length() + 1)*times - 1); |
| sb.append(s); |
| for (int i = 1; i < times; i++) { |
| sb.append(" "); |
| sb.append(s); |
| } |
| return sb.toString(); |
| } |
| |
| public IIOMetadataNode getStandardDataNode() { |
| IIOMetadataNode data_node = new IIOMetadataNode("Data"); |
| IIOMetadataNode node = null; // scratch node |
| |
| TIFFField f; |
| |
| boolean isPaletteColor = false; |
| f = getTIFFField(BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION); |
| if (f != null) { |
| isPaletteColor = |
| f.getAsInt(0) == |
| BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_PALETTE_COLOR; |
| } |
| |
| f = getTIFFField(BaselineTIFFTagSet.TAG_PLANAR_CONFIGURATION); |
| String planarConfiguration = "PixelInterleaved"; |
| if (f != null && |
| f.getAsInt(0) == BaselineTIFFTagSet.PLANAR_CONFIGURATION_PLANAR) { |
| planarConfiguration = "PlaneInterleaved"; |
| } |
| |
| node = new IIOMetadataNode("PlanarConfiguration"); |
| node.setAttribute("value", planarConfiguration); |
| data_node.appendChild(node); |
| |
| f = getTIFFField(BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION); |
| if (f != null) { |
| int photometricInterpretation = f.getAsInt(0); |
| String sampleFormat = "UnsignedIntegral"; |
| |
| if (photometricInterpretation == |
| BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_PALETTE_COLOR) { |
| sampleFormat = "Index"; |
| } else { |
| f = getTIFFField(BaselineTIFFTagSet.TAG_SAMPLE_FORMAT); |
| if (f != null) { |
| int format = f.getAsInt(0); |
| if (format == |
| BaselineTIFFTagSet.SAMPLE_FORMAT_SIGNED_INTEGER) { |
| sampleFormat = "SignedIntegral"; |
| } else if (format == |
| BaselineTIFFTagSet.SAMPLE_FORMAT_UNSIGNED_INTEGER) { |
| sampleFormat = "UnsignedIntegral"; |
| } else if (format == |
| BaselineTIFFTagSet.SAMPLE_FORMAT_FLOATING_POINT) { |
| sampleFormat = "Real"; |
| } else { |
| sampleFormat = null; // don't know |
| } |
| } |
| } |
| if (sampleFormat != null) { |
| node = new IIOMetadataNode("SampleFormat"); |
| node.setAttribute("value", sampleFormat); |
| data_node.appendChild(node); |
| } |
| } |
| |
| f = getTIFFField(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE); |
| int[] bitsPerSample = null; |
| if(f != null) { |
| bitsPerSample = f.getAsInts(); |
| } else { |
| f = getTIFFField(BaselineTIFFTagSet.TAG_COMPRESSION); |
| int compression = f != null ? |
| f.getAsInt(0) : BaselineTIFFTagSet.COMPRESSION_NONE; |
| if(getTIFFField(ExifParentTIFFTagSet.TAG_EXIF_IFD_POINTER) != |
| null || |
| compression == BaselineTIFFTagSet.COMPRESSION_JPEG || |
| compression == BaselineTIFFTagSet.COMPRESSION_OLD_JPEG || |
| getTIFFField(BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT) != |
| null) { |
| f = getTIFFField(BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION); |
| if(f != null && |
| (f.getAsInt(0) == |
| BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO || |
| f.getAsInt(0) == |
| BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO)) { |
| bitsPerSample = new int[] {8}; |
| } else { |
| bitsPerSample = new int[] {8, 8, 8}; |
| } |
| } else { |
| bitsPerSample = new int[] {1}; |
| } |
| } |
| StringBuffer sb = new StringBuffer(); |
| for (int i = 0; i < bitsPerSample.length; i++) { |
| if (i > 0) { |
| sb.append(" "); |
| } |
| sb.append(Integer.toString(bitsPerSample[i])); |
| } |
| node = new IIOMetadataNode("BitsPerSample"); |
| if(isPaletteColor) { |
| node.setAttribute("value", repeat(sb.toString(), 3)); |
| } else { |
| node.setAttribute("value", sb.toString()); |
| } |
| data_node.appendChild(node); |
| |
| // SampleMSB |
| f = getTIFFField(BaselineTIFFTagSet.TAG_FILL_ORDER); |
| int fillOrder = f != null ? |
| f.getAsInt(0) : BaselineTIFFTagSet.FILL_ORDER_LEFT_TO_RIGHT; |
| sb = new StringBuffer(); |
| for (int i = 0; i < bitsPerSample.length; i++) { |
| if (i > 0) { |
| sb.append(" "); |
| } |
| int maxBitIndex = bitsPerSample[i] == 1 ? |
| 7 : bitsPerSample[i] - 1; |
| int msb = |
| fillOrder == BaselineTIFFTagSet.FILL_ORDER_LEFT_TO_RIGHT ? |
| maxBitIndex : 0; |
| sb.append(Integer.toString(msb)); |
| } |
| node = new IIOMetadataNode("SampleMSB"); |
| if(isPaletteColor) { |
| node.setAttribute("value", repeat(sb.toString(), 3)); |
| } else { |
| node.setAttribute("value", sb.toString()); |
| } |
| data_node.appendChild(node); |
| |
| return data_node; |
| } |
| |
| private static final String[] orientationNames = { |
| null, |
| "Normal", |
| "FlipH", |
| "Rotate180", |
| "FlipV", |
| "FlipHRotate90", |
| "Rotate270", |
| "FlipVRotate90", |
| "Rotate90", |
| }; |
| |
| public IIOMetadataNode getStandardDimensionNode() { |
| IIOMetadataNode dimension_node = new IIOMetadataNode("Dimension"); |
| IIOMetadataNode node = null; // scratch node |
| |
| TIFFField f; |
| |
| long[] xres = null; |
| long[] yres = null; |
| |
| f = getTIFFField(BaselineTIFFTagSet.TAG_X_RESOLUTION); |
| if (f != null) { |
| xres = f.getAsRational(0).clone(); |
| } |
| |
| f = getTIFFField(BaselineTIFFTagSet.TAG_Y_RESOLUTION); |
| if (f != null) { |
| yres = f.getAsRational(0).clone(); |
| } |
| |
| if (xres != null && yres != null) { |
| node = new IIOMetadataNode("PixelAspectRatio"); |
| |
| // Compute (1/xres)/(1/yres) |
| // (xres_denom/xres_num)/(yres_denom/yres_num) = |
| // (xres_denom/xres_num)*(yres_num/yres_denom) = |
| // (xres_denom*yres_num)/(xres_num*yres_denom) |
| float ratio = (float)((double)xres[1]*yres[0])/(xres[0]*yres[1]); |
| node.setAttribute("value", Float.toString(ratio)); |
| dimension_node.appendChild(node); |
| } |
| |
| if (xres != null || yres != null) { |
| // Get unit field. |
| f = getTIFFField(BaselineTIFFTagSet.TAG_RESOLUTION_UNIT); |
| |
| // Set resolution unit. |
| int resolutionUnit = f != null ? |
| f.getAsInt(0) : BaselineTIFFTagSet.RESOLUTION_UNIT_INCH; |
| |
| // Have size if either centimeters or inches. |
| boolean gotPixelSize = |
| resolutionUnit != BaselineTIFFTagSet.RESOLUTION_UNIT_NONE; |
| |
| // Convert pixels/inch to pixels/centimeter. |
| if (resolutionUnit == BaselineTIFFTagSet.RESOLUTION_UNIT_INCH) { |
| // Divide xres by 2.54 |
| if (xres != null) { |
| xres[0] *= 100; |
| xres[1] *= 254; |
| } |
| |
| // Divide yres by 2.54 |
| if (yres != null) { |
| yres[0] *= 100; |
| yres[1] *= 254; |
| } |
| } |
| |
| if (gotPixelSize) { |
| if (xres != null) { |
| float horizontalPixelSize = (float)(10.0*xres[1]/xres[0]); |
| node = new IIOMetadataNode("HorizontalPixelSize"); |
| node.setAttribute("value", |
| Float.toString(horizontalPixelSize)); |
| dimension_node.appendChild(node); |
| } |
| |
| if (yres != null) { |
| float verticalPixelSize = (float)(10.0*yres[1]/yres[0]); |
| node = new IIOMetadataNode("VerticalPixelSize"); |
| node.setAttribute("value", |
| Float.toString(verticalPixelSize)); |
| dimension_node.appendChild(node); |
| } |
| } |
| } |
| |
| f = getTIFFField(BaselineTIFFTagSet.TAG_RESOLUTION_UNIT); |
| int resolutionUnit = f != null ? |
| f.getAsInt(0) : BaselineTIFFTagSet.RESOLUTION_UNIT_INCH; |
| if(resolutionUnit == BaselineTIFFTagSet.RESOLUTION_UNIT_INCH || |
| resolutionUnit == BaselineTIFFTagSet.RESOLUTION_UNIT_CENTIMETER) { |
| f = getTIFFField(BaselineTIFFTagSet.TAG_X_POSITION); |
| if(f != null) { |
| long[] xpos = f.getAsRational(0); |
| float xPosition = (float)xpos[0]/(float)xpos[1]; |
| // Convert to millimeters. |
| if(resolutionUnit == BaselineTIFFTagSet.RESOLUTION_UNIT_INCH) { |
| xPosition *= 254F; |
| } else { |
| xPosition *= 10F; |
| } |
| node = new IIOMetadataNode("HorizontalPosition"); |
| node.setAttribute("value", |
| Float.toString(xPosition)); |
| dimension_node.appendChild(node); |
| } |
| |
| f = getTIFFField(BaselineTIFFTagSet.TAG_Y_POSITION); |
| if(f != null) { |
| long[] ypos = f.getAsRational(0); |
| float yPosition = (float)ypos[0]/(float)ypos[1]; |
| // Convert to millimeters. |
| if(resolutionUnit == BaselineTIFFTagSet.RESOLUTION_UNIT_INCH) { |
| yPosition *= 254F; |
| } else { |
| yPosition *= 10F; |
| } |
| node = new IIOMetadataNode("VerticalPosition"); |
| node.setAttribute("value", |
| Float.toString(yPosition)); |
| dimension_node.appendChild(node); |
| } |
| } |
| |
| f = getTIFFField(BaselineTIFFTagSet.TAG_ORIENTATION); |
| if (f != null) { |
| int o = f.getAsInt(0); |
| if (o >= 0 && o < orientationNames.length) { |
| node = new IIOMetadataNode("ImageOrientation"); |
| node.setAttribute("value", orientationNames[o]); |
| dimension_node.appendChild(node); |
| } |
| } |
| |
| return dimension_node; |
| } |
| |
| public IIOMetadataNode getStandardDocumentNode() { |
| IIOMetadataNode document_node = new IIOMetadataNode("Document"); |
| IIOMetadataNode node = null; // scratch node |
| |
| TIFFField f; |
| |
| node = new IIOMetadataNode("FormatVersion"); |
| node.setAttribute("value", "6.0"); |
| document_node.appendChild(node); |
| |
| f = getTIFFField(BaselineTIFFTagSet.TAG_NEW_SUBFILE_TYPE); |
| if(f != null) { |
| int newSubFileType = f.getAsInt(0); |
| String value = null; |
| if((newSubFileType & |
| BaselineTIFFTagSet.NEW_SUBFILE_TYPE_TRANSPARENCY) != 0) { |
| value = "TransparencyMask"; |
| } else if((newSubFileType & |
| BaselineTIFFTagSet.NEW_SUBFILE_TYPE_REDUCED_RESOLUTION) != 0) { |
| value = "ReducedResolution"; |
| } else if((newSubFileType & |
| BaselineTIFFTagSet.NEW_SUBFILE_TYPE_SINGLE_PAGE) != 0) { |
| value = "SinglePage"; |
| } |
| if(value != null) { |
| node = new IIOMetadataNode("SubimageInterpretation"); |
| node.setAttribute("value", value); |
| document_node.appendChild(node); |
| } |
| } |
| |
| f = getTIFFField(BaselineTIFFTagSet.TAG_DATE_TIME); |
| if (f != null) { |
| String s = f.getAsString(0); |
| |
| // DateTime should be formatted as "YYYY:MM:DD hh:mm:ss". |
| if(s.length() == 19) { |
| node = new IIOMetadataNode("ImageCreationTime"); |
| |
| // Files with incorrect DateTime format have been |
| // observed so anticipate an exception from substring() |
| // and only add the node if the format is presumably |
| // correct. |
| boolean appendNode; |
| try { |
| node.setAttribute("year", s.substring(0, 4)); |
| node.setAttribute("month", s.substring(5, 7)); |
| node.setAttribute("day", s.substring(8, 10)); |
| node.setAttribute("hour", s.substring(11, 13)); |
| node.setAttribute("minute", s.substring(14, 16)); |
| node.setAttribute("second", s.substring(17, 19)); |
| appendNode = true; |
| } catch(IndexOutOfBoundsException e) { |
| appendNode = false; |
| } |
| |
| if(appendNode) { |
| document_node.appendChild(node); |
| } |
| } |
| } |
| |
| return document_node; |
| } |
| |
| public IIOMetadataNode getStandardTextNode() { |
| IIOMetadataNode text_node = null; |
| IIOMetadataNode node = null; // scratch node |
| |
| TIFFField f; |
| |
| int[] textFieldTagNumbers = new int[] { |
| BaselineTIFFTagSet.TAG_DOCUMENT_NAME, |
| BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION, |
| BaselineTIFFTagSet.TAG_MAKE, |
| BaselineTIFFTagSet.TAG_MODEL, |
| BaselineTIFFTagSet.TAG_PAGE_NAME, |
| BaselineTIFFTagSet.TAG_SOFTWARE, |
| BaselineTIFFTagSet.TAG_ARTIST, |
| BaselineTIFFTagSet.TAG_HOST_COMPUTER, |
| BaselineTIFFTagSet.TAG_INK_NAMES, |
| BaselineTIFFTagSet.TAG_COPYRIGHT |
| }; |
| |
| for(int i = 0; i < textFieldTagNumbers.length; i++) { |
| f = getTIFFField(textFieldTagNumbers[i]); |
| if(f != null) { |
| String value = f.getAsString(0); |
| if(text_node == null) { |
| text_node = new IIOMetadataNode("Text"); |
| } |
| node = new IIOMetadataNode("TextEntry"); |
| node.setAttribute("keyword", f.getTag().getName()); |
| node.setAttribute("value", value); |
| text_node.appendChild(node); |
| } |
| } |
| |
| return text_node; |
| } |
| |
| public IIOMetadataNode getStandardTransparencyNode() { |
| IIOMetadataNode transparency_node = |
| new IIOMetadataNode("Transparency"); |
| IIOMetadataNode node = null; // scratch node |
| |
| TIFFField f; |
| |
| node = new IIOMetadataNode("Alpha"); |
| String value = "none"; |
| |
| f = getTIFFField(BaselineTIFFTagSet.TAG_EXTRA_SAMPLES); |
| if(f != null) { |
| int[] extraSamples = f.getAsInts(); |
| for(int i = 0; i < extraSamples.length; i++) { |
| if(extraSamples[i] == |
| BaselineTIFFTagSet.EXTRA_SAMPLES_ASSOCIATED_ALPHA) { |
| value = "premultiplied"; |
| break; |
| } else if(extraSamples[i] == |
| BaselineTIFFTagSet.EXTRA_SAMPLES_UNASSOCIATED_ALPHA) { |
| value = "nonpremultiplied"; |
| break; |
| } |
| } |
| } |
| |
| node.setAttribute("value", value); |
| transparency_node.appendChild(node); |
| |
| return transparency_node; |
| } |
| |
| // Shorthand for throwing an IIOInvalidTreeException |
| private static void fatal(Node node, String reason) |
| throws IIOInvalidTreeException { |
| throw new IIOInvalidTreeException(reason, node); |
| } |
| |
| private int[] listToIntArray(String list) { |
| StringTokenizer st = new StringTokenizer(list, " "); |
| ArrayList<Integer> intList = new ArrayList<Integer>(); |
| while (st.hasMoreTokens()) { |
| String nextInteger = st.nextToken(); |
| Integer nextInt = Integer.valueOf(nextInteger); |
| intList.add(nextInt); |
| } |
| |
| int[] intArray = new int[intList.size()]; |
| for(int i = 0; i < intArray.length; i++) { |
| intArray[i] = intList.get(i); |
| } |
| |
| return intArray; |
| } |
| |
| private char[] listToCharArray(String list) { |
| StringTokenizer st = new StringTokenizer(list, " "); |
| ArrayList<Integer> intList = new ArrayList<Integer>(); |
| while (st.hasMoreTokens()) { |
| String nextInteger = st.nextToken(); |
| Integer nextInt = Integer.valueOf(nextInteger); |
| intList.add(nextInt); |
| } |
| |
| char[] charArray = new char[intList.size()]; |
| for(int i = 0; i < charArray.length; i++) { |
| charArray[i] = (char)(intList.get(i).intValue()); |
| } |
| |
| return charArray; |
| } |
| |
| private void mergeStandardTree(Node root) |
| throws IIOInvalidTreeException { |
| TIFFField f; |
| TIFFTag tag; |
| |
| Node node = root; |
| if (!node.getNodeName() |
| .equals(IIOMetadataFormatImpl.standardMetadataFormatName)) { |
| fatal(node, "Root must be " + |
| IIOMetadataFormatImpl.standardMetadataFormatName); |
| } |
| |
| // Obtain the sample format and set the palette flag if appropriate. |
| String sampleFormat = null; |
| Node dataNode = getChildNode(root, "Data"); |
| boolean isPaletteColor = false; |
| if(dataNode != null) { |
| Node sampleFormatNode = getChildNode(dataNode, "SampleFormat"); |
| if(sampleFormatNode != null) { |
| sampleFormat = getAttribute(sampleFormatNode, "value"); |
| isPaletteColor = sampleFormat.equals("Index"); |
| } |
| } |
| |
| // If palette flag not set check for palette. |
| if(!isPaletteColor) { |
| Node chromaNode = getChildNode(root, "Chroma"); |
| if(chromaNode != null && |
| getChildNode(chromaNode, "Palette") != null) { |
| isPaletteColor = true; |
| } |
| } |
| |
| node = node.getFirstChild(); |
| while (node != null) { |
| String name = node.getNodeName(); |
| |
| if (name.equals("Chroma")) { |
| String colorSpaceType = null; |
| String blackIsZero = null; |
| boolean gotPalette = false; |
| Node child = node.getFirstChild(); |
| while (child != null) { |
| String childName = child.getNodeName(); |
| if (childName.equals("ColorSpaceType")) { |
| colorSpaceType = getAttribute(child, "name"); |
| } else if (childName.equals("NumChannels")) { |
| tag = rootIFD.getTag(BaselineTIFFTagSet.TAG_SAMPLES_PER_PIXEL); |
| int samplesPerPixel = isPaletteColor ? |
| 1 : Integer.parseInt(getAttribute(child, "value")); |
| f = new TIFFField(tag, samplesPerPixel); |
| rootIFD.addTIFFField(f); |
| } else if (childName.equals("BlackIsZero")) { |
| blackIsZero = getAttribute(child, "value"); |
| } else if (childName.equals("Palette")) { |
| Node entry = child.getFirstChild(); |
| HashMap<Integer,char[]> palette = new HashMap<>(); |
| int maxIndex = -1; |
| while(entry != null) { |
| String entryName = entry.getNodeName(); |
| if(entryName.equals("PaletteEntry")) { |
| String idx = getAttribute(entry, "index"); |
| int id = Integer.parseInt(idx); |
| if(id > maxIndex) { |
| maxIndex = id; |
| } |
| char red = |
| (char)Integer.parseInt(getAttribute(entry, |
| "red")); |
| char green = |
| (char)Integer.parseInt(getAttribute(entry, |
| "green")); |
| char blue = |
| (char)Integer.parseInt(getAttribute(entry, |
| "blue")); |
| palette.put(Integer.valueOf(id), |
| new char[] {red, green, blue}); |
| |
| gotPalette = true; |
| } |
| entry = entry.getNextSibling(); |
| } |
| |
| if(gotPalette) { |
| int mapSize = maxIndex + 1; |
| int paletteLength = 3*mapSize; |
| char[] paletteEntries = new char[paletteLength]; |
| Iterator<Map.Entry<Integer,char[]>> paletteIter |
| = palette.entrySet().iterator(); |
| while(paletteIter.hasNext()) { |
| Map.Entry<Integer,char[]> paletteEntry |
| = paletteIter.next(); |
| int index = paletteEntry.getKey(); |
| char[] rgb = paletteEntry.getValue(); |
| paletteEntries[index] = |
| (char)((rgb[0]*65535)/255); |
| paletteEntries[mapSize + index] = |
| (char)((rgb[1]*65535)/255); |
| paletteEntries[2*mapSize + index] = |
| (char)((rgb[2]*65535)/255); |
| } |
| |
| tag = rootIFD.getTag(BaselineTIFFTagSet.TAG_COLOR_MAP); |
| f = new TIFFField(tag, TIFFTag.TIFF_SHORT, |
| paletteLength, paletteEntries); |
| rootIFD.addTIFFField(f); |
| } |
| } |
| |
| child = child.getNextSibling(); |
| } |
| |
| int photometricInterpretation = -1; |
| if((colorSpaceType == null || colorSpaceType.equals("GRAY")) && |
| blackIsZero != null && |
| blackIsZero.equalsIgnoreCase("FALSE")) { |
| photometricInterpretation = |
| BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO; |
| } else if(colorSpaceType != null) { |
| if(colorSpaceType.equals("GRAY")) { |
| boolean isTransparency = false; |
| if(root instanceof IIOMetadataNode) { |
| IIOMetadataNode iioRoot = (IIOMetadataNode)root; |
| NodeList siNodeList = |
| iioRoot.getElementsByTagName("SubimageInterpretation"); |
| if(siNodeList.getLength() == 1) { |
| Node siNode = siNodeList.item(0); |
| String value = getAttribute(siNode, "value"); |
| if(value.equals("TransparencyMask")) { |
| isTransparency = true; |
| } |
| } |
| } |
| if(isTransparency) { |
| photometricInterpretation = |
| BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_TRANSPARENCY_MASK; |
| } else { |
| photometricInterpretation = |
| BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO; |
| } |
| } else if(colorSpaceType.equals("RGB")) { |
| photometricInterpretation = |
| gotPalette ? |
| BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_PALETTE_COLOR : |
| BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_RGB; |
| } else if(colorSpaceType.equals("YCbCr")) { |
| photometricInterpretation = |
| BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_Y_CB_CR; |
| } else if(colorSpaceType.equals("CMYK")) { |
| photometricInterpretation = |
| BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_CMYK; |
| } else if(colorSpaceType.equals("Lab")) { |
| photometricInterpretation = |
| BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_CIELAB; |
| } |
| } |
| |
| if(photometricInterpretation != -1) { |
| tag = rootIFD.getTag(BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION); |
| f = new TIFFField(tag, photometricInterpretation); |
| rootIFD.addTIFFField(f); |
| } |
| } else if (name.equals("Compression")) { |
| Node child = node.getFirstChild(); |
| while (child != null) { |
| String childName = child.getNodeName(); |
| if (childName.equals("CompressionTypeName")) { |
| int compression = -1; |
| String compressionTypeName = |
| getAttribute(child, "value"); |
| if(compressionTypeName.equalsIgnoreCase("None")) { |
| compression = |
| BaselineTIFFTagSet.COMPRESSION_NONE; |
| } else { |
| String[] compressionNames = |
| TIFFImageWriter.compressionTypes; |
| for(int i = 0; i < compressionNames.length; i++) { |
| if(compressionNames[i].equalsIgnoreCase(compressionTypeName)) { |
| compression = |
| TIFFImageWriter.compressionNumbers[i]; |
| break; |
| } |
| } |
| } |
| |
| if(compression != -1) { |
| tag = rootIFD.getTag(BaselineTIFFTagSet.TAG_COMPRESSION); |
| f = new TIFFField(tag, compression); |
| rootIFD.addTIFFField(f); |
| |
| // Lossless is irrelevant. |
| } |
| } |
| |
| child = child.getNextSibling(); |
| } |
| } else if (name.equals("Data")) { |
| Node child = node.getFirstChild(); |
| while (child != null) { |
| String childName = child.getNodeName(); |
| |
| if (childName.equals("PlanarConfiguration")) { |
| String pc = getAttribute(child, "value"); |
| int planarConfiguration = -1; |
| if(pc.equals("PixelInterleaved")) { |
| planarConfiguration = |
| BaselineTIFFTagSet.PLANAR_CONFIGURATION_CHUNKY; |
| } else if(pc.equals("PlaneInterleaved")) { |
| planarConfiguration = |
| BaselineTIFFTagSet.PLANAR_CONFIGURATION_PLANAR; |
| } |
| if(planarConfiguration != -1) { |
| tag = rootIFD.getTag(BaselineTIFFTagSet.TAG_PLANAR_CONFIGURATION); |
| f = new TIFFField(tag, planarConfiguration); |
| rootIFD.addTIFFField(f); |
| } |
| } else if (childName.equals("BitsPerSample")) { |
| String bps = getAttribute(child, "value"); |
| char[] bitsPerSample = listToCharArray(bps); |
| tag = rootIFD.getTag(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE); |
| if(isPaletteColor) { |
| f = new TIFFField(tag, TIFFTag.TIFF_SHORT, 1, |
| new char[] {bitsPerSample[0]}); |
| } else { |
| f = new TIFFField(tag, TIFFTag.TIFF_SHORT, |
| bitsPerSample.length, |
| bitsPerSample); |
| } |
| rootIFD.addTIFFField(f); |
| } else if (childName.equals("SampleMSB")) { |
| // Add FillOrder only if lsb-to-msb (right to left) |
| // for all bands, i.e., SampleMSB is zero for all |
| // channels. |
| String sMSB = getAttribute(child, "value"); |
| int[] sampleMSB = listToIntArray(sMSB); |
| boolean isRightToLeft = true; |
| for(int i = 0; i < sampleMSB.length; i++) { |
| if(sampleMSB[i] != 0) { |
| isRightToLeft = false; |
| break; |
| } |
| } |
| int fillOrder = isRightToLeft ? |
| BaselineTIFFTagSet.FILL_ORDER_RIGHT_TO_LEFT : |
| BaselineTIFFTagSet.FILL_ORDER_LEFT_TO_RIGHT; |
| tag = |
| rootIFD.getTag(BaselineTIFFTagSet.TAG_FILL_ORDER); |
| f = new TIFFField(tag, fillOrder); |
| rootIFD.addTIFFField(f); |
| } |
| |
| child = child.getNextSibling(); |
| } |
| } else if (name.equals("Dimension")) { |
| float pixelAspectRatio = -1.0f; |
| boolean gotPixelAspectRatio = false; |
| |
| float horizontalPixelSize = -1.0f; |
| boolean gotHorizontalPixelSize = false; |
| |
| float verticalPixelSize = -1.0f; |
| boolean gotVerticalPixelSize = false; |
| |
| boolean sizeIsAbsolute = false; |
| |
| float horizontalPosition = -1.0f; |
| boolean gotHorizontalPosition = false; |
| |
| float verticalPosition = -1.0f; |
| boolean gotVerticalPosition = false; |
| |
| Node child = node.getFirstChild(); |
| while (child != null) { |
| String childName = child.getNodeName(); |
| if (childName.equals("PixelAspectRatio")) { |
| String par = getAttribute(child, "value"); |
| pixelAspectRatio = Float.parseFloat(par); |
| gotPixelAspectRatio = true; |
| } else if (childName.equals("ImageOrientation")) { |
| String orientation = getAttribute(child, "value"); |
| for (int i = 0; i < orientationNames.length; i++) { |
| if (orientation.equals(orientationNames[i])) { |
| char[] oData = new char[1]; |
| oData[0] = (char)i; |
| |
| f = new TIFFField( |
| rootIFD.getTag(BaselineTIFFTagSet.TAG_ORIENTATION), |
| TIFFTag.TIFF_SHORT, |
| 1, |
| oData); |
| |
| rootIFD.addTIFFField(f); |
| break; |
| } |
| } |
| |
| } else if (childName.equals("HorizontalPixelSize")) { |
| String hps = getAttribute(child, "value"); |
| horizontalPixelSize = Float.parseFloat(hps); |
| gotHorizontalPixelSize = true; |
| } else if (childName.equals("VerticalPixelSize")) { |
| String vps = getAttribute(child, "value"); |
| verticalPixelSize = Float.parseFloat(vps); |
| gotVerticalPixelSize = true; |
| } else if (childName.equals("HorizontalPosition")) { |
| String hp = getAttribute(child, "value"); |
| horizontalPosition = Float.parseFloat(hp); |
| gotHorizontalPosition = true; |
| } else if (childName.equals("VerticalPosition")) { |
| String vp = getAttribute(child, "value"); |
| verticalPosition = Float.parseFloat(vp); |
| gotVerticalPosition = true; |
| } |
| |
| child = child.getNextSibling(); |
| } |
| |
| sizeIsAbsolute = gotHorizontalPixelSize || |
| gotVerticalPixelSize; |
| |
| // Fill in pixel size data from aspect ratio |
| if (gotPixelAspectRatio) { |
| if (gotHorizontalPixelSize && !gotVerticalPixelSize) { |
| verticalPixelSize = |
| horizontalPixelSize/pixelAspectRatio; |
| gotVerticalPixelSize = true; |
| } else if (gotVerticalPixelSize && |
| !gotHorizontalPixelSize) { |
| horizontalPixelSize = |
| verticalPixelSize*pixelAspectRatio; |
| gotHorizontalPixelSize = true; |
| } else if (!gotHorizontalPixelSize && |
| !gotVerticalPixelSize) { |
| horizontalPixelSize = pixelAspectRatio; |
| verticalPixelSize = 1.0f; |
| gotHorizontalPixelSize = true; |
| gotVerticalPixelSize = true; |
| } |
| } |
| |
| // Compute pixels/centimeter |
| if (gotHorizontalPixelSize) { |
| float xResolution = |
| (sizeIsAbsolute ? 10.0f : 1.0f)/horizontalPixelSize; |
| long[][] hData = new long[1][2]; |
| hData[0] = new long[2]; |
| hData[0][0] = (long)(xResolution*10000.0f); |
| hData[0][1] = (long)10000; |
| |
| f = new TIFFField( |
| rootIFD.getTag(BaselineTIFFTagSet.TAG_X_RESOLUTION), |
| TIFFTag.TIFF_RATIONAL, |
| 1, |
| hData); |
| rootIFD.addTIFFField(f); |
| } |
| |
| if (gotVerticalPixelSize) { |
| float yResolution = |
| (sizeIsAbsolute ? 10.0f : 1.0f)/verticalPixelSize; |
| long[][] vData = new long[1][2]; |
| vData[0] = new long[2]; |
| vData[0][0] = (long)(yResolution*10000.0f); |
| vData[0][1] = (long)10000; |
| |
| f = new TIFFField( |
| rootIFD.getTag(BaselineTIFFTagSet.TAG_Y_RESOLUTION), |
| TIFFTag.TIFF_RATIONAL, |
| 1, |
| vData); |
| rootIFD.addTIFFField(f); |
| } |
| |
| // Emit ResolutionUnit tag |
| char[] res = new char[1]; |
| res[0] = (char)(sizeIsAbsolute ? |
| BaselineTIFFTagSet.RESOLUTION_UNIT_CENTIMETER : |
| BaselineTIFFTagSet.RESOLUTION_UNIT_NONE); |
| |
| f = new TIFFField( |
| rootIFD.getTag(BaselineTIFFTagSet.TAG_RESOLUTION_UNIT), |
| TIFFTag.TIFF_SHORT, |
| 1, |
| res); |
| rootIFD.addTIFFField(f); |
| |
| // Position |
| if(sizeIsAbsolute) { |
| if(gotHorizontalPosition) { |
| // Convert from millimeters to centimeters via |
| // numerator multiplier = denominator/10. |
| long[][] hData = new long[1][2]; |
| hData[0][0] = (long)(horizontalPosition*10000.0f); |
| hData[0][1] = (long)100000; |
| |
| f = new TIFFField( |
| rootIFD.getTag(BaselineTIFFTagSet.TAG_X_POSITION), |
| TIFFTag.TIFF_RATIONAL, |
| 1, |
| hData); |
| rootIFD.addTIFFField(f); |
| } |
| |
| if(gotVerticalPosition) { |
| // Convert from millimeters to centimeters via |
| // numerator multiplier = denominator/10. |
| long[][] vData = new long[1][2]; |
| vData[0][0] = (long)(verticalPosition*10000.0f); |
| vData[0][1] = (long)100000; |
| |
| f = new TIFFField( |
| rootIFD.getTag(BaselineTIFFTagSet.TAG_Y_POSITION), |
| TIFFTag.TIFF_RATIONAL, |
| 1, |
| vData); |
| rootIFD.addTIFFField(f); |
| } |
| } |
| } else if (name.equals("Document")) { |
| Node child = node.getFirstChild(); |
| while (child != null) { |
| String childName = child.getNodeName(); |
| |
| if (childName.equals("SubimageInterpretation")) { |
| String si = getAttribute(child, "value"); |
| int newSubFileType = -1; |
| if(si.equals("TransparencyMask")) { |
| newSubFileType = |
| BaselineTIFFTagSet.NEW_SUBFILE_TYPE_TRANSPARENCY; |
| } else if(si.equals("ReducedResolution")) { |
| newSubFileType = |
| BaselineTIFFTagSet.NEW_SUBFILE_TYPE_REDUCED_RESOLUTION; |
| } else if(si.equals("SinglePage")) { |
| newSubFileType = |
| BaselineTIFFTagSet.NEW_SUBFILE_TYPE_SINGLE_PAGE; |
| } |
| if(newSubFileType != -1) { |
| tag = |
| rootIFD.getTag(BaselineTIFFTagSet.TAG_NEW_SUBFILE_TYPE); |
| f = new TIFFField(tag, newSubFileType); |
| rootIFD.addTIFFField(f); |
| } |
| } |
| |
| if (childName.equals("ImageCreationTime")) { |
| String year = getAttribute(child, "year"); |
| String month = getAttribute(child, "month"); |
| String day = getAttribute(child, "day"); |
| String hour = getAttribute(child, "hour"); |
| String minute = getAttribute(child, "minute"); |
| String second = getAttribute(child, "second"); |
| |
| StringBuffer sb = new StringBuffer(); |
| sb.append(year); |
| sb.append(":"); |
| if(month.length() == 1) { |
| sb.append("0"); |
| } |
| sb.append(month); |
| sb.append(":"); |
| if(day.length() == 1) { |
| sb.append("0"); |
| } |
| sb.append(day); |
| sb.append(" "); |
| if(hour.length() == 1) { |
| sb.append("0"); |
| } |
| sb.append(hour); |
| sb.append(":"); |
| if(minute.length() == 1) { |
| sb.append("0"); |
| } |
| sb.append(minute); |
| sb.append(":"); |
| if(second.length() == 1) { |
| sb.append("0"); |
| } |
| sb.append(second); |
| |
| String[] dt = new String[1]; |
| dt[0] = sb.toString(); |
| |
| f = new TIFFField( |
| rootIFD.getTag(BaselineTIFFTagSet.TAG_DATE_TIME), |
| TIFFTag.TIFF_ASCII, |
| 1, |
| dt); |
| rootIFD.addTIFFField(f); |
| } |
| |
| child = child.getNextSibling(); |
| } |
| } else if (name.equals("Text")) { |
| Node child = node.getFirstChild(); |
| String theAuthor = null; |
| String theDescription = null; |
| String theTitle = null; |
| while (child != null) { |
| String childName = child.getNodeName(); |
| if(childName.equals("TextEntry")) { |
| int tagNumber = -1; |
| NamedNodeMap childAttrs = child.getAttributes(); |
| Node keywordNode = childAttrs.getNamedItem("keyword"); |
| if(keywordNode != null) { |
| String keyword = keywordNode.getNodeValue(); |
| String value = getAttribute(child, "value"); |
| if(!keyword.equals("") && !value.equals("")) { |
| if(keyword.equalsIgnoreCase("DocumentName")) { |
| tagNumber = |
| BaselineTIFFTagSet.TAG_DOCUMENT_NAME; |
| } else if(keyword.equalsIgnoreCase("ImageDescription")) { |
| tagNumber = |
| BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION; |
| } else if(keyword.equalsIgnoreCase("Make")) { |
| tagNumber = |
| BaselineTIFFTagSet.TAG_MAKE; |
| } else if(keyword.equalsIgnoreCase("Model")) { |
| tagNumber = |
| BaselineTIFFTagSet.TAG_MODEL; |
| } else if(keyword.equalsIgnoreCase("PageName")) { |
| tagNumber = |
| BaselineTIFFTagSet.TAG_PAGE_NAME; |
| } else if(keyword.equalsIgnoreCase("Software")) { |
| tagNumber = |
| BaselineTIFFTagSet.TAG_SOFTWARE; |
| } else if(keyword.equalsIgnoreCase("Artist")) { |
| tagNumber = |
| BaselineTIFFTagSet.TAG_ARTIST; |
| } else if(keyword.equalsIgnoreCase("HostComputer")) { |
| tagNumber = |
| BaselineTIFFTagSet.TAG_HOST_COMPUTER; |
| } else if(keyword.equalsIgnoreCase("InkNames")) { |
| tagNumber = |
| BaselineTIFFTagSet.TAG_INK_NAMES; |
| } else if(keyword.equalsIgnoreCase("Copyright")) { |
| tagNumber = |
| BaselineTIFFTagSet.TAG_COPYRIGHT; |
| } else if(keyword.equalsIgnoreCase("author")) { |
| theAuthor = value; |
| } else if(keyword.equalsIgnoreCase("description")) { |
| theDescription = value; |
| } else if(keyword.equalsIgnoreCase("title")) { |
| theTitle = value; |
| } |
| if(tagNumber != -1) { |
| f = new TIFFField(rootIFD.getTag(tagNumber), |
| TIFFTag.TIFF_ASCII, |
| 1, |
| new String[] {value}); |
| rootIFD.addTIFFField(f); |
| } |
| } |
| } |
| } |
| child = child.getNextSibling(); |
| } // child != null |
| if(theAuthor != null && |
| getTIFFField(BaselineTIFFTagSet.TAG_ARTIST) == null) { |
| f = new TIFFField(rootIFD.getTag(BaselineTIFFTagSet.TAG_ARTIST), |
| TIFFTag.TIFF_ASCII, |
| 1, |
| new String[] {theAuthor}); |
| rootIFD.addTIFFField(f); |
| } |
| if(theDescription != null && |
| getTIFFField(BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION) == null) { |
| f = new TIFFField(rootIFD.getTag(BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION), |
| TIFFTag.TIFF_ASCII, |
| 1, |
| new String[] {theDescription}); |
| rootIFD.addTIFFField(f); |
| } |
| if(theTitle != null && |
| getTIFFField(BaselineTIFFTagSet.TAG_DOCUMENT_NAME) == null) { |
| f = new TIFFField(rootIFD.getTag(BaselineTIFFTagSet.TAG_DOCUMENT_NAME), |
| TIFFTag.TIFF_ASCII, |
| 1, |
| new String[] {theTitle}); |
| rootIFD.addTIFFField(f); |
| } |
| } else if (name.equals("Transparency")) { |
| Node child = node.getFirstChild(); |
| while (child != null) { |
| String childName = child.getNodeName(); |
| |
| if (childName.equals("Alpha")) { |
| String alpha = getAttribute(child, "value"); |
| |
| f = null; |
| if (alpha.equals("premultiplied")) { |
| f = new TIFFField( |
| rootIFD.getTag(BaselineTIFFTagSet.TAG_EXTRA_SAMPLES), |
| BaselineTIFFTagSet.EXTRA_SAMPLES_ASSOCIATED_ALPHA); |
| } else if (alpha.equals("nonpremultiplied")) { |
| f = new TIFFField( |
| rootIFD.getTag(BaselineTIFFTagSet.TAG_EXTRA_SAMPLES), |
| BaselineTIFFTagSet.EXTRA_SAMPLES_UNASSOCIATED_ALPHA); |
| } |
| if (f != null) { |
| rootIFD.addTIFFField(f); |
| } |
| } |
| |
| child = child.getNextSibling(); |
| } |
| } |
| |
| node = node.getNextSibling(); |
| } |
| |
| // Set SampleFormat. |
| if(sampleFormat != null) { |
| // Derive the value. |
| int sf = -1; |
| if(sampleFormat.equals("SignedIntegral")) { |
| sf = BaselineTIFFTagSet.SAMPLE_FORMAT_SIGNED_INTEGER; |
| } else if(sampleFormat.equals("UnsignedIntegral")) { |
| sf = BaselineTIFFTagSet.SAMPLE_FORMAT_UNSIGNED_INTEGER; |
| } else if(sampleFormat.equals("Real")) { |
| sf = BaselineTIFFTagSet.SAMPLE_FORMAT_FLOATING_POINT; |
| } else if(sampleFormat.equals("Index")) { |
| sf = BaselineTIFFTagSet.SAMPLE_FORMAT_UNSIGNED_INTEGER; |
| } |
| |
| if(sf != -1) { |
| // Derive the count. |
| int count = 1; |
| |
| // Try SamplesPerPixel first. |
| f = getTIFFField(BaselineTIFFTagSet.TAG_SAMPLES_PER_PIXEL); |
| if(f != null) { |
| count = f.getAsInt(0); |
| } else { |
| // Try BitsPerSample. |
| f = getTIFFField(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE); |
| if(f != null) { |
| count = f.getCount(); |
| } |
| } |
| |
| char[] sampleFormatArray = new char[count]; |
| Arrays.fill(sampleFormatArray, (char)sf); |
| |
| // Add SampleFormat. |
| tag = rootIFD.getTag(BaselineTIFFTagSet.TAG_SAMPLE_FORMAT); |
| f = new TIFFField(tag, TIFFTag.TIFF_SHORT, |
| sampleFormatArray.length, sampleFormatArray); |
| rootIFD.addTIFFField(f); |
| } |
| } |
| } |
| |
| private static String getAttribute(Node node, String attrName) { |
| NamedNodeMap attrs = node.getAttributes(); |
| Node attr = attrs.getNamedItem(attrName); |
| return attr != null ? attr.getNodeValue() : null; |
| } |
| |
| private Node getChildNode(Node node, String childName) { |
| Node childNode = null; |
| if(node.hasChildNodes()) { |
| NodeList childNodes = node.getChildNodes(); |
| int length = childNodes.getLength(); |
| for(int i = 0; i < length; i++) { |
| Node item = childNodes.item(i); |
| if(item.getNodeName().equals(childName)) { |
| childNode = item; |
| break; |
| } |
| } |
| } |
| return childNode; |
| } |
| |
| public static TIFFIFD parseIFD(Node node) throws IIOInvalidTreeException { |
| if (!node.getNodeName().equals("TIFFIFD")) { |
| fatal(node, "Expected \"TIFFIFD\" node"); |
| } |
| |
| String tagSetNames = getAttribute(node, "tagSets"); |
| List<TIFFTagSet> tagSets = new ArrayList<TIFFTagSet>(5); |
| |
| if (tagSetNames != null) { |
| StringTokenizer st = new StringTokenizer(tagSetNames, ","); |
| while (st.hasMoreTokens()) { |
| String className = st.nextToken(); |
| |
| Object o = null; |
| Class<?> setClass = null; |
| try { |
| ClassLoader cl = TIFFImageMetadata.class.getClassLoader(); |
| setClass = Class.forName(className, false, cl); |
| if (!TIFFTagSet.class.isAssignableFrom(setClass)) { |
| fatal(node, "TagSets in IFD must be subset of" |
| + " TIFFTagSet class"); |
| } |
| Method getInstanceMethod = |
| setClass.getMethod("getInstance", (Class[])null); |
| o = getInstanceMethod.invoke(null, (Object[])null); |
| } catch (NoSuchMethodException e) { |
| throw new RuntimeException(e); |
| } catch (IllegalAccessException e) { |
| throw new RuntimeException(e); |
| } catch (InvocationTargetException e) { |
| throw new RuntimeException(e); |
| } catch (ClassNotFoundException e) { |
| throw new RuntimeException(e); |
| } |
| |
| if (!(o instanceof TIFFTagSet)) { |
| fatal(node, "Specified tag set class \"" + |
| className + |
| "\" is not an instance of TIFFTagSet"); |
| } else { |
| tagSets.add((TIFFTagSet)o); |
| } |
| } |
| } |
| |
| TIFFIFD ifd = new TIFFIFD(tagSets); |
| |
| node = node.getFirstChild(); |
| while (node != null) { |
| String name = node.getNodeName(); |
| |
| TIFFField f = null; |
| if (name.equals("TIFFIFD")) { |
| TIFFIFD subIFD = parseIFD(node); |
| String parentTagName = getAttribute(node, "parentTagName"); |
| String parentTagNumber = getAttribute(node, "parentTagNumber"); |
| TIFFTag tag = null; |
| if(parentTagName != null) { |
| tag = TIFFIFD.getTag(parentTagName, tagSets); |
| } else if(parentTagNumber != null) { |
| int tagNumber = Integer.parseUnsignedInt(parentTagNumber); |
| tag = TIFFIFD.getTag(tagNumber, tagSets); |
| } |
| |
| int type; |
| if (tag == null) { |
| type = TIFFTag.TIFF_LONG; |
| tag = new TIFFTag(TIFFTag.UNKNOWN_TAG_NAME, 0, 1 << type); |
| } else { |
| if (tag.isDataTypeOK(TIFFTag.TIFF_IFD_POINTER)) { |
| type = TIFFTag.TIFF_IFD_POINTER; |
| } else if (tag.isDataTypeOK(TIFFTag.TIFF_LONG)) { |
| type = TIFFTag.TIFF_LONG; |
| } else { |
| for (type = TIFFTag.MAX_DATATYPE; |
| type >= TIFFTag.MIN_DATATYPE; |
| type--) { |
| if (tag.isDataTypeOK(type)) { |
| break; |
| } |
| } |
| } |
| } |
| |
| f = new TIFFField(tag, type, 1L, subIFD); |
| } else if (name.equals("TIFFField")) { |
| int number = Integer.parseInt(getAttribute(node, "number")); |
| |
| TIFFTagSet tagSet = null; |
| Iterator<TIFFTagSet> iter = tagSets.iterator(); |
| while (iter.hasNext()) { |
| TIFFTagSet t = iter.next(); |
| if (t.getTag(number) != null) { |
| tagSet = t; |
| break; |
| } |
| } |
| |
| f = TIFFField.createFromMetadataNode(tagSet, node); |
| } else { |
| fatal(node, |
| "Expected either \"TIFFIFD\" or \"TIFFField\" node, got " |
| + name); |
| } |
| |
| ifd.addTIFFField(f); |
| node = node.getNextSibling(); |
| } |
| |
| return ifd; |
| } |
| |
| private void mergeNativeTree(Node root) throws IIOInvalidTreeException { |
| Node node = root; |
| if (!node.getNodeName().equals(nativeMetadataFormatName)) { |
| fatal(node, "Root must be " + nativeMetadataFormatName); |
| } |
| |
| node = node.getFirstChild(); |
| if (node == null || !node.getNodeName().equals("TIFFIFD")) { |
| fatal(root, "Root must have \"TIFFIFD\" child"); |
| } |
| TIFFIFD ifd = parseIFD(node); |
| |
| List<TIFFTagSet> rootIFDTagSets = rootIFD.getTagSetList(); |
| Iterator<TIFFTagSet> tagSetIter = ifd.getTagSetList().iterator(); |
| while(tagSetIter.hasNext()) { |
| Object o = tagSetIter.next(); |
| if(o instanceof TIFFTagSet && !rootIFDTagSets.contains(o)) { |
| rootIFD.addTagSet((TIFFTagSet)o); |
| } |
| } |
| |
| Iterator<TIFFField> ifdIter = ifd.iterator(); |
| while(ifdIter.hasNext()) { |
| TIFFField field = ifdIter.next(); |
| rootIFD.addTIFFField(field); |
| } |
| } |
| |
| public void mergeTree(String formatName, Node root) |
| throws IIOInvalidTreeException{ |
| if (formatName.equals(nativeMetadataFormatName)) { |
| if (root == null) { |
| throw new NullPointerException("root == null!"); |
| } |
| mergeNativeTree(root); |
| } else if (formatName.equals |
| (IIOMetadataFormatImpl.standardMetadataFormatName)) { |
| if (root == null) { |
| throw new NullPointerException("root == null!"); |
| } |
| mergeStandardTree(root); |
| } else { |
| throw new IllegalArgumentException("Not a recognized format!"); |
| } |
| } |
| |
| public void reset() { |
| rootIFD = new TIFFIFD(tagSets); |
| } |
| |
| public TIFFIFD getRootIFD() { |
| return rootIFD; |
| } |
| |
| public TIFFField getTIFFField(int tagNumber) { |
| return rootIFD.getTIFFField(tagNumber); |
| } |
| |
| public void removeTIFFField(int tagNumber) { |
| rootIFD.removeTIFFField(tagNumber); |
| } |
| |
| /** |
| * Returns a {@code TIFFImageMetadata} wherein all fields in the |
| * root IFD from the {@code BaselineTIFFTagSet} are copied by value |
| * and all other fields copied by reference. |
| */ |
| public TIFFImageMetadata getShallowClone() { |
| return new TIFFImageMetadata(rootIFD.getShallowClone()); |
| } |
| } |