/* * Copyright (c) 2005, 2015, 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. * *
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 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:
*
*
*
*
* TIFF Data Type * | ** Java Constant * | ** Java Data Type * | ** Java Type Name * | *
---|---|---|---|
* BYTE * | ** {@link TIFFTag#TIFF_BYTE} * | *
* byte
* |
*
* "Byte"
* |
*
* ASCII * | ** {@link TIFFTag#TIFF_ASCII} * | *
* String
* |
*
* "Ascii"
* |
*
* SHORT * | ** {@link TIFFTag#TIFF_SHORT} * | *
* char
* |
*
* "Short"
* |
*
* LONG * | ** {@link TIFFTag#TIFF_LONG} * | *
* long
* |
*
* "Long"
* |
*
* RATIONAL * | ** {@link TIFFTag#TIFF_RATIONAL} * | *
* long[2] {numerator, denominator}
* |
*
* "Rational"
* |
*
* SBYTE * | ** {@link TIFFTag#TIFF_SBYTE} * | *
* byte
* |
*
* "SByte"
* |
*
* UNDEFINED * | ** {@link TIFFTag#TIFF_UNDEFINED} * | *
* byte
* |
*
* "Undefined"
* |
*
* SSHORT * | ** {@link TIFFTag#TIFF_SSHORT} * | *
* short
* |
*
* "SShort"
* |
*
* SLONG * | ** {@link TIFFTag#TIFF_SLONG} * | *
* int
* |
*
* "SLong"
* |
*
* SRATIONAL * | ** {@link TIFFTag#TIFF_SRATIONAL} * | *
* int[2] {numerator, denominator}
* |
*
* "SRational"
* |
*
* FLOAT * | ** {@link TIFFTag#TIFF_FLOAT} * | *
* float
* |
*
* "Float"
* |
*
* DOUBLE * | ** {@link TIFFTag#TIFF_DOUBLE} * | *
* double
* |
*
* "Double"
* |
*
* IFD * | ** {@link TIFFTag#TIFF_IFD_POINTER} * | *
* long
* |
*
* "IFDPointer"
* |
*
TIFFField
from a TIFF native image
* metadata node. If the value of the "tagNumber" attribute
* of the node is not found in tagSet
then a new
* TIFFTag
with name TIFFTag.UNKNOWN_TAG_NAME
* will be created and assigned to the field.
*
* @param tagSet The TIFFTagSet
to which the
* TIFFTag
of the field belongs.
* @param node A native TIFF image metadata TIFFField
node.
* @throws NullPointerException if node
is
* null
.
* @throws IllegalArgumentException if the name of the node is not
* "TIFFField"
.
* @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 TIFFField
with arbitrary data. The
* type
parameter must be a value for which
* {@link TIFFTag#isDataTypeOK tag.isDataTypeOK()}
* returns true
. The data
parameter must
* be an array of a Java type appropriate for the type of the TIFF
* field.
*
* Note that the value (data) of the 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 IFD Entry 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 long[]
* containing the offset to the IFD and the TIFFDirectory
* returned by {@link #getDirectory()} will be its contents.)
*
* @param tag The tag to associated with this field.
* @param type One of the 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 tag == null
.
* @throws IllegalArgumentException if type
is not
* one of the TIFFTag.TIFF_*
data type constants.
* @throws IllegalArgumentException if type
is an unacceptable
* data type for the supplied TIFFTag
.
* @throws IllegalArgumentException if count < 0
.
* @throws NullPointerException if data == null
.
* @throws IllegalArgumentException if 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(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 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 tag == null
.
* @throws IllegalArgumentException if type
is not
* one of the TIFFTag.TIFF_*
data type constants.
* @throws IllegalArgumentException if type
is an unacceptable
* data type for the supplied TIFFTag
.
* @throws IllegalArgumentException if 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 TIFFField
with a single non-negative integral
* value.
* The field will have type
* {@link TIFFTag#TIFF_SHORT TIFF_SHORT} if
* 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 tag == null
.
* @throws IllegalArgumentException if the derived type is unacceptable
* for the supplied TIFFTag
.
* @throws IllegalArgumentException if 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 TIFFField
with an IFD offset and contents.
* The offset will be stored as the data of this field as
* 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 TIFFTag.TIFF_LONG
or
* TIFFTag.TIFF_IFD_POINTER
.
* @param offset The IFD offset.
* @param dir The directory.
*
* @throws NullPointerException if tag == null
.
* @throws IllegalArgumentException if type
is neither
* TIFFTag.TIFF_LONG
nor TIFFTag.TIFF_IFD_POINTER
.
* @throws IllegalArgumentException if type
is an unacceptable
* data type for the supplied TIFFTag
.
* @throws IllegalArgumentException if offset
is non-positive.
* @throws NullPointerException if 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 TIFFTag
.
*/
public TIFFTag getTag() {
return tag;
}
/**
* Retrieves the tag number in the range [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 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 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 dataType
is not
* one of the 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 -1
will be returned.
*
* @param typeName The type name.
* @return One of the TIFFTag.TIFF_*
constants or
* -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 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 dataType
is not
* one of the TIFFTag.TIFF_*
data type constants.
* @throws IllegalArgumentException if 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 TIFFField
as a node named either
* "TIFFField" or "TIFFIFD" as described in the
* TIFF native image metadata specification. The node will be named
* "TIFFIFD" if and only if the field's data object is an
* instance of {@link TIFFDirectory} or equivalently
* {@link TIFFTag#isIFDPointer getTag.isIFDPointer()} returns
* true
.
*
* @return a Node
named "TIFFField" or
* "TIFFIFD".
*/
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
* TIFFTag.TIFF_ASCII
fields, the value returned is the
* number of 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
* byte
s. The type of the field must be one of
* TIFFTag.TIFF_BYTE
, TIFF_SBYTE
, or
* TIFF_UNDEFINED
.
*
*
For data in 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
* TIFF_BYTE
, TIFF_SBYTE
, or
* TIFF_UNDEFINED
.
* @return The data as an uninterpreted array of bytes.
*/
public byte[] getAsBytes() {
return (byte[])data;
}
/**
* Returns TIFFTag.TIFF_SHORT
data as an array of
* char
s (unsigned 16-bit integers).
*
* @throws ClassCastException if the field is not of type
* TIFF_SHORT
.
* @return The data as an array of {@code char}s.
*/
public char[] getAsChars() {
return (char[])data;
}
/**
* Returns TIFFTag.TIFF_SSHORT
data as an array of
* short
s (signed 16-bit integers).
*
* @throws ClassCastException if the field is not of type
* TIFF_SSHORT
.
* @return The data as an array of {@code short}s.
*/
public short[] getAsShorts() {
return (short[])data;
}
/**
* Returns TIFFTag.TIFF_SLONG
data as an array of
* int
s (signed 32-bit integers).
*
* @throws ClassCastException if the field is not of type
* TIFF_SHORT
, TIFF_SSHORT
, or
* 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 TIFFTag.TIFF_LONG
or
* TIFF_IFD_POINTER
data as an array of
* long
s (signed 64-bit integers).
*
* @throws ClassCastException if the field is not of type
* TIFF_LONG
or TIFF_IFD_POINTER
.
* @return The data as an array of {@code long}s.
*/
public long[] getAsLongs() {
return (long[])data;
}
/**
* Returns TIFFTag.TIFF_FLOAT
data as an array of
* float
s (32-bit floating-point values).
*
* @throws ClassCastException if the field is not of type
* TIFF_FLOAT
.
* @return The data as an array of {@code float}s.
*/
public float[] getAsFloats() {
return (float[])data;
}
/**
* Returns TIFFTag.TIFF_DOUBLE
data as an array of
* double
s (64-bit floating-point values).
*
* @throws ClassCastException if the field is not of type
* TIFF_DOUBLE
.
* @return The data as an array of {@code double}s.
*/
public double[] getAsDoubles() {
return (double[])data;
}
/**
* Returns TIFFTag.TIFF_SRATIONAL
data as an array of
* 2-element arrays of int
s.
*
* @throws ClassCastException if the field is not of type
* TIFF_SRATIONAL
.
* @return The data as an array of signed rationals.
*/
public int[][] getAsSRationals() {
return (int[][])data;
}
/**
* Returns TIFFTag.TIFF_RATIONAL
data as an array of
* 2-element arrays of long
s.
*
* @throws ClassCastException if the field is not of type
* TIFF_RATIONAL
.
* @return The data as an array of unsigned rationals.
*/
public long[][] getAsRationals() {
return (long[][])data;
}
/**
* Returns data in any format as an int
.
*
*
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]. TIFF_SBYTE
data
* will be returned in the range [-128, 127].
*
*
A TIFF_UNDEFINED
value is treated as though
* it were a TIFF_BYTE
.
*
*
Data in TIFF_SLONG
, TIFF_LONG
,
* TIFF_FLOAT
, TIFF_DOUBLE
or
* TIFF_IFD_POINTER
format are simply cast to
* int
and may suffer from truncation.
*
*
Data in TIFF_SRATIONAL
or
* TIFF_RATIONAL
format are evaluated by dividing the
* numerator into the denominator using double-precision
* arithmetic and then casting to int
. Loss of
* precision and truncation may occur.
*
*
Data in TIFF_ASCII
format will be parsed as by
* the Double.parseDouble
method, with the result
* case to 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 long
.
*
*
TIFFTag.TIFF_BYTE
and 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].
* TIFF_SBYTE
data will be returned in the range
* [-128, 127].
*
*
Data in TIFF_ASCII
format will be parsed as by
* the Double.parseDouble
method, with the result
* cast to 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_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 float
.
*
*
TIFFTag.TIFF_BYTE
and 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].
* TIFF_SBYTE
data will be returned in the range
* [-128, 127].
*
*
Data in TIFF_SLONG
, TIFF_LONG
,
* TIFF_DOUBLE
, or TIFF_IFD_POINTER
format are
* simply cast to float
and may suffer from
* truncation.
*
*
Data in TIFF_SRATIONAL
or
* TIFF_RATIONAL
format are evaluated by dividing the
* numerator into the denominator using double-precision
* arithmetic and then casting to float
.
*
*
Data in TIFF_ASCII
format will be parsed as by
* the Double.parseDouble
method, with the result
* cast to 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 double
.
*
*
TIFFTag.TIFF_BYTE
and 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].
* TIFF_SBYTE
data will be returned in the range
* [-128, 127].
*
*
Data in TIFF_SRATIONAL
or
* TIFF_RATIONAL
format are evaluated by dividing the
* numerator into the denominator using double-precision
* arithmetic.
*
*
Data in TIFF_ASCII
format will be parsed as by
* the 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 TIFFTag.TIFF_ASCII
value as a
* String
.
*
* @throws ClassCastException if the field is not of type
* 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 TIFFTag.TIFF_SRATIONAL
data item as a
* two-element array of 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
* 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
* TIFF_RATIONAL
.
*/
public long[] getAsRational(int index) {
return ((long[][])data)[index];
}
/**
* Returns a String
containing a human-readable
* version of the data item. Data of type
* TIFFTag.TIFF_RATIONAL
or TIFF_SRATIONAL
are
* represented as a pair of integers separated by a
* '/'
character.
*
* @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 TIFFDirectory
.
*
* @return true if and only if getDirectory() returns non-null.
*/
public boolean hasDirectory() {
return getDirectory() != null;
}
/**
* Returns the associated TIFFDirectory
, if available. If no
* directory is set, then 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 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;
}
}