You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4267 lines
72 KiB
4267 lines
72 KiB
/*****************************************************************************/ |
|
// Copyright 2006-2012 Adobe Systems Incorporated |
|
// All Rights Reserved. |
|
// |
|
// NOTICE: Adobe permits you to use, modify, and distribute this file in |
|
// accordance with the terms of the Adobe license agreement accompanying it. |
|
/*****************************************************************************/ |
|
|
|
/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_ifd.cpp#3 $ */ |
|
/* $DateTime: 2012/06/05 11:05:39 $ */ |
|
/* $Change: 833352 $ */ |
|
/* $Author: tknoll $ */ |
|
|
|
/*****************************************************************************/ |
|
|
|
#include "dng_ifd.h" |
|
|
|
#include "dng_exceptions.h" |
|
#include "dng_flags.h" |
|
#include "dng_globals.h" |
|
#include "dng_ifd.h" |
|
#include "dng_types.h" |
|
#include "dng_parse_utils.h" |
|
#include "dng_read_image.h" |
|
#include "dng_stream.h" |
|
#include "dng_tag_codes.h" |
|
#include "dng_tag_types.h" |
|
#include "dng_tag_values.h" |
|
#include "dng_utils.h" |
|
|
|
/*****************************************************************************/ |
|
|
|
dng_preview_info::dng_preview_info () |
|
|
|
: fIsPrimary (true) |
|
, fApplicationName () |
|
, fApplicationVersion () |
|
, fSettingsName () |
|
, fSettingsDigest () |
|
, fColorSpace (previewColorSpace_MaxEnum) |
|
, fDateTime () |
|
, fRawToPreviewGain (1.0) |
|
, fCacheVersion (0) |
|
|
|
{ |
|
|
|
} |
|
|
|
/*****************************************************************************/ |
|
|
|
dng_preview_info::~dng_preview_info () |
|
{ |
|
|
|
} |
|
|
|
/*****************************************************************************/ |
|
|
|
dng_ifd::dng_ifd () |
|
|
|
: fUsesNewSubFileType (false) |
|
, fNewSubFileType (0) |
|
|
|
, fImageWidth (0) |
|
, fImageLength (0) |
|
|
|
, fCompression (ccUncompressed) |
|
, fPredictor (cpNullPredictor) |
|
|
|
, fPhotometricInterpretation (0xFFFFFFFF) |
|
|
|
, fFillOrder (1) |
|
|
|
, fOrientation (0) |
|
, fOrientationType (0) |
|
, fOrientationOffset (kDNGStreamInvalidOffset) |
|
, fOrientationBigEndian (false) |
|
|
|
, fSamplesPerPixel (1) |
|
|
|
, fPlanarConfiguration (pcInterleaved) |
|
|
|
, fXResolution (0.0) |
|
, fYResolution (0.0) |
|
, fResolutionUnit (0) |
|
|
|
, fUsesStrips (false) |
|
, fUsesTiles (false) |
|
|
|
, fTileWidth (0) |
|
, fTileLength (0) |
|
|
|
, fTileOffsetsType (0) |
|
, fTileOffsetsCount (0) |
|
, fTileOffsetsOffset (0) |
|
|
|
, fTileByteCountsType (0) |
|
, fTileByteCountsCount (0) |
|
, fTileByteCountsOffset (0) |
|
|
|
, fSubIFDsCount (0) |
|
, fSubIFDsOffset (0) |
|
|
|
, fExtraSamplesCount (0) |
|
|
|
, fJPEGTablesCount (0) |
|
, fJPEGTablesOffset (0) |
|
|
|
, fJPEGInterchangeFormat (0) |
|
, fJPEGInterchangeFormatLength (0) |
|
|
|
, fYCbCrCoefficientR (0.0) |
|
, fYCbCrCoefficientG (0.0) |
|
, fYCbCrCoefficientB (0.0) |
|
|
|
, fYCbCrSubSampleH (0) |
|
, fYCbCrSubSampleV (0) |
|
|
|
, fYCbCrPositioning (0) |
|
|
|
, fCFARepeatPatternRows (0) |
|
, fCFARepeatPatternCols (0) |
|
|
|
, fCFALayout (1) |
|
|
|
, fLinearizationTableType (0) |
|
, fLinearizationTableCount (0) |
|
, fLinearizationTableOffset (0) |
|
|
|
, fBlackLevelRepeatRows (1) |
|
, fBlackLevelRepeatCols (1) |
|
|
|
, fBlackLevelDeltaHType (0) |
|
, fBlackLevelDeltaHCount (0) |
|
, fBlackLevelDeltaHOffset (0) |
|
|
|
, fBlackLevelDeltaVType (0) |
|
, fBlackLevelDeltaVCount (0) |
|
, fBlackLevelDeltaVOffset (0) |
|
|
|
, fDefaultScaleH (1, 1) |
|
, fDefaultScaleV (1, 1) |
|
|
|
, fBestQualityScale (1, 1) |
|
|
|
, fDefaultCropOriginH (0, 1) |
|
, fDefaultCropOriginV (0, 1) |
|
|
|
, fDefaultCropSizeH () |
|
, fDefaultCropSizeV () |
|
|
|
, fDefaultUserCropT (0, 1) |
|
, fDefaultUserCropL (0, 1) |
|
, fDefaultUserCropB (1, 1) |
|
, fDefaultUserCropR (1, 1) |
|
|
|
, fBayerGreenSplit (0) |
|
|
|
, fChromaBlurRadius () |
|
|
|
, fAntiAliasStrength (1, 1) |
|
|
|
, fActiveArea () |
|
|
|
, fMaskedAreaCount (0) |
|
|
|
, fRowInterleaveFactor (1) |
|
|
|
, fSubTileBlockRows (1) |
|
, fSubTileBlockCols (1) |
|
|
|
, fPreviewInfo () |
|
|
|
, fOpcodeList1Count (0) |
|
, fOpcodeList1Offset (0) |
|
|
|
, fOpcodeList2Count (0) |
|
, fOpcodeList2Offset (0) |
|
|
|
, fOpcodeList3Count (0) |
|
, fOpcodeList3Offset (0) |
|
|
|
, fLosslessJPEGBug16 (false) |
|
|
|
, fSampleBitShift (0) |
|
|
|
, fThisIFD (0) |
|
, fNextIFD (0) |
|
|
|
, fCompressionQuality (-1) |
|
|
|
, fPatchFirstJPEGByte (false) |
|
|
|
{ |
|
|
|
uint32 j; |
|
uint32 k; |
|
uint32 n; |
|
|
|
for (j = 0; j < kMaxSamplesPerPixel; j++) |
|
{ |
|
fBitsPerSample [j] = 0; |
|
} |
|
|
|
for (j = 0; j < kMaxTileInfo; j++) |
|
{ |
|
fTileOffset [j] = 0; |
|
fTileByteCount [j] = 0; |
|
} |
|
|
|
for (j = 0; j < kMaxSamplesPerPixel; j++) |
|
{ |
|
fExtraSamples [j] = esUnspecified; |
|
} |
|
|
|
for (j = 0; j < kMaxSamplesPerPixel; j++) |
|
{ |
|
fSampleFormat [j] = sfUnsignedInteger; |
|
} |
|
|
|
for (j = 0; j < 6; j++) |
|
{ |
|
fReferenceBlackWhite [j] = 0.0; |
|
} |
|
|
|
for (j = 0; j < kMaxCFAPattern; j++) |
|
for (k = 0; k < kMaxCFAPattern; k++) |
|
{ |
|
fCFAPattern [j] [k] = 255; |
|
} |
|
|
|
for (j = 0; j < kMaxColorPlanes; j++) |
|
{ |
|
fCFAPlaneColor [j] = (uint8) (j < 3 ? j : 255); |
|
} |
|
|
|
for (j = 0; j < kMaxBlackPattern; j++) |
|
for (k = 0; k < kMaxBlackPattern; k++) |
|
for (n = 0; n < kMaxSamplesPerPixel; n++) |
|
{ |
|
fBlackLevel [j] [k] [n] = 0.0; |
|
} |
|
|
|
for (j = 0; j < kMaxSamplesPerPixel; j++) |
|
{ |
|
fWhiteLevel [j] = -1.0; // Don't know real default yet. |
|
} |
|
|
|
} |
|
|
|
/*****************************************************************************/ |
|
|
|
dng_ifd::~dng_ifd () |
|
{ |
|
|
|
} |
|
|
|
/*****************************************************************************/ |
|
|
|
// Parses tags that should only appear in IFDs that contain images. |
|
|
|
bool dng_ifd::ParseTag (dng_stream &stream, |
|
uint32 parentCode, |
|
uint32 tagCode, |
|
uint32 tagType, |
|
uint32 tagCount, |
|
uint64 tagOffset) |
|
{ |
|
|
|
uint32 j; |
|
uint32 k; |
|
uint32 n; |
|
|
|
switch (tagCode) |
|
{ |
|
|
|
case tcNewSubFileType: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttLong); |
|
|
|
CheckTagCount (parentCode, tagCode, tagCount, 1); |
|
|
|
fUsesNewSubFileType = true; |
|
|
|
fNewSubFileType = stream.TagValue_uint32 (tagType); |
|
|
|
fPreviewInfo.fIsPrimary = (fNewSubFileType == sfPreviewImage); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("NewSubFileType: %s\n", |
|
LookupNewSubFileType (fNewSubFileType)); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcImageWidth: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong); |
|
|
|
CheckTagCount (parentCode, tagCode, tagCount, 1); |
|
|
|
fImageWidth = stream.TagValue_uint32 (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
printf ("ImageWidth: %u\n", (unsigned) fImageWidth); |
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcImageLength: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong); |
|
|
|
CheckTagCount (parentCode, tagCode, tagCount, 1); |
|
|
|
fImageLength = stream.TagValue_uint32 (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
printf ("ImageLength: %u\n", (unsigned) fImageLength); |
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcBitsPerSample: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort); |
|
|
|
CheckTagCount (parentCode, tagCode, tagCount, 1, 0x0FFFF); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
printf ("BitsPerSample:"); |
|
} |
|
|
|
#endif |
|
|
|
bool extrasMatch = true; |
|
|
|
for (j = 0; j < tagCount; j++) |
|
{ |
|
|
|
uint32 x = stream.TagValue_uint32 (tagType); |
|
|
|
const uint32 maxBitsPerSample = 32; |
|
|
|
if (j < kMaxSamplesPerPixel) |
|
{ |
|
|
|
if (x > maxBitsPerSample) |
|
{ |
|
ThrowBadFormat ("BitsPerSample out of bounds."); |
|
} |
|
|
|
fBitsPerSample [j] = x; |
|
} |
|
|
|
else if (x != fBitsPerSample [kMaxSamplesPerPixel - 1]) |
|
{ |
|
extrasMatch = false; |
|
} |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
printf (" %u", (unsigned) x); |
|
} |
|
|
|
#endif |
|
|
|
} |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
printf ("\n"); |
|
} |
|
|
|
#endif |
|
|
|
if (!extrasMatch) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("BitsPerSample not constant"); |
|
|
|
#endif |
|
|
|
ThrowBadFormat (); |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcCompression: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort); |
|
|
|
CheckTagCount (parentCode, tagCode, tagCount, 1); |
|
|
|
fCompression = stream.TagValue_uint32 (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("Compression: %s\n", |
|
LookupCompression (fCompression)); |
|
|
|
} |
|
|
|
#endif |
|
|
|
// Correct a common TIFF writer mistake. |
|
|
|
if (fCompression == 0) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
{ |
|
|
|
char message [256]; |
|
|
|
sprintf (message, |
|
"%s has invalid zero compression code", |
|
LookupParentCode (parentCode)); |
|
|
|
ReportWarning (message); |
|
|
|
} |
|
|
|
#endif |
|
|
|
fCompression = ccUncompressed; |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcPhotometricInterpretation: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort); |
|
|
|
CheckTagCount (parentCode, tagCode, tagCount, 1); |
|
|
|
fPhotometricInterpretation = stream.TagValue_uint32 (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("PhotometricInterpretation: %s\n", |
|
LookupPhotometricInterpretation (fPhotometricInterpretation)); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcFillOrder: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort); |
|
|
|
CheckTagCount (parentCode, tagCode, tagCount, 1); |
|
|
|
fFillOrder = stream.TagValue_uint32 (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
printf ("FillOrder: %u\n", (unsigned) fFillOrder); |
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcStripOffsets: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong); |
|
|
|
fUsesStrips = true; |
|
|
|
fTileOffsetsType = tagType; |
|
fTileOffsetsCount = tagCount; |
|
fTileOffsetsOffset = tagOffset; |
|
|
|
if (tagCount <= kMaxTileInfo) |
|
{ |
|
|
|
for (j = 0; j < tagCount; j++) |
|
{ |
|
|
|
fTileOffset [j] = stream.TagValue_uint32 (tagType); |
|
|
|
} |
|
|
|
} |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
stream.SetReadPosition (tagOffset); |
|
|
|
DumpTagValues (stream, |
|
"Offset", |
|
parentCode, |
|
tagCode, |
|
tagType, |
|
tagCount); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcOrientation: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort); |
|
|
|
CheckTagCount (parentCode, tagCode, tagCount, 1); |
|
|
|
fOrientationType = tagType; |
|
fOrientationOffset = stream.PositionInOriginalFile (); |
|
fOrientationBigEndian = stream.BigEndian (); |
|
|
|
fOrientation = stream.TagValue_uint32 (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("Orientation: %s\n", |
|
LookupOrientation (fOrientation)); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcSamplesPerPixel: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort); |
|
|
|
CheckTagCount (parentCode, tagCode, tagCount, 1); |
|
|
|
fSamplesPerPixel = stream.TagValue_uint32 (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
printf ("SamplesPerPixel: %u\n", (unsigned) fSamplesPerPixel); |
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcRowsPerStrip: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong); |
|
|
|
CheckTagCount (parentCode, tagCode, tagCount, 1); |
|
|
|
fUsesStrips = true; |
|
|
|
fTileLength = stream.TagValue_uint32 (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
printf ("RowsPerStrip: %u\n", (unsigned) fTileLength); |
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcStripByteCounts: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong); |
|
|
|
fUsesStrips = true; |
|
|
|
fTileByteCountsType = tagType; |
|
fTileByteCountsCount = tagCount; |
|
fTileByteCountsOffset = tagOffset; |
|
|
|
if (tagCount <= kMaxTileInfo) |
|
{ |
|
|
|
for (j = 0; j < tagCount; j++) |
|
{ |
|
|
|
fTileByteCount [j] = stream.TagValue_uint32 (tagType); |
|
|
|
} |
|
|
|
} |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
stream.SetReadPosition (tagOffset); |
|
|
|
DumpTagValues (stream, |
|
"Count", |
|
parentCode, |
|
tagCode, |
|
tagType, |
|
tagCount); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcXResolution: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttRational); |
|
|
|
CheckTagCount (parentCode, tagCode, tagCount, 1); |
|
|
|
fXResolution = stream.TagValue_real64 (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
printf ("XResolution: %0.2f\n", fXResolution); |
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcYResolution: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttRational); |
|
|
|
CheckTagCount (parentCode, tagCode, tagCount, 1); |
|
|
|
fYResolution = stream.TagValue_real64 (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
printf ("YResolution: %0.2f\n", fYResolution); |
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcPlanarConfiguration: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort); |
|
|
|
CheckTagCount (parentCode, tagCode, tagCount, 1); |
|
|
|
fPlanarConfiguration = stream.TagValue_uint32 (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
printf ("PlanarConfiguration: %u\n", (unsigned) fPlanarConfiguration); |
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcResolutionUnit: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort); |
|
|
|
CheckTagCount (parentCode, tagCode, tagCount, 1); |
|
|
|
fResolutionUnit = stream.TagValue_uint32 (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("ResolutionUnit: %s\n", |
|
LookupResolutionUnit (fResolutionUnit)); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcPredictor: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort); |
|
|
|
CheckTagCount (parentCode, tagCode, tagCount, 1); |
|
|
|
fPredictor = stream.TagValue_uint32 (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("Predictor: %s\n", |
|
LookupPredictor (fPredictor)); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcTileWidth: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong); |
|
|
|
CheckTagCount (parentCode, tagCode, tagCount, 1); |
|
|
|
fUsesTiles = true; |
|
|
|
fTileWidth = stream.TagValue_uint32 (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
printf ("TileWidth: %u\n", (unsigned) fTileWidth); |
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcTileLength: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong); |
|
|
|
CheckTagCount (parentCode, tagCode, tagCount, 1); |
|
|
|
fUsesTiles = true; |
|
|
|
fTileLength = stream.TagValue_uint32 (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
printf ("TileLength: %u\n", (unsigned) fTileLength); |
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcTileOffsets: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttLong); |
|
|
|
fUsesTiles = true; |
|
|
|
fTileOffsetsType = tagType; |
|
fTileOffsetsCount = tagCount; |
|
fTileOffsetsOffset = tagOffset; |
|
|
|
if (tagCount <= kMaxTileInfo) |
|
{ |
|
|
|
for (j = 0; j < tagCount; j++) |
|
{ |
|
|
|
fTileOffset [j] = stream.TagValue_uint32 (tagType); |
|
|
|
} |
|
|
|
} |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
stream.SetReadPosition (tagOffset); |
|
|
|
DumpTagValues (stream, |
|
"Offset", |
|
parentCode, |
|
tagCode, |
|
tagType, |
|
tagCount); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcTileByteCounts: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong); |
|
|
|
fUsesTiles = true; |
|
|
|
fTileByteCountsType = tagType; |
|
fTileByteCountsCount = tagCount; |
|
fTileByteCountsOffset = tagOffset; |
|
|
|
if (tagCount <= kMaxTileInfo) |
|
{ |
|
|
|
for (j = 0; j < tagCount; j++) |
|
{ |
|
|
|
fTileByteCount [j] = stream.TagValue_uint32 (tagType); |
|
|
|
} |
|
|
|
} |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
stream.SetReadPosition (tagOffset); |
|
|
|
DumpTagValues (stream, |
|
"Count", |
|
parentCode, |
|
tagCode, |
|
tagType, |
|
tagCount); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcSubIFDs: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD); |
|
|
|
fSubIFDsCount = tagCount; |
|
fSubIFDsOffset = tagOffset; |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
DumpTagValues (stream, |
|
"IFD", |
|
parentCode, |
|
tagCode, |
|
ttLong, |
|
tagCount); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcExtraSamples: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort); |
|
|
|
CheckTagCount (parentCode, tagCode, tagCount, 1, fSamplesPerPixel); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
printf ("ExtraSamples:"); |
|
} |
|
|
|
#endif |
|
|
|
fExtraSamplesCount = tagCount; |
|
|
|
for (j = 0; j < tagCount; j++) |
|
{ |
|
|
|
uint32 x = stream.TagValue_uint32 (tagType); |
|
|
|
if (j < kMaxSamplesPerPixel) |
|
{ |
|
fExtraSamples [j] = x; |
|
} |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
printf (" %u", (unsigned) x); |
|
} |
|
|
|
#endif |
|
|
|
} |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
printf ("\n"); |
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcSampleFormat: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort); |
|
|
|
CheckTagCount (parentCode, tagCode, tagCount, fSamplesPerPixel); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
printf ("SampleFormat:"); |
|
} |
|
|
|
#endif |
|
|
|
bool extrasMatch = true; |
|
|
|
for (j = 0; j < tagCount; j++) |
|
{ |
|
|
|
uint32 x = stream.TagValue_uint32 (tagType); |
|
|
|
if (j < kMaxSamplesPerPixel) |
|
{ |
|
fSampleFormat [j] = x; |
|
} |
|
|
|
else if (x != fSampleFormat [kMaxSamplesPerPixel - 1]) |
|
{ |
|
extrasMatch = false; |
|
} |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
printf (" %s", LookupSampleFormat (x)); |
|
} |
|
|
|
#endif |
|
|
|
} |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
printf ("\n"); |
|
} |
|
|
|
#endif |
|
|
|
if (!extrasMatch) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("SampleFormat not constant"); |
|
|
|
#endif |
|
|
|
ThrowBadFormat (); |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcJPEGTables: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttUndefined); |
|
|
|
fJPEGTablesCount = tagCount; |
|
fJPEGTablesOffset = tagOffset; |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("JPEGTables: count = %u, offset = %u\n", |
|
(unsigned) fJPEGTablesCount, |
|
(unsigned) fJPEGTablesOffset); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcJPEGInterchangeFormat: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttLong); |
|
|
|
CheckTagCount (parentCode, tagCode, tagCount, 1); |
|
|
|
fJPEGInterchangeFormat = stream.TagValue_uint32 (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
printf ("JPEGInterchangeFormat: %u\n", |
|
(unsigned) fJPEGInterchangeFormat); |
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcJPEGInterchangeFormatLength: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttLong); |
|
|
|
CheckTagCount (parentCode, tagCode, tagCount, 1); |
|
|
|
fJPEGInterchangeFormatLength = stream.TagValue_uint32 (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
printf ("JPEGInterchangeFormatLength: %u\n", |
|
(unsigned) fJPEGInterchangeFormatLength); |
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcYCbCrCoefficients: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttRational); |
|
|
|
if (!CheckTagCount (parentCode, tagCode, tagCount, 3)) |
|
{ |
|
return false; |
|
} |
|
|
|
fYCbCrCoefficientR = stream.TagValue_real64 (tagType); |
|
fYCbCrCoefficientG = stream.TagValue_real64 (tagType); |
|
fYCbCrCoefficientB = stream.TagValue_real64 (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("YCbCrCoefficients: R = %0.3f, G = %0.3f, B = %0.3f\n", |
|
fYCbCrCoefficientR, |
|
fYCbCrCoefficientG, |
|
fYCbCrCoefficientB); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcYCbCrSubSampling: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort); |
|
|
|
if (!CheckTagCount (parentCode, tagCode, tagCount, 2)) |
|
{ |
|
return false; |
|
} |
|
|
|
fYCbCrSubSampleH = stream.TagValue_uint32 (tagType); |
|
fYCbCrSubSampleV = stream.TagValue_uint32 (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("YCbCrSubSampling: H = %u, V = %u\n", |
|
(unsigned) fYCbCrSubSampleH, |
|
(unsigned) fYCbCrSubSampleV); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcYCbCrPositioning: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort); |
|
|
|
CheckTagCount (parentCode, tagCode, tagCount, 1); |
|
|
|
fYCbCrPositioning = stream.TagValue_uint32 (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("YCbCrPositioning: %u\n", |
|
(unsigned) fYCbCrPositioning); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcReferenceBlackWhite: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttRational); |
|
|
|
if (!CheckTagCount (parentCode, tagCode, tagCount, 6)) |
|
{ |
|
return false; |
|
} |
|
|
|
for (j = 0; j < 6; j++) |
|
{ |
|
fReferenceBlackWhite [j] = stream.TagValue_real64 (tagType); |
|
} |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("ReferenceBlackWhite: %0.1f %0.1f %0.1f %0.1f %0.1f %0.1f\n", |
|
fReferenceBlackWhite [0], |
|
fReferenceBlackWhite [1], |
|
fReferenceBlackWhite [2], |
|
fReferenceBlackWhite [3], |
|
fReferenceBlackWhite [4], |
|
fReferenceBlackWhite [5]); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcCFARepeatPatternDim: |
|
{ |
|
|
|
CheckCFA (parentCode, tagCode, fPhotometricInterpretation); |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort); |
|
|
|
if (!CheckTagCount (parentCode, tagCode, tagCount, 2)) |
|
{ |
|
return false; |
|
} |
|
|
|
fCFARepeatPatternRows = stream.TagValue_uint32 (tagType); |
|
fCFARepeatPatternCols = stream.TagValue_uint32 (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("CFARepeatPatternDim: Rows = %u, Cols = %u\n", |
|
(unsigned) fCFARepeatPatternRows, |
|
(unsigned) fCFARepeatPatternCols); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcCFAPattern: |
|
{ |
|
|
|
CheckCFA (parentCode, tagCode, fPhotometricInterpretation); |
|
|
|
if (!CheckTagType (parentCode, tagCode, tagType, ttByte)) |
|
{ |
|
return false; |
|
} |
|
|
|
if (!CheckTagCount (parentCode, tagCode, tagCount, |
|
SafeUint32Mult(fCFARepeatPatternRows, fCFARepeatPatternCols))) |
|
{ |
|
return false; |
|
} |
|
|
|
if (fCFARepeatPatternRows < 1 || fCFARepeatPatternRows > kMaxCFAPattern || |
|
fCFARepeatPatternCols < 1 || fCFARepeatPatternCols > kMaxCFAPattern) |
|
{ |
|
return false; |
|
} |
|
|
|
// Note that the Exif spec stores this array in a different |
|
// scan order than the TIFF-EP spec. |
|
|
|
for (j = 0; j < fCFARepeatPatternRows; j++) |
|
for (k = 0; k < fCFARepeatPatternCols; k++) |
|
{ |
|
|
|
fCFAPattern [j] [k] = stream.Get_uint8 (); |
|
|
|
} |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("CFAPattern:\n"); |
|
|
|
for (j = 0; j < fCFARepeatPatternRows; j++) |
|
{ |
|
|
|
int32 spaces = 4; |
|
|
|
for (k = 0; k < fCFARepeatPatternCols; k++) |
|
{ |
|
|
|
while (spaces-- > 0) |
|
{ |
|
printf (" "); |
|
} |
|
|
|
const char *name = LookupCFAColor (fCFAPattern [j] [k]); |
|
|
|
spaces = 9 - (int32) strlen (name); |
|
|
|
printf ("%s", name); |
|
|
|
} |
|
|
|
printf ("\n"); |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcCFAPlaneColor: |
|
{ |
|
|
|
CheckCFA (parentCode, tagCode, fPhotometricInterpretation); |
|
|
|
if (!CheckTagType (parentCode, tagCode, tagType, ttByte)) |
|
{ |
|
return false; |
|
} |
|
|
|
if (!CheckTagCount (parentCode, tagCode, tagCount, 3, kMaxColorPlanes)) |
|
{ |
|
return false; |
|
} |
|
|
|
for (j = 0; j < kMaxColorPlanes; j++) |
|
{ |
|
|
|
if (j < tagCount) |
|
fCFAPlaneColor [j] = stream.Get_uint8 (); |
|
|
|
else |
|
fCFAPlaneColor [j] = 255; |
|
|
|
} |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("CFAPlaneColor:"); |
|
|
|
for (j = 0; j < tagCount; j++) |
|
{ |
|
|
|
printf (" %s", LookupCFAColor (fCFAPlaneColor [j])); |
|
|
|
} |
|
|
|
printf ("\n"); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcCFALayout: |
|
{ |
|
|
|
CheckCFA (parentCode, tagCode, fPhotometricInterpretation); |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort); |
|
|
|
CheckTagCount (parentCode, tagCode, tagCount, 1); |
|
|
|
fCFALayout = stream.TagValue_uint32 (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("CFALayout: %s\n", |
|
LookupCFALayout (fCFALayout)); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcLinearizationTable: |
|
{ |
|
|
|
CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation); |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort); |
|
|
|
fLinearizationTableType = tagType; |
|
fLinearizationTableCount = tagCount; |
|
fLinearizationTableOffset = tagOffset; |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
DumpTagValues (stream, |
|
"Table", |
|
parentCode, |
|
tagCode, |
|
tagType, |
|
tagCount); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcBlackLevelRepeatDim: |
|
{ |
|
|
|
CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation); |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort); |
|
|
|
if (!CheckTagCount (parentCode, tagCode, tagCount, 2)) |
|
{ |
|
return false; |
|
} |
|
|
|
fBlackLevelRepeatRows = stream.TagValue_uint32 (tagType); |
|
fBlackLevelRepeatCols = stream.TagValue_uint32 (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("BlackLevelRepeatDim: Rows = %u, Cols = %u\n", |
|
(unsigned) fBlackLevelRepeatRows, |
|
(unsigned) fBlackLevelRepeatCols); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcBlackLevel: |
|
{ |
|
|
|
CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation); |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong, ttRational); |
|
|
|
if (!CheckTagCount (parentCode, tagCode, tagCount, SafeUint32Mult(fBlackLevelRepeatRows, |
|
fBlackLevelRepeatCols, |
|
fSamplesPerPixel))) |
|
{ |
|
return false; |
|
} |
|
|
|
if (fBlackLevelRepeatRows < 1 || fBlackLevelRepeatRows > kMaxBlackPattern || |
|
fBlackLevelRepeatCols < 1 || fBlackLevelRepeatCols > kMaxBlackPattern || |
|
fSamplesPerPixel < 1 || fSamplesPerPixel > kMaxSamplesPerPixel) |
|
{ |
|
return false; |
|
} |
|
|
|
for (j = 0; j < fBlackLevelRepeatRows; j++) |
|
for (k = 0; k < fBlackLevelRepeatCols; k++) |
|
for (n = 0; n < fSamplesPerPixel; n++) |
|
{ |
|
|
|
fBlackLevel [j] [k] [n] = stream.TagValue_real64 (tagType); |
|
|
|
} |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("BlackLevel:"); |
|
|
|
if (fBlackLevelRepeatRows == 1 && |
|
fBlackLevelRepeatCols == 1) |
|
{ |
|
|
|
for (n = 0; n < fSamplesPerPixel; n++) |
|
{ |
|
printf (" %0.2f", fBlackLevel [0] [0] [n]); |
|
} |
|
|
|
printf ("\n"); |
|
|
|
} |
|
|
|
else |
|
{ |
|
|
|
printf ("\n"); |
|
|
|
for (n = 0; n < fSamplesPerPixel; n++) |
|
{ |
|
|
|
if (fSamplesPerPixel > 1) |
|
{ |
|
printf (" Sample: %u\n", (unsigned) n); |
|
} |
|
|
|
for (j = 0; j < fBlackLevelRepeatRows; j++) |
|
{ |
|
|
|
printf (" "); |
|
|
|
for (k = 0; k < fBlackLevelRepeatCols; k++) |
|
{ |
|
|
|
printf (" %8.2f", fBlackLevel [j] [k] [n]); |
|
|
|
} |
|
|
|
printf ("\n"); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcBlackLevelDeltaH: |
|
{ |
|
|
|
CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation); |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttSRational); |
|
|
|
fBlackLevelDeltaHType = tagType; |
|
fBlackLevelDeltaHCount = tagCount; |
|
fBlackLevelDeltaHOffset = tagOffset; |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
DumpTagValues (stream, |
|
"Delta", |
|
parentCode, |
|
tagCode, |
|
tagType, |
|
tagCount); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcBlackLevelDeltaV: |
|
{ |
|
|
|
CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation); |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttSRational); |
|
|
|
fBlackLevelDeltaVType = tagType; |
|
fBlackLevelDeltaVCount = tagCount; |
|
fBlackLevelDeltaVOffset = tagOffset; |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
DumpTagValues (stream, |
|
"Delta", |
|
parentCode, |
|
tagCode, |
|
tagType, |
|
tagCount); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcWhiteLevel: |
|
{ |
|
|
|
CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation); |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong); |
|
|
|
if (!CheckTagCount (parentCode, tagCode, tagCount, fSamplesPerPixel)) |
|
return false; |
|
|
|
for (j = 0; j < tagCount && j < kMaxSamplesPerPixel; j++) |
|
{ |
|
|
|
fWhiteLevel [j] = stream.TagValue_real64 (tagType); |
|
|
|
} |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("WhiteLevel:"); |
|
|
|
for (j = 0; j < tagCount && j < kMaxSamplesPerPixel; j++) |
|
{ |
|
|
|
printf (" %0.0f", fWhiteLevel [j]); |
|
|
|
} |
|
|
|
printf ("\n"); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcDefaultScale: |
|
{ |
|
|
|
CheckMainIFD (parentCode, tagCode, fNewSubFileType); |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttRational); |
|
|
|
if (!CheckTagCount (parentCode, tagCode, tagCount, 2)) |
|
return false; |
|
|
|
fDefaultScaleH = stream.TagValue_urational (tagType); |
|
fDefaultScaleV = stream.TagValue_urational (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("DefaultScale: H = %0.4f V = %0.4f\n", |
|
fDefaultScaleH.As_real64 (), |
|
fDefaultScaleV.As_real64 ()); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcDefaultCropOrigin: |
|
{ |
|
|
|
CheckMainIFD (parentCode, tagCode, fNewSubFileType); |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong, ttRational); |
|
|
|
if (!CheckTagCount (parentCode, tagCode, tagCount, 2)) |
|
return false; |
|
|
|
fDefaultCropOriginH = stream.TagValue_urational (tagType); |
|
fDefaultCropOriginV = stream.TagValue_urational (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("DefaultCropOrigin: H = %0.2f V = %0.2f\n", |
|
fDefaultCropOriginH.As_real64 (), |
|
fDefaultCropOriginV.As_real64 ()); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcDefaultCropSize: |
|
{ |
|
|
|
CheckMainIFD (parentCode, tagCode, fNewSubFileType); |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong, ttRational); |
|
|
|
if (!CheckTagCount (parentCode, tagCode, tagCount, 2)) |
|
return false; |
|
|
|
fDefaultCropSizeH = stream.TagValue_urational (tagType); |
|
fDefaultCropSizeV = stream.TagValue_urational (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("DefaultCropSize: H = %0.2f V = %0.2f\n", |
|
fDefaultCropSizeH.As_real64 (), |
|
fDefaultCropSizeV.As_real64 ()); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcDefaultUserCrop: |
|
{ |
|
|
|
CheckMainIFD (parentCode, tagCode, fNewSubFileType); |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttRational); |
|
|
|
if (!CheckTagCount (parentCode, tagCode, tagCount, 4)) |
|
return false; |
|
|
|
fDefaultUserCropT = stream.TagValue_urational (tagType); |
|
fDefaultUserCropL = stream.TagValue_urational (tagType); |
|
fDefaultUserCropB = stream.TagValue_urational (tagType); |
|
fDefaultUserCropR = stream.TagValue_urational (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("DefaultUserCrop: T = %0.2lf L = %0.2lf B = %0.2lf R = %0.2lf\n", |
|
(double) fDefaultUserCropT.As_real64 (), |
|
(double) fDefaultUserCropL.As_real64 (), |
|
(double) fDefaultUserCropB.As_real64 (), |
|
(double) fDefaultUserCropR.As_real64 ()); |
|
|
|
|
|
} |
|
|
|
#endif // qDNGValidate |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcBayerGreenSplit: |
|
{ |
|
|
|
CheckCFA (parentCode, tagCode, fPhotometricInterpretation); |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttLong); |
|
|
|
CheckTagCount (parentCode, tagCode, tagCount, 1); |
|
|
|
fBayerGreenSplit = stream.TagValue_uint32 (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
printf ("BayerGreenSplit: %u\n", (unsigned) fBayerGreenSplit); |
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcChromaBlurRadius: |
|
{ |
|
|
|
CheckMainIFD (parentCode, tagCode, fNewSubFileType); |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttRational); |
|
|
|
CheckTagCount (parentCode, tagCode, tagCount, 1); |
|
|
|
fChromaBlurRadius = stream.TagValue_urational (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("ChromaBlurRadius: %0.2f\n", |
|
fChromaBlurRadius.As_real64 ()); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcAntiAliasStrength: |
|
{ |
|
|
|
CheckMainIFD (parentCode, tagCode, fNewSubFileType); |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttRational); |
|
|
|
CheckTagCount (parentCode, tagCode, tagCount, 1); |
|
|
|
fAntiAliasStrength = stream.TagValue_urational (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("AntiAliasStrength: %0.2f\n", |
|
fAntiAliasStrength.As_real64 ()); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcBestQualityScale: |
|
{ |
|
|
|
CheckMainIFD (parentCode, tagCode, fNewSubFileType); |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttRational); |
|
|
|
CheckTagCount (parentCode, tagCode, tagCount, 1); |
|
|
|
fBestQualityScale = stream.TagValue_urational (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("BestQualityScale: %0.4f\n", |
|
fBestQualityScale.As_real64 ()); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcActiveArea: |
|
{ |
|
|
|
CheckMainIFD (parentCode, tagCode, fNewSubFileType); |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong); |
|
|
|
if (!CheckTagCount (parentCode, tagCode, tagCount, 4)) |
|
return false; |
|
|
|
fActiveArea.t = stream.TagValue_int32 (tagType); |
|
fActiveArea.l = stream.TagValue_int32 (tagType); |
|
fActiveArea.b = stream.TagValue_int32 (tagType); |
|
fActiveArea.r = stream.TagValue_int32 (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("ActiveArea: T = %d L = %d B = %d R = %d\n", |
|
(int) fActiveArea.t, |
|
(int) fActiveArea.l, |
|
(int) fActiveArea.b, |
|
(int) fActiveArea.r); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcMaskedAreas: |
|
{ |
|
|
|
CheckMainIFD (parentCode, tagCode, fNewSubFileType); |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong); |
|
|
|
uint32 rect_count = tagCount / 4; |
|
|
|
if (!CheckTagCount (parentCode, tagCode, tagCount, rect_count * 4)) |
|
return false; |
|
|
|
fMaskedAreaCount = rect_count; |
|
|
|
if (fMaskedAreaCount > kMaxMaskedAreas) |
|
fMaskedAreaCount = kMaxMaskedAreas; |
|
|
|
for (j = 0; j < fMaskedAreaCount; j++) |
|
{ |
|
|
|
fMaskedArea [j].t = stream.TagValue_int32 (tagType); |
|
fMaskedArea [j].l = stream.TagValue_int32 (tagType); |
|
fMaskedArea [j].b = stream.TagValue_int32 (tagType); |
|
fMaskedArea [j].r = stream.TagValue_int32 (tagType); |
|
|
|
} |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("MaskedAreas: %u\n", (unsigned) fMaskedAreaCount); |
|
|
|
for (j = 0; j < fMaskedAreaCount; j++) |
|
{ |
|
|
|
printf (" Area [%u]: T = %d L = %d B = %d R = %d\n", |
|
(unsigned) j, |
|
(int) fMaskedArea [j].t, |
|
(int) fMaskedArea [j].l, |
|
(int) fMaskedArea [j].b, |
|
(int) fMaskedArea [j].r); |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcPreviewApplicationName: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); |
|
|
|
ParseStringTag (stream, |
|
parentCode, |
|
tagCode, |
|
tagCount, |
|
fPreviewInfo.fApplicationName, |
|
false); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("PreviewApplicationName: "); |
|
|
|
DumpString (fPreviewInfo.fApplicationName); |
|
|
|
printf ("\n"); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcPreviewApplicationVersion: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); |
|
|
|
ParseStringTag (stream, |
|
parentCode, |
|
tagCode, |
|
tagCount, |
|
fPreviewInfo.fApplicationVersion, |
|
false); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("PreviewApplicationVersion: "); |
|
|
|
DumpString (fPreviewInfo.fApplicationVersion); |
|
|
|
printf ("\n"); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcPreviewSettingsName: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); |
|
|
|
ParseStringTag (stream, |
|
parentCode, |
|
tagCode, |
|
tagCount, |
|
fPreviewInfo.fSettingsName, |
|
false); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("PreviewSettingsName: "); |
|
|
|
DumpString (fPreviewInfo.fSettingsName); |
|
|
|
printf ("\n"); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcPreviewSettingsDigest: |
|
{ |
|
|
|
if (!CheckTagType (parentCode, tagCode, tagType, ttByte)) |
|
return false; |
|
|
|
if (!CheckTagCount (parentCode, tagCode, tagCount, 16)) |
|
return false; |
|
|
|
stream.Get (fPreviewInfo.fSettingsDigest.data, 16); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("PreviewSettingsDigest: "); |
|
|
|
DumpFingerprint (fPreviewInfo.fSettingsDigest); |
|
|
|
printf ("\n"); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcPreviewColorSpace: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttLong); |
|
|
|
CheckTagCount (parentCode, tagCode, tagCount, 1); |
|
|
|
fPreviewInfo.fColorSpace = (PreviewColorSpaceEnum) |
|
stream.TagValue_uint32 (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("PreviewColorSpace: %s\n", |
|
LookupPreviewColorSpace ((uint32) fPreviewInfo.fColorSpace)); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcPreviewDateTime: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttAscii); |
|
|
|
ParseStringTag (stream, |
|
parentCode, |
|
tagCode, |
|
tagCount, |
|
fPreviewInfo.fDateTime, |
|
false); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("PreviewDateTime: "); |
|
|
|
DumpString (fPreviewInfo.fDateTime); |
|
|
|
printf ("\n"); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcRowInterleaveFactor: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong); |
|
|
|
if (!CheckTagCount (parentCode, tagCode, tagCount, 1)) |
|
return false; |
|
|
|
fRowInterleaveFactor = stream.TagValue_uint32 (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("RowInterleaveFactor: %u\n", |
|
(unsigned) fRowInterleaveFactor); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcSubTileBlockSize: |
|
{ |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong); |
|
|
|
if (!CheckTagCount (parentCode, tagCode, tagCount, 2)) |
|
return false; |
|
|
|
fSubTileBlockRows = stream.TagValue_uint32 (tagType); |
|
fSubTileBlockCols = stream.TagValue_uint32 (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("SubTileBlockSize: rows = %u, cols = %u\n", |
|
(unsigned) fSubTileBlockRows, |
|
(unsigned) fSubTileBlockCols); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcOpcodeList1: |
|
{ |
|
|
|
CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation); |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttUndefined); |
|
|
|
fOpcodeList1Count = tagCount; |
|
fOpcodeList1Offset = tagOffset; |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("OpcodeList1: count = %u, offset = %u\n", |
|
(unsigned) fOpcodeList1Count, |
|
(unsigned) fOpcodeList1Offset); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcOpcodeList2: |
|
{ |
|
|
|
CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation); |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttUndefined); |
|
|
|
fOpcodeList2Count = tagCount; |
|
fOpcodeList2Offset = tagOffset; |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("OpcodeList2: count = %u, offset = %u\n", |
|
(unsigned) fOpcodeList2Count, |
|
(unsigned) fOpcodeList2Offset); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcOpcodeList3: |
|
{ |
|
|
|
CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation); |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttUndefined); |
|
|
|
fOpcodeList3Count = tagCount; |
|
fOpcodeList3Offset = tagOffset; |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("OpcodeList3: count = %u, offset = %u\n", |
|
(unsigned) fOpcodeList3Count, |
|
(unsigned) fOpcodeList3Offset); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcRawToPreviewGain: |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
if (fNewSubFileType != sfPreviewImage) |
|
{ |
|
|
|
char message [256]; |
|
|
|
sprintf (message, |
|
"%s %s is not allowed IFDs with NewSubFileType != PreviewImage", |
|
LookupParentCode (parentCode), |
|
LookupTagCode (parentCode, tagCode)); |
|
|
|
ReportWarning (message); |
|
|
|
} |
|
|
|
#endif |
|
|
|
CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation); |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttDouble); |
|
|
|
if (!CheckTagCount (parentCode, tagCode, tagCount, 1)) |
|
return false; |
|
|
|
fPreviewInfo.fRawToPreviewGain = stream.TagValue_real64 (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("RawToPreviewGain = %f\n", |
|
fPreviewInfo.fRawToPreviewGain); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
case tcCacheVersion: |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
if (fNewSubFileType != sfPreviewImage) |
|
{ |
|
|
|
char message [256]; |
|
|
|
sprintf (message, |
|
"%s %s is not allowed IFDs with NewSubFileType != PreviewImage", |
|
LookupParentCode (parentCode), |
|
LookupTagCode (parentCode, tagCode)); |
|
|
|
ReportWarning (message); |
|
|
|
} |
|
|
|
#endif |
|
|
|
CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation); |
|
|
|
CheckTagType (parentCode, tagCode, tagType, ttLong); |
|
|
|
if (!CheckTagCount (parentCode, tagCode, tagCount, 1)) |
|
return false; |
|
|
|
fPreviewInfo.fCacheVersion = stream.TagValue_uint32 (tagType); |
|
|
|
#if qDNGValidate |
|
|
|
if (gVerbose) |
|
{ |
|
|
|
printf ("CacheVersion = 0x%x\n", |
|
(unsigned) fPreviewInfo.fCacheVersion); |
|
|
|
} |
|
|
|
#endif |
|
|
|
break; |
|
|
|
} |
|
|
|
default: |
|
{ |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
return true; |
|
|
|
} |
|
|
|
/*****************************************************************************/ |
|
|
|
void dng_ifd::PostParse () |
|
{ |
|
|
|
uint32 j; |
|
uint32 k; |
|
|
|
// There is only one PlanarConfiguration for single sample imaages. |
|
|
|
if (fSamplesPerPixel == 1) |
|
{ |
|
fPlanarConfiguration = pcInterleaved; |
|
} |
|
|
|
// Default tile size. |
|
|
|
if (fTileWidth == 0) |
|
{ |
|
fTileWidth = fImageWidth; |
|
} |
|
|
|
if (fTileLength == 0) |
|
{ |
|
fTileLength = fImageLength; |
|
} |
|
|
|
// Default ActiveArea. |
|
|
|
dng_rect imageArea (0, 0, fImageLength, fImageWidth); |
|
|
|
if (fActiveArea.IsZero ()) |
|
{ |
|
fActiveArea = imageArea; |
|
} |
|
|
|
// Default crop size. |
|
|
|
if (fDefaultCropSizeH.d == 0) |
|
{ |
|
fDefaultCropSizeH = dng_urational (fActiveArea.W (), 1); |
|
} |
|
|
|
if (fDefaultCropSizeV.d == 0) |
|
{ |
|
fDefaultCropSizeV = dng_urational (fActiveArea.H (), 1); |
|
} |
|
|
|
// Default white level. |
|
|
|
uint32 defaultWhite = (fSampleFormat [0] == sfFloatingPoint) ? |
|
1 : |
|
(uint32) ((((uint64) 1) << fBitsPerSample [0]) - 1); |
|
|
|
for (j = 0; j < kMaxSamplesPerPixel; j++) |
|
{ |
|
|
|
if (fWhiteLevel [j] < 0.0) |
|
{ |
|
fWhiteLevel [j] = (real64) defaultWhite; |
|
} |
|
|
|
} |
|
|
|
// Check AntiAliasStrength. |
|
|
|
if (fAntiAliasStrength.As_real64 () < 0.0 || |
|
fAntiAliasStrength.As_real64 () > 1.0) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportWarning ("Invalid AntiAliasStrength"); |
|
|
|
#endif |
|
|
|
fAntiAliasStrength = dng_urational (1, 1); |
|
|
|
} |
|
|
|
// Check MaskedAreas. |
|
|
|
for (j = 0; j < fMaskedAreaCount; j++) |
|
{ |
|
|
|
const dng_rect &r = fMaskedArea [j]; |
|
|
|
if (r.IsEmpty () || ((r & imageArea) != r)) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportWarning ("Invalid MaskedArea"); |
|
|
|
#endif |
|
|
|
fMaskedAreaCount = 0; |
|
|
|
break; |
|
|
|
} |
|
|
|
if ((r & fActiveArea).NotEmpty ()) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportWarning ("MaskedArea overlaps ActiveArea"); |
|
|
|
#endif |
|
|
|
fMaskedAreaCount = 0; |
|
|
|
break; |
|
|
|
} |
|
|
|
for (k = 0; k < j; k++) |
|
{ |
|
|
|
if ((r & fMaskedArea [k]).NotEmpty ()) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportWarning ("MaskedAreas overlap each other"); |
|
|
|
#endif |
|
|
|
fMaskedAreaCount = 0; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
/*****************************************************************************/ |
|
|
|
bool dng_ifd::IsValidCFA (dng_shared &shared, |
|
uint32 parentCode) |
|
{ |
|
|
|
uint32 j; |
|
uint32 k; |
|
uint32 n; |
|
|
|
#if !qDNGValidate |
|
|
|
(void) parentCode; // Unused |
|
|
|
#endif |
|
|
|
if (fCFARepeatPatternRows < 1 || fCFARepeatPatternRows > kMaxCFAPattern || |
|
fCFARepeatPatternCols < 1 || fCFARepeatPatternCols > kMaxCFAPattern) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Missing or invalid CFAPatternRepeatDim", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
uint32 count [kMaxColorPlanes]; |
|
|
|
for (n = 0; n < shared.fCameraProfile.fColorPlanes; n++) |
|
{ |
|
count [n] = 0; |
|
} |
|
|
|
for (j = 0; j < fCFARepeatPatternRows; j++) |
|
{ |
|
|
|
for (k = 0; k < fCFARepeatPatternCols; k++) |
|
{ |
|
|
|
bool found = false; |
|
|
|
for (n = 0; n < shared.fCameraProfile.fColorPlanes; n++) |
|
{ |
|
|
|
if (fCFAPattern [j] [k] == fCFAPlaneColor [n]) |
|
{ |
|
found = true; |
|
count [n] ++; |
|
break; |
|
} |
|
|
|
} |
|
|
|
if (!found) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("CFAPattern contains colors not included in the CFAPlaneColor tag", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
for (n = 0; n < shared.fCameraProfile.fColorPlanes; n++) |
|
{ |
|
|
|
if (count [n] == 0) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("CFAPattern does not contain all the colors in the CFAPlaneColor tag", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
if (fCFALayout < 1 || fCFALayout > 9) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Invalid CFALayout", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
return true; |
|
|
|
} |
|
|
|
/*****************************************************************************/ |
|
|
|
bool dng_ifd::IsValidDNG (dng_shared &shared, |
|
uint32 parentCode) |
|
{ |
|
|
|
uint32 j; |
|
|
|
bool isFloatingPoint = (fSampleFormat [0] == sfFloatingPoint); |
|
|
|
dng_rect imageArea (0, 0, fImageLength, fImageWidth); |
|
|
|
uint32 defaultWhite = isFloatingPoint ? |
|
1 : |
|
(uint32) ((((uint64) 1) << fBitsPerSample [0]) - 1); |
|
|
|
bool isMonochrome = (shared.fCameraProfile.fColorPlanes == 1); |
|
bool isColor = !isMonochrome; |
|
|
|
bool isMainIFD = (fNewSubFileType == sfMainImage); |
|
|
|
// Check NewSubFileType. |
|
|
|
if (!fUsesNewSubFileType) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Missing NewSubFileType", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
if (fNewSubFileType != sfMainImage && |
|
fNewSubFileType != sfPreviewImage && |
|
fNewSubFileType != sfTransparencyMask && |
|
fNewSubFileType != sfPreviewMask && |
|
fNewSubFileType != sfAltPreviewImage) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Unexpected NewSubFileType", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
// Check ImageWidth and ImageLength. |
|
|
|
if (fImageWidth < 1) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Missing or invalid ImageWidth", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
if (fImageLength < 1) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Missing or invalid ImageLength", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
if (fImageWidth > kMaxImageSide || |
|
fImageLength > kMaxImageSide) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportWarning ("Image size is larger than supported"); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
// Check PhotometricInterpretation. |
|
|
|
if (fNewSubFileType == sfTransparencyMask || |
|
fNewSubFileType == sfPreviewMask) |
|
{ |
|
|
|
if (fPhotometricInterpretation != piTransparencyMask) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("NewSubFileType requires PhotometricInterpretation = TransparencyMask", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
{ |
|
|
|
switch (fPhotometricInterpretation) |
|
{ |
|
|
|
case piBlackIsZero: |
|
case piRGB: |
|
case piYCbCr: |
|
{ |
|
|
|
if (isMainIFD) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("PhotometricInterpretation requires NewSubFileType = 1", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
case piCFA: |
|
{ |
|
|
|
if (!isMainIFD) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("PhotometricInterpretation requires NewSubFileType = 0", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
case piLinearRaw: |
|
break; |
|
|
|
default: |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Missing or invalid PhotometricInterpretation", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
switch (fPhotometricInterpretation) |
|
{ |
|
|
|
case piBlackIsZero: |
|
{ |
|
|
|
// Allow black in white previews even in color images since the |
|
// raw processing software may be converting to grayscale. |
|
|
|
if (isColor && isMainIFD) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("PhotometricInterpretation forbids use of ColorMatrix1 tag", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
case piRGB: |
|
case piYCbCr: |
|
{ |
|
|
|
// Allow color previews even in monochrome DNG files, since the |
|
// raw procesing software may be adding color effects. |
|
|
|
break; |
|
|
|
} |
|
|
|
case piCFA: |
|
{ |
|
|
|
if (isMonochrome) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("PhotometricInterpretation requires use of ColorMatrix1 tag", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
if (isFloatingPoint) |
|
{ |
|
|
|
if (fPhotometricInterpretation != piCFA && |
|
fPhotometricInterpretation != piLinearRaw && |
|
fPhotometricInterpretation != piTransparencyMask) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Floating point data requires PhotometricInterpretation CFA or LinearRaw or TransparencyMask", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
// Check SamplesPerPixel and BitsPerSample. |
|
|
|
uint32 minSamplesPerPixel = 1; |
|
uint32 maxSamplesPerPixel = 1; |
|
|
|
uint32 minBitsPerSample = 8; |
|
uint32 maxBitsPerSample = 16; |
|
|
|
switch (fPhotometricInterpretation) |
|
{ |
|
|
|
case piBlackIsZero: |
|
break; |
|
|
|
case piRGB: |
|
case piYCbCr: |
|
{ |
|
minSamplesPerPixel = 3; |
|
maxSamplesPerPixel = 3; |
|
break; |
|
} |
|
|
|
case piCFA: |
|
{ |
|
maxSamplesPerPixel = kMaxSamplesPerPixel; |
|
maxBitsPerSample = 32; |
|
break; |
|
} |
|
|
|
case piLinearRaw: |
|
{ |
|
minSamplesPerPixel = shared.fCameraProfile.fColorPlanes; |
|
maxSamplesPerPixel = shared.fCameraProfile.fColorPlanes; |
|
maxBitsPerSample = 32; |
|
break; |
|
} |
|
|
|
case piTransparencyMask: |
|
{ |
|
minBitsPerSample = 8; |
|
maxBitsPerSample = 16; |
|
break; |
|
} |
|
|
|
} |
|
|
|
if (isFloatingPoint) |
|
{ |
|
minBitsPerSample = 16; |
|
maxBitsPerSample = 32; |
|
} |
|
|
|
if (fSamplesPerPixel < minSamplesPerPixel || |
|
fSamplesPerPixel > maxSamplesPerPixel) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Missing or invalid SamplesPerPixel", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
for (j = 0; j < kMaxSamplesPerPixel; j++) |
|
{ |
|
|
|
if (j < fSamplesPerPixel) |
|
{ |
|
|
|
if (fBitsPerSample [j] < minBitsPerSample || |
|
fBitsPerSample [j] > maxBitsPerSample) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Missing or invalid BitsPerSample", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
if (isFloatingPoint && |
|
fBitsPerSample [j] != 16 && |
|
fBitsPerSample [j] != 24 && |
|
fBitsPerSample [j] != 32) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Invalid BitsPerSample for floating point", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
if (minBitsPerSample == 8 && |
|
maxBitsPerSample == 16 && |
|
fBitsPerSample [j] != 8 && |
|
fBitsPerSample [j] != 16) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Rendered previews and integer masks require 8 or 16 bits per sample", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
if (j > 0 && fBitsPerSample [j] != fBitsPerSample [0]) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("BitsPerSample not equal for all samples", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
{ |
|
|
|
if (fBitsPerSample [j] != 0) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Too many values specified in BitsPerSample", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
// Check Compression. |
|
|
|
switch (fCompression) |
|
{ |
|
|
|
case ccUncompressed: |
|
break; |
|
|
|
case ccJPEG: |
|
{ |
|
|
|
if (fPhotometricInterpretation == piRGB) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("JPEG previews should use PhotometricInterpretation = YCbYb", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
if (fBitsPerSample [0] > 16) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("JPEG compression is limited to 16 bits/sample", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
case ccLossyJPEG: |
|
{ |
|
|
|
if (fPhotometricInterpretation != piLinearRaw) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Lossy JPEG compression code requires PhotometricInterpretation = LinearRaw", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
if (fBitsPerSample [0] != 8) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Lossy JPEG compression is limited to 8 bits/sample", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
case ccDeflate: |
|
{ |
|
|
|
if (!isFloatingPoint && |
|
fBitsPerSample [0] != 32 && |
|
fPhotometricInterpretation != piTransparencyMask) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("ZIP compression is limited to floating point and 32-bit integer and transparency masks", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
default: |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Unsupported Compression", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
// Check Predictor. |
|
|
|
if (isFloatingPoint && fCompression == ccDeflate && |
|
(fPredictor == cpFloatingPoint || |
|
fPredictor == cpFloatingPointX2 || |
|
fPredictor == cpFloatingPointX4)) |
|
{ |
|
|
|
// These combinations are supported. |
|
|
|
} |
|
|
|
else if (!isFloatingPoint && fCompression == ccDeflate && |
|
(fPredictor == cpHorizontalDifference || |
|
fPredictor == cpHorizontalDifferenceX2 || |
|
fPredictor == cpHorizontalDifferenceX4)) |
|
{ |
|
|
|
// These combinations are supported. |
|
|
|
} |
|
|
|
else if (fPredictor != cpNullPredictor) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Unsupported Predictor", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
// Check FillOrder. |
|
|
|
if (fFillOrder != 1) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Unsupported FillOrder", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
// Check PlanarConfiguration. |
|
|
|
if (fPlanarConfiguration != pcInterleaved) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Unsupported PlanarConfiguration", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
// Check ExtraSamples. |
|
|
|
if (fExtraSamplesCount != 0) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Unsupported ExtraSamples", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
// Check SampleFormat. |
|
|
|
for (j = 0; j < fSamplesPerPixel; j++) |
|
{ |
|
|
|
if (fSampleFormat [j] != (isFloatingPoint ? sfFloatingPoint : sfUnsignedInteger)) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Unsupported SampleFormat", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
// Check Orientation. |
|
|
|
if (fOrientation > 9) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Unknown Orientation", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
#if qDNGValidate |
|
|
|
if (fOrientation != 0 && parentCode != 0) |
|
{ |
|
|
|
ReportWarning ("Unexpected Orientation tag", |
|
LookupParentCode (parentCode)); |
|
|
|
} |
|
|
|
if (fOrientation == 0 && parentCode == 0) |
|
{ |
|
|
|
ReportWarning ("Missing Orientation tag", |
|
LookupParentCode (parentCode)); |
|
|
|
} |
|
|
|
#endif |
|
|
|
// Check Strips vs. Tiles. |
|
|
|
if (!fUsesStrips && !fUsesTiles) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("IFD uses neither strips nor tiles", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
if (fUsesStrips && fUsesTiles) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("IFD uses both strips and tiles", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
// Check tile info. |
|
|
|
uint32 tilesWide = SafeUint32DivideUp(fImageWidth, fTileWidth); |
|
uint32 tilesHigh = SafeUint32DivideUp(fImageLength, fTileLength); |
|
|
|
uint32 tileCount = tilesWide * tilesHigh; |
|
|
|
if (fTileOffsetsCount != tileCount) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Missing or invalid Strip/TileOffsets", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
if (fTileByteCountsCount != tileCount) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Missing or invalid Strip/TileByteCounts", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
// Check CFA pattern. |
|
|
|
if (fPhotometricInterpretation == piCFA) |
|
{ |
|
|
|
if (!IsValidCFA (shared, parentCode)) |
|
{ |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
// Check ActiveArea. |
|
|
|
if (((fActiveArea & imageArea) != fActiveArea) || fActiveArea.IsEmpty ()) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Invalid ActiveArea", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
if (fActiveArea != imageArea) |
|
{ |
|
|
|
if (shared.fDNGBackwardVersion < dngVersion_1_1_0_0) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Non-default ActiveArea tag not allowed in this DNG version", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
// Check LinearizationTable. |
|
|
|
if (fLinearizationTableCount) |
|
{ |
|
|
|
if (fLinearizationTableType != ttShort) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Invalidate LinearizationTable type", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
if (fLinearizationTableCount < 2 || |
|
fLinearizationTableCount > 65536) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Invalidate LinearizationTable count", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
if (isFloatingPoint || fBitsPerSample [0] > 16) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Linearization table not allowed for this data type", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
// Check BlackLevelRepeatDim. |
|
|
|
if (fBlackLevelRepeatRows < 1 || fBlackLevelRepeatRows > kMaxBlackPattern || |
|
fBlackLevelRepeatCols < 1 || fBlackLevelRepeatCols > kMaxBlackPattern) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Invalid BlackLevelRepeatDim", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
// Check BlackLevelDeltaH. |
|
|
|
if (fBlackLevelDeltaHCount != 0 && |
|
fBlackLevelDeltaHCount != fActiveArea.W ()) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Invalid BlackLevelDeltaH count", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
// Check BlackLevelDeltaV. |
|
|
|
if (fBlackLevelDeltaVCount != 0 && |
|
fBlackLevelDeltaVCount != fActiveArea.H ()) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Invalid BlackLevelDeltaV count", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
// Check WhiteLevel. |
|
|
|
real64 maxWhite = fLinearizationTableCount ? 65535.0 |
|
: (real64) defaultWhite; |
|
|
|
for (j = 0; j < fSamplesPerPixel; j++) |
|
{ |
|
|
|
if (fWhiteLevel [j] < 1.0 || (fWhiteLevel [j] > maxWhite && !isFloatingPoint)) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Invalid WhiteLevel", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
// Check BlackLevel. |
|
|
|
for (j = 0; j < kMaxBlackPattern; j++) |
|
{ |
|
|
|
for (uint32 k = 0; k < kMaxBlackPattern; k++) |
|
{ |
|
|
|
for (uint32 s = 0; s < kMaxSamplesPerPixel; s++) |
|
{ |
|
|
|
const real64 black = fBlackLevel [j][k][s]; |
|
|
|
if (black >= fWhiteLevel [s]) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Invalid BlackLevel", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
// Check DefaultScale. |
|
|
|
if (fDefaultScaleH.As_real64 () <= 0.0 || |
|
fDefaultScaleV.As_real64 () <= 0.0) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Invalid DefaultScale"); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
// Check BestQualityScale. |
|
|
|
if (fBestQualityScale.As_real64 () < 1.0) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Invalid BestQualityScale"); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
// Check DefaultCropOrigin. |
|
|
|
if (fDefaultCropOriginH.As_real64 () < 0.0 || |
|
fDefaultCropOriginV.As_real64 () < 0.0 || |
|
fDefaultCropOriginH.As_real64 () >= (real64) fActiveArea.W () || |
|
fDefaultCropOriginV.As_real64 () >= (real64) fActiveArea.H ()) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Invalid DefaultCropOrigin"); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
// Check DefaultCropSize. |
|
|
|
if (fDefaultCropSizeH.As_real64 () <= 0.0 || |
|
fDefaultCropSizeV.As_real64 () <= 0.0 || |
|
fDefaultCropSizeH.As_real64 () > (real64) fActiveArea.W () || |
|
fDefaultCropSizeV.As_real64 () > (real64) fActiveArea.H ()) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Invalid DefaultCropSize"); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
// Check DefaultCrop area. |
|
|
|
if (fDefaultCropOriginH.As_real64 () + |
|
fDefaultCropSizeH .As_real64 () > (real64) fActiveArea.W () || |
|
fDefaultCropOriginV.As_real64 () + |
|
fDefaultCropSizeV .As_real64 () > (real64) fActiveArea.H ()) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Default crop extends outside ActiveArea"); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
// Check DefaultUserCrop. |
|
|
|
if (fDefaultUserCropT.As_real64 () < 0.0 || |
|
fDefaultUserCropL.As_real64 () < 0.0 || |
|
fDefaultUserCropB.As_real64 () > 1.0 || |
|
fDefaultUserCropR.As_real64 () > 1.0 || |
|
fDefaultUserCropT.As_real64 () >= fDefaultUserCropB.As_real64 () || |
|
fDefaultUserCropL.As_real64 () >= fDefaultUserCropR.As_real64 ()) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Invalid DefaultUserCrop"); |
|
|
|
#endif // qDNGValidate |
|
|
|
return false; |
|
|
|
} |
|
|
|
// The default crop and default user crop tags are not allowed for the |
|
// non-main image. If they are there, at least require that they be NOPs. |
|
|
|
if (!isMainIFD) |
|
{ |
|
|
|
if (Round_int32 (fDefaultCropOriginH.As_real64 ()) != 0 || |
|
Round_int32 (fDefaultCropOriginV.As_real64 ()) != 0) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("non-default DefaultCropOrigin on non-main image"); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
if (Round_int32 (fDefaultCropSizeH.As_real64 ()) != (int32) fImageWidth || |
|
Round_int32 (fDefaultCropSizeV.As_real64 ()) != (int32) fImageLength) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("non-default DefaultCropSize on non-main image"); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
if (fDefaultUserCropT.As_real64 () != 0.0 || |
|
fDefaultUserCropL.As_real64 () != 0.0 || |
|
fDefaultUserCropB.As_real64 () != 1.0 || |
|
fDefaultUserCropR.As_real64 () != 1.0) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("non-default DefaultCUserCrop on non-main image"); |
|
|
|
#endif // qDNGValidate |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
// Warning if too little padding on CFA image. |
|
|
|
#if qDNGValidate |
|
|
|
if (fPhotometricInterpretation == piCFA) |
|
{ |
|
|
|
const real64 kMinPad = 1.9; |
|
|
|
if (fDefaultCropOriginH.As_real64 () < kMinPad) |
|
{ |
|
|
|
ReportWarning ("Too little padding on left edge of CFA image", |
|
"possible interpolation artifacts"); |
|
|
|
} |
|
|
|
if (fDefaultCropOriginV.As_real64 () < kMinPad) |
|
{ |
|
|
|
ReportWarning ("Too little padding on top edge of CFA image", |
|
"possible interpolation artifacts"); |
|
|
|
} |
|
|
|
if (fDefaultCropOriginH.As_real64 () + |
|
fDefaultCropSizeH .As_real64 () > (real64) fActiveArea.W () - kMinPad) |
|
{ |
|
|
|
ReportWarning ("Too little padding on right edge of CFA image", |
|
"possible interpolation artifacts"); |
|
|
|
} |
|
|
|
if (fDefaultCropOriginV.As_real64 () + |
|
fDefaultCropSizeV .As_real64 () > (real64) fActiveArea.H () - kMinPad) |
|
{ |
|
|
|
ReportWarning ("Too little padding on bottom edge of CFA image", |
|
"possible interpolation artifacts"); |
|
|
|
} |
|
|
|
} |
|
|
|
#endif |
|
|
|
// Check RowInterleaveFactor |
|
|
|
if (fRowInterleaveFactor != 1) |
|
{ |
|
|
|
if (fRowInterleaveFactor < 1 || |
|
fRowInterleaveFactor > fImageLength) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("RowInterleaveFactor out of valid range", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
if (shared.fDNGBackwardVersion < dngVersion_1_2_0_0) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Non-default RowInterleaveFactor tag not allowed in this DNG version", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
// Check SubTileBlockSize |
|
|
|
if (fSubTileBlockRows != 1 || fSubTileBlockCols != 1) |
|
{ |
|
|
|
if (fSubTileBlockRows < 2 || fSubTileBlockRows > fTileLength || |
|
fSubTileBlockCols < 1 || fSubTileBlockCols > fTileWidth) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("SubTileBlockSize out of valid range", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
if ((fTileLength % fSubTileBlockRows) != 0 || |
|
(fTileWidth % fSubTileBlockCols) != 0) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("TileSize not exact multiple of SubTileBlockSize", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
if (shared.fDNGBackwardVersion < dngVersion_1_2_0_0) |
|
{ |
|
|
|
#if qDNGValidate |
|
|
|
ReportError ("Non-default SubTileBlockSize tag not allowed in this DNG version", |
|
LookupParentCode (parentCode)); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
return true; |
|
|
|
} |
|
|
|
/*****************************************************************************/ |
|
|
|
uint32 dng_ifd::TilesAcross () const |
|
{ |
|
|
|
if (fTileWidth) |
|
{ |
|
|
|
return (SafeUint32Sub(SafeUint32Add(fImageWidth, fTileWidth), 1)) / fTileWidth; |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
/*****************************************************************************/ |
|
|
|
uint32 dng_ifd::TilesDown () const |
|
{ |
|
|
|
if (fTileLength) |
|
{ |
|
|
|
return (SafeUint32Sub(SafeUint32Add(fImageLength, fTileLength), 1)) / fTileLength; |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
/*****************************************************************************/ |
|
|
|
uint32 dng_ifd::TilesPerImage () const |
|
{ |
|
|
|
uint32 total = TilesAcross () * TilesDown (); |
|
|
|
if (fPlanarConfiguration == pcPlanar) |
|
{ |
|
|
|
total *= fSamplesPerPixel; |
|
|
|
} |
|
|
|
return total; |
|
|
|
} |
|
|
|
/*****************************************************************************/ |
|
|
|
dng_rect dng_ifd::TileArea (uint32 rowIndex, |
|
uint32 colIndex) const |
|
{ |
|
|
|
dng_rect r; |
|
|
|
r.t = rowIndex * fTileLength; |
|
r.b = r.t + fTileLength; |
|
|
|
r.l = colIndex * fTileWidth; |
|
r.r = r.l + fTileWidth; |
|
|
|
// If this IFD is using strips rather than tiles, the last strip |
|
// is trimmed so it does not extend beyond the end of the image. |
|
|
|
if (fUsesStrips) |
|
{ |
|
|
|
r.b = Min_uint32 (r.b, fImageLength); |
|
|
|
} |
|
|
|
return r; |
|
|
|
} |
|
|
|
/*****************************************************************************/ |
|
|
|
uint32 dng_ifd::TileByteCount (const dng_rect &tile) const |
|
{ |
|
|
|
if (fCompression == ccUncompressed) |
|
{ |
|
|
|
uint32 bitsPerRow = SafeUint32Mult(tile.W (), fBitsPerSample [0]); |
|
|
|
if (fPlanarConfiguration == pcInterleaved) |
|
{ |
|
|
|
bitsPerRow = SafeUint32Mult(bitsPerRow, fSamplesPerPixel); |
|
|
|
} |
|
|
|
uint32 bytesPerRow = SafeUint32DivideUp(bitsPerRow, 8); |
|
|
|
if (fPlanarConfiguration == pcRowInterleaved) |
|
{ |
|
|
|
bytesPerRow = SafeUint32Mult(bytesPerRow, fSamplesPerPixel); |
|
|
|
} |
|
|
|
return SafeUint32Mult(bytesPerRow, tile.H ()); |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
/*****************************************************************************/ |
|
|
|
void dng_ifd::SetSingleStrip () |
|
{ |
|
|
|
fTileWidth = fImageWidth; |
|
fTileLength = fImageLength; |
|
|
|
fUsesTiles = false; |
|
fUsesStrips = true; |
|
|
|
} |
|
|
|
/*****************************************************************************/ |
|
|
|
void dng_ifd::FindTileSize (uint32 bytesPerTile, |
|
uint32 cellH, |
|
uint32 cellV) |
|
{ |
|
|
|
uint32 bytesPerSample = fSamplesPerPixel * |
|
((fBitsPerSample [0] + 7) >> 3); |
|
|
|
uint32 samplesPerTile = bytesPerTile / bytesPerSample; |
|
|
|
uint32 tileSide = Round_uint32 (sqrt ((real64) samplesPerTile)); |
|
|
|
fTileWidth = Min_uint32 (fImageWidth, tileSide); |
|
|
|
uint32 across = TilesAcross (); |
|
|
|
fTileWidth = (fImageWidth + across - 1) / across; |
|
|
|
fTileWidth = ((fTileWidth + cellH - 1) / cellH) * cellH; |
|
|
|
fTileLength = Pin_uint32 (1, |
|
samplesPerTile / fTileWidth, |
|
fImageLength); |
|
|
|
uint32 down = TilesDown (); |
|
|
|
fTileLength = (fImageLength + down - 1) / down; |
|
|
|
fTileLength = ((fTileLength + cellV - 1) / cellV) * cellV; |
|
|
|
fUsesTiles = true; |
|
fUsesStrips = false; |
|
|
|
} |
|
|
|
/*****************************************************************************/ |
|
|
|
void dng_ifd::FindStripSize (uint32 bytesPerStrip, |
|
uint32 cellV) |
|
{ |
|
|
|
uint32 bytesPerSample = fSamplesPerPixel * |
|
((fBitsPerSample [0] + 7) >> 3); |
|
|
|
uint32 samplesPerStrip = bytesPerStrip / bytesPerSample; |
|
|
|
fTileWidth = fImageWidth; |
|
|
|
fTileLength = Pin_uint32 (1, |
|
samplesPerStrip / fTileWidth, |
|
fImageLength); |
|
|
|
uint32 down = TilesDown (); |
|
|
|
fTileLength = (fImageLength + down - 1) / down; |
|
|
|
fTileLength = ((fTileLength + cellV - 1) / cellV) * cellV; |
|
|
|
fUsesTiles = false; |
|
fUsesStrips = true; |
|
|
|
} |
|
|
|
/*****************************************************************************/ |
|
|
|
uint32 dng_ifd::PixelType () const |
|
{ |
|
|
|
if (fSampleFormat [0] == sfFloatingPoint) |
|
{ |
|
return ttFloat; |
|
} |
|
|
|
if (fBitsPerSample [0] <= 8) |
|
{ |
|
return ttByte; |
|
} |
|
|
|
else if (fBitsPerSample [0] <= 16) |
|
{ |
|
return ttShort; |
|
} |
|
|
|
return ttLong; |
|
|
|
} |
|
|
|
/*****************************************************************************/ |
|
|
|
bool dng_ifd::IsBaselineJPEG () const |
|
{ |
|
|
|
if (fBitsPerSample [0] != 8) |
|
{ |
|
return false; |
|
} |
|
|
|
if (fSampleFormat [0] != sfUnsignedInteger) |
|
{ |
|
return false; |
|
} |
|
|
|
if (fCompression == ccLossyJPEG) |
|
{ |
|
return true; |
|
} |
|
|
|
if (fCompression != ccJPEG) |
|
{ |
|
return false; |
|
} |
|
|
|
switch (fPhotometricInterpretation) |
|
{ |
|
|
|
case piBlackIsZero: |
|
{ |
|
return (fSamplesPerPixel == 1); |
|
} |
|
|
|
case piYCbCr: |
|
{ |
|
return (fSamplesPerPixel == 3 ) && |
|
(fPlanarConfiguration == pcInterleaved); |
|
} |
|
|
|
default: |
|
break; |
|
|
|
} |
|
|
|
return false; |
|
|
|
} |
|
|
|
/*****************************************************************************/ |
|
|
|
bool dng_ifd::CanRead () const |
|
{ |
|
|
|
dng_read_image reader; |
|
|
|
return reader.CanRead (*this); |
|
|
|
} |
|
|
|
/*****************************************************************************/ |
|
|
|
void dng_ifd::ReadImage (dng_host &host, |
|
dng_stream &stream, |
|
dng_image &image, |
|
dng_jpeg_image *jpegImage, |
|
dng_fingerprint *jpegDigest) const |
|
{ |
|
|
|
dng_read_image reader; |
|
|
|
reader.Read (host, |
|
*this, |
|
stream, |
|
image, |
|
jpegImage, |
|
jpegDigest); |
|
|
|
} |
|
|
|
/*****************************************************************************/
|
|
|