File indexing completed on 2025-01-19 03:55:16
0001 /*****************************************************************************/ 0002 // Copyright 2006-2019 Adobe Systems Incorporated 0003 // All Rights Reserved. 0004 // 0005 // NOTICE: Adobe permits you to use, modify, and distribute this file in 0006 // accordance with the terms of the Adobe license agreement accompanying it. 0007 /*****************************************************************************/ 0008 0009 #include "dng_shared.h" 0010 0011 #include "dng_camera_profile.h" 0012 #include "dng_exceptions.h" 0013 #include "dng_globals.h" 0014 #include "dng_memory.h" 0015 #include "dng_parse_utils.h" 0016 #include "dng_tag_codes.h" 0017 #include "dng_tag_types.h" 0018 #include "dng_tag_values.h" 0019 #include "dng_utils.h" 0020 0021 /*****************************************************************************/ 0022 0023 dng_camera_profile_info::dng_camera_profile_info () 0024 0025 : fBigEndian (false) 0026 0027 , fColorPlanes (0) 0028 0029 , fCalibrationIlluminant1 (lsUnknown) 0030 , fCalibrationIlluminant2 (lsUnknown) 0031 0032 , fColorMatrix1 () 0033 , fColorMatrix2 () 0034 0035 , fForwardMatrix1 () 0036 , fForwardMatrix2 () 0037 0038 , fReductionMatrix1 () 0039 , fReductionMatrix2 () 0040 0041 , fProfileCalibrationSignature () 0042 0043 , fProfileName () 0044 0045 , fProfileCopyright () 0046 0047 , fEmbedPolicy (pepAllowCopying) 0048 0049 , fProfileHues (0) 0050 , fProfileSats (0) 0051 , fProfileVals (0) 0052 0053 , fHueSatDeltas1Offset (0) 0054 , fHueSatDeltas1Count (0) 0055 0056 , fHueSatDeltas2Offset (0) 0057 , fHueSatDeltas2Count (0) 0058 0059 , fHueSatMapEncoding (encoding_Linear) 0060 0061 , fLookTableHues (0) 0062 , fLookTableSats (0) 0063 , fLookTableVals (0) 0064 0065 , fLookTableOffset (0) 0066 , fLookTableCount (0) 0067 0068 , fLookTableEncoding (encoding_Linear) 0069 0070 , fBaselineExposureOffset (0, 100) 0071 0072 , fDefaultBlackRender (defaultBlackRender_Auto) 0073 0074 , fToneCurveOffset (0) 0075 , fToneCurveCount (0) 0076 0077 , fUniqueCameraModel () 0078 0079 { 0080 0081 } 0082 0083 /*****************************************************************************/ 0084 0085 dng_camera_profile_info::~dng_camera_profile_info () 0086 { 0087 0088 } 0089 0090 /*****************************************************************************/ 0091 0092 DNG_ATTRIB_NO_SANITIZE("unsigned-integer-overflow") 0093 bool dng_camera_profile_info::ParseTag (dng_stream &stream, 0094 uint32 parentCode, 0095 uint32 tagCode, 0096 uint32 tagType, 0097 uint32 tagCount, 0098 uint64 tagOffset) 0099 { 0100 0101 switch (tagCode) 0102 { 0103 0104 case tcCalibrationIlluminant1: 0105 { 0106 0107 CheckTagType (parentCode, tagCode, tagType, ttShort); 0108 0109 CheckTagCount (parentCode, tagCode, tagCount, 1); 0110 0111 fCalibrationIlluminant1 = stream.TagValue_uint32 (tagType); 0112 0113 #if qDNGValidate 0114 0115 if (gVerbose) 0116 { 0117 0118 printf ("CalibrationIlluminant1: %s\n", 0119 LookupLightSource (fCalibrationIlluminant1)); 0120 0121 } 0122 0123 #endif 0124 0125 break; 0126 0127 } 0128 0129 case tcCalibrationIlluminant2: 0130 { 0131 0132 CheckTagType (parentCode, tagCode, tagType, ttShort); 0133 0134 CheckTagCount (parentCode, tagCode, tagCount, 1); 0135 0136 fCalibrationIlluminant2 = stream.TagValue_uint32 (tagType); 0137 0138 #if qDNGValidate 0139 0140 if (gVerbose) 0141 { 0142 0143 printf ("CalibrationIlluminant2: %s\n", 0144 LookupLightSource (fCalibrationIlluminant2)); 0145 0146 } 0147 0148 #endif 0149 0150 break; 0151 0152 } 0153 0154 case tcColorMatrix1: 0155 { 0156 0157 CheckTagType (parentCode, tagCode, tagType, ttSRational); 0158 0159 if (fColorPlanes == 0) 0160 { 0161 0162 fColorPlanes = Pin_uint32 (0, tagCount / 3, kMaxColorPlanes); 0163 0164 } 0165 0166 if (!CheckColorImage (parentCode, tagCode, fColorPlanes)) 0167 return false; 0168 0169 if (!ParseMatrixTag (stream, 0170 parentCode, 0171 tagCode, 0172 tagType, 0173 tagCount, 0174 fColorPlanes, 0175 3, 0176 fColorMatrix1)) 0177 return false; 0178 0179 #if qDNGValidate 0180 0181 if (gVerbose) 0182 { 0183 0184 printf ("ColorMatrix1:\n"); 0185 0186 DumpMatrix (fColorMatrix1); 0187 0188 } 0189 0190 #endif 0191 0192 break; 0193 0194 } 0195 0196 case tcColorMatrix2: 0197 { 0198 0199 CheckTagType (parentCode, tagCode, tagType, ttSRational); 0200 0201 // Kludge - Hasselblad FFF files are very DNG-like, but sometimes 0202 // only have a ColorMatrix2 tag and no ColorMatrix1 tag. 0203 0204 bool hasselbladHack = (fColorPlanes == 0); 0205 0206 if (hasselbladHack) 0207 { 0208 0209 fColorPlanes = Pin_uint32 (0, tagCount / 3, kMaxColorPlanes); 0210 0211 #if qDNGValidate 0212 0213 ReportWarning ("ColorMatrix2 without ColorMatrix1"); 0214 0215 #endif 0216 0217 } 0218 0219 if (!CheckColorImage (parentCode, tagCode, fColorPlanes)) 0220 return false; 0221 0222 if (!ParseMatrixTag (stream, 0223 parentCode, 0224 tagCode, 0225 tagType, 0226 tagCount, 0227 fColorPlanes, 0228 3, 0229 fColorMatrix2)) 0230 return false; 0231 0232 #if qDNGValidate 0233 0234 if (gVerbose) 0235 { 0236 0237 printf ("ColorMatrix2:\n"); 0238 0239 DumpMatrix (fColorMatrix2); 0240 0241 } 0242 0243 #endif 0244 0245 if (hasselbladHack) 0246 { 0247 0248 fColorMatrix1 = fColorMatrix2; 0249 0250 fColorMatrix2 = dng_matrix (); 0251 0252 } 0253 0254 break; 0255 0256 } 0257 0258 case tcForwardMatrix1: 0259 { 0260 0261 CheckTagType (parentCode, tagCode, tagType, ttSRational); 0262 0263 if (!CheckColorImage (parentCode, tagCode, fColorPlanes)) 0264 return false; 0265 0266 if (!ParseMatrixTag (stream, 0267 parentCode, 0268 tagCode, 0269 tagType, 0270 tagCount, 0271 3, 0272 fColorPlanes, 0273 fForwardMatrix1)) 0274 return false; 0275 0276 #if qDNGValidate 0277 0278 if (gVerbose) 0279 { 0280 0281 printf ("ForwardMatrix1:\n"); 0282 0283 DumpMatrix (fForwardMatrix1); 0284 0285 } 0286 0287 #endif 0288 0289 break; 0290 0291 } 0292 0293 case tcForwardMatrix2: 0294 { 0295 0296 CheckTagType (parentCode, tagCode, tagType, ttSRational); 0297 0298 if (!CheckColorImage (parentCode, tagCode, fColorPlanes)) 0299 return false; 0300 0301 if (!ParseMatrixTag (stream, 0302 parentCode, 0303 tagCode, 0304 tagType, 0305 tagCount, 0306 3, 0307 fColorPlanes, 0308 fForwardMatrix2)) 0309 return false; 0310 0311 #if qDNGValidate 0312 0313 if (gVerbose) 0314 { 0315 0316 printf ("ForwardMatrix2:\n"); 0317 0318 DumpMatrix (fForwardMatrix2); 0319 0320 } 0321 0322 #endif 0323 0324 break; 0325 0326 } 0327 0328 case tcReductionMatrix1: 0329 { 0330 0331 CheckTagType (parentCode, tagCode, tagType, ttSRational); 0332 0333 if (!CheckColorImage (parentCode, tagCode, fColorPlanes)) 0334 return false; 0335 0336 if (!ParseMatrixTag (stream, 0337 parentCode, 0338 tagCode, 0339 tagType, 0340 tagCount, 0341 3, 0342 fColorPlanes, 0343 fReductionMatrix1)) 0344 return false; 0345 0346 #if qDNGValidate 0347 0348 if (gVerbose) 0349 { 0350 0351 printf ("ReductionMatrix1:\n"); 0352 0353 DumpMatrix (fReductionMatrix1); 0354 0355 } 0356 0357 #endif 0358 0359 break; 0360 0361 } 0362 0363 case tcReductionMatrix2: 0364 { 0365 0366 CheckTagType (parentCode, tagCode, tagType, ttSRational); 0367 0368 if (!CheckColorImage (parentCode, tagCode, fColorPlanes)) 0369 return false; 0370 0371 if (!ParseMatrixTag (stream, 0372 parentCode, 0373 tagCode, 0374 tagType, 0375 tagCount, 0376 3, 0377 fColorPlanes, 0378 fReductionMatrix2)) 0379 return false; 0380 0381 #if qDNGValidate 0382 0383 if (gVerbose) 0384 { 0385 0386 printf ("ReductionMatrix2:\n"); 0387 0388 DumpMatrix (fReductionMatrix2); 0389 0390 } 0391 0392 #endif 0393 0394 break; 0395 0396 } 0397 0398 case tcProfileCalibrationSignature: 0399 { 0400 0401 CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); 0402 0403 ParseStringTag (stream, 0404 parentCode, 0405 tagCode, 0406 tagCount, 0407 fProfileCalibrationSignature, 0408 false); 0409 0410 #if qDNGValidate 0411 0412 if (gVerbose) 0413 { 0414 0415 printf ("ProfileCalibrationSignature: "); 0416 0417 DumpString (fProfileCalibrationSignature); 0418 0419 printf ("\n"); 0420 0421 } 0422 0423 #endif 0424 0425 break; 0426 0427 } 0428 0429 case tcProfileName: 0430 { 0431 0432 CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); 0433 0434 ParseStringTag (stream, 0435 parentCode, 0436 tagCode, 0437 tagCount, 0438 fProfileName, 0439 false); 0440 0441 #if qDNGValidate 0442 0443 if (gVerbose) 0444 { 0445 0446 printf ("ProfileName: "); 0447 0448 DumpString (fProfileName); 0449 0450 printf ("\n"); 0451 0452 } 0453 0454 #endif 0455 0456 break; 0457 0458 } 0459 0460 case tcProfileCopyright: 0461 { 0462 0463 CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); 0464 0465 ParseStringTag (stream, 0466 parentCode, 0467 tagCode, 0468 tagCount, 0469 fProfileCopyright, 0470 false); 0471 0472 #if qDNGValidate 0473 0474 if (gVerbose) 0475 { 0476 0477 printf ("ProfileCopyright: "); 0478 0479 DumpString (fProfileCopyright); 0480 0481 printf ("\n"); 0482 0483 } 0484 0485 #endif 0486 0487 break; 0488 0489 } 0490 0491 case tcProfileEmbedPolicy: 0492 { 0493 0494 CheckTagType (parentCode, tagCode, tagType, ttLong); 0495 0496 CheckTagCount (parentCode, tagCode, tagCount, 1); 0497 0498 fEmbedPolicy = stream.TagValue_uint32 (tagType); 0499 0500 #if qDNGValidate 0501 0502 if (gVerbose) 0503 { 0504 0505 const char *policy; 0506 0507 switch (fEmbedPolicy) 0508 { 0509 0510 case pepAllowCopying: 0511 policy = "Allow copying"; 0512 break; 0513 0514 case pepEmbedIfUsed: 0515 policy = "Embed if used"; 0516 break; 0517 0518 case pepEmbedNever: 0519 policy = "Embed never"; 0520 break; 0521 0522 case pepNoRestrictions: 0523 policy = "No restrictions"; 0524 break; 0525 0526 default: 0527 policy = "INVALID VALUE"; 0528 0529 } 0530 0531 printf ("ProfileEmbedPolicy: %s\n", policy); 0532 0533 } 0534 0535 #endif 0536 0537 break; 0538 0539 } 0540 0541 case tcProfileHueSatMapDims: 0542 { 0543 0544 CheckTagType (parentCode, tagCode, tagType, ttLong); 0545 0546 CheckTagCount (parentCode, tagCode, tagCount, 2, 3); 0547 0548 fProfileHues = stream.TagValue_uint32 (tagType); 0549 fProfileSats = stream.TagValue_uint32 (tagType); 0550 0551 if (tagCount > 2) 0552 fProfileVals = stream.TagValue_uint32 (tagType); 0553 else 0554 fProfileVals = 1; 0555 0556 #if qDNGValidate 0557 0558 if (gVerbose) 0559 { 0560 0561 printf ("ProfileHueSatMapDims: Hues = %u, Sats = %u, Vals = %u\n", 0562 (unsigned) fProfileHues, 0563 (unsigned) fProfileSats, 0564 (unsigned) fProfileVals); 0565 0566 } 0567 0568 #endif 0569 0570 break; 0571 0572 } 0573 0574 case tcProfileHueSatMapData1: 0575 { 0576 0577 if (!CheckTagType (parentCode, tagCode, tagType, ttFloat)) 0578 return false; 0579 0580 if (fProfileSats == 0) 0581 return false; 0582 0583 dng_safe_uint32 hueCount (fProfileHues); 0584 dng_safe_uint32 valCount (fProfileVals); 0585 0586 bool skipSat0 = (tagCount == (hueCount * 0587 (fProfileSats - 1) * 0588 (valCount * 3u)).Get ()); 0589 0590 if (!skipSat0) 0591 { 0592 0593 dng_safe_uint32 expected = hueCount * valCount * fProfileSats * 3u; 0594 0595 if (!CheckTagCount (parentCode, 0596 tagCode, 0597 tagCount, 0598 expected.Get ())) 0599 { 0600 return false; 0601 } 0602 0603 } 0604 0605 fBigEndian = stream.BigEndian (); 0606 0607 fHueSatDeltas1Offset = tagOffset; 0608 fHueSatDeltas1Count = tagCount; 0609 0610 #if qDNGValidate 0611 0612 if (gVerbose) 0613 { 0614 0615 printf ("ProfileHueSatMapData1:\n"); 0616 0617 DumpHueSatMap (stream, 0618 fProfileHues, 0619 fProfileSats, 0620 fProfileVals, 0621 skipSat0); 0622 0623 } 0624 0625 #endif 0626 0627 break; 0628 0629 } 0630 0631 case tcProfileHueSatMapData2: 0632 { 0633 0634 if (!CheckTagType (parentCode, tagCode, tagType, ttFloat)) 0635 return false; 0636 0637 if (fProfileSats == 0) 0638 return false; 0639 0640 dng_safe_uint32 hueCount (fProfileHues); 0641 dng_safe_uint32 valCount (fProfileVals); 0642 0643 bool skipSat0 = (tagCount == (hueCount * 0644 (fProfileSats - 1) * 0645 (valCount * 3u)).Get ()); 0646 0647 if (!skipSat0) 0648 { 0649 0650 dng_safe_uint32 expected = hueCount * valCount * fProfileSats * 3u; 0651 0652 if (!CheckTagCount (parentCode, 0653 tagCode, 0654 tagCount, 0655 expected.Get ())) 0656 { 0657 return false; 0658 } 0659 0660 } 0661 0662 fBigEndian = stream.BigEndian (); 0663 0664 fHueSatDeltas2Offset = tagOffset; 0665 fHueSatDeltas2Count = tagCount; 0666 0667 #if qDNGValidate 0668 0669 if (gVerbose) 0670 { 0671 0672 printf ("ProfileHueSatMapData2:\n"); 0673 0674 DumpHueSatMap (stream, 0675 fProfileHues, 0676 fProfileSats, 0677 fProfileVals, 0678 skipSat0); 0679 0680 } 0681 0682 #endif 0683 0684 break; 0685 0686 } 0687 0688 case tcProfileHueSatMapEncoding: 0689 { 0690 0691 CheckTagType (parentCode, tagCode, tagType, ttLong); 0692 0693 CheckTagCount (parentCode, tagCode, tagCount, 1); 0694 0695 fHueSatMapEncoding = stream.TagValue_uint32 (tagType); 0696 0697 #if qDNGValidate 0698 0699 if (gVerbose) 0700 { 0701 0702 const char *encoding = NULL; 0703 0704 switch (fHueSatMapEncoding) 0705 { 0706 0707 case encoding_Linear: 0708 encoding = "Linear"; 0709 break; 0710 0711 case encoding_sRGB: 0712 encoding = "sRGB"; 0713 break; 0714 0715 default: 0716 encoding = "INVALID VALUE"; 0717 0718 } 0719 0720 printf ("ProfileHueSatMapEncoding: %s\n", encoding); 0721 0722 } 0723 0724 #endif 0725 0726 break; 0727 0728 } 0729 0730 case tcProfileLookTableDims: 0731 { 0732 0733 CheckTagType (parentCode, tagCode, tagType, ttLong); 0734 0735 CheckTagCount (parentCode, tagCode, tagCount, 2, 3); 0736 0737 fLookTableHues = stream.TagValue_uint32 (tagType); 0738 fLookTableSats = stream.TagValue_uint32 (tagType); 0739 0740 if (tagCount > 2) 0741 fLookTableVals = stream.TagValue_uint32 (tagType); 0742 else 0743 fLookTableVals = 1; 0744 0745 #if qDNGValidate 0746 0747 if (gVerbose) 0748 { 0749 0750 printf ("ProfileLookTableDims: Hues = %u, Sats = %u, Vals = %u\n", 0751 (unsigned) fLookTableHues, 0752 (unsigned) fLookTableSats, 0753 (unsigned) fLookTableVals); 0754 0755 } 0756 0757 #endif 0758 0759 break; 0760 0761 } 0762 0763 case tcProfileLookTableData: 0764 { 0765 0766 if (!CheckTagType (parentCode, tagCode, tagType, ttFloat)) 0767 return false; 0768 0769 if (fLookTableSats == 0) 0770 return false; 0771 0772 dng_safe_uint32 hueCount (fLookTableHues); 0773 dng_safe_uint32 valCount (fLookTableVals); 0774 0775 bool skipSat0 = (tagCount == (hueCount * 0776 (fLookTableSats - 1) * 0777 valCount * 3u).Get ()); 0778 0779 if (!skipSat0) 0780 { 0781 0782 dng_safe_uint32 expected = hueCount * valCount * fLookTableSats * 3u; 0783 0784 if (!CheckTagCount (parentCode, 0785 tagCode, 0786 tagCount, 0787 expected.Get ())) 0788 { 0789 return false; 0790 } 0791 0792 } 0793 0794 fBigEndian = stream.BigEndian (); 0795 0796 fLookTableOffset = tagOffset; 0797 fLookTableCount = tagCount; 0798 0799 #if qDNGValidate 0800 0801 if (gVerbose) 0802 { 0803 0804 printf ("ProfileLookTableData:\n"); 0805 0806 DumpHueSatMap (stream, 0807 fLookTableHues, 0808 fLookTableSats, 0809 fLookTableVals, 0810 skipSat0); 0811 0812 } 0813 0814 #endif 0815 0816 break; 0817 0818 } 0819 0820 case tcProfileLookTableEncoding: 0821 { 0822 0823 CheckTagType (parentCode, tagCode, tagType, ttLong); 0824 0825 CheckTagCount (parentCode, tagCode, tagCount, 1); 0826 0827 fLookTableEncoding = stream.TagValue_uint32 (tagType); 0828 0829 #if qDNGValidate 0830 0831 if (gVerbose) 0832 { 0833 0834 const char *encoding = NULL; 0835 0836 switch (fLookTableEncoding) 0837 { 0838 0839 case encoding_Linear: 0840 encoding = "Linear"; 0841 break; 0842 0843 case encoding_sRGB: 0844 encoding = "sRGB"; 0845 break; 0846 0847 default: 0848 encoding = "INVALID VALUE"; 0849 0850 } 0851 0852 printf ("ProfileLookTableEncoding: %s\n", encoding); 0853 0854 } 0855 0856 #endif 0857 0858 break; 0859 0860 } 0861 0862 case tcBaselineExposureOffset: 0863 { 0864 0865 CheckTagType (parentCode, tagCode, tagType, ttSRational); 0866 0867 CheckTagCount (parentCode, tagCode, tagCount, 1); 0868 0869 fBaselineExposureOffset = stream.TagValue_srational (tagType); 0870 0871 #if qDNGValidate 0872 0873 if (gVerbose) 0874 { 0875 0876 printf ("BaselineExposureOffset: %+0.2f\n", 0877 fBaselineExposureOffset.As_real64 ()); 0878 0879 } 0880 0881 #endif 0882 0883 break; 0884 0885 } 0886 0887 case tcDefaultBlackRender: 0888 { 0889 0890 CheckTagType (parentCode, tagCode, tagType, ttLong); 0891 0892 CheckTagCount (parentCode, tagCode, tagCount, 1); 0893 0894 fDefaultBlackRender = stream.TagValue_uint32 (tagType); 0895 0896 #if qDNGValidate 0897 0898 if (gVerbose) 0899 { 0900 0901 const char *setting = NULL; 0902 0903 switch (fDefaultBlackRender) 0904 { 0905 0906 case defaultBlackRender_Auto: 0907 setting = "Auto"; 0908 break; 0909 0910 case defaultBlackRender_None: 0911 setting = "None"; 0912 break; 0913 0914 default: 0915 setting = "INVALID VALUE"; 0916 0917 } 0918 0919 printf ("DefaultBlackRender: %s\n", 0920 setting); 0921 0922 } 0923 0924 #endif 0925 0926 break; 0927 0928 } 0929 0930 case tcProfileToneCurve: 0931 { 0932 0933 if (!CheckTagType (parentCode, tagCode, tagType, ttFloat)) 0934 return false; 0935 0936 if (!CheckTagCount (parentCode, tagCode, tagCount, 4, tagCount)) 0937 return false; 0938 0939 if ((tagCount & 1) != 0) 0940 { 0941 0942 #if qDNGValidate 0943 0944 { 0945 0946 char message [256]; 0947 0948 sprintf (message, 0949 "%s %s has odd count (%u)", 0950 LookupParentCode (parentCode), 0951 LookupTagCode (parentCode, tagCode), 0952 (unsigned) tagCount); 0953 0954 ReportWarning (message); 0955 0956 } 0957 0958 #endif 0959 0960 return false; 0961 0962 } 0963 0964 fBigEndian = stream.BigEndian (); 0965 0966 fToneCurveOffset = tagOffset; 0967 fToneCurveCount = tagCount; 0968 0969 #if qDNGValidate 0970 0971 if (gVerbose) 0972 { 0973 0974 DumpTagValues (stream, 0975 "Coord", 0976 parentCode, 0977 tagCode, 0978 tagType, 0979 tagCount); 0980 0981 0982 } 0983 0984 #endif 0985 0986 break; 0987 0988 } 0989 0990 case tcUniqueCameraModel: 0991 { 0992 0993 // Note: This code is only used when parsing stand-alone 0994 // profiles. The embedded profiles are assumed to be restricted 0995 // to the model they are embedded in. 0996 0997 CheckTagType (parentCode, tagCode, tagType, ttAscii); 0998 0999 ParseStringTag (stream, 1000 parentCode, 1001 tagCode, 1002 tagCount, 1003 fUniqueCameraModel, 1004 false); 1005 1006 bool didTrim = fUniqueCameraModel.TrimTrailingBlanks (); 1007 1008 #if qDNGValidate 1009 1010 if (didTrim) 1011 { 1012 1013 ReportWarning ("UniqueCameraModel string has trailing blanks"); 1014 1015 } 1016 1017 if (gVerbose) 1018 { 1019 1020 printf ("UniqueCameraModel: "); 1021 1022 DumpString (fUniqueCameraModel); 1023 1024 printf ("\n"); 1025 1026 } 1027 1028 #else 1029 1030 (void) didTrim; // Unused 1031 1032 #endif 1033 1034 break; 1035 1036 } 1037 1038 default: 1039 { 1040 1041 return false; 1042 1043 } 1044 1045 } 1046 1047 return true; 1048 1049 } 1050 1051 /*****************************************************************************/ 1052 1053 bool dng_camera_profile_info::ParseExtended (dng_stream &stream) 1054 { 1055 1056 try 1057 { 1058 1059 // Offsets are relative to the start of this structure, not the entire file. 1060 1061 uint64 startPosition = stream.Position (); 1062 1063 // Read header. Like a TIFF header, but with different magic number 1064 // Plus all offsets are relative to the start of the IFD, not to the 1065 // stream or file. 1066 1067 uint16 byteOrder = stream.Get_uint16 (); 1068 1069 if (byteOrder == byteOrderMM) 1070 fBigEndian = true; 1071 1072 else if (byteOrder == byteOrderII) 1073 fBigEndian = false; 1074 1075 else 1076 return false; 1077 1078 TempBigEndian setEndianness (stream, fBigEndian); 1079 1080 uint16 magicNumber = stream.Get_uint16 (); 1081 1082 if (magicNumber != magicExtendedProfile) 1083 { 1084 return false; 1085 } 1086 1087 uint32 offset = stream.Get_uint32 (); 1088 1089 stream.Skip (offset - 8); 1090 1091 // Start on IFD entries. 1092 1093 uint32 ifdEntries = stream.Get_uint16 (); 1094 1095 if (ifdEntries < 1) 1096 { 1097 return false; 1098 } 1099 1100 for (uint32 tag_index = 0; tag_index < ifdEntries; tag_index++) 1101 { 1102 1103 stream.SetReadPosition (startPosition + 8 + 2 + tag_index * 12); 1104 1105 uint16 tagCode = stream.Get_uint16 (); 1106 uint32 tagType = stream.Get_uint16 (); 1107 uint32 tagCount = stream.Get_uint32 (); 1108 1109 uint64 tagOffset = stream.Position (); 1110 1111 if (TagTypeSize (tagType) * tagCount > 4) 1112 { 1113 1114 tagOffset = startPosition + stream.Get_uint32 (); 1115 1116 stream.SetReadPosition (tagOffset); 1117 1118 } 1119 1120 if (!ParseTag (stream, 1121 0, 1122 tagCode, 1123 tagType, 1124 tagCount, 1125 tagOffset)) 1126 { 1127 1128 #if qDNGValidate 1129 1130 if (gVerbose) 1131 { 1132 1133 stream.SetReadPosition (tagOffset); 1134 1135 printf ("*"); 1136 1137 DumpTagValues (stream, 1138 LookupTagType (tagType), 1139 0, 1140 tagCode, 1141 tagType, 1142 tagCount); 1143 1144 } 1145 1146 #endif 1147 1148 } 1149 1150 } 1151 1152 return true; 1153 1154 } 1155 1156 catch (...) 1157 { 1158 1159 // Eat parsing errors. 1160 1161 } 1162 1163 return false; 1164 1165 } 1166 1167 /*****************************************************************************/ 1168 1169 dng_shared::dng_shared () 1170 1171 : fExifIFD (0) 1172 , fGPSInfo (0) 1173 , fInteroperabilityIFD (0) 1174 , fKodakDCRPrivateIFD (0) 1175 , fKodakKDCPrivateIFD (0) 1176 1177 , fXMPCount (0) 1178 , fXMPOffset (0) 1179 1180 , fIPTC_NAA_Count (0) 1181 , fIPTC_NAA_Offset (0) 1182 1183 , fMakerNoteCount (0) 1184 , fMakerNoteOffset (0) 1185 , fMakerNoteSafety (0) 1186 1187 , fDNGVersion (0) 1188 , fDNGBackwardVersion (0) 1189 1190 , fUniqueCameraModel () 1191 , fLocalizedCameraModel () 1192 1193 , fCameraProfile () 1194 1195 , fExtraCameraProfiles () 1196 1197 , fCameraCalibration1 () 1198 , fCameraCalibration2 () 1199 1200 , fCameraCalibrationSignature () 1201 1202 , fAnalogBalance () 1203 1204 , fAsShotNeutral () 1205 1206 , fAsShotWhiteXY () 1207 1208 , fBaselineExposure (0, 1) 1209 , fBaselineNoise (1, 1) 1210 , fBaselineSharpness (1, 1) 1211 , fLinearResponseLimit (1, 1) 1212 , fShadowScale (1, 1) 1213 1214 , fHasBaselineExposure (false) 1215 , fHasShadowScale (false) 1216 1217 , fDNGPrivateDataCount (0) 1218 , fDNGPrivateDataOffset (0) 1219 1220 , fRawImageDigest () 1221 , fNewRawImageDigest () 1222 1223 , fRawDataUniqueID () 1224 1225 , fOriginalRawFileName () 1226 1227 , fOriginalRawFileDataCount (0) 1228 , fOriginalRawFileDataOffset (0) 1229 1230 , fOriginalRawFileDigest () 1231 1232 , fAsShotICCProfileCount (0) 1233 , fAsShotICCProfileOffset (0) 1234 1235 , fAsShotPreProfileMatrix () 1236 1237 , fCurrentICCProfileCount (0) 1238 , fCurrentICCProfileOffset (0) 1239 1240 , fCurrentPreProfileMatrix () 1241 1242 , fColorimetricReference (crSceneReferred) 1243 1244 , fAsShotProfileName () 1245 1246 , fOriginalDefaultFinalSize () 1247 , fOriginalBestQualityFinalSize () 1248 1249 , fOriginalDefaultCropSizeH () 1250 , fOriginalDefaultCropSizeV () 1251 1252 , fDepthFormat (depthFormatUnknown) 1253 , fDepthNear (0, 0) 1254 , fDepthFar (0, 0) 1255 , fDepthUnits (depthUnitsUnknown) 1256 , fDepthMeasureType (depthMeasureUnknown) 1257 1258 { 1259 1260 } 1261 1262 /*****************************************************************************/ 1263 1264 dng_shared::~dng_shared () 1265 { 1266 1267 } 1268 1269 /*****************************************************************************/ 1270 1271 bool dng_shared::ParseTag (dng_stream &stream, 1272 dng_exif &exif, 1273 uint32 parentCode, 1274 bool /* isMainIFD */, 1275 uint32 tagCode, 1276 uint32 tagType, 1277 uint32 tagCount, 1278 uint64 tagOffset, 1279 int64 /* offsetDelta */) 1280 { 1281 1282 if (parentCode == 0) 1283 { 1284 1285 if (Parse_ifd0 (stream, 1286 exif, 1287 parentCode, 1288 tagCode, 1289 tagType, 1290 tagCount, 1291 tagOffset)) 1292 { 1293 1294 return true; 1295 1296 } 1297 1298 } 1299 1300 if (parentCode == 0 || 1301 parentCode == tcExifIFD) 1302 { 1303 1304 if (Parse_ifd0_exif (stream, 1305 exif, 1306 parentCode, 1307 tagCode, 1308 tagType, 1309 tagCount, 1310 tagOffset)) 1311 { 1312 1313 return true; 1314 1315 } 1316 1317 } 1318 1319 return false; 1320 1321 } 1322 1323 /*****************************************************************************/ 1324 1325 // Parses tags that should only appear in IFD 0. 1326 1327 bool dng_shared::Parse_ifd0 (dng_stream &stream, 1328 dng_exif & /* exif */, 1329 uint32 parentCode, 1330 uint32 tagCode, 1331 uint32 tagType, 1332 uint32 tagCount, 1333 uint64 tagOffset) 1334 { 1335 1336 switch (tagCode) 1337 { 1338 1339 case tcXMP: 1340 { 1341 1342 CheckTagType (parentCode, tagCode, tagType, ttByte, ttUndefined); 1343 1344 fXMPCount = tagCount; 1345 fXMPOffset = fXMPCount ? tagOffset : 0; 1346 1347 #if qDNGValidate 1348 1349 if (gVerbose) 1350 { 1351 1352 printf ("XMP: Count = %u, Offset = %u\n", 1353 (unsigned) fXMPCount, 1354 (unsigned) fXMPOffset); 1355 1356 if (fXMPCount) 1357 { 1358 1359 DumpXMP (stream, fXMPCount); 1360 1361 } 1362 1363 } 1364 1365 #endif 1366 1367 break; 1368 1369 } 1370 1371 case tcIPTC_NAA: 1372 { 1373 1374 CheckTagType (parentCode, tagCode, tagType, ttLong, ttAscii, ttUndefined); 1375 1376 fIPTC_NAA_Count = (dng_safe_uint32 (tagCount) * TagTypeSize (tagType)).Get (); 1377 fIPTC_NAA_Offset = fIPTC_NAA_Count ? tagOffset : 0; 1378 1379 #if qDNGValidate 1380 1381 if (gVerbose) 1382 { 1383 1384 printf ("IPTC/NAA: Count = %u, Offset = %u\n", 1385 (unsigned) fIPTC_NAA_Count, 1386 (unsigned) fIPTC_NAA_Offset); 1387 1388 if (fIPTC_NAA_Count) 1389 { 1390 1391 DumpHexAscii (stream, fIPTC_NAA_Count); 1392 1393 } 1394 1395 // Compute and output the digest. 1396 1397 dng_memory_data buffer (fIPTC_NAA_Count); 1398 1399 stream.SetReadPosition (fIPTC_NAA_Offset); 1400 1401 stream.Get (buffer.Buffer (), fIPTC_NAA_Count); 1402 1403 const uint8 *data = buffer.Buffer_uint8 (); 1404 1405 uint32 count = fIPTC_NAA_Count; 1406 1407 // Method 1: Counting all bytes (this is correct). 1408 1409 { 1410 1411 dng_md5_printer printer; 1412 1413 printer.Process (data, count); 1414 1415 printf ("IPTCDigest: "); 1416 1417 DumpFingerprint (printer.Result ()); 1418 1419 printf ("\n"); 1420 1421 } 1422 1423 // Method 2: Ignoring zero padding. 1424 1425 { 1426 1427 uint32 removed = 0; 1428 1429 while ((removed < 3) && (count > 0) && (data [count - 1] == 0)) 1430 { 1431 removed++; 1432 count--; 1433 } 1434 1435 if (removed != 0) 1436 { 1437 1438 dng_md5_printer printer; 1439 1440 printer.Process (data, count); 1441 1442 printf ("IPTCDigest (ignoring zero padding): "); 1443 1444 DumpFingerprint (printer.Result ()); 1445 1446 printf ("\n"); 1447 1448 } 1449 1450 } 1451 1452 } 1453 1454 #endif 1455 1456 break; 1457 1458 } 1459 1460 case tcExifIFD: 1461 { 1462 1463 CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD); 1464 1465 CheckTagCount (parentCode, tagCode, tagCount, 1); 1466 1467 fExifIFD = stream.TagValue_uint32 (tagType); 1468 1469 #if qDNGValidate 1470 1471 if (gVerbose) 1472 { 1473 printf ("ExifIFD: %u\n", (unsigned) fExifIFD); 1474 } 1475 1476 #endif 1477 1478 break; 1479 1480 } 1481 1482 case tcGPSInfo: 1483 { 1484 1485 CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD); 1486 1487 CheckTagCount (parentCode, tagCode, tagCount, 1); 1488 1489 fGPSInfo = stream.TagValue_uint32 (tagType); 1490 1491 #if qDNGValidate 1492 1493 if (gVerbose) 1494 { 1495 printf ("GPSInfo: %u\n", (unsigned) fGPSInfo); 1496 } 1497 1498 #endif 1499 1500 break; 1501 1502 } 1503 1504 case tcKodakDCRPrivateIFD: 1505 { 1506 1507 CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD); 1508 1509 CheckTagCount (parentCode, tagCode, tagCount, 1); 1510 1511 fKodakDCRPrivateIFD = stream.TagValue_uint32 (tagType); 1512 1513 #if qDNGValidate 1514 1515 if (gVerbose) 1516 { 1517 printf ("KodakDCRPrivateIFD: %u\n", (unsigned) fKodakDCRPrivateIFD); 1518 } 1519 1520 #endif 1521 1522 break; 1523 1524 } 1525 1526 case tcKodakKDCPrivateIFD: 1527 { 1528 1529 CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD); 1530 1531 CheckTagCount (parentCode, tagCode, tagCount, 1); 1532 1533 fKodakKDCPrivateIFD = stream.TagValue_uint32 (tagType); 1534 1535 #if qDNGValidate 1536 1537 if (gVerbose) 1538 { 1539 printf ("KodakKDCPrivateIFD: %u\n", (unsigned) fKodakKDCPrivateIFD); 1540 } 1541 1542 #endif 1543 1544 break; 1545 1546 } 1547 1548 case tcDNGVersion: 1549 { 1550 1551 CheckTagType (parentCode, tagCode, tagType, ttByte); 1552 1553 CheckTagCount (parentCode, tagCode, tagCount, 4); 1554 1555 uint32 b0 = stream.Get_uint8 (); 1556 uint32 b1 = stream.Get_uint8 (); 1557 uint32 b2 = stream.Get_uint8 (); 1558 uint32 b3 = stream.Get_uint8 (); 1559 1560 fDNGVersion = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; 1561 1562 #if qDNGValidate 1563 1564 if (gVerbose) 1565 { 1566 printf ("DNGVersion: %u.%u.%u.%u\n", 1567 (unsigned) b0, 1568 (unsigned) b1, 1569 (unsigned) b2, 1570 (unsigned) b3); 1571 } 1572 1573 #endif 1574 1575 break; 1576 1577 } 1578 1579 case tcDNGBackwardVersion: 1580 { 1581 1582 CheckTagType (parentCode, tagCode, tagType, ttByte); 1583 1584 CheckTagCount (parentCode, tagCode, tagCount, 4); 1585 1586 uint32 b0 = stream.Get_uint8 (); 1587 uint32 b1 = stream.Get_uint8 (); 1588 uint32 b2 = stream.Get_uint8 (); 1589 uint32 b3 = stream.Get_uint8 (); 1590 1591 fDNGBackwardVersion = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; 1592 1593 #if qDNGValidate 1594 1595 if (gVerbose) 1596 { 1597 printf ("DNGBackwardVersion: %u.%u.%u.%u\n", 1598 (unsigned) b0, 1599 (unsigned) b1, 1600 (unsigned) b2, 1601 (unsigned) b3); 1602 } 1603 1604 #endif 1605 1606 break; 1607 1608 } 1609 1610 case tcUniqueCameraModel: 1611 { 1612 1613 CheckTagType (parentCode, tagCode, tagType, ttAscii); 1614 1615 ParseStringTag (stream, 1616 parentCode, 1617 tagCode, 1618 tagCount, 1619 fUniqueCameraModel, 1620 false); 1621 1622 bool didTrim = fUniqueCameraModel.TrimTrailingBlanks (); 1623 1624 #if qDNGValidate 1625 1626 if (didTrim) 1627 { 1628 1629 ReportWarning ("UniqueCameraModel string has trailing blanks"); 1630 1631 } 1632 1633 if (gVerbose) 1634 { 1635 1636 printf ("UniqueCameraModel: "); 1637 1638 DumpString (fUniqueCameraModel); 1639 1640 printf ("\n"); 1641 1642 } 1643 1644 #else 1645 1646 (void) didTrim; // Unused 1647 1648 #endif 1649 1650 break; 1651 1652 } 1653 1654 case tcLocalizedCameraModel: 1655 { 1656 1657 CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); 1658 1659 ParseStringTag (stream, 1660 parentCode, 1661 tagCode, 1662 tagCount, 1663 fLocalizedCameraModel, 1664 false); 1665 1666 bool didTrim = fLocalizedCameraModel.TrimTrailingBlanks (); 1667 1668 #if qDNGValidate 1669 1670 if (didTrim) 1671 { 1672 1673 ReportWarning ("LocalizedCameraModel string has trailing blanks"); 1674 1675 } 1676 1677 if (gVerbose) 1678 { 1679 1680 printf ("LocalizedCameraModel: "); 1681 1682 DumpString (fLocalizedCameraModel); 1683 1684 printf ("\n"); 1685 1686 } 1687 1688 #else 1689 1690 (void) didTrim; // Unused 1691 1692 #endif 1693 1694 break; 1695 1696 } 1697 1698 case tcCameraCalibration1: 1699 { 1700 1701 CheckTagType (parentCode, tagCode, tagType, ttSRational); 1702 1703 if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes)) 1704 return false; 1705 1706 if (!ParseMatrixTag (stream, 1707 parentCode, 1708 tagCode, 1709 tagType, 1710 tagCount, 1711 fCameraProfile.fColorPlanes, 1712 fCameraProfile.fColorPlanes, 1713 fCameraCalibration1)) 1714 return false; 1715 1716 #if qDNGValidate 1717 1718 if (gVerbose) 1719 { 1720 1721 printf ("CameraCalibration1:\n"); 1722 1723 DumpMatrix (fCameraCalibration1); 1724 1725 } 1726 1727 #endif 1728 1729 break; 1730 1731 } 1732 1733 case tcCameraCalibration2: 1734 { 1735 1736 CheckTagType (parentCode, tagCode, tagType, ttSRational); 1737 1738 if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes)) 1739 return false; 1740 1741 if (!ParseMatrixTag (stream, 1742 parentCode, 1743 tagCode, 1744 tagType, 1745 tagCount, 1746 fCameraProfile.fColorPlanes, 1747 fCameraProfile.fColorPlanes, 1748 fCameraCalibration2)) 1749 return false; 1750 1751 #if qDNGValidate 1752 1753 if (gVerbose) 1754 { 1755 1756 printf ("CameraCalibration2:\n"); 1757 1758 DumpMatrix (fCameraCalibration2); 1759 1760 } 1761 1762 #endif 1763 1764 break; 1765 1766 } 1767 1768 case tcCameraCalibrationSignature: 1769 { 1770 1771 CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); 1772 1773 ParseStringTag (stream, 1774 parentCode, 1775 tagCode, 1776 tagCount, 1777 fCameraCalibrationSignature, 1778 false); 1779 1780 #if qDNGValidate 1781 1782 if (gVerbose) 1783 { 1784 1785 printf ("CameraCalibrationSignature: "); 1786 1787 DumpString (fCameraCalibrationSignature); 1788 1789 printf ("\n"); 1790 1791 } 1792 1793 #endif 1794 1795 break; 1796 1797 } 1798 1799 case tcAnalogBalance: 1800 { 1801 1802 CheckTagType (parentCode, tagCode, tagType, ttRational); 1803 1804 // Kludge - Hasselblad FFF files are very DNG-like, but sometimes 1805 // they don't have any ColorMatrix tags. 1806 1807 bool hasselbladHack = (fDNGVersion == 0 && 1808 fCameraProfile.fColorPlanes == 0); 1809 1810 if (hasselbladHack) 1811 { 1812 1813 fCameraProfile.fColorPlanes = Pin_uint32 (0, tagCount, kMaxColorPlanes); 1814 1815 #if qDNGValidate 1816 1817 ReportWarning ("AnalogBalance without ColorMatrix1"); 1818 1819 #endif 1820 1821 } 1822 1823 if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes)) 1824 return false; 1825 1826 if (!ParseVectorTag (stream, 1827 parentCode, 1828 tagCode, 1829 tagType, 1830 tagCount, 1831 fCameraProfile.fColorPlanes, 1832 fAnalogBalance)) 1833 return false; 1834 1835 #if qDNGValidate 1836 1837 if (gVerbose) 1838 { 1839 1840 printf ("AnalogBalance:"); 1841 1842 DumpVector (fAnalogBalance); 1843 1844 } 1845 1846 #endif 1847 1848 break; 1849 1850 } 1851 1852 case tcAsShotNeutral: 1853 { 1854 1855 CheckTagType (parentCode, tagCode, tagType, ttRational); 1856 1857 // Kludge - Hasselblad FFF files are very DNG-like, but sometimes 1858 // they don't have any ColorMatrix tags. 1859 1860 bool hasselbladHack = (fDNGVersion == 0 && 1861 fCameraProfile.fColorPlanes == 0); 1862 1863 if (hasselbladHack) 1864 { 1865 1866 fCameraProfile.fColorPlanes = Pin_uint32 (0, tagCount, kMaxColorPlanes); 1867 1868 #if qDNGValidate 1869 1870 ReportWarning ("AsShotNeutral without ColorMatrix1"); 1871 1872 #endif 1873 1874 } 1875 1876 if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes)) 1877 return false; 1878 1879 if (!ParseVectorTag (stream, 1880 parentCode, 1881 tagCode, 1882 tagType, 1883 tagCount, 1884 fCameraProfile.fColorPlanes, 1885 fAsShotNeutral)) 1886 return false; 1887 1888 #if qDNGValidate 1889 1890 if (gVerbose) 1891 { 1892 1893 printf ("AsShotNeutral:"); 1894 1895 DumpVector (fAsShotNeutral); 1896 1897 } 1898 1899 #endif 1900 1901 break; 1902 1903 } 1904 1905 case tcAsShotWhiteXY: 1906 { 1907 1908 CheckTagType (parentCode, tagCode, tagType, ttRational); 1909 1910 if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes)) 1911 return false; 1912 1913 if (!CheckTagCount (parentCode, tagCode, tagCount, 2)) 1914 return false; 1915 1916 fAsShotWhiteXY.x = stream.TagValue_real64 (tagType); 1917 fAsShotWhiteXY.y = stream.TagValue_real64 (tagType); 1918 1919 #if qDNGValidate 1920 1921 if (gVerbose) 1922 { 1923 1924 printf ("AsShotWhiteXY: %0.4f %0.4f\n", 1925 fAsShotWhiteXY.x, 1926 fAsShotWhiteXY.y); 1927 1928 } 1929 1930 #endif 1931 1932 break; 1933 1934 } 1935 1936 case tcBaselineExposure: 1937 { 1938 1939 CheckTagType (parentCode, tagCode, tagType, ttSRational); 1940 1941 CheckTagCount (parentCode, tagCode, tagCount, 1); 1942 1943 fBaselineExposure = stream.TagValue_srational (tagType); 1944 1945 fHasBaselineExposure = true; 1946 1947 #if qDNGValidate 1948 1949 if (gVerbose) 1950 { 1951 1952 printf ("BaselineExposure: %+0.2f\n", 1953 fBaselineExposure.As_real64 ()); 1954 1955 } 1956 1957 #endif 1958 1959 break; 1960 1961 } 1962 1963 case tcBaselineNoise: 1964 { 1965 1966 CheckTagType (parentCode, tagCode, tagType, ttRational); 1967 1968 CheckTagCount (parentCode, tagCode, tagCount, 1); 1969 1970 fBaselineNoise = stream.TagValue_urational (tagType); 1971 1972 #if qDNGValidate 1973 1974 if (gVerbose) 1975 { 1976 1977 printf ("BaselineNoise: %0.2f\n", 1978 fBaselineNoise.As_real64 ()); 1979 1980 } 1981 1982 #endif 1983 1984 break; 1985 1986 } 1987 1988 case tcBaselineSharpness: 1989 { 1990 1991 CheckTagType (parentCode, tagCode, tagType, ttRational); 1992 1993 CheckTagCount (parentCode, tagCode, tagCount, 1); 1994 1995 fBaselineSharpness = stream.TagValue_urational (tagType); 1996 1997 #if qDNGValidate 1998 1999 if (gVerbose) 2000 { 2001 2002 printf ("BaselineSharpness: %0.2f\n", 2003 fBaselineSharpness.As_real64 ()); 2004 2005 } 2006 2007 #endif 2008 2009 break; 2010 2011 } 2012 2013 case tcLinearResponseLimit: 2014 { 2015 2016 CheckTagType (parentCode, tagCode, tagType, ttRational); 2017 2018 CheckTagCount (parentCode, tagCode, tagCount, 1); 2019 2020 fLinearResponseLimit = stream.TagValue_urational (tagType); 2021 2022 #if qDNGValidate 2023 2024 if (gVerbose) 2025 { 2026 2027 printf ("LinearResponseLimit: %0.2f\n", 2028 fLinearResponseLimit.As_real64 ()); 2029 2030 } 2031 2032 #endif 2033 2034 break; 2035 2036 } 2037 2038 case tcShadowScale: 2039 { 2040 2041 CheckTagType (parentCode, tagCode, tagType, ttRational); 2042 2043 CheckTagCount (parentCode, tagCode, tagCount, 1); 2044 2045 fShadowScale = stream.TagValue_urational (tagType); 2046 2047 fHasShadowScale = true; 2048 2049 #if qDNGValidate 2050 2051 if (gVerbose) 2052 { 2053 2054 printf ("ShadowScale: %0.4f\n", 2055 fShadowScale.As_real64 ()); 2056 2057 } 2058 2059 #endif 2060 2061 break; 2062 2063 } 2064 2065 case tcDNGPrivateData: 2066 { 2067 2068 CheckTagType (parentCode, tagCode, tagType, ttByte); 2069 2070 fDNGPrivateDataCount = tagCount; 2071 fDNGPrivateDataOffset = tagOffset; 2072 2073 #if qDNGValidate 2074 2075 if (gVerbose) 2076 { 2077 2078 printf ("DNGPrivateData: Count = %u, Offset = %u\n", 2079 (unsigned) fDNGPrivateDataCount, 2080 (unsigned) fDNGPrivateDataOffset); 2081 2082 DumpHexAscii (stream, tagCount); 2083 2084 } 2085 2086 #endif 2087 2088 break; 2089 2090 } 2091 2092 case tcMakerNoteSafety: 2093 { 2094 2095 CheckTagType (parentCode, tagCode, tagType, ttShort); 2096 2097 CheckTagCount (parentCode, tagCode, tagCount, 1); 2098 2099 fMakerNoteSafety = stream.TagValue_uint32 (tagType); 2100 2101 #if qDNGValidate 2102 2103 if (gVerbose) 2104 { 2105 2106 printf ("MakerNoteSafety: %s\n", 2107 LookupMakerNoteSafety (fMakerNoteSafety)); 2108 2109 } 2110 2111 #endif 2112 2113 break; 2114 2115 } 2116 2117 case tcRawImageDigest: 2118 { 2119 2120 if (!CheckTagType (parentCode, tagCode, tagType, ttByte)) 2121 return false; 2122 2123 if (!CheckTagCount (parentCode, tagCode, tagCount, 16)) 2124 return false; 2125 2126 stream.Get (fRawImageDigest.data, 16); 2127 2128 #if qDNGValidate 2129 2130 if (gVerbose) 2131 { 2132 2133 printf ("RawImageDigest: "); 2134 2135 DumpFingerprint (fRawImageDigest); 2136 2137 printf ("\n"); 2138 2139 } 2140 2141 #endif 2142 2143 break; 2144 2145 } 2146 2147 case tcNewRawImageDigest: 2148 { 2149 2150 if (!CheckTagType (parentCode, tagCode, tagType, ttByte)) 2151 return false; 2152 2153 if (!CheckTagCount (parentCode, tagCode, tagCount, 16)) 2154 return false; 2155 2156 stream.Get (fNewRawImageDigest.data, 16); 2157 2158 #if qDNGValidate 2159 2160 if (gVerbose) 2161 { 2162 2163 printf ("NewRawImageDigest: "); 2164 2165 DumpFingerprint (fNewRawImageDigest); 2166 2167 printf ("\n"); 2168 2169 } 2170 2171 #endif 2172 2173 break; 2174 2175 } 2176 2177 case tcRawDataUniqueID: 2178 { 2179 2180 if (!CheckTagType (parentCode, tagCode, tagType, ttByte)) 2181 return false; 2182 2183 if (!CheckTagCount (parentCode, tagCode, tagCount, 16)) 2184 return false; 2185 2186 stream.Get (fRawDataUniqueID.data, 16); 2187 2188 #if qDNGValidate 2189 2190 if (gVerbose) 2191 { 2192 2193 printf ("RawDataUniqueID: "); 2194 2195 DumpFingerprint (fRawDataUniqueID); 2196 2197 printf ("\n"); 2198 2199 } 2200 2201 #endif 2202 2203 break; 2204 2205 } 2206 2207 case tcOriginalRawFileName: 2208 { 2209 2210 CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); 2211 2212 ParseStringTag (stream, 2213 parentCode, 2214 tagCode, 2215 tagCount, 2216 fOriginalRawFileName, 2217 false); 2218 2219 #if qDNGValidate 2220 2221 if (gVerbose) 2222 { 2223 2224 printf ("OriginalRawFileName: "); 2225 2226 DumpString (fOriginalRawFileName); 2227 2228 printf ("\n"); 2229 2230 } 2231 2232 #endif 2233 2234 break; 2235 2236 } 2237 2238 case tcOriginalRawFileData: 2239 { 2240 2241 CheckTagType (parentCode, tagCode, tagType, ttUndefined); 2242 2243 fOriginalRawFileDataCount = tagCount; 2244 fOriginalRawFileDataOffset = tagOffset; 2245 2246 #if qDNGValidate 2247 2248 if (gVerbose) 2249 { 2250 2251 printf ("OriginalRawFileData: Count = %u, Offset = %u\n", 2252 (unsigned) fOriginalRawFileDataCount, 2253 (unsigned) fOriginalRawFileDataOffset); 2254 2255 DumpHexAscii (stream, tagCount); 2256 2257 } 2258 2259 #endif 2260 2261 break; 2262 2263 } 2264 2265 case tcOriginalRawFileDigest: 2266 { 2267 2268 if (!CheckTagType (parentCode, tagCode, tagType, ttByte)) 2269 return false; 2270 2271 if (!CheckTagCount (parentCode, tagCode, tagCount, 16)) 2272 return false; 2273 2274 stream.Get (fOriginalRawFileDigest.data, 16); 2275 2276 #if qDNGValidate 2277 2278 if (gVerbose) 2279 { 2280 2281 printf ("OriginalRawFileDigest: "); 2282 2283 DumpFingerprint (fOriginalRawFileDigest); 2284 2285 printf ("\n"); 2286 2287 } 2288 2289 #endif 2290 2291 break; 2292 2293 } 2294 2295 case tcAsShotICCProfile: 2296 { 2297 2298 CheckTagType (parentCode, tagCode, tagType, ttUndefined); 2299 2300 fAsShotICCProfileCount = tagCount; 2301 fAsShotICCProfileOffset = tagOffset; 2302 2303 #if qDNGValidate 2304 2305 if (gVerbose) 2306 { 2307 2308 printf ("AsShotICCProfile: Count = %u, Offset = %u\n", 2309 (unsigned) fAsShotICCProfileCount, 2310 (unsigned) fAsShotICCProfileOffset); 2311 2312 DumpHexAscii (stream, tagCount); 2313 2314 } 2315 2316 #endif 2317 2318 break; 2319 2320 } 2321 2322 case tcAsShotPreProfileMatrix: 2323 { 2324 2325 CheckTagType (parentCode, tagCode, tagType, ttSRational); 2326 2327 if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes)) 2328 return false; 2329 2330 uint32 rows = fCameraProfile.fColorPlanes; 2331 2332 if (tagCount == fCameraProfile.fColorPlanes * 3) 2333 { 2334 rows = 3; 2335 } 2336 2337 if (!ParseMatrixTag (stream, 2338 parentCode, 2339 tagCode, 2340 tagType, 2341 tagCount, 2342 rows, 2343 fCameraProfile.fColorPlanes, 2344 fAsShotPreProfileMatrix)) 2345 return false; 2346 2347 #if qDNGValidate 2348 2349 if (gVerbose) 2350 { 2351 2352 printf ("AsShotPreProfileMatrix:\n"); 2353 2354 DumpMatrix (fAsShotPreProfileMatrix); 2355 2356 } 2357 2358 #endif 2359 2360 break; 2361 2362 } 2363 2364 case tcCurrentICCProfile: 2365 { 2366 2367 CheckTagType (parentCode, tagCode, tagType, ttUndefined); 2368 2369 fCurrentICCProfileCount = tagCount; 2370 fCurrentICCProfileOffset = tagOffset; 2371 2372 #if qDNGValidate 2373 2374 if (gVerbose) 2375 { 2376 2377 printf ("CurrentICCProfile: Count = %u, Offset = %u\n", 2378 (unsigned) fCurrentICCProfileCount, 2379 (unsigned) fCurrentICCProfileOffset); 2380 2381 DumpHexAscii (stream, tagCount); 2382 2383 } 2384 2385 #endif 2386 2387 break; 2388 2389 } 2390 2391 case tcCurrentPreProfileMatrix: 2392 { 2393 2394 CheckTagType (parentCode, tagCode, tagType, ttSRational); 2395 2396 if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes)) 2397 return false; 2398 2399 uint32 rows = fCameraProfile.fColorPlanes; 2400 2401 if (tagCount == fCameraProfile.fColorPlanes * 3) 2402 { 2403 rows = 3; 2404 } 2405 2406 if (!ParseMatrixTag (stream, 2407 parentCode, 2408 tagCode, 2409 tagType, 2410 tagCount, 2411 rows, 2412 fCameraProfile.fColorPlanes, 2413 fCurrentPreProfileMatrix)) 2414 return false; 2415 2416 #if qDNGValidate 2417 2418 if (gVerbose) 2419 { 2420 2421 printf ("CurrentPreProfileMatrix:\n"); 2422 2423 DumpMatrix (fCurrentPreProfileMatrix); 2424 2425 } 2426 2427 #endif 2428 2429 break; 2430 2431 } 2432 2433 case tcColorimetricReference: 2434 { 2435 2436 CheckTagType (parentCode, tagCode, tagType, ttShort); 2437 2438 CheckTagCount (parentCode, tagCode, tagCount, 1); 2439 2440 fColorimetricReference = stream.TagValue_uint32 (tagType); 2441 2442 #if qDNGValidate 2443 2444 if (gVerbose) 2445 { 2446 2447 printf ("ColorimetricReference: %s\n", 2448 LookupColorimetricReference (fColorimetricReference)); 2449 2450 } 2451 2452 #endif 2453 2454 break; 2455 2456 } 2457 2458 case tcExtraCameraProfiles: 2459 { 2460 2461 CheckTagType (parentCode, tagCode, tagType, ttLong); 2462 2463 CheckTagCount (parentCode, tagCode, tagCount, 1, tagCount); 2464 2465 #if qDNGValidate 2466 2467 if (gVerbose) 2468 { 2469 2470 printf ("ExtraCameraProfiles: %u\n", (unsigned) tagCount); 2471 2472 } 2473 2474 #endif 2475 2476 fExtraCameraProfiles.reserve (tagCount); 2477 2478 for (uint32 index = 0; index < tagCount; index++) 2479 { 2480 2481 #if qDNGValidate 2482 2483 if (gVerbose) 2484 { 2485 2486 printf ("\nExtraCameraProfile [%u]:\n\n", (unsigned) index); 2487 2488 } 2489 2490 #endif 2491 2492 stream.SetReadPosition (tagOffset + index * 4); 2493 2494 uint32 profileOffset = stream.TagValue_uint32 (tagType); 2495 2496 dng_camera_profile_info profileInfo; 2497 2498 stream.SetReadPosition (profileOffset); 2499 2500 if (profileInfo.ParseExtended (stream)) 2501 { 2502 2503 fExtraCameraProfiles.push_back (profileInfo); 2504 2505 } 2506 2507 else 2508 { 2509 2510 #if qDNGValidate 2511 2512 ReportWarning ("Unable to parse extra camera profile"); 2513 2514 #endif 2515 2516 } 2517 2518 } 2519 2520 #if qDNGValidate 2521 2522 if (gVerbose) 2523 { 2524 2525 printf ("\nDone with ExtraCameraProfiles\n\n"); 2526 2527 } 2528 2529 #endif 2530 2531 break; 2532 2533 } 2534 2535 case tcAsShotProfileName: 2536 { 2537 2538 CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); 2539 2540 ParseStringTag (stream, 2541 parentCode, 2542 tagCode, 2543 tagCount, 2544 fAsShotProfileName, 2545 false); 2546 2547 #if qDNGValidate 2548 2549 if (gVerbose) 2550 { 2551 2552 printf ("AsShotProfileName: "); 2553 2554 DumpString (fAsShotProfileName); 2555 2556 printf ("\n"); 2557 2558 } 2559 2560 #endif 2561 2562 break; 2563 2564 } 2565 2566 case tcOriginalDefaultFinalSize: 2567 { 2568 2569 CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong); 2570 2571 if (!CheckTagCount (parentCode, tagCode, tagCount, 2)) 2572 return false; 2573 2574 fOriginalDefaultFinalSize.h = stream.TagValue_int32 (tagType); 2575 fOriginalDefaultFinalSize.v = stream.TagValue_int32 (tagType); 2576 2577 #if qDNGValidate 2578 2579 if (gVerbose) 2580 { 2581 2582 printf ("OriginalDefaultFinalSize: H = %d V = %d\n", 2583 (int) fOriginalDefaultFinalSize.h, 2584 (int) fOriginalDefaultFinalSize.v); 2585 2586 } 2587 2588 #endif 2589 2590 break; 2591 2592 } 2593 2594 case tcOriginalBestQualityFinalSize: 2595 { 2596 2597 CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong); 2598 2599 if (!CheckTagCount (parentCode, tagCode, tagCount, 2)) 2600 return false; 2601 2602 fOriginalBestQualityFinalSize.h = stream.TagValue_int32 (tagType); 2603 fOriginalBestQualityFinalSize.v = stream.TagValue_int32 (tagType); 2604 2605 #if qDNGValidate 2606 2607 if (gVerbose) 2608 { 2609 2610 printf ("OriginalBestQualityFinalSize: H = %d V = %d\n", 2611 (int) fOriginalBestQualityFinalSize.h, 2612 (int) fOriginalBestQualityFinalSize.v); 2613 2614 } 2615 2616 #endif 2617 2618 break; 2619 2620 } 2621 2622 case tcOriginalDefaultCropSize: 2623 { 2624 2625 CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong, ttRational); 2626 2627 if (!CheckTagCount (parentCode, tagCode, tagCount, 2)) 2628 return false; 2629 2630 fOriginalDefaultCropSizeH = stream.TagValue_urational (tagType); 2631 fOriginalDefaultCropSizeV = stream.TagValue_urational (tagType); 2632 2633 #if qDNGValidate 2634 2635 if (gVerbose) 2636 { 2637 2638 printf ("OriginalDefaultCropSize: H = %0.2f V = %0.2f\n", 2639 fOriginalDefaultCropSizeH.As_real64 (), 2640 fOriginalDefaultCropSizeV.As_real64 ()); 2641 2642 } 2643 2644 #endif 2645 2646 break; 2647 2648 } 2649 2650 case tcDepthFormat: 2651 { 2652 2653 CheckTagType (parentCode, tagCode, tagType, ttShort); 2654 2655 CheckTagCount (parentCode, tagCode, tagCount, 1); 2656 2657 fDepthFormat = stream.TagValue_uint32 (tagType); 2658 2659 #if qDNGValidate 2660 2661 if (gVerbose) 2662 { 2663 2664 printf ("DepthFormat: %s\n", 2665 LookupDepthFormat (fDepthFormat)); 2666 2667 } 2668 2669 #endif 2670 2671 break; 2672 2673 } 2674 2675 case tcDepthNear: 2676 { 2677 2678 CheckTagType (parentCode, tagCode, tagType, ttRational); 2679 2680 CheckTagCount (parentCode, tagCode, tagCount, 1); 2681 2682 fDepthNear = stream.TagValue_urational (tagType); 2683 2684 #if qDNGValidate 2685 2686 if (gVerbose) 2687 { 2688 2689 printf ("DepthNear: "); 2690 2691 if (fDepthNear == dng_urational (0, 0)) 2692 { 2693 printf ("Unknown"); 2694 } 2695 else if (fDepthNear.d == 0) 2696 { 2697 printf ("Infinity"); 2698 } 2699 else 2700 { 2701 printf ("%0.2f", fDepthNear.As_real64 ()); 2702 } 2703 2704 printf ("\n"); 2705 2706 } 2707 2708 #endif 2709 2710 break; 2711 2712 } 2713 2714 case tcDepthFar: 2715 { 2716 2717 CheckTagType (parentCode, tagCode, tagType, ttRational); 2718 2719 CheckTagCount (parentCode, tagCode, tagCount, 1); 2720 2721 fDepthFar = stream.TagValue_urational (tagType); 2722 2723 #if qDNGValidate 2724 2725 if (gVerbose) 2726 { 2727 2728 printf ("DepthFar: "); 2729 2730 if (fDepthFar == dng_urational (0, 0)) 2731 { 2732 printf ("Unknown"); 2733 } 2734 else if (fDepthFar.d == 0) 2735 { 2736 printf ("Infinity"); 2737 } 2738 else 2739 { 2740 printf ("%0.2f", fDepthFar.As_real64 ()); 2741 } 2742 2743 printf ("\n"); 2744 2745 } 2746 2747 #endif 2748 2749 break; 2750 2751 } 2752 2753 case tcDepthUnits: 2754 { 2755 2756 CheckTagType (parentCode, tagCode, tagType, ttShort); 2757 2758 CheckTagCount (parentCode, tagCode, tagCount, 1); 2759 2760 fDepthUnits = stream.TagValue_uint32 (tagType); 2761 2762 #if qDNGValidate 2763 2764 if (gVerbose) 2765 { 2766 2767 printf ("DepthUnits: %s\n", 2768 LookupDepthUnits (fDepthUnits)); 2769 2770 } 2771 2772 #endif 2773 2774 break; 2775 2776 } 2777 2778 case tcDepthMeasureType: 2779 { 2780 2781 CheckTagType (parentCode, tagCode, tagType, ttShort); 2782 2783 CheckTagCount (parentCode, tagCode, tagCount, 1); 2784 2785 fDepthMeasureType = stream.TagValue_uint32 (tagType); 2786 2787 #if qDNGValidate 2788 2789 if (gVerbose) 2790 { 2791 2792 printf ("DepthMeasureType: %s\n", 2793 LookupDepthMeasureType (fDepthMeasureType)); 2794 2795 } 2796 2797 #endif 2798 2799 break; 2800 2801 } 2802 2803 default: 2804 { 2805 2806 // The main camera profile tags also appear in IFD 0 2807 2808 return fCameraProfile.ParseTag (stream, 2809 parentCode, 2810 tagCode, 2811 tagType, 2812 tagCount, 2813 tagOffset); 2814 2815 } 2816 2817 } 2818 2819 return true; 2820 2821 } 2822 2823 /*****************************************************************************/ 2824 2825 // Parses tags that should only appear in IFD 0 or EXIF IFD. 2826 2827 bool dng_shared::Parse_ifd0_exif (dng_stream &stream, 2828 dng_exif & /* exif */, 2829 uint32 parentCode, 2830 uint32 tagCode, 2831 uint32 tagType, 2832 uint32 tagCount, 2833 uint64 tagOffset) 2834 { 2835 2836 switch (tagCode) 2837 { 2838 2839 case tcMakerNote: 2840 { 2841 2842 CheckTagType (parentCode, tagCode, tagType, ttUndefined); 2843 2844 fMakerNoteCount = tagCount; 2845 fMakerNoteOffset = tagOffset; 2846 2847 #if qDNGValidate 2848 2849 if (gVerbose) 2850 { 2851 2852 printf ("MakerNote: Count = %u, Offset = %u\n", 2853 (unsigned) fMakerNoteCount, 2854 (unsigned) fMakerNoteOffset); 2855 2856 DumpHexAscii (stream, tagCount); 2857 2858 } 2859 2860 #endif 2861 2862 break; 2863 2864 } 2865 2866 case tcInteroperabilityIFD: 2867 { 2868 2869 CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD); 2870 2871 CheckTagCount (parentCode, tagCode, tagCount, 1); 2872 2873 fInteroperabilityIFD = stream.TagValue_uint32 (tagType); 2874 2875 #if qDNGValidate 2876 2877 if (gVerbose) 2878 { 2879 printf ("InteroperabilityIFD: %u\n", (unsigned) fInteroperabilityIFD); 2880 } 2881 2882 #endif 2883 2884 break; 2885 2886 } 2887 2888 default: 2889 { 2890 2891 return false; 2892 2893 } 2894 2895 } 2896 2897 return true; 2898 2899 } 2900 2901 /*****************************************************************************/ 2902 2903 void dng_shared::PostParse (dng_host & /* host */, 2904 dng_exif & /* exif */) 2905 { 2906 2907 // Fill in default values for DNG images. 2908 2909 if (fDNGVersion != 0) 2910 { 2911 2912 // Support for DNG versions before 1.0.0.0. 2913 2914 if (fDNGVersion < dngVersion_1_0_0_0) 2915 { 2916 2917 #if qDNGValidate 2918 2919 ReportWarning ("DNGVersion less than 1.0.0.0"); 2920 2921 #endif 2922 2923 // The CalibrationIlluminant tags were added just before 2924 // DNG version 1.0.0.0, and were hardcoded before that. 2925 2926 fCameraProfile.fCalibrationIlluminant1 = lsStandardLightA; 2927 fCameraProfile.fCalibrationIlluminant2 = lsD65; 2928 2929 fDNGVersion = dngVersion_1_0_0_0; 2930 2931 } 2932 2933 // Default value for DNGBackwardVersion tag. 2934 2935 if (fDNGBackwardVersion == 0) 2936 { 2937 2938 fDNGBackwardVersion = fDNGVersion & 0xFFFF0000; 2939 2940 } 2941 2942 // Check DNGBackwardVersion value. 2943 2944 if (fDNGBackwardVersion < dngVersion_1_0_0_0) 2945 { 2946 2947 #if qDNGValidate 2948 2949 ReportWarning ("DNGBackwardVersion less than 1.0.0.0"); 2950 2951 #endif 2952 2953 fDNGBackwardVersion = dngVersion_1_0_0_0; 2954 2955 } 2956 2957 if (fDNGBackwardVersion > fDNGVersion) 2958 { 2959 2960 #if qDNGValidate 2961 2962 ReportWarning ("DNGBackwardVersion > DNGVersion"); 2963 2964 #endif 2965 2966 fDNGBackwardVersion = fDNGVersion; 2967 2968 } 2969 2970 // Check UniqueCameraModel. 2971 2972 if (fUniqueCameraModel.IsEmpty ()) 2973 { 2974 2975 #if qDNGValidate 2976 2977 ReportWarning ("Missing or invalid UniqueCameraModel"); 2978 2979 #endif 2980 2981 fUniqueCameraModel.Set ("Digital Negative"); 2982 2983 } 2984 2985 // If we don't know the color depth yet, it must be a monochrome DNG. 2986 2987 if (fCameraProfile.fColorPlanes == 0) 2988 { 2989 2990 fCameraProfile.fColorPlanes = 1; 2991 2992 } 2993 2994 // Check color info. 2995 2996 if (fCameraProfile.fColorPlanes > 1) 2997 { 2998 2999 // Check illuminant pair. 3000 3001 if (fCameraProfile.fColorMatrix2.NotEmpty ()) 3002 { 3003 3004 if (fCameraProfile.fCalibrationIlluminant1 == lsUnknown || 3005 (fCameraProfile.fCalibrationIlluminant2 == lsUnknown || 3006 (fCameraProfile.fCalibrationIlluminant1 == fCameraProfile.fCalibrationIlluminant2))) 3007 { 3008 3009 #if qDNGValidate 3010 3011 ReportWarning ("Invalid CalibrationIlluminant pair"); 3012 3013 #endif 3014 3015 fCameraProfile.fColorMatrix2 = dng_matrix (); 3016 3017 } 3018 3019 } 3020 3021 // If the colorimetric reference is the ICC profile PCS, then the 3022 // data must already be white balanced. The "AsShotWhiteXY" is required 3023 // to be the ICC Profile PCS white point. 3024 3025 if (fColorimetricReference == crICCProfilePCS) 3026 { 3027 3028 if (fAsShotNeutral.NotEmpty ()) 3029 { 3030 3031 #if qDNGValidate 3032 3033 ReportWarning ("AsShotNeutral not allowed for this " 3034 "ColorimetricReference value"); 3035 3036 #endif 3037 3038 fAsShotNeutral.Clear (); 3039 3040 } 3041 3042 dng_xy_coord pcs = PCStoXY (); 3043 3044 #if qDNGValidate 3045 3046 if (fAsShotWhiteXY.IsValid ()) 3047 { 3048 3049 if (Abs_real64 (fAsShotWhiteXY.x - pcs.x) > 0.01 || 3050 Abs_real64 (fAsShotWhiteXY.y - pcs.y) > 0.01) 3051 { 3052 3053 ReportWarning ("AsShotWhiteXY does not match the ICC Profile PCS"); 3054 3055 } 3056 3057 } 3058 3059 #endif 3060 3061 fAsShotWhiteXY = pcs; 3062 3063 } 3064 3065 else 3066 { 3067 3068 // Warn if both AsShotNeutral and AsShotWhiteXY are specified. 3069 3070 if (fAsShotNeutral.NotEmpty () && fAsShotWhiteXY.IsValid ()) 3071 { 3072 3073 #if qDNGValidate 3074 3075 ReportWarning ("Both AsShotNeutral and AsShotWhiteXY included"); 3076 3077 #endif 3078 3079 fAsShotWhiteXY = dng_xy_coord (); 3080 3081 } 3082 3083 // Warn if neither AsShotNeutral nor AsShotWhiteXY are specified. 3084 3085 #if qDNGValidate 3086 3087 if (fAsShotNeutral.IsEmpty () && !fAsShotWhiteXY.IsValid ()) 3088 { 3089 3090 ReportWarning ("Neither AsShotNeutral nor AsShotWhiteXY included", 3091 "legal but not recommended"); 3092 3093 } 3094 3095 #endif 3096 3097 } 3098 3099 // Default values of calibration signatures are required for legacy 3100 // compatiblity. 3101 3102 if (fCameraProfile.fCalibrationIlluminant1 == lsStandardLightA && 3103 fCameraProfile.fCalibrationIlluminant2 == lsD65 && 3104 fCameraCalibration1.Rows () == fCameraProfile.fColorPlanes && 3105 fCameraCalibration1.Cols () == fCameraProfile.fColorPlanes && 3106 fCameraCalibration2.Rows () == fCameraProfile.fColorPlanes && 3107 fCameraCalibration2.Cols () == fCameraProfile.fColorPlanes && 3108 fCameraCalibrationSignature.IsEmpty () && 3109 fCameraProfile.fProfileCalibrationSignature.IsEmpty () ) 3110 { 3111 3112 fCameraCalibrationSignature.Set (kAdobeCalibrationSignature); 3113 3114 fCameraProfile.fProfileCalibrationSignature.Set (kAdobeCalibrationSignature); 3115 3116 } 3117 3118 } 3119 3120 // Check BaselineNoise. 3121 3122 if (fBaselineNoise.As_real64 () <= 0.0) 3123 { 3124 3125 #if qDNGValidate 3126 3127 ReportWarning ("Invalid BaselineNoise"); 3128 3129 #endif 3130 3131 fBaselineNoise = dng_urational (1, 1); 3132 3133 } 3134 3135 // Check BaselineSharpness. 3136 3137 if (fBaselineSharpness.As_real64 () <= 0.0) 3138 { 3139 3140 #if qDNGValidate 3141 3142 ReportWarning ("Invalid BaselineSharpness"); 3143 3144 #endif 3145 3146 fBaselineSharpness = dng_urational (1, 1); 3147 3148 } 3149 3150 // Check LinearResponseLimit. 3151 3152 if (fLinearResponseLimit.As_real64 () < 0.5 || 3153 fLinearResponseLimit.As_real64 () > 1.0) 3154 { 3155 3156 #if qDNGValidate 3157 3158 ReportWarning ("Invalid LinearResponseLimit"); 3159 3160 #endif 3161 3162 fLinearResponseLimit = dng_urational (1, 1); 3163 3164 } 3165 3166 // Check ShadowScale. 3167 3168 if (fShadowScale.As_real64 () <= 0.0) 3169 { 3170 3171 #if qDNGValidate 3172 3173 ReportWarning ("Invalid ShadowScale"); 3174 3175 #endif 3176 3177 fShadowScale = dng_urational (1, 1); 3178 3179 } 3180 3181 } 3182 3183 } 3184 3185 /*****************************************************************************/ 3186 3187 bool dng_shared::IsValidDNG () 3188 { 3189 3190 // Check DNGVersion value. 3191 3192 if (fDNGVersion < dngVersion_1_0_0_0) 3193 { 3194 3195 #if qDNGValidate 3196 3197 if (fDNGVersion != dngVersion_None) 3198 { 3199 3200 ReportError ("Invalid DNGVersion"); 3201 3202 } 3203 3204 #if qDNGValidateTarget 3205 3206 else 3207 { 3208 3209 ReportError ("Missing DNGVersion"); 3210 3211 } 3212 3213 #endif 3214 3215 #endif 3216 3217 return false; 3218 3219 } 3220 3221 // Check DNGBackwardVersion value. 3222 3223 if (fDNGBackwardVersion > dngVersion_Current) 3224 { 3225 3226 #if qDNGValidate 3227 3228 ReportError ("DNGBackwardVersion (or DNGVersion) is too high"); 3229 3230 #endif 3231 3232 ThrowUnsupportedDNG (); 3233 3234 } 3235 3236 // Check color transform info. 3237 3238 if (fCameraProfile.fColorPlanes > 1) 3239 { 3240 3241 // CameraCalibration1 is optional, but it must be valid if present. 3242 3243 if (fCameraCalibration1.Cols () != 0 || 3244 fCameraCalibration1.Rows () != 0) 3245 { 3246 3247 if (fCameraCalibration1.Cols () != fCameraProfile.fColorPlanes || 3248 fCameraCalibration1.Rows () != fCameraProfile.fColorPlanes) 3249 { 3250 3251 #if qDNGValidate 3252 3253 ReportError ("CameraCalibration1 is wrong size"); 3254 3255 #endif 3256 3257 return false; 3258 3259 } 3260 3261 // Make sure it is invertable. 3262 3263 try 3264 { 3265 3266 (void) Invert (fCameraCalibration1); 3267 3268 } 3269 3270 catch (...) 3271 { 3272 3273 #if qDNGValidate 3274 3275 ReportError ("CameraCalibration1 is not invertable"); 3276 3277 #endif 3278 3279 return false; 3280 3281 } 3282 3283 } 3284 3285 // CameraCalibration2 is optional, but it must be valid if present. 3286 3287 if (fCameraCalibration2.Cols () != 0 || 3288 fCameraCalibration2.Rows () != 0) 3289 { 3290 3291 if (fCameraCalibration2.Cols () != fCameraProfile.fColorPlanes || 3292 fCameraCalibration2.Rows () != fCameraProfile.fColorPlanes) 3293 { 3294 3295 #if qDNGValidate 3296 3297 ReportError ("CameraCalibration2 is wrong size"); 3298 3299 #endif 3300 3301 return false; 3302 3303 } 3304 3305 // Make sure it is invertable. 3306 3307 try 3308 { 3309 3310 (void) Invert (fCameraCalibration2); 3311 3312 } 3313 3314 catch (...) 3315 { 3316 3317 #if qDNGValidate 3318 3319 ReportError ("CameraCalibration2 is not invertable"); 3320 3321 #endif 3322 3323 return false; 3324 3325 } 3326 3327 } 3328 3329 // Check analog balance 3330 3331 dng_matrix analogBalance; 3332 3333 if (fAnalogBalance.NotEmpty ()) 3334 { 3335 3336 analogBalance = fAnalogBalance.AsDiagonal (); 3337 3338 try 3339 { 3340 3341 (void) Invert (analogBalance); 3342 3343 } 3344 3345 catch (...) 3346 { 3347 3348 #if qDNGValidate 3349 3350 ReportError ("AnalogBalance is not invertable"); 3351 3352 #endif 3353 3354 return false; 3355 3356 } 3357 3358 } 3359 3360 } 3361 3362 return true; 3363 3364 } 3365 3366 /*****************************************************************************/