summaryrefslogtreecommitdiff
path: root/gpr/source/lib/dng_sdk/dng_ifd.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gpr/source/lib/dng_sdk/dng_ifd.cpp')
-rw-r--r--gpr/source/lib/dng_sdk/dng_ifd.cpp4266
1 files changed, 4266 insertions, 0 deletions
diff --git a/gpr/source/lib/dng_sdk/dng_ifd.cpp b/gpr/source/lib/dng_sdk/dng_ifd.cpp
new file mode 100644
index 0000000..949635d
--- /dev/null
+++ b/gpr/source/lib/dng_sdk/dng_ifd.cpp
@@ -0,0 +1,4266 @@
+/*****************************************************************************/
+// 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);
+
+ if (j < kMaxSamplesPerPixel)
+ {
+ 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, 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, 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;
+
+#if GPR_WRITING || GPR_READING
+ case ccVc5:
+ break;
+#endif
+
+ 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 = (fImageWidth + fTileWidth - 1) / fTileWidth;
+ uint32 tilesHigh = (fImageLength + fTileLength - 1) / 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 (fImageWidth + fTileWidth - 1) / fTileWidth;
+
+ }
+
+ return 0;
+
+ }
+
+/*****************************************************************************/
+
+uint32 dng_ifd::TilesDown () const
+ {
+
+ if (fTileLength)
+ {
+
+ return (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 = tile.W () *
+ fBitsPerSample [0];
+
+ if (fPlanarConfiguration == pcInterleaved)
+ {
+
+ bitsPerRow *= fSamplesPerPixel;
+
+ }
+
+ uint32 bytesPerRow = (bitsPerRow + 7) >> 3;
+
+ if (fPlanarConfiguration == pcRowInterleaved)
+ {
+
+ bytesPerRow *= fSamplesPerPixel;
+
+ }
+
+ return 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);
+
+ }
+
+/*****************************************************************************/