| /*****************************************************************************/ |
| // Copyright 2006-2008 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_shared.cpp#2 $ */ |
| /* $DateTime: 2012/06/14 20:24:41 $ */ |
| /* $Change: 835078 $ */ |
| /* $Author: tknoll $ */ |
| |
| /*****************************************************************************/ |
| |
| #include "dng_shared.h" |
| |
| #include "dng_camera_profile.h" |
| #include "dng_exceptions.h" |
| #include "dng_globals.h" |
| #include "dng_memory.h" |
| #include "dng_parse_utils.h" |
| #include "dng_safe_arithmetic.h" |
| #include "dng_tag_codes.h" |
| #include "dng_tag_types.h" |
| #include "dng_tag_values.h" |
| #include "dng_utils.h" |
| |
| /*****************************************************************************/ |
| |
| dng_camera_profile_info::dng_camera_profile_info () |
| |
| : fBigEndian (false) |
| |
| , fColorPlanes (0) |
| |
| , fCalibrationIlluminant1 (lsUnknown) |
| , fCalibrationIlluminant2 (lsUnknown) |
| |
| , fColorMatrix1 () |
| , fColorMatrix2 () |
| |
| , fForwardMatrix1 () |
| , fForwardMatrix2 () |
| |
| , fReductionMatrix1 () |
| , fReductionMatrix2 () |
| |
| , fProfileCalibrationSignature () |
| |
| , fProfileName () |
| |
| , fProfileCopyright () |
| |
| , fEmbedPolicy (pepAllowCopying) |
| |
| , fProfileHues (0) |
| , fProfileSats (0) |
| , fProfileVals (0) |
| |
| , fHueSatDeltas1Offset (0) |
| , fHueSatDeltas1Count (0) |
| |
| , fHueSatDeltas2Offset (0) |
| , fHueSatDeltas2Count (0) |
| |
| , fHueSatMapEncoding (encoding_Linear) |
| |
| , fLookTableHues (0) |
| , fLookTableSats (0) |
| , fLookTableVals (0) |
| |
| , fLookTableOffset (0) |
| , fLookTableCount (0) |
| |
| , fLookTableEncoding (encoding_Linear) |
| |
| , fBaselineExposureOffset (0, 100) |
| |
| , fDefaultBlackRender (defaultBlackRender_Auto) |
| |
| , fToneCurveOffset (0) |
| , fToneCurveCount (0) |
| |
| , fUniqueCameraModel () |
| |
| { |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_camera_profile_info::~dng_camera_profile_info () |
| { |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| bool dng_camera_profile_info::ParseTag (dng_stream &stream, |
| uint32 parentCode, |
| uint32 tagCode, |
| uint32 tagType, |
| uint32 tagCount, |
| uint64 tagOffset) |
| { |
| |
| switch (tagCode) |
| { |
| |
| case tcCalibrationIlluminant1: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttShort); |
| |
| CheckTagCount (parentCode, tagCode, tagCount, 1); |
| |
| fCalibrationIlluminant1 = stream.TagValue_uint32 (tagType); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("CalibrationIlluminant1: %s\n", |
| LookupLightSource (fCalibrationIlluminant1)); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcCalibrationIlluminant2: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttShort); |
| |
| CheckTagCount (parentCode, tagCode, tagCount, 1); |
| |
| fCalibrationIlluminant2 = stream.TagValue_uint32 (tagType); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("CalibrationIlluminant2: %s\n", |
| LookupLightSource (fCalibrationIlluminant2)); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcColorMatrix1: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttSRational); |
| |
| if (fColorPlanes == 0) |
| { |
| |
| fColorPlanes = Pin_uint32 (0, tagCount / 3, kMaxColorPlanes); |
| |
| } |
| |
| if (!CheckColorImage (parentCode, tagCode, fColorPlanes)) |
| return false; |
| |
| if (!ParseMatrixTag (stream, |
| parentCode, |
| tagCode, |
| tagType, |
| tagCount, |
| fColorPlanes, |
| 3, |
| fColorMatrix1)) |
| return false; |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("ColorMatrix1:\n"); |
| |
| DumpMatrix (fColorMatrix1); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcColorMatrix2: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttSRational); |
| |
| // Kludge - Hasselblad FFF files are very DNG-like, but sometimes |
| // only have a ColorMatrix2 tag and no ColorMatrix1 tag. |
| |
| bool hasselbladHack = (fColorPlanes == 0); |
| |
| if (hasselbladHack) |
| { |
| |
| fColorPlanes = Pin_uint32 (0, tagCount / 3, kMaxColorPlanes); |
| |
| #if qDNGValidate |
| |
| ReportWarning ("ColorMatrix2 without ColorMatrix1"); |
| |
| #endif |
| |
| } |
| |
| if (!CheckColorImage (parentCode, tagCode, fColorPlanes)) |
| return false; |
| |
| if (!ParseMatrixTag (stream, |
| parentCode, |
| tagCode, |
| tagType, |
| tagCount, |
| fColorPlanes, |
| 3, |
| fColorMatrix2)) |
| return false; |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("ColorMatrix2:\n"); |
| |
| DumpMatrix (fColorMatrix2); |
| |
| } |
| |
| #endif |
| |
| if (hasselbladHack) |
| { |
| |
| fColorMatrix1 = fColorMatrix2; |
| |
| fColorMatrix2 = dng_matrix (); |
| |
| } |
| |
| break; |
| |
| } |
| |
| case tcForwardMatrix1: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttSRational); |
| |
| if (!CheckColorImage (parentCode, tagCode, fColorPlanes)) |
| return false; |
| |
| if (!ParseMatrixTag (stream, |
| parentCode, |
| tagCode, |
| tagType, |
| tagCount, |
| 3, |
| fColorPlanes, |
| fForwardMatrix1)) |
| return false; |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("ForwardMatrix1:\n"); |
| |
| DumpMatrix (fForwardMatrix1); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcForwardMatrix2: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttSRational); |
| |
| if (!CheckColorImage (parentCode, tagCode, fColorPlanes)) |
| return false; |
| |
| if (!ParseMatrixTag (stream, |
| parentCode, |
| tagCode, |
| tagType, |
| tagCount, |
| 3, |
| fColorPlanes, |
| fForwardMatrix2)) |
| return false; |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("ForwardMatrix2:\n"); |
| |
| DumpMatrix (fForwardMatrix2); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcReductionMatrix1: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttSRational); |
| |
| if (!CheckColorImage (parentCode, tagCode, fColorPlanes)) |
| return false; |
| |
| if (!ParseMatrixTag (stream, |
| parentCode, |
| tagCode, |
| tagType, |
| tagCount, |
| 3, |
| fColorPlanes, |
| fReductionMatrix1)) |
| return false; |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("ReductionMatrix1:\n"); |
| |
| DumpMatrix (fReductionMatrix1); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcReductionMatrix2: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttSRational); |
| |
| if (!CheckColorImage (parentCode, tagCode, fColorPlanes)) |
| return false; |
| |
| if (!ParseMatrixTag (stream, |
| parentCode, |
| tagCode, |
| tagType, |
| tagCount, |
| 3, |
| fColorPlanes, |
| fReductionMatrix2)) |
| return false; |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("ReductionMatrix2:\n"); |
| |
| DumpMatrix (fReductionMatrix2); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcProfileCalibrationSignature: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); |
| |
| ParseStringTag (stream, |
| parentCode, |
| tagCode, |
| tagCount, |
| fProfileCalibrationSignature, |
| false); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("ProfileCalibrationSignature: "); |
| |
| DumpString (fProfileCalibrationSignature); |
| |
| printf ("\n"); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcProfileName: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); |
| |
| ParseStringTag (stream, |
| parentCode, |
| tagCode, |
| tagCount, |
| fProfileName, |
| false); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("ProfileName: "); |
| |
| DumpString (fProfileName); |
| |
| printf ("\n"); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcProfileCopyright: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); |
| |
| ParseStringTag (stream, |
| parentCode, |
| tagCode, |
| tagCount, |
| fProfileCopyright, |
| false); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("ProfileCopyright: "); |
| |
| DumpString (fProfileCopyright); |
| |
| printf ("\n"); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcProfileEmbedPolicy: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttLong); |
| |
| CheckTagCount (parentCode, tagCode, tagCount, 1); |
| |
| fEmbedPolicy = stream.TagValue_uint32 (tagType); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| const char *policy; |
| |
| switch (fEmbedPolicy) |
| { |
| |
| case pepAllowCopying: |
| policy = "Allow copying"; |
| break; |
| |
| case pepEmbedIfUsed: |
| policy = "Embed if used"; |
| break; |
| |
| case pepEmbedNever: |
| policy = "Embed never"; |
| break; |
| |
| case pepNoRestrictions: |
| policy = "No restrictions"; |
| break; |
| |
| default: |
| policy = "INVALID VALUE"; |
| |
| } |
| |
| printf ("ProfileEmbedPolicy: %s\n", policy); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcProfileHueSatMapDims: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttLong); |
| |
| CheckTagCount (parentCode, tagCode, tagCount, 2, 3); |
| |
| fProfileHues = stream.TagValue_uint32 (tagType); |
| fProfileSats = stream.TagValue_uint32 (tagType); |
| |
| if (tagCount > 2) |
| fProfileVals = stream.TagValue_uint32 (tagType); |
| else |
| fProfileVals = 1; |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("ProfileHueSatMapDims: Hues = %u, Sats = %u, Vals = %u\n", |
| (unsigned) fProfileHues, |
| (unsigned) fProfileSats, |
| (unsigned) fProfileVals); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcProfileHueSatMapData1: |
| { |
| |
| if (!CheckTagType (parentCode, tagCode, tagType, ttFloat)) |
| return false; |
| |
| bool skipSat0 = (tagCount == |
| SafeUint32Mult(fProfileHues, |
| SafeUint32Sub(fProfileSats, 1u), |
| fProfileVals, |
| 3u)); |
| |
| if (!skipSat0) |
| { |
| |
| if (!CheckTagCount (parentCode, tagCode, tagCount, |
| SafeUint32Mult(fProfileHues, fProfileSats, fProfileVals, 3))) |
| return false; |
| |
| } |
| |
| fBigEndian = stream.BigEndian (); |
| |
| fHueSatDeltas1Offset = tagOffset; |
| fHueSatDeltas1Count = tagCount; |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("ProfileHueSatMapData1:\n"); |
| |
| DumpHueSatMap (stream, |
| fProfileHues, |
| fProfileSats, |
| fProfileVals, |
| skipSat0); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcProfileHueSatMapData2: |
| { |
| |
| if (!CheckTagType (parentCode, tagCode, tagType, ttFloat)) |
| return false; |
| |
| bool skipSat0 = (tagCount == |
| SafeUint32Mult(fProfileHues, |
| SafeUint32Sub(fProfileSats, 1u), |
| fProfileVals, |
| 3u)); |
| |
| if (!skipSat0) |
| { |
| |
| if (!CheckTagCount (parentCode, tagCode, tagCount, |
| SafeUint32Mult(fProfileHues, fProfileSats, fProfileVals, 3))) |
| return false; |
| |
| } |
| |
| fBigEndian = stream.BigEndian (); |
| |
| fHueSatDeltas2Offset = tagOffset; |
| fHueSatDeltas2Count = tagCount; |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("ProfileHueSatMapData2:\n"); |
| |
| DumpHueSatMap (stream, |
| fProfileHues, |
| fProfileSats, |
| fProfileVals, |
| skipSat0); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcProfileHueSatMapEncoding: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttLong); |
| |
| CheckTagCount (parentCode, tagCode, tagCount, 1); |
| |
| fHueSatMapEncoding = stream.TagValue_uint32 (tagType); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| const char *encoding = NULL; |
| |
| switch (fHueSatMapEncoding) |
| { |
| |
| case encoding_Linear: |
| encoding = "Linear"; |
| break; |
| |
| case encoding_sRGB: |
| encoding = "sRGB"; |
| break; |
| |
| default: |
| encoding = "INVALID VALUE"; |
| |
| } |
| |
| printf ("ProfileHueSatMapEncoding: %s\n", encoding); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcProfileLookTableDims: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttLong); |
| |
| CheckTagCount (parentCode, tagCode, tagCount, 2, 3); |
| |
| fLookTableHues = stream.TagValue_uint32 (tagType); |
| fLookTableSats = stream.TagValue_uint32 (tagType); |
| |
| if (tagCount > 2) |
| fLookTableVals = stream.TagValue_uint32 (tagType); |
| else |
| fLookTableVals = 1; |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("ProfileLookTableDims: Hues = %u, Sats = %u, Vals = %u\n", |
| (unsigned) fLookTableHues, |
| (unsigned) fLookTableSats, |
| (unsigned) fLookTableVals); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcProfileLookTableData: |
| { |
| |
| if (!CheckTagType (parentCode, tagCode, tagType, ttFloat)) |
| return false; |
| |
| bool skipSat0 = (tagCount == |
| SafeUint32Mult(fLookTableHues, |
| SafeUint32Sub(fLookTableSats, 1u), |
| fLookTableVals, |
| 3u)); |
| |
| if (!skipSat0) |
| { |
| |
| if (!CheckTagCount (parentCode, tagCode, tagCount, |
| SafeUint32Mult(fLookTableHues, |
| fLookTableSats, |
| fLookTableVals, 3))) |
| return false; |
| |
| } |
| |
| fBigEndian = stream.BigEndian (); |
| |
| fLookTableOffset = tagOffset; |
| fLookTableCount = tagCount; |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("ProfileLookTableData:\n"); |
| |
| DumpHueSatMap (stream, |
| fLookTableHues, |
| fLookTableSats, |
| fLookTableVals, |
| skipSat0); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcProfileLookTableEncoding: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttLong); |
| |
| CheckTagCount (parentCode, tagCode, tagCount, 1); |
| |
| fLookTableEncoding = stream.TagValue_uint32 (tagType); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| const char *encoding = NULL; |
| |
| switch (fLookTableEncoding) |
| { |
| |
| case encoding_Linear: |
| encoding = "Linear"; |
| break; |
| |
| case encoding_sRGB: |
| encoding = "sRGB"; |
| break; |
| |
| default: |
| encoding = "INVALID VALUE"; |
| |
| } |
| |
| printf ("ProfileLookTableEncoding: %s\n", encoding); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcBaselineExposureOffset: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttSRational); |
| |
| CheckTagCount (parentCode, tagCode, tagCount, 1); |
| |
| fBaselineExposureOffset = stream.TagValue_srational (tagType); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("BaselineExposureOffset: %+0.2f\n", |
| fBaselineExposureOffset.As_real64 ()); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcDefaultBlackRender: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttLong); |
| |
| CheckTagCount (parentCode, tagCode, tagCount, 1); |
| |
| fDefaultBlackRender = stream.TagValue_uint32 (tagType); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| const char *setting = NULL; |
| |
| switch (fDefaultBlackRender) |
| { |
| |
| case defaultBlackRender_Auto: |
| setting = "Auto"; |
| break; |
| |
| case defaultBlackRender_None: |
| setting = "None"; |
| break; |
| |
| default: |
| setting = "INVALID VALUE"; |
| |
| } |
| |
| printf ("DefaultBlackRender: %s\n", |
| setting); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcProfileToneCurve: |
| { |
| |
| if (!CheckTagType (parentCode, tagCode, tagType, ttFloat)) |
| return false; |
| |
| if (!CheckTagCount (parentCode, tagCode, tagCount, 4, tagCount)) |
| return false; |
| |
| if ((tagCount & 1) != 0) |
| { |
| |
| #if qDNGValidate |
| |
| { |
| |
| char message [256]; |
| |
| sprintf (message, |
| "%s %s has odd count (%u)", |
| LookupParentCode (parentCode), |
| LookupTagCode (parentCode, tagCode), |
| (unsigned) tagCount); |
| |
| ReportWarning (message); |
| |
| } |
| |
| #endif |
| |
| return false; |
| |
| } |
| |
| fBigEndian = stream.BigEndian (); |
| |
| fToneCurveOffset = tagOffset; |
| fToneCurveCount = tagCount; |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| DumpTagValues (stream, |
| "Coord", |
| parentCode, |
| tagCode, |
| tagType, |
| tagCount); |
| |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcUniqueCameraModel: |
| { |
| |
| // Note: This code is only used when parsing stand-alone |
| // profiles. The embedded profiles are assumed to be restricted |
| // to the model they are embedded in. |
| |
| CheckTagType (parentCode, tagCode, tagType, ttAscii); |
| |
| ParseStringTag (stream, |
| parentCode, |
| tagCode, |
| tagCount, |
| fUniqueCameraModel, |
| false); |
| |
| bool didTrim = fUniqueCameraModel.TrimTrailingBlanks (); |
| |
| #if qDNGValidate |
| |
| if (didTrim) |
| { |
| |
| ReportWarning ("UniqueCameraModel string has trailing blanks"); |
| |
| } |
| |
| if (gVerbose) |
| { |
| |
| printf ("UniqueCameraModel: "); |
| |
| DumpString (fUniqueCameraModel); |
| |
| printf ("\n"); |
| |
| } |
| |
| #else |
| |
| (void) didTrim; // Unused |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| default: |
| { |
| |
| return false; |
| |
| } |
| |
| } |
| |
| return true; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| bool dng_camera_profile_info::ParseExtended (dng_stream &stream) |
| { |
| |
| try |
| { |
| |
| // Offsets are relative to the start of this structure, not the entire file. |
| |
| uint64 startPosition = stream.Position (); |
| |
| // Read header. Like a TIFF header, but with different magic number |
| // Plus all offsets are relative to the start of the IFD, not to the |
| // stream or file. |
| |
| uint16 byteOrder = stream.Get_uint16 (); |
| |
| if (byteOrder == byteOrderMM) |
| fBigEndian = true; |
| |
| else if (byteOrder == byteOrderII) |
| fBigEndian = false; |
| |
| else |
| return false; |
| |
| TempBigEndian setEndianness (stream, fBigEndian); |
| |
| uint16 magicNumber = stream.Get_uint16 (); |
| |
| if (magicNumber != magicExtendedProfile) |
| { |
| return false; |
| } |
| |
| uint32 offset = stream.Get_uint32 (); |
| |
| stream.Skip (SafeUint32Sub(offset, 8u)); |
| |
| // Start on IFD entries. |
| |
| uint32 ifdEntries = stream.Get_uint16 (); |
| |
| if (ifdEntries < 1) |
| { |
| return false; |
| } |
| |
| for (uint32 tag_index = 0; tag_index < ifdEntries; tag_index++) |
| { |
| |
| stream.SetReadPosition (startPosition + 8 + 2 + tag_index * 12); |
| |
| uint16 tagCode = stream.Get_uint16 (); |
| uint32 tagType = stream.Get_uint16 (); |
| uint32 tagCount = stream.Get_uint32 (); |
| |
| uint64 tagOffset = stream.Position (); |
| |
| if (SafeUint32Mult(TagTypeSize (tagType), tagCount) > 4) |
| { |
| |
| tagOffset = startPosition + stream.Get_uint32 (); |
| |
| stream.SetReadPosition (tagOffset); |
| |
| } |
| |
| if (!ParseTag (stream, |
| 0, |
| tagCode, |
| tagType, |
| tagCount, |
| tagOffset)) |
| { |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| stream.SetReadPosition (tagOffset); |
| |
| printf ("*"); |
| |
| DumpTagValues (stream, |
| LookupTagType (tagType), |
| 0, |
| tagCode, |
| tagType, |
| tagCount); |
| |
| } |
| |
| #endif |
| |
| } |
| |
| } |
| |
| return true; |
| |
| } |
| |
| catch (...) |
| { |
| |
| // Eat parsing errors. |
| |
| } |
| |
| return false; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_shared::dng_shared () |
| |
| : fExifIFD (0) |
| , fGPSInfo (0) |
| , fInteroperabilityIFD (0) |
| , fKodakDCRPrivateIFD (0) |
| , fKodakKDCPrivateIFD (0) |
| |
| , fXMPCount (0) |
| , fXMPOffset (0) |
| |
| , fIPTC_NAA_Count (0) |
| , fIPTC_NAA_Offset (0) |
| |
| , fMakerNoteCount (0) |
| , fMakerNoteOffset (0) |
| , fMakerNoteSafety (0) |
| |
| , fDNGVersion (0) |
| , fDNGBackwardVersion (0) |
| |
| , fUniqueCameraModel () |
| , fLocalizedCameraModel () |
| |
| , fCameraProfile () |
| |
| , fExtraCameraProfiles () |
| |
| , fCameraCalibration1 () |
| , fCameraCalibration2 () |
| |
| , fCameraCalibrationSignature () |
| |
| , fAnalogBalance () |
| |
| , fAsShotNeutral () |
| |
| , fAsShotWhiteXY () |
| |
| , fBaselineExposure (0, 1) |
| , fBaselineNoise (1, 1) |
| , fNoiseReductionApplied (0, 0) |
| , fBaselineSharpness (1, 1) |
| , fLinearResponseLimit (1, 1) |
| , fShadowScale (1, 1) |
| |
| , fHasBaselineExposure (false) |
| , fHasShadowScale (false) |
| |
| , fDNGPrivateDataCount (0) |
| , fDNGPrivateDataOffset (0) |
| |
| , fRawImageDigest () |
| , fNewRawImageDigest () |
| |
| , fRawDataUniqueID () |
| |
| , fOriginalRawFileName () |
| |
| , fOriginalRawFileDataCount (0) |
| , fOriginalRawFileDataOffset (0) |
| |
| , fOriginalRawFileDigest () |
| |
| , fAsShotICCProfileCount (0) |
| , fAsShotICCProfileOffset (0) |
| |
| , fAsShotPreProfileMatrix () |
| |
| , fCurrentICCProfileCount (0) |
| , fCurrentICCProfileOffset (0) |
| |
| , fCurrentPreProfileMatrix () |
| |
| , fColorimetricReference (crSceneReferred) |
| |
| , fAsShotProfileName () |
| |
| , fNoiseProfile () |
| |
| , fOriginalDefaultFinalSize () |
| , fOriginalBestQualityFinalSize () |
| |
| , fOriginalDefaultCropSizeH () |
| , fOriginalDefaultCropSizeV () |
| |
| { |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_shared::~dng_shared () |
| { |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| bool dng_shared::ParseTag (dng_stream &stream, |
| dng_exif &exif, |
| uint32 parentCode, |
| bool /* isMainIFD */, |
| uint32 tagCode, |
| uint32 tagType, |
| uint32 tagCount, |
| uint64 tagOffset, |
| int64 /* offsetDelta */) |
| { |
| |
| if (parentCode == 0) |
| { |
| |
| if (Parse_ifd0 (stream, |
| exif, |
| parentCode, |
| tagCode, |
| tagType, |
| tagCount, |
| tagOffset)) |
| { |
| |
| return true; |
| |
| } |
| |
| } |
| |
| if (parentCode == 0 || |
| parentCode == tcExifIFD) |
| { |
| |
| if (Parse_ifd0_exif (stream, |
| exif, |
| parentCode, |
| tagCode, |
| tagType, |
| tagCount, |
| tagOffset)) |
| { |
| |
| return true; |
| |
| } |
| |
| } |
| |
| return false; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| // Parses tags that should only appear in IFD 0. |
| |
| bool dng_shared::Parse_ifd0 (dng_stream &stream, |
| dng_exif & /* exif */, |
| uint32 parentCode, |
| uint32 tagCode, |
| uint32 tagType, |
| uint32 tagCount, |
| uint64 tagOffset) |
| { |
| |
| switch (tagCode) |
| { |
| |
| case tcXMP: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttByte, ttUndefined); |
| |
| fXMPCount = tagCount; |
| fXMPOffset = fXMPCount ? tagOffset : 0; |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("XMP: Count = %u, Offset = %u\n", |
| (unsigned) fXMPCount, |
| (unsigned) fXMPOffset); |
| |
| if (fXMPCount) |
| { |
| |
| DumpXMP (stream, fXMPCount); |
| |
| } |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcIPTC_NAA: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttLong, ttAscii, ttUndefined); |
| |
| fIPTC_NAA_Count = SafeUint32Mult(tagCount, |
| TagTypeSize(tagType)); |
| fIPTC_NAA_Offset = fIPTC_NAA_Count ? tagOffset : 0; |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("IPTC/NAA: Count = %u, Offset = %u\n", |
| (unsigned) fIPTC_NAA_Count, |
| (unsigned) fIPTC_NAA_Offset); |
| |
| if (fIPTC_NAA_Count) |
| { |
| |
| DumpHexAscii (stream, fIPTC_NAA_Count); |
| |
| } |
| |
| // Compute and output the digest. |
| |
| dng_memory_data buffer (fIPTC_NAA_Count); |
| |
| stream.SetReadPosition (fIPTC_NAA_Offset); |
| |
| stream.Get (buffer.Buffer (), fIPTC_NAA_Count); |
| |
| const uint8 *data = buffer.Buffer_uint8 (); |
| |
| uint32 count = fIPTC_NAA_Count; |
| |
| // Method 1: Counting all bytes (this is correct). |
| |
| { |
| |
| dng_md5_printer printer; |
| |
| printer.Process (data, count); |
| |
| printf ("IPTCDigest: "); |
| |
| DumpFingerprint (printer.Result ()); |
| |
| printf ("\n"); |
| |
| } |
| |
| // Method 2: Ignoring zero padding. |
| |
| { |
| |
| uint32 removed = 0; |
| |
| while ((removed < 3) && (count > 0) && (data [count - 1] == 0)) |
| { |
| removed++; |
| count--; |
| } |
| |
| if (removed != 0) |
| { |
| |
| dng_md5_printer printer; |
| |
| printer.Process (data, count); |
| |
| printf ("IPTCDigest (ignoring zero padding): "); |
| |
| DumpFingerprint (printer.Result ()); |
| |
| printf ("\n"); |
| |
| } |
| |
| } |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcExifIFD: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD); |
| |
| CheckTagCount (parentCode, tagCode, tagCount, 1); |
| |
| fExifIFD = stream.TagValue_uint32 (tagType); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| printf ("ExifIFD: %u\n", (unsigned) fExifIFD); |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcGPSInfo: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD); |
| |
| CheckTagCount (parentCode, tagCode, tagCount, 1); |
| |
| fGPSInfo = stream.TagValue_uint32 (tagType); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| printf ("GPSInfo: %u\n", (unsigned) fGPSInfo); |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcKodakDCRPrivateIFD: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD); |
| |
| CheckTagCount (parentCode, tagCode, tagCount, 1); |
| |
| fKodakDCRPrivateIFD = stream.TagValue_uint32 (tagType); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| printf ("KodakDCRPrivateIFD: %u\n", (unsigned) fKodakDCRPrivateIFD); |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcKodakKDCPrivateIFD: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD); |
| |
| CheckTagCount (parentCode, tagCode, tagCount, 1); |
| |
| fKodakKDCPrivateIFD = stream.TagValue_uint32 (tagType); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| printf ("KodakKDCPrivateIFD: %u\n", (unsigned) fKodakKDCPrivateIFD); |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcDNGVersion: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttByte); |
| |
| CheckTagCount (parentCode, tagCode, tagCount, 4); |
| |
| uint32 b0 = stream.Get_uint8 (); |
| uint32 b1 = stream.Get_uint8 (); |
| uint32 b2 = stream.Get_uint8 (); |
| uint32 b3 = stream.Get_uint8 (); |
| |
| fDNGVersion = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| printf ("DNGVersion: %u.%u.%u.%u\n", |
| (unsigned) b0, |
| (unsigned) b1, |
| (unsigned) b2, |
| (unsigned) b3); |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcDNGBackwardVersion: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttByte); |
| |
| CheckTagCount (parentCode, tagCode, tagCount, 4); |
| |
| uint32 b0 = stream.Get_uint8 (); |
| uint32 b1 = stream.Get_uint8 (); |
| uint32 b2 = stream.Get_uint8 (); |
| uint32 b3 = stream.Get_uint8 (); |
| |
| fDNGBackwardVersion = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| printf ("DNGBackwardVersion: %u.%u.%u.%u\n", |
| (unsigned) b0, |
| (unsigned) b1, |
| (unsigned) b2, |
| (unsigned) b3); |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcUniqueCameraModel: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttAscii); |
| |
| ParseStringTag (stream, |
| parentCode, |
| tagCode, |
| tagCount, |
| fUniqueCameraModel, |
| false); |
| |
| bool didTrim = fUniqueCameraModel.TrimTrailingBlanks (); |
| |
| #if qDNGValidate |
| |
| if (didTrim) |
| { |
| |
| ReportWarning ("UniqueCameraModel string has trailing blanks"); |
| |
| } |
| |
| if (gVerbose) |
| { |
| |
| printf ("UniqueCameraModel: "); |
| |
| DumpString (fUniqueCameraModel); |
| |
| printf ("\n"); |
| |
| } |
| |
| #else |
| |
| (void) didTrim; // Unused |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcLocalizedCameraModel: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); |
| |
| ParseStringTag (stream, |
| parentCode, |
| tagCode, |
| tagCount, |
| fLocalizedCameraModel, |
| false); |
| |
| bool didTrim = fLocalizedCameraModel.TrimTrailingBlanks (); |
| |
| #if qDNGValidate |
| |
| if (didTrim) |
| { |
| |
| ReportWarning ("LocalizedCameraModel string has trailing blanks"); |
| |
| } |
| |
| if (gVerbose) |
| { |
| |
| printf ("LocalizedCameraModel: "); |
| |
| DumpString (fLocalizedCameraModel); |
| |
| printf ("\n"); |
| |
| } |
| |
| #else |
| |
| (void) didTrim; // Unused |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcCameraCalibration1: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttSRational); |
| |
| if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes)) |
| return false; |
| |
| if (!ParseMatrixTag (stream, |
| parentCode, |
| tagCode, |
| tagType, |
| tagCount, |
| fCameraProfile.fColorPlanes, |
| fCameraProfile.fColorPlanes, |
| fCameraCalibration1)) |
| return false; |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("CameraCalibration1:\n"); |
| |
| DumpMatrix (fCameraCalibration1); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcCameraCalibration2: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttSRational); |
| |
| if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes)) |
| return false; |
| |
| if (!ParseMatrixTag (stream, |
| parentCode, |
| tagCode, |
| tagType, |
| tagCount, |
| fCameraProfile.fColorPlanes, |
| fCameraProfile.fColorPlanes, |
| fCameraCalibration2)) |
| return false; |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("CameraCalibration2:\n"); |
| |
| DumpMatrix (fCameraCalibration2); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcCameraCalibrationSignature: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); |
| |
| ParseStringTag (stream, |
| parentCode, |
| tagCode, |
| tagCount, |
| fCameraCalibrationSignature, |
| false); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("CameraCalibrationSignature: "); |
| |
| DumpString (fCameraCalibrationSignature); |
| |
| printf ("\n"); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcAnalogBalance: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttRational); |
| |
| // Kludge - Hasselblad FFF files are very DNG-like, but sometimes |
| // they don't have any ColorMatrix tags. |
| |
| bool hasselbladHack = (fDNGVersion == 0 && |
| fCameraProfile.fColorPlanes == 0); |
| |
| if (hasselbladHack) |
| { |
| |
| fCameraProfile.fColorPlanes = Pin_uint32 (0, tagCount, kMaxColorPlanes); |
| |
| #if qDNGValidate |
| |
| ReportWarning ("AnalogBalance without ColorMatrix1"); |
| |
| #endif |
| |
| } |
| |
| if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes)) |
| return false; |
| |
| if (!ParseVectorTag (stream, |
| parentCode, |
| tagCode, |
| tagType, |
| tagCount, |
| fCameraProfile.fColorPlanes, |
| fAnalogBalance)) |
| return false; |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("AnalogBalance:"); |
| |
| DumpVector (fAnalogBalance); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcAsShotNeutral: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttRational); |
| |
| // Kludge - Hasselblad FFF files are very DNG-like, but sometimes |
| // they don't have any ColorMatrix tags. |
| |
| bool hasselbladHack = (fDNGVersion == 0 && |
| fCameraProfile.fColorPlanes == 0); |
| |
| if (hasselbladHack) |
| { |
| |
| fCameraProfile.fColorPlanes = Pin_uint32 (0, tagCount, kMaxColorPlanes); |
| |
| #if qDNGValidate |
| |
| ReportWarning ("AsShotNeutral without ColorMatrix1"); |
| |
| #endif |
| |
| } |
| |
| if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes)) |
| return false; |
| |
| if (!ParseVectorTag (stream, |
| parentCode, |
| tagCode, |
| tagType, |
| tagCount, |
| fCameraProfile.fColorPlanes, |
| fAsShotNeutral)) |
| return false; |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("AsShotNeutral:"); |
| |
| DumpVector (fAsShotNeutral); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcAsShotWhiteXY: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttRational); |
| |
| if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes)) |
| return false; |
| |
| if (!CheckTagCount (parentCode, tagCode, tagCount, 2)) |
| return false; |
| |
| fAsShotWhiteXY.x = stream.TagValue_real64 (tagType); |
| fAsShotWhiteXY.y = stream.TagValue_real64 (tagType); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("AsShotWhiteXY: %0.4f %0.4f\n", |
| fAsShotWhiteXY.x, |
| fAsShotWhiteXY.y); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcBaselineExposure: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttSRational); |
| |
| CheckTagCount (parentCode, tagCode, tagCount, 1); |
| |
| fBaselineExposure = stream.TagValue_srational (tagType); |
| |
| fHasBaselineExposure = true; |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("BaselineExposure: %+0.2f\n", |
| fBaselineExposure.As_real64 ()); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcBaselineNoise: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttRational); |
| |
| CheckTagCount (parentCode, tagCode, tagCount, 1); |
| |
| fBaselineNoise = stream.TagValue_urational (tagType); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("BaselineNoise: %0.2f\n", |
| fBaselineNoise.As_real64 ()); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcNoiseReductionApplied: |
| { |
| |
| if (!CheckTagType (parentCode, tagCode, tagType, ttRational)) |
| return false; |
| |
| if (!CheckTagCount (parentCode, tagCode, tagCount, 1)) |
| return false; |
| |
| fNoiseReductionApplied = stream.TagValue_urational (tagType); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("NoiseReductionApplied: %u/%u\n", |
| (unsigned) fNoiseReductionApplied.n, |
| (unsigned) fNoiseReductionApplied.d); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcNoiseProfile: |
| { |
| |
| if (!CheckTagType (parentCode, tagCode, tagType, ttDouble)) |
| return false; |
| |
| // Must be an even, positive number of doubles in a noise profile. |
| |
| if (!tagCount || (tagCount & 1)) |
| return false; |
| |
| // Determine number of planes (i.e., half the number of doubles). |
| |
| const uint32 numPlanes = Pin_uint32 (0, |
| tagCount >> 1, |
| kMaxColorPlanes); |
| |
| // Parse the noise function parameters. |
| |
| dng_std_vector<dng_noise_function> noiseFunctions; |
| |
| for (uint32 i = 0; i < numPlanes; i++) |
| { |
| |
| const real64 scale = stream.TagValue_real64 (tagType); |
| const real64 offset = stream.TagValue_real64 (tagType); |
| |
| noiseFunctions.push_back (dng_noise_function (scale, offset)); |
| |
| } |
| |
| // Store the noise profile. |
| |
| fNoiseProfile = dng_noise_profile (noiseFunctions); |
| |
| // Debug. |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("NoiseProfile:\n"); |
| |
| printf (" Planes: %u\n", (unsigned) numPlanes); |
| |
| for (uint32 plane = 0; plane < numPlanes; plane++) |
| { |
| |
| printf (" Noise function for plane %u: scale = %.8lf, offset = %.8lf\n", |
| (unsigned) plane, |
| noiseFunctions [plane].Scale (), |
| noiseFunctions [plane].Offset ()); |
| |
| } |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcBaselineSharpness: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttRational); |
| |
| CheckTagCount (parentCode, tagCode, tagCount, 1); |
| |
| fBaselineSharpness = stream.TagValue_urational (tagType); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("BaselineSharpness: %0.2f\n", |
| fBaselineSharpness.As_real64 ()); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcLinearResponseLimit: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttRational); |
| |
| CheckTagCount (parentCode, tagCode, tagCount, 1); |
| |
| fLinearResponseLimit = stream.TagValue_urational (tagType); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("LinearResponseLimit: %0.2f\n", |
| fLinearResponseLimit.As_real64 ()); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcShadowScale: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttRational); |
| |
| CheckTagCount (parentCode, tagCode, tagCount, 1); |
| |
| fShadowScale = stream.TagValue_urational (tagType); |
| |
| fHasShadowScale = true; |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("ShadowScale: %0.4f\n", |
| fShadowScale.As_real64 ()); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcDNGPrivateData: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttByte); |
| |
| fDNGPrivateDataCount = tagCount; |
| fDNGPrivateDataOffset = tagOffset; |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("DNGPrivateData: Count = %u, Offset = %u\n", |
| (unsigned) fDNGPrivateDataCount, |
| (unsigned) fDNGPrivateDataOffset); |
| |
| DumpHexAscii (stream, tagCount); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcMakerNoteSafety: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttShort); |
| |
| CheckTagCount (parentCode, tagCode, tagCount, 1); |
| |
| fMakerNoteSafety = stream.TagValue_uint32 (tagType); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("MakerNoteSafety: %s\n", |
| LookupMakerNoteSafety (fMakerNoteSafety)); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcRawImageDigest: |
| { |
| |
| if (!CheckTagType (parentCode, tagCode, tagType, ttByte)) |
| return false; |
| |
| if (!CheckTagCount (parentCode, tagCode, tagCount, 16)) |
| return false; |
| |
| stream.Get (fRawImageDigest.data, 16); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("RawImageDigest: "); |
| |
| DumpFingerprint (fRawImageDigest); |
| |
| printf ("\n"); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcNewRawImageDigest: |
| { |
| |
| if (!CheckTagType (parentCode, tagCode, tagType, ttByte)) |
| return false; |
| |
| if (!CheckTagCount (parentCode, tagCode, tagCount, 16)) |
| return false; |
| |
| stream.Get (fNewRawImageDigest.data, 16); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("NewRawImageDigest: "); |
| |
| DumpFingerprint (fNewRawImageDigest); |
| |
| printf ("\n"); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcRawDataUniqueID: |
| { |
| |
| if (!CheckTagType (parentCode, tagCode, tagType, ttByte)) |
| return false; |
| |
| if (!CheckTagCount (parentCode, tagCode, tagCount, 16)) |
| return false; |
| |
| stream.Get (fRawDataUniqueID.data, 16); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("RawDataUniqueID: "); |
| |
| DumpFingerprint (fRawDataUniqueID); |
| |
| printf ("\n"); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcOriginalRawFileName: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); |
| |
| ParseStringTag (stream, |
| parentCode, |
| tagCode, |
| tagCount, |
| fOriginalRawFileName, |
| false); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("OriginalRawFileName: "); |
| |
| DumpString (fOriginalRawFileName); |
| |
| printf ("\n"); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcOriginalRawFileData: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttUndefined); |
| |
| fOriginalRawFileDataCount = tagCount; |
| fOriginalRawFileDataOffset = tagOffset; |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("OriginalRawFileData: Count = %u, Offset = %u\n", |
| (unsigned) fOriginalRawFileDataCount, |
| (unsigned) fOriginalRawFileDataOffset); |
| |
| DumpHexAscii (stream, tagCount); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcOriginalRawFileDigest: |
| { |
| |
| if (!CheckTagType (parentCode, tagCode, tagType, ttByte)) |
| return false; |
| |
| if (!CheckTagCount (parentCode, tagCode, tagCount, 16)) |
| return false; |
| |
| stream.Get (fOriginalRawFileDigest.data, 16); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("OriginalRawFileDigest: "); |
| |
| DumpFingerprint (fOriginalRawFileDigest); |
| |
| printf ("\n"); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcAsShotICCProfile: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttUndefined); |
| |
| fAsShotICCProfileCount = tagCount; |
| fAsShotICCProfileOffset = tagOffset; |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("AsShotICCProfile: Count = %u, Offset = %u\n", |
| (unsigned) fAsShotICCProfileCount, |
| (unsigned) fAsShotICCProfileOffset); |
| |
| DumpHexAscii (stream, tagCount); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcAsShotPreProfileMatrix: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttSRational); |
| |
| if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes)) |
| return false; |
| |
| uint32 rows = fCameraProfile.fColorPlanes; |
| |
| if (tagCount == fCameraProfile.fColorPlanes * 3) |
| { |
| rows = 3; |
| } |
| |
| if (!ParseMatrixTag (stream, |
| parentCode, |
| tagCode, |
| tagType, |
| tagCount, |
| rows, |
| fCameraProfile.fColorPlanes, |
| fAsShotPreProfileMatrix)) |
| return false; |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("AsShotPreProfileMatrix:\n"); |
| |
| DumpMatrix (fAsShotPreProfileMatrix); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcCurrentICCProfile: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttUndefined); |
| |
| fCurrentICCProfileCount = tagCount; |
| fCurrentICCProfileOffset = tagOffset; |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("CurrentICCProfile: Count = %u, Offset = %u\n", |
| (unsigned) fCurrentICCProfileCount, |
| (unsigned) fCurrentICCProfileOffset); |
| |
| DumpHexAscii (stream, tagCount); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcCurrentPreProfileMatrix: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttSRational); |
| |
| if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes)) |
| return false; |
| |
| uint32 rows = fCameraProfile.fColorPlanes; |
| |
| if (tagCount == fCameraProfile.fColorPlanes * 3) |
| { |
| rows = 3; |
| } |
| |
| if (!ParseMatrixTag (stream, |
| parentCode, |
| tagCode, |
| tagType, |
| tagCount, |
| rows, |
| fCameraProfile.fColorPlanes, |
| fCurrentPreProfileMatrix)) |
| return false; |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("CurrentPreProfileMatrix:\n"); |
| |
| DumpMatrix (fCurrentPreProfileMatrix); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcColorimetricReference: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttShort); |
| |
| CheckTagCount (parentCode, tagCode, tagCount, 1); |
| |
| fColorimetricReference = stream.TagValue_uint32 (tagType); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("ColorimetricReference: %s\n", |
| LookupColorimetricReference (fColorimetricReference)); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcExtraCameraProfiles: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttLong); |
| |
| CheckTagCount (parentCode, tagCode, tagCount, 1, tagCount); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("ExtraCameraProfiles: %u\n", (unsigned) tagCount); |
| |
| } |
| |
| #endif |
| |
| fExtraCameraProfiles.reserve (tagCount); |
| |
| for (uint32 index = 0; index < tagCount; index++) |
| { |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("\nExtraCameraProfile [%u]:\n\n", (unsigned) index); |
| |
| } |
| |
| #endif |
| |
| stream.SetReadPosition (tagOffset + index * 4); |
| |
| uint32 profileOffset = stream.TagValue_uint32 (tagType); |
| |
| dng_camera_profile_info profileInfo; |
| |
| stream.SetReadPosition (profileOffset); |
| |
| if (profileInfo.ParseExtended (stream)) |
| { |
| |
| fExtraCameraProfiles.push_back (profileInfo); |
| |
| } |
| |
| else |
| { |
| |
| #if qDNGValidate |
| |
| ReportWarning ("Unable to parse extra camera profile"); |
| |
| #endif |
| |
| } |
| |
| } |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("\nDone with ExtraCameraProfiles\n\n"); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcAsShotProfileName: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); |
| |
| ParseStringTag (stream, |
| parentCode, |
| tagCode, |
| tagCount, |
| fAsShotProfileName, |
| false); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("AsShotProfileName: "); |
| |
| DumpString (fAsShotProfileName); |
| |
| printf ("\n"); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcOriginalDefaultFinalSize: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong); |
| |
| if (!CheckTagCount (parentCode, tagCode, tagCount, 2)) |
| return false; |
| |
| fOriginalDefaultFinalSize.h = stream.TagValue_int32 (tagType); |
| fOriginalDefaultFinalSize.v = stream.TagValue_int32 (tagType); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("OriginalDefaultFinalSize: H = %d V = %d\n", |
| (int) fOriginalDefaultFinalSize.h, |
| (int) fOriginalDefaultFinalSize.v); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcOriginalBestQualityFinalSize: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong); |
| |
| if (!CheckTagCount (parentCode, tagCode, tagCount, 2)) |
| return false; |
| |
| fOriginalBestQualityFinalSize.h = stream.TagValue_int32 (tagType); |
| fOriginalBestQualityFinalSize.v = stream.TagValue_int32 (tagType); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("OriginalBestQualityFinalSize: H = %d V = %d\n", |
| (int) fOriginalBestQualityFinalSize.h, |
| (int) fOriginalBestQualityFinalSize.v); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcOriginalDefaultCropSize: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong, ttRational); |
| |
| if (!CheckTagCount (parentCode, tagCode, tagCount, 2)) |
| return false; |
| |
| fOriginalDefaultCropSizeH = stream.TagValue_urational (tagType); |
| fOriginalDefaultCropSizeV = stream.TagValue_urational (tagType); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("OriginalDefaultCropSize: H = %0.2f V = %0.2f\n", |
| fOriginalDefaultCropSizeH.As_real64 (), |
| fOriginalDefaultCropSizeV.As_real64 ()); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| default: |
| { |
| |
| // The main camera profile tags also appear in IFD 0 |
| |
| return fCameraProfile.ParseTag (stream, |
| parentCode, |
| tagCode, |
| tagType, |
| tagCount, |
| tagOffset); |
| |
| } |
| |
| } |
| |
| return true; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| // Parses tags that should only appear in IFD 0 or EXIF IFD. |
| |
| bool dng_shared::Parse_ifd0_exif (dng_stream &stream, |
| dng_exif & /* exif */, |
| uint32 parentCode, |
| uint32 tagCode, |
| uint32 tagType, |
| uint32 tagCount, |
| uint64 tagOffset) |
| { |
| |
| switch (tagCode) |
| { |
| |
| case tcMakerNote: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttUndefined); |
| |
| fMakerNoteCount = tagCount; |
| fMakerNoteOffset = tagOffset; |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("MakerNote: Count = %u, Offset = %u\n", |
| (unsigned) fMakerNoteCount, |
| (unsigned) fMakerNoteOffset); |
| |
| DumpHexAscii (stream, tagCount); |
| |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| case tcInteroperabilityIFD: |
| { |
| |
| CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD); |
| |
| CheckTagCount (parentCode, tagCode, tagCount, 1); |
| |
| fInteroperabilityIFD = stream.TagValue_uint32 (tagType); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| printf ("InteroperabilityIFD: %u\n", (unsigned) fInteroperabilityIFD); |
| } |
| |
| #endif |
| |
| break; |
| |
| } |
| |
| default: |
| { |
| |
| return false; |
| |
| } |
| |
| } |
| |
| return true; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_shared::PostParse (dng_host & /* host */, |
| dng_exif & /* exif */) |
| { |
| |
| // Fill in default values for DNG images. |
| |
| if (fDNGVersion != 0) |
| { |
| |
| // Support for DNG versions before 1.0.0.0. |
| |
| if (fDNGVersion < dngVersion_1_0_0_0) |
| { |
| |
| #if qDNGValidate |
| |
| ReportWarning ("DNGVersion less than 1.0.0.0"); |
| |
| #endif |
| |
| // The CalibrationIlluminant tags were added just before |
| // DNG version 1.0.0.0, and were hardcoded before that. |
| |
| fCameraProfile.fCalibrationIlluminant1 = lsStandardLightA; |
| fCameraProfile.fCalibrationIlluminant2 = lsD65; |
| |
| fDNGVersion = dngVersion_1_0_0_0; |
| |
| } |
| |
| // Default value for DNGBackwardVersion tag. |
| |
| if (fDNGBackwardVersion == 0) |
| { |
| |
| fDNGBackwardVersion = fDNGVersion & 0xFFFF0000; |
| |
| } |
| |
| // Check DNGBackwardVersion value. |
| |
| if (fDNGBackwardVersion < dngVersion_1_0_0_0) |
| { |
| |
| #if qDNGValidate |
| |
| ReportWarning ("DNGBackwardVersion less than 1.0.0.0"); |
| |
| #endif |
| |
| fDNGBackwardVersion = dngVersion_1_0_0_0; |
| |
| } |
| |
| if (fDNGBackwardVersion > fDNGVersion) |
| { |
| |
| #if qDNGValidate |
| |
| ReportWarning ("DNGBackwardVersion > DNGVersion"); |
| |
| #endif |
| |
| fDNGBackwardVersion = fDNGVersion; |
| |
| } |
| |
| // Check UniqueCameraModel. |
| |
| if (fUniqueCameraModel.IsEmpty ()) |
| { |
| |
| #if qDNGValidate |
| |
| ReportWarning ("Missing or invalid UniqueCameraModel"); |
| |
| #endif |
| |
| fUniqueCameraModel.Set ("Digital Negative"); |
| |
| } |
| |
| // If we don't know the color depth yet, it must be a monochrome DNG. |
| |
| if (fCameraProfile.fColorPlanes == 0) |
| { |
| |
| fCameraProfile.fColorPlanes = 1; |
| |
| } |
| |
| // Check color info. |
| |
| if (fCameraProfile.fColorPlanes > 1) |
| { |
| |
| // Check illuminant pair. |
| |
| if (fCameraProfile.fColorMatrix2.NotEmpty ()) |
| { |
| |
| if (fCameraProfile.fCalibrationIlluminant1 == lsUnknown || |
| (fCameraProfile.fCalibrationIlluminant2 == lsUnknown || |
| (fCameraProfile.fCalibrationIlluminant1 == fCameraProfile.fCalibrationIlluminant2))) |
| { |
| |
| #if qDNGValidate |
| |
| ReportWarning ("Invalid CalibrationIlluminant pair"); |
| |
| #endif |
| |
| fCameraProfile.fColorMatrix2 = dng_matrix (); |
| |
| } |
| |
| } |
| |
| // If the colorimetric reference is the ICC profile PCS, then the |
| // data must already be white balanced. The "AsShotWhiteXY" is required |
| // to be the ICC Profile PCS white point. |
| |
| if (fColorimetricReference == crICCProfilePCS) |
| { |
| |
| if (fAsShotNeutral.NotEmpty ()) |
| { |
| |
| #if qDNGValidate |
| |
| ReportWarning ("AsShotNeutral not allowed for this " |
| "ColorimetricReference value"); |
| |
| #endif |
| |
| fAsShotNeutral.Clear (); |
| |
| } |
| |
| dng_xy_coord pcs = PCStoXY (); |
| |
| #if qDNGValidate |
| |
| if (fAsShotWhiteXY.IsValid ()) |
| { |
| |
| if (Abs_real64 (fAsShotWhiteXY.x - pcs.x) > 0.01 || |
| Abs_real64 (fAsShotWhiteXY.y - pcs.y) > 0.01) |
| { |
| |
| ReportWarning ("AsShotWhiteXY does not match the ICC Profile PCS"); |
| |
| } |
| |
| } |
| |
| #endif |
| |
| fAsShotWhiteXY = pcs; |
| |
| } |
| |
| else |
| { |
| |
| // Warn if both AsShotNeutral and AsShotWhiteXY are specified. |
| |
| if (fAsShotNeutral.NotEmpty () && fAsShotWhiteXY.IsValid ()) |
| { |
| |
| #if qDNGValidate |
| |
| ReportWarning ("Both AsShotNeutral and AsShotWhiteXY included"); |
| |
| #endif |
| |
| fAsShotWhiteXY = dng_xy_coord (); |
| |
| } |
| |
| // Warn if neither AsShotNeutral nor AsShotWhiteXY are specified. |
| |
| #if qDNGValidate |
| |
| if (fAsShotNeutral.IsEmpty () && !fAsShotWhiteXY.IsValid ()) |
| { |
| |
| ReportWarning ("Neither AsShotNeutral nor AsShotWhiteXY included", |
| "legal but not recommended"); |
| |
| } |
| |
| #endif |
| |
| } |
| |
| // Default values of calibration signatures are required for legacy |
| // compatiblity. |
| |
| if (fCameraProfile.fCalibrationIlluminant1 == lsStandardLightA && |
| fCameraProfile.fCalibrationIlluminant2 == lsD65 && |
| fCameraCalibration1.Rows () == fCameraProfile.fColorPlanes && |
| fCameraCalibration1.Cols () == fCameraProfile.fColorPlanes && |
| fCameraCalibration2.Rows () == fCameraProfile.fColorPlanes && |
| fCameraCalibration2.Cols () == fCameraProfile.fColorPlanes && |
| fCameraCalibrationSignature.IsEmpty () && |
| fCameraProfile.fProfileCalibrationSignature.IsEmpty () ) |
| { |
| |
| fCameraCalibrationSignature.Set (kAdobeCalibrationSignature); |
| |
| fCameraProfile.fProfileCalibrationSignature.Set (kAdobeCalibrationSignature); |
| |
| } |
| |
| } |
| |
| // Check BaselineNoise. |
| |
| if (fBaselineNoise.As_real64 () <= 0.0) |
| { |
| |
| #if qDNGValidate |
| |
| ReportWarning ("Invalid BaselineNoise"); |
| |
| #endif |
| |
| fBaselineNoise = dng_urational (1, 1); |
| |
| } |
| |
| // Check BaselineSharpness. |
| |
| if (fBaselineSharpness.As_real64 () <= 0.0) |
| { |
| |
| #if qDNGValidate |
| |
| ReportWarning ("Invalid BaselineSharpness"); |
| |
| #endif |
| |
| fBaselineSharpness = dng_urational (1, 1); |
| |
| } |
| |
| // Check NoiseProfile. |
| |
| if (!fNoiseProfile.IsValid () && fNoiseProfile.NumFunctions () != 0) |
| { |
| |
| #if qDNGValidate |
| |
| ReportWarning ("Invalid NoiseProfile"); |
| |
| #endif |
| |
| fNoiseProfile = dng_noise_profile (); |
| |
| } |
| |
| // Check LinearResponseLimit. |
| |
| if (fLinearResponseLimit.As_real64 () < 0.5 || |
| fLinearResponseLimit.As_real64 () > 1.0) |
| { |
| |
| #if qDNGValidate |
| |
| ReportWarning ("Invalid LinearResponseLimit"); |
| |
| #endif |
| |
| fLinearResponseLimit = dng_urational (1, 1); |
| |
| } |
| |
| // Check ShadowScale. |
| |
| if (fShadowScale.As_real64 () <= 0.0) |
| { |
| |
| #if qDNGValidate |
| |
| ReportWarning ("Invalid ShadowScale"); |
| |
| #endif |
| |
| fShadowScale = dng_urational (1, 1); |
| |
| } |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| bool dng_shared::IsValidDNG () |
| { |
| |
| // Check DNGVersion value. |
| |
| if (fDNGVersion < dngVersion_1_0_0_0) |
| { |
| |
| #if qDNGValidate |
| |
| if (fDNGVersion != dngVersion_None) |
| { |
| |
| ReportError ("Invalid DNGVersion"); |
| |
| } |
| |
| #if qDNGValidateTarget |
| |
| else |
| { |
| |
| ReportError ("Missing DNGVersion"); |
| |
| } |
| |
| #endif |
| |
| #endif |
| |
| return false; |
| |
| } |
| |
| // Check DNGBackwardVersion value. |
| |
| if (fDNGBackwardVersion > dngVersion_Current) |
| { |
| |
| #if qDNGValidate |
| |
| ReportError ("DNGBackwardVersion (or DNGVersion) is too high"); |
| |
| #endif |
| |
| ThrowUnsupportedDNG (); |
| |
| } |
| |
| // Check color transform info. |
| |
| if (fCameraProfile.fColorPlanes > 1) |
| { |
| |
| // CameraCalibration1 is optional, but it must be valid if present. |
| |
| if (fCameraCalibration1.Cols () != 0 || |
| fCameraCalibration1.Rows () != 0) |
| { |
| |
| if (fCameraCalibration1.Cols () != fCameraProfile.fColorPlanes || |
| fCameraCalibration1.Rows () != fCameraProfile.fColorPlanes) |
| { |
| |
| #if qDNGValidate |
| |
| ReportError ("CameraCalibration1 is wrong size"); |
| |
| #endif |
| |
| return false; |
| |
| } |
| |
| // Make sure it is invertable. |
| |
| try |
| { |
| |
| (void) Invert (fCameraCalibration1); |
| |
| } |
| |
| catch (...) |
| { |
| |
| #if qDNGValidate |
| |
| ReportError ("CameraCalibration1 is not invertable"); |
| |
| #endif |
| |
| return false; |
| |
| } |
| |
| } |
| |
| // CameraCalibration2 is optional, but it must be valid if present. |
| |
| if (fCameraCalibration2.Cols () != 0 || |
| fCameraCalibration2.Rows () != 0) |
| { |
| |
| if (fCameraCalibration2.Cols () != fCameraProfile.fColorPlanes || |
| fCameraCalibration2.Rows () != fCameraProfile.fColorPlanes) |
| { |
| |
| #if qDNGValidate |
| |
| ReportError ("CameraCalibration2 is wrong size"); |
| |
| #endif |
| |
| return false; |
| |
| } |
| |
| // Make sure it is invertable. |
| |
| try |
| { |
| |
| (void) Invert (fCameraCalibration2); |
| |
| } |
| |
| catch (...) |
| { |
| |
| #if qDNGValidate |
| |
| ReportError ("CameraCalibration2 is not invertable"); |
| |
| #endif |
| |
| return false; |
| |
| } |
| |
| } |
| |
| // Check analog balance |
| |
| dng_matrix analogBalance; |
| |
| if (fAnalogBalance.NotEmpty ()) |
| { |
| |
| analogBalance = fAnalogBalance.AsDiagonal (); |
| |
| try |
| { |
| |
| (void) Invert (analogBalance); |
| |
| } |
| |
| catch (...) |
| { |
| |
| #if qDNGValidate |
| |
| ReportError ("AnalogBalance is not invertable"); |
| |
| #endif |
| |
| return false; |
| |
| } |
| |
| } |
| |
| } |
| |
| return true; |
| |
| } |
| |
| /*****************************************************************************/ |