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_camera_profile.cpp#1 $ */ 10 /* $DateTime: 2012/05/30 13:28:51 $ */ 11 /* $Change: 832332 $ */ 12 /* $Author: tknoll $ */ 13 14 #include "dng_camera_profile.h" 15 16 #include "dng_1d_table.h" 17 #include "dng_assertions.h" 18 #include "dng_color_space.h" 19 #include "dng_host.h" 20 #include "dng_exceptions.h" 21 #include "dng_image_writer.h" 22 #include "dng_info.h" 23 #include "dng_parse_utils.h" 24 #include "dng_safe_arithmetic.h" 25 #include "dng_tag_codes.h" 26 #include "dng_tag_types.h" 27 #include "dng_temperature.h" 28 #include "dng_xy_coord.h" 29 30 /*****************************************************************************/ 31 32 const char * kProfileName_Embedded = "Embedded"; 33 34 const char * kAdobeCalibrationSignature = "com.adobe"; 35 36 /*****************************************************************************/ 37 38 dng_camera_profile::dng_camera_profile () 39 40 : fName () 41 , fCalibrationIlluminant1 (lsUnknown) 42 , fCalibrationIlluminant2 (lsUnknown) 43 , fColorMatrix1 () 44 , fColorMatrix2 () 45 , fForwardMatrix1 () 46 , fForwardMatrix2 () 47 , fReductionMatrix1 () 48 , fReductionMatrix2 () 49 , fFingerprint () 50 , fCopyright () 51 , fEmbedPolicy (pepAllowCopying) 52 , fHueSatDeltas1 () 53 , fHueSatDeltas2 () 54 , fHueSatMapEncoding (encoding_Linear) 55 , fLookTable () 56 , fLookTableEncoding (encoding_Linear) 57 , fBaselineExposureOffset (0, 100) 58 , fDefaultBlackRender (defaultBlackRender_Auto) 59 , fToneCurve () 60 , fProfileCalibrationSignature () 61 , fUniqueCameraModelRestriction () 62 , fWasReadFromDNG (false) 63 , fWasReadFromDisk (false) 64 , fWasBuiltinMatrix (false) 65 , fWasStubbed (false) 66 67 { 68 69 fToneCurve.SetInvalid (); 70 71 } 72 73 /*****************************************************************************/ 74 75 dng_camera_profile::~dng_camera_profile () 76 { 77 78 } 79 80 /*****************************************************************************/ 81 82 real64 dng_camera_profile::IlluminantToTemperature (uint32 light) 83 { 84 85 switch (light) 86 { 87 88 case lsStandardLightA: 89 case lsTungsten: 90 { 91 return 2850.0; 92 } 93 94 case lsISOStudioTungsten: 95 { 96 return 3200.0; 97 } 98 99 case lsD50: 100 { 101 return 5000.0; 102 } 103 104 case lsD55: 105 case lsDaylight: 106 case lsFineWeather: 107 case lsFlash: 108 case lsStandardLightB: 109 { 110 return 5500.0; 111 } 112 113 case lsD65: 114 case lsStandardLightC: 115 case lsCloudyWeather: 116 { 117 return 6500.0; 118 } 119 120 case lsD75: 121 case lsShade: 122 { 123 return 7500.0; 124 } 125 126 case lsDaylightFluorescent: 127 { 128 return (5700.0 + 7100.0) * 0.5; 129 } 130 131 case lsDayWhiteFluorescent: 132 { 133 return (4600.0 + 5500.0) * 0.5; 134 } 135 136 case lsCoolWhiteFluorescent: 137 case lsFluorescent: 138 { 139 return (3800.0 + 4500.0) * 0.5; 140 } 141 142 case lsWhiteFluorescent: 143 { 144 return (3250.0 + 3800.0) * 0.5; 145 } 146 147 case lsWarmWhiteFluorescent: 148 { 149 return (2600.0 + 3250.0) * 0.5; 150 } 151 152 default: 153 { 154 return 0.0; 155 } 156 157 } 158 159 } 160 161 /******************************************************************************/ 162 163 void dng_camera_profile::NormalizeColorMatrix (dng_matrix &m) 164 { 165 166 if (m.NotEmpty ()) 167 { 168 169 // Find scale factor to normalize the matrix. 170 171 dng_vector coord = m * PCStoXYZ (); 172 173 real64 maxCoord = coord.MaxEntry (); 174 175 if (maxCoord > 0.0 && (maxCoord < 0.99 || maxCoord > 1.01)) 176 { 177 178 m.Scale (1.0 / maxCoord); 179 180 } 181 182 // Round to four decimal places. 183 184 m.Round (10000); 185 186 } 187 188 } 189 190 /******************************************************************************/ 191 192 void dng_camera_profile::SetColorMatrix1 (const dng_matrix &m) 193 { 194 195 fColorMatrix1 = m; 196 197 NormalizeColorMatrix (fColorMatrix1); 198 199 ClearFingerprint (); 200 201 } 202 203 /******************************************************************************/ 204 205 void dng_camera_profile::SetColorMatrix2 (const dng_matrix &m) 206 { 207 208 fColorMatrix2 = m; 209 210 NormalizeColorMatrix (fColorMatrix2); 211 212 ClearFingerprint (); 213 214 } 215 216 /******************************************************************************/ 217 218 // Make sure the forward matrix maps to exactly the PCS. 219 220 void dng_camera_profile::NormalizeForwardMatrix (dng_matrix &m) 221 { 222 223 if (m.NotEmpty ()) 224 { 225 226 dng_vector cameraOne; 227 228 cameraOne.SetIdentity (m.Cols ()); 229 230 dng_vector xyz = m * cameraOne; 231 232 m = PCStoXYZ ().AsDiagonal () * 233 Invert (xyz.AsDiagonal ()) * 234 m; 235 236 } 237 238 } 239 240 /******************************************************************************/ 241 242 void dng_camera_profile::SetForwardMatrix1 (const dng_matrix &m) 243 { 244 245 fForwardMatrix1 = m; 246 247 fForwardMatrix1.Round (10000); 248 249 ClearFingerprint (); 250 251 } 252 253 /******************************************************************************/ 254 255 void dng_camera_profile::SetForwardMatrix2 (const dng_matrix &m) 256 { 257 258 fForwardMatrix2 = m; 259 260 fForwardMatrix2.Round (10000); 261 262 ClearFingerprint (); 263 264 } 265 266 /*****************************************************************************/ 267 268 void dng_camera_profile::SetReductionMatrix1 (const dng_matrix &m) 269 { 270 271 fReductionMatrix1 = m; 272 273 fReductionMatrix1.Round (10000); 274 275 ClearFingerprint (); 276 277 } 278 279 /******************************************************************************/ 280 281 void dng_camera_profile::SetReductionMatrix2 (const dng_matrix &m) 282 { 283 284 fReductionMatrix2 = m; 285 286 fReductionMatrix2.Round (10000); 287 288 ClearFingerprint (); 289 290 } 291 292 /*****************************************************************************/ 293 294 bool dng_camera_profile::HasColorMatrix1 () const 295 { 296 297 return fColorMatrix1.Cols () == 3 && 298 fColorMatrix1.Rows () > 1; 299 300 } 301 302 /*****************************************************************************/ 303 304 bool dng_camera_profile::HasColorMatrix2 () const 305 { 306 307 return fColorMatrix2.Cols () == 3 && 308 fColorMatrix2.Rows () == fColorMatrix1.Rows (); 309 310 } 311 312 /*****************************************************************************/ 313 314 void dng_camera_profile::SetHueSatDeltas1 (const dng_hue_sat_map &deltas1) 315 { 316 317 fHueSatDeltas1 = deltas1; 318 319 ClearFingerprint (); 320 321 } 322 323 /*****************************************************************************/ 324 325 void dng_camera_profile::SetHueSatDeltas2 (const dng_hue_sat_map &deltas2) 326 { 327 328 fHueSatDeltas2 = deltas2; 329 330 ClearFingerprint (); 331 332 } 333 334 /*****************************************************************************/ 335 336 void dng_camera_profile::SetLookTable (const dng_hue_sat_map &table) 337 { 338 339 fLookTable = table; 340 341 ClearFingerprint (); 342 343 } 344 345 /*****************************************************************************/ 346 347 static void FingerprintMatrix (dng_md5_printer_stream &printer, 348 const dng_matrix &matrix) 349 { 350 351 tag_matrix tag (0, matrix); 352 353 // Tag's Put routine doesn't write the header, only the data 354 355 tag.Put (printer); 356 357 } 358 359 /*****************************************************************************/ 360 361 static void FingerprintHueSatMap (dng_md5_printer_stream &printer, 362 const dng_hue_sat_map &map) 363 { 364 365 if (map.IsNull ()) 366 return; 367 368 uint32 hues; 369 uint32 sats; 370 uint32 vals; 371 372 map.GetDivisions (hues, sats, vals); 373 374 printer.Put_uint32 (hues); 375 printer.Put_uint32 (sats); 376 printer.Put_uint32 (vals); 377 378 for (uint32 val = 0; val < vals; val++) 379 for (uint32 hue = 0; hue < hues; hue++) 380 for (uint32 sat = 0; sat < sats; sat++) 381 { 382 383 dng_hue_sat_map::HSBModify modify; 384 385 map.GetDelta (hue, sat, val, modify); 386 387 printer.Put_real32 (modify.fHueShift); 388 printer.Put_real32 (modify.fSatScale); 389 printer.Put_real32 (modify.fValScale); 390 391 } 392 393 } 394 395 /*****************************************************************************/ 396 397 void dng_camera_profile::CalculateFingerprint () const 398 { 399 400 DNG_ASSERT (!fWasStubbed, "CalculateFingerprint on stubbed profile"); 401 402 dng_md5_printer_stream printer; 403 404 // MD5 hash is always calculated on little endian data. 405 406 printer.SetLittleEndian (); 407 408 // The data that we fingerprint closely matches that saved 409 // by the profile_tag_set class in dng_image_writer.cpp, with 410 // the exception of the fingerprint itself. 411 412 if (HasColorMatrix1 ()) 413 { 414 415 uint32 colorChannels = ColorMatrix1 ().Rows (); 416 417 printer.Put_uint16 ((uint16) fCalibrationIlluminant1); 418 419 FingerprintMatrix (printer, fColorMatrix1); 420 421 if (fForwardMatrix1.Rows () == fColorMatrix1.Cols () && 422 fForwardMatrix1.Cols () == fColorMatrix1.Rows ()) 423 { 424 425 FingerprintMatrix (printer, fForwardMatrix1); 426 427 } 428 429 if (colorChannels > 3 && fReductionMatrix1.Rows () * 430 fReductionMatrix1.Cols () == colorChannels * 3) 431 { 432 433 FingerprintMatrix (printer, fReductionMatrix1); 434 435 } 436 437 if (HasColorMatrix2 ()) 438 { 439 440 printer.Put_uint16 ((uint16) fCalibrationIlluminant2); 441 442 FingerprintMatrix (printer, fColorMatrix2); 443 444 if (fForwardMatrix2.Rows () == fColorMatrix2.Cols () && 445 fForwardMatrix2.Cols () == fColorMatrix2.Rows ()) 446 { 447 448 FingerprintMatrix (printer, fForwardMatrix2); 449 450 } 451 452 if (colorChannels > 3 && fReductionMatrix2.Rows () * 453 fReductionMatrix2.Cols () == colorChannels * 3) 454 { 455 456 FingerprintMatrix (printer, fReductionMatrix2); 457 458 } 459 460 } 461 462 printer.Put (fName.Get (), 463 fName.Length ()); 464 465 printer.Put (fProfileCalibrationSignature.Get (), 466 fProfileCalibrationSignature.Length ()); 467 468 printer.Put_uint32 (fEmbedPolicy); 469 470 printer.Put (fCopyright.Get (), 471 fCopyright.Length ()); 472 473 bool haveHueSat1 = HueSatDeltas1 ().IsValid (); 474 475 bool haveHueSat2 = HueSatDeltas2 ().IsValid () && 476 HasColorMatrix2 (); 477 478 if (haveHueSat1) 479 { 480 481 FingerprintHueSatMap (printer, fHueSatDeltas1); 482 483 } 484 485 if (haveHueSat2) 486 { 487 488 FingerprintHueSatMap (printer, fHueSatDeltas2); 489 490 } 491 492 if (haveHueSat1 || haveHueSat2) 493 { 494 495 if (fHueSatMapEncoding != 0) 496 { 497 498 printer.Put_uint32 (fHueSatMapEncoding); 499 500 } 501 502 } 503 504 if (fLookTable.IsValid ()) 505 { 506 507 FingerprintHueSatMap (printer, fLookTable); 508 509 if (fLookTableEncoding != 0) 510 { 511 512 printer.Put_uint32 (fLookTableEncoding); 513 514 } 515 516 } 517 518 if (fBaselineExposureOffset.IsValid ()) 519 { 520 521 if (fBaselineExposureOffset.As_real64 () != 0.0) 522 { 523 524 printer.Put_real64 (fBaselineExposureOffset.As_real64 ()); 525 526 } 527 528 } 529 530 if (fDefaultBlackRender != 0) 531 { 532 533 printer.Put_int32 (fDefaultBlackRender); 534 535 } 536 537 if (fToneCurve.IsValid ()) 538 { 539 540 for (uint32 i = 0; i < fToneCurve.fCoord.size (); i++) 541 { 542 543 printer.Put_real32 ((real32) fToneCurve.fCoord [i].h); 544 printer.Put_real32 ((real32) fToneCurve.fCoord [i].v); 545 546 } 547 548 } 549 550 } 551 552 fFingerprint = printer.Result (); 553 554 } 555 556 /******************************************************************************/ 557 558 bool dng_camera_profile::ValidForwardMatrix (const dng_matrix &m) 559 { 560 561 const real64 kThreshold = 0.01; 562 563 if (m.NotEmpty ()) 564 { 565 566 dng_vector cameraOne; 567 568 cameraOne.SetIdentity (m.Cols ()); 569 570 dng_vector xyz = m * cameraOne; 571 572 dng_vector pcs = PCStoXYZ (); 573 574 if (Abs_real64 (xyz [0] - pcs [0]) > kThreshold || 575 Abs_real64 (xyz [1] - pcs [1]) > kThreshold || 576 Abs_real64 (xyz [2] - pcs [2]) > kThreshold) 577 { 578 579 return false; 580 581 } 582 583 } 584 585 return true; 586 587 } 588 589 /******************************************************************************/ 590 591 bool dng_camera_profile::IsValid (uint32 channels) const 592 { 593 594 // For Monochrome images, we ignore the camera profile. 595 596 if (channels == 1) 597 { 598 599 return true; 600 601 } 602 603 // ColorMatrix1 is required for all color images. 604 605 if (fColorMatrix1.Cols () != 3 || 606 fColorMatrix1.Rows () != channels) 607 { 608 609 #if qDNGValidate 610 611 ReportError ("ColorMatrix1 is wrong size"); 612 613 #endif 614 615 return false; 616 617 } 618 619 // ColorMatrix2 is optional, but it must be valid if present. 620 621 if (fColorMatrix2.Cols () != 0 || 622 fColorMatrix2.Rows () != 0) 623 { 624 625 if (fColorMatrix2.Cols () != 3 || 626 fColorMatrix2.Rows () != channels) 627 { 628 629 #if qDNGValidate 630 631 ReportError ("ColorMatrix2 is wrong size"); 632 633 #endif 634 635 return false; 636 637 } 638 639 } 640 641 // ForwardMatrix1 is optional, but it must be valid if present. 642 643 if (fForwardMatrix1.Cols () != 0 || 644 fForwardMatrix1.Rows () != 0) 645 { 646 647 if (fForwardMatrix1.Rows () != 3 || 648 fForwardMatrix1.Cols () != channels) 649 { 650 651 #if qDNGValidate 652 653 ReportError ("ForwardMatrix1 is wrong size"); 654 655 #endif 656 657 return false; 658 659 } 660 661 // Make sure ForwardMatrix1 does a valid mapping. 662 663 if (!ValidForwardMatrix (fForwardMatrix1)) 664 { 665 666 #if qDNGValidate 667 668 ReportError ("ForwardMatrix1 does not map equal camera values to XYZ D50"); 669 670 #endif 671 672 return false; 673 674 } 675 676 } 677 678 // ForwardMatrix2 is optional, but it must be valid if present. 679 680 if (fForwardMatrix2.Cols () != 0 || 681 fForwardMatrix2.Rows () != 0) 682 { 683 684 if (fForwardMatrix2.Rows () != 3 || 685 fForwardMatrix2.Cols () != channels) 686 { 687 688 #if qDNGValidate 689 690 ReportError ("ForwardMatrix2 is wrong size"); 691 692 #endif 693 694 return false; 695 696 } 697 698 // Make sure ForwardMatrix2 does a valid mapping. 699 700 if (!ValidForwardMatrix (fForwardMatrix2)) 701 { 702 703 #if qDNGValidate 704 705 ReportError ("ForwardMatrix2 does not map equal camera values to XYZ D50"); 706 707 #endif 708 709 return false; 710 711 } 712 713 } 714 715 // ReductionMatrix1 is optional, but it must be valid if present. 716 717 if (fReductionMatrix1.Cols () != 0 || 718 fReductionMatrix1.Rows () != 0) 719 { 720 721 if (fReductionMatrix1.Cols () != channels || 722 fReductionMatrix1.Rows () != 3) 723 { 724 725 #if qDNGValidate 726 727 ReportError ("ReductionMatrix1 is wrong size"); 728 729 #endif 730 731 return false; 732 733 } 734 735 } 736 737 // ReductionMatrix2 is optional, but it must be valid if present. 738 739 if (fReductionMatrix2.Cols () != 0 || 740 fReductionMatrix2.Rows () != 0) 741 { 742 743 if (fReductionMatrix2.Cols () != channels || 744 fReductionMatrix2.Rows () != 3) 745 { 746 747 #if qDNGValidate 748 749 ReportError ("ReductionMatrix2 is wrong size"); 750 751 #endif 752 753 return false; 754 755 } 756 757 } 758 759 // Make sure ColorMatrix1 is invertable. 760 761 try 762 { 763 764 if (fReductionMatrix1.NotEmpty ()) 765 { 766 767 (void) Invert (fColorMatrix1, 768 fReductionMatrix1); 769 770 } 771 772 else 773 { 774 775 (void) Invert (fColorMatrix1); 776 777 } 778 779 } 780 781 catch (...) 782 { 783 784 #if qDNGValidate 785 786 ReportError ("ColorMatrix1 is not invertable"); 787 788 #endif 789 790 return false; 791 792 } 793 794 // Make sure ColorMatrix2 is invertable. 795 796 if (fColorMatrix2.NotEmpty ()) 797 { 798 799 try 800 { 801 802 if (fReductionMatrix2.NotEmpty ()) 803 { 804 805 (void) Invert (fColorMatrix2, 806 fReductionMatrix2); 807 808 } 809 810 else 811 { 812 813 (void) Invert (fColorMatrix2); 814 815 } 816 817 } 818 819 catch (...) 820 { 821 822 #if qDNGValidate 823 824 ReportError ("ColorMatrix2 is not invertable"); 825 826 #endif 827 828 return false; 829 830 } 831 832 } 833 834 return true; 835 836 } 837 838 /*****************************************************************************/ 839 840 bool dng_camera_profile::EqualData (const dng_camera_profile &profile) const 841 { 842 843 return fCalibrationIlluminant1 == profile.fCalibrationIlluminant1 && 844 fCalibrationIlluminant2 == profile.fCalibrationIlluminant2 && 845 fColorMatrix1 == profile.fColorMatrix1 && 846 fColorMatrix2 == profile.fColorMatrix2 && 847 fForwardMatrix1 == profile.fForwardMatrix1 && 848 fForwardMatrix2 == profile.fForwardMatrix2 && 849 fReductionMatrix1 == profile.fReductionMatrix1 && 850 fReductionMatrix2 == profile.fReductionMatrix2 && 851 fHueSatDeltas1 == profile.fHueSatDeltas1 && 852 fHueSatDeltas2 == profile.fHueSatDeltas2 && 853 fHueSatMapEncoding == profile.fHueSatMapEncoding && 854 fLookTable == profile.fLookTable && 855 fLookTableEncoding == profile.fLookTableEncoding && 856 fDefaultBlackRender == profile.fDefaultBlackRender && 857 fToneCurve == profile.fToneCurve && 858 fBaselineExposureOffset.As_real64 () == profile.fBaselineExposureOffset.As_real64 () && 859 fProfileCalibrationSignature == profile.fProfileCalibrationSignature; 860 861 } 862 863 /*****************************************************************************/ 864 865 void dng_camera_profile::ReadHueSatMap (dng_stream &stream, 866 dng_hue_sat_map &hueSatMap, 867 uint32 hues, 868 uint32 sats, 869 uint32 vals, 870 bool skipSat0) 871 { 872 873 hueSatMap.SetDivisions (hues, sats, vals); 874 875 for (uint32 val = 0; val < vals; val++) 876 { 877 878 for (uint32 hue = 0; hue < hues; hue++) 879 { 880 881 for (uint32 sat = skipSat0 ? 1 : 0; sat < sats; sat++) 882 { 883 884 dng_hue_sat_map::HSBModify modify; 885 886 modify.fHueShift = stream.Get_real32 (); 887 modify.fSatScale = stream.Get_real32 (); 888 modify.fValScale = stream.Get_real32 (); 889 890 hueSatMap.SetDelta (hue, sat, val, modify); 891 892 } 893 894 } 895 896 } 897 898 } 899 900 /*****************************************************************************/ 901 902 void dng_camera_profile::Parse (dng_stream &stream, 903 dng_camera_profile_info &profileInfo) 904 { 905 906 SetUniqueCameraModelRestriction (profileInfo.fUniqueCameraModel.Get ()); 907 908 if (profileInfo.fProfileName.NotEmpty ()) 909 { 910 911 SetName (profileInfo.fProfileName.Get ()); 912 913 } 914 915 SetCopyright (profileInfo.fProfileCopyright.Get ()); 916 917 SetEmbedPolicy (profileInfo.fEmbedPolicy); 918 919 SetCalibrationIlluminant1 (profileInfo.fCalibrationIlluminant1); 920 921 SetColorMatrix1 (profileInfo.fColorMatrix1); 922 923 if (profileInfo.fForwardMatrix1.NotEmpty ()) 924 { 925 926 SetForwardMatrix1 (profileInfo.fForwardMatrix1); 927 928 } 929 930 if (profileInfo.fReductionMatrix1.NotEmpty ()) 931 { 932 933 SetReductionMatrix1 (profileInfo.fReductionMatrix1); 934 935 } 936 937 if (profileInfo.fColorMatrix2.NotEmpty ()) 938 { 939 940 SetCalibrationIlluminant2 (profileInfo.fCalibrationIlluminant2); 941 942 SetColorMatrix2 (profileInfo.fColorMatrix2); 943 944 if (profileInfo.fForwardMatrix2.NotEmpty ()) 945 { 946 947 SetForwardMatrix2 (profileInfo.fForwardMatrix2); 948 949 } 950 951 if (profileInfo.fReductionMatrix2.NotEmpty ()) 952 { 953 954 SetReductionMatrix2 (profileInfo.fReductionMatrix2); 955 956 } 957 958 } 959 960 SetProfileCalibrationSignature (profileInfo.fProfileCalibrationSignature.Get ()); 961 962 if (profileInfo.fHueSatDeltas1Offset != 0 && 963 profileInfo.fHueSatDeltas1Count != 0) 964 { 965 966 TempBigEndian setEndianness (stream, profileInfo.fBigEndian); 967 968 stream.SetReadPosition (profileInfo.fHueSatDeltas1Offset); 969 970 bool skipSat0 = (profileInfo.fHueSatDeltas1Count == SafeUint32Mult( 971 profileInfo.fProfileHues, 972 SafeUint32Sub(profileInfo.fProfileSats, 1), 973 profileInfo.fProfileVals, 3)); 974 975 ReadHueSatMap (stream, 976 fHueSatDeltas1, 977 profileInfo.fProfileHues, 978 profileInfo.fProfileSats, 979 profileInfo.fProfileVals, 980 skipSat0); 981 982 } 983 984 if (profileInfo.fHueSatDeltas2Offset != 0 && 985 profileInfo.fHueSatDeltas2Count != 0) 986 { 987 988 TempBigEndian setEndianness (stream, profileInfo.fBigEndian); 989 990 stream.SetReadPosition (profileInfo.fHueSatDeltas2Offset); 991 992 bool skipSat0 = (profileInfo.fHueSatDeltas2Count == SafeUint32Mult( 993 profileInfo.fProfileHues, 994 SafeUint32Sub(profileInfo.fProfileSats, 1), 995 profileInfo.fProfileVals, 3)); 996 997 ReadHueSatMap (stream, 998 fHueSatDeltas2, 999 profileInfo.fProfileHues, 1000 profileInfo.fProfileSats, 1001 profileInfo.fProfileVals, 1002 skipSat0); 1003 1004 } 1005 1006 if (profileInfo.fLookTableOffset != 0 && 1007 profileInfo.fLookTableCount != 0) 1008 { 1009 1010 TempBigEndian setEndianness (stream, profileInfo.fBigEndian); 1011 1012 stream.SetReadPosition (profileInfo.fLookTableOffset); 1013 1014 bool skipSat0 = (profileInfo.fLookTableCount == SafeUint32Mult( 1015 profileInfo.fLookTableHues, 1016 SafeUint32Sub(profileInfo.fLookTableSats, 1), 1017 profileInfo.fLookTableVals, 3)); 1018 1019 ReadHueSatMap (stream, 1020 fLookTable, 1021 profileInfo.fLookTableHues, 1022 profileInfo.fLookTableSats, 1023 profileInfo.fLookTableVals, 1024 skipSat0); 1025 1026 } 1027 1028 if ((profileInfo.fToneCurveCount & 1) == 0) 1029 { 1030 1031 TempBigEndian setEndianness (stream, profileInfo.fBigEndian); 1032 1033 stream.SetReadPosition (profileInfo.fToneCurveOffset); 1034 1035 uint32 points = profileInfo.fToneCurveCount / 2; 1036 1037 fToneCurve.fCoord.resize (points); 1038 1039 for (size_t i = 0; i < points; i++) 1040 { 1041 1042 dng_point_real64 point; 1043 1044 point.h = stream.Get_real32 (); 1045 point.v = stream.Get_real32 (); 1046 1047 fToneCurve.fCoord [i] = point; 1048 1049 } 1050 1051 } 1052 1053 SetHueSatMapEncoding (profileInfo.fHueSatMapEncoding); 1054 1055 SetLookTableEncoding (profileInfo.fLookTableEncoding); 1056 1057 SetBaselineExposureOffset (profileInfo.fBaselineExposureOffset.As_real64 ()); 1058 1059 SetDefaultBlackRender (profileInfo.fDefaultBlackRender); 1060 1061 } 1062 1063 /*****************************************************************************/ 1064 1065 bool dng_camera_profile::ParseExtended (dng_stream &stream) 1066 { 1067 1068 try 1069 { 1070 1071 dng_camera_profile_info profileInfo; 1072 1073 if (!profileInfo.ParseExtended (stream)) 1074 { 1075 return false; 1076 } 1077 1078 Parse (stream, profileInfo); 1079 1080 return true; 1081 1082 } 1083 1084 catch (...) 1085 { 1086 1087 // Eat parsing errors. 1088 1089 } 1090 1091 return false; 1092 1093 } 1094 1095 /*****************************************************************************/ 1096 1097 void dng_camera_profile::SetFourColorBayer () 1098 { 1099 1100 uint32 j; 1101 1102 if (!IsValid (3)) 1103 { 1104 ThrowProgramError (); 1105 } 1106 1107 if (fColorMatrix1.NotEmpty ()) 1108 { 1109 1110 dng_matrix m (4, 3); 1111 1112 for (j = 0; j < 3; j++) 1113 { 1114 m [0] [j] = fColorMatrix1 [0] [j]; 1115 m [1] [j] = fColorMatrix1 [1] [j]; 1116 m [2] [j] = fColorMatrix1 [2] [j]; 1117 m [3] [j] = fColorMatrix1 [1] [j]; 1118 } 1119 1120 fColorMatrix1 = m; 1121 1122 } 1123 1124 if (fColorMatrix2.NotEmpty ()) 1125 { 1126 1127 dng_matrix m (4, 3); 1128 1129 for (j = 0; j < 3; j++) 1130 { 1131 m [0] [j] = fColorMatrix2 [0] [j]; 1132 m [1] [j] = fColorMatrix2 [1] [j]; 1133 m [2] [j] = fColorMatrix2 [2] [j]; 1134 m [3] [j] = fColorMatrix2 [1] [j]; 1135 } 1136 1137 fColorMatrix2 = m; 1138 1139 } 1140 1141 fReductionMatrix1.Clear (); 1142 fReductionMatrix2.Clear (); 1143 1144 fForwardMatrix1.Clear (); 1145 fForwardMatrix2.Clear (); 1146 1147 } 1148 1149 /*****************************************************************************/ 1150 1151 dng_hue_sat_map * dng_camera_profile::HueSatMapForWhite (const dng_xy_coord &white) const 1152 { 1153 1154 if (fHueSatDeltas1.IsValid ()) 1155 { 1156 1157 // If we only have the first table, just use it for any color temperature. 1158 1159 if (!fHueSatDeltas2.IsValid ()) 1160 { 1161 1162 return new dng_hue_sat_map (fHueSatDeltas1); 1163 1164 } 1165 1166 // Else we need to interpolate based on color temperature. 1167 1168 real64 temperature1 = CalibrationTemperature1 (); 1169 real64 temperature2 = CalibrationTemperature2 (); 1170 1171 if (temperature1 <= 0.0 || 1172 temperature2 <= 0.0 || 1173 temperature1 == temperature2) 1174 { 1175 1176 return new dng_hue_sat_map (fHueSatDeltas1); 1177 1178 } 1179 1180 bool reverseOrder = temperature1 > temperature2; 1181 1182 if (reverseOrder) 1183 { 1184 real64 temp = temperature1; 1185 temperature1 = temperature2; 1186 temperature2 = temp; 1187 } 1188 1189 // Convert to temperature/offset space. 1190 1191 dng_temperature td (white); 1192 1193 // Find fraction to weight the first calibration. 1194 1195 real64 g; 1196 1197 if (td.Temperature () <= temperature1) 1198 g = 1.0; 1199 1200 else if (td.Temperature () >= temperature2) 1201 g = 0.0; 1202 1203 else 1204 { 1205 1206 real64 invT = 1.0 / td.Temperature (); 1207 1208 g = (invT - (1.0 / temperature2)) / 1209 ((1.0 / temperature1) - (1.0 / temperature2)); 1210 1211 } 1212 1213 // Fix up if we swapped the order. 1214 1215 if (reverseOrder) 1216 { 1217 g = 1.0 - g; 1218 } 1219 1220 // Do the interpolation. 1221 1222 return dng_hue_sat_map::Interpolate (HueSatDeltas1 (), 1223 HueSatDeltas2 (), 1224 g); 1225 1226 } 1227 1228 return NULL; 1229 1230 } 1231 1232 /*****************************************************************************/ 1233 1234 void dng_camera_profile::Stub () 1235 { 1236 1237 (void) Fingerprint (); 1238 1239 dng_hue_sat_map nullTable; 1240 1241 fHueSatDeltas1 = nullTable; 1242 fHueSatDeltas2 = nullTable; 1243 1244 fLookTable = nullTable; 1245 1246 fToneCurve.SetInvalid (); 1247 1248 fWasStubbed = true; 1249 1250 } 1251 1252 /*****************************************************************************/ 1253 1254 void SplitCameraProfileName (const dng_string &name, 1255 dng_string &baseName, 1256 int32 &version) 1257 { 1258 1259 baseName = name; 1260 1261 version = 0; 1262 1263 uint32 len = baseName.Length (); 1264 1265 if (len > 5 && baseName.EndsWith (" beta")) 1266 { 1267 1268 baseName.Truncate (len - 5); 1269 1270 version += -10; 1271 1272 } 1273 1274 else if (len > 7) 1275 { 1276 1277 char lastChar = name.Get () [len - 1]; 1278 1279 if (lastChar >= '0' && lastChar <= '9') 1280 { 1281 1282 dng_string temp = name; 1283 1284 temp.Truncate (len - 1); 1285 1286 if (temp.EndsWith (" beta ")) 1287 { 1288 1289 baseName.Truncate (len - 7); 1290 1291 version += ((int32) (lastChar - '0')) - 10; 1292 1293 } 1294 1295 } 1296 1297 } 1298 1299 len = baseName.Length (); 1300 1301 if (len > 3) 1302 { 1303 1304 char lastChar = name.Get () [len - 1]; 1305 1306 if (lastChar >= '0' && lastChar <= '9') 1307 { 1308 1309 dng_string temp = name; 1310 1311 temp.Truncate (len - 1); 1312 1313 if (temp.EndsWith (" v")) 1314 { 1315 1316 baseName.Truncate (len - 3); 1317 1318 version += ((int32) (lastChar - '0')) * 100; 1319 1320 } 1321 1322 } 1323 1324 } 1325 1326 } 1327 1328 /*****************************************************************************/ 1329 1330 void BuildHueSatMapEncodingTable (dng_memory_allocator &allocator, 1331 uint32 encoding, 1332 AutoPtr<dng_1d_table> &encodeTable, 1333 AutoPtr<dng_1d_table> &decodeTable, 1334 bool subSample) 1335 { 1336 1337 encodeTable.Reset (); 1338 decodeTable.Reset (); 1339 1340 switch (encoding) 1341 { 1342 1343 case encoding_Linear: 1344 { 1345 1346 break; 1347 1348 } 1349 1350 case encoding_sRGB: 1351 { 1352 1353 encodeTable.Reset (new dng_1d_table); 1354 decodeTable.Reset (new dng_1d_table); 1355 1356 const dng_1d_function & curve = dng_function_GammaEncode_sRGB::Get (); 1357 1358 encodeTable->Initialize (allocator, 1359 curve, 1360 subSample); 1361 1362 const dng_1d_inverse inverse (curve); 1363 1364 decodeTable->Initialize (allocator, 1365 inverse, 1366 subSample); 1367 1368 break; 1369 1370 } 1371 1372 default: 1373 { 1374 1375 DNG_REPORT ("Unsupported hue sat map / look table encoding."); 1376 1377 break; 1378 1379 } 1380 1381 } 1382 1383 } 1384 1385 /*****************************************************************************/ 1386