/* * 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.Iterator; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; /** * A class defining the notion of a TIFF tag. A TIFF tag is a key * that may appear in an Image File Directory (IFD). In the IFD * each tag has some data associated with it, which may consist of zero * or more values of a given data type. The combination of a tag and a * value is known as an IFD Entry or TIFF Field. * * <p> The actual tag values used in the root IFD of a standard ("baseline") * tiff stream are defined in the {@link BaselineTIFFTagSet * BaselineTIFFTagSet} class. * * @since 9 * @see BaselineTIFFTagSet * @see TIFFField * @see TIFFTagSet */ public class TIFFTag { // TIFF 6.0 + Adobe PageMaker(R) 6.0 TIFF Technical Notes 1 IFD data type /** Flag for 8 bit unsigned integers. */ public static final int TIFF_BYTE = 1; /** Flag for null-terminated ASCII strings. */ public static final int TIFF_ASCII = 2; /** Flag for 16 bit unsigned integers. */ public static final int TIFF_SHORT = 3; /** Flag for 32 bit unsigned integers. */ public static final int TIFF_LONG = 4; /** Flag for pairs of 32 bit unsigned integers. */ public static final int TIFF_RATIONAL = 5; /** Flag for 8 bit signed integers. */ public static final int TIFF_SBYTE = 6; /** Flag for 8 bit uninterpreted bytes. */ public static final int TIFF_UNDEFINED = 7; /** Flag for 16 bit signed integers. */ public static final int TIFF_SSHORT = 8; /** Flag for 32 bit signed integers. */ public static final int TIFF_SLONG = 9; /** Flag for pairs of 32 bit signed integers. */ public static final int TIFF_SRATIONAL = 10; /** Flag for 32 bit IEEE floats. */ public static final int TIFF_FLOAT = 11; /** Flag for 64 bit IEEE doubles. */ public static final int TIFF_DOUBLE = 12; /** * Flag for IFD pointer defined in TIFF Tech Note 1 in * TIFF Specification Supplement 1. */ public static final int TIFF_IFD_POINTER = 13; /** * The numerically smallest constant representing a TIFF data type. */ public static final int MIN_DATATYPE = TIFF_BYTE; /** * The numerically largest constant representing a TIFF data type. */ public static final int MAX_DATATYPE = TIFF_IFD_POINTER; /** * The name assigned to a tag with an unknown tag number. Such * a tag may be created for example when reading an IFD and a * tag number is encountered which is not in any of the * {@code TIFFTagSet}s known to the reader. */ public static final String UNKNOWN_TAG_NAME = "UnknownTag"; /** * Disallowed data type mask. */ private static final int DISALLOWED_DATATYPES_MASK = ~0x3fff; private static final int[] SIZE_OF_TYPE = { 0, // 0 = n/a 1, // 1 = byte 1, // 2 = ascii 2, // 3 = short 4, // 4 = long 8, // 5 = rational 1, // 6 = sbyte 1, // 7 = undefined 2, // 8 = sshort 4, // 9 = slong 8, // 10 = srational 4, // 11 = float 8, // 12 = double 4, // 13 = IFD_POINTER }; private int number; private String name; private int dataTypes; private int count; private TIFFTagSet tagSet = null; // Mnemonic names for integral enumerated constants private SortedMap<Integer,String> valueNames = null; /** * Constructs a {@code TIFFTag} with a given name, tag number, set * of legal data types, and value count. A negative value count signifies * that either an arbitrary number of values is legal or the required count * is determined by the values of other fields in the IFD. A non-negative * count specifies the number of values which an associated field must * contain. The tag will have no associated {@code TIFFTagSet}. * * <p> If there are mnemonic names to be associated with the legal * data values for the tag, {@link #addValueName(int, String) * addValueName()} should be called on the new instance for each name. * Mnemonic names apply only to tags which have integral data type.</p> * * <p> See the documentation for {@link #getDataTypes() * getDataTypes()} for an explanation of how the set * of data types is to be converted into a bit mask.</p> * * @param name the name of the tag. * @param number the number used to represent the tag. * @param dataTypes a bit mask indicating the set of legal data * types for this tag. * @param count the value count for this tag. * @throws NullPointerException if name is null. * @throws IllegalArgumentException if number is negative or dataTypes * is negative or specifies an out of range type. */ public TIFFTag(String name, int number, int dataTypes, int count) { if (name == null) { throw new NullPointerException("name == null"); } else if (number < 0) { throw new IllegalArgumentException("number (" + number + ") < 0"); } else if (dataTypes < 0 || (dataTypes & DISALLOWED_DATATYPES_MASK) != 0) { throw new IllegalArgumentException("dataTypes out of range"); } this.name = name; this.number = number; this.dataTypes = dataTypes; this.count = count; } /** * Constructs a {@code TIFFTag} with a given name, tag number and * {@code TIFFTagSet} to which it refers. The legal data types are * set to include {@link #TIFF_LONG} and {@link #TIFF_IFD_POINTER} and the * value count is unity. The {@code TIFFTagSet} will * represent the set of {@code TIFFTag}s which appear in the IFD * pointed to. A {@code TIFFTag} represents an IFD pointer if and * only if {@code tagSet} is non-{@code null} or the data * type {@code TIFF_IFD_POINTER} is legal. * * @param name the name of the tag. * @param number the number used to represent the tag. * @param tagSet the {@code TIFFTagSet} to which this tag belongs. * @throws NullPointerException if name or tagSet is null. * @throws IllegalArgumentException if number is negative. * * @see #TIFFTag(String, int, int, int) */ public TIFFTag(String name, int number, TIFFTagSet tagSet) { this(name, number, 1 << TIFFTag.TIFF_LONG | 1 << TIFFTag.TIFF_IFD_POINTER, 1); if (tagSet == null) { throw new NullPointerException("tagSet == null"); } this.tagSet = tagSet; } /** * Constructs a {@code TIFFTag} with a given name, tag number, * and set of legal data types. The value count of the tag will be * undefined and it will have no associated {@code TIFFTagSet}. * * @param name the name of the tag. * @param number the number used to represent the tag. * @param dataTypes a bit mask indicating the set of legal data * types for this tag. * @throws NullPointerException if name is null. * @throws IllegalArgumentException if number is negative or dataTypes * is negative or specifies an out of range type. * * @see #TIFFTag(String, int, int, int) */ public TIFFTag(String name, int number, int dataTypes) { this(name, number, dataTypes, -1); } /** * Returns the number of bytes used to store a value of the given * data type. * * @param dataType the data type to be queried. * * @return the number of bytes used to store the given data type. * * @throws IllegalArgumentException if {@code datatype} is * less than {@code MIN_DATATYPE} or greater than * {@code MAX_DATATYPE}. */ public static int getSizeOfType(int dataType) { if (dataType < MIN_DATATYPE ||dataType > MAX_DATATYPE) { throw new IllegalArgumentException("dataType out of range!"); } return SIZE_OF_TYPE[dataType]; } /** * Returns the name of the tag, as it will appear in image metadata. * * @return the tag name, as a {@code String}. */ public String getName() { return name; } /** * Returns the integer used to represent the tag. * * @return the tag number, as an {@code int}. */ public int getNumber() { return number; } /** * Returns a bit mask indicating the set of data types that may * be used to store the data associated with the tag. * For example, a tag that can store both SHORT and LONG values * would return a value of: * * <pre> * (1 << TIFFTag.TIFF_SHORT) | (1 << TIFFTag.TIFF_LONG) * </pre> * * @return an {@code int} containing a bitmask encoding the * set of valid data types. */ public int getDataTypes() { return dataTypes; } /** * Returns the value count of this tag. If this value is positive, it * represents the required number of values for a {@code TIFFField} * which has this tag. If the value is negative, the count is undefined. * In the latter case the count may be derived, e.g., the number of values * of the {@code BitsPerSample} field is {@code SamplesPerPixel}, * or it may be variable as in the case of most {@code US-ASCII} * fields. * * @return the value count of this tag. */ public int getCount() { return count; } /** * Returns {@code true} if the given data type * may be used for the data associated with this tag. * * @param dataType the data type to be queried, one of * {@code TIFF_BYTE}, {@code TIFF_SHORT}, etc. * * @return a {@code boolean} indicating whether the given * data type may be used with this tag. * * @throws IllegalArgumentException if {@code datatype} is * less than {@code MIN_DATATYPE} or greater than * {@code MAX_DATATYPE}. */ public boolean isDataTypeOK(int dataType) { if (dataType < MIN_DATATYPE || dataType > MAX_DATATYPE) { throw new IllegalArgumentException("datatype not in range!"); } return (dataTypes & (1 << dataType)) != 0; } /** * Returns the {@code TIFFTagSet} of which this tag is a part. * * @return the containing {@code TIFFTagSet}. */ public TIFFTagSet getTagSet() { return tagSet; } /** * Returns {@code true} if this tag is used to point to an IFD * structure containing additional tags. A {@code TIFFTag} represents * an IFD pointer if and only if its {@code TIFFTagSet} is * non-{@code null} or the data type {@code TIFF_IFD_POINTER} is * legal. This condition will be satisfied if and only if either * {@code getTagSet() != null} or * {@code isDataTypeOK(TIFF_IFD_POINTER) == true}. * * <p>Many TIFF extensions use the IFD mechanism in order to limit the * number of new tags that may appear in the root IFD.</p> * * @return {@code true} if this tag points to an IFD. */ public boolean isIFDPointer() { return tagSet != null || isDataTypeOK(TIFF_IFD_POINTER); } /** * Returns {@code true} if there are mnemonic names associated with * the set of legal values for the data associated with this tag. Mnemonic * names apply only to tags which have integral data type. * * @return {@code true} if mnemonic value names are available. */ public boolean hasValueNames() { return valueNames != null; } /** * Adds a mnemonic name for a particular value that this tag's data may take * on. Mnemonic names apply only to tags which have integral data type. * * @param value the data value. * @param name the name to associate with the value. */ protected void addValueName(int value, String name) { if (valueNames == null) { valueNames = new TreeMap<Integer,String>(); } valueNames.put(Integer.valueOf(value), name); } /** * Returns the mnemonic name associated with a particular value * that this tag's data may take on, or {@code null} if * no name is present. Mnemonic names apply only to tags which have * integral data type. * * @param value the data value. * * @return the mnemonic name associated with the value, as a * {@code String}. */ public String getValueName(int value) { if (valueNames == null) { return null; } return valueNames.get(Integer.valueOf(value)); } /** * Returns an array of values for which mnemonic names are defined. The * method {@link #getValueName(int) getValueName()} will return * non-{@code null} only for values contained in the returned array. * Mnemonic names apply only to tags which have integral data type. * * @return the values for which there is a mnemonic name. */ public int[] getNamedValues() { int[] intValues = null; if (valueNames != null) { Set<Integer> values = valueNames.keySet(); Iterator<Integer> iter = values.iterator(); intValues = new int[values.size()]; int i = 0; while (iter.hasNext()) { intValues[i++] = iter.next(); } } return intValues; } }