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