0001: /*
0002: * $RCSfile: TIFFImageMetadata.java,v $
0003: *
0004: *
0005: * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved.
0006: *
0007: * Redistribution and use in source and binary forms, with or without
0008: * modification, are permitted provided that the following conditions
0009: * are met:
0010: *
0011: * - Redistribution of source code must retain the above copyright
0012: * notice, this list of conditions and the following disclaimer.
0013: *
0014: * - Redistribution in binary form must reproduce the above copyright
0015: * notice, this list of conditions and the following disclaimer in
0016: * the documentation and/or other materials provided with the
0017: * distribution.
0018: *
0019: * Neither the name of Sun Microsystems, Inc. or the names of
0020: * contributors may be used to endorse or promote products derived
0021: * from this software without specific prior written permission.
0022: *
0023: * This software is provided "AS IS," without a warranty of any
0024: * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
0025: * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
0026: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
0027: * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
0028: * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
0029: * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
0030: * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
0031: * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
0032: * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
0033: * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
0034: * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
0035: * POSSIBILITY OF SUCH DAMAGES.
0036: *
0037: * You acknowledge that this software is not designed or intended for
0038: * use in the design, construction, operation or maintenance of any
0039: * nuclear facility.
0040: *
0041: * $Revision: 1.11 $
0042: * $Date: 2006/07/21 22:56:55 $
0043: * $State: Exp $
0044: */
0045: package com.sun.media.imageioimpl.plugins.tiff;
0046:
0047: import java.awt.image.ColorModel;
0048: import java.awt.image.SampleModel;
0049: import java.io.IOException;
0050: import java.lang.reflect.InvocationTargetException;
0051: import java.lang.reflect.Method;
0052: import java.util.ArrayList;
0053: import java.util.Arrays;
0054: import java.util.HashMap;
0055: import java.util.Iterator;
0056: import java.util.List;
0057: import java.util.StringTokenizer;
0058: import java.util.Vector;
0059: import javax.imageio.ImageTypeSpecifier;
0060: import javax.imageio.metadata.IIOMetadata;
0061: import javax.imageio.metadata.IIOInvalidTreeException;
0062: import javax.imageio.metadata.IIOMetadataFormatImpl;
0063: import javax.imageio.metadata.IIOMetadataNode;
0064: import javax.imageio.stream.ImageInputStream;
0065: import org.w3c.dom.NamedNodeMap;
0066: import org.w3c.dom.Node;
0067: import org.w3c.dom.NodeList;
0068: import com.sun.media.imageio.plugins.tiff.BaselineTIFFTagSet;
0069: import com.sun.media.imageio.plugins.tiff.EXIFParentTIFFTagSet;
0070: import com.sun.media.imageio.plugins.tiff.TIFFField;
0071: import com.sun.media.imageio.plugins.tiff.TIFFTag;
0072: import com.sun.media.imageio.plugins.tiff.TIFFTagSet;
0073:
0074: public class TIFFImageMetadata extends IIOMetadata {
0075:
0076: // package scope
0077:
0078: public static final String nativeMetadataFormatName = "com_sun_media_imageio_plugins_tiff_image_1.0";
0079:
0080: public static final String nativeMetadataFormatClassName = "com.sun.media.imageioimpl.plugins.tiff.TIFFImageMetadataFormat";
0081:
0082: List tagSets;
0083:
0084: TIFFIFD rootIFD;
0085:
0086: public TIFFImageMetadata(List tagSets) {
0087: super (true, nativeMetadataFormatName,
0088: nativeMetadataFormatClassName, null, null);
0089:
0090: this .tagSets = tagSets;
0091: this .rootIFD = new TIFFIFD(tagSets);
0092: }
0093:
0094: public TIFFImageMetadata(TIFFIFD ifd) {
0095: super (true, nativeMetadataFormatName,
0096: nativeMetadataFormatClassName, null, null);
0097: this .tagSets = ifd.getTagSetList();
0098: this .rootIFD = ifd;
0099: }
0100:
0101: public void initializeFromStream(ImageInputStream stream,
0102: boolean ignoreUnknownFields) throws IOException {
0103: rootIFD.initialize(stream, ignoreUnknownFields);
0104: }
0105:
0106: public void addShortOrLongField(int tagNumber, int value) {
0107: TIFFField field = new TIFFField(rootIFD.getTag(tagNumber),
0108: value);
0109: rootIFD.addTIFFField(field);
0110: }
0111:
0112: // public void initializeFromImageType(ImageTypeSpecifier imageType) {
0113: // SampleModel sampleModel = imageType.getSampleModel();
0114: // ColorModel colorModel = imageType.getColorModel();
0115:
0116: // int numBands = sampleModel.getNumBands();
0117: // char[] bitsPerSample = new char[numBands];
0118: // for (int i = 0; i < numBands; i++) {
0119: // bitsPerSample[i] = (char)(sampleModel.getSampleSize(i));
0120: // }
0121: // TIFFField bitsPerSampleField =
0122: // new TIFFField(rootIFD.getTag(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE),
0123: // TIFFTag.TIFF_SHORT,
0124: // numBands,
0125: // bitsPerSample);
0126: // rootIFD.addTIFFField(bitsPerSampleField);
0127: // }
0128:
0129: public boolean isReadOnly() {
0130: return false;
0131: }
0132:
0133: private Node getIFDAsTree(TIFFIFD ifd, String parentTagName,
0134: int parentTagNumber) {
0135: IIOMetadataNode IFDRoot = new IIOMetadataNode("TIFFIFD");
0136: if (parentTagNumber != 0) {
0137: IFDRoot.setAttribute("parentTagNumber", Integer
0138: .toString(parentTagNumber));
0139: }
0140: if (parentTagName != null) {
0141: IFDRoot.setAttribute("parentTagName", parentTagName);
0142: }
0143:
0144: List tagSets = ifd.getTagSetList();
0145: if (tagSets.size() > 0) {
0146: Iterator iter = tagSets.iterator();
0147: String tagSetNames = "";
0148: while (iter.hasNext()) {
0149: TIFFTagSet tagSet = (TIFFTagSet) iter.next();
0150: tagSetNames += tagSet.getClass().getName();
0151: if (iter.hasNext()) {
0152: tagSetNames += ",";
0153: }
0154: }
0155:
0156: IFDRoot.setAttribute("tagSets", tagSetNames);
0157: }
0158:
0159: Iterator iter = ifd.iterator();
0160: while (iter.hasNext()) {
0161: TIFFField f = (TIFFField) iter.next();
0162: int tagNumber = f.getTagNumber();
0163: TIFFTag tag = TIFFIFD.getTag(tagNumber, tagSets);
0164:
0165: Node node = null;
0166: if (tag == null) {
0167: node = f.getAsNativeNode();
0168: } else if (tag.isIFDPointer()) {
0169: TIFFIFD subIFD = (TIFFIFD) f.getData();
0170:
0171: // Recurse
0172: node = getIFDAsTree(subIFD, tag.getName(), tag
0173: .getNumber());
0174: } else {
0175: node = f.getAsNativeNode();
0176: }
0177:
0178: if (node != null) {
0179: IFDRoot.appendChild(node);
0180: }
0181: }
0182:
0183: return IFDRoot;
0184: }
0185:
0186: public Node getAsTree(String formatName) {
0187: if (formatName.equals(nativeMetadataFormatName)) {
0188: return getNativeTree();
0189: } else if (formatName
0190: .equals(IIOMetadataFormatImpl.standardMetadataFormatName)) {
0191: return getStandardTree();
0192: } else {
0193: throw new IllegalArgumentException(
0194: "Not a recognized format!");
0195: }
0196: }
0197:
0198: private Node getNativeTree() {
0199: IIOMetadataNode root = new IIOMetadataNode(
0200: nativeMetadataFormatName);
0201:
0202: Node IFDNode = getIFDAsTree(rootIFD, null, 0);
0203: root.appendChild(IFDNode);
0204:
0205: return root;
0206: }
0207:
0208: private static final String[] colorSpaceNames = { "GRAY", // WhiteIsZero
0209: "GRAY", // BlackIsZero
0210: "RGB", // RGB
0211: "RGB", // PaletteColor
0212: "GRAY", // TransparencyMask
0213: "CMYK", // CMYK
0214: "YCbCr", // YCbCr
0215: "Lab", // CIELab
0216: "Lab", // ICCLab
0217: };
0218:
0219: public IIOMetadataNode getStandardChromaNode() {
0220: IIOMetadataNode chroma_node = new IIOMetadataNode("Chroma");
0221: IIOMetadataNode node = null; // scratch node
0222:
0223: TIFFField f;
0224:
0225: // Set the PhotometricInterpretation and the palette color flag.
0226: int photometricInterpretation = -1;
0227: boolean isPaletteColor = false;
0228: f = getTIFFField(BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION);
0229: if (f != null) {
0230: photometricInterpretation = f.getAsInt(0);
0231:
0232: isPaletteColor = photometricInterpretation == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_PALETTE_COLOR;
0233: }
0234:
0235: // Determine the number of channels.
0236: int numChannels = -1;
0237: if (isPaletteColor) {
0238: numChannels = 3;
0239: } else {
0240: f = getTIFFField(BaselineTIFFTagSet.TAG_SAMPLES_PER_PIXEL);
0241: if (f != null) {
0242: numChannels = f.getAsInt(0);
0243: } else { // f == null
0244: f = getTIFFField(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE);
0245: if (f != null) {
0246: numChannels = f.getCount();
0247: }
0248: }
0249: }
0250:
0251: if (photometricInterpretation != -1) {
0252: if (photometricInterpretation >= 0
0253: && photometricInterpretation < colorSpaceNames.length) {
0254: node = new IIOMetadataNode("ColorSpaceType");
0255: String csName;
0256: if (photometricInterpretation == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_CMYK
0257: && numChannels == 3) {
0258: csName = "CMY";
0259: } else {
0260: csName = colorSpaceNames[photometricInterpretation];
0261: }
0262: node.setAttribute("name", csName);
0263: chroma_node.appendChild(node);
0264: }
0265:
0266: node = new IIOMetadataNode("BlackIsZero");
0267: node
0268: .setAttribute(
0269: "value",
0270: (photometricInterpretation == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO) ? "FALSE"
0271: : "TRUE");
0272: chroma_node.appendChild(node);
0273: }
0274:
0275: if (numChannels != -1) {
0276: node = new IIOMetadataNode("NumChannels");
0277: node.setAttribute("value", Integer.toString(numChannels));
0278: chroma_node.appendChild(node);
0279: }
0280:
0281: f = getTIFFField(BaselineTIFFTagSet.TAG_COLOR_MAP);
0282: if (f != null) {
0283: // NOTE: The presence of hasAlpha is vestigial: there is
0284: // no way in TIFF to represent an alpha component in a palette
0285: // color image. See bug 5086341.
0286: boolean hasAlpha = false;
0287:
0288: node = new IIOMetadataNode("Palette");
0289: int len = f.getCount() / (hasAlpha ? 4 : 3);
0290: for (int i = 0; i < len; i++) {
0291: IIOMetadataNode entry = new IIOMetadataNode(
0292: "PaletteEntry");
0293: entry.setAttribute("index", Integer.toString(i));
0294:
0295: int r = (f.getAsInt(i) * 255) / 65535;
0296: int g = (f.getAsInt(len + i) * 255) / 65535;
0297: int b = (f.getAsInt(2 * len + i) * 255) / 65535;
0298:
0299: entry.setAttribute("red", Integer.toString(r));
0300: entry.setAttribute("green", Integer.toString(g));
0301: entry.setAttribute("blue", Integer.toString(b));
0302: if (hasAlpha) {
0303: int alpha = 0;
0304: entry
0305: .setAttribute("alpha", Integer
0306: .toString(alpha));
0307: }
0308: node.appendChild(entry);
0309: }
0310: chroma_node.appendChild(node);
0311: }
0312:
0313: return chroma_node;
0314: }
0315:
0316: public IIOMetadataNode getStandardCompressionNode() {
0317: IIOMetadataNode compression_node = new IIOMetadataNode(
0318: "Compression");
0319: IIOMetadataNode node = null; // scratch node
0320:
0321: TIFFField f;
0322:
0323: f = getTIFFField(BaselineTIFFTagSet.TAG_COMPRESSION);
0324: if (f != null) {
0325: String compressionTypeName = null;
0326: int compression = f.getAsInt(0);
0327: boolean isLossless = true; // obligate initialization.
0328: if (compression == BaselineTIFFTagSet.COMPRESSION_NONE) {
0329: compressionTypeName = "None";
0330: isLossless = true;
0331: } else {
0332: int[] compressionNumbers = TIFFImageWriter.compressionNumbers;
0333: for (int i = 0; i < compressionNumbers.length; i++) {
0334: if (compression == compressionNumbers[i]) {
0335: compressionTypeName = TIFFImageWriter.compressionTypes[i];
0336: isLossless = TIFFImageWriter.isCompressionLossless[i];
0337: break;
0338: }
0339: }
0340: }
0341:
0342: if (compressionTypeName != null) {
0343: node = new IIOMetadataNode("CompressionTypeName");
0344: node.setAttribute("value", compressionTypeName);
0345: compression_node.appendChild(node);
0346:
0347: node = new IIOMetadataNode("Lossless");
0348: node.setAttribute("value", isLossless ? "TRUE"
0349: : "FALSE");
0350: compression_node.appendChild(node);
0351: }
0352: }
0353:
0354: node = new IIOMetadataNode("NumProgressiveScans");
0355: node.setAttribute("value", "1");
0356: compression_node.appendChild(node);
0357:
0358: return compression_node;
0359: }
0360:
0361: private String repeat(String s, int times) {
0362: if (times == 1) {
0363: return s;
0364: }
0365: StringBuffer sb = new StringBuffer((s.length() + 1) * times - 1);
0366: sb.append(s);
0367: for (int i = 1; i < times; i++) {
0368: sb.append(" ");
0369: sb.append(s);
0370: }
0371: return sb.toString();
0372: }
0373:
0374: public IIOMetadataNode getStandardDataNode() {
0375: IIOMetadataNode data_node = new IIOMetadataNode("Data");
0376: IIOMetadataNode node = null; // scratch node
0377:
0378: TIFFField f;
0379:
0380: boolean isPaletteColor = false;
0381: f = getTIFFField(BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION);
0382: if (f != null) {
0383: isPaletteColor = f.getAsInt(0) == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_PALETTE_COLOR;
0384: }
0385:
0386: f = getTIFFField(BaselineTIFFTagSet.TAG_PLANAR_CONFIGURATION);
0387: String planarConfiguration = "PixelInterleaved";
0388: if (f != null
0389: && f.getAsInt(0) == BaselineTIFFTagSet.PLANAR_CONFIGURATION_PLANAR) {
0390: planarConfiguration = "PlaneInterleaved";
0391: }
0392:
0393: node = new IIOMetadataNode("PlanarConfiguration");
0394: node.setAttribute("value", planarConfiguration);
0395: data_node.appendChild(node);
0396:
0397: f = getTIFFField(BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION);
0398: if (f != null) {
0399: int photometricInterpretation = f.getAsInt(0);
0400: String sampleFormat = "UnsignedIntegral";
0401:
0402: if (photometricInterpretation == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_PALETTE_COLOR) {
0403: sampleFormat = "Index";
0404: } else {
0405: f = getTIFFField(BaselineTIFFTagSet.TAG_SAMPLE_FORMAT);
0406: if (f != null) {
0407: int format = f.getAsInt(0);
0408: if (format == BaselineTIFFTagSet.SAMPLE_FORMAT_SIGNED_INTEGER) {
0409: sampleFormat = "SignedIntegral";
0410: } else if (format == BaselineTIFFTagSet.SAMPLE_FORMAT_UNSIGNED_INTEGER) {
0411: sampleFormat = "UnsignedIntegral";
0412: } else if (format == BaselineTIFFTagSet.SAMPLE_FORMAT_FLOATING_POINT) {
0413: sampleFormat = "Real";
0414: } else {
0415: sampleFormat = null; // don't know
0416: }
0417: }
0418: }
0419: if (sampleFormat != null) {
0420: node = new IIOMetadataNode("SampleFormat");
0421: node.setAttribute("value", sampleFormat);
0422: data_node.appendChild(node);
0423: }
0424: }
0425:
0426: f = getTIFFField(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE);
0427: int[] bitsPerSample = null;
0428: if (f != null) {
0429: bitsPerSample = f.getAsInts();
0430: } else {
0431: f = getTIFFField(BaselineTIFFTagSet.TAG_COMPRESSION);
0432: int compression = f != null ? f.getAsInt(0)
0433: : BaselineTIFFTagSet.COMPRESSION_NONE;
0434: if (getTIFFField(EXIFParentTIFFTagSet.TAG_EXIF_IFD_POINTER) != null
0435: || compression == BaselineTIFFTagSet.COMPRESSION_JPEG
0436: || compression == BaselineTIFFTagSet.COMPRESSION_OLD_JPEG
0437: || getTIFFField(BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT) != null) {
0438: f = getTIFFField(BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION);
0439: if (f != null
0440: && (f.getAsInt(0) == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO || f
0441: .getAsInt(0) == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO)) {
0442: bitsPerSample = new int[] { 8 };
0443: } else {
0444: bitsPerSample = new int[] { 8, 8, 8 };
0445: }
0446: } else {
0447: bitsPerSample = new int[] { 1 };
0448: }
0449: }
0450: StringBuffer sb = new StringBuffer();
0451: for (int i = 0; i < bitsPerSample.length; i++) {
0452: if (i > 0) {
0453: sb.append(" ");
0454: }
0455: sb.append(Integer.toString(bitsPerSample[i]));
0456: }
0457: node = new IIOMetadataNode("BitsPerSample");
0458: if (isPaletteColor) {
0459: node.setAttribute("value", repeat(sb.toString(), 3));
0460: } else {
0461: node.setAttribute("value", sb.toString());
0462: }
0463: data_node.appendChild(node);
0464:
0465: // SampleMSB
0466: f = getTIFFField(BaselineTIFFTagSet.TAG_FILL_ORDER);
0467: int fillOrder = f != null ? f.getAsInt(0)
0468: : BaselineTIFFTagSet.FILL_ORDER_LEFT_TO_RIGHT;
0469: sb = new StringBuffer();
0470: for (int i = 0; i < bitsPerSample.length; i++) {
0471: if (i > 0) {
0472: sb.append(" ");
0473: }
0474: int maxBitIndex = bitsPerSample[i] == 1 ? 7
0475: : bitsPerSample[i] - 1;
0476: int msb = fillOrder == BaselineTIFFTagSet.FILL_ORDER_LEFT_TO_RIGHT ? maxBitIndex
0477: : 0;
0478: sb.append(Integer.toString(msb));
0479: }
0480: node = new IIOMetadataNode("SampleMSB");
0481: if (isPaletteColor) {
0482: node.setAttribute("value", repeat(sb.toString(), 3));
0483: } else {
0484: node.setAttribute("value", sb.toString());
0485: }
0486: data_node.appendChild(node);
0487:
0488: return data_node;
0489: }
0490:
0491: private static final String[] orientationNames = { null, "Normal",
0492: "FlipH", "Rotate180", "FlipV", "FlipHRotate90",
0493: "Rotate270", "FlipVRotate90", "Rotate90", };
0494:
0495: public IIOMetadataNode getStandardDimensionNode() {
0496: IIOMetadataNode dimension_node = new IIOMetadataNode(
0497: "Dimension");
0498: IIOMetadataNode node = null; // scratch node
0499:
0500: TIFFField f;
0501:
0502: long[] xres = null;
0503: long[] yres = null;
0504:
0505: f = getTIFFField(BaselineTIFFTagSet.TAG_X_RESOLUTION);
0506: if (f != null) {
0507: xres = (long[]) f.getAsRational(0).clone();
0508: }
0509:
0510: f = getTIFFField(BaselineTIFFTagSet.TAG_Y_RESOLUTION);
0511: if (f != null) {
0512: yres = (long[]) f.getAsRational(0).clone();
0513: }
0514:
0515: if (xres != null && yres != null) {
0516: node = new IIOMetadataNode("PixelAspectRatio");
0517:
0518: // Compute (1/xres)/(1/yres)
0519: // (xres_denom/xres_num)/(yres_denom/yres_num) =
0520: // (xres_denom/xres_num)*(yres_num/yres_denom) =
0521: // (xres_denom*yres_num)/(xres_num*yres_denom)
0522: float ratio = (float) ((double) xres[1] * yres[0])
0523: / (xres[0] * yres[1]);
0524: node.setAttribute("value", Float.toString(ratio));
0525: dimension_node.appendChild(node);
0526: }
0527:
0528: if (xres != null || yres != null) {
0529: // Get unit field.
0530: f = getTIFFField(BaselineTIFFTagSet.TAG_RESOLUTION_UNIT);
0531:
0532: // Set resolution unit.
0533: int resolutionUnit = f != null ? f.getAsInt(0)
0534: : BaselineTIFFTagSet.RESOLUTION_UNIT_INCH;
0535:
0536: // Have size if either centimeters or inches.
0537: boolean gotPixelSize = resolutionUnit != BaselineTIFFTagSet.RESOLUTION_UNIT_NONE;
0538:
0539: // Convert pixels/inch to pixels/centimeter.
0540: if (resolutionUnit == BaselineTIFFTagSet.RESOLUTION_UNIT_INCH) {
0541: // Divide xres by 2.54
0542: if (xres != null) {
0543: xres[0] *= 100;
0544: xres[1] *= 254;
0545: }
0546:
0547: // Divide yres by 2.54
0548: if (yres != null) {
0549: yres[0] *= 100;
0550: yres[1] *= 254;
0551: }
0552: }
0553:
0554: if (gotPixelSize) {
0555: if (xres != null) {
0556: float horizontalPixelSize = (float) (10.0 * xres[1] / xres[0]);
0557: node = new IIOMetadataNode("HorizontalPixelSize");
0558: node.setAttribute("value", Float
0559: .toString(horizontalPixelSize));
0560: dimension_node.appendChild(node);
0561: }
0562:
0563: if (yres != null) {
0564: float verticalPixelSize = (float) (10.0 * yres[1] / yres[0]);
0565: node = new IIOMetadataNode("VerticalPixelSize");
0566: node.setAttribute("value", Float
0567: .toString(verticalPixelSize));
0568: dimension_node.appendChild(node);
0569: }
0570: }
0571: }
0572:
0573: f = getTIFFField(BaselineTIFFTagSet.TAG_RESOLUTION_UNIT);
0574: int resolutionUnit = f != null ? f.getAsInt(0)
0575: : BaselineTIFFTagSet.RESOLUTION_UNIT_INCH;
0576: if (resolutionUnit == BaselineTIFFTagSet.RESOLUTION_UNIT_INCH
0577: || resolutionUnit == BaselineTIFFTagSet.RESOLUTION_UNIT_CENTIMETER) {
0578: f = getTIFFField(BaselineTIFFTagSet.TAG_X_POSITION);
0579: if (f != null) {
0580: long[] xpos = (long[]) f.getAsRational(0);
0581: float xPosition = (float) xpos[0] / (float) xpos[1];
0582: // Convert to millimeters.
0583: if (resolutionUnit == BaselineTIFFTagSet.RESOLUTION_UNIT_INCH) {
0584: xPosition *= 254F;
0585: } else {
0586: xPosition *= 10F;
0587: }
0588: node = new IIOMetadataNode("HorizontalPosition");
0589: node.setAttribute("value", Float.toString(xPosition));
0590: dimension_node.appendChild(node);
0591: }
0592:
0593: f = getTIFFField(BaselineTIFFTagSet.TAG_Y_POSITION);
0594: if (f != null) {
0595: long[] ypos = (long[]) f.getAsRational(0);
0596: float yPosition = (float) ypos[0] / (float) ypos[1];
0597: // Convert to millimeters.
0598: if (resolutionUnit == BaselineTIFFTagSet.RESOLUTION_UNIT_INCH) {
0599: yPosition *= 254F;
0600: } else {
0601: yPosition *= 10F;
0602: }
0603: node = new IIOMetadataNode("VerticalPosition");
0604: node.setAttribute("value", Float.toString(yPosition));
0605: dimension_node.appendChild(node);
0606: }
0607: }
0608:
0609: f = getTIFFField(BaselineTIFFTagSet.TAG_ORIENTATION);
0610: if (f != null) {
0611: int o = f.getAsInt(0);
0612: if (o >= 0 && o < orientationNames.length) {
0613: node = new IIOMetadataNode("ImageOrientation");
0614: node.setAttribute("value", orientationNames[o]);
0615: dimension_node.appendChild(node);
0616: }
0617: }
0618:
0619: return dimension_node;
0620: }
0621:
0622: public IIOMetadataNode getStandardDocumentNode() {
0623: IIOMetadataNode document_node = new IIOMetadataNode("Document");
0624: IIOMetadataNode node = null; // scratch node
0625:
0626: TIFFField f;
0627:
0628: node = new IIOMetadataNode("FormatVersion");
0629: node.setAttribute("value", "6.0");
0630: document_node.appendChild(node);
0631:
0632: f = getTIFFField(BaselineTIFFTagSet.TAG_NEW_SUBFILE_TYPE);
0633: if (f != null) {
0634: int newSubFileType = f.getAsInt(0);
0635: String value = null;
0636: if ((newSubFileType & BaselineTIFFTagSet.NEW_SUBFILE_TYPE_TRANSPARENCY) != 0) {
0637: value = "TransparencyMask";
0638: } else if ((newSubFileType & BaselineTIFFTagSet.NEW_SUBFILE_TYPE_REDUCED_RESOLUTION) != 0) {
0639: value = "ReducedResolution";
0640: } else if ((newSubFileType & BaselineTIFFTagSet.NEW_SUBFILE_TYPE_SINGLE_PAGE) != 0) {
0641: value = "SinglePage";
0642: }
0643: if (value != null) {
0644: node = new IIOMetadataNode("SubimageInterpretation");
0645: node.setAttribute("value", value);
0646: document_node.appendChild(node);
0647: }
0648: }
0649:
0650: f = getTIFFField(BaselineTIFFTagSet.TAG_DATE_TIME);
0651: if (f != null) {
0652: String s = f.getAsString(0);
0653:
0654: // DateTime should be formatted as "YYYY:MM:DD hh:mm:ss".
0655: if (s.length() == 19) {
0656: node = new IIOMetadataNode("ImageCreationTime");
0657:
0658: // Files with incorrect DateTime format have been
0659: // observed so anticipate an exception from substring()
0660: // and only add the node if the format is presumably
0661: // correct.
0662: boolean appendNode;
0663: try {
0664: node.setAttribute("year", s.substring(0, 4));
0665: node.setAttribute("month", s.substring(5, 7));
0666: node.setAttribute("day", s.substring(8, 10));
0667: node.setAttribute("hour", s.substring(11, 13));
0668: node.setAttribute("minute", s.substring(14, 16));
0669: node.setAttribute("second", s.substring(17, 19));
0670: appendNode = true;
0671: } catch (IndexOutOfBoundsException e) {
0672: appendNode = false;
0673: }
0674:
0675: if (appendNode) {
0676: document_node.appendChild(node);
0677: }
0678: }
0679: }
0680:
0681: return document_node;
0682: }
0683:
0684: public IIOMetadataNode getStandardTextNode() {
0685: IIOMetadataNode text_node = null;
0686: IIOMetadataNode node = null; // scratch node
0687:
0688: TIFFField f;
0689:
0690: int[] textFieldTagNumbers = new int[] {
0691: BaselineTIFFTagSet.TAG_DOCUMENT_NAME,
0692: BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION,
0693: BaselineTIFFTagSet.TAG_MAKE,
0694: BaselineTIFFTagSet.TAG_MODEL,
0695: BaselineTIFFTagSet.TAG_PAGE_NAME,
0696: BaselineTIFFTagSet.TAG_SOFTWARE,
0697: BaselineTIFFTagSet.TAG_ARTIST,
0698: BaselineTIFFTagSet.TAG_HOST_COMPUTER,
0699: BaselineTIFFTagSet.TAG_INK_NAMES,
0700: BaselineTIFFTagSet.TAG_COPYRIGHT };
0701:
0702: for (int i = 0; i < textFieldTagNumbers.length; i++) {
0703: f = getTIFFField(textFieldTagNumbers[i]);
0704: if (f != null) {
0705: String value = f.getAsString(0);
0706: if (text_node == null) {
0707: text_node = new IIOMetadataNode("Text");
0708: }
0709: node = new IIOMetadataNode("TextEntry");
0710: node.setAttribute("keyword", f.getTag().getName());
0711: node.setAttribute("value", value);
0712: text_node.appendChild(node);
0713: }
0714: }
0715:
0716: return text_node;
0717: }
0718:
0719: public IIOMetadataNode getStandardTransparencyNode() {
0720: IIOMetadataNode transparency_node = new IIOMetadataNode(
0721: "Transparency");
0722: IIOMetadataNode node = null; // scratch node
0723:
0724: TIFFField f;
0725:
0726: node = new IIOMetadataNode("Alpha");
0727: String value = "none";
0728:
0729: f = getTIFFField(BaselineTIFFTagSet.TAG_EXTRA_SAMPLES);
0730: if (f != null) {
0731: int[] extraSamples = f.getAsInts();
0732: for (int i = 0; i < extraSamples.length; i++) {
0733: if (extraSamples[i] == BaselineTIFFTagSet.EXTRA_SAMPLES_ASSOCIATED_ALPHA) {
0734: value = "premultiplied";
0735: break;
0736: } else if (extraSamples[i] == BaselineTIFFTagSet.EXTRA_SAMPLES_UNASSOCIATED_ALPHA) {
0737: value = "nonpremultiplied";
0738: break;
0739: }
0740: }
0741: }
0742:
0743: node.setAttribute("value", value);
0744: transparency_node.appendChild(node);
0745:
0746: return transparency_node;
0747: }
0748:
0749: // Shorthand for throwing an IIOInvalidTreeException
0750: private static void fatal(Node node, String reason)
0751: throws IIOInvalidTreeException {
0752: throw new IIOInvalidTreeException(reason, node);
0753: }
0754:
0755: private int[] listToIntArray(String list) {
0756: StringTokenizer st = new StringTokenizer(list, " ");
0757: ArrayList intList = new ArrayList();
0758: while (st.hasMoreTokens()) {
0759: String nextInteger = st.nextToken();
0760: Integer nextInt = new Integer(nextInteger);
0761: intList.add(nextInt);
0762: }
0763:
0764: int[] intArray = new int[intList.size()];
0765: for (int i = 0; i < intArray.length; i++) {
0766: intArray[i] = ((Integer) intList.get(i)).intValue();
0767: }
0768:
0769: return intArray;
0770: }
0771:
0772: private char[] listToCharArray(String list) {
0773: StringTokenizer st = new StringTokenizer(list, " ");
0774: ArrayList intList = new ArrayList();
0775: while (st.hasMoreTokens()) {
0776: String nextInteger = st.nextToken();
0777: Integer nextInt = new Integer(nextInteger);
0778: intList.add(nextInt);
0779: }
0780:
0781: char[] charArray = new char[intList.size()];
0782: for (int i = 0; i < charArray.length; i++) {
0783: charArray[i] = (char) ((Integer) intList.get(i)).intValue();
0784: }
0785:
0786: return charArray;
0787: }
0788:
0789: private void mergeStandardTree(Node root)
0790: throws IIOInvalidTreeException {
0791: TIFFField f;
0792: TIFFTag tag;
0793:
0794: Node node = root;
0795: if (!node.getNodeName().equals(
0796: IIOMetadataFormatImpl.standardMetadataFormatName)) {
0797: fatal(node, "Root must be "
0798: + IIOMetadataFormatImpl.standardMetadataFormatName);
0799: }
0800:
0801: // Obtain the sample format and set the palette flag if appropriate.
0802: String sampleFormat = null;
0803: Node dataNode = getChildNode(root, "Data");
0804: boolean isPaletteColor = false;
0805: if (dataNode != null) {
0806: Node sampleFormatNode = getChildNode(dataNode,
0807: "SampleFormat");
0808: if (sampleFormatNode != null) {
0809: sampleFormat = getAttribute(sampleFormatNode, "value");
0810: isPaletteColor = sampleFormat.equals("Index");
0811: }
0812: }
0813:
0814: // If palette flag not set check for palette.
0815: if (!isPaletteColor) {
0816: Node chromaNode = getChildNode(root, "Chroma");
0817: if (chromaNode != null
0818: && getChildNode(chromaNode, "Palette") != null) {
0819: isPaletteColor = true;
0820: }
0821: }
0822:
0823: node = node.getFirstChild();
0824: while (node != null) {
0825: String name = node.getNodeName();
0826:
0827: if (name.equals("Chroma")) {
0828: String colorSpaceType = null;
0829: String blackIsZero = null;
0830: boolean gotPalette = false;
0831: Node child = node.getFirstChild();
0832: while (child != null) {
0833: String childName = child.getNodeName();
0834: if (childName.equals("ColorSpaceType")) {
0835: colorSpaceType = getAttribute(child, "name");
0836: } else if (childName.equals("NumChannels")) {
0837: tag = rootIFD
0838: .getTag(BaselineTIFFTagSet.TAG_SAMPLES_PER_PIXEL);
0839: int samplesPerPixel = isPaletteColor ? 1
0840: : Integer.parseInt(getAttribute(child,
0841: "value"));
0842: f = new TIFFField(tag, samplesPerPixel);
0843: rootIFD.addTIFFField(f);
0844: } else if (childName.equals("BlackIsZero")) {
0845: blackIsZero = getAttribute(child, "value");
0846: } else if (childName.equals("Palette")) {
0847: Node entry = child.getFirstChild();
0848: HashMap palette = new HashMap();
0849: int maxIndex = -1;
0850: while (entry != null) {
0851: String entryName = entry.getNodeName();
0852: if (entryName.equals("PaletteEntry")) {
0853: String idx = getAttribute(entry,
0854: "index");
0855: int id = Integer.parseInt(idx);
0856: if (id > maxIndex) {
0857: maxIndex = id;
0858: }
0859: char red = (char) Integer
0860: .parseInt(getAttribute(entry,
0861: "red"));
0862: char green = (char) Integer
0863: .parseInt(getAttribute(entry,
0864: "green"));
0865: char blue = (char) Integer
0866: .parseInt(getAttribute(entry,
0867: "blue"));
0868: palette
0869: .put(new Integer(id),
0870: new char[] { red,
0871: green, blue });
0872:
0873: gotPalette = true;
0874: }
0875: entry = entry.getNextSibling();
0876: }
0877:
0878: if (gotPalette) {
0879: int mapSize = maxIndex + 1;
0880: int paletteLength = 3 * mapSize;
0881: char[] paletteEntries = new char[paletteLength];
0882: Iterator paletteIter = palette.keySet()
0883: .iterator();
0884: while (paletteIter.hasNext()) {
0885: Integer index = (Integer) paletteIter
0886: .next();
0887: char[] rgb = (char[]) palette
0888: .get(index);
0889: int idx = index.intValue();
0890: paletteEntries[idx] = (char) ((rgb[0] * 65535) / 255);
0891: paletteEntries[mapSize + idx] = (char) ((rgb[1] * 65535) / 255);
0892: paletteEntries[2 * mapSize + idx] = (char) ((rgb[2] * 65535) / 255);
0893: }
0894:
0895: tag = rootIFD
0896: .getTag(BaselineTIFFTagSet.TAG_COLOR_MAP);
0897: f = new TIFFField(tag, TIFFTag.TIFF_SHORT,
0898: paletteLength, paletteEntries);
0899: rootIFD.addTIFFField(f);
0900: }
0901: }
0902:
0903: child = child.getNextSibling();
0904: }
0905:
0906: int photometricInterpretation = -1;
0907: if ((colorSpaceType == null || colorSpaceType
0908: .equals("GRAY"))
0909: && blackIsZero != null
0910: && blackIsZero.equalsIgnoreCase("FALSE")) {
0911: photometricInterpretation = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO;
0912: } else if (colorSpaceType != null) {
0913: if (colorSpaceType.equals("GRAY")) {
0914: boolean isTransparency = false;
0915: if (root instanceof IIOMetadataNode) {
0916: IIOMetadataNode iioRoot = (IIOMetadataNode) root;
0917: NodeList siNodeList = iioRoot
0918: .getElementsByTagName("SubimageInterpretation");
0919: if (siNodeList.getLength() == 1) {
0920: Node siNode = siNodeList.item(0);
0921: String value = getAttribute(siNode,
0922: "value");
0923: if (value.equals("TransparencyMask")) {
0924: isTransparency = true;
0925: }
0926: }
0927: }
0928: if (isTransparency) {
0929: photometricInterpretation = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_TRANSPARENCY_MASK;
0930: } else {
0931: photometricInterpretation = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO;
0932: }
0933: } else if (colorSpaceType.equals("RGB")) {
0934: photometricInterpretation = gotPalette ? BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_PALETTE_COLOR
0935: : BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_RGB;
0936: } else if (colorSpaceType.equals("YCbCr")) {
0937: photometricInterpretation = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_Y_CB_CR;
0938: } else if (colorSpaceType.equals("CMYK")) {
0939: photometricInterpretation = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_CMYK;
0940: } else if (colorSpaceType.equals("Lab")) {
0941: photometricInterpretation = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_CIELAB;
0942: }
0943: }
0944:
0945: if (photometricInterpretation != -1) {
0946: tag = rootIFD
0947: .getTag(BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION);
0948: f = new TIFFField(tag, photometricInterpretation);
0949: rootIFD.addTIFFField(f);
0950: }
0951: } else if (name.equals("Compression")) {
0952: Node child = node.getFirstChild();
0953: while (child != null) {
0954: String childName = child.getNodeName();
0955: if (childName.equals("CompressionTypeName")) {
0956: int compression = -1;
0957: String compressionTypeName = getAttribute(
0958: child, "value");
0959: if (compressionTypeName
0960: .equalsIgnoreCase("None")) {
0961: compression = BaselineTIFFTagSet.COMPRESSION_NONE;
0962: } else {
0963: String[] compressionNames = TIFFImageWriter.compressionTypes;
0964: for (int i = 0; i < compressionNames.length; i++) {
0965: if (compressionNames[i]
0966: .equalsIgnoreCase(compressionTypeName)) {
0967: compression = TIFFImageWriter.compressionNumbers[i];
0968: break;
0969: }
0970: }
0971: }
0972:
0973: if (compression != -1) {
0974: tag = rootIFD
0975: .getTag(BaselineTIFFTagSet.TAG_COMPRESSION);
0976: f = new TIFFField(tag, compression);
0977: rootIFD.addTIFFField(f);
0978:
0979: // Lossless is irrelevant.
0980: }
0981: }
0982:
0983: child = child.getNextSibling();
0984: }
0985: } else if (name.equals("Data")) {
0986: Node child = node.getFirstChild();
0987: while (child != null) {
0988: String childName = child.getNodeName();
0989:
0990: if (childName.equals("PlanarConfiguration")) {
0991: String pc = getAttribute(child, "value");
0992: int planarConfiguration = -1;
0993: if (pc.equals("PixelInterleaved")) {
0994: planarConfiguration = BaselineTIFFTagSet.PLANAR_CONFIGURATION_CHUNKY;
0995: } else if (pc.equals("PlaneInterleaved")) {
0996: planarConfiguration = BaselineTIFFTagSet.PLANAR_CONFIGURATION_PLANAR;
0997: }
0998: if (planarConfiguration != -1) {
0999: tag = rootIFD
1000: .getTag(BaselineTIFFTagSet.TAG_PLANAR_CONFIGURATION);
1001: f = new TIFFField(tag, planarConfiguration);
1002: rootIFD.addTIFFField(f);
1003: }
1004: } else if (childName.equals("BitsPerSample")) {
1005: String bps = getAttribute(child, "value");
1006: char[] bitsPerSample = listToCharArray(bps);
1007: tag = rootIFD
1008: .getTag(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE);
1009: if (isPaletteColor) {
1010: f = new TIFFField(tag, TIFFTag.TIFF_SHORT,
1011: 1, new char[] { bitsPerSample[0] });
1012: } else {
1013: f = new TIFFField(tag, TIFFTag.TIFF_SHORT,
1014: bitsPerSample.length, bitsPerSample);
1015: }
1016: rootIFD.addTIFFField(f);
1017: } else if (childName.equals("SampleMSB")) {
1018: // Add FillOrder only if lsb-to-msb (right to left)
1019: // for all bands, i.e., SampleMSB is zero for all
1020: // channels.
1021: String sMSB = getAttribute(child, "value");
1022: int[] sampleMSB = listToIntArray(sMSB);
1023: boolean isRightToLeft = true;
1024: for (int i = 0; i < sampleMSB.length; i++) {
1025: if (sampleMSB[i] != 0) {
1026: isRightToLeft = false;
1027: break;
1028: }
1029: }
1030: int fillOrder = isRightToLeft ? BaselineTIFFTagSet.FILL_ORDER_RIGHT_TO_LEFT
1031: : BaselineTIFFTagSet.FILL_ORDER_LEFT_TO_RIGHT;
1032: tag = rootIFD
1033: .getTag(BaselineTIFFTagSet.TAG_FILL_ORDER);
1034: f = new TIFFField(tag, fillOrder);
1035: rootIFD.addTIFFField(f);
1036: }
1037:
1038: child = child.getNextSibling();
1039: }
1040: } else if (name.equals("Dimension")) {
1041: float pixelAspectRatio = -1.0f;
1042: boolean gotPixelAspectRatio = false;
1043:
1044: float horizontalPixelSize = -1.0f;
1045: boolean gotHorizontalPixelSize = false;
1046:
1047: float verticalPixelSize = -1.0f;
1048: boolean gotVerticalPixelSize = false;
1049:
1050: boolean sizeIsAbsolute = false;
1051:
1052: float horizontalPosition = -1.0f;
1053: boolean gotHorizontalPosition = false;
1054:
1055: float verticalPosition = -1.0f;
1056: boolean gotVerticalPosition = false;
1057:
1058: Node child = node.getFirstChild();
1059: while (child != null) {
1060: String childName = child.getNodeName();
1061: if (childName.equals("PixelAspectRatio")) {
1062: String par = getAttribute(child, "value");
1063: pixelAspectRatio = Float.parseFloat(par);
1064: gotPixelAspectRatio = true;
1065: } else if (childName.equals("ImageOrientation")) {
1066: String orientation = getAttribute(child,
1067: "value");
1068: for (int i = 0; i < orientationNames.length; i++) {
1069: if (orientation.equals(orientationNames[i])) {
1070: char[] oData = new char[1];
1071: oData[0] = (char) i;
1072:
1073: f = new TIFFField(
1074: rootIFD
1075: .getTag(BaselineTIFFTagSet.TAG_ORIENTATION),
1076: TIFFTag.TIFF_SHORT, 1, oData);
1077:
1078: rootIFD.addTIFFField(f);
1079: break;
1080: }
1081: }
1082:
1083: } else if (childName.equals("HorizontalPixelSize")) {
1084: String hps = getAttribute(child, "value");
1085: horizontalPixelSize = Float.parseFloat(hps);
1086: gotHorizontalPixelSize = true;
1087: } else if (childName.equals("VerticalPixelSize")) {
1088: String vps = getAttribute(child, "value");
1089: verticalPixelSize = Float.parseFloat(vps);
1090: gotVerticalPixelSize = true;
1091: } else if (childName.equals("HorizontalPosition")) {
1092: String hp = getAttribute(child, "value");
1093: horizontalPosition = Float.parseFloat(hp);
1094: gotHorizontalPosition = true;
1095: } else if (childName.equals("VerticalPosition")) {
1096: String vp = getAttribute(child, "value");
1097: verticalPosition = Float.parseFloat(vp);
1098: gotVerticalPosition = true;
1099: }
1100:
1101: child = child.getNextSibling();
1102: }
1103:
1104: sizeIsAbsolute = gotHorizontalPixelSize
1105: || gotVerticalPixelSize;
1106:
1107: // Fill in pixel size data from aspect ratio
1108: if (gotPixelAspectRatio) {
1109: if (gotHorizontalPixelSize && !gotVerticalPixelSize) {
1110: verticalPixelSize = horizontalPixelSize
1111: / pixelAspectRatio;
1112: gotVerticalPixelSize = true;
1113: } else if (gotVerticalPixelSize
1114: && !gotHorizontalPixelSize) {
1115: horizontalPixelSize = verticalPixelSize
1116: * pixelAspectRatio;
1117: gotHorizontalPixelSize = true;
1118: } else if (!gotHorizontalPixelSize
1119: && !gotVerticalPixelSize) {
1120: horizontalPixelSize = pixelAspectRatio;
1121: verticalPixelSize = 1.0f;
1122: gotHorizontalPixelSize = true;
1123: gotVerticalPixelSize = true;
1124: }
1125: }
1126:
1127: // Compute pixels/centimeter
1128: if (gotHorizontalPixelSize) {
1129: float xResolution = (sizeIsAbsolute ? 10.0f : 1.0f)
1130: / horizontalPixelSize;
1131: long[][] hData = new long[1][2];
1132: hData[0] = new long[2];
1133: hData[0][0] = (long) (xResolution * 10000.0f);
1134: hData[0][1] = (long) 10000;
1135:
1136: f = new TIFFField(
1137: rootIFD
1138: .getTag(BaselineTIFFTagSet.TAG_X_RESOLUTION),
1139: TIFFTag.TIFF_RATIONAL, 1, hData);
1140: rootIFD.addTIFFField(f);
1141: }
1142:
1143: if (gotVerticalPixelSize) {
1144: float yResolution = (sizeIsAbsolute ? 10.0f : 1.0f)
1145: / verticalPixelSize;
1146: long[][] vData = new long[1][2];
1147: vData[0] = new long[2];
1148: vData[0][0] = (long) (yResolution * 10000.0f);
1149: vData[0][1] = (long) 10000;
1150:
1151: f = new TIFFField(
1152: rootIFD
1153: .getTag(BaselineTIFFTagSet.TAG_Y_RESOLUTION),
1154: TIFFTag.TIFF_RATIONAL, 1, vData);
1155: rootIFD.addTIFFField(f);
1156: }
1157:
1158: // Emit ResolutionUnit tag
1159: char[] res = new char[1];
1160: res[0] = (char) (sizeIsAbsolute ? BaselineTIFFTagSet.RESOLUTION_UNIT_CENTIMETER
1161: : BaselineTIFFTagSet.RESOLUTION_UNIT_NONE);
1162:
1163: f = new TIFFField(
1164: rootIFD
1165: .getTag(BaselineTIFFTagSet.TAG_RESOLUTION_UNIT),
1166: TIFFTag.TIFF_SHORT, 1, res);
1167: rootIFD.addTIFFField(f);
1168:
1169: // Position
1170: if (sizeIsAbsolute) {
1171: if (gotHorizontalPosition) {
1172: // Convert from millimeters to centimeters via
1173: // numerator multiplier = denominator/10.
1174: long[][] hData = new long[1][2];
1175: hData[0][0] = (long) (horizontalPosition * 10000.0f);
1176: hData[0][1] = (long) 100000;
1177:
1178: f = new TIFFField(
1179: rootIFD
1180: .getTag(BaselineTIFFTagSet.TAG_X_POSITION),
1181: TIFFTag.TIFF_RATIONAL, 1, hData);
1182: rootIFD.addTIFFField(f);
1183: }
1184:
1185: if (gotVerticalPosition) {
1186: // Convert from millimeters to centimeters via
1187: // numerator multiplier = denominator/10.
1188: long[][] vData = new long[1][2];
1189: vData[0][0] = (long) (verticalPosition * 10000.0f);
1190: vData[0][1] = (long) 100000;
1191:
1192: f = new TIFFField(
1193: rootIFD
1194: .getTag(BaselineTIFFTagSet.TAG_Y_POSITION),
1195: TIFFTag.TIFF_RATIONAL, 1, vData);
1196: rootIFD.addTIFFField(f);
1197: }
1198: }
1199: } else if (name.equals("Document")) {
1200: Node child = node.getFirstChild();
1201: while (child != null) {
1202: String childName = child.getNodeName();
1203:
1204: if (childName.equals("SubimageInterpretation")) {
1205: String si = getAttribute(child, "value");
1206: int newSubFileType = -1;
1207: if (si.equals("TransparencyMask")) {
1208: newSubFileType = BaselineTIFFTagSet.NEW_SUBFILE_TYPE_TRANSPARENCY;
1209: } else if (si.equals("ReducedResolution")) {
1210: newSubFileType = BaselineTIFFTagSet.NEW_SUBFILE_TYPE_REDUCED_RESOLUTION;
1211: } else if (si.equals("SinglePage")) {
1212: newSubFileType = BaselineTIFFTagSet.NEW_SUBFILE_TYPE_SINGLE_PAGE;
1213: }
1214: if (newSubFileType != -1) {
1215: tag = rootIFD
1216: .getTag(BaselineTIFFTagSet.TAG_NEW_SUBFILE_TYPE);
1217: f = new TIFFField(tag, newSubFileType);
1218: rootIFD.addTIFFField(f);
1219: }
1220: }
1221:
1222: if (childName.equals("ImageCreationTime")) {
1223: String year = getAttribute(child, "year");
1224: String month = getAttribute(child, "month");
1225: String day = getAttribute(child, "day");
1226: String hour = getAttribute(child, "hour");
1227: String minute = getAttribute(child, "minute");
1228: String second = getAttribute(child, "second");
1229:
1230: StringBuffer sb = new StringBuffer();
1231: sb.append(year);
1232: sb.append(":");
1233: if (month.length() == 1) {
1234: sb.append("0");
1235: }
1236: sb.append(month);
1237: sb.append(":");
1238: if (day.length() == 1) {
1239: sb.append("0");
1240: }
1241: sb.append(day);
1242: sb.append(" ");
1243: if (hour.length() == 1) {
1244: sb.append("0");
1245: }
1246: sb.append(hour);
1247: sb.append(":");
1248: if (minute.length() == 1) {
1249: sb.append("0");
1250: }
1251: sb.append(minute);
1252: sb.append(":");
1253: if (second.length() == 1) {
1254: sb.append("0");
1255: }
1256: sb.append(second);
1257:
1258: String[] dt = new String[1];
1259: dt[0] = sb.toString();
1260:
1261: f = new TIFFField(
1262: rootIFD
1263: .getTag(BaselineTIFFTagSet.TAG_DATE_TIME),
1264: TIFFTag.TIFF_ASCII, 1, dt);
1265: rootIFD.addTIFFField(f);
1266: }
1267:
1268: child = child.getNextSibling();
1269: }
1270: } else if (name.equals("Text")) {
1271: Node child = node.getFirstChild();
1272: String theAuthor = null;
1273: String theDescription = null;
1274: String theTitle = null;
1275: while (child != null) {
1276: String childName = child.getNodeName();
1277: if (childName.equals("TextEntry")) {
1278: int tagNumber = -1;
1279: NamedNodeMap childAttrs = child.getAttributes();
1280: Node keywordNode = childAttrs
1281: .getNamedItem("keyword");
1282: if (keywordNode != null) {
1283: String keyword = keywordNode.getNodeValue();
1284: String value = getAttribute(child, "value");
1285: if (!keyword.equals("")
1286: && !value.equals("")) {
1287: if (keyword
1288: .equalsIgnoreCase("DocumentName")) {
1289: tagNumber = BaselineTIFFTagSet.TAG_DOCUMENT_NAME;
1290: } else if (keyword
1291: .equalsIgnoreCase("ImageDescription")) {
1292: tagNumber = BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION;
1293: } else if (keyword
1294: .equalsIgnoreCase("Make")) {
1295: tagNumber = BaselineTIFFTagSet.TAG_MAKE;
1296: } else if (keyword
1297: .equalsIgnoreCase("Model")) {
1298: tagNumber = BaselineTIFFTagSet.TAG_MODEL;
1299: } else if (keyword
1300: .equalsIgnoreCase("PageName")) {
1301: tagNumber = BaselineTIFFTagSet.TAG_PAGE_NAME;
1302: } else if (keyword
1303: .equalsIgnoreCase("Software")) {
1304: tagNumber = BaselineTIFFTagSet.TAG_SOFTWARE;
1305: } else if (keyword
1306: .equalsIgnoreCase("Artist")) {
1307: tagNumber = BaselineTIFFTagSet.TAG_ARTIST;
1308: } else if (keyword
1309: .equalsIgnoreCase("HostComputer")) {
1310: tagNumber = BaselineTIFFTagSet.TAG_HOST_COMPUTER;
1311: } else if (keyword
1312: .equalsIgnoreCase("InkNames")) {
1313: tagNumber = BaselineTIFFTagSet.TAG_INK_NAMES;
1314: } else if (keyword
1315: .equalsIgnoreCase("Copyright")) {
1316: tagNumber = BaselineTIFFTagSet.TAG_COPYRIGHT;
1317: } else if (keyword
1318: .equalsIgnoreCase("author")) {
1319: theAuthor = value;
1320: } else if (keyword
1321: .equalsIgnoreCase("description")) {
1322: theDescription = value;
1323: } else if (keyword
1324: .equalsIgnoreCase("title")) {
1325: theTitle = value;
1326: }
1327: if (tagNumber != -1) {
1328: f = new TIFFField(rootIFD
1329: .getTag(tagNumber),
1330: TIFFTag.TIFF_ASCII, 1,
1331: new String[] { value });
1332: rootIFD.addTIFFField(f);
1333: }
1334: }
1335: }
1336: }
1337: child = child.getNextSibling();
1338: } // child != null
1339: if (theAuthor != null
1340: && getTIFFField(BaselineTIFFTagSet.TAG_ARTIST) == null) {
1341: f = new TIFFField(rootIFD
1342: .getTag(BaselineTIFFTagSet.TAG_ARTIST),
1343: TIFFTag.TIFF_ASCII, 1,
1344: new String[] { theAuthor });
1345: rootIFD.addTIFFField(f);
1346: }
1347: if (theDescription != null
1348: && getTIFFField(BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION) == null) {
1349: f = new TIFFField(
1350: rootIFD
1351: .getTag(BaselineTIFFTagSet.TAG_IMAGE_DESCRIPTION),
1352: TIFFTag.TIFF_ASCII, 1,
1353: new String[] { theDescription });
1354: rootIFD.addTIFFField(f);
1355: }
1356: if (theTitle != null
1357: && getTIFFField(BaselineTIFFTagSet.TAG_DOCUMENT_NAME) == null) {
1358: f = new TIFFField(
1359: rootIFD
1360: .getTag(BaselineTIFFTagSet.TAG_DOCUMENT_NAME),
1361: TIFFTag.TIFF_ASCII, 1,
1362: new String[] { theTitle });
1363: rootIFD.addTIFFField(f);
1364: }
1365: } else if (name.equals("Transparency")) {
1366: Node child = node.getFirstChild();
1367: while (child != null) {
1368: String childName = child.getNodeName();
1369:
1370: if (childName.equals("Alpha")) {
1371: String alpha = getAttribute(child, "value");
1372:
1373: f = null;
1374: if (alpha.equals("premultiplied")) {
1375: f = new TIFFField(
1376: rootIFD
1377: .getTag(BaselineTIFFTagSet.TAG_EXTRA_SAMPLES),
1378: BaselineTIFFTagSet.EXTRA_SAMPLES_ASSOCIATED_ALPHA);
1379: } else if (alpha.equals("nonpremultiplied")) {
1380: f = new TIFFField(
1381: rootIFD
1382: .getTag(BaselineTIFFTagSet.TAG_EXTRA_SAMPLES),
1383: BaselineTIFFTagSet.EXTRA_SAMPLES_UNASSOCIATED_ALPHA);
1384: }
1385: if (f != null) {
1386: rootIFD.addTIFFField(f);
1387: }
1388: }
1389:
1390: child = child.getNextSibling();
1391: }
1392: }
1393:
1394: node = node.getNextSibling();
1395: }
1396:
1397: // Set SampleFormat.
1398: if (sampleFormat != null) {
1399: // Derive the value.
1400: int sf = -1;
1401: if (sampleFormat.equals("SignedIntegral")) {
1402: sf = BaselineTIFFTagSet.SAMPLE_FORMAT_SIGNED_INTEGER;
1403: } else if (sampleFormat.equals("UnsignedIntegral")) {
1404: sf = BaselineTIFFTagSet.SAMPLE_FORMAT_UNSIGNED_INTEGER;
1405: } else if (sampleFormat.equals("Real")) {
1406: sf = BaselineTIFFTagSet.SAMPLE_FORMAT_FLOATING_POINT;
1407: } else if (sampleFormat.equals("Index")) {
1408: sf = BaselineTIFFTagSet.SAMPLE_FORMAT_UNSIGNED_INTEGER;
1409: }
1410:
1411: if (sf != -1) {
1412: // Derive the count.
1413: int count = 1;
1414:
1415: // Try SamplesPerPixel first.
1416: f = getTIFFField(BaselineTIFFTagSet.TAG_SAMPLES_PER_PIXEL);
1417: if (f != null) {
1418: count = f.getAsInt(0);
1419: } else {
1420: // Try BitsPerSample.
1421: f = getTIFFField(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE);
1422: if (f != null) {
1423: count = f.getCount();
1424: }
1425: }
1426:
1427: char[] sampleFormatArray = new char[count];
1428: Arrays.fill(sampleFormatArray, (char) sf);
1429:
1430: // Add SampleFormat.
1431: tag = rootIFD
1432: .getTag(BaselineTIFFTagSet.TAG_SAMPLE_FORMAT);
1433: f = new TIFFField(tag, TIFFTag.TIFF_SHORT,
1434: sampleFormatArray.length, sampleFormatArray);
1435: rootIFD.addTIFFField(f);
1436: }
1437: }
1438: }
1439:
1440: private static String getAttribute(Node node, String attrName) {
1441: NamedNodeMap attrs = node.getAttributes();
1442: Node attr = attrs.getNamedItem(attrName);
1443: return attr != null ? attr.getNodeValue() : null;
1444: }
1445:
1446: private Node getChildNode(Node node, String childName) {
1447: Node childNode = null;
1448: if (node.hasChildNodes()) {
1449: NodeList childNodes = node.getChildNodes();
1450: int length = childNodes.getLength();
1451: for (int i = 0; i < length; i++) {
1452: Node item = childNodes.item(i);
1453: if (item.getNodeName().equals(childName)) {
1454: childNode = item;
1455: break;
1456: }
1457: }
1458: }
1459: return childNode;
1460: }
1461:
1462: public static TIFFIFD parseIFD(Node node)
1463: throws IIOInvalidTreeException {
1464: if (!node.getNodeName().equals("TIFFIFD")) {
1465: fatal(node, "Expected \"TIFFIFD\" node");
1466: }
1467:
1468: String tagSetNames = getAttribute(node, "tagSets");
1469: List tagSets = new ArrayList(5);
1470:
1471: if (tagSetNames != null) {
1472: StringTokenizer st = new StringTokenizer(tagSetNames, ",");
1473: while (st.hasMoreTokens()) {
1474: String className = st.nextToken();
1475:
1476: Object o = null;
1477: try {
1478: Class setClass = Class.forName(className);
1479: Method getInstanceMethod = setClass.getMethod(
1480: "getInstance", (Class[]) null);
1481: o = getInstanceMethod.invoke(null, (Object[]) null);
1482: } catch (NoSuchMethodException e) {
1483: throw new RuntimeException(e);
1484: } catch (IllegalAccessException e) {
1485: throw new RuntimeException(e);
1486: } catch (InvocationTargetException e) {
1487: throw new RuntimeException(e);
1488: } catch (ClassNotFoundException e) {
1489: throw new RuntimeException(e);
1490: }
1491:
1492: if (!(o instanceof TIFFTagSet)) {
1493: fatal(node, "Specified tag set class \""
1494: + className
1495: + "\" is not an instance of TIFFTagSet");
1496: } else {
1497: tagSets.add((TIFFTagSet) o);
1498: }
1499: }
1500: }
1501:
1502: TIFFIFD ifd = new TIFFIFD(tagSets);
1503:
1504: node = node.getFirstChild();
1505: while (node != null) {
1506: String name = node.getNodeName();
1507:
1508: TIFFField f = null;
1509: if (name.equals("TIFFIFD")) {
1510: TIFFIFD subIFD = parseIFD(node);
1511: String parentTagName = getAttribute(node,
1512: "parentTagName");
1513: String parentTagNumber = getAttribute(node,
1514: "parentTagNumber");
1515: TIFFTag tag = null;
1516: if (parentTagName != null) {
1517: tag = TIFFIFD.getTag(parentTagName, tagSets);
1518: } else if (parentTagNumber != null) {
1519: int tagNumber = Integer.valueOf(parentTagNumber)
1520: .intValue();
1521: tag = TIFFIFD.getTag(tagNumber, tagSets);
1522: }
1523:
1524: if (tag == null) {
1525: tag = new TIFFTag("unknown", 0, 0, null);
1526: }
1527:
1528: int type;
1529: if (tag.isDataTypeOK(TIFFTag.TIFF_IFD_POINTER)) {
1530: type = TIFFTag.TIFF_IFD_POINTER;
1531: } else {
1532: type = TIFFTag.TIFF_LONG;
1533: }
1534:
1535: f = new TIFFField(tag, type, 1, subIFD);
1536: } else if (name.equals("TIFFField")) {
1537: int number = Integer.parseInt(getAttribute(node,
1538: "number"));
1539:
1540: TIFFTagSet tagSet = null;
1541: Iterator iter = tagSets.iterator();
1542: while (iter.hasNext()) {
1543: TIFFTagSet t = (TIFFTagSet) iter.next();
1544: if (t.getTag(number) != null) {
1545: tagSet = t;
1546: break;
1547: }
1548: }
1549:
1550: f = TIFFField.createFromMetadataNode(tagSet, node);
1551: } else {
1552: fatal(node,
1553: "Expected either \"TIFFIFD\" or \"TIFFField\" node, got "
1554: + name);
1555: }
1556:
1557: ifd.addTIFFField(f);
1558: node = node.getNextSibling();
1559: }
1560:
1561: return ifd;
1562: }
1563:
1564: private void mergeNativeTree(Node root)
1565: throws IIOInvalidTreeException {
1566: Node node = root;
1567: if (!node.getNodeName().equals(nativeMetadataFormatName)) {
1568: fatal(node, "Root must be " + nativeMetadataFormatName);
1569: }
1570:
1571: node = node.getFirstChild();
1572: if (node == null || !node.getNodeName().equals("TIFFIFD")) {
1573: fatal(root, "Root must have \"TIFFIFD\" child");
1574: }
1575: TIFFIFD ifd = parseIFD(node);
1576:
1577: List rootIFDTagSets = rootIFD.getTagSetList();
1578: Iterator tagSetIter = ifd.getTagSetList().iterator();
1579: while (tagSetIter.hasNext()) {
1580: Object o = tagSetIter.next();
1581: if (o instanceof TIFFTagSet && !rootIFDTagSets.contains(o)) {
1582: rootIFD.addTagSet((TIFFTagSet) o);
1583: }
1584: }
1585:
1586: Iterator ifdIter = ifd.iterator();
1587: while (ifdIter.hasNext()) {
1588: TIFFField field = (TIFFField) ifdIter.next();
1589: rootIFD.addTIFFField(field);
1590: }
1591: }
1592:
1593: public void mergeTree(String formatName, Node root)
1594: throws IIOInvalidTreeException {
1595: if (formatName.equals(nativeMetadataFormatName)) {
1596: if (root == null) {
1597: throw new IllegalArgumentException("root == null!");
1598: }
1599: mergeNativeTree(root);
1600: } else if (formatName
1601: .equals(IIOMetadataFormatImpl.standardMetadataFormatName)) {
1602: if (root == null) {
1603: throw new IllegalArgumentException("root == null!");
1604: }
1605: mergeStandardTree(root);
1606: } else {
1607: throw new IllegalArgumentException(
1608: "Not a recognized format!");
1609: }
1610: }
1611:
1612: public void reset() {
1613: rootIFD = new TIFFIFD(tagSets);
1614: }
1615:
1616: public TIFFIFD getRootIFD() {
1617: return rootIFD;
1618: }
1619:
1620: public TIFFField getTIFFField(int tagNumber) {
1621: return rootIFD.getTIFFField(tagNumber);
1622: }
1623:
1624: public void removeTIFFField(int tagNumber) {
1625: rootIFD.removeTIFFField(tagNumber);
1626: }
1627:
1628: /**
1629: * Returns a <code>TIFFImageMetadata</code> wherein all fields in the
1630: * root IFD from the <code>BaselineTIFFTagSet</code> are copied by value
1631: * and all other fields copied by reference.
1632: */
1633: public TIFFImageMetadata getShallowClone() {
1634: return new TIFFImageMetadata(rootIFD.getShallowClone());
1635: }
1636: }
|