Path: blob/master/src/java.desktop/share/classes/javax/imageio/plugins/tiff/TIFFField.java
41159 views
/*1* Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/24package javax.imageio.plugins.tiff;2526import java.util.StringTokenizer;27import org.w3c.dom.NamedNodeMap;28import org.w3c.dom.Node;29import com.sun.imageio.plugins.tiff.TIFFFieldNode;30import com.sun.imageio.plugins.tiff.TIFFIFD;3132/**33* A class representing a field in a TIFF 6.0 Image File Directory.34*35* <p> A field in a TIFF Image File Directory (IFD) is defined as a36* tag number accompanied by a sequence of values of identical data type.37* TIFF 6.0 defines 12 data types; a 13th type {@code IFD} is38* defined in TIFF Tech Note 1 of TIFF Specification Supplement 1. These39* TIFF data types are referred to by Java constants and mapped internally40* onto Java language data types and type names as follows:41*42* <table class="striped">43* <caption>TIFF Data Type to Java Data Type Mapping</caption>44* <thead>45* <tr>46* <th scope="col">TIFF Data Type47* <th scope="col">Java Constant48* <th scope="col">Java Data Type49* <th scope="col">Java Type Name50* </thead>51* <tbody>52* <tr>53* <th scope="row">{@code BYTE}54* <td>{@link TIFFTag#TIFF_BYTE}55* <td>{@code byte}56* <td>{@code "Byte"}57* <tr>58* <th scope="row">{@code ASCII}59* <td>{@link TIFFTag#TIFF_ASCII}60* <td>{@code String}61* <td>{@code "Ascii"}62* <tr>63* <th scope="row">{@code SHORT}64* <td>{@link TIFFTag#TIFF_SHORT}65* <td>{@code char}66* <td>{@code "Short"}67* <tr>68* <th scope="row">{@code LONG}69* <td>{@link TIFFTag#TIFF_LONG}70* <td>{@code long}71* <td>{@code "Long"}72* <tr>73* <th scope="row">{@code RATIONAL}74* <td>{@link TIFFTag#TIFF_RATIONAL}75* <td>{@code long[2]} {numerator, denominator}76* <td>{@code "Rational"}77* <tr>78* <th scope="row">{@code SBYTE}79* <td>{@link TIFFTag#TIFF_SBYTE}80* <td>{@code byte}81* <td>{@code "SByte"}82* <tr>83* <th scope="row">{@code UNDEFINED}84* <td>{@link TIFFTag#TIFF_UNDEFINED}85* <td>{@code byte}86* <td>{@code "Undefined"}87* <tr>88* <th scope="row">{@code SSHORT}89* <td>{@link TIFFTag#TIFF_SSHORT}90* <td>{@code short}91* <td>{@code "SShort"}92* <tr>93* <th scope="row">{@code SLONG}94* <td>{@link TIFFTag#TIFF_SLONG}95* <td>{@code int}96* <td>{@code "SLong"}97* <tr>98* <th scope="row">{@code SRATIONAL}99* <td>{@link TIFFTag#TIFF_SRATIONAL}100* <td>{@code int[2]} {numerator, denominator}101* <td>{@code "SRational"}102* <tr>103* <th scope="row">{@code FLOAT}104* <td>{@link TIFFTag#TIFF_FLOAT}105* <td>{@code float}106* <td>{@code "Float"}107* <tr>108* <th scope="row">{@code DOUBLE}109* <td>{@link TIFFTag#TIFF_DOUBLE}110* <td>{@code double}111* <td>{@code "Double"}112* <tr>113* <th scope="row">{@code IFD}114* <td>{@link TIFFTag#TIFF_IFD_POINTER}115* <td>{@code long}116* <td>{@code "IFDPointer"}117* </tr>118* </tbody>119* </table>120*121* @since 9122* @see TIFFDirectory123* @see TIFFTag124*/125public final class TIFFField implements Cloneable {126127private static final long MAX_UINT32 = 0xffffffffL;128129private static final String[] TYPE_NAMES = {130null,131"Byte", "Ascii", "Short", "Long", "Rational",132"SByte", "Undefined", "SShort", "SLong", "SRational",133"Float", "Double", "IFDPointer"134};135136private static final boolean[] IS_INTEGRAL = {137false,138true, false, true, true, false,139true, true, true, true, false,140false, false, false141};142143/** The tag. */144private TIFFTag tag;145146/** The tag number. */147private int tagNumber;148149/** The tag type. */150private int type;151152/** The number of data items present in the field. */153private int count;154155/** The field data. */156private Object data;157158/** The IFD contents if available. This will usually be a TIFFIFD. */159private TIFFDirectory dir;160161/** The default constructor. */162private TIFFField() {}163164private static String getAttribute(Node node, String attrName) {165NamedNodeMap attrs = node.getAttributes();166return attrs.getNamedItem(attrName).getNodeValue();167}168169private static void initData(Node node,170int[] otype, int[] ocount, Object[] odata) {171int type;172int count;173Object data = null;174175String typeName = node.getNodeName();176typeName = typeName.substring(4);177typeName = typeName.substring(0, typeName.length() - 1);178type = TIFFField.getTypeByName(typeName);179if (type == -1) {180throw new IllegalArgumentException("typeName = " + typeName);181}182183Node child = node.getFirstChild();184185count = 0;186while (child != null) {187String childTypeName = child.getNodeName().substring(4);188if (!typeName.equals(childTypeName)) {189// warning190}191192++count;193child = child.getNextSibling();194}195196if (count > 0) {197data = createArrayForType(type, count);198child = node.getFirstChild();199int idx = 0;200while (child != null) {201String value = getAttribute(child, "value");202203String numerator, denominator;204int slashPos;205206switch (type) {207case TIFFTag.TIFF_ASCII:208((String[])data)[idx] = value;209break;210case TIFFTag.TIFF_BYTE:211case TIFFTag.TIFF_SBYTE:212((byte[])data)[idx] =213(byte)Integer.parseInt(value);214break;215case TIFFTag.TIFF_SHORT:216((char[])data)[idx] =217(char)Integer.parseInt(value);218break;219case TIFFTag.TIFF_SSHORT:220((short[])data)[idx] =221(short)Integer.parseInt(value);222break;223case TIFFTag.TIFF_SLONG:224((int[])data)[idx] =225Integer.parseInt(value);226break;227case TIFFTag.TIFF_LONG:228case TIFFTag.TIFF_IFD_POINTER:229((long[])data)[idx] =230Long.parseLong(value);231break;232case TIFFTag.TIFF_FLOAT:233((float[])data)[idx] =234Float.parseFloat(value);235break;236case TIFFTag.TIFF_DOUBLE:237((double[])data)[idx] =238Double.parseDouble(value);239break;240case TIFFTag.TIFF_SRATIONAL:241slashPos = value.indexOf("/");242numerator = value.substring(0, slashPos);243denominator = value.substring(slashPos + 1);244245((int[][])data)[idx] = new int[2];246((int[][])data)[idx][0] =247Integer.parseInt(numerator);248((int[][])data)[idx][1] =249Integer.parseInt(denominator);250break;251case TIFFTag.TIFF_RATIONAL:252slashPos = value.indexOf("/");253numerator = value.substring(0, slashPos);254denominator = value.substring(slashPos + 1);255256((long[][])data)[idx] = new long[2];257((long[][])data)[idx][0] =258Long.parseLong(numerator);259((long[][])data)[idx][1] =260Long.parseLong(denominator);261break;262default:263// error264}265266idx++;267child = child.getNextSibling();268}269}270271otype[0] = type;272ocount[0] = count;273odata[0] = data;274}275276/**277* Creates a {@code TIFFField} from a TIFF native image278* metadata node. If the value of the {@code "number"} attribute279* of the node is not found in {@code tagSet} then a new280* {@code TIFFTag} with name {@code TIFFTag.UNKNOWN_TAG_NAME}281* will be created and assigned to the field.282*283* @param tagSet The {@code TIFFTagSet} to which the284* {@code TIFFTag} of the field belongs.285* @param node A native TIFF image metadata {@code TIFFField} node.286* @throws IllegalArgumentException If the {@code Node} parameter content287* does not adhere to the {@code TIFFField} element structure defined by288* the <a href="../../metadata/doc-files/tiff_metadata.html#ImageMetadata">289* TIFF native image metadata format specification</a>, or if the290* combination of node attributes and data is not legal per the291* {@link #TIFFField(TIFFTag,int,int,Object)} constructor specification.292* Note that a cause might be set on such an exception.293* @return A new {@code TIFFField}.294*/295public static TIFFField createFromMetadataNode(TIFFTagSet tagSet,296Node node) {297if (node == null) {298// This method is specified to throw only IllegalArgumentExceptions299// so we create an IAE with a NullPointerException as its cause.300throw new IllegalArgumentException(new NullPointerException301("node == null!"));302}303String name = node.getNodeName();304if (!name.equals("TIFFField")) {305throw new IllegalArgumentException("!name.equals(\"TIFFField\")");306}307308int tagNumber = Integer.parseInt(getAttribute(node, "number"));309TIFFTag tag = null;310if (tagSet != null) {311tag = tagSet.getTag(tagNumber);312}313314int type = TIFFTag.TIFF_UNDEFINED;315int count = 0;316Object data = null;317318Node child = node.getFirstChild();319if (child != null) {320String typeName = child.getNodeName();321if (typeName.equals("TIFFUndefined")) {322String values = getAttribute(child, "value");323StringTokenizer st = new StringTokenizer(values, ",");324count = st.countTokens();325326byte[] bdata = new byte[count];327for (int i = 0; i < count; i++) {328bdata[i] = (byte)Integer.parseInt(st.nextToken());329}330331type = TIFFTag.TIFF_UNDEFINED;332data = bdata;333} else {334int[] otype = new int[1];335int[] ocount = new int[1];336Object[] odata = new Object[1];337338initData(node.getFirstChild(), otype, ocount, odata);339type = otype[0];340count = ocount[0];341data = odata[0];342}343} else if (tag != null) {344int t = TIFFTag.MAX_DATATYPE;345while(t >= TIFFTag.MIN_DATATYPE && !tag.isDataTypeOK(t)) {346t--;347}348type = t;349}350351if (tag == null) {352tag = new TIFFTag(TIFFTag.UNKNOWN_TAG_NAME, tagNumber, 1 << type);353}354355TIFFField field;356try {357field = new TIFFField(tag, type, count, data);358} catch (NullPointerException npe) {359// This method is specified to throw only IllegalArgumentExceptions360// so we catch the NullPointerException and set it as the cause of361// the IAE which is thrown.362throw new IllegalArgumentException(npe);363}364365return field;366}367368/**369* Constructs a {@code TIFFField} with arbitrary data. The370* {@code type} parameter must be a value for which371* {@link TIFFTag#isDataTypeOK tag.isDataTypeOK()}372* returns {@code true}. The {@code data} parameter must373* be an array of a Java type appropriate for the type of the TIFF374* field.375*376* <p>Note that the value (data) of the {@code TIFFField}377* will always be the actual field value regardless of the number of378* bytes required for that value. This is the case despite the fact379* that the TIFF <i>IFD Entry</i> corresponding to the field may380* actually contain the offset to the value of the field rather than381* the value itself (the latter occurring if and only if the382* value fits into 4 bytes). In other words, the value of the383* field will already have been read from the TIFF stream. (An exception384* to this case may occur when the field represents the contents of a385* non-baseline IFD. In that case the data will be a {@code long[]}386* containing the offset to the IFD and the {@code TIFFDirectory}387* returned by {@link #getDirectory()} will be its contents.)388*389* @param tag The tag to associated with this field.390* @param type One of the {@code TIFFTag.TIFF_*} constants391* indicating the data type of the field as written to the TIFF stream.392* @param count The number of data values.393* @param data The actual data content of the field.394*395* @throws NullPointerException if {@code tag == null}.396* @throws IllegalArgumentException if {@code type} is not397* one of the {@code TIFFTag.TIFF_*} data type constants.398* @throws IllegalArgumentException if {@code type} is an unacceptable399* data type for the supplied {@code TIFFTag}.400* @throws IllegalArgumentException if {@code count < 0}.401* @throws IllegalArgumentException if {@code count < 1}402* and {@code type} is {@code TIFF_RATIONAL} or403* {@code TIFF_SRATIONAL}.404* @throws IllegalArgumentException if {@code count != 1}405* and {@code type} is {@code TIFF_IFD_POINTER}.406* @throws NullPointerException if {@code data == null}.407* @throws IllegalArgumentException if {@code data} is an instance of408* a class incompatible with the specified type.409* @throws IllegalArgumentException if the size of the data array is wrong.410* @throws IllegalArgumentException if the type of the data array is411* {@code TIFF_LONG}, {@code TIFF_RATIONAL}, or {@code TIFF_IFD_POINTER}412* and any of the elements is negative or greater than {@code 0xffffffff}.413*/414public TIFFField(TIFFTag tag, int type, int count, Object data) {415if(tag == null) {416throw new NullPointerException("tag == null!");417} else if(type < TIFFTag.MIN_DATATYPE || type > TIFFTag.MAX_DATATYPE) {418throw new IllegalArgumentException("Unknown data type "+type);419} else if(!tag.isDataTypeOK(type)) {420throw new IllegalArgumentException("Illegal data type " + type421+ " for " + tag.getName() + " tag");422} else if(count < 0) {423throw new IllegalArgumentException("count < 0!");424} else if((type == TIFFTag.TIFF_RATIONAL425|| type == TIFFTag.TIFF_SRATIONAL)426&& count < 1) {427throw new IllegalArgumentException428("Type is TIFF_RATIONAL or TIFF_SRATIONAL and count < 1");429} else if (type == TIFFTag.TIFF_IFD_POINTER && count != 1) {430throw new IllegalArgumentException431("Type is TIFF_IFD_POINTER and count != 1");432} else if(data == null) {433throw new NullPointerException("data == null!");434}435436boolean isDataArrayCorrect = false;437438switch (type) {439case TIFFTag.TIFF_BYTE:440case TIFFTag.TIFF_SBYTE:441case TIFFTag.TIFF_UNDEFINED:442isDataArrayCorrect = data instanceof byte[]443&& ((byte[])data).length == count;444break;445case TIFFTag.TIFF_ASCII:446isDataArrayCorrect = data instanceof String[]447&& ((String[])data).length == count;448break;449case TIFFTag.TIFF_SHORT:450isDataArrayCorrect = data instanceof char[]451&& ((char[])data).length == count;452break;453case TIFFTag.TIFF_LONG:454isDataArrayCorrect = data instanceof long[]455&& ((long[])data).length == count;456if (isDataArrayCorrect) {457for (long datum : (long[])data) {458if (datum < 0) {459throw new IllegalArgumentException460("Negative value supplied for TIFF_LONG");461}462if (datum > MAX_UINT32) {463throw new IllegalArgumentException464("Too large value supplied for TIFF_LONG");465}466}467}468break;469case TIFFTag.TIFF_IFD_POINTER:470isDataArrayCorrect = data instanceof long[]471&& ((long[])data).length == 1;472if (((long[])data)[0] < 0) {473throw new IllegalArgumentException474("Negative value supplied for TIFF_IFD_POINTER");475}476if (((long[])data)[0] > MAX_UINT32) {477throw new IllegalArgumentException478("Too large value supplied for TIFF_IFD_POINTER");479}480break;481case TIFFTag.TIFF_RATIONAL:482isDataArrayCorrect = data instanceof long[][]483&& ((long[][])data).length == count;484if (isDataArrayCorrect) {485for (long[] datum : (long[][])data) {486if (datum.length != 2) {487isDataArrayCorrect = false;488break;489}490if (datum[0] < 0 || datum[1] < 0) {491throw new IllegalArgumentException492("Negative value supplied for TIFF_RATIONAL");493}494if (datum[0] > MAX_UINT32 || datum[1] > MAX_UINT32) {495throw new IllegalArgumentException496("Too large value supplied for TIFF_RATIONAL");497}498}499}500break;501case TIFFTag.TIFF_SSHORT:502isDataArrayCorrect = data instanceof short[]503&& ((short[])data).length == count;504break;505case TIFFTag.TIFF_SLONG:506isDataArrayCorrect = data instanceof int[]507&& ((int[])data).length == count;508break;509case TIFFTag.TIFF_SRATIONAL:510isDataArrayCorrect = data instanceof int[][]511&& ((int[][])data).length == count;512if (isDataArrayCorrect) {513for (int[] datum : (int[][])data) {514if (datum.length != 2) {515isDataArrayCorrect = false;516break;517}518}519}520break;521case TIFFTag.TIFF_FLOAT:522isDataArrayCorrect = data instanceof float[]523&& ((float[])data).length == count;524break;525case TIFFTag.TIFF_DOUBLE:526isDataArrayCorrect = data instanceof double[]527&& ((double[])data).length == count;528break;529default:530throw new IllegalArgumentException("Unknown data type "+type);531}532533if (!isDataArrayCorrect) {534throw new IllegalArgumentException535("Illegal class or length for data array");536}537538this.tag = tag;539this.tagNumber = tag.getNumber();540this.type = type;541this.count = count;542this.data = data;543}544545/**546* Constructs a data array using {@link #createArrayForType547* createArrayForType()} and invokes548* {@link #TIFFField(TIFFTag,int,int,Object)} with the supplied549* parameters and the created array.550*551* @param tag The tag to associated with this field.552* @param type One of the {@code TIFFTag.TIFF_*} constants553* indicating the data type of the field as written to the TIFF stream.554* @param count The number of data values.555* @throws NullPointerException if {@code tag == null}.556* @throws IllegalArgumentException if {@code type} is not557* one of the {@code TIFFTag.TIFF_*} data type constants.558* @throws IllegalArgumentException if {@code type} is an unacceptable559* data type for the supplied {@code TIFFTag}.560* @throws IllegalArgumentException if {@code count < 0}.561* @see #TIFFField(TIFFTag,int,int,Object)562* @throws IllegalArgumentException if {@code count < 1}563* and {@code type} is {@code TIFF_RATIONAL} or564* {@code TIFF_SRATIONAL}.565* @throws IllegalArgumentException if {@code count != 1}566* and {@code type} is {@code TIFF_IFD_POINTER}.567*/568public TIFFField(TIFFTag tag, int type, int count) {569this(tag, type, count, createArrayForType(type, count));570}571572/**573* Constructs a {@code TIFFField} with a single non-negative integral574* value. The field will have type {@link TIFFTag#TIFF_SHORT TIFF_SHORT}575* if {@code value} is in {@code [0,0xffff]}, and type576* {@link TIFFTag#TIFF_LONG TIFF_LONG} if {@code value} is in577* {@code [0x10000,0xffffffff]}. The count of the field will be unity.578*579* @param tag The tag to associate with this field.580* @param value The value to associate with this field.581* @throws NullPointerException if {@code tag == null}.582* @throws IllegalArgumentException if {@code value} is not in583* {@code [0,0xffffffff]}.584* @throws IllegalArgumentException if {@code value} is in585* {@code [0,0xffff]} and {@code TIFF_SHORT} is an unacceptable type586* for the {@code TIFFTag}, or if {@code value} is in587* {@code [0x10000,0xffffffff]} and {@code TIFF_LONG} is an unacceptable588* type for the {@code TIFFTag}.589*/590public TIFFField(TIFFTag tag, long value) {591if(tag == null) {592throw new NullPointerException("tag == null!");593}594if (value < 0) {595throw new IllegalArgumentException("value < 0!");596}597if (value > MAX_UINT32) {598throw new IllegalArgumentException("value > 0xffffffff!");599}600601this.tag = tag;602this.tagNumber = tag.getNumber();603this.count = 1;604605if (value < 65536) {606if (!tag.isDataTypeOK(TIFFTag.TIFF_SHORT)) {607throw new IllegalArgumentException("Illegal data type "608+ getTypeName(TIFFTag.TIFF_SHORT) + " for tag "609+ "\"" + tag.getName() + "\"");610}611this.type = TIFFTag.TIFF_SHORT;612char[] cdata = new char[1];613cdata[0] = (char)value;614this.data = cdata;615} else {616if (!tag.isDataTypeOK(TIFFTag.TIFF_LONG)) {617throw new IllegalArgumentException("Illegal data type "618+ getTypeName(TIFFTag.TIFF_LONG) + " for tag "619+ "\"" + tag.getName() + "\"");620}621this.type = TIFFTag.TIFF_LONG;622long[] ldata = new long[1];623ldata[0] = value;624this.data = ldata;625}626}627628/**629* Constructs a {@code TIFFField} with an IFD offset and contents.630* The offset will be stored as the data of this field as631* {@code long[] {offset}}. The directory will not be cloned. The count632* of the field will be unity.633*634* @param tag The tag to associated with this field.635* @param type One of the constants {@code TIFFTag.TIFF_LONG} or636* {@code TIFFTag.TIFF_IFD_POINTER}.637* @param offset The IFD offset.638* @param dir The directory.639*640* @throws NullPointerException if {@code tag == null}.641* @throws IllegalArgumentException if {@code type} is an unacceptable642* data type for the supplied {@code TIFFTag}.643* @throws IllegalArgumentException if {@code type} is neither644* {@code TIFFTag.TIFF_LONG} nor {@code TIFFTag.TIFF_IFD_POINTER}.645* @throws IllegalArgumentException if {@code offset <= 0}.646* @throws NullPointerException if {@code dir == null}.647*648* @see #TIFFField(TIFFTag,int,int,Object)649*/650public TIFFField(TIFFTag tag, int type, long offset, TIFFDirectory dir) {651if (tag == null) {652throw new NullPointerException("tag == null!");653} else if (type < TIFFTag.MIN_DATATYPE || type > TIFFTag.MAX_DATATYPE) {654throw new IllegalArgumentException("Unknown data type "+type);655} else if (!tag.isDataTypeOK(type)) {656throw new IllegalArgumentException("Illegal data type " + type657+ " for " + tag.getName() + " tag");658} else if (type != TIFFTag.TIFF_LONG659&& type != TIFFTag.TIFF_IFD_POINTER) {660throw new IllegalArgumentException("type " + type661+ " is neither TIFFTag.TIFF_LONG nor TIFFTag.TIFF_IFD_POINTER");662} else if (offset <= 0) {663throw new IllegalArgumentException("offset " + offset664+ " is non-positive");665} else if (dir == null) {666throw new NullPointerException("dir == null");667}668669this.tag = tag;670this.tagNumber = tag.getNumber();671this.type = type;672this.count = 1;673this.data = new long[] {offset};674675this.dir = dir;676}677678/**679* Retrieves the tag associated with this field.680*681* @return The associated {@code TIFFTag}.682*/683public TIFFTag getTag() {684return tag;685}686687/**688* Retrieves the tag number in the range {@code [0,65535]}.689*690* @return The tag number.691*/692public int getTagNumber() {693return tagNumber;694}695696/**697* Returns the type of the data stored in the field. For a TIFF 6.0698* stream, the value will equal one of the {@code TIFFTag.TIFF_*}699* constants. For future revisions of TIFF, higher values are possible.700*701* @return The data type of the field value.702*/703public int getType() {704return type;705}706707/**708* Returns the name of the supplied data type constant.709*710* @param dataType One of the {@code TIFFTag.TIFF_*} constants711* indicating the data type of the field as written to the TIFF stream.712* @return The type name corresponding to the supplied type constant.713* @throws IllegalArgumentException if {@code dataType} is not714* one of the {@code TIFFTag.TIFF_*} data type constants.715*/716public static String getTypeName(int dataType) {717if (dataType < TIFFTag.MIN_DATATYPE ||718dataType > TIFFTag.MAX_DATATYPE) {719throw new IllegalArgumentException("Unknown data type "+dataType);720}721722return TYPE_NAMES[dataType];723}724725/**726* Returns the data type constant corresponding to the supplied data727* type name. If the name is unknown {@code -1} will be returned.728*729* @param typeName The type name.730* @return One of the {@code TIFFTag.TIFF_*} constants or731* {@code -1} if the name is not recognized.732*/733public static int getTypeByName(String typeName) {734for (int i = TIFFTag.MIN_DATATYPE; i <= TIFFTag.MAX_DATATYPE; i++) {735if (typeName.equals(TYPE_NAMES[i])) {736return i;737}738}739740return -1;741}742743/**744* Creates an array appropriate for the indicated data type.745*746* @param dataType One of the {@code TIFFTag.TIFF_*} data type747* constants.748* @param count The number of values in the array.749* @return An array appropriate for the specified data type.750*751* @throws IllegalArgumentException if {@code dataType} is not752* one of the {@code TIFFTag.TIFF_*} data type constants.753* @throws IllegalArgumentException if {@code count < 0}.754* @throws IllegalArgumentException if {@code count < 1}755* and {@code type} is {@code TIFF_RATIONAL} or756* {@code TIFF_SRATIONAL}.757* @throws IllegalArgumentException if {@code count != 1}758* and {@code type} is {@code TIFF_IFD_POINTER}.759*/760public static Object createArrayForType(int dataType, int count) {761762if(count < 0) {763throw new IllegalArgumentException("count < 0!");764} else if ((dataType == TIFFTag.TIFF_RATIONAL765|| dataType == TIFFTag.TIFF_SRATIONAL)766&& count < 1) {767throw new IllegalArgumentException768("Type is TIFF_RATIONAL or TIFF_SRATIONAL and count < 1");769} else if (dataType == TIFFTag.TIFF_IFD_POINTER && count != 1) {770throw new IllegalArgumentException771("Type is TIFF_IFD_POINTER and count != 1");772}773774switch (dataType) {775case TIFFTag.TIFF_BYTE:776case TIFFTag.TIFF_SBYTE:777case TIFFTag.TIFF_UNDEFINED:778return new byte[count];779case TIFFTag.TIFF_ASCII:780return new String[count];781case TIFFTag.TIFF_SHORT:782return new char[count];783case TIFFTag.TIFF_LONG:784case TIFFTag.TIFF_IFD_POINTER:785return new long[count];786case TIFFTag.TIFF_RATIONAL:787return new long[count][2];788case TIFFTag.TIFF_SSHORT:789return new short[count];790case TIFFTag.TIFF_SLONG:791return new int[count];792case TIFFTag.TIFF_SRATIONAL:793return new int[count][2];794case TIFFTag.TIFF_FLOAT:795return new float[count];796case TIFFTag.TIFF_DOUBLE:797return new double[count];798default:799throw new IllegalArgumentException("Unknown data type "+dataType);800}801}802803/**804* Returns the {@code TIFFField} as a node named either805* {@code "TIFFField"} or {@code "TIFFIFD"} as described in the806* TIFF native image metadata specification. The node will be named807* {@code "TIFFIFD"} if and only if {@link #hasDirectory()} returns808* {@code true} and the field's type is either {@link TIFFTag#TIFF_LONG}809* or {@link TIFFTag#TIFF_IFD_POINTER}.810*811* @return a {@code Node} named {@code "TIFFField"} or812* {@code "TIFFIFD"}.813*/814public Node getAsNativeNode() {815return new TIFFFieldNode(this);816}817818/**819* Indicates whether the value associated with the field is of820* integral data type.821*822* @return Whether the field type is integral.823*/824public boolean isIntegral() {825return IS_INTEGRAL[type];826}827828/**829* Returns the number of data items present in the field. For830* {@code TIFFTag.TIFF_ASCII} fields, the value returned is the831* number of {@code String}s, not the total length of the832* data as in the file representation.833*834* @return The number of data items present in the field.835*/836public int getCount() {837return count;838}839840/**841* Returns a reference to the data object associated with the field.842*843* @return The data object of the field.844*/845public Object getData() {846return data;847}848849/**850* Returns the data as an uninterpreted array of851* {@code byte}s. The type of the field must be one of852* {@code TIFFTag.TIFF_BYTE}, {@code TIFF_SBYTE}, or853* {@code TIFF_UNDEFINED}.854*855* <p> For data in {@code TIFFTag.TIFF_BYTE} format, the application856* must take care when promoting the data to longer integral types857* to avoid sign extension.858*859* @throws ClassCastException if the field is not of type860* {@code TIFF_BYTE}, {@code TIFF_SBYTE}, or861* {@code TIFF_UNDEFINED}.862* @return The data as an uninterpreted array of bytes.863*/864public byte[] getAsBytes() {865return (byte[])data;866}867868/**869* Returns {@code TIFFTag.TIFF_SHORT} data as an array of870* {@code char}s (unsigned 16-bit integers).871*872* @throws ClassCastException if the field is not of type873* {@code TIFF_SHORT}.874* @return The data as an array of {@code char}s.875*/876public char[] getAsChars() {877return (char[])data;878}879880/**881* Returns {@code TIFFTag.TIFF_SSHORT} data as an array of882* {@code short}s (signed 16-bit integers).883*884* @throws ClassCastException if the field is not of type885* {@code TIFF_SSHORT}.886* @return The data as an array of {@code short}s.887*/888public short[] getAsShorts() {889return (short[])data;890}891892/**893* Returns {@code TIFFTag.TIFF_SLONG} data as an array of894* {@code int}s (signed 32-bit integers).895*896* @throws ClassCastException if the field is not of type897* {@code TIFF_SHORT}, {@code TIFF_SSHORT}, or898* {@code TIFF_SLONG}.899* @return The data as an array of {@code int}s.900*/901public int[] getAsInts() {902if (data instanceof int[]) {903return (int[])data;904} else if (data instanceof char[]){905char[] cdata = (char[])data;906int[] idata = new int[cdata.length];907for (int i = 0; i < cdata.length; i++) {908idata[i] = cdata[i] & 0xffff;909}910return idata;911} else if (data instanceof short[]){912short[] sdata = (short[])data;913int[] idata = new int[sdata.length];914for (int i = 0; i < sdata.length; i++) {915idata[i] = (int)sdata[i];916}917return idata;918} else {919throw new ClassCastException("Data not char[], short[], or int[]!");920}921}922923/**924* Returns {@code TIFFTag.TIFF_LONG} or925* {@code TIFF_IFD_POINTER} data as an array of926* {@code long}s (signed 64-bit integers).927*928* @throws ClassCastException if the field is not of type929* {@code TIFF_LONG} or {@code TIFF_IFD_POINTER}.930* @return The data as an array of {@code long}s.931*/932public long[] getAsLongs() {933return (long[])data;934}935936/**937* Returns {@code TIFFTag.TIFF_FLOAT} data as an array of938* {@code float}s (32-bit floating-point values).939*940* @throws ClassCastException if the field is not of type941* {@code TIFF_FLOAT}.942* @return The data as an array of {@code float}s.943*/944public float[] getAsFloats() {945return (float[])data;946}947948/**949* Returns {@code TIFFTag.TIFF_DOUBLE} data as an array of950* {@code double}s (64-bit floating-point values).951*952* @throws ClassCastException if the field is not of type953* {@code TIFF_DOUBLE}.954* @return The data as an array of {@code double}s.955*/956public double[] getAsDoubles() {957return (double[])data;958}959960/**961* Returns {@code TIFFTag.TIFF_SRATIONAL} data as an array of962* 2-element arrays of {@code int}s.963*964* @throws ClassCastException if the field is not of type965* {@code TIFF_SRATIONAL}.966* @return The data as an array of signed rationals.967*/968public int[][] getAsSRationals() {969return (int[][])data;970}971972/**973* Returns {@code TIFFTag.TIFF_RATIONAL} data as an array of974* 2-element arrays of {@code long}s.975*976* @throws ClassCastException if the field is not of type977* {@code TIFF_RATIONAL}.978* @return The data as an array of unsigned rationals.979*/980public long[][] getAsRationals() {981return (long[][])data;982}983984/**985* Returns data in any format as an {@code int}.986*987* <p> {@code TIFFTag.TIFF_BYTE} values are treated as unsigned; that988* is, no sign extension will take place and the returned value989* will be in the range [0, 255]. {@code TIFF_SBYTE} data990* will be returned in the range [-128, 127].991*992* <p> A {@code TIFF_UNDEFINED} value is treated as though993* it were a {@code TIFF_BYTE}.994*995* <p> Data in {@code TIFF_SLONG}, {@code TIFF_LONG},996* {@code TIFF_FLOAT}, {@code TIFF_DOUBLE} or997* {@code TIFF_IFD_POINTER} format are simply cast to998* {@code int} and may suffer from truncation.999*1000* <p> Data in {@code TIFF_SRATIONAL} or1001* {@code TIFF_RATIONAL} format are evaluated by dividing the1002* numerator into the denominator using double-precision1003* arithmetic and then casting to {@code int}. Loss of1004* precision and truncation may occur.1005*1006* <p> Data in {@code TIFF_ASCII} format will be parsed as by1007* the {@code Double.parseDouble} method, with the result1008* case to {@code int}.1009*1010* @param index The index of the data.1011* @return The data at the given index as an {@code int}.1012*/1013public int getAsInt(int index) {1014switch (type) {1015case TIFFTag.TIFF_BYTE:1016case TIFFTag.TIFF_UNDEFINED:1017return ((byte[])data)[index] & 0xff;1018case TIFFTag.TIFF_SBYTE:1019return ((byte[])data)[index];1020case TIFFTag.TIFF_SHORT:1021return ((char[])data)[index] & 0xffff;1022case TIFFTag.TIFF_SSHORT:1023return ((short[])data)[index];1024case TIFFTag.TIFF_SLONG:1025return ((int[])data)[index];1026case TIFFTag.TIFF_LONG:1027case TIFFTag.TIFF_IFD_POINTER:1028return (int)((long[])data)[index];1029case TIFFTag.TIFF_FLOAT:1030return (int)((float[])data)[index];1031case TIFFTag.TIFF_DOUBLE:1032return (int)((double[])data)[index];1033case TIFFTag.TIFF_SRATIONAL:1034int[] ivalue = getAsSRational(index);1035return (int)((double)ivalue[0]/ivalue[1]);1036case TIFFTag.TIFF_RATIONAL:1037long[] lvalue = getAsRational(index);1038return (int)((double)lvalue[0]/lvalue[1]);1039case TIFFTag.TIFF_ASCII:1040String s = ((String[])data)[index];1041return (int)Double.parseDouble(s);1042default:1043throw new ClassCastException(); // should never happen1044}1045}10461047/**1048* Returns data in any format as a {@code long}.1049*1050* <p> {@code TIFFTag.TIFF_BYTE} and {@code TIFF_UNDEFINED} data1051* are treated as unsigned; that is, no sign extension will take1052* place and the returned value will be in the range [0, 255].1053* {@code TIFF_SBYTE} data will be returned in the range1054* [-128, 127].1055*1056* <p> Data in {@code TIFF_FLOAT} and {@code TIFF_DOUBLE} are1057* simply cast to {@code long} and may suffer from truncation.1058*1059* <p> Data in {@code TIFF_SRATIONAL} or1060* {@code TIFF_RATIONAL} format are evaluated by dividing the1061* numerator into the denominator using double-precision1062* arithmetic and then casting to {@code long}. Loss of1063* precision and truncation may occur.1064*1065* <p> Data in {@code TIFF_ASCII} format will be parsed as by1066* the {@code Double.parseDouble} method, with the result1067* cast to {@code long}.1068*1069* @param index The index of the data.1070* @return The data at the given index as a {@code long}.1071*/1072public long getAsLong(int index) {1073switch (type) {1074case TIFFTag.TIFF_BYTE:1075case TIFFTag.TIFF_UNDEFINED:1076return ((byte[])data)[index] & 0xff;1077case TIFFTag.TIFF_SBYTE:1078return ((byte[])data)[index];1079case TIFFTag.TIFF_SHORT:1080return ((char[])data)[index] & 0xffff;1081case TIFFTag.TIFF_SSHORT:1082return ((short[])data)[index];1083case TIFFTag.TIFF_SLONG:1084return ((int[])data)[index];1085case TIFFTag.TIFF_LONG:1086case TIFFTag.TIFF_IFD_POINTER:1087return ((long[])data)[index];1088case TIFFTag.TIFF_FLOAT:1089return (long)((float[])data)[index];1090case TIFFTag.TIFF_DOUBLE:1091return (long)((double[])data)[index];1092case TIFFTag.TIFF_SRATIONAL:1093int[] ivalue = getAsSRational(index);1094return (long)((double)ivalue[0]/ivalue[1]);1095case TIFFTag.TIFF_RATIONAL:1096long[] lvalue = getAsRational(index);1097return (long)((double)lvalue[0]/lvalue[1]);1098case TIFFTag.TIFF_ASCII:1099String s = ((String[])data)[index];1100return (long)Double.parseDouble(s);1101default:1102throw new ClassCastException(); // should never happen1103}1104}11051106/**1107* Returns data in any format as a {@code float}.1108*1109* <p> {@code TIFFTag.TIFF_BYTE} and {@code TIFF_UNDEFINED} data1110* are treated as unsigned; that is, no sign extension will take1111* place and the returned value will be in the range [0, 255].1112* {@code TIFF_SBYTE} data will be returned in the range1113* [-128, 127].1114*1115* <p> Data in {@code TIFF_SLONG}, {@code TIFF_LONG},1116* {@code TIFF_DOUBLE}, or {@code TIFF_IFD_POINTER} format are1117* simply cast to {@code float} and may suffer from1118* truncation.1119*1120* <p> Data in {@code TIFF_SRATIONAL} or1121* {@code TIFF_RATIONAL} format are evaluated by dividing the1122* numerator into the denominator using double-precision1123* arithmetic and then casting to {@code float}.1124*1125* <p> Data in {@code TIFF_ASCII} format will be parsed as by1126* the {@code Double.parseDouble} method, with the result1127* cast to {@code float}.1128*1129* @param index The index of the data.1130* @return The data at the given index as a {@code float}.1131*/1132public float getAsFloat(int index) {1133switch (type) {1134case TIFFTag.TIFF_BYTE:1135case TIFFTag.TIFF_UNDEFINED:1136return ((byte[])data)[index] & 0xff;1137case TIFFTag.TIFF_SBYTE:1138return ((byte[])data)[index];1139case TIFFTag.TIFF_SHORT:1140return ((char[])data)[index] & 0xffff;1141case TIFFTag.TIFF_SSHORT:1142return ((short[])data)[index];1143case TIFFTag.TIFF_SLONG:1144return ((int[])data)[index];1145case TIFFTag.TIFF_LONG:1146case TIFFTag.TIFF_IFD_POINTER:1147return ((long[])data)[index];1148case TIFFTag.TIFF_FLOAT:1149return ((float[])data)[index];1150case TIFFTag.TIFF_DOUBLE:1151return (float)((double[])data)[index];1152case TIFFTag.TIFF_SRATIONAL:1153int[] ivalue = getAsSRational(index);1154return (float)((double)ivalue[0]/ivalue[1]);1155case TIFFTag.TIFF_RATIONAL:1156long[] lvalue = getAsRational(index);1157return (float)((double)lvalue[0]/lvalue[1]);1158case TIFFTag.TIFF_ASCII:1159String s = ((String[])data)[index];1160return (float)Double.parseDouble(s);1161default:1162throw new ClassCastException(); // should never happen1163}1164}11651166/**1167* Returns data in any format as a {@code double}.1168*1169* <p> {@code TIFFTag.TIFF_BYTE} and {@code TIFF_UNDEFINED} data1170* are treated as unsigned; that is, no sign extension will take1171* place and the returned value will be in the range [0, 255].1172* {@code TIFF_SBYTE} data will be returned in the range1173* [-128, 127].1174*1175* <p> Data in {@code TIFF_SRATIONAL} or1176* {@code TIFF_RATIONAL} format are evaluated by dividing the1177* numerator into the denominator using double-precision1178* arithmetic.1179*1180* <p> Data in {@code TIFF_ASCII} format will be parsed as by1181* the {@code Double.parseDouble} method.1182*1183* @param index The index of the data.1184* @return The data at the given index as a {@code double}.1185*/1186public double getAsDouble(int index) {1187switch (type) {1188case TIFFTag.TIFF_BYTE:1189case TIFFTag.TIFF_UNDEFINED:1190return ((byte[])data)[index] & 0xff;1191case TIFFTag.TIFF_SBYTE:1192return ((byte[])data)[index];1193case TIFFTag.TIFF_SHORT:1194return ((char[])data)[index] & 0xffff;1195case TIFFTag.TIFF_SSHORT:1196return ((short[])data)[index];1197case TIFFTag.TIFF_SLONG:1198return ((int[])data)[index];1199case TIFFTag.TIFF_LONG:1200case TIFFTag.TIFF_IFD_POINTER:1201return ((long[])data)[index];1202case TIFFTag.TIFF_FLOAT:1203return ((float[])data)[index];1204case TIFFTag.TIFF_DOUBLE:1205return ((double[])data)[index];1206case TIFFTag.TIFF_SRATIONAL:1207int[] ivalue = getAsSRational(index);1208return (double)ivalue[0]/ivalue[1];1209case TIFFTag.TIFF_RATIONAL:1210long[] lvalue = getAsRational(index);1211return (double)lvalue[0]/lvalue[1];1212case TIFFTag.TIFF_ASCII:1213String s = ((String[])data)[index];1214return Double.parseDouble(s);1215default:1216throw new ClassCastException(); // should never happen1217}1218}12191220/**1221* Returns a {@code TIFFTag.TIFF_ASCII} value as a1222* {@code String}.1223*1224* @throws ClassCastException if the field is not of type1225* {@code TIFF_ASCII}.1226*1227* @param index The index of the data.1228* @return The data at the given index as a {@code String}.1229*/1230public String getAsString(int index) {1231return ((String[])data)[index];1232}12331234/**1235* Returns a {@code TIFFTag.TIFF_SRATIONAL} data item as a1236* two-element array of {@code int}s.1237*1238* @param index The index of the data.1239* @return The data at the given index as a signed rational.1240* @throws ClassCastException if the field is not of type1241* {@code TIFF_SRATIONAL}.1242*/1243public int[] getAsSRational(int index) {1244return ((int[][])data)[index];1245}12461247/**1248* Returns a TIFFTag.TIFF_RATIONAL data item as a two-element array1249* of ints.1250*1251* @param index The index of the data.1252* @return The data at the given index as an unsigned rational.1253* @throws ClassCastException if the field is not of type1254* {@code TIFF_RATIONAL}.1255*/1256public long[] getAsRational(int index) {1257return ((long[][])data)[index];1258}125912601261/**1262* Returns a {@code String} containing a human-readable1263* version of the data item. Data of type1264* {@code TIFFTag.TIFF_RATIONAL} or {@code TIFF_SRATIONAL} are1265* represented as a pair of integers separated by a1266* {@code '/'} character. If the numerator of a1267* {@code TIFFTag.TIFF_RATIONAL} or {@code TIFF_SRATIONAL} is an integral1268* multiple of the denominator, then the value is represented as1269* {@code "q/1"} where {@code q} is the quotient of the numerator and1270* denominator.1271*1272* @param index The index of the data.1273* @return The data at the given index as a {@code String}.1274* @throws ClassCastException if the field is not of one of the1275* legal field types.1276*/1277public String getValueAsString(int index) {1278switch (type) {1279case TIFFTag.TIFF_ASCII:1280return ((String[])data)[index];1281case TIFFTag.TIFF_BYTE:1282case TIFFTag.TIFF_UNDEFINED:1283return Integer.toString(((byte[])data)[index] & 0xff);1284case TIFFTag.TIFF_SBYTE:1285return Integer.toString(((byte[])data)[index]);1286case TIFFTag.TIFF_SHORT:1287return Integer.toString(((char[])data)[index] & 0xffff);1288case TIFFTag.TIFF_SSHORT:1289return Integer.toString(((short[])data)[index]);1290case TIFFTag.TIFF_SLONG:1291return Integer.toString(((int[])data)[index]);1292case TIFFTag.TIFF_LONG:1293case TIFFTag.TIFF_IFD_POINTER:1294return Long.toString(((long[])data)[index]);1295case TIFFTag.TIFF_FLOAT:1296return Float.toString(((float[])data)[index]);1297case TIFFTag.TIFF_DOUBLE:1298return Double.toString(((double[])data)[index]);1299case TIFFTag.TIFF_SRATIONAL:1300int[] ivalue = getAsSRational(index);1301String srationalString;1302if(ivalue[1] != 0 && ivalue[0] % ivalue[1] == 0) {1303// If the denominator is a non-zero integral divisor1304// of the numerator then convert the fraction to be1305// with respect to a unity denominator.1306srationalString =1307Integer.toString(ivalue[0] / ivalue[1]) + "/1";1308} else {1309// Use the values directly.1310srationalString =1311Integer.toString(ivalue[0]) +1312"/" +1313Integer.toString(ivalue[1]);1314}1315return srationalString;1316case TIFFTag.TIFF_RATIONAL:1317long[] lvalue = getAsRational(index);1318String rationalString;1319if(lvalue[1] != 0L && lvalue[0] % lvalue[1] == 0) {1320// If the denominator is a non-zero integral divisor1321// of the numerator then convert the fraction to be1322// with respect to a unity denominator.1323rationalString =1324Long.toString(lvalue[0] / lvalue[1]) + "/1";1325} else {1326// Use the values directly.1327rationalString =1328Long.toString(lvalue[0]) +1329"/" +1330Long.toString(lvalue[1]);1331}1332return rationalString;1333default:1334throw new ClassCastException(); // should never happen1335}1336}13371338/**1339* Returns whether the field has a {@code TIFFDirectory}.1340*1341* @return true if and only if getDirectory() returns non-null.1342*/1343public boolean hasDirectory() {1344return getDirectory() != null;1345}13461347/**1348* Returns the associated {@code TIFFDirectory}, if available. If no1349* directory is set, then {@code null} will be returned.1350*1351* @return the TIFFDirectory instance or null.1352*/1353public TIFFDirectory getDirectory() {1354return dir;1355}13561357/**1358* Clones the field and all the information contained therein.1359*1360* @return A clone of this {@code TIFFField}.1361* @throws CloneNotSupportedException if the instance cannot be cloned.1362*/1363@Override1364public TIFFField clone() throws CloneNotSupportedException {1365TIFFField field = (TIFFField)super.clone();13661367Object fieldData;1368switch (type) {1369case TIFFTag.TIFF_BYTE:1370case TIFFTag.TIFF_UNDEFINED:1371case TIFFTag.TIFF_SBYTE:1372fieldData = ((byte[])data).clone();1373break;1374case TIFFTag.TIFF_SHORT:1375fieldData = ((char[])data).clone();1376break;1377case TIFFTag.TIFF_SSHORT:1378fieldData = ((short[])data).clone();1379break;1380case TIFFTag.TIFF_SLONG:1381fieldData = ((int[])data).clone();1382break;1383case TIFFTag.TIFF_LONG:1384case TIFFTag.TIFF_IFD_POINTER:1385fieldData = ((long[])data).clone();1386break;1387case TIFFTag.TIFF_FLOAT:1388fieldData = ((float[])data).clone();1389break;1390case TIFFTag.TIFF_DOUBLE:1391fieldData = ((double[])data).clone();1392break;1393case TIFFTag.TIFF_SRATIONAL:1394fieldData = ((int[][])data).clone();1395break;1396case TIFFTag.TIFF_RATIONAL:1397fieldData = ((long[][])data).clone();1398break;1399case TIFFTag.TIFF_ASCII:1400fieldData = ((String[])data).clone();1401break;1402default:1403throw new ClassCastException(); // should never happen1404}14051406field.tag = tag;1407field.tagNumber = tagNumber;1408field.type = type;1409field.count = count;1410field.data = fieldData;1411field.dir = dir != null ? dir.clone() : null;14121413return field;1414}1415}141614171418