| /* |
| * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| package javax.imageio.plugins.tiff; |
| |
| import java.util.StringTokenizer; |
| import org.w3c.dom.NamedNodeMap; |
| import org.w3c.dom.Node; |
| import com.sun.imageio.plugins.tiff.TIFFFieldNode; |
| import com.sun.imageio.plugins.tiff.TIFFIFD; |
| |
| /** |
| * A class representing a field in a TIFF 6.0 Image File Directory. |
| * |
| * <p> A field in a TIFF Image File Directory (IFD) is defined as a |
| * tag number accompanied by a sequence of values of identical data type. |
| * TIFF 6.0 defines 12 data types; a 13th type {@code IFD} is |
| * defined in TIFF Tech Note 1 of TIFF Specification Supplement 1. These |
| * TIFF data types are referred to by Java constants and mapped internally |
| * onto Java language data types and type names as follows: |
| * |
| * <br> |
| * <br> |
| * <table border="1"> |
| * <caption>TIFF Data Type to Java Data Type Mapping</caption> |
| * |
| * <tr> |
| * <th> |
| * <b>TIFF Data Type</b> |
| * </th> |
| * <th> |
| * <b>Java Constant</b> |
| * </th> |
| * <th> |
| * <b>Java Data Type</b> |
| * </th> |
| * <th> |
| * <b>Java Type Name</b> |
| * </th> |
| * </tr> |
| * |
| * <tr> |
| * <td> |
| * <tt>BYTE</tt> |
| * </td> |
| * <td> |
| * {@link TIFFTag#TIFF_BYTE} |
| * </td> |
| * <td> |
| * {@code byte} |
| * </td> |
| * <td> |
| * {@code "Byte"} |
| * </td> |
| * </tr> |
| * |
| * <tr> |
| * <td> |
| * <tt>ASCII</tt> |
| * </td> |
| * <td> |
| * {@link TIFFTag#TIFF_ASCII} |
| * </td> |
| * <td> |
| * {@code String} |
| * </td> |
| * <td> |
| * {@code "Ascii"} |
| * </td> |
| * </tr> |
| * |
| * <tr> |
| * <td> |
| * <tt>SHORT</tt> |
| * </td> |
| * <td> |
| * {@link TIFFTag#TIFF_SHORT} |
| * </td> |
| * <td> |
| * {@code char} |
| * </td> |
| * <td> |
| * {@code "Short"} |
| * </td> |
| * </tr> |
| * |
| * <tr> |
| * <td> |
| * <tt>LONG</tt> |
| * </td> |
| * <td> |
| * {@link TIFFTag#TIFF_LONG} |
| * </td> |
| * <td> |
| * {@code long} |
| * </td> |
| * <td> |
| * {@code "Long"} |
| * </td> |
| * </tr> |
| * |
| * <tr> |
| * <td> |
| * <tt>RATIONAL</tt> |
| * </td> |
| * <td> |
| * {@link TIFFTag#TIFF_RATIONAL} |
| * </td> |
| * <td> |
| * {@code long[2]} {numerator, denominator} |
| * </td> |
| * <td> |
| * {@code "Rational"} |
| * </td> |
| * </tr> |
| * |
| * <tr> |
| * <td> |
| * <tt>SBYTE</tt> |
| * </td> |
| * <td> |
| * {@link TIFFTag#TIFF_SBYTE} |
| * </td> |
| * <td> |
| * {@code byte} |
| * </td> |
| * <td> |
| * {@code "SByte"} |
| * </td> |
| * </tr> |
| * |
| * <tr> |
| * <td> |
| * <tt>UNDEFINED</tt> |
| * </td> |
| * <td> |
| * {@link TIFFTag#TIFF_UNDEFINED} |
| * </td> |
| * <td> |
| * {@code byte} |
| * </td> |
| * <td> |
| * {@code "Undefined"} |
| * </td> |
| * </tr> |
| * |
| * <tr> |
| * <td> |
| * <tt>SSHORT</tt> |
| * </td> |
| * <td> |
| * {@link TIFFTag#TIFF_SSHORT} |
| * </td> |
| * <td> |
| * {@code short} |
| * </td> |
| * <td> |
| * {@code "SShort"} |
| * </td> |
| * </tr> |
| * |
| * <tr> |
| * <td> |
| * <tt>SLONG</tt> |
| * </td> |
| * <td> |
| * {@link TIFFTag#TIFF_SLONG} |
| * </td> |
| * <td> |
| * {@code int} |
| * </td> |
| * <td> |
| * {@code "SLong"} |
| * </td> |
| * </tr> |
| * |
| * <tr> |
| * <td> |
| * <tt>SRATIONAL</tt> |
| * </td> |
| * <td> |
| * {@link TIFFTag#TIFF_SRATIONAL} |
| * </td> |
| * <td> |
| * {@code int[2]} {numerator, denominator} |
| * </td> |
| * <td> |
| * {@code "SRational"} |
| * </td> |
| * </tr> |
| * |
| * <tr> |
| * <td> |
| * <tt>FLOAT</tt> |
| * </td> |
| * <td> |
| * {@link TIFFTag#TIFF_FLOAT} |
| * </td> |
| * <td> |
| * {@code float} |
| * </td> |
| * <td> |
| * {@code "Float"} |
| * </td> |
| * </tr> |
| * |
| * <tr> |
| * <td> |
| * <tt>DOUBLE</tt> |
| * </td> |
| * <td> |
| * {@link TIFFTag#TIFF_DOUBLE} |
| * </td> |
| * <td> |
| * {@code double} |
| * </td> |
| * <td> |
| * {@code "Double"} |
| * </td> |
| * </tr> |
| * |
| * <tr> |
| * <td> |
| * <tt>IFD</tt> |
| * </td> |
| * <td> |
| * {@link TIFFTag#TIFF_IFD_POINTER} |
| * </td> |
| * <td> |
| * {@code long} |
| * </td> |
| * <td> |
| * {@code "IFDPointer"} |
| * </td> |
| * </tr> |
| * |
| * </table> |
| * |
| * @since 9 |
| * @see TIFFDirectory |
| * @see TIFFTag |
| */ |
| public class TIFFField implements Cloneable { |
| |
| private static final String[] typeNames = { |
| null, |
| "Byte", "Ascii", "Short", "Long", "Rational", |
| "SByte", "Undefined", "SShort", "SLong", "SRational", |
| "Float", "Double", "IFDPointer" |
| }; |
| |
| private static final boolean[] isIntegral = { |
| false, |
| true, false, true, true, false, |
| true, true, true, true, false, |
| false, false, false |
| }; |
| |
| /** The tag. */ |
| private TIFFTag tag; |
| |
| /** The tag number. */ |
| private int tagNumber; |
| |
| /** The tag type. */ |
| private int type; |
| |
| /** The number of data items present in the field. */ |
| private int count; |
| |
| /** The field data. */ |
| private Object data; |
| |
| /** The IFD contents if available. This will usually be a TIFFIFD. */ |
| private TIFFDirectory dir; |
| |
| /** The default constructor. */ |
| private TIFFField() {} |
| |
| private static String getAttribute(Node node, String attrName) { |
| NamedNodeMap attrs = node.getAttributes(); |
| return attrs.getNamedItem(attrName).getNodeValue(); |
| } |
| |
| private static void initData(Node node, |
| int[] otype, int[] ocount, Object[] odata) { |
| int type; |
| int count; |
| Object data = null; |
| |
| String typeName = node.getNodeName(); |
| typeName = typeName.substring(4); |
| typeName = typeName.substring(0, typeName.length() - 1); |
| type = TIFFField.getTypeByName(typeName); |
| if (type == -1) { |
| throw new IllegalArgumentException("typeName = " + typeName); |
| } |
| |
| Node child = node.getFirstChild(); |
| |
| count = 0; |
| while (child != null) { |
| String childTypeName = child.getNodeName().substring(4); |
| if (!typeName.equals(childTypeName)) { |
| // warning |
| } |
| |
| ++count; |
| child = child.getNextSibling(); |
| } |
| |
| if (count > 0) { |
| data = createArrayForType(type, count); |
| child = node.getFirstChild(); |
| int idx = 0; |
| while (child != null) { |
| String value = getAttribute(child, "value"); |
| |
| String numerator, denominator; |
| int slashPos; |
| |
| switch (type) { |
| case TIFFTag.TIFF_ASCII: |
| ((String[])data)[idx] = value; |
| break; |
| case TIFFTag.TIFF_BYTE: |
| case TIFFTag.TIFF_SBYTE: |
| ((byte[])data)[idx] = |
| (byte)Integer.parseInt(value); |
| break; |
| case TIFFTag.TIFF_SHORT: |
| ((char[])data)[idx] = |
| (char)Integer.parseInt(value); |
| break; |
| case TIFFTag.TIFF_SSHORT: |
| ((short[])data)[idx] = |
| (short)Integer.parseInt(value); |
| break; |
| case TIFFTag.TIFF_SLONG: |
| ((int[])data)[idx] = |
| Integer.parseInt(value); |
| break; |
| case TIFFTag.TIFF_LONG: |
| case TIFFTag.TIFF_IFD_POINTER: |
| ((long[])data)[idx] = |
| Long.parseLong(value); |
| break; |
| case TIFFTag.TIFF_FLOAT: |
| ((float[])data)[idx] = |
| Float.parseFloat(value); |
| break; |
| case TIFFTag.TIFF_DOUBLE: |
| ((double[])data)[idx] = |
| Double.parseDouble(value); |
| break; |
| case TIFFTag.TIFF_SRATIONAL: |
| slashPos = value.indexOf("/"); |
| numerator = value.substring(0, slashPos); |
| denominator = value.substring(slashPos + 1); |
| |
| ((int[][])data)[idx] = new int[2]; |
| ((int[][])data)[idx][0] = |
| Integer.parseInt(numerator); |
| ((int[][])data)[idx][1] = |
| Integer.parseInt(denominator); |
| break; |
| case TIFFTag.TIFF_RATIONAL: |
| slashPos = value.indexOf("/"); |
| numerator = value.substring(0, slashPos); |
| denominator = value.substring(slashPos + 1); |
| |
| ((long[][])data)[idx] = new long[2]; |
| ((long[][])data)[idx][0] = |
| Long.parseLong(numerator); |
| ((long[][])data)[idx][1] = |
| Long.parseLong(denominator); |
| break; |
| default: |
| // error |
| } |
| |
| idx++; |
| child = child.getNextSibling(); |
| } |
| } |
| |
| otype[0] = type; |
| ocount[0] = count; |
| odata[0] = data; |
| } |
| |
| /** |
| * Creates a {@code TIFFField} from a TIFF native image |
| * metadata node. If the value of the <tt>"number"</tt> attribute |
| * of the node is not found in {@code tagSet} then a new |
| * {@code TIFFTag} with name {@code TIFFTag.UNKNOWN_TAG_NAME} |
| * will be created and assigned to the field. |
| * |
| * @param tagSet The {@code TIFFTagSet} to which the |
| * {@code TIFFTag} of the field belongs. |
| * @param node A native TIFF image metadata {@code TIFFField} node. |
| * @throws NullPointerException if {@code node} is |
| * {@code null}. |
| * @throws IllegalArgumentException if the name of the node is not |
| * {@code "TIFFField"}. |
| * @throws NullPointerException if the node does not contain any data. |
| * @throws IllegalArgumentException if the combination of node attributes |
| * and data is not legal per the {@link #TIFFField(TIFFTag,int,int,Object)} |
| * constructor specification. |
| * @return A new {@code TIFFField}. |
| */ |
| public static TIFFField createFromMetadataNode(TIFFTagSet tagSet, |
| Node node) { |
| if (node == null) { |
| throw new NullPointerException("node == null!"); |
| } |
| String name = node.getNodeName(); |
| if (!name.equals("TIFFField")) { |
| throw new IllegalArgumentException("!name.equals(\"TIFFField\")"); |
| } |
| |
| int tagNumber = Integer.parseInt(getAttribute(node, "number")); |
| TIFFTag tag = null; |
| if (tagSet != null) { |
| tag = tagSet.getTag(tagNumber); |
| } |
| |
| int type = TIFFTag.TIFF_UNDEFINED; |
| int count = 0; |
| Object data = null; |
| |
| Node child = node.getFirstChild(); |
| if (child != null) { |
| String typeName = child.getNodeName(); |
| if (typeName.equals("TIFFUndefined")) { |
| String values = getAttribute(child, "value"); |
| StringTokenizer st = new StringTokenizer(values, ","); |
| count = st.countTokens(); |
| |
| byte[] bdata = new byte[count]; |
| for (int i = 0; i < count; i++) { |
| bdata[i] = (byte)Integer.parseInt(st.nextToken()); |
| } |
| |
| type = TIFFTag.TIFF_UNDEFINED; |
| data = bdata; |
| } else { |
| int[] otype = new int[1]; |
| int[] ocount = new int[1]; |
| Object[] odata = new Object[1]; |
| |
| initData(node.getFirstChild(), otype, ocount, odata); |
| type = otype[0]; |
| count = ocount[0]; |
| data = odata[0]; |
| } |
| } else if (tag != null) { |
| int t = TIFFTag.MAX_DATATYPE; |
| while(t >= TIFFTag.MIN_DATATYPE && !tag.isDataTypeOK(t)) { |
| t--; |
| } |
| type = t; |
| } |
| |
| if (tag == null) { |
| tag = new TIFFTag(TIFFTag.UNKNOWN_TAG_NAME, tagNumber, 1 << type); |
| } |
| |
| return new TIFFField(tag, type, count, data); |
| } |
| |
| /** |
| * Constructs a {@code TIFFField} with arbitrary data. The |
| * {@code type} parameter must be a value for which |
| * {@link TIFFTag#isDataTypeOK tag.isDataTypeOK()} |
| * returns {@code true}. The {@code data} parameter must |
| * be an array of a Java type appropriate for the type of the TIFF |
| * field. |
| * |
| * <p>Note that the value (data) of the {@code TIFFField} |
| * will always be the actual field value regardless of the number of |
| * bytes required for that value. This is the case despite the fact |
| * that the TIFF <i>IFD Entry</i> corresponding to the field may |
| * actually contain the offset to the value of the field rather than |
| * the value itself (the latter occurring if and only if the |
| * value fits into 4 bytes). In other words, the value of the |
| * field will already have been read from the TIFF stream. (An exception |
| * to this case may occur when the field represents the contents of a |
| * non-baseline IFD. In that case the data will be a {@code long[]} |
| * containing the offset to the IFD and the {@code TIFFDirectory} |
| * returned by {@link #getDirectory()} will be its contents.) |
| * |
| * @param tag The tag to associated with this field. |
| * @param type One of the {@code TIFFTag.TIFF_*} constants |
| * indicating the data type of the field as written to the TIFF stream. |
| * @param count The number of data values. |
| * @param data The actual data content of the field. |
| * |
| * @throws NullPointerException if {@code tag == null}. |
| * @throws IllegalArgumentException if {@code type} is not |
| * one of the {@code TIFFTag.TIFF_*} data type constants. |
| * @throws IllegalArgumentException if {@code type} is an unacceptable |
| * data type for the supplied {@code TIFFTag}. |
| * @throws IllegalArgumentException if {@code count < 0}. |
| * @throws IllegalArgumentException if {@code count < 1} |
| * and {@code type} is {@code TIFF_RATIONAL} or |
| * {@code TIFF_SRATIONAL}. |
| * @throws IllegalArgumentException if {@code count ≠ 1} |
| * and {@code type} is {@code TIFF_IFD_POINTER}. |
| * @throws NullPointerException if {@code data == null}. |
| * @throws IllegalArgumentException if {@code data} is an instance of |
| * a class incompatible with the specified type. |
| * @throws IllegalArgumentException if the size of the data array is wrong. |
| */ |
| public TIFFField(TIFFTag tag, int type, int count, Object data) { |
| if(tag == null) { |
| throw new NullPointerException("tag == null!"); |
| } else if(type < TIFFTag.MIN_DATATYPE || type > TIFFTag.MAX_DATATYPE) { |
| throw new IllegalArgumentException("Unknown data type "+type); |
| } else if(!tag.isDataTypeOK(type)) { |
| throw new IllegalArgumentException("Illegal data type " + type |
| + " for " + tag.getName() + " tag"); |
| } else if(count < 0) { |
| throw new IllegalArgumentException("count < 0!"); |
| } else if((type == TIFFTag.TIFF_RATIONAL |
| || type == TIFFTag.TIFF_SRATIONAL) |
| && count < 1) { |
| throw new IllegalArgumentException |
| ("Type is TIFF_RATIONAL or TIFF_SRATIONAL and count < 1"); |
| } else if (type == TIFFTag.TIFF_IFD_POINTER && count != 1) { |
| throw new IllegalArgumentException |
| ("Type is TIFF_IFD_POINTER count != 1"); |
| } else if(data == null) { |
| throw new NullPointerException("data == null!"); |
| } |
| |
| boolean isDataArrayCorrect = false; |
| |
| switch (type) { |
| case TIFFTag.TIFF_BYTE: |
| case TIFFTag.TIFF_SBYTE: |
| case TIFFTag.TIFF_UNDEFINED: |
| isDataArrayCorrect = data instanceof byte[] |
| && ((byte[])data).length == count; |
| break; |
| case TIFFTag.TIFF_ASCII: |
| isDataArrayCorrect = data instanceof String[] |
| && ((String[])data).length == count; |
| break; |
| case TIFFTag.TIFF_SHORT: |
| isDataArrayCorrect = data instanceof char[] |
| && ((char[])data).length == count; |
| break; |
| case TIFFTag.TIFF_LONG: |
| isDataArrayCorrect = data instanceof long[] |
| && ((long[])data).length == count; |
| break; |
| case TIFFTag.TIFF_IFD_POINTER: |
| isDataArrayCorrect = data instanceof long[] |
| && ((long[])data).length == 1; |
| break; |
| case TIFFTag.TIFF_RATIONAL: |
| isDataArrayCorrect = data instanceof long[][] |
| && ((long[][])data).length == count |
| && ((long[][])data)[0].length == 2; |
| break; |
| case TIFFTag.TIFF_SSHORT: |
| isDataArrayCorrect = data instanceof short[] |
| && ((short[])data).length == count; |
| break; |
| case TIFFTag.TIFF_SLONG: |
| isDataArrayCorrect = data instanceof int[] |
| && ((int[])data).length == count; |
| break; |
| case TIFFTag.TIFF_SRATIONAL: |
| isDataArrayCorrect = data instanceof int[][] |
| && ((int[][])data).length == count |
| && ((int[][])data)[0].length == 2; |
| break; |
| case TIFFTag.TIFF_FLOAT: |
| isDataArrayCorrect = data instanceof float[] |
| && ((float[])data).length == count; |
| break; |
| case TIFFTag.TIFF_DOUBLE: |
| isDataArrayCorrect = data instanceof double[] |
| && ((double[])data).length == count; |
| break; |
| default: |
| throw new IllegalArgumentException("Unknown data type "+type); |
| } |
| |
| if (!isDataArrayCorrect) { |
| throw new IllegalArgumentException |
| ("Illegal class or length for data array"); |
| } |
| |
| this.tag = tag; |
| this.tagNumber = tag.getNumber(); |
| this.type = type; |
| this.count = count; |
| this.data = data; |
| } |
| |
| /** |
| * Constructs a data array using {@link #createArrayForType |
| * createArrayForType()} and invokes |
| * {@link #TIFFField(TIFFTag,int,int,Object)} with the supplied |
| * parameters and the created array. |
| * |
| * @param tag The tag to associated with this field. |
| * @param type One of the {@code TIFFTag.TIFF_*} constants |
| * indicating the data type of the field as written to the TIFF stream. |
| * @param count The number of data values. |
| * @throws NullPointerException if {@code tag == null}. |
| * @throws IllegalArgumentException if {@code type} is not |
| * one of the {@code TIFFTag.TIFF_*} data type constants. |
| * @throws IllegalArgumentException if {@code type} is an unacceptable |
| * data type for the supplied {@code TIFFTag}. |
| * @throws IllegalArgumentException if {@code count < 0}. |
| * @see #TIFFField(TIFFTag,int,int,Object) |
| */ |
| public TIFFField(TIFFTag tag, int type, int count) { |
| this(tag, type, count, createArrayForType(type, count)); |
| } |
| |
| /** |
| * Constructs a {@code TIFFField} with a single non-negative integral |
| * value. |
| * The field will have type |
| * {@link TIFFTag#TIFF_SHORT TIFF_SHORT} if |
| * {@code val < 65536} and type |
| * {@link TIFFTag#TIFF_LONG TIFF_LONG} otherwise. The count |
| * of the field will be unity. |
| * |
| * @param tag The tag to associate with this field. |
| * @param value The value to associate with this field. |
| * @throws NullPointerException if {@code tag == null}. |
| * @throws IllegalArgumentException if the derived type is unacceptable |
| * for the supplied {@code TIFFTag}. |
| * @throws IllegalArgumentException if {@code value < 0}. |
| */ |
| public TIFFField(TIFFTag tag, int value) { |
| if(tag == null) { |
| throw new NullPointerException("tag == null!"); |
| } |
| if (value < 0) { |
| throw new IllegalArgumentException("value < 0!"); |
| } |
| |
| this.tag = tag; |
| this.tagNumber = tag.getNumber(); |
| this.count = 1; |
| |
| if (value < 65536) { |
| if (!tag.isDataTypeOK(TIFFTag.TIFF_SHORT)) { |
| throw new IllegalArgumentException("Illegal data type " |
| + TIFFTag.TIFF_SHORT + " for " + tag.getName() + " tag"); |
| } |
| this.type = TIFFTag.TIFF_SHORT; |
| char[] cdata = new char[1]; |
| cdata[0] = (char)value; |
| this.data = cdata; |
| } else { |
| if (!tag.isDataTypeOK(TIFFTag.TIFF_LONG)) { |
| throw new IllegalArgumentException("Illegal data type " |
| + TIFFTag.TIFF_LONG + " for " + tag.getName() + " tag"); |
| } |
| this.type = TIFFTag.TIFF_LONG; |
| long[] ldata = new long[1]; |
| ldata[0] = value; |
| this.data = ldata; |
| } |
| } |
| |
| /** |
| * Constructs a {@code TIFFField} with an IFD offset and contents. |
| * The offset will be stored as the data of this field as |
| * {@code long[] {offset}}. The directory will not be cloned. The count |
| * of the field will be unity. |
| * |
| * @param tag The tag to associated with this field. |
| * @param type One of the constants {@code TIFFTag.TIFF_LONG} or |
| * {@code TIFFTag.TIFF_IFD_POINTER}. |
| * @param offset The IFD offset. |
| * @param dir The directory. |
| * |
| * @throws NullPointerException if {@code tag == null}. |
| * @throws IllegalArgumentException if {@code type} is neither |
| * {@code TIFFTag.TIFF_LONG} nor {@code TIFFTag.TIFF_IFD_POINTER}. |
| * @throws IllegalArgumentException if {@code type} is an unacceptable |
| * data type for the supplied {@code TIFFTag}. |
| * @throws IllegalArgumentException if {@code offset} is non-positive. |
| * @throws NullPointerException if {@code dir == null}. |
| * |
| * @see #TIFFField(TIFFTag,int,int,Object) |
| */ |
| public TIFFField(TIFFTag tag, int type, long offset, TIFFDirectory dir) { |
| this(tag, type, 1, new long[] {offset}); |
| if (type != TIFFTag.TIFF_LONG && type != TIFFTag.TIFF_IFD_POINTER) { |
| throw new IllegalArgumentException("type " + type |
| + " is neither TIFFTag.TIFF_LONG nor TIFFTag.TIFF_IFD_POINTER"); |
| } else if (offset <= 0) { |
| throw new IllegalArgumentException("offset " + offset |
| + " is non-positive"); |
| } else if (dir == null) { |
| throw new NullPointerException("dir == null"); |
| } |
| this.dir = dir; |
| } |
| |
| /** |
| * Retrieves the tag associated with this field. |
| * |
| * @return The associated {@code TIFFTag}. |
| */ |
| public TIFFTag getTag() { |
| return tag; |
| } |
| |
| /** |
| * Retrieves the tag number in the range {@code [0, 65535]}. |
| * |
| * @return The tag number. |
| */ |
| public int getTagNumber() { |
| return tagNumber; |
| } |
| |
| /** |
| * Returns the type of the data stored in the field. For a TIFF 6.0 |
| * stream, the value will equal one of the {@code TIFFTag.TIFF_*} |
| * constants. For future revisions of TIFF, higher values are possible. |
| * |
| * @return The data type of the field value. |
| */ |
| public int getType() { |
| return type; |
| } |
| |
| /** |
| * Returns the name of the supplied data type constant. |
| * |
| * @param dataType One of the {@code TIFFTag.TIFF_*} constants |
| * indicating the data type of the field as written to the TIFF stream. |
| * @return The type name corresponding to the supplied type constant. |
| * @throws IllegalArgumentException if {@code dataType} is not |
| * one of the {@code TIFFTag.TIFF_*} data type constants. |
| */ |
| public static String getTypeName(int dataType) { |
| if (dataType < TIFFTag.MIN_DATATYPE || |
| dataType > TIFFTag.MAX_DATATYPE) { |
| throw new IllegalArgumentException("Unknown data type "+dataType); |
| } |
| |
| return typeNames[dataType]; |
| } |
| |
| /** |
| * Returns the data type constant corresponding to the supplied data |
| * type name. If the name is unknown {@code -1} will be returned. |
| * |
| * @param typeName The type name. |
| * @return One of the {@code TIFFTag.TIFF_*} constants or |
| * {@code -1} if the name is not recognized. |
| */ |
| public static int getTypeByName(String typeName) { |
| for (int i = TIFFTag.MIN_DATATYPE; i <= TIFFTag.MAX_DATATYPE; i++) { |
| if (typeName.equals(typeNames[i])) { |
| return i; |
| } |
| } |
| |
| return -1; |
| } |
| |
| /** |
| * Creates an array appropriate for the indicated data type. |
| * |
| * @param dataType One of the {@code TIFFTag.TIFF_*} data type |
| * constants. |
| * @param count The number of values in the array. |
| * @return An array appropriate for the specified data type. |
| * |
| * @throws IllegalArgumentException if {@code dataType} is not |
| * one of the {@code TIFFTag.TIFF_*} data type constants. |
| * @throws IllegalArgumentException if {@code count < 0}. |
| */ |
| public static Object createArrayForType(int dataType, int count) { |
| if(count < 0) { |
| throw new IllegalArgumentException("count < 0!"); |
| } |
| switch (dataType) { |
| case TIFFTag.TIFF_BYTE: |
| case TIFFTag.TIFF_SBYTE: |
| case TIFFTag.TIFF_UNDEFINED: |
| return new byte[count]; |
| case TIFFTag.TIFF_ASCII: |
| return new String[count]; |
| case TIFFTag.TIFF_SHORT: |
| return new char[count]; |
| case TIFFTag.TIFF_LONG: |
| case TIFFTag.TIFF_IFD_POINTER: |
| return new long[count]; |
| case TIFFTag.TIFF_RATIONAL: |
| return new long[count][2]; |
| case TIFFTag.TIFF_SSHORT: |
| return new short[count]; |
| case TIFFTag.TIFF_SLONG: |
| return new int[count]; |
| case TIFFTag.TIFF_SRATIONAL: |
| return new int[count][2]; |
| case TIFFTag.TIFF_FLOAT: |
| return new float[count]; |
| case TIFFTag.TIFF_DOUBLE: |
| return new double[count]; |
| default: |
| throw new IllegalArgumentException("Unknown data type "+dataType); |
| } |
| } |
| |
| /** |
| * Returns the {@code TIFFField} as a node named either |
| * <tt>"TIFFField"</tt> or <tt>"TIFFIFD"</tt> as described in the |
| * TIFF native image metadata specification. The node will be named |
| * <tt>"TIFFIFD"</tt> if and only if the field's data object is an |
| * instance of {@link TIFFDirectory} or equivalently |
| * {@link TIFFTag#isIFDPointer getTag.isIFDPointer()} returns |
| * {@code true}. |
| * |
| * @return a {@code Node} named <tt>"TIFFField"</tt> or |
| * <tt>"TIFFIFD"</tt>. |
| */ |
| public Node getAsNativeNode() { |
| return new TIFFFieldNode(this); |
| } |
| |
| /** |
| * Indicates whether the value associated with the field is of |
| * integral data type. |
| * |
| * @return Whether the field type is integral. |
| */ |
| public boolean isIntegral() { |
| return isIntegral[type]; |
| } |
| |
| /** |
| * Returns the number of data items present in the field. For |
| * {@code TIFFTag.TIFF_ASCII} fields, the value returned is the |
| * number of {@code String}s, not the total length of the |
| * data as in the file representation. |
| * |
| * @return The number of data items present in the field. |
| */ |
| public int getCount() { |
| return count; |
| } |
| |
| /** |
| * Returns a reference to the data object associated with the field. |
| * |
| * @return The data object of the field. |
| */ |
| public Object getData() { |
| return data; |
| } |
| |
| /** |
| * Returns the data as an uninterpreted array of |
| * {@code byte}s. The type of the field must be one of |
| * {@code TIFFTag.TIFF_BYTE}, {@code TIFF_SBYTE}, or |
| * {@code TIFF_UNDEFINED}. |
| * |
| * <p> For data in {@code TIFFTag.TIFF_BYTE} format, the application |
| * must take care when promoting the data to longer integral types |
| * to avoid sign extension. |
| * |
| * @throws ClassCastException if the field is not of type |
| * {@code TIFF_BYTE}, {@code TIFF_SBYTE}, or |
| * {@code TIFF_UNDEFINED}. |
| * @return The data as an uninterpreted array of bytes. |
| */ |
| public byte[] getAsBytes() { |
| return (byte[])data; |
| } |
| |
| /** |
| * Returns {@code TIFFTag.TIFF_SHORT} data as an array of |
| * {@code char}s (unsigned 16-bit integers). |
| * |
| * @throws ClassCastException if the field is not of type |
| * {@code TIFF_SHORT}. |
| * @return The data as an array of {@code char}s. |
| */ |
| public char[] getAsChars() { |
| return (char[])data; |
| } |
| |
| /** |
| * Returns {@code TIFFTag.TIFF_SSHORT} data as an array of |
| * {@code short}s (signed 16-bit integers). |
| * |
| * @throws ClassCastException if the field is not of type |
| * {@code TIFF_SSHORT}. |
| * @return The data as an array of {@code short}s. |
| */ |
| public short[] getAsShorts() { |
| return (short[])data; |
| } |
| |
| /** |
| * Returns {@code TIFFTag.TIFF_SLONG} data as an array of |
| * {@code int}s (signed 32-bit integers). |
| * |
| * @throws ClassCastException if the field is not of type |
| * {@code TIFF_SHORT}, {@code TIFF_SSHORT}, or |
| * {@code TIFF_SLONG}. |
| * @return The data as an array of {@code int}s. |
| */ |
| public int[] getAsInts() { |
| if (data instanceof int[]) { |
| return (int[])data; |
| } else if (data instanceof char[]){ |
| char[] cdata = (char[])data; |
| int[] idata = new int[cdata.length]; |
| for (int i = 0; i < cdata.length; i++) { |
| idata[i] = cdata[i] & 0xffff; |
| } |
| return idata; |
| } else if (data instanceof short[]){ |
| short[] sdata = (short[])data; |
| int[] idata = new int[sdata.length]; |
| for (int i = 0; i < sdata.length; i++) { |
| idata[i] = (int)sdata[i]; |
| } |
| return idata; |
| } else { |
| throw new ClassCastException("Data not char[], short[], or int[]!"); |
| } |
| } |
| |
| /** |
| * Returns {@code TIFFTag.TIFF_LONG} or |
| * {@code TIFF_IFD_POINTER} data as an array of |
| * {@code long}s (signed 64-bit integers). |
| * |
| * @throws ClassCastException if the field is not of type |
| * {@code TIFF_LONG} or {@code TIFF_IFD_POINTER}. |
| * @return The data as an array of {@code long}s. |
| */ |
| public long[] getAsLongs() { |
| return (long[])data; |
| } |
| |
| /** |
| * Returns {@code TIFFTag.TIFF_FLOAT} data as an array of |
| * {@code float}s (32-bit floating-point values). |
| * |
| * @throws ClassCastException if the field is not of type |
| * {@code TIFF_FLOAT}. |
| * @return The data as an array of {@code float}s. |
| */ |
| public float[] getAsFloats() { |
| return (float[])data; |
| } |
| |
| /** |
| * Returns {@code TIFFTag.TIFF_DOUBLE} data as an array of |
| * {@code double}s (64-bit floating-point values). |
| * |
| * @throws ClassCastException if the field is not of type |
| * {@code TIFF_DOUBLE}. |
| * @return The data as an array of {@code double}s. |
| */ |
| public double[] getAsDoubles() { |
| return (double[])data; |
| } |
| |
| /** |
| * Returns {@code TIFFTag.TIFF_SRATIONAL} data as an array of |
| * 2-element arrays of {@code int}s. |
| * |
| * @throws ClassCastException if the field is not of type |
| * {@code TIFF_SRATIONAL}. |
| * @return The data as an array of signed rationals. |
| */ |
| public int[][] getAsSRationals() { |
| return (int[][])data; |
| } |
| |
| /** |
| * Returns {@code TIFFTag.TIFF_RATIONAL} data as an array of |
| * 2-element arrays of {@code long}s. |
| * |
| * @throws ClassCastException if the field is not of type |
| * {@code TIFF_RATIONAL}. |
| * @return The data as an array of unsigned rationals. |
| */ |
| public long[][] getAsRationals() { |
| return (long[][])data; |
| } |
| |
| /** |
| * Returns data in any format as an {@code int}. |
| * |
| * <p> {@code TIFFTag.TIFF_BYTE} values are treated as unsigned; that |
| * is, no sign extension will take place and the returned value |
| * will be in the range [0, 255]. {@code TIFF_SBYTE} data |
| * will be returned in the range [-128, 127]. |
| * |
| * <p> A {@code TIFF_UNDEFINED} value is treated as though |
| * it were a {@code TIFF_BYTE}. |
| * |
| * <p> Data in {@code TIFF_SLONG}, {@code TIFF_LONG}, |
| * {@code TIFF_FLOAT}, {@code TIFF_DOUBLE} or |
| * {@code TIFF_IFD_POINTER} format are simply cast to |
| * {@code int} and may suffer from truncation. |
| * |
| * <p> Data in {@code TIFF_SRATIONAL} or |
| * {@code TIFF_RATIONAL} format are evaluated by dividing the |
| * numerator into the denominator using double-precision |
| * arithmetic and then casting to {@code int}. Loss of |
| * precision and truncation may occur. |
| * |
| * <p> Data in {@code TIFF_ASCII} format will be parsed as by |
| * the {@code Double.parseDouble} method, with the result |
| * case to {@code int}. |
| * |
| * @param index The index of the data. |
| * @return The data at the given index as an {@code int}. |
| */ |
| public int getAsInt(int index) { |
| switch (type) { |
| case TIFFTag.TIFF_BYTE: |
| case TIFFTag.TIFF_UNDEFINED: |
| return ((byte[])data)[index] & 0xff; |
| case TIFFTag.TIFF_SBYTE: |
| return ((byte[])data)[index]; |
| case TIFFTag.TIFF_SHORT: |
| return ((char[])data)[index] & 0xffff; |
| case TIFFTag.TIFF_SSHORT: |
| return ((short[])data)[index]; |
| case TIFFTag.TIFF_SLONG: |
| return ((int[])data)[index]; |
| case TIFFTag.TIFF_LONG: |
| case TIFFTag.TIFF_IFD_POINTER: |
| return (int)((long[])data)[index]; |
| case TIFFTag.TIFF_FLOAT: |
| return (int)((float[])data)[index]; |
| case TIFFTag.TIFF_DOUBLE: |
| return (int)((double[])data)[index]; |
| case TIFFTag.TIFF_SRATIONAL: |
| int[] ivalue = getAsSRational(index); |
| return (int)((double)ivalue[0]/ivalue[1]); |
| case TIFFTag.TIFF_RATIONAL: |
| long[] lvalue = getAsRational(index); |
| return (int)((double)lvalue[0]/lvalue[1]); |
| case TIFFTag.TIFF_ASCII: |
| String s = ((String[])data)[index]; |
| return (int)Double.parseDouble(s); |
| default: |
| throw new ClassCastException(); // should never happen |
| } |
| } |
| |
| /** |
| * Returns data in any format as a {@code long}. |
| * |
| * <p> {@code TIFFTag.TIFF_BYTE} and {@code TIFF_UNDEFINED} data |
| * are treated as unsigned; that is, no sign extension will take |
| * place and the returned value will be in the range [0, 255]. |
| * {@code TIFF_SBYTE} data will be returned in the range |
| * [-128, 127]. |
| * |
| * <p> Data in {@code TIFF_FLOAT} and {@code TIFF_DOUBLE} are |
| * simply cast to {@code long} and may suffer from truncation. |
| * |
| * <p> Data in {@code TIFF_SRATIONAL} or |
| * {@code TIFF_RATIONAL} format are evaluated by dividing the |
| * numerator into the denominator using double-precision |
| * arithmetic and then casting to {@code long}. Loss of |
| * precision and truncation may occur. |
| * |
| * <p> Data in {@code TIFF_ASCII} format will be parsed as by |
| * the {@code Double.parseDouble} method, with the result |
| * cast to {@code long}. |
| * |
| * @param index The index of the data. |
| * @return The data at the given index as a {@code long}. |
| */ |
| public long getAsLong(int index) { |
| switch (type) { |
| case TIFFTag.TIFF_BYTE: |
| case TIFFTag.TIFF_UNDEFINED: |
| return ((byte[])data)[index] & 0xff; |
| case TIFFTag.TIFF_SBYTE: |
| return ((byte[])data)[index]; |
| case TIFFTag.TIFF_SHORT: |
| return ((char[])data)[index] & 0xffff; |
| case TIFFTag.TIFF_SSHORT: |
| return ((short[])data)[index]; |
| case TIFFTag.TIFF_SLONG: |
| return ((int[])data)[index]; |
| case TIFFTag.TIFF_LONG: |
| case TIFFTag.TIFF_IFD_POINTER: |
| return ((long[])data)[index]; |
| case TIFFTag.TIFF_FLOAT: |
| return (long)((float[])data)[index]; |
| case TIFFTag.TIFF_DOUBLE: |
| return (long)((double[])data)[index]; |
| case TIFFTag.TIFF_SRATIONAL: |
| int[] ivalue = getAsSRational(index); |
| return (long)((double)ivalue[0]/ivalue[1]); |
| case TIFFTag.TIFF_RATIONAL: |
| long[] lvalue = getAsRational(index); |
| return (long)((double)lvalue[0]/lvalue[1]); |
| case TIFFTag.TIFF_ASCII: |
| String s = ((String[])data)[index]; |
| return (long)Double.parseDouble(s); |
| default: |
| throw new ClassCastException(); // should never happen |
| } |
| } |
| |
| /** |
| * Returns data in any format as a {@code float}. |
| * |
| * <p> {@code TIFFTag.TIFF_BYTE} and {@code TIFF_UNDEFINED} data |
| * are treated as unsigned; that is, no sign extension will take |
| * place and the returned value will be in the range [0, 255]. |
| * {@code TIFF_SBYTE} data will be returned in the range |
| * [-128, 127]. |
| * |
| * <p> Data in {@code TIFF_SLONG}, {@code TIFF_LONG}, |
| * {@code TIFF_DOUBLE}, or {@code TIFF_IFD_POINTER} format are |
| * simply cast to {@code float} and may suffer from |
| * truncation. |
| * |
| * <p> Data in {@code TIFF_SRATIONAL} or |
| * {@code TIFF_RATIONAL} format are evaluated by dividing the |
| * numerator into the denominator using double-precision |
| * arithmetic and then casting to {@code float}. |
| * |
| * <p> Data in {@code TIFF_ASCII} format will be parsed as by |
| * the {@code Double.parseDouble} method, with the result |
| * cast to {@code float}. |
| * |
| * @param index The index of the data. |
| * @return The data at the given index as a {@code float}. |
| */ |
| public float getAsFloat(int index) { |
| switch (type) { |
| case TIFFTag.TIFF_BYTE: |
| case TIFFTag.TIFF_UNDEFINED: |
| return ((byte[])data)[index] & 0xff; |
| case TIFFTag.TIFF_SBYTE: |
| return ((byte[])data)[index]; |
| case TIFFTag.TIFF_SHORT: |
| return ((char[])data)[index] & 0xffff; |
| case TIFFTag.TIFF_SSHORT: |
| return ((short[])data)[index]; |
| case TIFFTag.TIFF_SLONG: |
| return ((int[])data)[index]; |
| case TIFFTag.TIFF_LONG: |
| case TIFFTag.TIFF_IFD_POINTER: |
| return ((long[])data)[index]; |
| case TIFFTag.TIFF_FLOAT: |
| return ((float[])data)[index]; |
| case TIFFTag.TIFF_DOUBLE: |
| return (float)((double[])data)[index]; |
| case TIFFTag.TIFF_SRATIONAL: |
| int[] ivalue = getAsSRational(index); |
| return (float)((double)ivalue[0]/ivalue[1]); |
| case TIFFTag.TIFF_RATIONAL: |
| long[] lvalue = getAsRational(index); |
| return (float)((double)lvalue[0]/lvalue[1]); |
| case TIFFTag.TIFF_ASCII: |
| String s = ((String[])data)[index]; |
| return (float)Double.parseDouble(s); |
| default: |
| throw new ClassCastException(); // should never happen |
| } |
| } |
| |
| /** |
| * Returns data in any format as a {@code double}. |
| * |
| * <p> {@code TIFFTag.TIFF_BYTE} and {@code TIFF_UNDEFINED} data |
| * are treated as unsigned; that is, no sign extension will take |
| * place and the returned value will be in the range [0, 255]. |
| * {@code TIFF_SBYTE} data will be returned in the range |
| * [-128, 127]. |
| * |
| * <p> Data in {@code TIFF_SRATIONAL} or |
| * {@code TIFF_RATIONAL} format are evaluated by dividing the |
| * numerator into the denominator using double-precision |
| * arithmetic. |
| * |
| * <p> Data in {@code TIFF_ASCII} format will be parsed as by |
| * the {@code Double.parseDouble} method. |
| * |
| * @param index The index of the data. |
| * @return The data at the given index as a {@code double}. |
| */ |
| public double getAsDouble(int index) { |
| switch (type) { |
| case TIFFTag.TIFF_BYTE: |
| case TIFFTag.TIFF_UNDEFINED: |
| return ((byte[])data)[index] & 0xff; |
| case TIFFTag.TIFF_SBYTE: |
| return ((byte[])data)[index]; |
| case TIFFTag.TIFF_SHORT: |
| return ((char[])data)[index] & 0xffff; |
| case TIFFTag.TIFF_SSHORT: |
| return ((short[])data)[index]; |
| case TIFFTag.TIFF_SLONG: |
| return ((int[])data)[index]; |
| case TIFFTag.TIFF_LONG: |
| case TIFFTag.TIFF_IFD_POINTER: |
| return ((long[])data)[index]; |
| case TIFFTag.TIFF_FLOAT: |
| return ((float[])data)[index]; |
| case TIFFTag.TIFF_DOUBLE: |
| return ((double[])data)[index]; |
| case TIFFTag.TIFF_SRATIONAL: |
| int[] ivalue = getAsSRational(index); |
| return (double)ivalue[0]/ivalue[1]; |
| case TIFFTag.TIFF_RATIONAL: |
| long[] lvalue = getAsRational(index); |
| return (double)lvalue[0]/lvalue[1]; |
| case TIFFTag.TIFF_ASCII: |
| String s = ((String[])data)[index]; |
| return Double.parseDouble(s); |
| default: |
| throw new ClassCastException(); // should never happen |
| } |
| } |
| |
| /** |
| * Returns a {@code TIFFTag.TIFF_ASCII} value as a |
| * {@code String}. |
| * |
| * @throws ClassCastException if the field is not of type |
| * {@code TIFF_ASCII}. |
| * |
| * @param index The index of the data. |
| * @return The data at the given index as a {@code String}. |
| */ |
| public String getAsString(int index) { |
| return ((String[])data)[index]; |
| } |
| |
| /** |
| * Returns a {@code TIFFTag.TIFF_SRATIONAL} data item as a |
| * two-element array of {@code int}s. |
| * |
| * @param index The index of the data. |
| * @return The data at the given index as a signed rational. |
| * @throws ClassCastException if the field is not of type |
| * {@code TIFF_SRATIONAL}. |
| */ |
| public int[] getAsSRational(int index) { |
| return ((int[][])data)[index]; |
| } |
| |
| /** |
| * Returns a TIFFTag.TIFF_RATIONAL data item as a two-element array |
| * of ints. |
| * |
| * @param index The index of the data. |
| * @return The data at the given index as an unsigned rational. |
| * @throws ClassCastException if the field is not of type |
| * {@code TIFF_RATIONAL}. |
| */ |
| public long[] getAsRational(int index) { |
| return ((long[][])data)[index]; |
| } |
| |
| |
| /** |
| * Returns a {@code String} containing a human-readable |
| * version of the data item. Data of type |
| * {@code TIFFTag.TIFF_RATIONAL} or {@code TIFF_SRATIONAL} are |
| * represented as a pair of integers separated by a |
| * {@code '/'} character. If the numerator of a |
| * {@code TIFFTag.TIFF_RATIONAL} or {@code TIFF_SRATIONAL} is an integral |
| * multiple of the denominator, then the value is represented as |
| * {@code "q/1"} where {@code q} is the quotient of the numerator and |
| * denominator. |
| * |
| * @param index The index of the data. |
| * @return The data at the given index as a {@code String}. |
| * @throws ClassCastException if the field is not of one of the |
| * legal field types. |
| */ |
| public String getValueAsString(int index) { |
| switch (type) { |
| case TIFFTag.TIFF_ASCII: |
| return ((String[])data)[index]; |
| case TIFFTag.TIFF_BYTE: |
| case TIFFTag.TIFF_UNDEFINED: |
| return Integer.toString(((byte[])data)[index] & 0xff); |
| case TIFFTag.TIFF_SBYTE: |
| return Integer.toString(((byte[])data)[index]); |
| case TIFFTag.TIFF_SHORT: |
| return Integer.toString(((char[])data)[index] & 0xffff); |
| case TIFFTag.TIFF_SSHORT: |
| return Integer.toString(((short[])data)[index]); |
| case TIFFTag.TIFF_SLONG: |
| return Integer.toString(((int[])data)[index]); |
| case TIFFTag.TIFF_LONG: |
| case TIFFTag.TIFF_IFD_POINTER: |
| return Long.toString(((long[])data)[index]); |
| case TIFFTag.TIFF_FLOAT: |
| return Float.toString(((float[])data)[index]); |
| case TIFFTag.TIFF_DOUBLE: |
| return Double.toString(((double[])data)[index]); |
| case TIFFTag.TIFF_SRATIONAL: |
| int[] ivalue = getAsSRational(index); |
| String srationalString; |
| if(ivalue[1] != 0 && ivalue[0] % ivalue[1] == 0) { |
| // If the denominator is a non-zero integral divisor |
| // of the numerator then convert the fraction to be |
| // with respect to a unity denominator. |
| srationalString = |
| Integer.toString(ivalue[0] / ivalue[1]) + "/1"; |
| } else { |
| // Use the values directly. |
| srationalString = |
| Integer.toString(ivalue[0]) + |
| "/" + |
| Integer.toString(ivalue[1]); |
| } |
| return srationalString; |
| case TIFFTag.TIFF_RATIONAL: |
| long[] lvalue = getAsRational(index); |
| String rationalString; |
| if(lvalue[1] != 0L && lvalue[0] % lvalue[1] == 0) { |
| // If the denominator is a non-zero integral divisor |
| // of the numerator then convert the fraction to be |
| // with respect to a unity denominator. |
| rationalString = |
| Long.toString(lvalue[0] / lvalue[1]) + "/1"; |
| } else { |
| // Use the values directly. |
| rationalString = |
| Long.toString(lvalue[0]) + |
| "/" + |
| Long.toString(lvalue[1]); |
| } |
| return rationalString; |
| default: |
| throw new ClassCastException(); // should never happen |
| } |
| } |
| |
| /** |
| * Returns whether the field has a {@code TIFFDirectory}. |
| * |
| * @return true if and only if getDirectory() returns non-null. |
| */ |
| public boolean hasDirectory() { |
| return getDirectory() != null; |
| } |
| |
| /** |
| * Returns the associated {@code TIFFDirectory}, if available. If no |
| * directory is set, then {@code null} will be returned. |
| * |
| * @return the TIFFDirectory instance or null. |
| */ |
| public TIFFDirectory getDirectory() { |
| return dir; |
| } |
| |
| /** |
| * Clones the field and all the information contained therein. |
| * |
| * @return A clone of this {@code TIFFField}. |
| * @throws CloneNotSupportedException if the instance cannot be cloned. |
| */ |
| @Override |
| public TIFFField clone() throws CloneNotSupportedException { |
| TIFFField field = (TIFFField)super.clone(); |
| |
| Object fieldData; |
| switch (type) { |
| case TIFFTag.TIFF_BYTE: |
| case TIFFTag.TIFF_UNDEFINED: |
| case TIFFTag.TIFF_SBYTE: |
| fieldData = ((byte[])data).clone(); |
| break; |
| case TIFFTag.TIFF_SHORT: |
| fieldData = ((char[])data).clone(); |
| break; |
| case TIFFTag.TIFF_SSHORT: |
| fieldData = ((short[])data).clone(); |
| break; |
| case TIFFTag.TIFF_SLONG: |
| fieldData = ((int[])data).clone(); |
| break; |
| case TIFFTag.TIFF_LONG: |
| case TIFFTag.TIFF_IFD_POINTER: |
| fieldData = ((long[])data).clone(); |
| break; |
| case TIFFTag.TIFF_FLOAT: |
| fieldData = ((float[])data).clone(); |
| break; |
| case TIFFTag.TIFF_DOUBLE: |
| fieldData = ((double[])data).clone(); |
| break; |
| case TIFFTag.TIFF_SRATIONAL: |
| fieldData = ((int[][])data).clone(); |
| break; |
| case TIFFTag.TIFF_RATIONAL: |
| fieldData = ((long[][])data).clone(); |
| break; |
| case TIFFTag.TIFF_ASCII: |
| fieldData = ((String[])data).clone(); |
| break; |
| default: |
| throw new ClassCastException(); // should never happen |
| } |
| |
| field.tag = tag; |
| field.tagNumber = tagNumber; |
| field.type = type; |
| field.count = count; |
| field.data = fieldData; |
| field.dir = dir != null ? dir.clone() : null; |
| |
| return field; |
| } |
| } |