0001: /*
0002: * $RCSfile: TIFFField.java,v $
0003: *
0004: *
0005: * Copyright (c) 2006 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.4 $
0042: * $Date: 2006/04/28 01:28:49 $
0043: * $State: Exp $
0044: */
0045: package com.sun.media.imageio.plugins.tiff;
0046:
0047: import java.io.IOException;
0048: import java.io.Serializable;
0049: import java.util.StringTokenizer;
0050: import javax.imageio.metadata.IIOMetadataNode;
0051: import javax.imageio.stream.ImageOutputStream;
0052: import org.w3c.dom.NamedNodeMap;
0053: import org.w3c.dom.Node;
0054: import com.sun.media.imageio.plugins.tiff.TIFFTag;
0055: import com.sun.media.imageio.plugins.tiff.TIFFTagSet;
0056: import com.sun.media.imageioimpl.plugins.tiff.TIFFFieldNode;
0057:
0058: /**
0059: * A class representing a field in a TIFF 6.0 Image File Directory.
0060: *
0061: * <p> A field in a TIFF Image File Directory (IFD) is defined as a
0062: * tag number accompanied by a sequence of values of identical data type.
0063: * TIFF 6.0 defines 12 data types; a 13th type <code>IFD</code> is
0064: * defined in TIFF Tech Note 1 of TIFF Specification Supplement 1. These
0065: * TIFF data types are referred to by Java constants and mapped internally
0066: * onto Java language data types and type names as follows:
0067: *
0068: * <br>
0069: * <br>
0070: * <table border="1">
0071: *
0072: * <tr>
0073: * <th>
0074: * <b>TIFF Data Type</b>
0075: * </th>
0076: * <th>
0077: * <b>Java Constant</b>
0078: * </th>
0079: * <th>
0080: * <b>Java Data Type</b>
0081: * </th>
0082: * <th>
0083: * <b>Java Type Name</b>
0084: * </th>
0085: * </tr>
0086: *
0087: * <tr>
0088: * <td>
0089: * <tt>BYTE</tt>
0090: * </td>
0091: * <td>
0092: * {@link TIFFTag#TIFF_BYTE}
0093: * </td>
0094: * <td>
0095: * <code>byte</code>
0096: * </td>
0097: * <td>
0098: * <code>"Byte"</code>
0099: * </td>
0100: * </tr>
0101: *
0102: * <tr>
0103: * <td>
0104: * <tt>ASCII</tt>
0105: * </td>
0106: * <td>
0107: * {@link TIFFTag#TIFF_ASCII}
0108: * </td>
0109: * <td>
0110: * <code>String</code>
0111: * </td>
0112: * <td>
0113: * <code>"Ascii"</code>
0114: * </td>
0115: * </tr>
0116: *
0117: * <tr>
0118: * <td>
0119: * <tt>SHORT</tt>
0120: * </td>
0121: * <td>
0122: * {@link TIFFTag#TIFF_SHORT}
0123: * </td>
0124: * <td>
0125: * <code>char</code>
0126: * </td>
0127: * <td>
0128: * <code>"Short"</code>
0129: * </td>
0130: * </tr>
0131: *
0132: * <tr>
0133: * <td>
0134: * <tt>LONG</tt>
0135: * </td>
0136: * <td>
0137: * {@link TIFFTag#TIFF_LONG}
0138: * </td>
0139: * <td>
0140: * <code>long</code>
0141: * </td>
0142: * <td>
0143: * <code>"Long"</code>
0144: * </td>
0145: * </tr>
0146: *
0147: * <tr>
0148: * <td>
0149: * <tt>RATIONAL</tt>
0150: * </td>
0151: * <td>
0152: * {@link TIFFTag#TIFF_RATIONAL}
0153: * </td>
0154: * <td>
0155: * <code>long[2]</code> {numerator, denominator}
0156: * </td>
0157: * <td>
0158: * <code>"Rational"</code>
0159: * </td>
0160: * </tr>
0161: *
0162: * <tr>
0163: * <td>
0164: * <tt>SBYTE</tt>
0165: * </td>
0166: * <td>
0167: * {@link TIFFTag#TIFF_SBYTE}
0168: * </td>
0169: * <td>
0170: * <code>byte</code>
0171: * </td>
0172: * <td>
0173: * <code>"SByte"</code>
0174: * </td>
0175: * </tr>
0176: *
0177: * <tr>
0178: * <td>
0179: * <tt>UNDEFINED</tt>
0180: * </td>
0181: * <td>
0182: * {@link TIFFTag#TIFF_UNDEFINED}
0183: * </td>
0184: * <td>
0185: * <code>byte</code>
0186: * </td>
0187: * <td>
0188: * <code>"Undefined"</code>
0189: * </td>
0190: * </tr>
0191: *
0192: * <tr>
0193: * <td>
0194: * <tt>SSHORT</tt>
0195: * </td>
0196: * <td>
0197: * {@link TIFFTag#TIFF_SSHORT}
0198: * </td>
0199: * <td>
0200: * <code>short</code>
0201: * </td>
0202: * <td>
0203: * <code>"SShort"</code>
0204: * </td>
0205: * </tr>
0206: *
0207: * <tr>
0208: * <td>
0209: * <tt>SLONG</tt>
0210: * </td>
0211: * <td>
0212: * {@link TIFFTag#TIFF_SLONG}
0213: * </td>
0214: * <td>
0215: * <code>int</code>
0216: * </td>
0217: * <td>
0218: * <code>"SLong"</code>
0219: * </td>
0220: * </tr>
0221: *
0222: * <tr>
0223: * <td>
0224: * <tt>SRATIONAL</tt>
0225: * </td>
0226: * <td>
0227: * {@link TIFFTag#TIFF_SRATIONAL}
0228: * </td>
0229: * <td>
0230: * <code>int[2]</code> {numerator, denominator}
0231: * </td>
0232: * <td>
0233: * <code>"SRational"</code>
0234: * </td>
0235: * </tr>
0236: *
0237: * <tr>
0238: * <td>
0239: * <tt>FLOAT</tt>
0240: * </td>
0241: * <td>
0242: * {@link TIFFTag#TIFF_FLOAT}
0243: * </td>
0244: * <td>
0245: * <code>float</code>
0246: * </td>
0247: * <td>
0248: * <code>"Float"</code>
0249: * </td>
0250: * </tr>
0251: *
0252: * <tr>
0253: * <td>
0254: * <tt>DOUBLE</tt>
0255: * </td>
0256: * <td>
0257: * {@link TIFFTag#TIFF_DOUBLE}
0258: * </td>
0259: * <td>
0260: * <code>double</code>
0261: * </td>
0262: * <td>
0263: * <code>"Double"</code>
0264: * </td>
0265: * </tr>
0266: *
0267: * <tr>
0268: * <td>
0269: * <tt>IFD</tt>
0270: * </td>
0271: * <td>
0272: * {@link TIFFTag#TIFF_IFD_POINTER}
0273: * </td>
0274: * <td>
0275: * <code>long</code>
0276: * </td>
0277: * <td>
0278: * <code>"IFDPointer"</code>
0279: * </td>
0280: * </tr>
0281: *
0282: * </table>
0283: *
0284: * @see TIFFDirectory
0285: * @see TIFFTag
0286: */
0287: public class TIFFField implements Comparable {
0288:
0289: private static final String[] typeNames = { null, "Byte", "Ascii",
0290: "Short", "Long", "Rational", "SByte", "Undefined",
0291: "SShort", "SLong", "SRational", "Float", "Double",
0292: "IFDPointer" };
0293:
0294: private static final boolean[] isIntegral = { false, true, false,
0295: true, true, false, true, true, true, true, false, false,
0296: false, false };
0297:
0298: /** The tag. */
0299: private TIFFTag tag;
0300:
0301: /** The tag number. */
0302: private int tagNumber;
0303:
0304: /** The tag type. */
0305: private int type;
0306:
0307: /** The number of data items present in the field. */
0308: private int count;
0309:
0310: /** The field data. */
0311: private Object data;
0312:
0313: /** The default constructor. */
0314: private TIFFField() {
0315: }
0316:
0317: private static String getAttribute(Node node, String attrName) {
0318: NamedNodeMap attrs = node.getAttributes();
0319: return attrs.getNamedItem(attrName).getNodeValue();
0320: }
0321:
0322: private static void initData(Node node, int[] otype, int[] ocount,
0323: Object[] odata) {
0324: int type;
0325: int count;
0326: Object data = null;
0327:
0328: String typeName = node.getNodeName();
0329: typeName = typeName.substring(4);
0330: typeName = typeName.substring(0, typeName.length() - 1);
0331: type = TIFFField.getTypeByName(typeName);
0332: if (type == -1) {
0333: throw new IllegalArgumentException("typeName = " + typeName);
0334: }
0335:
0336: Node child = node.getFirstChild();
0337:
0338: count = 0;
0339: while (child != null) {
0340: String childTypeName = child.getNodeName().substring(4);
0341: if (!typeName.equals(childTypeName)) {
0342: // warning
0343: }
0344:
0345: ++count;
0346: child = child.getNextSibling();
0347: }
0348:
0349: if (count > 0) {
0350: data = createArrayForType(type, count);
0351: child = node.getFirstChild();
0352: int idx = 0;
0353: while (child != null) {
0354: String value = getAttribute(child, "value");
0355:
0356: String numerator, denominator;
0357: int slashPos;
0358:
0359: switch (type) {
0360: case TIFFTag.TIFF_ASCII:
0361: ((String[]) data)[idx] = value;
0362: break;
0363: case TIFFTag.TIFF_BYTE:
0364: case TIFFTag.TIFF_SBYTE:
0365: ((byte[]) data)[idx] = (byte) Integer
0366: .parseInt(value);
0367: break;
0368: case TIFFTag.TIFF_SHORT:
0369: ((char[]) data)[idx] = (char) Integer
0370: .parseInt(value);
0371: break;
0372: case TIFFTag.TIFF_SSHORT:
0373: ((short[]) data)[idx] = (short) Integer
0374: .parseInt(value);
0375: break;
0376: case TIFFTag.TIFF_SLONG:
0377: ((int[]) data)[idx] = (int) Integer.parseInt(value);
0378: break;
0379: case TIFFTag.TIFF_LONG:
0380: case TIFFTag.TIFF_IFD_POINTER:
0381: ((long[]) data)[idx] = (long) Long.parseLong(value);
0382: break;
0383: case TIFFTag.TIFF_FLOAT:
0384: ((float[]) data)[idx] = (float) Float
0385: .parseFloat(value);
0386: break;
0387: case TIFFTag.TIFF_DOUBLE:
0388: ((double[]) data)[idx] = (double) Double
0389: .parseDouble(value);
0390: break;
0391: case TIFFTag.TIFF_SRATIONAL:
0392: slashPos = value.indexOf("/");
0393: numerator = value.substring(0, slashPos);
0394: denominator = value.substring(slashPos + 1);
0395:
0396: ((int[][]) data)[idx] = new int[2];
0397: ((int[][]) data)[idx][0] = Integer
0398: .parseInt(numerator);
0399: ((int[][]) data)[idx][1] = Integer
0400: .parseInt(denominator);
0401: break;
0402: case TIFFTag.TIFF_RATIONAL:
0403: slashPos = value.indexOf("/");
0404: numerator = value.substring(0, slashPos);
0405: denominator = value.substring(slashPos + 1);
0406:
0407: ((long[][]) data)[idx] = new long[2];
0408: ((long[][]) data)[idx][0] = Long
0409: .parseLong(numerator);
0410: ((long[][]) data)[idx][1] = Long
0411: .parseLong(denominator);
0412: break;
0413: default:
0414: // error
0415: }
0416:
0417: idx++;
0418: child = child.getNextSibling();
0419: }
0420: }
0421:
0422: otype[0] = type;
0423: ocount[0] = count;
0424: odata[0] = data;
0425: }
0426:
0427: /**
0428: * Creates a <code>TIFFField</code> from a TIFF native image
0429: * metadata node. If the value of the <tt>"tagNumber"</tt> attribute
0430: * of the node is not found in <code>tagSet</code> then a new
0431: * <code>TIFFTag</code> with name <code>"unknown"</code> will be
0432: * created and assigned to the field.
0433: *
0434: * @param tagSet The <code>TIFFTagSet</code> to which the
0435: * <code>TIFFTag</code> of the field belongs.
0436: * @param node A native TIFF image metadata <code>TIFFField</code> node.
0437: * @throws IllegalArgumentException if <code>node</code> is
0438: * <code>null</code>.
0439: * @throws IllegalArgumentException if the name of the node is not
0440: * <code>"TIFFField"</code>.
0441: */
0442: public static TIFFField createFromMetadataNode(TIFFTagSet tagSet,
0443: Node node) {
0444: if (node == null) {
0445: throw new IllegalArgumentException("node == null!");
0446: }
0447: String name = node.getNodeName();
0448: if (!name.equals("TIFFField")) {
0449: throw new IllegalArgumentException(
0450: "!name.equals(\"TIFFField\")");
0451: }
0452:
0453: int tagNumber = Integer.parseInt(getAttribute(node, "number"));
0454: TIFFTag tag;
0455: if (tagSet != null) {
0456: tag = tagSet.getTag(tagNumber);
0457: } else {
0458: tag = new TIFFTag("unknown", tagNumber, 0, null);
0459: }
0460:
0461: int type = TIFFTag.TIFF_UNDEFINED;
0462: int count = 0;
0463: Object data = null;
0464:
0465: Node child = node.getFirstChild();
0466: if (child != null) {
0467: String typeName = child.getNodeName();
0468: if (typeName.equals("TIFFUndefined")) {
0469: String values = getAttribute(child, "value");
0470: StringTokenizer st = new StringTokenizer(values, ",");
0471: count = st.countTokens();
0472:
0473: byte[] bdata = new byte[count];
0474: for (int i = 0; i < count; i++) {
0475: bdata[i] = (byte) Integer.parseInt(st.nextToken());
0476: }
0477:
0478: type = TIFFTag.TIFF_UNDEFINED;
0479: data = bdata;
0480: } else {
0481: int[] otype = new int[1];
0482: int[] ocount = new int[1];
0483: Object[] odata = new Object[1];
0484:
0485: initData(node.getFirstChild(), otype, ocount, odata);
0486: type = otype[0];
0487: count = ocount[0];
0488: data = odata[0];
0489: }
0490: } else {
0491: int t = TIFFTag.MAX_DATATYPE;
0492: while (t >= TIFFTag.MIN_DATATYPE && !tag.isDataTypeOK(t)) {
0493: t--;
0494: }
0495: type = t;
0496: }
0497:
0498: return new TIFFField(tag, type, count, data);
0499: }
0500:
0501: /**
0502: * Constructs a <code>TIFFField</code> with arbitrary data. The
0503: * <code>type</code> parameter must be a value for which
0504: * {@link TIFFTag#isDataTypeOK <code>tag.isDataTypeOK()</code>}
0505: * returns <code>true</code>. The <code>data</code> parameter must
0506: * be an array of a Java type appropriate for the type of the TIFF
0507: * field unless {@link TIFFTag#isIFDPointer
0508: * <code>tag.isIFDPointer()</code>} returns <code>true</code> in
0509: * which case it must be a <code>TIFFDirectory</code> instance.
0510: *
0511: * <p><i>Neither the legality of <code>type</code> with respect to
0512: * <code>tag</code> nor that or <code>data</code> with respect to
0513: * <code>type</code> is verified by this constructor.</i> The methods
0514: * {@link TIFFTag#isDataTypeOK <code>TIFFTag.isDataTypeOK()</code>}
0515: * and {@link #createArrayForType <code>createArrayForType()</code>}
0516: * should be used programmatically to ensure that subsequent errors
0517: * such as <code>ClassCastException</code>s do not occur as a result
0518: * of providing inconsitent parameters to this constructor.</p>
0519: *
0520: * <p>Note that the value (data) of the <code>TIFFField</code>
0521: * will always be the actual field value regardless of the number of
0522: * bytes required for that value. This is the case despite the fact
0523: * that the TIFF <i>IFD Entry</i> corresponding to the field may
0524: * actually contain the offset to the field's value rather than
0525: * the value itself (the latter occurring if and only if the
0526: * value fits into 4 bytes). In other words, the value of the
0527: * field will already have been read from the TIFF stream. This
0528: * subsumes the case where <code>tag.isIFDPointer()</code> returns
0529: * <code>true</code> and the value will be a <code>TIFFDirectory</code>
0530: * rather than an array.</p>
0531: *
0532: * @param tag The tag to associated with this field.
0533: * @param type One of the <code>TIFFTag.TIFF_*</code> constants
0534: * indicating the data type of the field as written to the TIFF stream.
0535: * @param count The number of data values.
0536: * @param data The actual data content of the field.
0537: *
0538: * @throws IllegalArgumentException if <code>tag == null</code>.
0539: * @throws IllegalArgumentException if <code>dataType</code> is not
0540: * one of the <code>TIFFTag.TIFF_*</code> data type constants.
0541: * @throws IllegalArgumentException if <code>count < 0</code>.
0542: */
0543: public TIFFField(TIFFTag tag, int type, int count, Object data) {
0544: if (tag == null) {
0545: throw new IllegalArgumentException("tag == null!");
0546: } else if (type < TIFFTag.MIN_DATATYPE
0547: || type > TIFFTag.MAX_DATATYPE) {
0548: throw new IllegalArgumentException("Unknown data type "
0549: + type);
0550: } else if (count < 0) {
0551: throw new IllegalArgumentException("count < 0!");
0552: }
0553: this .tag = tag;
0554: this .tagNumber = tag.getNumber();
0555: this .type = type;
0556: this .count = count;
0557: this .data = data;
0558: }
0559:
0560: /**
0561: * Constructs a data array using {@link #createArrayForType
0562: * <code>createArrayForType()</code>} and invokes
0563: * {@link #TIFFField(TIFFTag,int,int,Object)} with the supplied
0564: * parameters and the created array.
0565: *
0566: * @see #TIFFField(TIFFTag,int,int,Object)
0567: */
0568: public TIFFField(TIFFTag tag, int type, int count) {
0569: this (tag, type, count, createArrayForType(type, count));
0570: }
0571:
0572: /**
0573: * Constructs a <code>TIFFField</code> with a single integral value.
0574: * The field will have type
0575: * {@link TIFFTag#TIFF_SHORT <code>TIFF_SHORT</code>} if
0576: * <code>val < 65536</code> and type
0577: * {@link TIFFTag#TIFF_LONG <code>TIFF_LONG</code>} otherwise.
0578: * <i>It is <b>not</b> verified whether the resulting type is
0579: * legal for <code>tag</code>.</i>
0580: *
0581: * @param tag The tag to associate with this field.
0582: * @param value The value to associate with this field.
0583: * @throws IllegalArgumentException if <code>tag == null</code>.
0584: * @throws IllegalArgumentException if <code>value < 0</code>.
0585: */
0586: public TIFFField(TIFFTag tag, int value) {
0587: if (tag == null) {
0588: throw new IllegalArgumentException("tag == null!");
0589: }
0590: if (value < 0) {
0591: throw new IllegalArgumentException("value < 0!");
0592: }
0593:
0594: this .tag = tag;
0595: this .tagNumber = tag.getNumber();
0596: this .count = 1;
0597:
0598: if (value < 65536) {
0599: this .type = TIFFTag.TIFF_SHORT;
0600: char[] cdata = new char[1];
0601: cdata[0] = (char) value;
0602: this .data = cdata;
0603: } else {
0604: this .type = TIFFTag.TIFF_LONG;
0605: long[] ldata = new long[1];
0606: ldata[0] = value;
0607: this .data = ldata;
0608: }
0609: }
0610:
0611: /**
0612: * Retrieves the tag associated with this field.
0613: *
0614: * @return The associated <code>TIFFTag</code>.
0615: */
0616: public TIFFTag getTag() {
0617: return tag;
0618: }
0619:
0620: /**
0621: * Retrieves the tag number in the range <code>[0, 65535]</code>.
0622: *
0623: * @return The tag number.
0624: */
0625: public int getTagNumber() {
0626: return tagNumber;
0627: }
0628:
0629: /**
0630: * Returns the type of the data stored in the field. For a TIFF 6.0
0631: * stream, the value will equal one of the <code>TIFFTag.TIFF_*</code>
0632: * constants. For future revisions of TIFF, higher values are possible.
0633: *
0634: * @return The data type of the field value.
0635: */
0636: public int getType() {
0637: return type;
0638: }
0639:
0640: /**
0641: * Returns the name of the supplied data type constant.
0642: *
0643: * @param dataType One of the <code>TIFFTag.TIFF_*</code> constants
0644: * indicating the data type of the field as written to the TIFF stream.
0645: * @return The type name corresponding to the supplied type constant.
0646: * @throws IllegalArgumentException if <code>dataType</code> is not
0647: * one of the <code>TIFFTag.TIFF_*</code> data type constants.
0648: */
0649: public static String getTypeName(int dataType) {
0650: if (dataType < TIFFTag.MIN_DATATYPE
0651: || dataType > TIFFTag.MAX_DATATYPE) {
0652: throw new IllegalArgumentException("Unknown data type "
0653: + dataType);
0654: }
0655:
0656: return typeNames[dataType];
0657: }
0658:
0659: /**
0660: * Returns the data type constant corresponding to the supplied data
0661: * type name. If the name is unknown <code>-1</code> will be returned.
0662: *
0663: * @return One of the <code>TIFFTag.TIFF_*</code> constants or
0664: * <code>-1</code> if the name is not recognized.
0665: */
0666: public static int getTypeByName(String typeName) {
0667: for (int i = TIFFTag.MIN_DATATYPE; i <= TIFFTag.MAX_DATATYPE; i++) {
0668: if (typeName.equals(typeNames[i])) {
0669: return i;
0670: }
0671: }
0672:
0673: return -1;
0674: }
0675:
0676: /**
0677: * Creates an array appropriate for the indicated data type.
0678: *
0679: * @param dataType One of the <code>TIFFTag.TIFF_*</code> data type
0680: * constants.
0681: * @param count The number of values in the array.
0682: *
0683: * @throws IllegalArgumentException if <code>dataType</code> is not
0684: * one of the <code>TIFFTag.TIFF_*</code> data type constants.
0685: * @throws IllegalArgumentException if <code>count < 0</code>.
0686: */
0687: public static Object createArrayForType(int dataType, int count) {
0688: if (count < 0) {
0689: throw new IllegalArgumentException("count < 0!");
0690: }
0691: switch (dataType) {
0692: case TIFFTag.TIFF_BYTE:
0693: case TIFFTag.TIFF_SBYTE:
0694: case TIFFTag.TIFF_UNDEFINED:
0695: return new byte[count];
0696: case TIFFTag.TIFF_ASCII:
0697: return new String[count];
0698: case TIFFTag.TIFF_SHORT:
0699: return new char[count];
0700: case TIFFTag.TIFF_LONG:
0701: case TIFFTag.TIFF_IFD_POINTER:
0702: return new long[count];
0703: case TIFFTag.TIFF_RATIONAL:
0704: return new long[count][2];
0705: case TIFFTag.TIFF_SSHORT:
0706: return new short[count];
0707: case TIFFTag.TIFF_SLONG:
0708: return new int[count];
0709: case TIFFTag.TIFF_SRATIONAL:
0710: return new int[count][2];
0711: case TIFFTag.TIFF_FLOAT:
0712: return new float[count];
0713: case TIFFTag.TIFF_DOUBLE:
0714: return new double[count];
0715: default:
0716: throw new IllegalArgumentException("Unknown data type "
0717: + dataType);
0718: }
0719: }
0720:
0721: /**
0722: * Returns the <code>TIFFField</code> as a node named either
0723: * <tt>"TIFFField"</tt> or <tt>"TIFFIFD"</tt> as described in the
0724: * TIFF native image metadata specification. The node will be named
0725: * <tt>"TIFFIFD"</tt> if and only if the field's data object is an
0726: * instance of {@link TIFFDirectory} or equivalently
0727: * {@link TIFFTag#isIFDPointer getTag.isIFDPointer()} returns
0728: * <code>true</code>.
0729: *
0730: * @return a <code>Node</code> named <tt>"TIFFField"</tt> or
0731: * <tt>"TIFFIFD"</tt>.
0732: */
0733: public Node getAsNativeNode() {
0734: return new TIFFFieldNode(this );
0735: }
0736:
0737: /**
0738: * Indicates whether the value associated with the field is of
0739: * integral data type.
0740: *
0741: * @return Whether the field type is integral.
0742: */
0743: public boolean isIntegral() {
0744: return isIntegral[type];
0745: }
0746:
0747: /**
0748: * Returns the number of data items present in the field. For
0749: * <code>TIFFTag.TIFF_ASCII</code> fields, the value returned is the
0750: * number of <code>String</code>s, not the total length of the
0751: * data as in the file representation.
0752: */
0753: public int getCount() {
0754: return count;
0755: }
0756:
0757: /**
0758: * Returns a reference to the data object associated with the field.
0759: *
0760: * @return The data object of the field.
0761: */
0762: public Object getData() {
0763: return data;
0764: }
0765:
0766: /**
0767: * Returns the data as an uninterpreted array of
0768: * <code>byte</code>s. The type of the field must be one of
0769: * <code>TIFFTag.TIFF_BYTE</code>, <code>TIFF_SBYTE</code>, or
0770: * <code>TIFF_UNDEFINED</code>.
0771: *
0772: * <p> For data in <code>TIFFTag.TIFF_BYTE</code> format, the application
0773: * must take care when promoting the data to longer integral types
0774: * to avoid sign extension.
0775: *
0776: * @throws ClassCastException if the field is not of type
0777: * <code>TIFF_BYTE</code>, <code>TIFF_SBYTE</code>, or
0778: * <code>TIFF_UNDEFINED</code>.
0779: */
0780: public byte[] getAsBytes() {
0781: return (byte[]) data;
0782: }
0783:
0784: /**
0785: * Returns <code>TIFFTag.TIFF_SHORT</code> data as an array of
0786: * <code>char</code>s (unsigned 16-bit integers).
0787: *
0788: * @throws ClassCastException if the field is not of type
0789: * <code>TIFF_SHORT</code>.
0790: */
0791: public char[] getAsChars() {
0792: return (char[]) data;
0793: }
0794:
0795: /**
0796: * Returns <code>TIFFTag.TIFF_SSHORT</code> data as an array of
0797: * <code>short</code>s (signed 16-bit integers).
0798: *
0799: * @throws ClassCastException if the field is not of type
0800: * <code>TIFF_SSHORT</code>.
0801: */
0802: public short[] getAsShorts() {
0803: return (short[]) data;
0804: }
0805:
0806: /**
0807: * Returns <code>TIFFTag.TIFF_SLONG</code> data as an array of
0808: * <code>int</code>s (signed 32-bit integers).
0809: *
0810: * @throws ClassCastException if the field is not of type
0811: * <code>TIFF_SHORT</code>, <code>TIFF_SSHORT</code>, or
0812: * <code>TIFF_SLONG</code>.
0813: */
0814: public int[] getAsInts() {
0815: if (data instanceof int[]) {
0816: return (int[]) data;
0817: } else if (data instanceof char[]) {
0818: char[] cdata = (char[]) data;
0819: int[] idata = new int[cdata.length];
0820: for (int i = 0; i < cdata.length; i++) {
0821: idata[i] = (int) (cdata[i] & 0xffff);
0822: }
0823: return idata;
0824: } else if (data instanceof short[]) {
0825: short[] sdata = (short[]) data;
0826: int[] idata = new int[sdata.length];
0827: for (int i = 0; i < sdata.length; i++) {
0828: idata[i] = (int) sdata[i];
0829: }
0830: return idata;
0831: } else {
0832: throw new ClassCastException(
0833: "Data not char[], short[], or int[]!");
0834: }
0835: }
0836:
0837: /**
0838: * Returns <code>TIFFTag.TIFF_LONG</code> or
0839: * <code>TIFF_IFD_POINTER</code> data as an array of
0840: * <code>long</code>s (signed 64-bit integers).
0841: *
0842: * @throws ClassCastException if the field is not of type
0843: * <code>TIFF_LONG</code> or <code>TIFF_IFD_POINTER</code>.
0844: */
0845: public long[] getAsLongs() {
0846: return (long[]) data;
0847: }
0848:
0849: /**
0850: * Returns <code>TIFFTag.TIFF_FLOAT</code> data as an array of
0851: * <code>float</code>s (32-bit floating-point values).
0852: *
0853: * @throws ClassCastException if the field is not of type
0854: * <code>TIFF_FLOAT</code>.
0855: */
0856: public float[] getAsFloats() {
0857: return (float[]) data;
0858: }
0859:
0860: /**
0861: * Returns <code>TIFFTag.TIFF_DOUBLE</code> data as an array of
0862: * <code>double</code>s (64-bit floating-point values).
0863: *
0864: * @throws ClassCastException if the field is not of type
0865: * <code>TIFF_DOUBLE</code>.
0866: */
0867: public double[] getAsDoubles() {
0868: return (double[]) data;
0869: }
0870:
0871: /**
0872: * Returns <code>TIFFTag.TIFF_SRATIONAL</code> data as an array of
0873: * 2-element arrays of <code>int</code>s.
0874: *
0875: * @throws ClassCastException if the field is not of type
0876: * <code>TIFF_SRATIONAL</code>.
0877: */
0878: public int[][] getAsSRationals() {
0879: return (int[][]) data;
0880: }
0881:
0882: /**
0883: * Returns <code>TIFFTag.TIFF_RATIONAL</code> data as an array of
0884: * 2-element arrays of <code>long</code>s.
0885: *
0886: * @throws ClassCastException if the field is not of type
0887: * <code>TIFF_RATIONAL</code>.
0888: */
0889: public long[][] getAsRationals() {
0890: return (long[][]) data;
0891: }
0892:
0893: /**
0894: * Returns data in any format as an <code>int</code>.
0895: *
0896: * <p> <code>TIFFTag.TIFF_BYTE</code> values are treated as unsigned; that
0897: * is, no sign extension will take place and the returned value
0898: * will be in the range [0, 255]. <code>TIFF_SBYTE</code> data
0899: * will be returned in the range [-128, 127].
0900: *
0901: * <p> A <code>TIFF_UNDEFINED</code> value is treated as though
0902: * it were a <code>TIFF_BYTE</code>.
0903: *
0904: * <p> Data in <code>TIFF_SLONG</code>, <code>TIFF_LONG</code>,
0905: * <code>TIFF_FLOAT</code>, <code>TIFF_DOUBLE</code> or
0906: * <code>TIFF_IFD_POINTER</code> format are simply cast to
0907: * <code>int</code> and may suffer from truncation.
0908: *
0909: * <p> Data in <code>TIFF_SRATIONAL</code> or
0910: * <code>TIFF_RATIONAL</code> format are evaluated by dividing the
0911: * numerator into the denominator using double-precision
0912: * arithmetic and then casting to <code>int</code>. Loss of
0913: * precision and truncation may occur.
0914: *
0915: * <p> Data in <code>TIFF_ASCII</code> format will be parsed as by
0916: * the <code>Double.parseDouble</code> method, with the result
0917: * case to <code>int</code>.
0918: */
0919: public int getAsInt(int index) {
0920: switch (type) {
0921: case TIFFTag.TIFF_BYTE:
0922: case TIFFTag.TIFF_UNDEFINED:
0923: return ((byte[]) data)[index] & 0xff;
0924: case TIFFTag.TIFF_SBYTE:
0925: return ((byte[]) data)[index];
0926: case TIFFTag.TIFF_SHORT:
0927: return ((char[]) data)[index] & 0xffff;
0928: case TIFFTag.TIFF_SSHORT:
0929: return ((short[]) data)[index];
0930: case TIFFTag.TIFF_SLONG:
0931: return ((int[]) data)[index];
0932: case TIFFTag.TIFF_LONG:
0933: case TIFFTag.TIFF_IFD_POINTER:
0934: return (int) ((long[]) data)[index];
0935: case TIFFTag.TIFF_FLOAT:
0936: return (int) ((float[]) data)[index];
0937: case TIFFTag.TIFF_DOUBLE:
0938: return (int) ((double[]) data)[index];
0939: case TIFFTag.TIFF_SRATIONAL:
0940: int[] ivalue = getAsSRational(index);
0941: return (int) ((double) ivalue[0] / ivalue[1]);
0942: case TIFFTag.TIFF_RATIONAL:
0943: long[] lvalue = getAsRational(index);
0944: return (int) ((double) lvalue[0] / lvalue[1]);
0945: case TIFFTag.TIFF_ASCII:
0946: String s = ((String[]) data)[index];
0947: return (int) Double.parseDouble(s);
0948: default:
0949: throw new ClassCastException();
0950: }
0951: }
0952:
0953: /**
0954: * Returns data in any format as a <code>long</code>.
0955: *
0956: * <p> <code>TIFFTag.TIFF_BYTE</code> and <code>TIFF_UNDEFINED</code> data
0957: * are treated as unsigned; that is, no sign extension will take
0958: * place and the returned value will be in the range [0, 255].
0959: * <code>TIFF_SBYTE</code> data will be returned in the range
0960: * [-128, 127].
0961: *
0962: * <p> Data in <code>TIFF_ASCII</code> format will be parsed as by
0963: * the <code>Double.parseDouble</code> method, with the result
0964: * cast to <code>long</code>.
0965: */
0966: public long getAsLong(int index) {
0967: switch (type) {
0968: case TIFFTag.TIFF_BYTE:
0969: case TIFFTag.TIFF_UNDEFINED:
0970: return ((byte[]) data)[index] & 0xff;
0971: case TIFFTag.TIFF_SBYTE:
0972: return ((byte[]) data)[index];
0973: case TIFFTag.TIFF_SHORT:
0974: return ((char[]) data)[index] & 0xffff;
0975: case TIFFTag.TIFF_SSHORT:
0976: return ((short[]) data)[index];
0977: case TIFFTag.TIFF_SLONG:
0978: return ((int[]) data)[index];
0979: case TIFFTag.TIFF_LONG:
0980: case TIFFTag.TIFF_IFD_POINTER:
0981: return ((long[]) data)[index];
0982: case TIFFTag.TIFF_SRATIONAL:
0983: int[] ivalue = getAsSRational(index);
0984: return (long) ((double) ivalue[0] / ivalue[1]);
0985: case TIFFTag.TIFF_RATIONAL:
0986: long[] lvalue = getAsRational(index);
0987: return (long) ((double) lvalue[0] / lvalue[1]);
0988: case TIFFTag.TIFF_ASCII:
0989: String s = ((String[]) data)[index];
0990: return (long) Double.parseDouble(s);
0991: default:
0992: throw new ClassCastException();
0993: }
0994: }
0995:
0996: /**
0997: * Returns data in any format as a <code>float</code>.
0998: *
0999: * <p> <code>TIFFTag.TIFF_BYTE</code> and <code>TIFF_UNDEFINED</code> data
1000: * are treated as unsigned; that is, no sign extension will take
1001: * place and the returned value will be in the range [0, 255].
1002: * <code>TIFF_SBYTE</code> data will be returned in the range
1003: * [-128, 127].
1004: *
1005: * <p> Data in <code>TIFF_SLONG</code>, <code>TIFF_LONG</code>,
1006: * <code>TIFF_DOUBLE</code>, or <code>TIFF_IFD_POINTER</code> format are
1007: * simply cast to <code>float</code> and may suffer from
1008: * truncation.
1009: *
1010: * <p> Data in <code>TIFF_SRATIONAL</code> or
1011: * <code>TIFF_RATIONAL</code> format are evaluated by dividing the
1012: * numerator into the denominator using double-precision
1013: * arithmetic and then casting to <code>float</code>.
1014: *
1015: * <p> Data in <code>TIFF_ASCII</code> format will be parsed as by
1016: * the <code>Double.parseDouble</code> method, with the result
1017: * cast to <code>float</code>.
1018: */
1019: public float getAsFloat(int index) {
1020: switch (type) {
1021: case TIFFTag.TIFF_BYTE:
1022: case TIFFTag.TIFF_UNDEFINED:
1023: return ((byte[]) data)[index] & 0xff;
1024: case TIFFTag.TIFF_SBYTE:
1025: return ((byte[]) data)[index];
1026: case TIFFTag.TIFF_SHORT:
1027: return ((char[]) data)[index] & 0xffff;
1028: case TIFFTag.TIFF_SSHORT:
1029: return ((short[]) data)[index];
1030: case TIFFTag.TIFF_SLONG:
1031: return ((int[]) data)[index];
1032: case TIFFTag.TIFF_LONG:
1033: case TIFFTag.TIFF_IFD_POINTER:
1034: return ((long[]) data)[index];
1035: case TIFFTag.TIFF_FLOAT:
1036: return ((float[]) data)[index];
1037: case TIFFTag.TIFF_DOUBLE:
1038: return (float) ((double[]) data)[index];
1039: case TIFFTag.TIFF_SRATIONAL:
1040: int[] ivalue = getAsSRational(index);
1041: return (float) ((double) ivalue[0] / ivalue[1]);
1042: case TIFFTag.TIFF_RATIONAL:
1043: long[] lvalue = getAsRational(index);
1044: return (float) ((double) lvalue[0] / lvalue[1]);
1045: case TIFFTag.TIFF_ASCII:
1046: String s = ((String[]) data)[index];
1047: return (float) Double.parseDouble(s);
1048: default:
1049: throw new ClassCastException();
1050: }
1051: }
1052:
1053: /**
1054: * Returns data in any format as a <code>double</code>.
1055: *
1056: * <p> <code>TIFFTag.TIFF_BYTE</code> and <code>TIFF_UNDEFINED</code> data
1057: * are treated as unsigned; that is, no sign extension will take
1058: * place and the returned value will be in the range [0, 255].
1059: * <code>TIFF_SBYTE</code> data will be returned in the range
1060: * [-128, 127].
1061: *
1062: * <p> Data in <code>TIFF_SRATIONAL</code> or
1063: * <code>TIFF_RATIONAL</code> format are evaluated by dividing the
1064: * numerator into the denominator using double-precision
1065: * arithmetic.
1066: *
1067: * <p> Data in <code>TIFF_ASCII</code> format will be parsed as by
1068: * the <code>Double.parseDouble</code> method.
1069: */
1070: public double getAsDouble(int index) {
1071: switch (type) {
1072: case TIFFTag.TIFF_BYTE:
1073: case TIFFTag.TIFF_UNDEFINED:
1074: return ((byte[]) data)[index] & 0xff;
1075: case TIFFTag.TIFF_SBYTE:
1076: return ((byte[]) data)[index];
1077: case TIFFTag.TIFF_SHORT:
1078: return ((char[]) data)[index] & 0xffff;
1079: case TIFFTag.TIFF_SSHORT:
1080: return ((short[]) data)[index];
1081: case TIFFTag.TIFF_SLONG:
1082: return ((int[]) data)[index];
1083: case TIFFTag.TIFF_LONG:
1084: case TIFFTag.TIFF_IFD_POINTER:
1085: return ((long[]) data)[index];
1086: case TIFFTag.TIFF_FLOAT:
1087: return ((float[]) data)[index];
1088: case TIFFTag.TIFF_DOUBLE:
1089: return ((double[]) data)[index];
1090: case TIFFTag.TIFF_SRATIONAL:
1091: int[] ivalue = getAsSRational(index);
1092: return (double) ivalue[0] / ivalue[1];
1093: case TIFFTag.TIFF_RATIONAL:
1094: long[] lvalue = getAsRational(index);
1095: return (double) lvalue[0] / lvalue[1];
1096: case TIFFTag.TIFF_ASCII:
1097: String s = ((String[]) data)[index];
1098: return Double.parseDouble(s);
1099: default:
1100: throw new ClassCastException();
1101: }
1102: }
1103:
1104: /**
1105: * Returns a <code>TIFFTag.TIFF_ASCII</code> value as a
1106: * <code>String</code>.
1107: *
1108: * @throws ClassCastException if the field is not of type
1109: * <code>TIFF_ASCII</code>.
1110: */
1111: public String getAsString(int index) {
1112: return ((String[]) data)[index];
1113: }
1114:
1115: /**
1116: * Returns a <code>TIFFTag.TIFF_SRATIONAL</code> data item as a
1117: * two-element array of <code>int</code>s.
1118: *
1119: * @throws ClassCastException if the field is not of type
1120: * <code>TIFF_SRATIONAL</code>.
1121: */
1122: public int[] getAsSRational(int index) {
1123: return ((int[][]) data)[index];
1124: }
1125:
1126: /**
1127: * Returns a TIFFTag.TIFF_RATIONAL data item as a two-element array
1128: * of ints.
1129: *
1130: * @throws ClassCastException if the field is not of type
1131: * <code>TIFF_RATIONAL</code>.
1132: */
1133: public long[] getAsRational(int index) {
1134: return ((long[][]) data)[index];
1135: }
1136:
1137: /**
1138: * Returns a <code>String</code> containing a human-readable
1139: * version of the data item. Data of type
1140: * <code>TIFFTag.TIFF_RATIONAL</code> or <code>TIFF_SRATIONAL</code> are
1141: * represented as a pair of integers separated by a
1142: * <code>'/'</code> character.
1143: *
1144: * @throws ClassCastException if the field is not of one of the
1145: * legal field types.
1146: */
1147: public String getValueAsString(int index) {
1148: switch (type) {
1149: case TIFFTag.TIFF_ASCII:
1150: return ((String[]) data)[index];
1151: case TIFFTag.TIFF_BYTE:
1152: case TIFFTag.TIFF_UNDEFINED:
1153: return Integer.toString(((byte[]) data)[index] & 0xff);
1154: case TIFFTag.TIFF_SBYTE:
1155: return Integer.toString(((byte[]) data)[index]);
1156: case TIFFTag.TIFF_SHORT:
1157: return Integer.toString(((char[]) data)[index] & 0xffff);
1158: case TIFFTag.TIFF_SSHORT:
1159: return Integer.toString(((short[]) data)[index]);
1160: case TIFFTag.TIFF_SLONG:
1161: return Integer.toString(((int[]) data)[index]);
1162: case TIFFTag.TIFF_LONG:
1163: case TIFFTag.TIFF_IFD_POINTER:
1164: return Long.toString(((long[]) data)[index]);
1165: case TIFFTag.TIFF_FLOAT:
1166: return Float.toString(((float[]) data)[index]);
1167: case TIFFTag.TIFF_DOUBLE:
1168: return Double.toString(((double[]) data)[index]);
1169: case TIFFTag.TIFF_SRATIONAL:
1170: int[] ivalue = getAsSRational(index);
1171: String srationalString;
1172: if (ivalue[1] != 0 && ivalue[0] % ivalue[1] == 0) {
1173: // If the denominator is a non-zero integral divisor
1174: // of the numerator then convert the fraction to be
1175: // with respect to a unity denominator.
1176: srationalString = Integer.toString(ivalue[0]
1177: / ivalue[1])
1178: + "/1";
1179: } else {
1180: // Use the values directly.
1181: srationalString = Integer.toString(ivalue[0]) + "/"
1182: + Integer.toString(ivalue[1]);
1183: }
1184: return srationalString;
1185: case TIFFTag.TIFF_RATIONAL:
1186: long[] lvalue = getAsRational(index);
1187: String rationalString;
1188: if (lvalue[1] != 0L && lvalue[0] % lvalue[1] == 0) {
1189: // If the denominator is a non-zero integral divisor
1190: // of the numerator then convert the fraction to be
1191: // with respect to a unity denominator.
1192: rationalString = Long.toString(lvalue[0] / lvalue[1])
1193: + "/1";
1194: } else {
1195: // Use the values directly.
1196: rationalString = Long.toString(lvalue[0]) + "/"
1197: + Long.toString(lvalue[1]);
1198: }
1199: return rationalString;
1200: default:
1201: throw new ClassCastException();
1202: }
1203: }
1204:
1205: /**
1206: * Compares this <code>TIFFField</code> with another
1207: * <code>TIFFField</code> by comparing the tags.
1208: *
1209: * <p><b>Note: this class has a natural ordering that is inconsistent
1210: * with <code>equals()</code>.</b>
1211: *
1212: * @throws IllegalArgumentException if the parameter is <code>null</code>.
1213: * @throws ClassCastException if the parameter is not a
1214: * <code>TIFFField</code>.
1215: */
1216: public int compareTo(Object o) {
1217: if (o == null) {
1218: throw new IllegalArgumentException();
1219: }
1220:
1221: int oTagNumber = ((TIFFField) o).getTagNumber();
1222: if (tagNumber < oTagNumber) {
1223: return -1;
1224: } else if (tagNumber > oTagNumber) {
1225: return 1;
1226: } else {
1227: return 0;
1228: }
1229: }
1230: }
|