/**
* JHOVE2 - Next-generation architecture for format-aware characterization
* <p>
* Copyright (c) 2010 by The Regents of the University of California. All rights reserved.
* </p>
* <p>
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* </p>
* <ul>
* <li>Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.</li>
* <li>Redistributions 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.</li>
* <li>Neither the name of the University of California/California Digital
* Library, Ithaka Harbors/Portico, or Stanford University, nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.</li>
* </ul>
* <p>
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* </p>
*/
package org.jhove2.module.format.tiff;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.jhove2.annotation.ReportableProperty;
import org.jhove2.core.JHOVE2;
import org.jhove2.core.JHOVE2Exception;
import org.jhove2.core.Message;
import org.jhove2.core.Message.Context;
import org.jhove2.core.Message.Severity;
import org.jhove2.core.source.MeasurableSource;
import org.jhove2.core.source.Source;
import org.jhove2.module.format.Validator.Validity;
import org.jhove2.module.format.tiff.type.Byte;
import org.jhove2.module.format.tiff.type.Long;
import org.jhove2.module.format.tiff.type.LongArray;
import org.jhove2.module.format.tiff.type.Rational;
import org.jhove2.module.format.tiff.type.Short;
import org.jhove2.module.format.tiff.type.ShortArray;
import com.sleepycat.persist.model.Persistent;
/**
* @author mstrong
*
*/
@Persistent
public class TiffIFD
extends IFD
{
public static final int NULL = -1;
/** Partial list of Tiff Tags */
public static final int
ARTIST = 315,
BACKGROUNDCOLORINDICATOR = 34024,
BACKGROUNDCOLORVALUE = 34026,
BITSPERRUNLENGTH = 34020,
BITSPEREXTENDEDRUNLENGTH = 34021,
BITSPERSAMPLE = 258,
CELLLENGTH = 265,
CFAREPEATPATTTERNDIM = 33421,
CFAPATTERN = 33422,
CLIPPATH =343,
CMYKEQUIVALENT = 34032,
COLORMAP = 320,
COLORSEQUENCE = 34017,
COLORTABLE = 34022,
COPYRIGHT = 33432,
COMPRESSION = 259,
DATETIME = 306,
DATETIMEORIGINAL = 36867,
DOCUMENTNAME = 269,
DOTRANGE = 336,
EXTRASAMPLES = 338,
FILLORDER = 266,
GEOKEYDIRECTORY = 34735,
HALFTONEHINTS = 321,
HOSTCOMPUTER = 316,
ICCPROFILE = 34675,
IT8HEADER = 34018,
IMAGEWIDTH = 256,
IMAGECOLORINDICATOR = 34023,
IMAGECOLORVALUE = 34025,
IMAGEDESCRIPTION = 270,
IMAGELENGTH = 257,
INDEXED = 346,
INKNAMES = 333,
INKSET = 332,
JPEGACTABLES = 521,
JPEGDCTABLES = 520,
JPEGINTERCHANGEFORMAT = 513,
JPEGINTERCHANGEFORMATLENGTH = 514,
JPEGLOSSLESSPREDICTORS = 517,
JPEGPOINTTRANSFORMS = 518,
JPEGPROC = 512,
JPEG_RESTART_INTERVAL = 515,
JPEG_QTABLES = 519,
MAKE = 271,
MODEL = 272,
MODELTIEPOINT = 33922,
MODELTRANSFORMATION = 34264,
NUMBEROFINKS = 334,
ORIENTATION = 274,
PAGENAME = 285,
NEWSUBFILETYPE = 254,
PLANARCONFIGURATION = 284,
PREDICTOR = 317,
PRIMARY_CHROMATACITIES = 319,
REFERENCEBLACKWHITE = 532,
PHOTMETRIC_INTERPRETATION = 262,
PIXELINTENSITYRANGE = 34027,
RASTERPADDING = 34019,
RESOLUTIONUNIT = 296,
ROWSPERSTRIP = 278,
SAMPLEFORMAT = 339,
SAMPLESPERPIXEL = 277,
SENSINGMETHOD = 37399,
SITE = 34016,
SMINSAMPLEVALUE = 340,
SMAXSAMPLEVALUE = 341,
SOFTWARE = 305,
STRIPBYTECOUNTS = 279,
STRIPOFFSETS = 273,
TARGETPRINTER = 337,
THRESHHOLDING = 263,
TIFFEPSTANDARDID = 37398,
TILEBYTECOUNTS = 325,
TILELENGTH = 323,
TILEWIDTH = 322,
TILEOFFSETS = 324,
TRANSFERRANGE = 342,
TRANSPARENCYINDICATOR = 34028,
TRAPINDICATOR = 34031,
WHITEPOINT = 318,
XCLIPPATHUNITS = 344,
XMP = 700,
XRESOLUTION = 282,
YCBCRCOEFFICIENTS = 529,
YCBCRSUBSAMPLING = 530,
YCBCRPOSITIONING = 531,
YRESOLUTION = 283;
/** compression tag value */
private int compression = NULL;
/* dot range tag value */
private int[] dotRange = null;
/* dot range out of range message */
private Message dotRangeOutofRangeMessage;
/** flag indicating if Photometric Interpreation is present */
boolean hasPhotometricInterpretation = false;
/** flag indicating if strip byte counts tag is present */
private boolean hasStripByteCounts = false;
/** flag indicating if strip offsets are present */
public boolean hasStripOffsets = false;
/** indicates if TileByteCounts tag present */
private boolean hasTileByteCounts;
/** indicates if TileLength tag present */
private boolean hasTileLength;
/** indicates if TileOffsets tag present */
private boolean hasTileOffsets;
/** indicates if TileWidth tag present */
private boolean hasTileWidth;
/** image length tag value */
private long imageLength = NULL;
/** image width tag value */
private long imageWidth = NULL;
/** Missing required tag message. */
protected List<Message> missingRequiredTagMessages;
/** photometric interpretation value */
private int photometricInterpretation = NULL;
/** strip byte counts value */
long[] stripByteCounts = null;
/** strip offsets value */
private long[] stripOffsets = null;
/** tile byte counts tag value */
private long[] tileByteCounts = null;
/** tile length tag value */
private long tileLength = NULL;
/** tile offsets tag value */
private long [] tileOffsets = null;
/** tiles and strips are both defined message */
private Message tilesAndStripsDefinedMessage;
/** neither tile and strips not defined message */
private Message tilesAndStripsNotDefinedMessage;
/** tileWidth tag value */
private long tileWidth = NULL;
/** strip byte counts tag not defined message */
private Message stripByteCountsNotDefinedMessage;
/** strip offsets tag not defined message */
private Message stripOffsetsNotDefinedMessage;
/** Planar configuration tag value */
private int planarConfiguration = NULL;
/** samples per pixel tag value */
private int samplesPerPixel = NULL;
/** strip lengths inconsisten message */
private Message StripsLengthInconsistentMessage;
/** invalid strip offset message */
private Message invalidStripOffsetMessage;
/** tile byte counts not defined message */
private Message tileByteCountsNotDefinedMessage;
/** tile offsets not defined message */
private Message tileOffsetsNotDefinedMessage;
/** tile width not defined message */
private Message tileWidthNotDefinedMessage;
/** tile length not defined message */
private Message tileLengthNotDefinedMessage;
/** tile offset values are insufficient message */
private Message tileOffsetValuesInsufficientMessage;
/** tile byte counts values insufficient message */
private Message tileByteCountsValuesInsufficientMessage;
/** transparency mask value is inconsistent message */
private Message transparencyMaskValueInconsistentMessage;
/** Bits Per Sample Invalid for Transparency Mask Message */
private Message BPSInvalidForTransparencyMaskMessage;
/** photometric interpretation Samples Per Pixel Less Than 1 Message */
private Message photometricInterpretationSppLT1InvalidMessage;
/** photometric interpretation samples per pixel less than 3 Message */
private Message photometricInterpretationSppLT3InvalidMessage;
/** color map bit code value */
private int[] colorMapBitCode = null;
/** color map red value */
private int[] colorMapRed = null;
/** color map green value */
private int[] colorMapGreen = null;
/** color map blue value */
private int[] colorMapBlue = null;
/** color map not defined for pallete color message */
private Message colorMapNotDefinedForPalleteColorMessage;
/** Samples Per Pixel must equal one for Pallete color message */
private Message sppMustEqualOneForPalleteColorMessage;
/** newSubfileType tag value */
private long newSubfileType = NULL;
/** bit per sample tag value */
private int[] bitsPerSample = null;
/** colorMap tag value */
private int[] colorMap = null;
/** insufficient color map values for Pallete color message */
private Message insufficientColorMapValuesForPalleteColorMessage;
/** color map not defined for pallete folor message */
private Message colorMapNotDefinedForPalletteColorMessage;
/** cell length should not be present message */
private Message cellLengthShouldNotBePresentMessage;
/** Samples per pixel and extral samples value are invalid message */
private Message sppExtraSamplesValueInvalidMessage;
/** bits per sample value invalid for CIE L*a*b* message */
private Message bpsValueInvalidforCIELabMessage;
/** XCLipPathUnits not defined when ClipPaths defined message */
private Message xClipPathUnitsNotDefinedMessage;
private int resolutionUnit = NULL;
private long xResolution = NULL;
private Rational yResolution = null;
private int orientation = NULL;
private int imageColorIndicator = NULL;
private int backgroundColorIndicator = NULL;
private int indexed = NULL;
private int fillOrder = NULL;
private boolean hasImageLength = false;
private boolean hasImageWidth = false;
private boolean hasXResolution = false;
private boolean hasYResolution = false;
private boolean hasRowsPerStrip = false;
private long rowsPerStrip = NULL;
/** Instantiate a <code>TiffIFD</code> object
* represents a Tiff IFD
*/
public TiffIFD() {
super();
this.isValid = Validity.Undetermined;
this.missingRequiredTagMessages = new ArrayList<Message>();
}
public void postParse()
{
IFDEntry entry = null;
if ((entry = entries.get(RESOLUTIONUNIT)) != null) {
this.resolutionUnit = ((Short) entry.getValue()).getValue();
}
if ((entry = entries.get(XRESOLUTION)) != null) {
this.xResolution = (((Rational) entry.getValue()).toLong());
hasXResolution = true;
}
if ((entry = entries.get(YRESOLUTION)) != null) {
this.yResolution = (Rational) entry.getValue();
hasYResolution = true;
}
if ((entry = entries.get(IMAGECOLORINDICATOR)) != null) {
this.imageColorIndicator = ((Byte) entry.getValue()).getValue();
}
if ((entry = entries.get(ORIENTATION)) != null) {
this.orientation = ((Short) entry.getValue()).getValue();
}
if ((entry = entries.get(BACKGROUNDCOLORINDICATOR)) != null) {
this.backgroundColorIndicator = ((Short) entry.getValue()).getValue();
}
if ((entry = entries.get(INDEXED)) != null) {
this.indexed = ((Short) entry.getValue()).getValue();
}
if ((entry = entries.get(FILLORDER)) != null) {
this.fillOrder = ((Short) entry.getValue()).getValue();
}
if ((entry = entries.get(ROWSPERSTRIP)) != null) {
this.rowsPerStrip = ((Long) entry.getValue()).getValue();
hasRowsPerStrip = true;
}
}
public Validity validate(JHOVE2 jhove2, Source source) throws JHOVE2Exception, FileNotFoundException, IOException
{
IFDEntry entry = null;
/* Validate The ImageLength (tag 257), ImageWidth (256), and PhotometricInterpretation (262) tags are defined */
if ((entry = entries.get(IMAGELENGTH)) != null) {
this.imageLength = ((Long) entry.getValue()).getValue();
hasImageLength = true;
}
else {
this.isValid = Validity.False;
Object [] args = new Object [] {"Image Length"};
Message msg = new Message(Severity.ERROR, Context.OBJECT,
"org.jhove2.module.format.tiff.TiffIFD.MissingRequiredTag",
args, jhove2.getConfigInfo());
this.missingRequiredTagMessages.add(msg);
}
if ((entry = entries.get(IMAGEWIDTH)) != null) {
this.imageWidth = ((Long) entry.getValue()).getValue();
hasImageWidth = true;
}
else {
this.isValid = Validity.False;
Object [] args = new Object [] {"Image Width"};
Message msg = new Message(Severity.ERROR, Context.OBJECT,
"org.jhove2.module.format.tiff.TiffIFD.MissingRequiredTag",
args, jhove2.getConfigInfo());
this.missingRequiredTagMessages.add(msg);
}
if ((entry = entries.get(PHOTMETRIC_INTERPRETATION)) != null) {
this.photometricInterpretation = ((Short) entry.getValue()).getValue();
hasPhotometricInterpretation = true;
}
else {
this.isValid = Validity.False;
Object [] args = new Object [] {"PhotometricInterpretation"};
Message msg = new Message(Severity.ERROR, Context.OBJECT,
"org.jhove2.module.format.tiff.TiffIFD.MissingRequiredTag",
args, jhove2.getConfigInfo());
this.missingRequiredTagMessages.add(msg);
}
/* Validate If version 4.0 or 5.0 then StripByteCounts (279) and StripOffsets (273) are defined;
* if version 6.0 then either all of StripByteCounts and StripOffsets or
* TileByteCounts (325), TileLength (323), TileOffsets (324), and TileWidth (322) are defined
*/
if ((entry = entries.get(STRIPBYTECOUNTS)) != null) {
this.stripByteCounts = getStripValue(entry);
hasStripByteCounts = true;
}
if ((entry = entries.get(STRIPOFFSETS)) != null) {
this.stripOffsets = getStripValue(entry);
hasStripOffsets = true;
}
boolean hasStripsDefined = (hasStripByteCounts || hasStripOffsets);
if (hasStripsDefined) {
if (!hasStripByteCounts) {
this.isValid = Validity.False;
this.stripByteCountsNotDefinedMessage = new Message(Severity.ERROR, Context.OBJECT,
"org.jhove2.module.format.tiff.TiffIFD.StripByteCountsNotDefinedMessage",
jhove2.getConfigInfo());
}
else if (!hasStripOffsets){
this.isValid = Validity.False;
this.stripOffsetsNotDefinedMessage = new Message(Severity.ERROR, Context.OBJECT,
"org.jhove2.module.format.tiff.TiffIFD.StripOffsetsNotDefinedMessage",
jhove2.getConfigInfo());
}
int length = stripOffsets.length;
if (stripByteCounts.length != length) {
this.isValid = Validity.False;
Object[] args = new Object[]{stripByteCounts.length, length};
this.StripsLengthInconsistentMessage = new Message(Severity.ERROR, Context.OBJECT,
"org.jhove2.module.format.tiff.TiffIFD.StripsLengthInconsistentMessage",
args, jhove2.getConfigInfo());
}
long fileLength = ((MeasurableSource) source).getSize();
for (int i=0; i<length; i++) {
long offset = stripOffsets[i];
long count = stripByteCounts[i];
if (offset+count > fileLength) {
this.isValid = Validity.False;
this.invalidStripOffsetMessage = new Message(Severity.ERROR, Context.OBJECT,
"org.jhove2.module.format.tiff.TiffIFD.InvalidStripOffsetMessage",
jhove2.getConfigInfo());
}
}
}
if ((entry = entries.get(TILEWIDTH)) != null) {
this.tileWidth = ((Long) entry.getValue()).getValue();
hasTileWidth = true;
}
if ((entry = entries.get(TILELENGTH)) != null) {
this.tileLength = ((Long) entry.getValue()).getValue();
hasTileLength = true;
}
if ((entry = entries.get(TILEOFFSETS)) != null) {
this.tileOffsets = ((LongArray) entry.getValue()).getLongArrayValue();
hasTileOffsets = true;
}
if ((entry = entries.get(TILEBYTECOUNTS)) != null) {
this.tileByteCounts = ((LongArray) entry.getValue()).getLongArrayValue();
hasTileByteCounts = true;
}
boolean hasTilesDefined = (hasTileWidth || hasTileLength ||
hasTileOffsets || hasTileByteCounts);
if (hasTilesDefined){
if (!hasTileWidth) {
this.isValid = Validity.False;
this.tileWidthNotDefinedMessage = new Message(Severity.ERROR, Context.OBJECT,
"org.jhove2.module.format.tiff.TiffIFD.TileWidthNotDefinedMessage",
jhove2.getConfigInfo());
}
if (!hasTileLength) {
this.isValid = Validity.False;
this.tileLengthNotDefinedMessage = new Message(Severity.ERROR, Context.OBJECT,
"org.jhove2.module.format.tiff.TiffIFD.TileLengthNotDefinedMessage",
jhove2.getConfigInfo());
}
if (!hasTileByteCounts) {
this.isValid = Validity.False;
this.tileByteCountsNotDefinedMessage = new Message(Severity.ERROR, Context.OBJECT,
"org.jhove2.module.format.tiff.TiffIFD.TileByteCountsNotDefinedMessage",
jhove2.getConfigInfo());
}
if (!hasTileOffsets) {
this.isValid = Validity.False;
this.tileOffsetsNotDefinedMessage = new Message(Severity.ERROR, Context.OBJECT,
"org.jhove2.module.format.tiff.TiffIFD.TileOffsetsNotDefinedMessage",
jhove2.getConfigInfo());
}
}
if (hasStripsDefined && hasTilesDefined) {
this.isValid = Validity.False;
this.tilesAndStripsDefinedMessage = new Message(Severity.ERROR, Context.OBJECT,
"org.jhove2.module.format.tiff.TiffIFD.TilesAndStripsDefinedMessage",
jhove2.getConfigInfo());
}
if (!hasStripsDefined && !hasTilesDefined) {
this.isValid = Validity.False;
this.tilesAndStripsNotDefinedMessage = new Message(Severity.ERROR, Context.OBJECT,
"org.jhove2.module.format.tiff.TiffIFD.TilesAndStripsNotDefinedMessage",
jhove2.getConfigInfo());
}
if (hasTilesDefined) {
if ((entry = entries.get(PLANARCONFIGURATION)) != null) {
this.planarConfiguration = ((Short) entry.getValue()).getValue();
}
if ((entry = entries.get(SAMPLESPERPIXEL)) != null) {
this.samplesPerPixel = ((Short)entry.getValue()).getValue();
}
long tilesPerImage = ((this.imageWidth + this.tileWidth - 1)/this.tileWidth) *
((this.imageLength + this.tileLength - 1)/this.tileLength);
if (planarConfiguration == 2) {
long spp_tpi = samplesPerPixel* tilesPerImage;
if (this.tileOffsets != null && this.tileOffsets.length < spp_tpi) {
this.isValid = Validity.False;
Object[] args = new Object[] {tileOffsets.length, spp_tpi};
this.tileOffsetValuesInsufficientMessage = new Message(Severity.ERROR, Context.OBJECT,
"org.jhove2.module.format.tiff.TiffIFD.TileOffsetValuesInsufficientMessage",
args, jhove2.getConfigInfo());
}
if (this.tileByteCounts != null &&
this.tileByteCounts.length < spp_tpi) {
this.isValid = Validity.False;
Object[] args = new Object[] {tileOffsets.length, spp_tpi};
this.tileByteCountsValuesInsufficientMessage = new Message(Severity.ERROR, Context.OBJECT,
"org.jhove2.module.format.tiff.TiffIFD.TileByteCountsValuesInsufficientMessage",
args, jhove2.getConfigInfo());
}
else {
if (tileOffsets != null &&
tileOffsets.length < tilesPerImage) {
this.isValid = Validity.False;
Object[] args = new Object[] {tileOffsets.length, tilesPerImage};
this.tileByteCountsValuesInsufficientMessage = new Message(Severity.ERROR, Context.OBJECT,
"org.jhove2.module.format.tiff.TiffIFD.TileByteCountsValuesInsufficientMessage",
args, jhove2.getConfigInfo());
}
if (tileByteCounts != null &&
tileByteCounts.length < tilesPerImage) {
this.isValid = Validity.False;
Object[] args = new Object[] {tileOffsets.length, tilesPerImage};
this.tileByteCountsValuesInsufficientMessage = new Message(Severity.ERROR, Context.OBJECT,
"org.jhove2.module.format.tiff.TiffIFD.TileByteCountsValuesInsufficientMessage",
args, jhove2.getConfigInfo());
}
}
}
}
if (hasPhotometricInterpretation) {
if ((entry = entries.get(SAMPLESPERPIXEL)) != null) {
this.samplesPerPixel = ((Short)entry.getValue()).getValue();
}
if ((entry = this.entries.get(NEWSUBFILETYPE)) != null) {
this.newSubfileType = ((Long) entry.getValue()).getValue();
/* If PhotometricInterpretation = 4, then bit 2 of NewSubfileType (254) = 1, and vice versa */
if ((photometricInterpretation == 4 && (newSubfileType & 4) == 0) ||
(photometricInterpretation != 4) && (newSubfileType & 4) != 0) {
this.isValid = Validity.False;
this.transparencyMaskValueInconsistentMessage = new Message(Severity.ERROR, Context.OBJECT,
"org.jhove2.module.format.tiff.TiffIFD.TransparencyMaskValueInconsistentMessage",
jhove2.getConfigInfo());
}
/* If PhotometricInterpretation = 4, then SamplesPerPixel = 1 and BitsPerSample = 1 */
if ((entry = this.entries.get(BITSPERSAMPLE)) != null) {
this.bitsPerSample = getShortValue(entry);
if (photometricInterpretation == 4) {
if (samplesPerPixel < 1 || bitsPerSample[0] != 1) {
this.isValid = Validity.False;
this.BPSInvalidForTransparencyMaskMessage = new Message(Severity.ERROR, Context.OBJECT,
"org.jhove2.module.format.tiff.TiffIFD.BPSInvalidForTransparencyMaskMessage",
jhove2.getConfigInfo());
}
}
}
/* If PhotometricInterpretation = 0,1,3, or 4, then SamplesPerPixel >= 1 */
if (photometricInterpretation != 2 && photometricInterpretation <= 4 ) {
if (samplesPerPixel < 1) {
this.isValid = Validity.False;
this.photometricInterpretationSppLT1InvalidMessage = new Message(Severity.ERROR, Context.OBJECT,
"org.jhove2.module.format.tiff.TiffIFD.photometricInterpretationSppLT1InvalidMessage",
jhove2.getConfigInfo());
}
}
/* If PhotometricInterpretation = 2,6, or 8, then SamplesPerPixel >= 3 */
if (photometricInterpretation == 2 || photometricInterpretation == 6 || photometricInterpretation == 8) {
if (samplesPerPixel < 3) {
this.isValid = Validity.False;
this.photometricInterpretationSppLT3InvalidMessage = new Message(Severity.ERROR, Context.OBJECT,
"org.jhove2.module.format.tiff.TiffIFD.PhotometricInterpretationSppLT3InvalidMessage",
jhove2.getConfigInfo());
}
}
/* If PhotometricInterpretation = 3 (Pallette Color,
* then ColorMap is defined with
* 2BitsPerSample[0] + 2BitsPerSample[1] + 2BitsPerSample[2] values
*/
if (photometricInterpretation == 3) {
if ((entry = entries.get(COLORMAP)) != null) {
this.colorMap = ((ShortArray) entry.getValue()).getShortArrayValue();
this.colorMapBitCode = new int [colorMap.length];
this.colorMapRed = new int [colorMap.length];
this.colorMapGreen = new int [colorMap.length];
this.colorMapBlue = new int [colorMap.length];
int len = colorMap.length/3;
int len2= 2*len;
for (int i=0; i<len; i++) {
colorMapBitCode[i] = i;
colorMapRed[i] = colorMap[i];
colorMapGreen[i] = colorMap[i + len];
colorMapBlue[i] = colorMap[i + len2];
}
if (colorMapBitCode == null || colorMapRed == null ||
colorMapGreen == null || colorMapBlue == null) {
this.isValid = Validity.False;
this.colorMapNotDefinedForPalletteColorMessage = new Message (Severity.ERROR, Context.OBJECT,
"org.jhove2.module.format.tiff.TiffIFD.ColorMapNotDefinedForPalletteColorMessage",
jhove2.getConfigInfo());
}
if (samplesPerPixel != 1) {
this.isValid = Validity.False;
this.sppMustEqualOneForPalleteColorMessage = new Message (Severity.ERROR, Context.OBJECT,
"org.jhove2.module.format.tiff.TiffIFD.SppMustEqualOneForPalleteColorMessage",
jhove2.getConfigInfo());
}
len = (1<<bitsPerSample[0]);
if (colorMapBitCode.length < len) {
this.isValid = Validity.False;
this.insufficientColorMapValuesForPalleteColorMessage = new Message (Severity.ERROR, Context.OBJECT,
"org.jhove2.module.format.tiff.TiffIFD.InsufficientColorMapValuesForPalleteColorMessage",
jhove2.getConfigInfo());
}
}
}
}
/* CIE L*a*b* or ICCLab Validation */
if (photometricInterpretation == 8 || photometricInterpretation == 9) {
int len = 0;
/* SamplesPerPixel-ExtraSamples = 1 or 3 */
if ((entry = entries.get(EXTRASAMPLES)) != null) {
int[] extraSamples = ((ShortArray) entry.getValue()).getShortArrayValue();
len = extraSamples.length;
int in = samplesPerPixel - len;
if (in != 1 && in != 3) {
this.isValid = Validity.False;
this.sppExtraSamplesValueInvalidMessage = new Message (Severity.ERROR, Context.OBJECT,
"org.jhove2.module.format.tiff.TiffIFD.SppExtraSamplesValueInvalidMessage",
jhove2.getConfigInfo());
}
}
/* BitsPerSample = 8 or 16 */
for (int i=0; i<bitsPerSample.length; i++) {
if (bitsPerSample[i] != 8 && bitsPerSample[i] != 16) {
this.isValid = Validity.False;
this.bpsValueInvalidforCIELabMessage = new Message (Severity.ERROR, Context.OBJECT,
"org.jhove2.module.format.tiff.TiffIFD.BpsValueInvalidforCIELabMessage",
jhove2.getConfigInfo());
}
}
}
} /* end of PhotmetricInterpretation Validation */
/* If Compression Scheme = 6 (JPEG) then JPEGProc is defined */
if ((entry = entries.get(COMPRESSION)) != null) {
compression = ((Short) entry.getValue()).getValue();
if (compression == 6) {
if ((entry = entries.get(JPEGPROC)) == null) {
this.isValid = Validity.False;
this.insufficientColorMapValuesForPalleteColorMessage = new Message (Severity.ERROR, Context.OBJECT,
"org.jhove2.module.format.tiff.TiffIFD.InsufficientColorMapValuesForPalleteColorMessage",
jhove2.getConfigInfo());
}
}
}
/* CellLength should only be present if Threshholding = 2 . */
if ((entry = entries.get(THRESHHOLDING)) != null) {
int threshholding = ((Short) entry.getValue()).getValue();
if (threshholding != 2 &&
((entry = entries.get(CELLLENGTH)) != null)) {
this.isValid = Validity.False;
this.cellLengthShouldNotBePresentMessage = new Message (Severity.ERROR, Context.OBJECT,
"org.jhove2.module.format.tiff.TiffIFD.CellLengthShouldNotBePresentMessage",
jhove2.getConfigInfo());
}
}
/* The values for DotRange (336) are in the range [0, (2BitsPerSample[i])-1] */
if ((entry = entries.get(DOTRANGE)) != null) {
this.dotRange = ((ShortArray) entry.getValue()).getShortArrayValue();
if (dotRange != null && bitsPerSample != null) {
int sampleMax = 1 << bitsPerSample[0];
if (dotRange.length < 2 || dotRange[0] >= sampleMax ||
dotRange[1] >= sampleMax) {
this.isValid = Validity.False;
this.dotRangeOutofRangeMessage = new Message (Severity.ERROR, Context.OBJECT,
"org.jhove2.module.format.tiff.TiffIFD.dotRangeOutofRangeMessage",
jhove2.getConfigInfo());
}
}
}
/* If ClipPath (343) is defined, then XClipPathUnits (344) is defined */
if ((entry = entries.get(CLIPPATH)) != null) {
if ((entry = entries.get(XCLIPPATHUNITS)) == null) {
this.isValid = Validity.False;
this.xClipPathUnitsNotDefinedMessage = new Message (Severity.ERROR, Context.OBJECT,
"org.jhove2.module.format.tiff.TiffIFD.xClipPathUnitsNotDefinedMessage",
jhove2.getConfigInfo());
}
}
if (this.isValid != Validity.False)
this.isValid = Validity.True;
return isValid;
}
/* determine if the field is either a single value or
* an array and read it appropriately
*/
private long[] getStripValue(IFDEntry entry) {
long[] field = null;
if (entry.count == 1) {
field = new long[1];
field[0] = ((Long) entry.getValue()).getValue();
}
else {
field = ((LongArray) entry.getValue()).getLongArrayValue();
}
return field;
}
/* determine if the field is either a single value or
* an array and read it appropriately
*/
private int[] getShortValue(IFDEntry entry) {
int[] field = null;
if (entry.count == 1) {
field = new int[1];
field[0] = ((Short) entry.getValue()).getValue();
}
else {
field = ((ShortArray) entry.getValue()).getShortArrayValue();
}
return field;
}
/**
* @return the compression
*/
public int getCompression() {
return compression;
}
/**
* @return the dotRange
*/
public int[] getDotRange() {
return dotRange;
}
/**
* @return the dotRangeOutofRangeMessage
*/
@ReportableProperty(order = 1, value="Dot Range out of range message.")
public Message getDotRangeOutofRangeMessage() {
return dotRangeOutofRangeMessage;
}
/**
* @return the missingRequiredTagMessages
*/
@ReportableProperty(order = 2, value = "Missing Required tag message.")
public List<Message> getMissingRequiredTagMessages() {
return missingRequiredTagMessages;
}
/**
* @return the photometricInterpretation
*/
public int getPhotometricInterpretation() {
return photometricInterpretation;
}
/**
* @return the stripByteCounts
*/
public long[] getStripByteCounts() {
return stripByteCounts;
}
/**
* @return the stripOffsets
*/
public long[] getStripOffsets() {
return stripOffsets;
}
/**
* @return the tileByteCounts
*/
public long[] getTileByteCounts() {
return tileByteCounts;
}
/**
* @return the tileLength
*/
public long getTileLength() {
return tileLength;
}
/**
* @return the tileOffsets
*/
public long[] getTileOffsets() {
return tileOffsets;
}
/**
* @return the tilesAndStripsDefinedMessage
*/
@ReportableProperty(order = 3, value = "Tiles and strips defined message.")
public Message getTilesAndStripsDefinedMessage() {
return tilesAndStripsDefinedMessage;
}
/**
* @return the tilesAndStripsNotDefinedMessage
*/
@ReportableProperty(order = 4, value = "tiles and strips not defined message.")
public Message getTilesAndStripsNotDefinedMessage() {
return tilesAndStripsNotDefinedMessage;
}
/**
* @return the tileWidth
*/
public long getTileWidth() {
return tileWidth;
}
/**
* @return the stripByteCountsNotDefinedMessage
*/
@ReportableProperty(order = 5, value = "StripByteCounts not defined message.")
public Message getStripByteCountsNotDefinedMessage() {
return stripByteCountsNotDefinedMessage;
}
/**
* @return the stripOffsetsNotDefinedMessage
*/
@ReportableProperty(order = 6, value = "StripOffsets not defined message.")
public Message getStripOffsetsNotDefinedMessage() {
return stripOffsetsNotDefinedMessage;
}
/**
* @return the planarConfiguration
*/
public int getPlanarConfiguration() {
return planarConfiguration;
}
/**
* @return the samplesPerPixel
*/
public int getSamplesPerPixel() {
return samplesPerPixel;
}
/**
* @return the stripsLengthInconsistentMessage
*/
@ReportableProperty(order = 7, value = "StripsLength is inconsistent message.")
public Message getStripsLengthInconsistentMessage() {
return StripsLengthInconsistentMessage;
}
/**
* @return the invalidStripOffsetMessage
*/
@ReportableProperty(order = 8, value = "Invalid StripOffset message.")
public Message getInvalidStripOffsetMessage() {
return invalidStripOffsetMessage;
}
/**
* @return the tileByteCountsNotDefinedMessage
*/
@ReportableProperty(order = 9, value = "TileByteCounts not defined message")
public Message getTileByteCountsNotDefinedMessage() {
return tileByteCountsNotDefinedMessage;
}
/**
* @return the tileOffsetsNotDefinedMessage
*/
@ReportableProperty(order = 10, value = "TileOffsets not defined message.")
public Message getTileOffsetsNotDefinedMessage() {
return tileOffsetsNotDefinedMessage;
}
/**
* @return the tileWidthNotDefinedMessage
*/
@ReportableProperty(order = 11, value = "TileWidth not defined message")
public Message getTileWidthNotDefinedMessage() {
return tileWidthNotDefinedMessage;
}
/**
* @return the tileLengthNotDefinedMessage
*/
@ReportableProperty(order = 12, value = "TileLength not defined message")
public Message getTileLengthNotDefinedMessage() {
return tileLengthNotDefinedMessage;
}
/**
* @return the tileOffsetValuesInsufficientMessage
*/
@ReportableProperty(order = 13, value = "TileOffsetValues are insufficient message.")
public Message getTileOffsetValuesInsufficientMessage() {
return tileOffsetValuesInsufficientMessage;
}
/**
* @return the tileByteCountsValuesInsufficientMessage
*/
@ReportableProperty(order = 14, value = "TilesByteCountsValues are insufficient message.")
public Message getTileByteCountsValuesInsufficientMessage() {
return tileByteCountsValuesInsufficientMessage;
}
/**
* @return the transparencyMaskValueInconsistentMessage
*/
@ReportableProperty(order = 15, value = "Transparency Mask value inconsistent message.")
public Message getTransparencyMaskValueInconsistentMessage() {
return transparencyMaskValueInconsistentMessage;
}
/**
* @return the bPSInvalidForTransparencyMaskMessage
*/
@ReportableProperty(order = 16, value = "BitsPerSample Invalid for transparency mask message.")
public Message getBPSInvalidForTransparencyMaskMessage() {
return BPSInvalidForTransparencyMaskMessage;
}
/**
* @return the photometricInterpretationSppLT1InvalidMessage
*/
@ReportableProperty(order = 17, value = "PhotometricInterpretation SamplesPerPixel less than one invalid message.")
public Message getPhotometricInterpretationSppLT1InvalidMessage() {
return photometricInterpretationSppLT1InvalidMessage;
}
/**
* @return the photometricInterpretationSppLT3InvalidMessage
*/
@ReportableProperty(order = 17, value = "PhotometricInterpretation SamplesPerPixel less than three invalid message.")
public Message getPhotometricInterpretationSppLT3InvalidMessage() {
return photometricInterpretationSppLT3InvalidMessage;
}
/**
* @return the colorMapBitCode
*/
public int[] getColorMapBitCode() {
return colorMapBitCode;
}
/**
* @return the colorMapRed
*/
public int[] getColorMapRed() {
return colorMapRed;
}
/**
* @return the colorMapGreen
*/
public int[] getColorMapGreen() {
return colorMapGreen;
}
/**
* @return the colorMapBlue
*/
public int[] getColorMapBlue() {
return colorMapBlue;
}
/**
* @return the colorMapNotDefinedForPalleteColorMessage
*/
@ReportableProperty(order = 18, value = "ColorMap not defined for pallete color message.")
public Message getColorMapNotDefinedForPalleteColorMessage() {
return colorMapNotDefinedForPalleteColorMessage;
}
/**
* @return the sppMustEqualOneForPalleteColorMessage
*/
@ReportableProperty(order = 19, value = "Samples Per Pixel must equal one for pallete color message.")
public Message getSppMustEqualOneForPalleteColorMessage() {
return sppMustEqualOneForPalleteColorMessage;
}
/**
* @return the newSubfileType
*/
public long getNewSubfileType() {
return newSubfileType;
}
/**
* @return the bitsPerSample
*/
public int[] getBitsPerSample() {
return bitsPerSample;
}
/**
* @return the colorMap
*/
public int[] getColorMap() {
return colorMap;
}
/**
* @return the insufficientColorMapValuesForPalleteColorMessage
*/
@ReportableProperty(order = 20, value = "Insufficient colormpa values for pallete color message.")
public Message getInsufficientColorMapValuesForPalleteColorMessage() {
return insufficientColorMapValuesForPalleteColorMessage;
}
/**
* @return the colorMapNotDefinedForPalletteColorMessage
*/
@ReportableProperty(order = 21, value = "Color map not defined for pallete color message.")
public Message getColorMapNotDefinedForPalletteColorMessage() {
return colorMapNotDefinedForPalletteColorMessage;
}
/**
* @return the cellLengthShouldNotBePresentMessage
*/
@ReportableProperty(order = 22, value = "CellLength should not be present message.")
public Message getCellLengthShouldNotBePresentMessage() {
return cellLengthShouldNotBePresentMessage;
}
/**
* @return the sppExtraSamplesValueInvalidMessage
*/
@ReportableProperty(order = 23, value = "Samples per pixel-extra samples value invalid message.")
public Message getSppExtraSamplesValueInvalidMessage() {
return sppExtraSamplesValueInvalidMessage;
}
/**
* @return the bpsValueInvalidforCIELabMessage
*/
@ReportableProperty(order = 24, value = "Bits per sample value invalid for CIE L*a*b* message.")
public Message getBpsValueInvalidforCIELabMessage() {
return bpsValueInvalidforCIELabMessage;
}
/**
* @return the xClipPathUnitsNotDefinedMessage
*/
@ReportableProperty(order = 25, value = "XClipPlathUnits not defined message.")
public Message getXClipPathUnitsNotDefinedMessage() {
return xClipPathUnitsNotDefinedMessage;
}
/**
* @return the hasPhotometricInterpretation
*/
public boolean hasPhotometricInterpretation() {
return hasPhotometricInterpretation;
}
/**
* @return the hasImageLength
*/
public boolean hasImageLength() {
return hasImageLength;
}
/**
* @return the hasImageWidth
*/
public boolean hasImageWidth() {
return hasImageWidth;
}
/**
* @return the hasStripByteCounts
*/
public boolean hasStripByteCounts() {
return hasStripByteCounts;
}
/**
* @return the hasStripOffsets
*/
public boolean hasStripOffsets() {
return hasStripOffsets;
}
/**
* @return the hasTileByteCounts
*/
public boolean hasTileByteCounts() {
return hasTileByteCounts;
}
/**
* @return the hasTileLength
*/
public boolean hasTileLength() {
return hasTileLength;
}
/**
* @return the hasTileOffsets
*/
public boolean hasTileOffsets() {
return hasTileOffsets;
}
/**
* @return the hasTileWidth
*/
public boolean hasTileWidth() {
return hasTileWidth;
}
/**
*
* @return
*/
public boolean hasXResolution() {
return this.hasXResolution;
}
/**
*
* @return boolean hasYResolution
*/
public boolean hasYResolution() {
return this.hasYResolution;
}
/**
* @return the resolutionUnit
*/
public int getResolutionUnit() {
return resolutionUnit;
}
public long getXResolution() {
return xResolution;
}
/**
* @return the yResolution
*/
public Rational getYResolution() {
return yResolution;
}
/**
* @return the orientation
*/
public int getOrientation() {
return this.orientation;
}
/**
* @return the image color indicator tag value
*/
public int getImageColorIndicator() {
return this.imageColorIndicator;
}
/**
* @return the background color indicator tag value
*/
public int getBackgroundColorIndicator() {
return this.backgroundColorIndicator;
}
/**
* @return the imageLength
*/
public long getImageLength() {
return imageLength;
}
/**
* @return the imageWidth
*/
public long getImageWidth() {
return imageWidth;
}
/**
* @return the indexed tag value
*/
public int getIndexed() {
return indexed;
}
/**
* @return the fillOrder
*/
public int getFillOrder() {
return this.fillOrder;
}
public boolean hasRowsPerStrip() {
return this.hasRowsPerStrip;
}
}