com.github.jaiimageio.plugins.tiff.TIFFDirectory Maven / Gradle / Ivy
Show all versions of jai-imageio-core Show documentation
/* * $RCSfile: TIFFDirectory.java,v $ * * * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * This software is provided "AS IS," without a warranty of any * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that this software is not designed or intended for * use in the design, construction, operation or maintenance of any * nuclear facility. * * $Revision: 1.4 $ * $Date: 2006/08/25 00:16:49 $ * $State: Exp $ */ package com.github.jaiimageio.plugins.tiff; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.TreeMap; import javax.imageio.metadata.IIOInvalidTreeException; import javax.imageio.metadata.IIOMetadata; import javax.imageio.metadata.IIOMetadataFormatImpl; import com.github.jaiimageio.impl.plugins.tiff.TIFFIFD; import com.github.jaiimageio.impl.plugins.tiff.TIFFImageMetadata; /** * A convenience class for simplifying interaction with TIFF native * image metadata. A TIFF image metadata tree represents an Image File * Directory (IFD) from a TIFF 6.0 stream. An IFD consists of a number of * IFD Entries each of which associates an identifying tag number with * a compatible value. A
methods of {@link javax.imageio.ImageWriter} may be * created from aTIFFDirectory
instance corresponds * to an IFD and contains a set of {@link TIFFField}s each of which * corresponds to an IFD Entry in the IFD. * *When reading, a
* *TIFFDirectory
may be created by passing * the value returned by {@link javax.imageio.ImageReader#getImageMetadata * ImageReader.getImageMetadata()} to {@link #createFromMetadata * createFromMetadata()}. The {@link TIFFField}s in the directory may then * be obtained using the accessor methods provided in this class.When writing, an {@link IIOMetadata} object for use by one of the *
write() TIFFDirectory
by {@link #getAsMetadata()}. * TheTIFFDirectory
itself may be created by construction or * from theIIOMetadata
object returned by * {@link javax.imageio.ImageWriter#getDefaultImageMetadata * ImageWriter.getDefaultImageMetadata()}. TheTIFFField
s in the * directory may be set using the mutator methods provided in this class. * *A
* *TIFFDirectory
is aware of the tag numbers in the * group of {@link TIFFTagSet}s associated with it. When * aTIFFDirectory
is created from a native image metadata * object, these tag sets are derived from the tagSets attribute * of the TIFFIFD node.A
* *TIFFDirectory
might also have a parent {@link TIFFTag}. * This will occur if the directory represents an IFD other than the root * IFD of the image. The parent tag is the tag of the IFD Entry which is a * pointer to the IFD represented by thisTIFFDirectory
. The * {@link TIFFTag#isIFDPointer} method of this parentTIFFTag
* must returntrue
. When aTIFFDirectory
is * created from a native image metadata object, the parent tag set is set * from the parentTagName attribute of the corresponding * TIFFIFD node. Note that aTIFFDirectory
instance * which has a non-null
parent tag will be contained in the * data field of aTIFFField
instance which has a tag field * equal to the contained directory's parent tag.As an example consider an EXIF image. The
* *TIFFDirectory
* instance corresponding to the EXIF IFD in the EXIF stream would have parent * tag {@link EXIFParentTIFFTagSet#TAG_EXIF_IFD_POINTER TAG_EXIF_IFD_POINTER} * and would include {@link EXIFTIFFTagSet} in its group of known tag sets. * TheTIFFDirectory
corresponding to this EXIF IFD will be * contained in the data field of aTIFFField
which will in turn * be contained in theTIFFDirectory
corresponding to the primary * IFD of the EXIF image which will itself have anull
-valued * parent tag.Note that this implementation is not synchronized. If multiple * threads use a
* * @see IIOMetadata * @see TIFFField * @see TIFFTag * @see TIFFTagSet * * @since 1.1-beta */ // XXX doc: not thread safe public class TIFFDirectory implements Cloneable { /** The largest low-valued tag number in the TIFF 6.0 specification. */ private static final int MAX_LOW_FIELD_TAG_NUM = BaselineTIFFTagSet.TAG_REFERENCE_BLACK_WHITE; /** TheTIFFDirectory
instance concurrently, and at * least one of the threads modifies the directory, for example, by adding * or removingTIFFField
s orTIFFTagSet
s, it * must be synchronized externally.TIFFTagSets
associated with this directory. */ private List tagSets; /** The parentTIFFTag
of this directory. */ private TIFFTag parentTag; /** * The fields in this directory which have a low tag number. These are * managed as an array for efficiency as they are the most common fields. */ private TIFFField[] lowFields = new TIFFField[MAX_LOW_FIELD_TAG_NUM + 1]; /** The number of low tag numbered fields in the directory. */ private int numLowFields = 0; /** * A mapping ofInteger
tag numbers toTIFFField
s * for fields which are not low tag numbered. */ private Map highFields = new TreeMap(); /** * Creates aTIFFDirectory
instance from the contents of * an image metadata object. The supplied object must support an image * metadata format supported by the TIFF {@link javax.imageio.ImageWriter} * plug-in. This will usually be either the TIFF native image metadata * format com_sun_media_imageio_plugins_tiff_1.0 or the Java * Image I/O standard metadata format javax_imageio_1.0. * * @param tiffImageMetadata A metadata object which supports a compatible * image metadata format. * * @return ATIFFDirectory
populated from the contents of * the supplied metadata object. * * @throws IllegalArgumentException iftiffImageMetadata
* isnull
. * @throws IllegalArgumentException iftiffImageMetadata
* does not support a compatible image metadata format. * @throws IIOInvalidTreeException if the supplied metadata object * cannot be parsed. */ public static TIFFDirectory createFromMetadata(IIOMetadata tiffImageMetadata) throws IIOInvalidTreeException { if(tiffImageMetadata == null) { throw new IllegalArgumentException("tiffImageMetadata == null"); } TIFFImageMetadata tim; if(tiffImageMetadata instanceof TIFFImageMetadata) { tim = (TIFFImageMetadata)tiffImageMetadata; } else { // Create a native metadata object. ArrayList l = new ArrayList(1); l.add(BaselineTIFFTagSet.getInstance()); tim = new TIFFImageMetadata(l); // Determine the format name to use. String formatName = null; if(TIFFImageMetadata.nativeMetadataFormatName.equals (tiffImageMetadata.getNativeMetadataFormatName())) { formatName = TIFFImageMetadata.nativeMetadataFormatName; } else { String[] extraNames = tiffImageMetadata.getExtraMetadataFormatNames(); if(extraNames != null) { for(int i = 0; i < extraNames.length; i++) { if(TIFFImageMetadata.nativeMetadataFormatName.equals (extraNames[i])) { formatName = extraNames[i]; break; } } } if(formatName == null) { if(tiffImageMetadata.isStandardMetadataFormatSupported()) { formatName = IIOMetadataFormatImpl.standardMetadataFormatName; } else { throw new IllegalArgumentException ("Parameter does not support required metadata format!"); } } } // Set the native metadata object from the tree. tim.setFromTree(formatName, tiffImageMetadata.getAsTree(formatName)); } return tim.getRootIFD(); } /** * Converts aTIFFDirectory
to aTIFFIFD
. */ private static TIFFIFD getDirectoryAsIFD(TIFFDirectory dir) { if(dir instanceof TIFFIFD) { return (TIFFIFD)dir; } TIFFIFD ifd = new TIFFIFD(Arrays.asList(dir.getTagSets()), dir.getParentTag()); TIFFField[] fields = dir.getTIFFFields(); int numFields = fields.length; for(int i = 0; i < numFields; i++) { TIFFField f = fields[i]; TIFFTag tag = f.getTag(); if(tag.isIFDPointer()) { TIFFDirectory subIFD = getDirectoryAsIFD((TIFFDirectory)f.getData()); f = new TIFFField(tag, f.getType(), f.getCount(), subIFD); } ifd.addTIFFField(f); } return ifd; } /** * Constructs aTIFFDirectory
which is aware of a given * group of {@link TIFFTagSet}s. An optional parent {@link TIFFTag} * may also be specified. * * @param tagSets TheTIFFTagSets
associated with this * directory. * @param parentTag The parentTIFFTag
of this directory; * may benull
. * @throws IllegalArgumentException iftagSets
is *null
. */ public TIFFDirectory(TIFFTagSet[] tagSets, TIFFTag parentTag) { if(tagSets == null) { throw new IllegalArgumentException("tagSets == null!"); } this.tagSets = new ArrayList(tagSets.length); int numTagSets = tagSets.length; for(int i = 0; i < numTagSets; i++) { this.tagSets.add(tagSets[i]); } this.parentTag = parentTag; } /** * Returns the {@link TIFFTagSet}s of which this directory is aware. * * @return TheTIFFTagSet
s associated with this *TIFFDirectory
. */ public TIFFTagSet[] getTagSets() { return (TIFFTagSet[])tagSets.toArray(new TIFFTagSet[tagSets.size()]); } /** * Adds an element to the group of {@link TIFFTagSet}s of which this * directory is aware. * * @param tagSet TheTIFFTagSet
to add. * @throws IllegalArgumentException iftagSet
is *null
. */ public void addTagSet(TIFFTagSet tagSet) { if(tagSet == null) { throw new IllegalArgumentException("tagSet == null"); } if(!tagSets.contains(tagSet)) { tagSets.add(tagSet); } } /** * Removes an element from the group of {@link TIFFTagSet}s of which this * directory is aware. * * @param tagSet TheTIFFTagSet
to remove. * @throws IllegalArgumentException iftagSet
is *null
. */ public void removeTagSet(TIFFTagSet tagSet) { if(tagSet == null) { throw new IllegalArgumentException("tagSet == null"); } if(tagSets.contains(tagSet)) { tagSets.remove(tagSet); } } /** * Returns the parent {@link TIFFTag} of this directory if one * has been defined ornull
otherwise. * * @return The parentTIFFTag
of this *TIFFDiectory
ornull
. */ public TIFFTag getParentTag() { return parentTag; } /** * Returns the {@link TIFFTag} which has tag number equal to *tagNumber
ornull
if no such tag * exists in the {@link TIFFTagSet}s associated with this * directory. * * @param tagNumber The tag number of interest. * @return The correspondingTIFFTag
ornull
. */ public TIFFTag getTag(int tagNumber) { return TIFFIFD.getTag(tagNumber, tagSets); } /** * Returns the number of {@link TIFFField}s in this directory. * * @return The number ofTIFFField
s in this *TIFFDirectory
. */ public int getNumTIFFFields() { return numLowFields + highFields.size(); } /** * Determines whether a TIFF field with the given tag number is * contained in this directory. * * @return Whether a {@link TIFFTag} with tag number equal to *tagNumber
is present in thisTIFFDirectory
. */ public boolean containsTIFFField(int tagNumber) { return (tagNumber >= 0 && tagNumber <= MAX_LOW_FIELD_TAG_NUM && lowFields[tagNumber] != null) || highFields.containsKey(new Integer(tagNumber)); } /** * Adds a TIFF field to the directory. * * @param f The field to add. * @throws IllegalArgumentException iff
isnull
. */ public void addTIFFField(TIFFField f) { if(f == null) { throw new IllegalArgumentException("f == null"); } int tagNumber = f.getTagNumber(); if(tagNumber >= 0 && tagNumber <= MAX_LOW_FIELD_TAG_NUM) { if(lowFields[tagNumber] == null) { numLowFields++; } lowFields[tagNumber] = f; } else { highFields.put(new Integer(tagNumber), f); } } /** * Retrieves a TIFF field from the directory. * * @param tagNumber The tag number of the tag associated with the field. * @return ATIFFField
with the requested tag number of *null
if no such field is present. */ public TIFFField getTIFFField(int tagNumber) { TIFFField f; if(tagNumber >= 0 && tagNumber <= MAX_LOW_FIELD_TAG_NUM) { f = lowFields[tagNumber]; } else { f = (TIFFField)highFields.get(new Integer(tagNumber)); } return f; } /** * Removes a TIFF field from the directory. * * @param tagNumber The tag number of the tag associated with the field. */ public void removeTIFFField(int tagNumber) { if(tagNumber >= 0 && tagNumber <= MAX_LOW_FIELD_TAG_NUM) { if(lowFields[tagNumber] != null) { numLowFields--; lowFields[tagNumber] = null; } } else { highFields.remove(new Integer(tagNumber)); } } /** * Retrieves all TIFF fields from the directory. * * @return An array of all TIFF fields in order of numerically increasing * tag number. */ public TIFFField[] getTIFFFields() { // Allocate return value. TIFFField[] fields = new TIFFField[numLowFields + highFields.size()]; // Copy any low-index fields. int nextIndex = 0; for(int i = 0; i <= MAX_LOW_FIELD_TAG_NUM; i++) { if(lowFields[i] != null) { fields[nextIndex++] = lowFields[i]; if(nextIndex == numLowFields) break; } } // Copy any high-index fields. if(!highFields.isEmpty()) { Iterator keys = highFields.keySet().iterator(); while(keys.hasNext()) { fields[nextIndex++] = (TIFFField)highFields.get(keys.next()); } } return fields; } /** * Removes all TIFF fields from the directory. */ public void removeTIFFFields() { Arrays.fill(lowFields, (Object)null); numLowFields = 0; highFields.clear(); } /** * Converts the directory to a metadata object. * * @return A metadata instance initialized from the contents of this *TIFFDirectory
. */ public IIOMetadata getAsMetadata() { return new TIFFImageMetadata(getDirectoryAsIFD(this)); } /** * Clones the directory and all the fields contained therein. * * @return A clone of thisTIFFDirectory
. */ public Object clone() { TIFFDirectory dir = new TIFFDirectory(getTagSets(), getParentTag()); TIFFField[] fields = getTIFFFields(); int numFields = fields.length; for(int i = 0; i < numFields; i++) { dir.addTIFFField(fields[i]); } return dir; } }