1 /*****************************************************************************/ 2 // Copyright 2006-2008 Adobe Systems Incorporated 3 // All Rights Reserved. 4 // 5 // NOTICE: Adobe permits you to use, modify, and distribute this file in 6 // accordance with the terms of the Adobe license agreement accompanying it. 7 /*****************************************************************************/ 8 9 /* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_shared.cpp#2 $ */ 10 /* $DateTime: 2012/06/14 20:24:41 $ */ 11 /* $Change: 835078 $ */ 12 /* $Author: tknoll $ */ 13 14 /*****************************************************************************/ 15 16 #include "dng_shared.h" 17 18 #include "dng_camera_profile.h" 19 #include "dng_exceptions.h" 20 #include "dng_globals.h" 21 #include "dng_memory.h" 22 #include "dng_parse_utils.h" 23 #include "dng_safe_arithmetic.h" 24 #include "dng_tag_codes.h" 25 #include "dng_tag_types.h" 26 #include "dng_tag_values.h" 27 #include "dng_utils.h" 28 29 /*****************************************************************************/ 30 31 dng_camera_profile_info::dng_camera_profile_info () 32 33 : fBigEndian (false) 34 35 , fColorPlanes (0) 36 37 , fCalibrationIlluminant1 (lsUnknown) 38 , fCalibrationIlluminant2 (lsUnknown) 39 40 , fColorMatrix1 () 41 , fColorMatrix2 () 42 43 , fForwardMatrix1 () 44 , fForwardMatrix2 () 45 46 , fReductionMatrix1 () 47 , fReductionMatrix2 () 48 49 , fProfileCalibrationSignature () 50 51 , fProfileName () 52 53 , fProfileCopyright () 54 55 , fEmbedPolicy (pepAllowCopying) 56 57 , fProfileHues (0) 58 , fProfileSats (0) 59 , fProfileVals (0) 60 61 , fHueSatDeltas1Offset (0) 62 , fHueSatDeltas1Count (0) 63 64 , fHueSatDeltas2Offset (0) 65 , fHueSatDeltas2Count (0) 66 67 , fHueSatMapEncoding (encoding_Linear) 68 69 , fLookTableHues (0) 70 , fLookTableSats (0) 71 , fLookTableVals (0) 72 73 , fLookTableOffset (0) 74 , fLookTableCount (0) 75 76 , fLookTableEncoding (encoding_Linear) 77 78 , fBaselineExposureOffset (0, 100) 79 80 , fDefaultBlackRender (defaultBlackRender_Auto) 81 82 , fToneCurveOffset (0) 83 , fToneCurveCount (0) 84 85 , fUniqueCameraModel () 86 87 { 88 89 } 90 91 /*****************************************************************************/ 92 93 dng_camera_profile_info::~dng_camera_profile_info () 94 { 95 96 } 97 98 /*****************************************************************************/ 99 100 bool dng_camera_profile_info::ParseTag (dng_stream &stream, 101 uint32 parentCode, 102 uint32 tagCode, 103 uint32 tagType, 104 uint32 tagCount, 105 uint64 tagOffset) 106 { 107 108 switch (tagCode) 109 { 110 111 case tcCalibrationIlluminant1: 112 { 113 114 CheckTagType (parentCode, tagCode, tagType, ttShort); 115 116 CheckTagCount (parentCode, tagCode, tagCount, 1); 117 118 fCalibrationIlluminant1 = stream.TagValue_uint32 (tagType); 119 120 #if qDNGValidate 121 122 if (gVerbose) 123 { 124 125 printf ("CalibrationIlluminant1: %s\n", 126 LookupLightSource (fCalibrationIlluminant1)); 127 128 } 129 130 #endif 131 132 break; 133 134 } 135 136 case tcCalibrationIlluminant2: 137 { 138 139 CheckTagType (parentCode, tagCode, tagType, ttShort); 140 141 CheckTagCount (parentCode, tagCode, tagCount, 1); 142 143 fCalibrationIlluminant2 = stream.TagValue_uint32 (tagType); 144 145 #if qDNGValidate 146 147 if (gVerbose) 148 { 149 150 printf ("CalibrationIlluminant2: %s\n", 151 LookupLightSource (fCalibrationIlluminant2)); 152 153 } 154 155 #endif 156 157 break; 158 159 } 160 161 case tcColorMatrix1: 162 { 163 164 CheckTagType (parentCode, tagCode, tagType, ttSRational); 165 166 if (fColorPlanes == 0) 167 { 168 169 fColorPlanes = Pin_uint32 (0, tagCount / 3, kMaxColorPlanes); 170 171 } 172 173 if (!CheckColorImage (parentCode, tagCode, fColorPlanes)) 174 return false; 175 176 if (!ParseMatrixTag (stream, 177 parentCode, 178 tagCode, 179 tagType, 180 tagCount, 181 fColorPlanes, 182 3, 183 fColorMatrix1)) 184 return false; 185 186 #if qDNGValidate 187 188 if (gVerbose) 189 { 190 191 printf ("ColorMatrix1:\n"); 192 193 DumpMatrix (fColorMatrix1); 194 195 } 196 197 #endif 198 199 break; 200 201 } 202 203 case tcColorMatrix2: 204 { 205 206 CheckTagType (parentCode, tagCode, tagType, ttSRational); 207 208 // Kludge - Hasselblad FFF files are very DNG-like, but sometimes 209 // only have a ColorMatrix2 tag and no ColorMatrix1 tag. 210 211 bool hasselbladHack = (fColorPlanes == 0); 212 213 if (hasselbladHack) 214 { 215 216 fColorPlanes = Pin_uint32 (0, tagCount / 3, kMaxColorPlanes); 217 218 #if qDNGValidate 219 220 ReportWarning ("ColorMatrix2 without ColorMatrix1"); 221 222 #endif 223 224 } 225 226 if (!CheckColorImage (parentCode, tagCode, fColorPlanes)) 227 return false; 228 229 if (!ParseMatrixTag (stream, 230 parentCode, 231 tagCode, 232 tagType, 233 tagCount, 234 fColorPlanes, 235 3, 236 fColorMatrix2)) 237 return false; 238 239 #if qDNGValidate 240 241 if (gVerbose) 242 { 243 244 printf ("ColorMatrix2:\n"); 245 246 DumpMatrix (fColorMatrix2); 247 248 } 249 250 #endif 251 252 if (hasselbladHack) 253 { 254 255 fColorMatrix1 = fColorMatrix2; 256 257 fColorMatrix2 = dng_matrix (); 258 259 } 260 261 break; 262 263 } 264 265 case tcForwardMatrix1: 266 { 267 268 CheckTagType (parentCode, tagCode, tagType, ttSRational); 269 270 if (!CheckColorImage (parentCode, tagCode, fColorPlanes)) 271 return false; 272 273 if (!ParseMatrixTag (stream, 274 parentCode, 275 tagCode, 276 tagType, 277 tagCount, 278 3, 279 fColorPlanes, 280 fForwardMatrix1)) 281 return false; 282 283 #if qDNGValidate 284 285 if (gVerbose) 286 { 287 288 printf ("ForwardMatrix1:\n"); 289 290 DumpMatrix (fForwardMatrix1); 291 292 } 293 294 #endif 295 296 break; 297 298 } 299 300 case tcForwardMatrix2: 301 { 302 303 CheckTagType (parentCode, tagCode, tagType, ttSRational); 304 305 if (!CheckColorImage (parentCode, tagCode, fColorPlanes)) 306 return false; 307 308 if (!ParseMatrixTag (stream, 309 parentCode, 310 tagCode, 311 tagType, 312 tagCount, 313 3, 314 fColorPlanes, 315 fForwardMatrix2)) 316 return false; 317 318 #if qDNGValidate 319 320 if (gVerbose) 321 { 322 323 printf ("ForwardMatrix2:\n"); 324 325 DumpMatrix (fForwardMatrix2); 326 327 } 328 329 #endif 330 331 break; 332 333 } 334 335 case tcReductionMatrix1: 336 { 337 338 CheckTagType (parentCode, tagCode, tagType, ttSRational); 339 340 if (!CheckColorImage (parentCode, tagCode, fColorPlanes)) 341 return false; 342 343 if (!ParseMatrixTag (stream, 344 parentCode, 345 tagCode, 346 tagType, 347 tagCount, 348 3, 349 fColorPlanes, 350 fReductionMatrix1)) 351 return false; 352 353 #if qDNGValidate 354 355 if (gVerbose) 356 { 357 358 printf ("ReductionMatrix1:\n"); 359 360 DumpMatrix (fReductionMatrix1); 361 362 } 363 364 #endif 365 366 break; 367 368 } 369 370 case tcReductionMatrix2: 371 { 372 373 CheckTagType (parentCode, tagCode, tagType, ttSRational); 374 375 if (!CheckColorImage (parentCode, tagCode, fColorPlanes)) 376 return false; 377 378 if (!ParseMatrixTag (stream, 379 parentCode, 380 tagCode, 381 tagType, 382 tagCount, 383 3, 384 fColorPlanes, 385 fReductionMatrix2)) 386 return false; 387 388 #if qDNGValidate 389 390 if (gVerbose) 391 { 392 393 printf ("ReductionMatrix2:\n"); 394 395 DumpMatrix (fReductionMatrix2); 396 397 } 398 399 #endif 400 401 break; 402 403 } 404 405 case tcProfileCalibrationSignature: 406 { 407 408 CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); 409 410 ParseStringTag (stream, 411 parentCode, 412 tagCode, 413 tagCount, 414 fProfileCalibrationSignature, 415 false); 416 417 #if qDNGValidate 418 419 if (gVerbose) 420 { 421 422 printf ("ProfileCalibrationSignature: "); 423 424 DumpString (fProfileCalibrationSignature); 425 426 printf ("\n"); 427 428 } 429 430 #endif 431 432 break; 433 434 } 435 436 case tcProfileName: 437 { 438 439 CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); 440 441 ParseStringTag (stream, 442 parentCode, 443 tagCode, 444 tagCount, 445 fProfileName, 446 false); 447 448 #if qDNGValidate 449 450 if (gVerbose) 451 { 452 453 printf ("ProfileName: "); 454 455 DumpString (fProfileName); 456 457 printf ("\n"); 458 459 } 460 461 #endif 462 463 break; 464 465 } 466 467 case tcProfileCopyright: 468 { 469 470 CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); 471 472 ParseStringTag (stream, 473 parentCode, 474 tagCode, 475 tagCount, 476 fProfileCopyright, 477 false); 478 479 #if qDNGValidate 480 481 if (gVerbose) 482 { 483 484 printf ("ProfileCopyright: "); 485 486 DumpString (fProfileCopyright); 487 488 printf ("\n"); 489 490 } 491 492 #endif 493 494 break; 495 496 } 497 498 case tcProfileEmbedPolicy: 499 { 500 501 CheckTagType (parentCode, tagCode, tagType, ttLong); 502 503 CheckTagCount (parentCode, tagCode, tagCount, 1); 504 505 fEmbedPolicy = stream.TagValue_uint32 (tagType); 506 507 #if qDNGValidate 508 509 if (gVerbose) 510 { 511 512 const char *policy; 513 514 switch (fEmbedPolicy) 515 { 516 517 case pepAllowCopying: 518 policy = "Allow copying"; 519 break; 520 521 case pepEmbedIfUsed: 522 policy = "Embed if used"; 523 break; 524 525 case pepEmbedNever: 526 policy = "Embed never"; 527 break; 528 529 case pepNoRestrictions: 530 policy = "No restrictions"; 531 break; 532 533 default: 534 policy = "INVALID VALUE"; 535 536 } 537 538 printf ("ProfileEmbedPolicy: %s\n", policy); 539 540 } 541 542 #endif 543 544 break; 545 546 } 547 548 case tcProfileHueSatMapDims: 549 { 550 551 CheckTagType (parentCode, tagCode, tagType, ttLong); 552 553 CheckTagCount (parentCode, tagCode, tagCount, 2, 3); 554 555 fProfileHues = stream.TagValue_uint32 (tagType); 556 fProfileSats = stream.TagValue_uint32 (tagType); 557 558 if (tagCount > 2) 559 fProfileVals = stream.TagValue_uint32 (tagType); 560 else 561 fProfileVals = 1; 562 563 #if qDNGValidate 564 565 if (gVerbose) 566 { 567 568 printf ("ProfileHueSatMapDims: Hues = %u, Sats = %u, Vals = %u\n", 569 (unsigned) fProfileHues, 570 (unsigned) fProfileSats, 571 (unsigned) fProfileVals); 572 573 } 574 575 #endif 576 577 break; 578 579 } 580 581 case tcProfileHueSatMapData1: 582 { 583 584 if (!CheckTagType (parentCode, tagCode, tagType, ttFloat)) 585 return false; 586 587 bool skipSat0 = (tagCount == 588 SafeUint32Mult(fProfileHues, 589 SafeUint32Sub(fProfileSats, 1u), 590 fProfileVals, 591 3u)); 592 593 if (!skipSat0) 594 { 595 596 if (!CheckTagCount (parentCode, tagCode, tagCount, 597 SafeUint32Mult(fProfileHues, fProfileSats, fProfileVals, 3))) 598 return false; 599 600 } 601 602 fBigEndian = stream.BigEndian (); 603 604 fHueSatDeltas1Offset = tagOffset; 605 fHueSatDeltas1Count = tagCount; 606 607 #if qDNGValidate 608 609 if (gVerbose) 610 { 611 612 printf ("ProfileHueSatMapData1:\n"); 613 614 DumpHueSatMap (stream, 615 fProfileHues, 616 fProfileSats, 617 fProfileVals, 618 skipSat0); 619 620 } 621 622 #endif 623 624 break; 625 626 } 627 628 case tcProfileHueSatMapData2: 629 { 630 631 if (!CheckTagType (parentCode, tagCode, tagType, ttFloat)) 632 return false; 633 634 bool skipSat0 = (tagCount == 635 SafeUint32Mult(fProfileHues, 636 SafeUint32Sub(fProfileSats, 1u), 637 fProfileVals, 638 3u)); 639 640 if (!skipSat0) 641 { 642 643 if (!CheckTagCount (parentCode, tagCode, tagCount, 644 SafeUint32Mult(fProfileHues, fProfileSats, fProfileVals, 3))) 645 return false; 646 647 } 648 649 fBigEndian = stream.BigEndian (); 650 651 fHueSatDeltas2Offset = tagOffset; 652 fHueSatDeltas2Count = tagCount; 653 654 #if qDNGValidate 655 656 if (gVerbose) 657 { 658 659 printf ("ProfileHueSatMapData2:\n"); 660 661 DumpHueSatMap (stream, 662 fProfileHues, 663 fProfileSats, 664 fProfileVals, 665 skipSat0); 666 667 } 668 669 #endif 670 671 break; 672 673 } 674 675 case tcProfileHueSatMapEncoding: 676 { 677 678 CheckTagType (parentCode, tagCode, tagType, ttLong); 679 680 CheckTagCount (parentCode, tagCode, tagCount, 1); 681 682 fHueSatMapEncoding = stream.TagValue_uint32 (tagType); 683 684 #if qDNGValidate 685 686 if (gVerbose) 687 { 688 689 const char *encoding = NULL; 690 691 switch (fHueSatMapEncoding) 692 { 693 694 case encoding_Linear: 695 encoding = "Linear"; 696 break; 697 698 case encoding_sRGB: 699 encoding = "sRGB"; 700 break; 701 702 default: 703 encoding = "INVALID VALUE"; 704 705 } 706 707 printf ("ProfileHueSatMapEncoding: %s\n", encoding); 708 709 } 710 711 #endif 712 713 break; 714 715 } 716 717 case tcProfileLookTableDims: 718 { 719 720 CheckTagType (parentCode, tagCode, tagType, ttLong); 721 722 CheckTagCount (parentCode, tagCode, tagCount, 2, 3); 723 724 fLookTableHues = stream.TagValue_uint32 (tagType); 725 fLookTableSats = stream.TagValue_uint32 (tagType); 726 727 if (tagCount > 2) 728 fLookTableVals = stream.TagValue_uint32 (tagType); 729 else 730 fLookTableVals = 1; 731 732 #if qDNGValidate 733 734 if (gVerbose) 735 { 736 737 printf ("ProfileLookTableDims: Hues = %u, Sats = %u, Vals = %u\n", 738 (unsigned) fLookTableHues, 739 (unsigned) fLookTableSats, 740 (unsigned) fLookTableVals); 741 742 } 743 744 #endif 745 746 break; 747 748 } 749 750 case tcProfileLookTableData: 751 { 752 753 if (!CheckTagType (parentCode, tagCode, tagType, ttFloat)) 754 return false; 755 756 bool skipSat0 = (tagCount == 757 SafeUint32Mult(fLookTableHues, 758 SafeUint32Sub(fLookTableSats, 1u), 759 fLookTableVals, 760 3u)); 761 762 if (!skipSat0) 763 { 764 765 if (!CheckTagCount (parentCode, tagCode, tagCount, 766 SafeUint32Mult(fLookTableHues, 767 fLookTableSats, 768 fLookTableVals, 3))) 769 return false; 770 771 } 772 773 fBigEndian = stream.BigEndian (); 774 775 fLookTableOffset = tagOffset; 776 fLookTableCount = tagCount; 777 778 #if qDNGValidate 779 780 if (gVerbose) 781 { 782 783 printf ("ProfileLookTableData:\n"); 784 785 DumpHueSatMap (stream, 786 fLookTableHues, 787 fLookTableSats, 788 fLookTableVals, 789 skipSat0); 790 791 } 792 793 #endif 794 795 break; 796 797 } 798 799 case tcProfileLookTableEncoding: 800 { 801 802 CheckTagType (parentCode, tagCode, tagType, ttLong); 803 804 CheckTagCount (parentCode, tagCode, tagCount, 1); 805 806 fLookTableEncoding = stream.TagValue_uint32 (tagType); 807 808 #if qDNGValidate 809 810 if (gVerbose) 811 { 812 813 const char *encoding = NULL; 814 815 switch (fLookTableEncoding) 816 { 817 818 case encoding_Linear: 819 encoding = "Linear"; 820 break; 821 822 case encoding_sRGB: 823 encoding = "sRGB"; 824 break; 825 826 default: 827 encoding = "INVALID VALUE"; 828 829 } 830 831 printf ("ProfileLookTableEncoding: %s\n", encoding); 832 833 } 834 835 #endif 836 837 break; 838 839 } 840 841 case tcBaselineExposureOffset: 842 { 843 844 CheckTagType (parentCode, tagCode, tagType, ttSRational); 845 846 CheckTagCount (parentCode, tagCode, tagCount, 1); 847 848 fBaselineExposureOffset = stream.TagValue_srational (tagType); 849 850 #if qDNGValidate 851 852 if (gVerbose) 853 { 854 855 printf ("BaselineExposureOffset: %+0.2f\n", 856 fBaselineExposureOffset.As_real64 ()); 857 858 } 859 860 #endif 861 862 break; 863 864 } 865 866 case tcDefaultBlackRender: 867 { 868 869 CheckTagType (parentCode, tagCode, tagType, ttLong); 870 871 CheckTagCount (parentCode, tagCode, tagCount, 1); 872 873 fDefaultBlackRender = stream.TagValue_uint32 (tagType); 874 875 #if qDNGValidate 876 877 if (gVerbose) 878 { 879 880 const char *setting = NULL; 881 882 switch (fDefaultBlackRender) 883 { 884 885 case defaultBlackRender_Auto: 886 setting = "Auto"; 887 break; 888 889 case defaultBlackRender_None: 890 setting = "None"; 891 break; 892 893 default: 894 setting = "INVALID VALUE"; 895 896 } 897 898 printf ("DefaultBlackRender: %s\n", 899 setting); 900 901 } 902 903 #endif 904 905 break; 906 907 } 908 909 case tcProfileToneCurve: 910 { 911 912 if (!CheckTagType (parentCode, tagCode, tagType, ttFloat)) 913 return false; 914 915 if (!CheckTagCount (parentCode, tagCode, tagCount, 4, tagCount)) 916 return false; 917 918 if ((tagCount & 1) != 0) 919 { 920 921 #if qDNGValidate 922 923 { 924 925 char message [256]; 926 927 sprintf (message, 928 "%s %s has odd count (%u)", 929 LookupParentCode (parentCode), 930 LookupTagCode (parentCode, tagCode), 931 (unsigned) tagCount); 932 933 ReportWarning (message); 934 935 } 936 937 #endif 938 939 return false; 940 941 } 942 943 fBigEndian = stream.BigEndian (); 944 945 fToneCurveOffset = tagOffset; 946 fToneCurveCount = tagCount; 947 948 #if qDNGValidate 949 950 if (gVerbose) 951 { 952 953 DumpTagValues (stream, 954 "Coord", 955 parentCode, 956 tagCode, 957 tagType, 958 tagCount); 959 960 961 } 962 963 #endif 964 965 break; 966 967 } 968 969 case tcUniqueCameraModel: 970 { 971 972 // Note: This code is only used when parsing stand-alone 973 // profiles. The embedded profiles are assumed to be restricted 974 // to the model they are embedded in. 975 976 CheckTagType (parentCode, tagCode, tagType, ttAscii); 977 978 ParseStringTag (stream, 979 parentCode, 980 tagCode, 981 tagCount, 982 fUniqueCameraModel, 983 false); 984 985 bool didTrim = fUniqueCameraModel.TrimTrailingBlanks (); 986 987 #if qDNGValidate 988 989 if (didTrim) 990 { 991 992 ReportWarning ("UniqueCameraModel string has trailing blanks"); 993 994 } 995 996 if (gVerbose) 997 { 998 999 printf ("UniqueCameraModel: "); 1000 1001 DumpString (fUniqueCameraModel); 1002 1003 printf ("\n"); 1004 1005 } 1006 1007 #else 1008 1009 (void) didTrim; // Unused 1010 1011 #endif 1012 1013 break; 1014 1015 } 1016 1017 default: 1018 { 1019 1020 return false; 1021 1022 } 1023 1024 } 1025 1026 return true; 1027 1028 } 1029 1030 /*****************************************************************************/ 1031 1032 bool dng_camera_profile_info::ParseExtended (dng_stream &stream) 1033 { 1034 1035 try 1036 { 1037 1038 // Offsets are relative to the start of this structure, not the entire file. 1039 1040 uint64 startPosition = stream.Position (); 1041 1042 // Read header. Like a TIFF header, but with different magic number 1043 // Plus all offsets are relative to the start of the IFD, not to the 1044 // stream or file. 1045 1046 uint16 byteOrder = stream.Get_uint16 (); 1047 1048 if (byteOrder == byteOrderMM) 1049 fBigEndian = true; 1050 1051 else if (byteOrder == byteOrderII) 1052 fBigEndian = false; 1053 1054 else 1055 return false; 1056 1057 TempBigEndian setEndianness (stream, fBigEndian); 1058 1059 uint16 magicNumber = stream.Get_uint16 (); 1060 1061 if (magicNumber != magicExtendedProfile) 1062 { 1063 return false; 1064 } 1065 1066 uint32 offset = stream.Get_uint32 (); 1067 1068 stream.Skip (SafeUint32Sub(offset, 8u)); 1069 1070 // Start on IFD entries. 1071 1072 uint32 ifdEntries = stream.Get_uint16 (); 1073 1074 if (ifdEntries < 1) 1075 { 1076 return false; 1077 } 1078 1079 for (uint32 tag_index = 0; tag_index < ifdEntries; tag_index++) 1080 { 1081 1082 stream.SetReadPosition (startPosition + 8 + 2 + tag_index * 12); 1083 1084 uint16 tagCode = stream.Get_uint16 (); 1085 uint32 tagType = stream.Get_uint16 (); 1086 uint32 tagCount = stream.Get_uint32 (); 1087 1088 uint64 tagOffset = stream.Position (); 1089 1090 if (SafeUint32Mult(TagTypeSize (tagType), tagCount) > 4) 1091 { 1092 1093 tagOffset = startPosition + stream.Get_uint32 (); 1094 1095 stream.SetReadPosition (tagOffset); 1096 1097 } 1098 1099 if (!ParseTag (stream, 1100 0, 1101 tagCode, 1102 tagType, 1103 tagCount, 1104 tagOffset)) 1105 { 1106 1107 #if qDNGValidate 1108 1109 if (gVerbose) 1110 { 1111 1112 stream.SetReadPosition (tagOffset); 1113 1114 printf ("*"); 1115 1116 DumpTagValues (stream, 1117 LookupTagType (tagType), 1118 0, 1119 tagCode, 1120 tagType, 1121 tagCount); 1122 1123 } 1124 1125 #endif 1126 1127 } 1128 1129 } 1130 1131 return true; 1132 1133 } 1134 1135 catch (...) 1136 { 1137 1138 // Eat parsing errors. 1139 1140 } 1141 1142 return false; 1143 1144 } 1145 1146 /*****************************************************************************/ 1147 1148 dng_shared::dng_shared () 1149 1150 : fExifIFD (0) 1151 , fGPSInfo (0) 1152 , fInteroperabilityIFD (0) 1153 , fKodakDCRPrivateIFD (0) 1154 , fKodakKDCPrivateIFD (0) 1155 1156 , fXMPCount (0) 1157 , fXMPOffset (0) 1158 1159 , fIPTC_NAA_Count (0) 1160 , fIPTC_NAA_Offset (0) 1161 1162 , fMakerNoteCount (0) 1163 , fMakerNoteOffset (0) 1164 , fMakerNoteSafety (0) 1165 1166 , fDNGVersion (0) 1167 , fDNGBackwardVersion (0) 1168 1169 , fUniqueCameraModel () 1170 , fLocalizedCameraModel () 1171 1172 , fCameraProfile () 1173 1174 , fExtraCameraProfiles () 1175 1176 , fCameraCalibration1 () 1177 , fCameraCalibration2 () 1178 1179 , fCameraCalibrationSignature () 1180 1181 , fAnalogBalance () 1182 1183 , fAsShotNeutral () 1184 1185 , fAsShotWhiteXY () 1186 1187 , fBaselineExposure (0, 1) 1188 , fBaselineNoise (1, 1) 1189 , fNoiseReductionApplied (0, 0) 1190 , fBaselineSharpness (1, 1) 1191 , fLinearResponseLimit (1, 1) 1192 , fShadowScale (1, 1) 1193 1194 , fHasBaselineExposure (false) 1195 , fHasShadowScale (false) 1196 1197 , fDNGPrivateDataCount (0) 1198 , fDNGPrivateDataOffset (0) 1199 1200 , fRawImageDigest () 1201 , fNewRawImageDigest () 1202 1203 , fRawDataUniqueID () 1204 1205 , fOriginalRawFileName () 1206 1207 , fOriginalRawFileDataCount (0) 1208 , fOriginalRawFileDataOffset (0) 1209 1210 , fOriginalRawFileDigest () 1211 1212 , fAsShotICCProfileCount (0) 1213 , fAsShotICCProfileOffset (0) 1214 1215 , fAsShotPreProfileMatrix () 1216 1217 , fCurrentICCProfileCount (0) 1218 , fCurrentICCProfileOffset (0) 1219 1220 , fCurrentPreProfileMatrix () 1221 1222 , fColorimetricReference (crSceneReferred) 1223 1224 , fAsShotProfileName () 1225 1226 , fNoiseProfile () 1227 1228 , fOriginalDefaultFinalSize () 1229 , fOriginalBestQualityFinalSize () 1230 1231 , fOriginalDefaultCropSizeH () 1232 , fOriginalDefaultCropSizeV () 1233 1234 { 1235 1236 } 1237 1238 /*****************************************************************************/ 1239 1240 dng_shared::~dng_shared () 1241 { 1242 1243 } 1244 1245 /*****************************************************************************/ 1246 1247 bool dng_shared::ParseTag (dng_stream &stream, 1248 dng_exif &exif, 1249 uint32 parentCode, 1250 bool /* isMainIFD */, 1251 uint32 tagCode, 1252 uint32 tagType, 1253 uint32 tagCount, 1254 uint64 tagOffset, 1255 int64 /* offsetDelta */) 1256 { 1257 1258 if (parentCode == 0) 1259 { 1260 1261 if (Parse_ifd0 (stream, 1262 exif, 1263 parentCode, 1264 tagCode, 1265 tagType, 1266 tagCount, 1267 tagOffset)) 1268 { 1269 1270 return true; 1271 1272 } 1273 1274 } 1275 1276 if (parentCode == 0 || 1277 parentCode == tcExifIFD) 1278 { 1279 1280 if (Parse_ifd0_exif (stream, 1281 exif, 1282 parentCode, 1283 tagCode, 1284 tagType, 1285 tagCount, 1286 tagOffset)) 1287 { 1288 1289 return true; 1290 1291 } 1292 1293 } 1294 1295 return false; 1296 1297 } 1298 1299 /*****************************************************************************/ 1300 1301 // Parses tags that should only appear in IFD 0. 1302 1303 bool dng_shared::Parse_ifd0 (dng_stream &stream, 1304 dng_exif & /* exif */, 1305 uint32 parentCode, 1306 uint32 tagCode, 1307 uint32 tagType, 1308 uint32 tagCount, 1309 uint64 tagOffset) 1310 { 1311 1312 switch (tagCode) 1313 { 1314 1315 case tcXMP: 1316 { 1317 1318 CheckTagType (parentCode, tagCode, tagType, ttByte, ttUndefined); 1319 1320 fXMPCount = tagCount; 1321 fXMPOffset = fXMPCount ? tagOffset : 0; 1322 1323 #if qDNGValidate 1324 1325 if (gVerbose) 1326 { 1327 1328 printf ("XMP: Count = %u, Offset = %u\n", 1329 (unsigned) fXMPCount, 1330 (unsigned) fXMPOffset); 1331 1332 if (fXMPCount) 1333 { 1334 1335 DumpXMP (stream, fXMPCount); 1336 1337 } 1338 1339 } 1340 1341 #endif 1342 1343 break; 1344 1345 } 1346 1347 case tcIPTC_NAA: 1348 { 1349 1350 CheckTagType (parentCode, tagCode, tagType, ttLong, ttAscii, ttUndefined); 1351 1352 fIPTC_NAA_Count = SafeUint32Mult(tagCount, 1353 TagTypeSize(tagType)); 1354 fIPTC_NAA_Offset = fIPTC_NAA_Count ? tagOffset : 0; 1355 1356 #if qDNGValidate 1357 1358 if (gVerbose) 1359 { 1360 1361 printf ("IPTC/NAA: Count = %u, Offset = %u\n", 1362 (unsigned) fIPTC_NAA_Count, 1363 (unsigned) fIPTC_NAA_Offset); 1364 1365 if (fIPTC_NAA_Count) 1366 { 1367 1368 DumpHexAscii (stream, fIPTC_NAA_Count); 1369 1370 } 1371 1372 // Compute and output the digest. 1373 1374 dng_memory_data buffer (fIPTC_NAA_Count); 1375 1376 stream.SetReadPosition (fIPTC_NAA_Offset); 1377 1378 stream.Get (buffer.Buffer (), fIPTC_NAA_Count); 1379 1380 const uint8 *data = buffer.Buffer_uint8 (); 1381 1382 uint32 count = fIPTC_NAA_Count; 1383 1384 // Method 1: Counting all bytes (this is correct). 1385 1386 { 1387 1388 dng_md5_printer printer; 1389 1390 printer.Process (data, count); 1391 1392 printf ("IPTCDigest: "); 1393 1394 DumpFingerprint (printer.Result ()); 1395 1396 printf ("\n"); 1397 1398 } 1399 1400 // Method 2: Ignoring zero padding. 1401 1402 { 1403 1404 uint32 removed = 0; 1405 1406 while ((removed < 3) && (count > 0) && (data [count - 1] == 0)) 1407 { 1408 removed++; 1409 count--; 1410 } 1411 1412 if (removed != 0) 1413 { 1414 1415 dng_md5_printer printer; 1416 1417 printer.Process (data, count); 1418 1419 printf ("IPTCDigest (ignoring zero padding): "); 1420 1421 DumpFingerprint (printer.Result ()); 1422 1423 printf ("\n"); 1424 1425 } 1426 1427 } 1428 1429 } 1430 1431 #endif 1432 1433 break; 1434 1435 } 1436 1437 case tcExifIFD: 1438 { 1439 1440 CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD); 1441 1442 CheckTagCount (parentCode, tagCode, tagCount, 1); 1443 1444 fExifIFD = stream.TagValue_uint32 (tagType); 1445 1446 #if qDNGValidate 1447 1448 if (gVerbose) 1449 { 1450 printf ("ExifIFD: %u\n", (unsigned) fExifIFD); 1451 } 1452 1453 #endif 1454 1455 break; 1456 1457 } 1458 1459 case tcGPSInfo: 1460 { 1461 1462 CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD); 1463 1464 CheckTagCount (parentCode, tagCode, tagCount, 1); 1465 1466 fGPSInfo = stream.TagValue_uint32 (tagType); 1467 1468 #if qDNGValidate 1469 1470 if (gVerbose) 1471 { 1472 printf ("GPSInfo: %u\n", (unsigned) fGPSInfo); 1473 } 1474 1475 #endif 1476 1477 break; 1478 1479 } 1480 1481 case tcKodakDCRPrivateIFD: 1482 { 1483 1484 CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD); 1485 1486 CheckTagCount (parentCode, tagCode, tagCount, 1); 1487 1488 fKodakDCRPrivateIFD = stream.TagValue_uint32 (tagType); 1489 1490 #if qDNGValidate 1491 1492 if (gVerbose) 1493 { 1494 printf ("KodakDCRPrivateIFD: %u\n", (unsigned) fKodakDCRPrivateIFD); 1495 } 1496 1497 #endif 1498 1499 break; 1500 1501 } 1502 1503 case tcKodakKDCPrivateIFD: 1504 { 1505 1506 CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD); 1507 1508 CheckTagCount (parentCode, tagCode, tagCount, 1); 1509 1510 fKodakKDCPrivateIFD = stream.TagValue_uint32 (tagType); 1511 1512 #if qDNGValidate 1513 1514 if (gVerbose) 1515 { 1516 printf ("KodakKDCPrivateIFD: %u\n", (unsigned) fKodakKDCPrivateIFD); 1517 } 1518 1519 #endif 1520 1521 break; 1522 1523 } 1524 1525 case tcDNGVersion: 1526 { 1527 1528 CheckTagType (parentCode, tagCode, tagType, ttByte); 1529 1530 CheckTagCount (parentCode, tagCode, tagCount, 4); 1531 1532 uint32 b0 = stream.Get_uint8 (); 1533 uint32 b1 = stream.Get_uint8 (); 1534 uint32 b2 = stream.Get_uint8 (); 1535 uint32 b3 = stream.Get_uint8 (); 1536 1537 fDNGVersion = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; 1538 1539 #if qDNGValidate 1540 1541 if (gVerbose) 1542 { 1543 printf ("DNGVersion: %u.%u.%u.%u\n", 1544 (unsigned) b0, 1545 (unsigned) b1, 1546 (unsigned) b2, 1547 (unsigned) b3); 1548 } 1549 1550 #endif 1551 1552 break; 1553 1554 } 1555 1556 case tcDNGBackwardVersion: 1557 { 1558 1559 CheckTagType (parentCode, tagCode, tagType, ttByte); 1560 1561 CheckTagCount (parentCode, tagCode, tagCount, 4); 1562 1563 uint32 b0 = stream.Get_uint8 (); 1564 uint32 b1 = stream.Get_uint8 (); 1565 uint32 b2 = stream.Get_uint8 (); 1566 uint32 b3 = stream.Get_uint8 (); 1567 1568 fDNGBackwardVersion = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; 1569 1570 #if qDNGValidate 1571 1572 if (gVerbose) 1573 { 1574 printf ("DNGBackwardVersion: %u.%u.%u.%u\n", 1575 (unsigned) b0, 1576 (unsigned) b1, 1577 (unsigned) b2, 1578 (unsigned) b3); 1579 } 1580 1581 #endif 1582 1583 break; 1584 1585 } 1586 1587 case tcUniqueCameraModel: 1588 { 1589 1590 CheckTagType (parentCode, tagCode, tagType, ttAscii); 1591 1592 ParseStringTag (stream, 1593 parentCode, 1594 tagCode, 1595 tagCount, 1596 fUniqueCameraModel, 1597 false); 1598 1599 bool didTrim = fUniqueCameraModel.TrimTrailingBlanks (); 1600 1601 #if qDNGValidate 1602 1603 if (didTrim) 1604 { 1605 1606 ReportWarning ("UniqueCameraModel string has trailing blanks"); 1607 1608 } 1609 1610 if (gVerbose) 1611 { 1612 1613 printf ("UniqueCameraModel: "); 1614 1615 DumpString (fUniqueCameraModel); 1616 1617 printf ("\n"); 1618 1619 } 1620 1621 #else 1622 1623 (void) didTrim; // Unused 1624 1625 #endif 1626 1627 break; 1628 1629 } 1630 1631 case tcLocalizedCameraModel: 1632 { 1633 1634 CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); 1635 1636 ParseStringTag (stream, 1637 parentCode, 1638 tagCode, 1639 tagCount, 1640 fLocalizedCameraModel, 1641 false); 1642 1643 bool didTrim = fLocalizedCameraModel.TrimTrailingBlanks (); 1644 1645 #if qDNGValidate 1646 1647 if (didTrim) 1648 { 1649 1650 ReportWarning ("LocalizedCameraModel string has trailing blanks"); 1651 1652 } 1653 1654 if (gVerbose) 1655 { 1656 1657 printf ("LocalizedCameraModel: "); 1658 1659 DumpString (fLocalizedCameraModel); 1660 1661 printf ("\n"); 1662 1663 } 1664 1665 #else 1666 1667 (void) didTrim; // Unused 1668 1669 #endif 1670 1671 break; 1672 1673 } 1674 1675 case tcCameraCalibration1: 1676 { 1677 1678 CheckTagType (parentCode, tagCode, tagType, ttSRational); 1679 1680 if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes)) 1681 return false; 1682 1683 if (!ParseMatrixTag (stream, 1684 parentCode, 1685 tagCode, 1686 tagType, 1687 tagCount, 1688 fCameraProfile.fColorPlanes, 1689 fCameraProfile.fColorPlanes, 1690 fCameraCalibration1)) 1691 return false; 1692 1693 #if qDNGValidate 1694 1695 if (gVerbose) 1696 { 1697 1698 printf ("CameraCalibration1:\n"); 1699 1700 DumpMatrix (fCameraCalibration1); 1701 1702 } 1703 1704 #endif 1705 1706 break; 1707 1708 } 1709 1710 case tcCameraCalibration2: 1711 { 1712 1713 CheckTagType (parentCode, tagCode, tagType, ttSRational); 1714 1715 if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes)) 1716 return false; 1717 1718 if (!ParseMatrixTag (stream, 1719 parentCode, 1720 tagCode, 1721 tagType, 1722 tagCount, 1723 fCameraProfile.fColorPlanes, 1724 fCameraProfile.fColorPlanes, 1725 fCameraCalibration2)) 1726 return false; 1727 1728 #if qDNGValidate 1729 1730 if (gVerbose) 1731 { 1732 1733 printf ("CameraCalibration2:\n"); 1734 1735 DumpMatrix (fCameraCalibration2); 1736 1737 } 1738 1739 #endif 1740 1741 break; 1742 1743 } 1744 1745 case tcCameraCalibrationSignature: 1746 { 1747 1748 CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); 1749 1750 ParseStringTag (stream, 1751 parentCode, 1752 tagCode, 1753 tagCount, 1754 fCameraCalibrationSignature, 1755 false); 1756 1757 #if qDNGValidate 1758 1759 if (gVerbose) 1760 { 1761 1762 printf ("CameraCalibrationSignature: "); 1763 1764 DumpString (fCameraCalibrationSignature); 1765 1766 printf ("\n"); 1767 1768 } 1769 1770 #endif 1771 1772 break; 1773 1774 } 1775 1776 case tcAnalogBalance: 1777 { 1778 1779 CheckTagType (parentCode, tagCode, tagType, ttRational); 1780 1781 // Kludge - Hasselblad FFF files are very DNG-like, but sometimes 1782 // they don't have any ColorMatrix tags. 1783 1784 bool hasselbladHack = (fDNGVersion == 0 && 1785 fCameraProfile.fColorPlanes == 0); 1786 1787 if (hasselbladHack) 1788 { 1789 1790 fCameraProfile.fColorPlanes = Pin_uint32 (0, tagCount, kMaxColorPlanes); 1791 1792 #if qDNGValidate 1793 1794 ReportWarning ("AnalogBalance without ColorMatrix1"); 1795 1796 #endif 1797 1798 } 1799 1800 if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes)) 1801 return false; 1802 1803 if (!ParseVectorTag (stream, 1804 parentCode, 1805 tagCode, 1806 tagType, 1807 tagCount, 1808 fCameraProfile.fColorPlanes, 1809 fAnalogBalance)) 1810 return false; 1811 1812 #if qDNGValidate 1813 1814 if (gVerbose) 1815 { 1816 1817 printf ("AnalogBalance:"); 1818 1819 DumpVector (fAnalogBalance); 1820 1821 } 1822 1823 #endif 1824 1825 break; 1826 1827 } 1828 1829 case tcAsShotNeutral: 1830 { 1831 1832 CheckTagType (parentCode, tagCode, tagType, ttRational); 1833 1834 // Kludge - Hasselblad FFF files are very DNG-like, but sometimes 1835 // they don't have any ColorMatrix tags. 1836 1837 bool hasselbladHack = (fDNGVersion == 0 && 1838 fCameraProfile.fColorPlanes == 0); 1839 1840 if (hasselbladHack) 1841 { 1842 1843 fCameraProfile.fColorPlanes = Pin_uint32 (0, tagCount, kMaxColorPlanes); 1844 1845 #if qDNGValidate 1846 1847 ReportWarning ("AsShotNeutral without ColorMatrix1"); 1848 1849 #endif 1850 1851 } 1852 1853 if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes)) 1854 return false; 1855 1856 if (!ParseVectorTag (stream, 1857 parentCode, 1858 tagCode, 1859 tagType, 1860 tagCount, 1861 fCameraProfile.fColorPlanes, 1862 fAsShotNeutral)) 1863 return false; 1864 1865 #if qDNGValidate 1866 1867 if (gVerbose) 1868 { 1869 1870 printf ("AsShotNeutral:"); 1871 1872 DumpVector (fAsShotNeutral); 1873 1874 } 1875 1876 #endif 1877 1878 break; 1879 1880 } 1881 1882 case tcAsShotWhiteXY: 1883 { 1884 1885 CheckTagType (parentCode, tagCode, tagType, ttRational); 1886 1887 if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes)) 1888 return false; 1889 1890 if (!CheckTagCount (parentCode, tagCode, tagCount, 2)) 1891 return false; 1892 1893 fAsShotWhiteXY.x = stream.TagValue_real64 (tagType); 1894 fAsShotWhiteXY.y = stream.TagValue_real64 (tagType); 1895 1896 #if qDNGValidate 1897 1898 if (gVerbose) 1899 { 1900 1901 printf ("AsShotWhiteXY: %0.4f %0.4f\n", 1902 fAsShotWhiteXY.x, 1903 fAsShotWhiteXY.y); 1904 1905 } 1906 1907 #endif 1908 1909 break; 1910 1911 } 1912 1913 case tcBaselineExposure: 1914 { 1915 1916 CheckTagType (parentCode, tagCode, tagType, ttSRational); 1917 1918 CheckTagCount (parentCode, tagCode, tagCount, 1); 1919 1920 fBaselineExposure = stream.TagValue_srational (tagType); 1921 1922 fHasBaselineExposure = true; 1923 1924 #if qDNGValidate 1925 1926 if (gVerbose) 1927 { 1928 1929 printf ("BaselineExposure: %+0.2f\n", 1930 fBaselineExposure.As_real64 ()); 1931 1932 } 1933 1934 #endif 1935 1936 break; 1937 1938 } 1939 1940 case tcBaselineNoise: 1941 { 1942 1943 CheckTagType (parentCode, tagCode, tagType, ttRational); 1944 1945 CheckTagCount (parentCode, tagCode, tagCount, 1); 1946 1947 fBaselineNoise = stream.TagValue_urational (tagType); 1948 1949 #if qDNGValidate 1950 1951 if (gVerbose) 1952 { 1953 1954 printf ("BaselineNoise: %0.2f\n", 1955 fBaselineNoise.As_real64 ()); 1956 1957 } 1958 1959 #endif 1960 1961 break; 1962 1963 } 1964 1965 case tcNoiseReductionApplied: 1966 { 1967 1968 if (!CheckTagType (parentCode, tagCode, tagType, ttRational)) 1969 return false; 1970 1971 if (!CheckTagCount (parentCode, tagCode, tagCount, 1)) 1972 return false; 1973 1974 fNoiseReductionApplied = stream.TagValue_urational (tagType); 1975 1976 #if qDNGValidate 1977 1978 if (gVerbose) 1979 { 1980 1981 printf ("NoiseReductionApplied: %u/%u\n", 1982 (unsigned) fNoiseReductionApplied.n, 1983 (unsigned) fNoiseReductionApplied.d); 1984 1985 } 1986 1987 #endif 1988 1989 break; 1990 1991 } 1992 1993 case tcNoiseProfile: 1994 { 1995 1996 if (!CheckTagType (parentCode, tagCode, tagType, ttDouble)) 1997 return false; 1998 1999 // Must be an even, positive number of doubles in a noise profile. 2000 2001 if (!tagCount || (tagCount & 1)) 2002 return false; 2003 2004 // Determine number of planes (i.e., half the number of doubles). 2005 2006 const uint32 numPlanes = Pin_uint32 (0, 2007 tagCount >> 1, 2008 kMaxColorPlanes); 2009 2010 // Parse the noise function parameters. 2011 2012 dng_std_vector<dng_noise_function> noiseFunctions; 2013 2014 for (uint32 i = 0; i < numPlanes; i++) 2015 { 2016 2017 const real64 scale = stream.TagValue_real64 (tagType); 2018 const real64 offset = stream.TagValue_real64 (tagType); 2019 2020 noiseFunctions.push_back (dng_noise_function (scale, offset)); 2021 2022 } 2023 2024 // Store the noise profile. 2025 2026 fNoiseProfile = dng_noise_profile (noiseFunctions); 2027 2028 // Debug. 2029 2030 #if qDNGValidate 2031 2032 if (gVerbose) 2033 { 2034 2035 printf ("NoiseProfile:\n"); 2036 2037 printf (" Planes: %u\n", (unsigned) numPlanes); 2038 2039 for (uint32 plane = 0; plane < numPlanes; plane++) 2040 { 2041 2042 printf (" Noise function for plane %u: scale = %.8lf, offset = %.8lf\n", 2043 (unsigned) plane, 2044 noiseFunctions [plane].Scale (), 2045 noiseFunctions [plane].Offset ()); 2046 2047 } 2048 2049 } 2050 2051 #endif 2052 2053 break; 2054 2055 } 2056 2057 case tcBaselineSharpness: 2058 { 2059 2060 CheckTagType (parentCode, tagCode, tagType, ttRational); 2061 2062 CheckTagCount (parentCode, tagCode, tagCount, 1); 2063 2064 fBaselineSharpness = stream.TagValue_urational (tagType); 2065 2066 #if qDNGValidate 2067 2068 if (gVerbose) 2069 { 2070 2071 printf ("BaselineSharpness: %0.2f\n", 2072 fBaselineSharpness.As_real64 ()); 2073 2074 } 2075 2076 #endif 2077 2078 break; 2079 2080 } 2081 2082 case tcLinearResponseLimit: 2083 { 2084 2085 CheckTagType (parentCode, tagCode, tagType, ttRational); 2086 2087 CheckTagCount (parentCode, tagCode, tagCount, 1); 2088 2089 fLinearResponseLimit = stream.TagValue_urational (tagType); 2090 2091 #if qDNGValidate 2092 2093 if (gVerbose) 2094 { 2095 2096 printf ("LinearResponseLimit: %0.2f\n", 2097 fLinearResponseLimit.As_real64 ()); 2098 2099 } 2100 2101 #endif 2102 2103 break; 2104 2105 } 2106 2107 case tcShadowScale: 2108 { 2109 2110 CheckTagType (parentCode, tagCode, tagType, ttRational); 2111 2112 CheckTagCount (parentCode, tagCode, tagCount, 1); 2113 2114 fShadowScale = stream.TagValue_urational (tagType); 2115 2116 fHasShadowScale = true; 2117 2118 #if qDNGValidate 2119 2120 if (gVerbose) 2121 { 2122 2123 printf ("ShadowScale: %0.4f\n", 2124 fShadowScale.As_real64 ()); 2125 2126 } 2127 2128 #endif 2129 2130 break; 2131 2132 } 2133 2134 case tcDNGPrivateData: 2135 { 2136 2137 CheckTagType (parentCode, tagCode, tagType, ttByte); 2138 2139 fDNGPrivateDataCount = tagCount; 2140 fDNGPrivateDataOffset = tagOffset; 2141 2142 #if qDNGValidate 2143 2144 if (gVerbose) 2145 { 2146 2147 printf ("DNGPrivateData: Count = %u, Offset = %u\n", 2148 (unsigned) fDNGPrivateDataCount, 2149 (unsigned) fDNGPrivateDataOffset); 2150 2151 DumpHexAscii (stream, tagCount); 2152 2153 } 2154 2155 #endif 2156 2157 break; 2158 2159 } 2160 2161 case tcMakerNoteSafety: 2162 { 2163 2164 CheckTagType (parentCode, tagCode, tagType, ttShort); 2165 2166 CheckTagCount (parentCode, tagCode, tagCount, 1); 2167 2168 fMakerNoteSafety = stream.TagValue_uint32 (tagType); 2169 2170 #if qDNGValidate 2171 2172 if (gVerbose) 2173 { 2174 2175 printf ("MakerNoteSafety: %s\n", 2176 LookupMakerNoteSafety (fMakerNoteSafety)); 2177 2178 } 2179 2180 #endif 2181 2182 break; 2183 2184 } 2185 2186 case tcRawImageDigest: 2187 { 2188 2189 if (!CheckTagType (parentCode, tagCode, tagType, ttByte)) 2190 return false; 2191 2192 if (!CheckTagCount (parentCode, tagCode, tagCount, 16)) 2193 return false; 2194 2195 stream.Get (fRawImageDigest.data, 16); 2196 2197 #if qDNGValidate 2198 2199 if (gVerbose) 2200 { 2201 2202 printf ("RawImageDigest: "); 2203 2204 DumpFingerprint (fRawImageDigest); 2205 2206 printf ("\n"); 2207 2208 } 2209 2210 #endif 2211 2212 break; 2213 2214 } 2215 2216 case tcNewRawImageDigest: 2217 { 2218 2219 if (!CheckTagType (parentCode, tagCode, tagType, ttByte)) 2220 return false; 2221 2222 if (!CheckTagCount (parentCode, tagCode, tagCount, 16)) 2223 return false; 2224 2225 stream.Get (fNewRawImageDigest.data, 16); 2226 2227 #if qDNGValidate 2228 2229 if (gVerbose) 2230 { 2231 2232 printf ("NewRawImageDigest: "); 2233 2234 DumpFingerprint (fNewRawImageDigest); 2235 2236 printf ("\n"); 2237 2238 } 2239 2240 #endif 2241 2242 break; 2243 2244 } 2245 2246 case tcRawDataUniqueID: 2247 { 2248 2249 if (!CheckTagType (parentCode, tagCode, tagType, ttByte)) 2250 return false; 2251 2252 if (!CheckTagCount (parentCode, tagCode, tagCount, 16)) 2253 return false; 2254 2255 stream.Get (fRawDataUniqueID.data, 16); 2256 2257 #if qDNGValidate 2258 2259 if (gVerbose) 2260 { 2261 2262 printf ("RawDataUniqueID: "); 2263 2264 DumpFingerprint (fRawDataUniqueID); 2265 2266 printf ("\n"); 2267 2268 } 2269 2270 #endif 2271 2272 break; 2273 2274 } 2275 2276 case tcOriginalRawFileName: 2277 { 2278 2279 CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); 2280 2281 ParseStringTag (stream, 2282 parentCode, 2283 tagCode, 2284 tagCount, 2285 fOriginalRawFileName, 2286 false); 2287 2288 #if qDNGValidate 2289 2290 if (gVerbose) 2291 { 2292 2293 printf ("OriginalRawFileName: "); 2294 2295 DumpString (fOriginalRawFileName); 2296 2297 printf ("\n"); 2298 2299 } 2300 2301 #endif 2302 2303 break; 2304 2305 } 2306 2307 case tcOriginalRawFileData: 2308 { 2309 2310 CheckTagType (parentCode, tagCode, tagType, ttUndefined); 2311 2312 fOriginalRawFileDataCount = tagCount; 2313 fOriginalRawFileDataOffset = tagOffset; 2314 2315 #if qDNGValidate 2316 2317 if (gVerbose) 2318 { 2319 2320 printf ("OriginalRawFileData: Count = %u, Offset = %u\n", 2321 (unsigned) fOriginalRawFileDataCount, 2322 (unsigned) fOriginalRawFileDataOffset); 2323 2324 DumpHexAscii (stream, tagCount); 2325 2326 } 2327 2328 #endif 2329 2330 break; 2331 2332 } 2333 2334 case tcOriginalRawFileDigest: 2335 { 2336 2337 if (!CheckTagType (parentCode, tagCode, tagType, ttByte)) 2338 return false; 2339 2340 if (!CheckTagCount (parentCode, tagCode, tagCount, 16)) 2341 return false; 2342 2343 stream.Get (fOriginalRawFileDigest.data, 16); 2344 2345 #if qDNGValidate 2346 2347 if (gVerbose) 2348 { 2349 2350 printf ("OriginalRawFileDigest: "); 2351 2352 DumpFingerprint (fOriginalRawFileDigest); 2353 2354 printf ("\n"); 2355 2356 } 2357 2358 #endif 2359 2360 break; 2361 2362 } 2363 2364 case tcAsShotICCProfile: 2365 { 2366 2367 CheckTagType (parentCode, tagCode, tagType, ttUndefined); 2368 2369 fAsShotICCProfileCount = tagCount; 2370 fAsShotICCProfileOffset = tagOffset; 2371 2372 #if qDNGValidate 2373 2374 if (gVerbose) 2375 { 2376 2377 printf ("AsShotICCProfile: Count = %u, Offset = %u\n", 2378 (unsigned) fAsShotICCProfileCount, 2379 (unsigned) fAsShotICCProfileOffset); 2380 2381 DumpHexAscii (stream, tagCount); 2382 2383 } 2384 2385 #endif 2386 2387 break; 2388 2389 } 2390 2391 case tcAsShotPreProfileMatrix: 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 fAsShotPreProfileMatrix)) 2414 return false; 2415 2416 #if qDNGValidate 2417 2418 if (gVerbose) 2419 { 2420 2421 printf ("AsShotPreProfileMatrix:\n"); 2422 2423 DumpMatrix (fAsShotPreProfileMatrix); 2424 2425 } 2426 2427 #endif 2428 2429 break; 2430 2431 } 2432 2433 case tcCurrentICCProfile: 2434 { 2435 2436 CheckTagType (parentCode, tagCode, tagType, ttUndefined); 2437 2438 fCurrentICCProfileCount = tagCount; 2439 fCurrentICCProfileOffset = tagOffset; 2440 2441 #if qDNGValidate 2442 2443 if (gVerbose) 2444 { 2445 2446 printf ("CurrentICCProfile: Count = %u, Offset = %u\n", 2447 (unsigned) fCurrentICCProfileCount, 2448 (unsigned) fCurrentICCProfileOffset); 2449 2450 DumpHexAscii (stream, tagCount); 2451 2452 } 2453 2454 #endif 2455 2456 break; 2457 2458 } 2459 2460 case tcCurrentPreProfileMatrix: 2461 { 2462 2463 CheckTagType (parentCode, tagCode, tagType, ttSRational); 2464 2465 if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes)) 2466 return false; 2467 2468 uint32 rows = fCameraProfile.fColorPlanes; 2469 2470 if (tagCount == fCameraProfile.fColorPlanes * 3) 2471 { 2472 rows = 3; 2473 } 2474 2475 if (!ParseMatrixTag (stream, 2476 parentCode, 2477 tagCode, 2478 tagType, 2479 tagCount, 2480 rows, 2481 fCameraProfile.fColorPlanes, 2482 fCurrentPreProfileMatrix)) 2483 return false; 2484 2485 #if qDNGValidate 2486 2487 if (gVerbose) 2488 { 2489 2490 printf ("CurrentPreProfileMatrix:\n"); 2491 2492 DumpMatrix (fCurrentPreProfileMatrix); 2493 2494 } 2495 2496 #endif 2497 2498 break; 2499 2500 } 2501 2502 case tcColorimetricReference: 2503 { 2504 2505 CheckTagType (parentCode, tagCode, tagType, ttShort); 2506 2507 CheckTagCount (parentCode, tagCode, tagCount, 1); 2508 2509 fColorimetricReference = stream.TagValue_uint32 (tagType); 2510 2511 #if qDNGValidate 2512 2513 if (gVerbose) 2514 { 2515 2516 printf ("ColorimetricReference: %s\n", 2517 LookupColorimetricReference (fColorimetricReference)); 2518 2519 } 2520 2521 #endif 2522 2523 break; 2524 2525 } 2526 2527 case tcExtraCameraProfiles: 2528 { 2529 2530 CheckTagType (parentCode, tagCode, tagType, ttLong); 2531 2532 CheckTagCount (parentCode, tagCode, tagCount, 1, tagCount); 2533 2534 #if qDNGValidate 2535 2536 if (gVerbose) 2537 { 2538 2539 printf ("ExtraCameraProfiles: %u\n", (unsigned) tagCount); 2540 2541 } 2542 2543 #endif 2544 2545 fExtraCameraProfiles.reserve (tagCount); 2546 2547 for (uint32 index = 0; index < tagCount; index++) 2548 { 2549 2550 #if qDNGValidate 2551 2552 if (gVerbose) 2553 { 2554 2555 printf ("\nExtraCameraProfile [%u]:\n\n", (unsigned) index); 2556 2557 } 2558 2559 #endif 2560 2561 stream.SetReadPosition (tagOffset + index * 4); 2562 2563 uint32 profileOffset = stream.TagValue_uint32 (tagType); 2564 2565 dng_camera_profile_info profileInfo; 2566 2567 stream.SetReadPosition (profileOffset); 2568 2569 if (profileInfo.ParseExtended (stream)) 2570 { 2571 2572 fExtraCameraProfiles.push_back (profileInfo); 2573 2574 } 2575 2576 else 2577 { 2578 2579 #if qDNGValidate 2580 2581 ReportWarning ("Unable to parse extra camera profile"); 2582 2583 #endif 2584 2585 } 2586 2587 } 2588 2589 #if qDNGValidate 2590 2591 if (gVerbose) 2592 { 2593 2594 printf ("\nDone with ExtraCameraProfiles\n\n"); 2595 2596 } 2597 2598 #endif 2599 2600 break; 2601 2602 } 2603 2604 case tcAsShotProfileName: 2605 { 2606 2607 CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte); 2608 2609 ParseStringTag (stream, 2610 parentCode, 2611 tagCode, 2612 tagCount, 2613 fAsShotProfileName, 2614 false); 2615 2616 #if qDNGValidate 2617 2618 if (gVerbose) 2619 { 2620 2621 printf ("AsShotProfileName: "); 2622 2623 DumpString (fAsShotProfileName); 2624 2625 printf ("\n"); 2626 2627 } 2628 2629 #endif 2630 2631 break; 2632 2633 } 2634 2635 case tcOriginalDefaultFinalSize: 2636 { 2637 2638 CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong); 2639 2640 if (!CheckTagCount (parentCode, tagCode, tagCount, 2)) 2641 return false; 2642 2643 fOriginalDefaultFinalSize.h = stream.TagValue_int32 (tagType); 2644 fOriginalDefaultFinalSize.v = stream.TagValue_int32 (tagType); 2645 2646 #if qDNGValidate 2647 2648 if (gVerbose) 2649 { 2650 2651 printf ("OriginalDefaultFinalSize: H = %d V = %d\n", 2652 (int) fOriginalDefaultFinalSize.h, 2653 (int) fOriginalDefaultFinalSize.v); 2654 2655 } 2656 2657 #endif 2658 2659 break; 2660 2661 } 2662 2663 case tcOriginalBestQualityFinalSize: 2664 { 2665 2666 CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong); 2667 2668 if (!CheckTagCount (parentCode, tagCode, tagCount, 2)) 2669 return false; 2670 2671 fOriginalBestQualityFinalSize.h = stream.TagValue_int32 (tagType); 2672 fOriginalBestQualityFinalSize.v = stream.TagValue_int32 (tagType); 2673 2674 #if qDNGValidate 2675 2676 if (gVerbose) 2677 { 2678 2679 printf ("OriginalBestQualityFinalSize: H = %d V = %d\n", 2680 (int) fOriginalBestQualityFinalSize.h, 2681 (int) fOriginalBestQualityFinalSize.v); 2682 2683 } 2684 2685 #endif 2686 2687 break; 2688 2689 } 2690 2691 case tcOriginalDefaultCropSize: 2692 { 2693 2694 CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong, ttRational); 2695 2696 if (!CheckTagCount (parentCode, tagCode, tagCount, 2)) 2697 return false; 2698 2699 fOriginalDefaultCropSizeH = stream.TagValue_urational (tagType); 2700 fOriginalDefaultCropSizeV = stream.TagValue_urational (tagType); 2701 2702 #if qDNGValidate 2703 2704 if (gVerbose) 2705 { 2706 2707 printf ("OriginalDefaultCropSize: H = %0.2f V = %0.2f\n", 2708 fOriginalDefaultCropSizeH.As_real64 (), 2709 fOriginalDefaultCropSizeV.As_real64 ()); 2710 2711 } 2712 2713 #endif 2714 2715 break; 2716 2717 } 2718 2719 default: 2720 { 2721 2722 // The main camera profile tags also appear in IFD 0 2723 2724 return fCameraProfile.ParseTag (stream, 2725 parentCode, 2726 tagCode, 2727 tagType, 2728 tagCount, 2729 tagOffset); 2730 2731 } 2732 2733 } 2734 2735 return true; 2736 2737 } 2738 2739 /*****************************************************************************/ 2740 2741 // Parses tags that should only appear in IFD 0 or EXIF IFD. 2742 2743 bool dng_shared::Parse_ifd0_exif (dng_stream &stream, 2744 dng_exif & /* exif */, 2745 uint32 parentCode, 2746 uint32 tagCode, 2747 uint32 tagType, 2748 uint32 tagCount, 2749 uint64 tagOffset) 2750 { 2751 2752 switch (tagCode) 2753 { 2754 2755 case tcMakerNote: 2756 { 2757 2758 CheckTagType (parentCode, tagCode, tagType, ttUndefined); 2759 2760 fMakerNoteCount = tagCount; 2761 fMakerNoteOffset = tagOffset; 2762 2763 #if qDNGValidate 2764 2765 if (gVerbose) 2766 { 2767 2768 printf ("MakerNote: Count = %u, Offset = %u\n", 2769 (unsigned) fMakerNoteCount, 2770 (unsigned) fMakerNoteOffset); 2771 2772 DumpHexAscii (stream, tagCount); 2773 2774 } 2775 2776 #endif 2777 2778 break; 2779 2780 } 2781 2782 case tcInteroperabilityIFD: 2783 { 2784 2785 CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD); 2786 2787 CheckTagCount (parentCode, tagCode, tagCount, 1); 2788 2789 fInteroperabilityIFD = stream.TagValue_uint32 (tagType); 2790 2791 #if qDNGValidate 2792 2793 if (gVerbose) 2794 { 2795 printf ("InteroperabilityIFD: %u\n", (unsigned) fInteroperabilityIFD); 2796 } 2797 2798 #endif 2799 2800 break; 2801 2802 } 2803 2804 default: 2805 { 2806 2807 return false; 2808 2809 } 2810 2811 } 2812 2813 return true; 2814 2815 } 2816 2817 /*****************************************************************************/ 2818 2819 void dng_shared::PostParse (dng_host & /* host */, 2820 dng_exif & /* exif */) 2821 { 2822 2823 // Fill in default values for DNG images. 2824 2825 if (fDNGVersion != 0) 2826 { 2827 2828 // Support for DNG versions before 1.0.0.0. 2829 2830 if (fDNGVersion < dngVersion_1_0_0_0) 2831 { 2832 2833 #if qDNGValidate 2834 2835 ReportWarning ("DNGVersion less than 1.0.0.0"); 2836 2837 #endif 2838 2839 // The CalibrationIlluminant tags were added just before 2840 // DNG version 1.0.0.0, and were hardcoded before that. 2841 2842 fCameraProfile.fCalibrationIlluminant1 = lsStandardLightA; 2843 fCameraProfile.fCalibrationIlluminant2 = lsD65; 2844 2845 fDNGVersion = dngVersion_1_0_0_0; 2846 2847 } 2848 2849 // Default value for DNGBackwardVersion tag. 2850 2851 if (fDNGBackwardVersion == 0) 2852 { 2853 2854 fDNGBackwardVersion = fDNGVersion & 0xFFFF0000; 2855 2856 } 2857 2858 // Check DNGBackwardVersion value. 2859 2860 if (fDNGBackwardVersion < dngVersion_1_0_0_0) 2861 { 2862 2863 #if qDNGValidate 2864 2865 ReportWarning ("DNGBackwardVersion less than 1.0.0.0"); 2866 2867 #endif 2868 2869 fDNGBackwardVersion = dngVersion_1_0_0_0; 2870 2871 } 2872 2873 if (fDNGBackwardVersion > fDNGVersion) 2874 { 2875 2876 #if qDNGValidate 2877 2878 ReportWarning ("DNGBackwardVersion > DNGVersion"); 2879 2880 #endif 2881 2882 fDNGBackwardVersion = fDNGVersion; 2883 2884 } 2885 2886 // Check UniqueCameraModel. 2887 2888 if (fUniqueCameraModel.IsEmpty ()) 2889 { 2890 2891 #if qDNGValidate 2892 2893 ReportWarning ("Missing or invalid UniqueCameraModel"); 2894 2895 #endif 2896 2897 fUniqueCameraModel.Set ("Digital Negative"); 2898 2899 } 2900 2901 // If we don't know the color depth yet, it must be a monochrome DNG. 2902 2903 if (fCameraProfile.fColorPlanes == 0) 2904 { 2905 2906 fCameraProfile.fColorPlanes = 1; 2907 2908 } 2909 2910 // Check color info. 2911 2912 if (fCameraProfile.fColorPlanes > 1) 2913 { 2914 2915 // Check illuminant pair. 2916 2917 if (fCameraProfile.fColorMatrix2.NotEmpty ()) 2918 { 2919 2920 if (fCameraProfile.fCalibrationIlluminant1 == lsUnknown || 2921 (fCameraProfile.fCalibrationIlluminant2 == lsUnknown || 2922 (fCameraProfile.fCalibrationIlluminant1 == fCameraProfile.fCalibrationIlluminant2))) 2923 { 2924 2925 #if qDNGValidate 2926 2927 ReportWarning ("Invalid CalibrationIlluminant pair"); 2928 2929 #endif 2930 2931 fCameraProfile.fColorMatrix2 = dng_matrix (); 2932 2933 } 2934 2935 } 2936 2937 // If the colorimetric reference is the ICC profile PCS, then the 2938 // data must already be white balanced. The "AsShotWhiteXY" is required 2939 // to be the ICC Profile PCS white point. 2940 2941 if (fColorimetricReference == crICCProfilePCS) 2942 { 2943 2944 if (fAsShotNeutral.NotEmpty ()) 2945 { 2946 2947 #if qDNGValidate 2948 2949 ReportWarning ("AsShotNeutral not allowed for this " 2950 "ColorimetricReference value"); 2951 2952 #endif 2953 2954 fAsShotNeutral.Clear (); 2955 2956 } 2957 2958 dng_xy_coord pcs = PCStoXY (); 2959 2960 #if qDNGValidate 2961 2962 if (fAsShotWhiteXY.IsValid ()) 2963 { 2964 2965 if (Abs_real64 (fAsShotWhiteXY.x - pcs.x) > 0.01 || 2966 Abs_real64 (fAsShotWhiteXY.y - pcs.y) > 0.01) 2967 { 2968 2969 ReportWarning ("AsShotWhiteXY does not match the ICC Profile PCS"); 2970 2971 } 2972 2973 } 2974 2975 #endif 2976 2977 fAsShotWhiteXY = pcs; 2978 2979 } 2980 2981 else 2982 { 2983 2984 // Warn if both AsShotNeutral and AsShotWhiteXY are specified. 2985 2986 if (fAsShotNeutral.NotEmpty () && fAsShotWhiteXY.IsValid ()) 2987 { 2988 2989 #if qDNGValidate 2990 2991 ReportWarning ("Both AsShotNeutral and AsShotWhiteXY included"); 2992 2993 #endif 2994 2995 fAsShotWhiteXY = dng_xy_coord (); 2996 2997 } 2998 2999 // Warn if neither AsShotNeutral nor AsShotWhiteXY are specified. 3000 3001 #if qDNGValidate 3002 3003 if (fAsShotNeutral.IsEmpty () && !fAsShotWhiteXY.IsValid ()) 3004 { 3005 3006 ReportWarning ("Neither AsShotNeutral nor AsShotWhiteXY included", 3007 "legal but not recommended"); 3008 3009 } 3010 3011 #endif 3012 3013 } 3014 3015 // Default values of calibration signatures are required for legacy 3016 // compatiblity. 3017 3018 if (fCameraProfile.fCalibrationIlluminant1 == lsStandardLightA && 3019 fCameraProfile.fCalibrationIlluminant2 == lsD65 && 3020 fCameraCalibration1.Rows () == fCameraProfile.fColorPlanes && 3021 fCameraCalibration1.Cols () == fCameraProfile.fColorPlanes && 3022 fCameraCalibration2.Rows () == fCameraProfile.fColorPlanes && 3023 fCameraCalibration2.Cols () == fCameraProfile.fColorPlanes && 3024 fCameraCalibrationSignature.IsEmpty () && 3025 fCameraProfile.fProfileCalibrationSignature.IsEmpty () ) 3026 { 3027 3028 fCameraCalibrationSignature.Set (kAdobeCalibrationSignature); 3029 3030 fCameraProfile.fProfileCalibrationSignature.Set (kAdobeCalibrationSignature); 3031 3032 } 3033 3034 } 3035 3036 // Check BaselineNoise. 3037 3038 if (fBaselineNoise.As_real64 () <= 0.0) 3039 { 3040 3041 #if qDNGValidate 3042 3043 ReportWarning ("Invalid BaselineNoise"); 3044 3045 #endif 3046 3047 fBaselineNoise = dng_urational (1, 1); 3048 3049 } 3050 3051 // Check BaselineSharpness. 3052 3053 if (fBaselineSharpness.As_real64 () <= 0.0) 3054 { 3055 3056 #if qDNGValidate 3057 3058 ReportWarning ("Invalid BaselineSharpness"); 3059 3060 #endif 3061 3062 fBaselineSharpness = dng_urational (1, 1); 3063 3064 } 3065 3066 // Check NoiseProfile. 3067 3068 if (!fNoiseProfile.IsValid () && fNoiseProfile.NumFunctions () != 0) 3069 { 3070 3071 #if qDNGValidate 3072 3073 ReportWarning ("Invalid NoiseProfile"); 3074 3075 #endif 3076 3077 fNoiseProfile = dng_noise_profile (); 3078 3079 } 3080 3081 // Check LinearResponseLimit. 3082 3083 if (fLinearResponseLimit.As_real64 () < 0.5 || 3084 fLinearResponseLimit.As_real64 () > 1.0) 3085 { 3086 3087 #if qDNGValidate 3088 3089 ReportWarning ("Invalid LinearResponseLimit"); 3090 3091 #endif 3092 3093 fLinearResponseLimit = dng_urational (1, 1); 3094 3095 } 3096 3097 // Check ShadowScale. 3098 3099 if (fShadowScale.As_real64 () <= 0.0) 3100 { 3101 3102 #if qDNGValidate 3103 3104 ReportWarning ("Invalid ShadowScale"); 3105 3106 #endif 3107 3108 fShadowScale = dng_urational (1, 1); 3109 3110 } 3111 3112 } 3113 3114 } 3115 3116 /*****************************************************************************/ 3117 3118 bool dng_shared::IsValidDNG () 3119 { 3120 3121 // Check DNGVersion value. 3122 3123 if (fDNGVersion < dngVersion_1_0_0_0) 3124 { 3125 3126 #if qDNGValidate 3127 3128 if (fDNGVersion != dngVersion_None) 3129 { 3130 3131 ReportError ("Invalid DNGVersion"); 3132 3133 } 3134 3135 #if qDNGValidateTarget 3136 3137 else 3138 { 3139 3140 ReportError ("Missing DNGVersion"); 3141 3142 } 3143 3144 #endif 3145 3146 #endif 3147 3148 return false; 3149 3150 } 3151 3152 // Check DNGBackwardVersion value. 3153 3154 if (fDNGBackwardVersion > dngVersion_Current) 3155 { 3156 3157 #if qDNGValidate 3158 3159 ReportError ("DNGBackwardVersion (or DNGVersion) is too high"); 3160 3161 #endif 3162 3163 ThrowUnsupportedDNG (); 3164 3165 } 3166 3167 // Check color transform info. 3168 3169 if (fCameraProfile.fColorPlanes > 1) 3170 { 3171 3172 // CameraCalibration1 is optional, but it must be valid if present. 3173 3174 if (fCameraCalibration1.Cols () != 0 || 3175 fCameraCalibration1.Rows () != 0) 3176 { 3177 3178 if (fCameraCalibration1.Cols () != fCameraProfile.fColorPlanes || 3179 fCameraCalibration1.Rows () != fCameraProfile.fColorPlanes) 3180 { 3181 3182 #if qDNGValidate 3183 3184 ReportError ("CameraCalibration1 is wrong size"); 3185 3186 #endif 3187 3188 return false; 3189 3190 } 3191 3192 // Make sure it is invertable. 3193 3194 try 3195 { 3196 3197 (void) Invert (fCameraCalibration1); 3198 3199 } 3200 3201 catch (...) 3202 { 3203 3204 #if qDNGValidate 3205 3206 ReportError ("CameraCalibration1 is not invertable"); 3207 3208 #endif 3209 3210 return false; 3211 3212 } 3213 3214 } 3215 3216 // CameraCalibration2 is optional, but it must be valid if present. 3217 3218 if (fCameraCalibration2.Cols () != 0 || 3219 fCameraCalibration2.Rows () != 0) 3220 { 3221 3222 if (fCameraCalibration2.Cols () != fCameraProfile.fColorPlanes || 3223 fCameraCalibration2.Rows () != fCameraProfile.fColorPlanes) 3224 { 3225 3226 #if qDNGValidate 3227 3228 ReportError ("CameraCalibration2 is wrong size"); 3229 3230 #endif 3231 3232 return false; 3233 3234 } 3235 3236 // Make sure it is invertable. 3237 3238 try 3239 { 3240 3241 (void) Invert (fCameraCalibration2); 3242 3243 } 3244 3245 catch (...) 3246 { 3247 3248 #if qDNGValidate 3249 3250 ReportError ("CameraCalibration2 is not invertable"); 3251 3252 #endif 3253 3254 return false; 3255 3256 } 3257 3258 } 3259 3260 // Check analog balance 3261 3262 dng_matrix analogBalance; 3263 3264 if (fAnalogBalance.NotEmpty ()) 3265 { 3266 3267 analogBalance = fAnalogBalance.AsDiagonal (); 3268 3269 try 3270 { 3271 3272 (void) Invert (analogBalance); 3273 3274 } 3275 3276 catch (...) 3277 { 3278 3279 #if qDNGValidate 3280 3281 ReportError ("AnalogBalance is not invertable"); 3282 3283 #endif 3284 3285 return false; 3286 3287 } 3288 3289 } 3290 3291 } 3292 3293 return true; 3294 3295 } 3296 3297 /*****************************************************************************/ 3298