1 /*****************************************************************************/ 2 // Copyright 2006-2012 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_negative.cpp#3 $ */ 10 /* $DateTime: 2012/06/14 20:24:41 $ */ 11 /* $Change: 835078 $ */ 12 /* $Author: tknoll $ */ 13 14 /*****************************************************************************/ 15 16 #include "dng_negative.h" 17 18 #include "dng_1d_table.h" 19 #include "dng_abort_sniffer.h" 20 #include "dng_area_task.h" 21 #include "dng_assertions.h" 22 #include "dng_bottlenecks.h" 23 #include "dng_camera_profile.h" 24 #include "dng_color_space.h" 25 #include "dng_color_spec.h" 26 #include "dng_exceptions.h" 27 #include "dng_globals.h" 28 #include "dng_host.h" 29 #include "dng_image.h" 30 #include "dng_image_writer.h" 31 #include "dng_info.h" 32 #include "dng_jpeg_image.h" 33 #include "dng_linearization_info.h" 34 #include "dng_memory.h" 35 #include "dng_memory_stream.h" 36 #include "dng_misc_opcodes.h" 37 #include "dng_mosaic_info.h" 38 #include "dng_preview.h" 39 #include "dng_resample.h" 40 #include "dng_safe_arithmetic.h" 41 #include "dng_simple_image.h" 42 #include "dng_tag_codes.h" 43 #include "dng_tag_values.h" 44 #include "dng_tile_iterator.h" 45 #include "dng_utils.h" 46 47 #if qDNGUseXMP 48 #include "dng_xmp.h" 49 #endif 50 51 /*****************************************************************************/ 52 53 dng_noise_profile::dng_noise_profile () 54 55 : fNoiseFunctions () 56 57 { 58 59 } 60 61 /*****************************************************************************/ 62 63 dng_noise_profile::dng_noise_profile (const dng_std_vector<dng_noise_function> &functions) 64 65 : fNoiseFunctions (functions) 66 67 { 68 69 } 70 71 /*****************************************************************************/ 72 73 bool dng_noise_profile::IsValid () const 74 { 75 76 if (NumFunctions () == 0 || NumFunctions () > kMaxColorPlanes) 77 { 78 return false; 79 } 80 81 for (uint32 plane = 0; plane < NumFunctions (); plane++) 82 { 83 84 if (!NoiseFunction (plane).IsValid ()) 85 { 86 return false; 87 } 88 89 } 90 91 return true; 92 93 } 94 95 /*****************************************************************************/ 96 97 bool dng_noise_profile::IsValidForNegative (const dng_negative &negative) const 98 { 99 100 if (!(NumFunctions () == 1 || NumFunctions () == negative.ColorChannels ())) 101 { 102 return false; 103 } 104 105 return IsValid (); 106 107 } 108 109 /*****************************************************************************/ 110 111 const dng_noise_function & dng_noise_profile::NoiseFunction (uint32 plane) const 112 { 113 114 if (NumFunctions () == 1) 115 { 116 return fNoiseFunctions.front (); 117 } 118 119 DNG_REQUIRE (plane < NumFunctions (), 120 "Bad plane index argument for NoiseFunction ()."); 121 122 return fNoiseFunctions [plane]; 123 124 } 125 126 /*****************************************************************************/ 127 128 uint32 dng_noise_profile::NumFunctions () const 129 { 130 return (uint32) fNoiseFunctions.size (); 131 } 132 133 /*****************************************************************************/ 134 135 dng_metadata::dng_metadata (dng_host &host) 136 137 : fHasBaseOrientation (false) 138 , fBaseOrientation () 139 , fIsMakerNoteSafe (false) 140 , fMakerNote () 141 , fExif (host.Make_dng_exif ()) 142 , fOriginalExif () 143 , fIPTCBlock () 144 , fIPTCOffset (kDNGStreamInvalidOffset) 145 146 #if qDNGUseXMP 147 148 , fXMP (host.Make_dng_xmp ()) 149 150 #endif 151 152 , fEmbeddedXMPDigest () 153 , fXMPinSidecar (false) 154 , fXMPisNewer (false) 155 , fSourceMIMI () 156 157 { 158 } 159 160 /*****************************************************************************/ 161 162 dng_metadata::~dng_metadata () 163 { 164 } 165 166 /******************************************************************************/ 167 168 template< class T > 169 T * CloneAutoPtr (const AutoPtr< T > &ptr) 170 { 171 172 return ptr.Get () ? ptr->Clone () : NULL; 173 174 } 175 176 /******************************************************************************/ 177 178 template< class T, typename U > 179 T * CloneAutoPtr (const AutoPtr< T > &ptr, U &u) 180 { 181 182 return ptr.Get () ? ptr->Clone (u) : NULL; 183 184 } 185 186 /******************************************************************************/ 187 188 dng_metadata::dng_metadata (const dng_metadata &rhs, 189 dng_memory_allocator &allocator) 190 191 : fHasBaseOrientation (rhs.fHasBaseOrientation) 192 , fBaseOrientation (rhs.fBaseOrientation) 193 , fIsMakerNoteSafe (rhs.fIsMakerNoteSafe) 194 , fMakerNote (CloneAutoPtr (rhs.fMakerNote, allocator)) 195 , fExif (CloneAutoPtr (rhs.fExif)) 196 , fOriginalExif (CloneAutoPtr (rhs.fOriginalExif)) 197 , fIPTCBlock (CloneAutoPtr (rhs.fIPTCBlock, allocator)) 198 , fIPTCOffset (rhs.fIPTCOffset) 199 200 #if qDNGUseXMP 201 202 , fXMP (CloneAutoPtr (rhs.fXMP)) 203 204 #endif 205 206 , fEmbeddedXMPDigest (rhs.fEmbeddedXMPDigest) 207 , fXMPinSidecar (rhs.fXMPinSidecar) 208 , fXMPisNewer (rhs.fXMPisNewer) 209 , fSourceMIMI (rhs.fSourceMIMI) 210 211 { 212 213 } 214 215 /******************************************************************************/ 216 217 dng_metadata * dng_metadata::Clone (dng_memory_allocator &allocator) const 218 { 219 220 return new dng_metadata (*this, allocator); 221 222 } 223 224 /******************************************************************************/ 225 226 void dng_metadata::SetBaseOrientation (const dng_orientation &orientation) 227 { 228 229 fHasBaseOrientation = true; 230 231 fBaseOrientation = orientation; 232 233 } 234 235 /******************************************************************************/ 236 237 void dng_metadata::ApplyOrientation (const dng_orientation &orientation) 238 { 239 240 fBaseOrientation += orientation; 241 242 #if qDNGUseXMP 243 244 fXMP->SetOrientation (fBaseOrientation); 245 246 #endif 247 248 } 249 250 /*****************************************************************************/ 251 252 void dng_metadata::ResetExif (dng_exif * newExif) 253 { 254 255 fExif.Reset (newExif); 256 257 } 258 259 /******************************************************************************/ 260 261 dng_memory_block * dng_metadata::BuildExifBlock (dng_memory_allocator &allocator, 262 const dng_resolution *resolution, 263 bool includeIPTC, 264 const dng_jpeg_preview *thumbnail) const 265 { 266 267 dng_memory_stream stream (allocator); 268 269 { 270 271 // Create the main IFD 272 273 dng_tiff_directory mainIFD; 274 275 // Optionally include the resolution tags. 276 277 dng_resolution res; 278 279 if (resolution) 280 { 281 res = *resolution; 282 } 283 284 tag_urational tagXResolution (tcXResolution, res.fXResolution); 285 tag_urational tagYResolution (tcYResolution, res.fYResolution); 286 287 tag_uint16 tagResolutionUnit (tcResolutionUnit, res.fResolutionUnit); 288 289 if (resolution) 290 { 291 mainIFD.Add (&tagXResolution ); 292 mainIFD.Add (&tagYResolution ); 293 mainIFD.Add (&tagResolutionUnit); 294 } 295 296 // Optionally include IPTC block. 297 298 tag_iptc tagIPTC (IPTCData (), 299 IPTCLength ()); 300 301 if (includeIPTC && tagIPTC.Count ()) 302 { 303 mainIFD.Add (&tagIPTC); 304 } 305 306 // Exif tags. 307 308 exif_tag_set exifSet (mainIFD, 309 *GetExif (), 310 IsMakerNoteSafe (), 311 MakerNoteData (), 312 MakerNoteLength (), 313 false); 314 315 // Figure out the Exif IFD offset. 316 317 uint32 exifOffset = 8 + mainIFD.Size (); 318 319 exifSet.Locate (exifOffset); 320 321 // Thumbnail IFD (if any). 322 323 dng_tiff_directory thumbIFD; 324 325 tag_uint16 thumbCompression (tcCompression, ccOldJPEG); 326 327 tag_urational thumbXResolution (tcXResolution, dng_urational (72, 1)); 328 tag_urational thumbYResolution (tcYResolution, dng_urational (72, 1)); 329 330 tag_uint16 thumbResolutionUnit (tcResolutionUnit, ruInch); 331 332 tag_uint32 thumbDataOffset (tcJPEGInterchangeFormat , 0); 333 tag_uint32 thumbDataLength (tcJPEGInterchangeFormatLength, 0); 334 335 if (thumbnail) 336 { 337 338 thumbIFD.Add (&thumbCompression); 339 340 thumbIFD.Add (&thumbXResolution); 341 thumbIFD.Add (&thumbYResolution); 342 thumbIFD.Add (&thumbResolutionUnit); 343 344 thumbIFD.Add (&thumbDataOffset); 345 thumbIFD.Add (&thumbDataLength); 346 347 thumbDataLength.Set (thumbnail->fCompressedData->LogicalSize ()); 348 349 uint32 thumbOffset = exifOffset + exifSet.Size (); 350 351 mainIFD.SetChained (thumbOffset); 352 353 thumbDataOffset.Set (thumbOffset + thumbIFD.Size ()); 354 355 } 356 357 // Don't write anything unless the main IFD has some tags. 358 359 if (mainIFD.Size () != 0) 360 { 361 362 // Write TIFF Header. 363 364 stream.SetWritePosition (0); 365 366 stream.Put_uint16 (stream.BigEndian () ? byteOrderMM : byteOrderII); 367 368 stream.Put_uint16 (42); 369 370 stream.Put_uint32 (8); 371 372 // Write the IFDs. 373 374 mainIFD.Put (stream); 375 376 exifSet.Put (stream); 377 378 if (thumbnail) 379 { 380 381 thumbIFD.Put (stream); 382 383 stream.Put (thumbnail->fCompressedData->Buffer (), 384 thumbnail->fCompressedData->LogicalSize ()); 385 386 } 387 388 // Trim the file to this length. 389 390 stream.Flush (); 391 392 stream.SetLength (stream.Position ()); 393 394 } 395 396 } 397 398 return stream.AsMemoryBlock (allocator); 399 400 } 401 402 /******************************************************************************/ 403 404 void dng_metadata::SetIPTC (AutoPtr<dng_memory_block> &block, uint64 offset) 405 { 406 407 fIPTCBlock.Reset (block.Release ()); 408 409 fIPTCOffset = offset; 410 411 } 412 413 /******************************************************************************/ 414 415 void dng_metadata::SetIPTC (AutoPtr<dng_memory_block> &block) 416 { 417 418 SetIPTC (block, kDNGStreamInvalidOffset); 419 420 } 421 422 /******************************************************************************/ 423 424 void dng_metadata::ClearIPTC () 425 { 426 427 fIPTCBlock.Reset (); 428 429 fIPTCOffset = kDNGStreamInvalidOffset; 430 431 } 432 433 /*****************************************************************************/ 434 435 const void * dng_metadata::IPTCData () const 436 { 437 438 if (fIPTCBlock.Get ()) 439 { 440 441 return fIPTCBlock->Buffer (); 442 443 } 444 445 return NULL; 446 447 } 448 449 /*****************************************************************************/ 450 451 uint32 dng_metadata::IPTCLength () const 452 { 453 454 if (fIPTCBlock.Get ()) 455 { 456 457 return fIPTCBlock->LogicalSize (); 458 459 } 460 461 return 0; 462 463 } 464 465 /*****************************************************************************/ 466 467 uint64 dng_metadata::IPTCOffset () const 468 { 469 470 if (fIPTCBlock.Get ()) 471 { 472 473 return fIPTCOffset; 474 475 } 476 477 return kDNGStreamInvalidOffset; 478 479 } 480 481 /*****************************************************************************/ 482 483 dng_fingerprint dng_metadata::IPTCDigest (bool includePadding) const 484 { 485 486 if (IPTCLength ()) 487 { 488 489 dng_md5_printer printer; 490 491 const uint8 *data = (const uint8 *) IPTCData (); 492 493 uint32 count = IPTCLength (); 494 495 // Because of some stupid ways of storing the IPTC data, the IPTC 496 // data might be padded with up to three zeros. The official Adobe 497 // logic is to include these zeros in the digest. However, older 498 // versions of the Camera Raw code did not include the padding zeros 499 // in the digest, so we support both methods and allow either to 500 // match. 501 502 if (!includePadding) 503 { 504 505 uint32 removed = 0; 506 507 while ((removed < 3) && (count > 0) && (data [count - 1] == 0)) 508 { 509 removed++; 510 count--; 511 } 512 513 } 514 515 printer.Process (data, count); 516 517 return printer.Result (); 518 519 } 520 521 return dng_fingerprint (); 522 523 } 524 525 /******************************************************************************/ 526 527 #if qDNGUseXMP 528 529 void dng_metadata::RebuildIPTC (dng_memory_allocator &allocator, 530 bool padForTIFF) 531 { 532 533 ClearIPTC (); 534 535 fXMP->RebuildIPTC (*this, allocator, padForTIFF); 536 537 dng_fingerprint digest = IPTCDigest (); 538 539 fXMP->SetIPTCDigest (digest); 540 541 } 542 543 /*****************************************************************************/ 544 545 void dng_metadata::ResetXMP (dng_xmp * newXMP) 546 { 547 548 fXMP.Reset (newXMP); 549 550 } 551 552 /*****************************************************************************/ 553 554 void dng_metadata::ResetXMPSidecarNewer (dng_xmp * newXMP, 555 bool inSidecar, 556 bool isNewer ) 557 { 558 559 fXMP.Reset (newXMP); 560 561 fXMPinSidecar = inSidecar; 562 563 fXMPisNewer = isNewer; 564 565 } 566 567 /*****************************************************************************/ 568 569 bool dng_metadata::SetXMP (dng_host &host, 570 const void *buffer, 571 uint32 count, 572 bool xmpInSidecar, 573 bool xmpIsNewer) 574 { 575 576 bool result = false; 577 578 try 579 { 580 581 AutoPtr<dng_xmp> tempXMP (host.Make_dng_xmp ()); 582 583 tempXMP->Parse (host, buffer, count); 584 585 ResetXMPSidecarNewer (tempXMP.Release (), xmpInSidecar, xmpIsNewer); 586 587 result = true; 588 589 } 590 591 catch (dng_exception &except) 592 { 593 594 // Don't ignore transient errors. 595 596 if (host.IsTransientError (except.ErrorCode ())) 597 { 598 599 throw; 600 601 } 602 603 // Eat other parsing errors. 604 605 } 606 607 catch (...) 608 { 609 610 // Eat unknown parsing exceptions. 611 612 } 613 614 return result; 615 616 } 617 618 /*****************************************************************************/ 619 620 void dng_metadata::SetEmbeddedXMP (dng_host &host, 621 const void *buffer, 622 uint32 count) 623 { 624 625 if (SetXMP (host, buffer, count)) 626 { 627 628 dng_md5_printer printer; 629 630 printer.Process (buffer, count); 631 632 fEmbeddedXMPDigest = printer.Result (); 633 634 // Remove any sidecar specific tags from embedded XMP. 635 636 if (fXMP.Get ()) 637 { 638 639 fXMP->Remove (XMP_NS_PHOTOSHOP, "SidecarForExtension"); 640 fXMP->Remove (XMP_NS_PHOTOSHOP, "EmbeddedXMPDigest"); 641 642 } 643 644 } 645 646 else 647 { 648 649 fEmbeddedXMPDigest.Clear (); 650 651 } 652 653 } 654 655 #endif 656 657 /*****************************************************************************/ 658 659 void dng_metadata::SynchronizeMetadata () 660 { 661 662 if (!fOriginalExif.Get ()) 663 { 664 665 fOriginalExif.Reset (fExif->Clone ()); 666 667 } 668 669 #if qDNGUseXMP 670 671 fXMP->ValidateMetadata (); 672 673 fXMP->IngestIPTC (*this, fXMPisNewer); 674 675 fXMP->SyncExif (*fExif.Get ()); 676 677 fXMP->SyncOrientation (*this, fXMPinSidecar); 678 679 #endif 680 681 } 682 683 /*****************************************************************************/ 684 685 void dng_metadata::UpdateDateTime (const dng_date_time_info &dt) 686 { 687 688 fExif->UpdateDateTime (dt); 689 690 #if qDNGUseXMP 691 fXMP->UpdateDateTime (dt); 692 #endif 693 694 } 695 696 /*****************************************************************************/ 697 698 void dng_metadata::UpdateDateTimeToNow () 699 { 700 701 dng_date_time_info dt; 702 703 CurrentDateTimeAndZone (dt); 704 705 UpdateDateTime (dt); 706 707 #if qDNGUseXMP 708 709 fXMP->UpdateMetadataDate (dt); 710 711 #endif 712 713 } 714 715 /*****************************************************************************/ 716 717 void dng_metadata::UpdateMetadataDateTimeToNow () 718 { 719 720 dng_date_time_info dt; 721 722 CurrentDateTimeAndZone (dt); 723 724 #if qDNGUseXMP 725 fXMP->UpdateMetadataDate (dt); 726 #endif 727 728 } 729 730 /*****************************************************************************/ 731 732 dng_negative::dng_negative (dng_host &host) 733 734 : fAllocator (host.Allocator ()) 735 736 , fModelName () 737 , fLocalName () 738 , fDefaultCropSizeH () 739 , fDefaultCropSizeV () 740 , fDefaultCropOriginH (0, 1) 741 , fDefaultCropOriginV (0, 1) 742 , fDefaultUserCropT (0, 1) 743 , fDefaultUserCropL (0, 1) 744 , fDefaultUserCropB (1, 1) 745 , fDefaultUserCropR (1, 1) 746 , fDefaultScaleH (1, 1) 747 , fDefaultScaleV (1, 1) 748 , fBestQualityScale (1, 1) 749 , fOriginalDefaultFinalSize () 750 , fOriginalBestQualityFinalSize () 751 , fOriginalDefaultCropSizeH () 752 , fOriginalDefaultCropSizeV () 753 , fRawToFullScaleH (1.0) 754 , fRawToFullScaleV (1.0) 755 , fBaselineNoise (100, 100) 756 , fNoiseReductionApplied (0, 0) 757 , fNoiseProfile () 758 , fBaselineExposure ( 0, 100) 759 , fBaselineSharpness (100, 100) 760 , fChromaBlurRadius () 761 , fAntiAliasStrength (100, 100) 762 , fLinearResponseLimit (100, 100) 763 , fShadowScale (1, 1) 764 , fColorimetricReference (crSceneReferred) 765 , fColorChannels (0) 766 , fAnalogBalance () 767 , fCameraNeutral () 768 , fCameraWhiteXY () 769 , fCameraCalibration1 () 770 , fCameraCalibration2 () 771 , fCameraCalibrationSignature () 772 , fCameraProfile () 773 , fAsShotProfileName () 774 , fRawImageDigest () 775 , fNewRawImageDigest () 776 , fRawDataUniqueID () 777 , fOriginalRawFileName () 778 , fHasOriginalRawFileData (false) 779 , fOriginalRawFileData () 780 , fOriginalRawFileDigest () 781 , fDNGPrivateData () 782 , fMetadata (host) 783 , fLinearizationInfo () 784 , fMosaicInfo () 785 , fOpcodeList1 (1) 786 , fOpcodeList2 (2) 787 , fOpcodeList3 (3) 788 , fStage1Image () 789 , fStage2Image () 790 , fStage3Image () 791 , fStage3Gain (1.0) 792 , fIsPreview (false) 793 , fIsDamaged (false) 794 , fRawImageStage (rawImageStageNone) 795 , fRawImage () 796 , fRawFloatBitDepth (0) 797 , fRawJPEGImage () 798 , fRawJPEGImageDigest () 799 , fTransparencyMask () 800 , fRawTransparencyMask () 801 , fRawTransparencyMaskBitDepth (0) 802 , fUnflattenedStage3Image () 803 804 { 805 806 } 807 808 /*****************************************************************************/ 809 810 dng_negative::~dng_negative () 811 { 812 813 // Delete any camera profiles owned by this negative. 814 815 ClearProfiles (); 816 817 } 818 819 /******************************************************************************/ 820 821 void dng_negative::Initialize () 822 { 823 824 } 825 826 /******************************************************************************/ 827 828 dng_negative * dng_negative::Make (dng_host &host) 829 { 830 831 AutoPtr<dng_negative> result (new dng_negative (host)); 832 833 if (!result.Get ()) 834 { 835 ThrowMemoryFull (); 836 } 837 838 result->Initialize (); 839 840 return result.Release (); 841 842 } 843 844 /******************************************************************************/ 845 846 dng_metadata * dng_negative::CloneInternalMetadata () const 847 { 848 849 return InternalMetadata ().Clone (Allocator ()); 850 851 } 852 853 /******************************************************************************/ 854 855 dng_orientation dng_negative::ComputeOrientation (const dng_metadata &metadata) const 856 { 857 858 return metadata.BaseOrientation (); 859 860 } 861 862 /******************************************************************************/ 863 864 void dng_negative::SetAnalogBalance (const dng_vector &b) 865 { 866 867 real64 minEntry = b.MinEntry (); 868 869 if (b.NotEmpty () && minEntry > 0.0) 870 { 871 872 fAnalogBalance = b; 873 874 fAnalogBalance.Scale (1.0 / minEntry); 875 876 fAnalogBalance.Round (1000000.0); 877 878 } 879 880 else 881 { 882 883 fAnalogBalance.Clear (); 884 885 } 886 887 } 888 889 /*****************************************************************************/ 890 891 real64 dng_negative::AnalogBalance (uint32 channel) const 892 { 893 894 DNG_ASSERT (channel < ColorChannels (), "Channel out of bounds"); 895 896 if (channel < fAnalogBalance.Count ()) 897 { 898 899 return fAnalogBalance [channel]; 900 901 } 902 903 return 1.0; 904 905 } 906 907 /*****************************************************************************/ 908 909 dng_urational dng_negative::AnalogBalanceR (uint32 channel) const 910 { 911 912 dng_urational result; 913 914 result.Set_real64 (AnalogBalance (channel), 1000000); 915 916 return result; 917 918 } 919 920 /******************************************************************************/ 921 922 void dng_negative::SetCameraNeutral (const dng_vector &n) 923 { 924 925 real64 maxEntry = n.MaxEntry (); 926 927 if (n.NotEmpty () && maxEntry > 0.0) 928 { 929 930 fCameraNeutral = n; 931 932 fCameraNeutral.Scale (1.0 / maxEntry); 933 934 fCameraNeutral.Round (1000000.0); 935 936 } 937 938 else 939 { 940 941 fCameraNeutral.Clear (); 942 943 } 944 945 } 946 947 /*****************************************************************************/ 948 949 dng_urational dng_negative::CameraNeutralR (uint32 channel) const 950 { 951 952 dng_urational result; 953 954 result.Set_real64 (CameraNeutral () [channel], 1000000); 955 956 return result; 957 958 } 959 960 /******************************************************************************/ 961 962 void dng_negative::SetCameraWhiteXY (const dng_xy_coord &coord) 963 { 964 965 if (coord.IsValid ()) 966 { 967 968 fCameraWhiteXY.x = Round_int32 (coord.x * 1000000.0) / 1000000.0; 969 fCameraWhiteXY.y = Round_int32 (coord.y * 1000000.0) / 1000000.0; 970 971 } 972 973 else 974 { 975 976 fCameraWhiteXY.Clear (); 977 978 } 979 980 } 981 982 /*****************************************************************************/ 983 984 const dng_xy_coord & dng_negative::CameraWhiteXY () const 985 { 986 987 DNG_ASSERT (HasCameraWhiteXY (), "Using undefined CameraWhiteXY"); 988 989 return fCameraWhiteXY; 990 991 } 992 993 /*****************************************************************************/ 994 995 void dng_negative::GetCameraWhiteXY (dng_urational &x, 996 dng_urational &y) const 997 { 998 999 dng_xy_coord coord = CameraWhiteXY (); 1000 1001 x.Set_real64 (coord.x, 1000000); 1002 y.Set_real64 (coord.y, 1000000); 1003 1004 } 1005 1006 /*****************************************************************************/ 1007 1008 void dng_negative::SetCameraCalibration1 (const dng_matrix &m) 1009 { 1010 1011 fCameraCalibration1 = m; 1012 1013 fCameraCalibration1.Round (10000); 1014 1015 } 1016 1017 /******************************************************************************/ 1018 1019 void dng_negative::SetCameraCalibration2 (const dng_matrix &m) 1020 { 1021 1022 fCameraCalibration2 = m; 1023 1024 fCameraCalibration2.Round (10000); 1025 1026 } 1027 1028 /******************************************************************************/ 1029 1030 void dng_negative::AddProfile (AutoPtr<dng_camera_profile> &profile) 1031 { 1032 1033 // Make sure we have a profile to add. 1034 1035 if (!profile.Get ()) 1036 { 1037 1038 return; 1039 1040 } 1041 1042 // We must have some profile name. Use "embedded" if nothing else. 1043 1044 if (profile->Name ().IsEmpty ()) 1045 { 1046 1047 profile->SetName (kProfileName_Embedded); 1048 1049 } 1050 1051 // Special case support for reading older DNG files which did not store 1052 // the profile name in the main IFD profile. 1053 1054 if (fCameraProfile.size ()) 1055 { 1056 1057 // See the first profile has a default "embedded" name, and has 1058 // the same data as the profile we are adding. 1059 1060 if (fCameraProfile [0]->NameIsEmbedded () && 1061 fCameraProfile [0]->EqualData (*profile.Get ())) 1062 { 1063 1064 // If the profile we are deleting was read from DNG 1065 // then the new profile should be marked as such also. 1066 1067 if (fCameraProfile [0]->WasReadFromDNG ()) 1068 { 1069 1070 profile->SetWasReadFromDNG (); 1071 1072 } 1073 1074 // If the profile we are deleting wasn't read from disk then the new 1075 // profile should be marked as such also. 1076 1077 if (!fCameraProfile [0]->WasReadFromDisk ()) 1078 { 1079 1080 profile->SetWasReadFromDisk (false); 1081 1082 } 1083 1084 // Delete the profile with default name. 1085 1086 delete fCameraProfile [0]; 1087 1088 fCameraProfile [0] = NULL; 1089 1090 fCameraProfile.erase (fCameraProfile.begin ()); 1091 1092 } 1093 1094 } 1095 1096 // Duplicate detection logic. We give a preference to last added profile 1097 // so the profiles end up in a more consistent order no matter what profiles 1098 // happen to be embedded in the DNG. 1099 1100 for (uint32 index = 0; index < (uint32) fCameraProfile.size (); index++) 1101 { 1102 1103 // Instead of checking for matching fingerprints, we check that the two 1104 // profiles have the same color and have the same name. This allows two 1105 // profiles that are identical except for copyright string and embed policy 1106 // to be considered duplicates. 1107 1108 const bool equalColorAndSameName = (fCameraProfile [index]->EqualData (*profile.Get ()) && 1109 fCameraProfile [index]->Name () == profile->Name ()); 1110 1111 if (equalColorAndSameName) 1112 { 1113 1114 // If the profile we are deleting was read from DNG 1115 // then the new profile should be marked as such also. 1116 1117 if (fCameraProfile [index]->WasReadFromDNG ()) 1118 { 1119 1120 profile->SetWasReadFromDNG (); 1121 1122 } 1123 1124 // If the profile we are deleting wasn't read from disk then the new 1125 // profile should be marked as such also. 1126 1127 if (!fCameraProfile [index]->WasReadFromDisk ()) 1128 { 1129 1130 profile->SetWasReadFromDisk (false); 1131 1132 } 1133 1134 // Delete the duplicate profile. 1135 1136 delete fCameraProfile [index]; 1137 1138 fCameraProfile [index] = NULL; 1139 1140 fCameraProfile.erase (fCameraProfile.begin () + index); 1141 1142 break; 1143 1144 } 1145 1146 } 1147 1148 // Now add to profile list. 1149 1150 fCameraProfile.push_back (NULL); 1151 1152 fCameraProfile [fCameraProfile.size () - 1] = profile.Release (); 1153 1154 } 1155 1156 /******************************************************************************/ 1157 1158 void dng_negative::ClearProfiles () 1159 { 1160 1161 // Delete any camera profiles owned by this negative. 1162 1163 for (uint32 index = 0; index < (uint32) fCameraProfile.size (); index++) 1164 { 1165 1166 if (fCameraProfile [index]) 1167 { 1168 1169 delete fCameraProfile [index]; 1170 1171 fCameraProfile [index] = NULL; 1172 1173 } 1174 1175 } 1176 1177 // Now empty list. 1178 1179 fCameraProfile.clear (); 1180 1181 } 1182 1183 /*****************************************************************************/ 1184 1185 void dng_negative::ClearProfiles (bool clearBuiltinMatrixProfiles, 1186 bool clearReadFromDisk) 1187 { 1188 1189 // If neither flag is set, then there's nothing to do. 1190 1191 if (!clearBuiltinMatrixProfiles && 1192 !clearReadFromDisk) 1193 { 1194 return; 1195 } 1196 1197 // Delete any camera profiles in this negative that match the specified criteria. 1198 1199 dng_std_vector<dng_camera_profile *>::iterator iter = fCameraProfile.begin (); 1200 dng_std_vector<dng_camera_profile *>::iterator next; 1201 1202 for (; iter != fCameraProfile.end (); iter = next) 1203 { 1204 1205 dng_camera_profile *profile = *iter; 1206 1207 // If the profile is invalid (i.e., NULL pointer), or meets one of the 1208 // specified criteria, then axe it. 1209 1210 if (!profile || 1211 (clearBuiltinMatrixProfiles && profile->WasBuiltinMatrix ()) || 1212 (clearReadFromDisk && profile->WasReadFromDisk ())) 1213 { 1214 1215 delete profile; 1216 1217 next = fCameraProfile.erase (iter); 1218 1219 } 1220 1221 // Otherwise, just advance to the next element. 1222 1223 else 1224 { 1225 1226 next = iter + 1; 1227 1228 } 1229 1230 } 1231 1232 } 1233 1234 /******************************************************************************/ 1235 1236 uint32 dng_negative::ProfileCount () const 1237 { 1238 1239 return (uint32) fCameraProfile.size (); 1240 1241 } 1242 1243 /******************************************************************************/ 1244 1245 const dng_camera_profile & dng_negative::ProfileByIndex (uint32 index) const 1246 { 1247 1248 DNG_ASSERT (index < ProfileCount (), 1249 "Invalid index for ProfileByIndex"); 1250 1251 return *fCameraProfile [index]; 1252 1253 } 1254 1255 /*****************************************************************************/ 1256 1257 const dng_camera_profile * dng_negative::ProfileByID (const dng_camera_profile_id &id, 1258 bool useDefaultIfNoMatch) const 1259 { 1260 1261 uint32 index; 1262 1263 // If this negative does not have any profiles, we are not going to 1264 // find a match. 1265 1266 uint32 profileCount = ProfileCount (); 1267 1268 if (profileCount == 0) 1269 { 1270 return NULL; 1271 } 1272 1273 // If we have both a profile name and fingerprint, try matching both. 1274 1275 if (id.Name ().NotEmpty () && id.Fingerprint ().IsValid ()) 1276 { 1277 1278 for (index = 0; index < profileCount; index++) 1279 { 1280 1281 const dng_camera_profile &profile = ProfileByIndex (index); 1282 1283 if (id.Name () == profile.Name () && 1284 id.Fingerprint () == profile.Fingerprint ()) 1285 { 1286 1287 return &profile; 1288 1289 } 1290 1291 } 1292 1293 } 1294 1295 // If we have a name, try matching that. 1296 1297 if (id.Name ().NotEmpty ()) 1298 { 1299 1300 for (index = 0; index < profileCount; index++) 1301 { 1302 1303 const dng_camera_profile &profile = ProfileByIndex (index); 1304 1305 if (id.Name () == profile.Name ()) 1306 { 1307 1308 return &profile; 1309 1310 } 1311 1312 } 1313 1314 } 1315 1316 // If we have a valid fingerprint, try matching that. 1317 1318 if (id.Fingerprint ().IsValid ()) 1319 { 1320 1321 for (index = 0; index < profileCount; index++) 1322 { 1323 1324 const dng_camera_profile &profile = ProfileByIndex (index); 1325 1326 if (id.Fingerprint () == profile.Fingerprint ()) 1327 { 1328 1329 return &profile; 1330 1331 } 1332 1333 } 1334 1335 } 1336 1337 // Try "upgrading" profile name versions. 1338 1339 if (id.Name ().NotEmpty ()) 1340 { 1341 1342 dng_string baseName; 1343 int32 version; 1344 1345 SplitCameraProfileName (id.Name (), 1346 baseName, 1347 version); 1348 1349 int32 bestIndex = -1; 1350 int32 bestVersion = 0; 1351 1352 for (index = 0; index < profileCount; index++) 1353 { 1354 1355 const dng_camera_profile &profile = ProfileByIndex (index); 1356 1357 if (profile.Name ().StartsWith (baseName.Get ())) 1358 { 1359 1360 dng_string testBaseName; 1361 int32 testVersion; 1362 1363 SplitCameraProfileName (profile.Name (), 1364 testBaseName, 1365 testVersion); 1366 1367 if (bestIndex == -1 || testVersion > bestVersion) 1368 { 1369 1370 bestIndex = index; 1371 bestVersion = testVersion; 1372 1373 } 1374 1375 } 1376 1377 } 1378 1379 if (bestIndex != -1) 1380 { 1381 1382 return &ProfileByIndex (bestIndex); 1383 1384 } 1385 1386 } 1387 1388 // Did not find a match any way. See if we should return a default value. 1389 1390 if (useDefaultIfNoMatch) 1391 { 1392 1393 return &ProfileByIndex (0); 1394 1395 } 1396 1397 // Found nothing. 1398 1399 return NULL; 1400 1401 } 1402 1403 /*****************************************************************************/ 1404 1405 const dng_camera_profile * dng_negative::ComputeCameraProfileToEmbed 1406 (const dng_metadata & /* metadata */) const 1407 { 1408 1409 uint32 index; 1410 1411 uint32 count = ProfileCount (); 1412 1413 if (count == 0) 1414 { 1415 1416 return NULL; 1417 1418 } 1419 1420 // First try to look for the first profile that was already in the DNG 1421 // when we read it. 1422 1423 for (index = 0; index < count; index++) 1424 { 1425 1426 const dng_camera_profile &profile (ProfileByIndex (index)); 1427 1428 if (profile.WasReadFromDNG ()) 1429 { 1430 1431 return &profile; 1432 1433 } 1434 1435 } 1436 1437 // Next we look for the first profile that is legal to embed. 1438 1439 for (index = 0; index < count; index++) 1440 { 1441 1442 const dng_camera_profile &profile (ProfileByIndex (index)); 1443 1444 if (profile.IsLegalToEmbed ()) 1445 { 1446 1447 return &profile; 1448 1449 } 1450 1451 } 1452 1453 // Else just return the first profile. 1454 1455 return fCameraProfile [0]; 1456 1457 } 1458 1459 /*****************************************************************************/ 1460 1461 dng_color_spec * dng_negative::MakeColorSpec (const dng_camera_profile_id &id) const 1462 { 1463 1464 dng_color_spec *spec = new dng_color_spec (*this, ProfileByID (id)); 1465 1466 if (!spec) 1467 { 1468 ThrowMemoryFull (); 1469 } 1470 1471 return spec; 1472 1473 } 1474 1475 /*****************************************************************************/ 1476 1477 dng_fingerprint dng_negative::FindImageDigest (dng_host &host, 1478 const dng_image &image) const 1479 { 1480 1481 dng_md5_printer printer; 1482 1483 dng_pixel_buffer buffer (image.Bounds (), 0, image.Planes (), 1484 image.PixelType (), pcInterleaved, NULL); 1485 1486 // Sometimes we expand 8-bit data to 16-bit data while reading or 1487 // writing, so always compute the digest of 8-bit data as 16-bits. 1488 1489 if (buffer.fPixelType == ttByte) 1490 { 1491 buffer.fPixelType = ttShort; 1492 buffer.fPixelSize = 2; 1493 } 1494 1495 const uint32 kBufferRows = 16; 1496 1497 uint32 bufferBytes = 0; 1498 1499 if (!SafeUint32Mult (kBufferRows, buffer.fRowStep, &bufferBytes) || 1500 !SafeUint32Mult (bufferBytes, buffer.fPixelSize, &bufferBytes)) 1501 { 1502 1503 ThrowMemoryFull("Arithmetic overflow computing buffer size."); 1504 1505 } 1506 1507 AutoPtr<dng_memory_block> bufferData (host.Allocate (bufferBytes)); 1508 1509 buffer.fData = bufferData->Buffer (); 1510 1511 dng_rect area; 1512 1513 dng_tile_iterator iter (dng_point (kBufferRows, 1514 image.Width ()), 1515 image.Bounds ()); 1516 1517 while (iter.GetOneTile (area)) 1518 { 1519 1520 host.SniffForAbort (); 1521 1522 buffer.fArea = area; 1523 1524 image.Get (buffer); 1525 1526 uint32 count = buffer.fArea.H () * 1527 buffer.fRowStep * 1528 buffer.fPixelSize; 1529 1530 #if qDNGBigEndian 1531 1532 // We need to use the same byte order to compute 1533 // the digest, no matter the native order. Little-endian 1534 // is more common now, so use that. 1535 1536 switch (buffer.fPixelSize) 1537 { 1538 1539 case 1: 1540 break; 1541 1542 case 2: 1543 { 1544 DoSwapBytes16 ((uint16 *) buffer.fData, count >> 1); 1545 break; 1546 } 1547 1548 case 4: 1549 { 1550 DoSwapBytes32 ((uint32 *) buffer.fData, count >> 2); 1551 break; 1552 } 1553 1554 default: 1555 { 1556 DNG_REPORT ("Unexpected pixel size"); 1557 break; 1558 } 1559 1560 } 1561 1562 #endif 1563 1564 printer.Process (buffer.fData, 1565 count); 1566 1567 } 1568 1569 return printer.Result (); 1570 1571 } 1572 1573 /*****************************************************************************/ 1574 1575 void dng_negative::FindRawImageDigest (dng_host &host) const 1576 { 1577 1578 if (fRawImageDigest.IsNull ()) 1579 { 1580 1581 // Since we are adding the floating point and transparency support 1582 // in DNG 1.4, and there are no legacy floating point or transparent 1583 // DNGs, switch to using the more MP friendly algorithm to compute 1584 // the digest for these images. 1585 1586 if (RawImage ().PixelType () == ttFloat || RawTransparencyMask ()) 1587 { 1588 1589 FindNewRawImageDigest (host); 1590 1591 fRawImageDigest = fNewRawImageDigest; 1592 1593 } 1594 1595 else 1596 { 1597 1598 #if qDNGValidate 1599 1600 dng_timer timeScope ("FindRawImageDigest time"); 1601 1602 #endif 1603 1604 fRawImageDigest = FindImageDigest (host, RawImage ()); 1605 1606 } 1607 1608 } 1609 1610 } 1611 1612 /*****************************************************************************/ 1613 1614 class dng_find_new_raw_image_digest_task : public dng_area_task 1615 { 1616 1617 private: 1618 1619 enum 1620 { 1621 kTileSize = 256 1622 }; 1623 1624 const dng_image &fImage; 1625 1626 uint32 fPixelType; 1627 uint32 fPixelSize; 1628 1629 uint32 fTilesAcross; 1630 uint32 fTilesDown; 1631 1632 uint32 fTileCount; 1633 1634 AutoArray<dng_fingerprint> fTileHash; 1635 1636 AutoPtr<dng_memory_block> fBufferData [kMaxMPThreads]; 1637 1638 public: 1639 1640 dng_find_new_raw_image_digest_task (const dng_image &image, 1641 uint32 pixelType) 1642 1643 : fImage (image) 1644 , fPixelType (pixelType) 1645 , fPixelSize (TagTypeSize (pixelType)) 1646 , fTilesAcross (0) 1647 , fTilesDown (0) 1648 , fTileCount (0) 1649 , fTileHash () 1650 1651 { 1652 1653 fMinTaskArea = 1; 1654 1655 fUnitCell = dng_point (Min_int32 (kTileSize, fImage.Bounds ().H ()), 1656 Min_int32 (kTileSize, fImage.Bounds ().W ())); 1657 1658 fMaxTileSize = fUnitCell; 1659 1660 } 1661 1662 virtual void Start (uint32 threadCount, 1663 const dng_point &tileSize, 1664 dng_memory_allocator *allocator, 1665 dng_abort_sniffer * /* sniffer */) 1666 { 1667 1668 if (tileSize != fUnitCell) 1669 { 1670 ThrowProgramError (); 1671 } 1672 1673 fTilesAcross = (fImage.Bounds ().W () + fUnitCell.h - 1) / fUnitCell.h; 1674 fTilesDown = (fImage.Bounds ().H () + fUnitCell.v - 1) / fUnitCell.v; 1675 1676 fTileCount = fTilesAcross * fTilesDown; 1677 1678 fTileHash.Reset (fTileCount); 1679 1680 const uint32 bufferSize = 1681 ComputeBufferSize(fPixelType, tileSize, fImage.Planes(), 1682 padNone); 1683 1684 for (uint32 index = 0; index < threadCount; index++) 1685 { 1686 1687 fBufferData [index].Reset (allocator->Allocate (bufferSize)); 1688 1689 } 1690 1691 } 1692 1693 virtual void Process (uint32 threadIndex, 1694 const dng_rect &tile, 1695 dng_abort_sniffer * /* sniffer */) 1696 { 1697 1698 int32 colIndex = (tile.l - fImage.Bounds ().l) / fUnitCell.h; 1699 int32 rowIndex = (tile.t - fImage.Bounds ().t) / fUnitCell.v; 1700 1701 DNG_ASSERT (tile.l == fImage.Bounds ().l + colIndex * fUnitCell.h && 1702 tile.t == fImage.Bounds ().t + rowIndex * fUnitCell.v, 1703 "Bad tile origin"); 1704 1705 uint32 tileIndex = rowIndex * fTilesAcross + colIndex; 1706 1707 dng_pixel_buffer buffer (tile, 0, fImage.Planes (), 1708 fPixelType, pcPlanar, 1709 fBufferData [threadIndex]->Buffer ()); 1710 1711 fImage.Get (buffer); 1712 1713 uint32 count = buffer.fPlaneStep * 1714 buffer.fPlanes * 1715 buffer.fPixelSize; 1716 1717 #if qDNGBigEndian 1718 1719 // We need to use the same byte order to compute 1720 // the digest, no matter the native order. Little-endian 1721 // is more common now, so use that. 1722 1723 switch (buffer.fPixelSize) 1724 { 1725 1726 case 1: 1727 break; 1728 1729 case 2: 1730 { 1731 DoSwapBytes16 ((uint16 *) buffer.fData, count >> 1); 1732 break; 1733 } 1734 1735 case 4: 1736 { 1737 DoSwapBytes32 ((uint32 *) buffer.fData, count >> 2); 1738 break; 1739 } 1740 1741 default: 1742 { 1743 DNG_REPORT ("Unexpected pixel size"); 1744 break; 1745 } 1746 1747 } 1748 1749 #endif 1750 1751 dng_md5_printer printer; 1752 1753 printer.Process (buffer.fData, count); 1754 1755 fTileHash [tileIndex] = printer.Result (); 1756 1757 } 1758 1759 dng_fingerprint Result () 1760 { 1761 1762 dng_md5_printer printer; 1763 1764 for (uint32 tileIndex = 0; tileIndex < fTileCount; tileIndex++) 1765 { 1766 1767 printer.Process (fTileHash [tileIndex] . data, 16); 1768 1769 } 1770 1771 return printer.Result (); 1772 1773 } 1774 1775 }; 1776 1777 /*****************************************************************************/ 1778 1779 void dng_negative::FindNewRawImageDigest (dng_host &host) const 1780 { 1781 1782 if (fNewRawImageDigest.IsNull ()) 1783 { 1784 1785 #if qDNGValidate 1786 1787 dng_timer timeScope ("FindNewRawImageDigest time"); 1788 1789 #endif 1790 1791 // Find fast digest of the raw image. 1792 1793 { 1794 1795 const dng_image &rawImage = RawImage (); 1796 1797 // Find pixel type that will be saved in the file. When saving DNGs, we convert 1798 // some 16-bit data to 8-bit data, so we need to do the matching logic here. 1799 1800 uint32 rawPixelType = rawImage.PixelType (); 1801 1802 if (rawPixelType == ttShort) 1803 { 1804 1805 // See if we are using a linearization table with <= 256 entries, in which 1806 // case the useful data will all fit within 8-bits. 1807 1808 const dng_linearization_info *rangeInfo = GetLinearizationInfo (); 1809 1810 if (rangeInfo) 1811 { 1812 1813 if (rangeInfo->fLinearizationTable.Get ()) 1814 { 1815 1816 uint32 entries = rangeInfo->fLinearizationTable->LogicalSize () >> 1; 1817 1818 if (entries <= 256) 1819 { 1820 1821 rawPixelType = ttByte; 1822 1823 } 1824 1825 } 1826 1827 } 1828 1829 } 1830 1831 // Find the fast digest on the raw image. 1832 1833 dng_find_new_raw_image_digest_task task (rawImage, rawPixelType); 1834 1835 host.PerformAreaTask (task, rawImage.Bounds ()); 1836 1837 fNewRawImageDigest = task.Result (); 1838 1839 } 1840 1841 // If there is a transparancy mask, we need to include that in the 1842 // digest also. 1843 1844 if (RawTransparencyMask () != NULL) 1845 { 1846 1847 // Find the fast digest on the raw mask. 1848 1849 dng_fingerprint maskDigest; 1850 1851 { 1852 1853 dng_find_new_raw_image_digest_task task (*RawTransparencyMask (), 1854 RawTransparencyMask ()->PixelType ()); 1855 1856 host.PerformAreaTask (task, RawTransparencyMask ()->Bounds ()); 1857 1858 maskDigest = task.Result (); 1859 1860 } 1861 1862 // Combine the two digests into a single digest. 1863 1864 dng_md5_printer printer; 1865 1866 printer.Process (fNewRawImageDigest.data, 16); 1867 1868 printer.Process (maskDigest.data, 16); 1869 1870 fNewRawImageDigest = printer.Result (); 1871 1872 } 1873 1874 } 1875 1876 } 1877 1878 /*****************************************************************************/ 1879 1880 void dng_negative::ValidateRawImageDigest (dng_host &host) 1881 { 1882 1883 if (Stage1Image () && !IsPreview () && (fRawImageDigest .IsValid () || 1884 fNewRawImageDigest.IsValid ())) 1885 { 1886 1887 bool isNewDigest = fNewRawImageDigest.IsValid (); 1888 1889 dng_fingerprint &rawDigest = isNewDigest ? fNewRawImageDigest 1890 : fRawImageDigest; 1891 1892 // For lossy compressed JPEG images, we need to compare the stored 1893 // digest to the digest computed from the compressed data, since 1894 // decompressing lossy JPEG data is itself a lossy process. 1895 1896 if (RawJPEGImageDigest ().IsValid () || RawJPEGImage ()) 1897 { 1898 1899 // Compute the raw JPEG image digest if we have not done so 1900 // already. 1901 1902 FindRawJPEGImageDigest (host); 1903 1904 if (rawDigest != RawJPEGImageDigest ()) 1905 { 1906 1907 #if qDNGValidate 1908 1909 ReportError ("RawImageDigest does not match raw jpeg image"); 1910 1911 #else 1912 1913 SetIsDamaged (true); 1914 1915 #endif 1916 1917 } 1918 1919 } 1920 1921 // Else we can compare the stored digest to the image in memory. 1922 1923 else 1924 { 1925 1926 dng_fingerprint oldDigest = rawDigest; 1927 1928 try 1929 { 1930 1931 rawDigest.Clear (); 1932 1933 if (isNewDigest) 1934 { 1935 1936 FindNewRawImageDigest (host); 1937 1938 } 1939 1940 else 1941 { 1942 1943 FindRawImageDigest (host); 1944 1945 } 1946 1947 } 1948 1949 catch (...) 1950 { 1951 1952 rawDigest = oldDigest; 1953 1954 throw; 1955 1956 } 1957 1958 if (oldDigest != rawDigest) 1959 { 1960 1961 #if qDNGValidate 1962 1963 if (isNewDigest) 1964 { 1965 ReportError ("NewRawImageDigest does not match raw image"); 1966 } 1967 else 1968 { 1969 ReportError ("RawImageDigest does not match raw image"); 1970 } 1971 1972 SetIsDamaged (true); 1973 1974 #else 1975 1976 if (!isNewDigest) 1977 { 1978 1979 // Note that Lightroom 1.4 Windows had a bug that corrupts the 1980 // first four bytes of the RawImageDigest tag. So if the last 1981 // twelve bytes match, this is very likely the result of the 1982 // bug, and not an actual corrupt file. So don't report this 1983 // to the user--just fix it. 1984 1985 { 1986 1987 bool matchLast12 = true; 1988 1989 for (uint32 j = 4; j < 16; j++) 1990 { 1991 matchLast12 = matchLast12 && (oldDigest.data [j] == fRawImageDigest.data [j]); 1992 } 1993 1994 if (matchLast12) 1995 { 1996 return; 1997 } 1998 1999 } 2000 2001 // Sometimes Lightroom 1.4 would corrupt more than the first four 2002 // bytes, but for all those files that I have seen so far the 2003 // resulting first four bytes are 0x08 0x00 0x00 0x00. 2004 2005 if (oldDigest.data [0] == 0x08 && 2006 oldDigest.data [1] == 0x00 && 2007 oldDigest.data [2] == 0x00 && 2008 oldDigest.data [3] == 0x00) 2009 { 2010 return; 2011 } 2012 2013 } 2014 2015 SetIsDamaged (true); 2016 2017 #endif 2018 2019 } 2020 2021 } 2022 2023 } 2024 2025 } 2026 2027 /*****************************************************************************/ 2028 2029 // If the raw data unique ID is missing, compute one based on a MD5 hash of 2030 // the raw image hash and the model name, plus other commonly changed 2031 // data that can affect rendering. 2032 2033 void dng_negative::FindRawDataUniqueID (dng_host &host) const 2034 { 2035 2036 if (fRawDataUniqueID.IsNull ()) 2037 { 2038 2039 dng_md5_printer_stream printer; 2040 2041 // If we have a raw jpeg image, it is much faster to 2042 // use its digest as part of the unique ID since 2043 // the data size is much smaller. We cannot use it 2044 // if there a transparency mask, since that is not 2045 // included in the RawJPEGImageDigest. 2046 2047 if (RawJPEGImage () && !RawTransparencyMask ()) 2048 { 2049 2050 FindRawJPEGImageDigest (host); 2051 2052 printer.Put (fRawJPEGImageDigest.data, 16); 2053 2054 } 2055 2056 // Include the new raw image digest in the unique ID. 2057 2058 else 2059 { 2060 2061 FindNewRawImageDigest (host); 2062 2063 printer.Put (fNewRawImageDigest.data, 16); 2064 2065 } 2066 2067 // Include model name. 2068 2069 printer.Put (ModelName ().Get (), 2070 ModelName ().Length ()); 2071 2072 // Include default crop area, since DNG Recover Edges can modify 2073 // these values and they affect rendering. 2074 2075 printer.Put_uint32 (fDefaultCropSizeH.n); 2076 printer.Put_uint32 (fDefaultCropSizeH.d); 2077 2078 printer.Put_uint32 (fDefaultCropSizeV.n); 2079 printer.Put_uint32 (fDefaultCropSizeV.d); 2080 2081 printer.Put_uint32 (fDefaultCropOriginH.n); 2082 printer.Put_uint32 (fDefaultCropOriginH.d); 2083 2084 printer.Put_uint32 (fDefaultCropOriginV.n); 2085 printer.Put_uint32 (fDefaultCropOriginV.d); 2086 2087 // Include default user crop. 2088 2089 printer.Put_uint32 (fDefaultUserCropT.n); 2090 printer.Put_uint32 (fDefaultUserCropT.d); 2091 2092 printer.Put_uint32 (fDefaultUserCropL.n); 2093 printer.Put_uint32 (fDefaultUserCropL.d); 2094 2095 printer.Put_uint32 (fDefaultUserCropB.n); 2096 printer.Put_uint32 (fDefaultUserCropB.d); 2097 2098 printer.Put_uint32 (fDefaultUserCropR.n); 2099 printer.Put_uint32 (fDefaultUserCropR.d); 2100 2101 // Include opcode lists, since lens correction utilities can modify 2102 // these values and they affect rendering. 2103 2104 fOpcodeList1.FingerprintToStream (printer); 2105 fOpcodeList2.FingerprintToStream (printer); 2106 fOpcodeList3.FingerprintToStream (printer); 2107 2108 fRawDataUniqueID = printer.Result (); 2109 2110 } 2111 2112 } 2113 2114 /******************************************************************************/ 2115 2116 // Forces recomputation of RawDataUniqueID, useful to call 2117 // after modifying the opcode lists, etc. 2118 2119 void dng_negative::RecomputeRawDataUniqueID (dng_host &host) 2120 { 2121 2122 fRawDataUniqueID.Clear (); 2123 2124 FindRawDataUniqueID (host); 2125 2126 } 2127 2128 /******************************************************************************/ 2129 2130 void dng_negative::FindOriginalRawFileDigest () const 2131 { 2132 2133 if (fOriginalRawFileDigest.IsNull () && fOriginalRawFileData.Get ()) 2134 { 2135 2136 dng_md5_printer printer; 2137 2138 printer.Process (fOriginalRawFileData->Buffer (), 2139 fOriginalRawFileData->LogicalSize ()); 2140 2141 fOriginalRawFileDigest = printer.Result (); 2142 2143 } 2144 2145 } 2146 2147 /*****************************************************************************/ 2148 2149 void dng_negative::ValidateOriginalRawFileDigest () 2150 { 2151 2152 if (fOriginalRawFileDigest.IsValid () && fOriginalRawFileData.Get ()) 2153 { 2154 2155 dng_fingerprint oldDigest = fOriginalRawFileDigest; 2156 2157 try 2158 { 2159 2160 fOriginalRawFileDigest.Clear (); 2161 2162 FindOriginalRawFileDigest (); 2163 2164 } 2165 2166 catch (...) 2167 { 2168 2169 fOriginalRawFileDigest = oldDigest; 2170 2171 throw; 2172 2173 } 2174 2175 if (oldDigest != fOriginalRawFileDigest) 2176 { 2177 2178 #if qDNGValidate 2179 2180 ReportError ("OriginalRawFileDigest does not match OriginalRawFileData"); 2181 2182 #else 2183 2184 SetIsDamaged (true); 2185 2186 #endif 2187 2188 // Don't "repair" the original image data digest. Once it is 2189 // bad, it stays bad. The user cannot tell by looking at the image 2190 // whether the damage is acceptable and can be ignored in the 2191 // future. 2192 2193 fOriginalRawFileDigest = oldDigest; 2194 2195 } 2196 2197 } 2198 2199 } 2200 2201 /******************************************************************************/ 2202 2203 dng_rect dng_negative::DefaultCropArea () const 2204 { 2205 2206 // First compute the area using simple rounding. 2207 2208 dng_rect result; 2209 2210 result.l = Round_int32 (fDefaultCropOriginH.As_real64 () * fRawToFullScaleH); 2211 result.t = Round_int32 (fDefaultCropOriginV.As_real64 () * fRawToFullScaleV); 2212 2213 result.r = result.l + Round_int32 (fDefaultCropSizeH.As_real64 () * fRawToFullScaleH); 2214 result.b = result.t + Round_int32 (fDefaultCropSizeV.As_real64 () * fRawToFullScaleV); 2215 2216 // Sometimes the simple rounding causes the resulting default crop 2217 // area to slide off the scaled image area. So we force this not 2218 // to happen. We only do this if the image is not stubbed. 2219 2220 const dng_image *image = Stage3Image (); 2221 2222 if (image) 2223 { 2224 2225 dng_point imageSize = image->Size (); 2226 2227 if (result.r > imageSize.h) 2228 { 2229 result.l -= result.r - imageSize.h; 2230 result.r = imageSize.h; 2231 } 2232 2233 if (result.b > imageSize.v) 2234 { 2235 result.t -= result.b - imageSize.v; 2236 result.b = imageSize.v; 2237 } 2238 2239 } 2240 2241 return result; 2242 2243 } 2244 2245 /*****************************************************************************/ 2246 2247 real64 dng_negative::TotalBaselineExposure (const dng_camera_profile_id &profileID) const 2248 { 2249 2250 real64 total = BaselineExposure (); 2251 2252 const dng_camera_profile *profile = ProfileByID (profileID); 2253 2254 if (profile) 2255 { 2256 2257 real64 offset = profile->BaselineExposureOffset ().As_real64 (); 2258 2259 total += offset; 2260 2261 } 2262 2263 return total; 2264 2265 } 2266 2267 /******************************************************************************/ 2268 2269 void dng_negative::SetShadowScale (const dng_urational &scale) 2270 { 2271 2272 if (scale.d > 0) 2273 { 2274 2275 real64 s = scale.As_real64 (); 2276 2277 if (s > 0.0 && s <= 1.0) 2278 { 2279 2280 fShadowScale = scale; 2281 2282 } 2283 2284 } 2285 2286 } 2287 2288 /******************************************************************************/ 2289 2290 void dng_negative::SetActiveArea (const dng_rect &area) 2291 { 2292 2293 NeedLinearizationInfo (); 2294 2295 dng_linearization_info &info = *fLinearizationInfo.Get (); 2296 2297 info.fActiveArea = area; 2298 2299 } 2300 2301 /******************************************************************************/ 2302 2303 void dng_negative::SetMaskedAreas (uint32 count, 2304 const dng_rect *area) 2305 { 2306 2307 DNG_ASSERT (count <= kMaxMaskedAreas, "Too many masked areas"); 2308 2309 NeedLinearizationInfo (); 2310 2311 dng_linearization_info &info = *fLinearizationInfo.Get (); 2312 2313 info.fMaskedAreaCount = Min_uint32 (count, kMaxMaskedAreas); 2314 2315 for (uint32 index = 0; index < info.fMaskedAreaCount; index++) 2316 { 2317 2318 info.fMaskedArea [index] = area [index]; 2319 2320 } 2321 2322 } 2323 2324 /*****************************************************************************/ 2325 2326 void dng_negative::SetLinearization (AutoPtr<dng_memory_block> &curve) 2327 { 2328 2329 NeedLinearizationInfo (); 2330 2331 dng_linearization_info &info = *fLinearizationInfo.Get (); 2332 2333 info.fLinearizationTable.Reset (curve.Release ()); 2334 2335 } 2336 2337 /*****************************************************************************/ 2338 2339 void dng_negative::SetBlackLevel (real64 black, 2340 int32 plane) 2341 { 2342 2343 NeedLinearizationInfo (); 2344 2345 dng_linearization_info &info = *fLinearizationInfo.Get (); 2346 2347 info.fBlackLevelRepeatRows = 1; 2348 info.fBlackLevelRepeatCols = 1; 2349 2350 if (plane < 0) 2351 { 2352 2353 for (uint32 j = 0; j < kMaxSamplesPerPixel; j++) 2354 { 2355 2356 info.fBlackLevel [0] [0] [j] = black; 2357 2358 } 2359 2360 } 2361 2362 else 2363 { 2364 2365 info.fBlackLevel [0] [0] [plane] = black; 2366 2367 } 2368 2369 info.RoundBlacks (); 2370 2371 } 2372 2373 /*****************************************************************************/ 2374 2375 void dng_negative::SetQuadBlacks (real64 black0, 2376 real64 black1, 2377 real64 black2, 2378 real64 black3, 2379 int32 plane) 2380 { 2381 2382 NeedLinearizationInfo (); 2383 2384 dng_linearization_info &info = *fLinearizationInfo.Get (); 2385 2386 info.fBlackLevelRepeatRows = 2; 2387 info.fBlackLevelRepeatCols = 2; 2388 2389 if (plane < 0) 2390 { 2391 2392 for (uint32 j = 0; j < kMaxSamplesPerPixel; j++) 2393 { 2394 2395 info.fBlackLevel [0] [0] [j] = black0; 2396 info.fBlackLevel [0] [1] [j] = black1; 2397 info.fBlackLevel [1] [0] [j] = black2; 2398 info.fBlackLevel [1] [1] [j] = black3; 2399 2400 } 2401 2402 } 2403 2404 else 2405 { 2406 2407 info.fBlackLevel [0] [0] [plane] = black0; 2408 info.fBlackLevel [0] [1] [plane] = black1; 2409 info.fBlackLevel [1] [0] [plane] = black2; 2410 info.fBlackLevel [1] [1] [plane] = black3; 2411 2412 } 2413 2414 info.RoundBlacks (); 2415 2416 } 2417 2418 /*****************************************************************************/ 2419 2420 void dng_negative::SetRowBlacks (const real64 *blacks, 2421 uint32 count) 2422 { 2423 2424 if (count) 2425 { 2426 2427 NeedLinearizationInfo (); 2428 2429 dng_linearization_info &info = *fLinearizationInfo.Get (); 2430 2431 uint32 byteCount = 0; 2432 2433 if (!SafeUint32Mult (count, (uint32) sizeof (real64), &byteCount)) 2434 { 2435 2436 ThrowMemoryFull("Arithmetic overflow computing byte count."); 2437 2438 } 2439 2440 info.fBlackDeltaV.Reset (Allocator ().Allocate (byteCount)); 2441 2442 DoCopyBytes (blacks, 2443 info.fBlackDeltaV->Buffer (), 2444 byteCount); 2445 2446 info.RoundBlacks (); 2447 2448 } 2449 2450 else if (fLinearizationInfo.Get ()) 2451 { 2452 2453 dng_linearization_info &info = *fLinearizationInfo.Get (); 2454 2455 info.fBlackDeltaV.Reset (); 2456 2457 } 2458 2459 } 2460 2461 /*****************************************************************************/ 2462 2463 void dng_negative::SetColumnBlacks (const real64 *blacks, 2464 uint32 count) 2465 { 2466 2467 if (count) 2468 { 2469 2470 NeedLinearizationInfo (); 2471 2472 dng_linearization_info &info = *fLinearizationInfo.Get (); 2473 2474 uint32 byteCount = 0; 2475 2476 if (!SafeUint32Mult (count, (uint32) sizeof (real64), &byteCount)) 2477 { 2478 2479 ThrowMemoryFull("Arithmetic overflow computing byte count."); 2480 2481 } 2482 2483 info.fBlackDeltaH.Reset (Allocator ().Allocate (byteCount)); 2484 2485 DoCopyBytes (blacks, 2486 info.fBlackDeltaH->Buffer (), 2487 byteCount); 2488 2489 info.RoundBlacks (); 2490 2491 } 2492 2493 else if (fLinearizationInfo.Get ()) 2494 { 2495 2496 dng_linearization_info &info = *fLinearizationInfo.Get (); 2497 2498 info.fBlackDeltaH.Reset (); 2499 2500 } 2501 2502 } 2503 2504 /*****************************************************************************/ 2505 2506 uint32 dng_negative::WhiteLevel (uint32 plane) const 2507 { 2508 2509 if (fLinearizationInfo.Get ()) 2510 { 2511 2512 const dng_linearization_info &info = *fLinearizationInfo.Get (); 2513 2514 return Round_uint32 (info.fWhiteLevel [plane]); 2515 2516 } 2517 2518 if (RawImage ().PixelType () == ttFloat) 2519 { 2520 2521 return 1; 2522 2523 } 2524 2525 return 0x0FFFF; 2526 2527 } 2528 2529 /*****************************************************************************/ 2530 2531 void dng_negative::SetWhiteLevel (uint32 white, 2532 int32 plane) 2533 { 2534 2535 NeedLinearizationInfo (); 2536 2537 dng_linearization_info &info = *fLinearizationInfo.Get (); 2538 2539 if (plane < 0) 2540 { 2541 2542 for (uint32 j = 0; j < kMaxSamplesPerPixel; j++) 2543 { 2544 2545 info.fWhiteLevel [j] = (real64) white; 2546 2547 } 2548 2549 } 2550 2551 else 2552 { 2553 2554 info.fWhiteLevel [plane] = (real64) white; 2555 2556 } 2557 2558 } 2559 2560 /******************************************************************************/ 2561 2562 void dng_negative::SetColorKeys (ColorKeyCode color0, 2563 ColorKeyCode color1, 2564 ColorKeyCode color2, 2565 ColorKeyCode color3) 2566 { 2567 2568 NeedMosaicInfo (); 2569 2570 dng_mosaic_info &info = *fMosaicInfo.Get (); 2571 2572 info.fCFAPlaneColor [0] = color0; 2573 info.fCFAPlaneColor [1] = color1; 2574 info.fCFAPlaneColor [2] = color2; 2575 info.fCFAPlaneColor [3] = color3; 2576 2577 } 2578 2579 /******************************************************************************/ 2580 2581 void dng_negative::SetBayerMosaic (uint32 phase) 2582 { 2583 2584 NeedMosaicInfo (); 2585 2586 dng_mosaic_info &info = *fMosaicInfo.Get (); 2587 2588 ColorKeyCode color0 = (ColorKeyCode) info.fCFAPlaneColor [0]; 2589 ColorKeyCode color1 = (ColorKeyCode) info.fCFAPlaneColor [1]; 2590 ColorKeyCode color2 = (ColorKeyCode) info.fCFAPlaneColor [2]; 2591 2592 info.fCFAPatternSize = dng_point (2, 2); 2593 2594 switch (phase) 2595 { 2596 2597 case 0: 2598 { 2599 info.fCFAPattern [0] [0] = color1; 2600 info.fCFAPattern [0] [1] = color0; 2601 info.fCFAPattern [1] [0] = color2; 2602 info.fCFAPattern [1] [1] = color1; 2603 break; 2604 } 2605 2606 case 1: 2607 { 2608 info.fCFAPattern [0] [0] = color0; 2609 info.fCFAPattern [0] [1] = color1; 2610 info.fCFAPattern [1] [0] = color1; 2611 info.fCFAPattern [1] [1] = color2; 2612 break; 2613 } 2614 2615 case 2: 2616 { 2617 info.fCFAPattern [0] [0] = color2; 2618 info.fCFAPattern [0] [1] = color1; 2619 info.fCFAPattern [1] [0] = color1; 2620 info.fCFAPattern [1] [1] = color0; 2621 break; 2622 } 2623 2624 case 3: 2625 { 2626 info.fCFAPattern [0] [0] = color1; 2627 info.fCFAPattern [0] [1] = color2; 2628 info.fCFAPattern [1] [0] = color0; 2629 info.fCFAPattern [1] [1] = color1; 2630 break; 2631 } 2632 2633 } 2634 2635 info.fColorPlanes = 3; 2636 2637 info.fCFALayout = 1; 2638 2639 } 2640 2641 /******************************************************************************/ 2642 2643 void dng_negative::SetFujiMosaic (uint32 phase) 2644 { 2645 2646 NeedMosaicInfo (); 2647 2648 dng_mosaic_info &info = *fMosaicInfo.Get (); 2649 2650 ColorKeyCode color0 = (ColorKeyCode) info.fCFAPlaneColor [0]; 2651 ColorKeyCode color1 = (ColorKeyCode) info.fCFAPlaneColor [1]; 2652 ColorKeyCode color2 = (ColorKeyCode) info.fCFAPlaneColor [2]; 2653 2654 info.fCFAPatternSize = dng_point (2, 4); 2655 2656 switch (phase) 2657 { 2658 2659 case 0: 2660 { 2661 info.fCFAPattern [0] [0] = color0; 2662 info.fCFAPattern [0] [1] = color1; 2663 info.fCFAPattern [0] [2] = color2; 2664 info.fCFAPattern [0] [3] = color1; 2665 info.fCFAPattern [1] [0] = color2; 2666 info.fCFAPattern [1] [1] = color1; 2667 info.fCFAPattern [1] [2] = color0; 2668 info.fCFAPattern [1] [3] = color1; 2669 break; 2670 } 2671 2672 case 1: 2673 { 2674 info.fCFAPattern [0] [0] = color2; 2675 info.fCFAPattern [0] [1] = color1; 2676 info.fCFAPattern [0] [2] = color0; 2677 info.fCFAPattern [0] [3] = color1; 2678 info.fCFAPattern [1] [0] = color0; 2679 info.fCFAPattern [1] [1] = color1; 2680 info.fCFAPattern [1] [2] = color2; 2681 info.fCFAPattern [1] [3] = color1; 2682 break; 2683 } 2684 2685 } 2686 2687 info.fColorPlanes = 3; 2688 2689 info.fCFALayout = 2; 2690 2691 } 2692 2693 /*****************************************************************************/ 2694 2695 void dng_negative::SetFujiMosaic6x6 (uint32 phase) 2696 { 2697 2698 NeedMosaicInfo (); 2699 2700 dng_mosaic_info &info = *fMosaicInfo.Get (); 2701 2702 ColorKeyCode color0 = (ColorKeyCode) info.fCFAPlaneColor [0]; 2703 ColorKeyCode color1 = (ColorKeyCode) info.fCFAPlaneColor [1]; 2704 ColorKeyCode color2 = (ColorKeyCode) info.fCFAPlaneColor [2]; 2705 2706 const uint32 patSize = 6; 2707 2708 info.fCFAPatternSize = dng_point (patSize, patSize); 2709 2710 info.fCFAPattern [0] [0] = color1; 2711 info.fCFAPattern [0] [1] = color2; 2712 info.fCFAPattern [0] [2] = color1; 2713 info.fCFAPattern [0] [3] = color1; 2714 info.fCFAPattern [0] [4] = color0; 2715 info.fCFAPattern [0] [5] = color1; 2716 2717 info.fCFAPattern [1] [0] = color0; 2718 info.fCFAPattern [1] [1] = color1; 2719 info.fCFAPattern [1] [2] = color0; 2720 info.fCFAPattern [1] [3] = color2; 2721 info.fCFAPattern [1] [4] = color1; 2722 info.fCFAPattern [1] [5] = color2; 2723 2724 info.fCFAPattern [2] [0] = color1; 2725 info.fCFAPattern [2] [1] = color2; 2726 info.fCFAPattern [2] [2] = color1; 2727 info.fCFAPattern [2] [3] = color1; 2728 info.fCFAPattern [2] [4] = color0; 2729 info.fCFAPattern [2] [5] = color1; 2730 2731 info.fCFAPattern [3] [0] = color1; 2732 info.fCFAPattern [3] [1] = color0; 2733 info.fCFAPattern [3] [2] = color1; 2734 info.fCFAPattern [3] [3] = color1; 2735 info.fCFAPattern [3] [4] = color2; 2736 info.fCFAPattern [3] [5] = color1; 2737 2738 info.fCFAPattern [4] [0] = color2; 2739 info.fCFAPattern [4] [1] = color1; 2740 info.fCFAPattern [4] [2] = color2; 2741 info.fCFAPattern [4] [3] = color0; 2742 info.fCFAPattern [4] [4] = color1; 2743 info.fCFAPattern [4] [5] = color0; 2744 2745 info.fCFAPattern [5] [0] = color1; 2746 info.fCFAPattern [5] [1] = color0; 2747 info.fCFAPattern [5] [2] = color1; 2748 info.fCFAPattern [5] [3] = color1; 2749 info.fCFAPattern [5] [4] = color2; 2750 info.fCFAPattern [5] [5] = color1; 2751 2752 DNG_REQUIRE (phase >= 0 && phase < patSize * patSize, 2753 "Bad phase in SetFujiMosaic6x6."); 2754 2755 if (phase > 0) 2756 { 2757 2758 dng_mosaic_info temp = info; 2759 2760 uint32 phaseRow = phase / patSize; 2761 2762 uint32 phaseCol = phase - (phaseRow * patSize); 2763 2764 for (uint32 dstRow = 0; dstRow < patSize; dstRow++) 2765 { 2766 2767 uint32 srcRow = (dstRow + phaseRow) % patSize; 2768 2769 for (uint32 dstCol = 0; dstCol < patSize; dstCol++) 2770 { 2771 2772 uint32 srcCol = (dstCol + phaseCol) % patSize; 2773 2774 temp.fCFAPattern [dstRow] [dstCol] = info.fCFAPattern [srcRow] [srcCol]; 2775 2776 } 2777 2778 } 2779 2780 info = temp; 2781 2782 } 2783 2784 info.fColorPlanes = 3; 2785 2786 info.fCFALayout = 1; 2787 2788 } 2789 2790 /******************************************************************************/ 2791 2792 void dng_negative::SetQuadMosaic (uint32 pattern) 2793 { 2794 2795 // The pattern of the four colors is assumed to be repeat at least every two 2796 // columns and eight rows. The pattern is encoded as a 32-bit integer, 2797 // with every two bits encoding a color, in scan order for two columns and 2798 // eight rows (lsb is first). The usual color coding is: 2799 // 2800 // 0 = Green 2801 // 1 = Magenta 2802 // 2 = Cyan 2803 // 3 = Yellow 2804 // 2805 // Examples: 2806 // 2807 // PowerShot 600 uses 0xe1e4e1e4: 2808 // 2809 // 0 1 2 3 4 5 2810 // 0 G M G M G M 2811 // 1 C Y C Y C Y 2812 // 2 M G M G M G 2813 // 3 C Y C Y C Y 2814 // 2815 // PowerShot A5 uses 0x1e4e1e4e: 2816 // 2817 // 0 1 2 3 4 5 2818 // 0 C Y C Y C Y 2819 // 1 G M G M G M 2820 // 2 C Y C Y C Y 2821 // 3 M G M G M G 2822 // 2823 // PowerShot A50 uses 0x1b4e4b1e: 2824 // 2825 // 0 1 2 3 4 5 2826 // 0 C Y C Y C Y 2827 // 1 M G M G M G 2828 // 2 Y C Y C Y C 2829 // 3 G M G M G M 2830 // 4 C Y C Y C Y 2831 // 5 G M G M G M 2832 // 6 Y C Y C Y C 2833 // 7 M G M G M G 2834 // 2835 // PowerShot Pro70 uses 0x1e4b4e1b: 2836 // 2837 // 0 1 2 3 4 5 2838 // 0 Y C Y C Y C 2839 // 1 M G M G M G 2840 // 2 C Y C Y C Y 2841 // 3 G M G M G M 2842 // 4 Y C Y C Y C 2843 // 5 G M G M G M 2844 // 6 C Y C Y C Y 2845 // 7 M G M G M G 2846 // 2847 // PowerShots Pro90 and G1 use 0xb4b4b4b4: 2848 // 2849 // 0 1 2 3 4 5 2850 // 0 G M G M G M 2851 // 1 Y C Y C Y C 2852 2853 NeedMosaicInfo (); 2854 2855 dng_mosaic_info &info = *fMosaicInfo.Get (); 2856 2857 if (((pattern >> 16) & 0x0FFFF) != (pattern & 0x0FFFF)) 2858 { 2859 info.fCFAPatternSize = dng_point (8, 2); 2860 } 2861 2862 else if (((pattern >> 8) & 0x0FF) != (pattern & 0x0FF)) 2863 { 2864 info.fCFAPatternSize = dng_point (4, 2); 2865 } 2866 2867 else 2868 { 2869 info.fCFAPatternSize = dng_point (2, 2); 2870 } 2871 2872 for (int32 row = 0; row < info.fCFAPatternSize.v; row++) 2873 { 2874 2875 for (int32 col = 0; col < info.fCFAPatternSize.h; col++) 2876 { 2877 2878 uint32 index = (pattern >> ((((row << 1) & 14) + (col & 1)) << 1)) & 3; 2879 2880 info.fCFAPattern [row] [col] = info.fCFAPlaneColor [index]; 2881 2882 } 2883 2884 } 2885 2886 info.fColorPlanes = 4; 2887 2888 info.fCFALayout = 1; 2889 2890 } 2891 2892 /******************************************************************************/ 2893 2894 void dng_negative::SetGreenSplit (uint32 split) 2895 { 2896 2897 NeedMosaicInfo (); 2898 2899 dng_mosaic_info &info = *fMosaicInfo.Get (); 2900 2901 info.fBayerGreenSplit = split; 2902 2903 } 2904 2905 /*****************************************************************************/ 2906 2907 void dng_negative::Parse (dng_host &host, 2908 dng_stream &stream, 2909 dng_info &info) 2910 { 2911 2912 // Shared info. 2913 2914 dng_shared &shared = *(info.fShared.Get ()); 2915 2916 // Find IFD holding the main raw information. 2917 2918 dng_ifd &rawIFD = *info.fIFD [info.fMainIndex].Get (); 2919 2920 // Model name. 2921 2922 SetModelName (shared.fUniqueCameraModel.Get ()); 2923 2924 // Localized model name. 2925 2926 SetLocalName (shared.fLocalizedCameraModel.Get ()); 2927 2928 // Base orientation. 2929 2930 { 2931 2932 uint32 orientation = info.fIFD [0]->fOrientation; 2933 2934 if (orientation >= 1 && orientation <= 8) 2935 { 2936 2937 SetBaseOrientation (dng_orientation::TIFFtoDNG (orientation)); 2938 2939 } 2940 2941 } 2942 2943 // Default crop rectangle. 2944 2945 SetDefaultCropSize (rawIFD.fDefaultCropSizeH, 2946 rawIFD.fDefaultCropSizeV); 2947 2948 SetDefaultCropOrigin (rawIFD.fDefaultCropOriginH, 2949 rawIFD.fDefaultCropOriginV); 2950 2951 // Default user crop rectangle. 2952 2953 SetDefaultUserCrop (rawIFD.fDefaultUserCropT, 2954 rawIFD.fDefaultUserCropL, 2955 rawIFD.fDefaultUserCropB, 2956 rawIFD.fDefaultUserCropR); 2957 2958 // Default scale. 2959 2960 SetDefaultScale (rawIFD.fDefaultScaleH, 2961 rawIFD.fDefaultScaleV); 2962 2963 // Best quality scale. 2964 2965 SetBestQualityScale (rawIFD.fBestQualityScale); 2966 2967 // Baseline noise. 2968 2969 SetBaselineNoise (shared.fBaselineNoise.As_real64 ()); 2970 2971 // NoiseReductionApplied. 2972 2973 SetNoiseReductionApplied (shared.fNoiseReductionApplied); 2974 2975 // NoiseProfile. 2976 2977 SetNoiseProfile (shared.fNoiseProfile); 2978 2979 // Baseline exposure. 2980 2981 SetBaselineExposure (shared.fBaselineExposure.As_real64 ()); 2982 2983 // Baseline sharpness. 2984 2985 SetBaselineSharpness (shared.fBaselineSharpness.As_real64 ()); 2986 2987 // Chroma blur radius. 2988 2989 SetChromaBlurRadius (rawIFD.fChromaBlurRadius); 2990 2991 // Anti-alias filter strength. 2992 2993 SetAntiAliasStrength (rawIFD.fAntiAliasStrength); 2994 2995 // Linear response limit. 2996 2997 SetLinearResponseLimit (shared.fLinearResponseLimit.As_real64 ()); 2998 2999 // Shadow scale. 3000 3001 SetShadowScale (shared.fShadowScale); 3002 3003 // Colorimetric reference. 3004 3005 SetColorimetricReference (shared.fColorimetricReference); 3006 3007 // Color channels. 3008 3009 SetColorChannels (shared.fCameraProfile.fColorPlanes); 3010 3011 // Analog balance. 3012 3013 if (shared.fAnalogBalance.NotEmpty ()) 3014 { 3015 3016 SetAnalogBalance (shared.fAnalogBalance); 3017 3018 } 3019 3020 // Camera calibration matrices 3021 3022 if (shared.fCameraCalibration1.NotEmpty ()) 3023 { 3024 3025 SetCameraCalibration1 (shared.fCameraCalibration1); 3026 3027 } 3028 3029 if (shared.fCameraCalibration2.NotEmpty ()) 3030 { 3031 3032 SetCameraCalibration2 (shared.fCameraCalibration2); 3033 3034 } 3035 3036 if (shared.fCameraCalibration1.NotEmpty () || 3037 shared.fCameraCalibration2.NotEmpty ()) 3038 { 3039 3040 SetCameraCalibrationSignature (shared.fCameraCalibrationSignature.Get ()); 3041 3042 } 3043 3044 // Embedded camera profiles. 3045 3046 if (shared.fCameraProfile.fColorPlanes > 1) 3047 { 3048 3049 if (qDNGValidate || host.NeedsMeta () || host.NeedsImage ()) 3050 { 3051 3052 // Add profile from main IFD. 3053 3054 { 3055 3056 AutoPtr<dng_camera_profile> profile (new dng_camera_profile ()); 3057 3058 dng_camera_profile_info &profileInfo = shared.fCameraProfile; 3059 3060 profile->Parse (stream, profileInfo); 3061 3062 // The main embedded profile must be valid. 3063 3064 if (!profile->IsValid (shared.fCameraProfile.fColorPlanes)) 3065 { 3066 3067 ThrowBadFormat (); 3068 3069 } 3070 3071 profile->SetWasReadFromDNG (); 3072 3073 AddProfile (profile); 3074 3075 } 3076 3077 // Extra profiles. 3078 3079 for (uint32 index = 0; index < (uint32) shared.fExtraCameraProfiles.size (); index++) 3080 { 3081 3082 try 3083 { 3084 3085 AutoPtr<dng_camera_profile> profile (new dng_camera_profile ()); 3086 3087 dng_camera_profile_info &profileInfo = shared.fExtraCameraProfiles [index]; 3088 3089 profile->Parse (stream, profileInfo); 3090 3091 if (!profile->IsValid (shared.fCameraProfile.fColorPlanes)) 3092 { 3093 3094 ThrowBadFormat (); 3095 3096 } 3097 3098 profile->SetWasReadFromDNG (); 3099 3100 AddProfile (profile); 3101 3102 } 3103 3104 catch (dng_exception &except) 3105 { 3106 3107 // Don't ignore transient errors. 3108 3109 if (host.IsTransientError (except.ErrorCode ())) 3110 { 3111 3112 throw; 3113 3114 } 3115 3116 // Eat other parsing errors. 3117 3118 #if qDNGValidate 3119 3120 ReportWarning ("Unable to parse extra profile"); 3121 3122 #endif 3123 3124 } 3125 3126 } 3127 3128 } 3129 3130 // As shot profile name. 3131 3132 if (shared.fAsShotProfileName.NotEmpty ()) 3133 { 3134 3135 SetAsShotProfileName (shared.fAsShotProfileName.Get ()); 3136 3137 } 3138 3139 } 3140 3141 // Raw image data digest. 3142 3143 if (shared.fRawImageDigest.IsValid ()) 3144 { 3145 3146 SetRawImageDigest (shared.fRawImageDigest); 3147 3148 } 3149 3150 // New raw image data digest. 3151 3152 if (shared.fNewRawImageDigest.IsValid ()) 3153 { 3154 3155 SetNewRawImageDigest (shared.fNewRawImageDigest); 3156 3157 } 3158 3159 // Raw data unique ID. 3160 3161 if (shared.fRawDataUniqueID.IsValid ()) 3162 { 3163 3164 SetRawDataUniqueID (shared.fRawDataUniqueID); 3165 3166 } 3167 3168 // Original raw file name. 3169 3170 if (shared.fOriginalRawFileName.NotEmpty ()) 3171 { 3172 3173 SetOriginalRawFileName (shared.fOriginalRawFileName.Get ()); 3174 3175 } 3176 3177 // Original raw file data. 3178 3179 if (shared.fOriginalRawFileDataCount) 3180 { 3181 3182 SetHasOriginalRawFileData (true); 3183 3184 if (host.KeepOriginalFile ()) 3185 { 3186 3187 uint32 count = shared.fOriginalRawFileDataCount; 3188 3189 AutoPtr<dng_memory_block> block (host.Allocate (count)); 3190 3191 stream.SetReadPosition (shared.fOriginalRawFileDataOffset); 3192 3193 stream.Get (block->Buffer (), count); 3194 3195 SetOriginalRawFileData (block); 3196 3197 SetOriginalRawFileDigest (shared.fOriginalRawFileDigest); 3198 3199 ValidateOriginalRawFileDigest (); 3200 3201 } 3202 3203 } 3204 3205 // DNG private data. 3206 3207 if (shared.fDNGPrivateDataCount && (host.SaveDNGVersion () != dngVersion_None)) 3208 { 3209 3210 uint32 length = shared.fDNGPrivateDataCount; 3211 3212 AutoPtr<dng_memory_block> block (host.Allocate (length)); 3213 3214 stream.SetReadPosition (shared.fDNGPrivateDataOffset); 3215 3216 stream.Get (block->Buffer (), length); 3217 3218 SetPrivateData (block); 3219 3220 } 3221 3222 // Hand off EXIF metadata to negative. 3223 3224 ResetExif (info.fExif.Release ()); 3225 3226 // Parse linearization info. 3227 3228 NeedLinearizationInfo (); 3229 3230 fLinearizationInfo.Get ()->Parse (host, 3231 stream, 3232 info); 3233 3234 // Parse mosaic info. 3235 3236 if (rawIFD.fPhotometricInterpretation == piCFA) 3237 { 3238 3239 NeedMosaicInfo (); 3240 3241 fMosaicInfo.Get ()->Parse (host, 3242 stream, 3243 info); 3244 3245 } 3246 3247 // Fill in original sizes. 3248 3249 if (shared.fOriginalDefaultFinalSize.h > 0 && 3250 shared.fOriginalDefaultFinalSize.v > 0) 3251 { 3252 3253 SetOriginalDefaultFinalSize (shared.fOriginalDefaultFinalSize); 3254 3255 SetOriginalBestQualityFinalSize (shared.fOriginalDefaultFinalSize); 3256 3257 SetOriginalDefaultCropSize (dng_urational (shared.fOriginalDefaultFinalSize.h, 1), 3258 dng_urational (shared.fOriginalDefaultFinalSize.v, 1)); 3259 3260 } 3261 3262 if (shared.fOriginalBestQualityFinalSize.h > 0 && 3263 shared.fOriginalBestQualityFinalSize.v > 0) 3264 { 3265 3266 SetOriginalBestQualityFinalSize (shared.fOriginalBestQualityFinalSize); 3267 3268 } 3269 3270 if (shared.fOriginalDefaultCropSizeH.As_real64 () >= 1.0 && 3271 shared.fOriginalDefaultCropSizeV.As_real64 () >= 1.0) 3272 { 3273 3274 SetOriginalDefaultCropSize (shared.fOriginalDefaultCropSizeH, 3275 shared.fOriginalDefaultCropSizeV); 3276 3277 } 3278 3279 } 3280 3281 /*****************************************************************************/ 3282 3283 void dng_negative::SetDefaultOriginalSizes () 3284 { 3285 3286 // Fill in original sizes if we don't have them already. 3287 3288 if (OriginalDefaultFinalSize () == dng_point ()) 3289 { 3290 3291 SetOriginalDefaultFinalSize (dng_point (DefaultFinalHeight (), 3292 DefaultFinalWidth ())); 3293 3294 } 3295 3296 if (OriginalBestQualityFinalSize () == dng_point ()) 3297 { 3298 3299 SetOriginalBestQualityFinalSize (dng_point (BestQualityFinalHeight (), 3300 BestQualityFinalWidth ())); 3301 3302 } 3303 3304 if (OriginalDefaultCropSizeH ().NotValid () || 3305 OriginalDefaultCropSizeV ().NotValid ()) 3306 { 3307 3308 SetOriginalDefaultCropSize (DefaultCropSizeH (), 3309 DefaultCropSizeV ()); 3310 3311 } 3312 3313 } 3314 3315 /*****************************************************************************/ 3316 3317 void dng_negative::PostParse (dng_host &host, 3318 dng_stream &stream, 3319 dng_info &info) 3320 { 3321 3322 // Shared info. 3323 3324 dng_shared &shared = *(info.fShared.Get ()); 3325 3326 if (host.NeedsMeta ()) 3327 { 3328 3329 // Fill in original sizes if we don't have them already. 3330 3331 SetDefaultOriginalSizes (); 3332 3333 // MakerNote. 3334 3335 if (shared.fMakerNoteCount) 3336 { 3337 3338 // See if we know if the MakerNote is safe or not. 3339 3340 SetMakerNoteSafety (shared.fMakerNoteSafety == 1); 3341 3342 // If the MakerNote is safe, preserve it as a MakerNote. 3343 3344 if (IsMakerNoteSafe ()) 3345 { 3346 3347 AutoPtr<dng_memory_block> block (host.Allocate (shared.fMakerNoteCount)); 3348 3349 stream.SetReadPosition (shared.fMakerNoteOffset); 3350 3351 stream.Get (block->Buffer (), shared.fMakerNoteCount); 3352 3353 SetMakerNote (block); 3354 3355 } 3356 3357 } 3358 3359 // IPTC metadata. 3360 3361 if (shared.fIPTC_NAA_Count) 3362 { 3363 3364 AutoPtr<dng_memory_block> block (host.Allocate (shared.fIPTC_NAA_Count)); 3365 3366 stream.SetReadPosition (shared.fIPTC_NAA_Offset); 3367 3368 uint64 iptcOffset = stream.PositionInOriginalFile(); 3369 3370 stream.Get (block->Buffer (), 3371 block->LogicalSize ()); 3372 3373 SetIPTC (block, iptcOffset); 3374 3375 } 3376 3377 // XMP metadata. 3378 3379 #if qDNGUseXMP 3380 3381 if (shared.fXMPCount) 3382 { 3383 3384 AutoPtr<dng_memory_block> block (host.Allocate (shared.fXMPCount)); 3385 3386 stream.SetReadPosition (shared.fXMPOffset); 3387 3388 stream.Get (block->Buffer (), 3389 block->LogicalSize ()); 3390 3391 Metadata ().SetEmbeddedXMP (host, 3392 block->Buffer (), 3393 block->LogicalSize ()); 3394 3395 #if qDNGValidate 3396 3397 if (!Metadata ().HaveValidEmbeddedXMP ()) 3398 { 3399 ReportError ("The embedded XMP is invalid"); 3400 } 3401 3402 #endif 3403 3404 } 3405 3406 #endif 3407 3408 // Color info. 3409 3410 if (!IsMonochrome ()) 3411 { 3412 3413 // If the ColorimetricReference is the ICC profile PCS, 3414 // then the data must be already be white balanced to the 3415 // ICC profile PCS white point. 3416 3417 if (ColorimetricReference () == crICCProfilePCS) 3418 { 3419 3420 ClearCameraNeutral (); 3421 3422 SetCameraWhiteXY (PCStoXY ()); 3423 3424 } 3425 3426 else 3427 { 3428 3429 // AsShotNeutral. 3430 3431 if (shared.fAsShotNeutral.Count () == ColorChannels ()) 3432 { 3433 3434 SetCameraNeutral (shared.fAsShotNeutral); 3435 3436 } 3437 3438 // AsShotWhiteXY. 3439 3440 if (shared.fAsShotWhiteXY.IsValid () && !HasCameraNeutral ()) 3441 { 3442 3443 SetCameraWhiteXY (shared.fAsShotWhiteXY); 3444 3445 } 3446 3447 } 3448 3449 } 3450 3451 } 3452 3453 } 3454 3455 /*****************************************************************************/ 3456 3457 bool dng_negative::SetFourColorBayer () 3458 { 3459 3460 if (ColorChannels () != 3) 3461 { 3462 return false; 3463 } 3464 3465 if (!fMosaicInfo.Get ()) 3466 { 3467 return false; 3468 } 3469 3470 if (!fMosaicInfo.Get ()->SetFourColorBayer ()) 3471 { 3472 return false; 3473 } 3474 3475 SetColorChannels (4); 3476 3477 if (fCameraNeutral.Count () == 3) 3478 { 3479 3480 dng_vector n (4); 3481 3482 n [0] = fCameraNeutral [0]; 3483 n [1] = fCameraNeutral [1]; 3484 n [2] = fCameraNeutral [2]; 3485 n [3] = fCameraNeutral [1]; 3486 3487 fCameraNeutral = n; 3488 3489 } 3490 3491 fCameraCalibration1.Clear (); 3492 fCameraCalibration2.Clear (); 3493 3494 fCameraCalibrationSignature.Clear (); 3495 3496 for (uint32 index = 0; index < (uint32) fCameraProfile.size (); index++) 3497 { 3498 3499 fCameraProfile [index]->SetFourColorBayer (); 3500 3501 } 3502 3503 return true; 3504 3505 } 3506 3507 /*****************************************************************************/ 3508 3509 const dng_image & dng_negative::RawImage () const 3510 { 3511 3512 if (fRawImage.Get ()) 3513 { 3514 return *fRawImage.Get (); 3515 } 3516 3517 if (fStage1Image.Get ()) 3518 { 3519 return *fStage1Image.Get (); 3520 } 3521 3522 if (fUnflattenedStage3Image.Get ()) 3523 { 3524 return *fUnflattenedStage3Image.Get (); 3525 } 3526 3527 DNG_ASSERT (fStage3Image.Get (), 3528 "dng_negative::RawImage with no raw image"); 3529 3530 return *fStage3Image.Get (); 3531 3532 } 3533 3534 /*****************************************************************************/ 3535 3536 const dng_jpeg_image * dng_negative::RawJPEGImage () const 3537 { 3538 3539 return fRawJPEGImage.Get (); 3540 3541 } 3542 3543 /*****************************************************************************/ 3544 3545 void dng_negative::SetRawJPEGImage (AutoPtr<dng_jpeg_image> &jpegImage) 3546 { 3547 3548 fRawJPEGImage.Reset (jpegImage.Release ()); 3549 3550 } 3551 3552 /*****************************************************************************/ 3553 3554 void dng_negative::ClearRawJPEGImage () 3555 { 3556 3557 fRawJPEGImage.Reset (); 3558 3559 } 3560 3561 /*****************************************************************************/ 3562 3563 void dng_negative::FindRawJPEGImageDigest (dng_host &host) const 3564 { 3565 3566 if (fRawJPEGImageDigest.IsNull ()) 3567 { 3568 3569 if (fRawJPEGImage.Get ()) 3570 { 3571 3572 #if qDNGValidate 3573 3574 dng_timer timer ("FindRawJPEGImageDigest time"); 3575 3576 #endif 3577 3578 fRawJPEGImageDigest = fRawJPEGImage->FindDigest (host); 3579 3580 } 3581 3582 else 3583 { 3584 3585 ThrowProgramError ("No raw JPEG image"); 3586 3587 } 3588 3589 } 3590 3591 } 3592 3593 /*****************************************************************************/ 3594 3595 void dng_negative::ReadStage1Image (dng_host &host, 3596 dng_stream &stream, 3597 dng_info &info) 3598 { 3599 3600 // Allocate image we are reading. 3601 3602 dng_ifd &rawIFD = *info.fIFD [info.fMainIndex].Get (); 3603 3604 fStage1Image.Reset (host.Make_dng_image (rawIFD.Bounds (), 3605 rawIFD.fSamplesPerPixel, 3606 rawIFD.PixelType ())); 3607 3608 // See if we should grab the compressed JPEG data. 3609 3610 AutoPtr<dng_jpeg_image> jpegImage; 3611 3612 if (host.SaveDNGVersion () >= dngVersion_1_4_0_0 && 3613 !host.PreferredSize () && 3614 !host.ForPreview () && 3615 rawIFD.fCompression == ccLossyJPEG) 3616 { 3617 3618 jpegImage.Reset (new dng_jpeg_image); 3619 3620 } 3621 3622 // See if we need to compute the digest of the compressed JPEG data 3623 // while reading. 3624 3625 bool needJPEGDigest = (RawImageDigest ().IsValid () || 3626 NewRawImageDigest ().IsValid ()) && 3627 rawIFD.fCompression == ccLossyJPEG && 3628 jpegImage.Get () == NULL; 3629 3630 dng_fingerprint jpegDigest; 3631 3632 // Read the image. 3633 3634 rawIFD.ReadImage (host, 3635 stream, 3636 *fStage1Image.Get (), 3637 jpegImage.Get (), 3638 needJPEGDigest ? &jpegDigest : NULL); 3639 3640 // Remember the raw floating point bit depth, if reading from 3641 // a floating point image. 3642 3643 if (fStage1Image->PixelType () == ttFloat) 3644 { 3645 3646 SetRawFloatBitDepth (rawIFD.fBitsPerSample [0]); 3647 3648 } 3649 3650 // Remember the compressed JPEG data if we read it. 3651 3652 if (jpegImage.Get ()) 3653 { 3654 3655 SetRawJPEGImage (jpegImage); 3656 3657 } 3658 3659 // Remember the compressed JPEG digest if we computed it. 3660 3661 if (jpegDigest.IsValid ()) 3662 { 3663 3664 SetRawJPEGImageDigest (jpegDigest); 3665 3666 } 3667 3668 // We are are reading the main image, we should read the opcode lists 3669 // also. 3670 3671 if (rawIFD.fOpcodeList1Count) 3672 { 3673 3674 #if qDNGValidate 3675 3676 if (gVerbose) 3677 { 3678 printf ("\nParsing OpcodeList1: "); 3679 } 3680 3681 #endif 3682 3683 fOpcodeList1.Parse (host, 3684 stream, 3685 rawIFD.fOpcodeList1Count, 3686 rawIFD.fOpcodeList1Offset); 3687 3688 } 3689 3690 if (rawIFD.fOpcodeList2Count) 3691 { 3692 3693 #if qDNGValidate 3694 3695 if (gVerbose) 3696 { 3697 printf ("\nParsing OpcodeList2: "); 3698 } 3699 3700 #endif 3701 3702 fOpcodeList2.Parse (host, 3703 stream, 3704 rawIFD.fOpcodeList2Count, 3705 rawIFD.fOpcodeList2Offset); 3706 3707 } 3708 3709 if (rawIFD.fOpcodeList3Count) 3710 { 3711 3712 #if qDNGValidate 3713 3714 if (gVerbose) 3715 { 3716 printf ("\nParsing OpcodeList3: "); 3717 } 3718 3719 #endif 3720 3721 fOpcodeList3.Parse (host, 3722 stream, 3723 rawIFD.fOpcodeList3Count, 3724 rawIFD.fOpcodeList3Offset); 3725 3726 } 3727 3728 } 3729 3730 /*****************************************************************************/ 3731 3732 void dng_negative::SetStage1Image (AutoPtr<dng_image> &image) 3733 { 3734 3735 fStage1Image.Reset (image.Release ()); 3736 3737 } 3738 3739 /*****************************************************************************/ 3740 3741 void dng_negative::SetStage2Image (AutoPtr<dng_image> &image) 3742 { 3743 3744 fStage2Image.Reset (image.Release ()); 3745 3746 } 3747 3748 /*****************************************************************************/ 3749 3750 void dng_negative::SetStage3Image (AutoPtr<dng_image> &image) 3751 { 3752 3753 fStage3Image.Reset (image.Release ()); 3754 3755 } 3756 3757 /*****************************************************************************/ 3758 3759 void dng_negative::DoBuildStage2 (dng_host &host) 3760 { 3761 3762 dng_image &stage1 = *fStage1Image.Get (); 3763 3764 dng_linearization_info &info = *fLinearizationInfo.Get (); 3765 3766 uint32 pixelType = ttShort; 3767 3768 if (stage1.PixelType () == ttLong || 3769 stage1.PixelType () == ttFloat) 3770 { 3771 3772 pixelType = ttFloat; 3773 3774 } 3775 3776 fStage2Image.Reset (host.Make_dng_image (info.fActiveArea.Size (), 3777 stage1.Planes (), 3778 pixelType)); 3779 3780 info.Linearize (host, 3781 stage1, 3782 *fStage2Image.Get ()); 3783 3784 } 3785 3786 /*****************************************************************************/ 3787 3788 void dng_negative::DoPostOpcodeList2 (dng_host & /* host */) 3789 { 3790 3791 // Nothing by default. 3792 3793 } 3794 3795 /*****************************************************************************/ 3796 3797 bool dng_negative::NeedDefloatStage2 (dng_host &host) 3798 { 3799 3800 if (fStage2Image->PixelType () == ttFloat) 3801 { 3802 3803 if (fRawImageStage >= rawImageStagePostOpcode2 && 3804 host.SaveDNGVersion () != dngVersion_None && 3805 host.SaveDNGVersion () < dngVersion_1_4_0_0) 3806 { 3807 3808 return true; 3809 3810 } 3811 3812 } 3813 3814 return false; 3815 3816 } 3817 3818 /*****************************************************************************/ 3819 3820 void dng_negative::DefloatStage2 (dng_host & /* host */) 3821 { 3822 3823 ThrowNotYetImplemented ("dng_negative::DefloatStage2"); 3824 3825 } 3826 3827 /*****************************************************************************/ 3828 3829 void dng_negative::BuildStage2Image (dng_host &host) 3830 { 3831 3832 // If reading the negative to save in DNG format, figure out 3833 // when to grab a copy of the raw data. 3834 3835 if (host.SaveDNGVersion () != dngVersion_None) 3836 { 3837 3838 // Transparency masks are only supported in DNG version 1.4 and 3839 // later. In this case, the flattening of the transparency mask happens 3840 // on the the stage3 image. 3841 3842 if (TransparencyMask () && host.SaveDNGVersion () < dngVersion_1_4_0_0) 3843 { 3844 fRawImageStage = rawImageStagePostOpcode3; 3845 } 3846 3847 else if (fOpcodeList3.MinVersion (false) > host.SaveDNGVersion () || 3848 fOpcodeList3.AlwaysApply ()) 3849 { 3850 fRawImageStage = rawImageStagePostOpcode3; 3851 } 3852 3853 else if (host.SaveLinearDNG (*this)) 3854 { 3855 3856 // If the opcode list 3 has optional tags that are beyond the 3857 // the minimum version, and we are saving a linear DNG anyway, 3858 // then go ahead and apply them. 3859 3860 if (fOpcodeList3.MinVersion (true) > host.SaveDNGVersion ()) 3861 { 3862 fRawImageStage = rawImageStagePostOpcode3; 3863 } 3864 3865 else 3866 { 3867 fRawImageStage = rawImageStagePreOpcode3; 3868 } 3869 3870 } 3871 3872 else if (fOpcodeList2.MinVersion (false) > host.SaveDNGVersion () || 3873 fOpcodeList2.AlwaysApply ()) 3874 { 3875 fRawImageStage = rawImageStagePostOpcode2; 3876 } 3877 3878 else if (fOpcodeList1.MinVersion (false) > host.SaveDNGVersion () || 3879 fOpcodeList1.AlwaysApply ()) 3880 { 3881 fRawImageStage = rawImageStagePostOpcode1; 3882 } 3883 3884 else 3885 { 3886 fRawImageStage = rawImageStagePreOpcode1; 3887 } 3888 3889 // We should not save floating point stage1 images unless the target 3890 // DNG version is high enough to understand floating point images. 3891 // We handle this by converting from floating point to integer if 3892 // required after building stage2 image. 3893 3894 if (fStage1Image->PixelType () == ttFloat) 3895 { 3896 3897 if (fRawImageStage < rawImageStagePostOpcode2) 3898 { 3899 3900 if (host.SaveDNGVersion () < dngVersion_1_4_0_0) 3901 { 3902 3903 fRawImageStage = rawImageStagePostOpcode2; 3904 3905 } 3906 3907 } 3908 3909 } 3910 3911 } 3912 3913 // Grab clone of raw image if required. 3914 3915 if (fRawImageStage == rawImageStagePreOpcode1) 3916 { 3917 3918 fRawImage.Reset (fStage1Image->Clone ()); 3919 3920 if (fTransparencyMask.Get ()) 3921 { 3922 fRawTransparencyMask.Reset (fTransparencyMask->Clone ()); 3923 } 3924 3925 } 3926 3927 else 3928 { 3929 3930 // If we are not keeping the most raw image, we need 3931 // to recompute the raw image digest. 3932 3933 ClearRawImageDigest (); 3934 3935 // If we don't grab the unprocessed stage 1 image, then 3936 // the raw JPEG image is no longer valid. 3937 3938 ClearRawJPEGImage (); 3939 3940 // Nor is the digest of the raw JPEG data. 3941 3942 ClearRawJPEGImageDigest (); 3943 3944 // We also don't know the raw floating point bit depth. 3945 3946 SetRawFloatBitDepth (0); 3947 3948 } 3949 3950 // Process opcode list 1. 3951 3952 host.ApplyOpcodeList (fOpcodeList1, *this, fStage1Image); 3953 3954 // See if we are done with the opcode list 1. 3955 3956 if (fRawImageStage > rawImageStagePreOpcode1) 3957 { 3958 3959 fOpcodeList1.Clear (); 3960 3961 } 3962 3963 // Grab clone of raw image if required. 3964 3965 if (fRawImageStage == rawImageStagePostOpcode1) 3966 { 3967 3968 fRawImage.Reset (fStage1Image->Clone ()); 3969 3970 if (fTransparencyMask.Get ()) 3971 { 3972 fRawTransparencyMask.Reset (fTransparencyMask->Clone ()); 3973 } 3974 3975 } 3976 3977 // Finalize linearization info. 3978 3979 { 3980 3981 NeedLinearizationInfo (); 3982 3983 dng_linearization_info &info = *fLinearizationInfo.Get (); 3984 3985 info.PostParse (host, *this); 3986 3987 } 3988 3989 // Perform the linearization. 3990 3991 DoBuildStage2 (host); 3992 3993 // Delete the stage1 image now that we have computed the stage 2 image. 3994 3995 fStage1Image.Reset (); 3996 3997 // Are we done with the linearization info. 3998 3999 if (fRawImageStage > rawImageStagePostOpcode1) 4000 { 4001 4002 ClearLinearizationInfo (); 4003 4004 } 4005 4006 // Process opcode list 2. 4007 4008 host.ApplyOpcodeList (fOpcodeList2, *this, fStage2Image); 4009 4010 // See if we are done with the opcode list 2. 4011 4012 if (fRawImageStage > rawImageStagePostOpcode1) 4013 { 4014 4015 fOpcodeList2.Clear (); 4016 4017 } 4018 4019 // Hook for any required processing just after opcode list 2. 4020 4021 DoPostOpcodeList2 (host); 4022 4023 // Convert from floating point to integer if required. 4024 4025 if (NeedDefloatStage2 (host)) 4026 { 4027 4028 DefloatStage2 (host); 4029 4030 } 4031 4032 // Grab clone of raw image if required. 4033 4034 if (fRawImageStage == rawImageStagePostOpcode2) 4035 { 4036 4037 fRawImage.Reset (fStage2Image->Clone ()); 4038 4039 if (fTransparencyMask.Get ()) 4040 { 4041 fRawTransparencyMask.Reset (fTransparencyMask->Clone ()); 4042 } 4043 4044 } 4045 4046 } 4047 4048 /*****************************************************************************/ 4049 4050 void dng_negative::DoInterpolateStage3 (dng_host &host, 4051 int32 srcPlane) 4052 { 4053 4054 dng_image &stage2 = *fStage2Image.Get (); 4055 4056 dng_mosaic_info &info = *fMosaicInfo.Get (); 4057 4058 dng_point downScale = info.DownScale (host.MinimumSize (), 4059 host.PreferredSize (), 4060 host.CropFactor ()); 4061 4062 if (downScale != dng_point (1, 1)) 4063 { 4064 SetIsPreview (true); 4065 } 4066 4067 dng_point dstSize = info.DstSize (downScale); 4068 4069 fStage3Image.Reset (host.Make_dng_image (dng_rect (dstSize), 4070 info.fColorPlanes, 4071 stage2.PixelType ())); 4072 4073 if (srcPlane < 0 || srcPlane >= (int32) stage2.Planes ()) 4074 { 4075 srcPlane = 0; 4076 } 4077 4078 info.Interpolate (host, 4079 *this, 4080 stage2, 4081 *fStage3Image.Get (), 4082 downScale, 4083 srcPlane); 4084 4085 } 4086 4087 /*****************************************************************************/ 4088 4089 // Interpolate and merge a multi-channel CFA image. 4090 4091 void dng_negative::DoMergeStage3 (dng_host &host) 4092 { 4093 4094 // The DNG SDK does not provide multi-channel CFA image merging code. 4095 // It just grabs the first channel and uses that. 4096 4097 DoInterpolateStage3 (host, 0); 4098 4099 // Just grabbing the first channel would often result in the very 4100 // bright image using the baseline exposure value. 4101 4102 fStage3Gain = pow (2.0, BaselineExposure ()); 4103 4104 } 4105 4106 /*****************************************************************************/ 4107 4108 void dng_negative::DoBuildStage3 (dng_host &host, 4109 int32 srcPlane) 4110 { 4111 4112 // If we don't have a mosaic pattern, then just move the stage 2 4113 // image on to stage 3. 4114 4115 dng_mosaic_info *info = fMosaicInfo.Get (); 4116 4117 if (!info || !info->IsColorFilterArray ()) 4118 { 4119 4120 fStage3Image.Reset (fStage2Image.Release ()); 4121 4122 } 4123 4124 else 4125 { 4126 4127 // Remember the size of the stage 2 image. 4128 4129 dng_point stage2_size = fStage2Image->Size (); 4130 4131 // Special case multi-channel CFA interpolation. 4132 4133 if ((fStage2Image->Planes () > 1) && (srcPlane < 0)) 4134 { 4135 4136 DoMergeStage3 (host); 4137 4138 } 4139 4140 // Else do a single channel interpolation. 4141 4142 else 4143 { 4144 4145 DoInterpolateStage3 (host, srcPlane); 4146 4147 } 4148 4149 // Calculate the ratio of the stage 3 image size to stage 2 image size. 4150 4151 dng_point stage3_size = fStage3Image->Size (); 4152 4153 fRawToFullScaleH = (real64) stage3_size.h / (real64) stage2_size.h; 4154 fRawToFullScaleV = (real64) stage3_size.v / (real64) stage2_size.v; 4155 4156 } 4157 4158 } 4159 4160 /*****************************************************************************/ 4161 4162 void dng_negative::BuildStage3Image (dng_host &host, 4163 int32 srcPlane) 4164 { 4165 4166 // Finalize the mosaic information. 4167 4168 dng_mosaic_info *info = fMosaicInfo.Get (); 4169 4170 if (info) 4171 { 4172 4173 info->PostParse (host, *this); 4174 4175 } 4176 4177 // Do the interpolation as required. 4178 4179 DoBuildStage3 (host, srcPlane); 4180 4181 // Delete the stage2 image now that we have computed the stage 3 image. 4182 4183 fStage2Image.Reset (); 4184 4185 // Are we done with the mosaic info? 4186 4187 if (fRawImageStage >= rawImageStagePreOpcode3) 4188 { 4189 4190 ClearMosaicInfo (); 4191 4192 // To support saving linear DNG files, to need to account for 4193 // and upscaling during interpolation. 4194 4195 if (fRawToFullScaleH > 1.0) 4196 { 4197 4198 uint32 adjust = Round_uint32 (fRawToFullScaleH); 4199 4200 fDefaultCropSizeH .n = 4201 SafeUint32Mult (fDefaultCropSizeH.n, adjust); 4202 fDefaultCropOriginH.n = 4203 SafeUint32Mult (fDefaultCropOriginH.n, adjust); 4204 fDefaultScaleH .d = SafeUint32Mult (fDefaultScaleH.d, adjust); 4205 4206 fRawToFullScaleH /= (real64) adjust; 4207 4208 } 4209 4210 if (fRawToFullScaleV > 1.0) 4211 { 4212 4213 uint32 adjust = Round_uint32 (fRawToFullScaleV); 4214 4215 fDefaultCropSizeV .n = 4216 SafeUint32Mult (fDefaultCropSizeV.n, adjust); 4217 fDefaultCropOriginV.n = 4218 SafeUint32Mult (fDefaultCropOriginV.n, adjust); 4219 fDefaultScaleV .d = 4220 SafeUint32Mult (fDefaultScaleV.d, adjust); 4221 4222 fRawToFullScaleV /= (real64) adjust; 4223 4224 } 4225 4226 } 4227 4228 // Resample the transparency mask if required. 4229 4230 ResizeTransparencyToMatchStage3 (host); 4231 4232 // Grab clone of raw image if required. 4233 4234 if (fRawImageStage == rawImageStagePreOpcode3) 4235 { 4236 4237 fRawImage.Reset (fStage3Image->Clone ()); 4238 4239 if (fTransparencyMask.Get ()) 4240 { 4241 fRawTransparencyMask.Reset (fTransparencyMask->Clone ()); 4242 } 4243 4244 } 4245 4246 // Process opcode list 3. 4247 4248 host.ApplyOpcodeList (fOpcodeList3, *this, fStage3Image); 4249 4250 // See if we are done with the opcode list 3. 4251 4252 if (fRawImageStage > rawImageStagePreOpcode3) 4253 { 4254 4255 fOpcodeList3.Clear (); 4256 4257 } 4258 4259 // Just in case the opcode list 3 changed the image size, resample the 4260 // transparency mask again if required. This is nearly always going 4261 // to be a fast NOP operation. 4262 4263 ResizeTransparencyToMatchStage3 (host); 4264 4265 // Don't need to grab a copy of raw data at this stage since 4266 // it is kept around as the stage 3 image. 4267 4268 } 4269 4270 /******************************************************************************/ 4271 4272 class dng_gamma_encode_proxy : public dng_1d_function 4273 { 4274 4275 private: 4276 4277 real64 fBlack; 4278 real64 fWhite; 4279 4280 bool fIsSceneReferred; 4281 4282 real64 scale; 4283 real64 t1; 4284 4285 public: 4286 4287 dng_gamma_encode_proxy (real64 black, 4288 real64 white, 4289 bool isSceneReferred) 4290 4291 : fBlack (black) 4292 , fWhite (white) 4293 , fIsSceneReferred (isSceneReferred) 4294 4295 , scale (1.0 / (fWhite - fBlack)) 4296 , t1 (1.0 / (27.0 * pow (5.0, 3.0 / 2.0))) 4297 4298 { 4299 } 4300 4301 virtual real64 Evaluate (real64 x) const 4302 { 4303 4304 x = Pin_real64 (0.0, (x - fBlack) * scale, 1.0); 4305 4306 real64 y; 4307 4308 if (fIsSceneReferred) 4309 { 4310 4311 real64 t = pow (sqrt (25920.0 * x * x + 1.0) * t1 + x * (8.0 / 15.0), 1.0 / 3.0); 4312 4313 y = t - 1.0 / (45.0 * t); 4314 4315 DNG_ASSERT (Abs_real64 (x - (y / 16.0 + y * y * y * 15.0 / 16.0)) < 0.0000001, 4316 "Round trip error"); 4317 4318 } 4319 4320 else 4321 { 4322 4323 y = (sqrt (960.0 * x + 1.0) - 1.0) / 30.0; 4324 4325 DNG_ASSERT (Abs_real64 (x - (y / 16.0 + y * y * (15.0 / 16.0))) < 0.0000001, 4326 "Round trip error"); 4327 4328 } 4329 4330 return y; 4331 4332 } 4333 4334 }; 4335 4336 /*****************************************************************************/ 4337 4338 class dng_encode_proxy_task: public dng_area_task 4339 { 4340 4341 private: 4342 4343 const dng_image &fSrcImage; 4344 4345 dng_image &fDstImage; 4346 4347 AutoPtr<dng_memory_block> fTable16 [kMaxColorPlanes]; 4348 4349 public: 4350 4351 dng_encode_proxy_task (dng_host &host, 4352 const dng_image &srcImage, 4353 dng_image &dstImage, 4354 const real64 *black, 4355 const real64 *white, 4356 bool isSceneReferred); 4357 4358 virtual dng_rect RepeatingTile1 () const 4359 { 4360 return fSrcImage.RepeatingTile (); 4361 } 4362 4363 virtual dng_rect RepeatingTile2 () const 4364 { 4365 return fDstImage.RepeatingTile (); 4366 } 4367 4368 virtual void Process (uint32 threadIndex, 4369 const dng_rect &tile, 4370 dng_abort_sniffer *sniffer); 4371 4372 private: 4373 4374 // Hidden copy constructor and assignment operator. 4375 4376 dng_encode_proxy_task (const dng_encode_proxy_task &task); 4377 4378 dng_encode_proxy_task & operator= (const dng_encode_proxy_task &task); 4379 4380 }; 4381 4382 /*****************************************************************************/ 4383 4384 dng_encode_proxy_task::dng_encode_proxy_task (dng_host &host, 4385 const dng_image &srcImage, 4386 dng_image &dstImage, 4387 const real64 *black, 4388 const real64 *white, 4389 bool isSceneReferred) 4390 4391 : fSrcImage (srcImage) 4392 , fDstImage (dstImage) 4393 4394 { 4395 4396 for (uint32 plane = 0; plane < fSrcImage.Planes (); plane++) 4397 { 4398 4399 dng_gamma_encode_proxy gamma (black [plane], 4400 white [plane], 4401 isSceneReferred); 4402 4403 dng_1d_table table32; 4404 4405 table32.Initialize (host.Allocator (), gamma); 4406 4407 fTable16 [plane] . Reset (host.Allocate (0x10000 * sizeof (uint16))); 4408 4409 table32.Expand16 (fTable16 [plane]->Buffer_uint16 ()); 4410 4411 } 4412 4413 } 4414 4415 /*****************************************************************************/ 4416 4417 void dng_encode_proxy_task::Process (uint32 /* threadIndex */, 4418 const dng_rect &tile, 4419 dng_abort_sniffer * /* sniffer */) 4420 { 4421 4422 dng_const_tile_buffer srcBuffer (fSrcImage, tile); 4423 dng_dirty_tile_buffer dstBuffer (fDstImage, tile); 4424 4425 int32 sColStep = srcBuffer.fColStep; 4426 int32 dColStep = dstBuffer.fColStep; 4427 4428 const uint16 *noise = dng_dither::Get ().NoiseBuffer16 (); 4429 4430 for (uint32 plane = 0; plane < fSrcImage.Planes (); plane++) 4431 { 4432 4433 const uint16 *map = fTable16 [plane]->Buffer_uint16 (); 4434 4435 for (int32 row = tile.t; row < tile.b; row++) 4436 { 4437 4438 const uint16 *sPtr = srcBuffer.ConstPixel_uint16 (row, tile.l, plane); 4439 4440 uint8 *dPtr = dstBuffer.DirtyPixel_uint8 (row, tile.l, plane); 4441 4442 const uint16 *rPtr = &noise [(row & dng_dither::kRNGMask) * dng_dither::kRNGSize]; 4443 4444 for (int32 col = tile.l; col < tile.r; col++) 4445 { 4446 4447 uint32 x = *sPtr; 4448 4449 uint32 r = rPtr [col & dng_dither::kRNGMask]; 4450 4451 x = map [x]; 4452 4453 x = (((x << 8) - x) + r) >> 16; 4454 4455 *dPtr = (uint8) x; 4456 4457 sPtr += sColStep; 4458 dPtr += dColStep; 4459 4460 } 4461 4462 } 4463 4464 } 4465 4466 } 4467 4468 /******************************************************************************/ 4469 4470 dng_image * dng_negative::EncodeRawProxy (dng_host &host, 4471 const dng_image &srcImage, 4472 dng_opcode_list &opcodeList) const 4473 { 4474 4475 if (srcImage.PixelType () != ttShort) 4476 { 4477 return NULL; 4478 } 4479 4480 real64 black [kMaxColorPlanes]; 4481 real64 white [kMaxColorPlanes]; 4482 4483 bool isSceneReferred = (ColorimetricReference () == crSceneReferred); 4484 4485 { 4486 4487 const real64 kClipFraction = 0.00001; 4488 4489 uint64 pixels = (uint64) srcImage.Bounds ().H () * 4490 (uint64) srcImage.Bounds ().W (); 4491 4492 uint32 limit = Round_int32 ((real64) pixels * kClipFraction); 4493 4494 AutoPtr<dng_memory_block> histData (host.Allocate (65536 * sizeof (uint32))); 4495 4496 uint32 *hist = histData->Buffer_uint32 (); 4497 4498 for (uint32 plane = 0; plane < srcImage.Planes (); plane++) 4499 { 4500 4501 HistogramArea (host, 4502 srcImage, 4503 srcImage.Bounds (), 4504 hist, 4505 65535, 4506 plane); 4507 4508 uint32 total = 0; 4509 4510 uint32 upper = 65535; 4511 4512 while (total + hist [upper] <= limit && upper > 255) 4513 { 4514 4515 total += hist [upper]; 4516 4517 upper--; 4518 4519 } 4520 4521 total = 0; 4522 4523 uint32 lower = 0; 4524 4525 while (total + hist [lower] <= limit && lower < upper - 255) 4526 { 4527 4528 total += hist [lower]; 4529 4530 lower++; 4531 4532 } 4533 4534 black [plane] = lower / 65535.0; 4535 white [plane] = upper / 65535.0; 4536 4537 } 4538 4539 } 4540 4541 // Apply the gamma encoding, using dither when downsampling to 8-bit. 4542 4543 AutoPtr<dng_image> dstImage (host.Make_dng_image (srcImage.Bounds (), 4544 srcImage.Planes (), 4545 ttByte)); 4546 4547 { 4548 4549 dng_encode_proxy_task task (host, 4550 srcImage, 4551 *dstImage, 4552 black, 4553 white, 4554 isSceneReferred); 4555 4556 host.PerformAreaTask (task, 4557 srcImage.Bounds ()); 4558 4559 } 4560 4561 // Add opcodes to undo the gamma encoding. 4562 4563 { 4564 4565 for (uint32 plane = 0; plane < srcImage.Planes (); plane++) 4566 { 4567 4568 dng_area_spec areaSpec (srcImage.Bounds (), 4569 plane); 4570 4571 real64 coefficient [4]; 4572 4573 coefficient [0] = 0.0; 4574 coefficient [1] = 1.0 / 16.0; 4575 4576 if (isSceneReferred) 4577 { 4578 coefficient [2] = 0.0; 4579 coefficient [3] = 15.0 / 16.0; 4580 } 4581 else 4582 { 4583 coefficient [2] = 15.0 / 16.0; 4584 coefficient [3] = 0.0; 4585 } 4586 4587 coefficient [0] *= white [plane] - black [plane]; 4588 coefficient [1] *= white [plane] - black [plane]; 4589 coefficient [2] *= white [plane] - black [plane]; 4590 coefficient [3] *= white [plane] - black [plane]; 4591 4592 coefficient [0] += black [plane]; 4593 4594 AutoPtr<dng_opcode> opcode (new dng_opcode_MapPolynomial (areaSpec, 4595 isSceneReferred ? 3 : 2, 4596 coefficient)); 4597 4598 opcodeList.Append (opcode); 4599 4600 } 4601 4602 } 4603 4604 return dstImage.Release (); 4605 4606 } 4607 4608 /******************************************************************************/ 4609 4610 void dng_negative::AdjustProfileForStage3 () 4611 { 4612 4613 // For dng_sdk, the stage3 image's color space is always the same as the 4614 // raw image's color space. 4615 4616 } 4617 4618 /******************************************************************************/ 4619 4620 void dng_negative::ConvertToProxy (dng_host &host, 4621 dng_image_writer &writer, 4622 uint32 proxySize, 4623 uint64 proxyCount) 4624 { 4625 4626 if (!proxySize) 4627 { 4628 proxySize = kMaxImageSide; 4629 } 4630 4631 if (!proxyCount) 4632 { 4633 proxyCount = (uint64) proxySize * proxySize; 4634 } 4635 4636 // Don't need to private data around in non-full size proxies. 4637 4638 if (proxySize < kMaxImageSide || 4639 proxyCount < kMaxImageSide * kMaxImageSide) 4640 { 4641 4642 ClearMakerNote (); 4643 4644 ClearPrivateData (); 4645 4646 } 4647 4648 // See if we already have an acceptable proxy image. 4649 4650 if (fRawImage.Get () && 4651 fRawImage->PixelType () == ttByte && 4652 fRawImage->Bounds () == DefaultCropArea () && 4653 fRawImage->Bounds ().H () <= proxySize && 4654 fRawImage->Bounds ().W () <= proxySize && 4655 (uint64) fRawImage->Bounds ().H () * 4656 (uint64) fRawImage->Bounds ().W () <= proxyCount && 4657 (!GetMosaicInfo () || !GetMosaicInfo ()->IsColorFilterArray ()) && 4658 fRawJPEGImage.Get () && 4659 (!RawTransparencyMask () || RawTransparencyMask ()->PixelType () == ttByte)) 4660 { 4661 4662 return; 4663 4664 } 4665 4666 if (fRawImage.Get () && 4667 fRawImage->PixelType () == ttFloat && 4668 fRawImage->Bounds ().H () <= proxySize && 4669 fRawImage->Bounds ().W () <= proxySize && 4670 (uint64) fRawImage->Bounds ().H () * 4671 (uint64) fRawImage->Bounds ().W () <= proxyCount && 4672 RawFloatBitDepth () == 16 && 4673 (!RawTransparencyMask () || RawTransparencyMask ()->PixelType () == ttByte)) 4674 { 4675 4676 return; 4677 4678 } 4679 4680 // Clear any grabbed raw image, since we are going to start 4681 // building the proxy with the stage3 image. 4682 4683 fRawImage.Reset (); 4684 4685 ClearRawJPEGImage (); 4686 4687 SetRawFloatBitDepth (0); 4688 4689 ClearLinearizationInfo (); 4690 4691 ClearMosaicInfo (); 4692 4693 fOpcodeList1.Clear (); 4694 fOpcodeList2.Clear (); 4695 fOpcodeList3.Clear (); 4696 4697 // Adjust the profile to match the stage 3 image, if required. 4698 4699 AdjustProfileForStage3 (); 4700 4701 // Not saving the raw-most image, do the old raw digest is no 4702 // longer valid. 4703 4704 ClearRawImageDigest (); 4705 4706 ClearRawJPEGImageDigest (); 4707 4708 // Trim off extra pixels outside the default crop area. 4709 4710 dng_rect defaultCropArea = DefaultCropArea (); 4711 4712 if (Stage3Image ()->Bounds () != defaultCropArea) 4713 { 4714 4715 fStage3Image->Trim (defaultCropArea); 4716 4717 if (fTransparencyMask.Get ()) 4718 { 4719 fTransparencyMask->Trim (defaultCropArea); 4720 } 4721 4722 fDefaultCropOriginH = dng_urational (0, 1); 4723 fDefaultCropOriginV = dng_urational (0, 1); 4724 4725 } 4726 4727 // Figure out the requested proxy pixel size. 4728 4729 real64 aspectRatio = AspectRatio (); 4730 4731 dng_point newSize (proxySize, proxySize); 4732 4733 if (aspectRatio >= 1.0) 4734 { 4735 newSize.v = Max_int32 (1, Round_int32 (proxySize / aspectRatio)); 4736 } 4737 else 4738 { 4739 newSize.h = Max_int32 (1, Round_int32 (proxySize * aspectRatio)); 4740 } 4741 4742 newSize.v = Min_int32 (newSize.v, DefaultFinalHeight ()); 4743 newSize.h = Min_int32 (newSize.h, DefaultFinalWidth ()); 4744 4745 if ((uint64) newSize.v * 4746 (uint64) newSize.h > proxyCount) 4747 { 4748 4749 if (aspectRatio >= 1.0) 4750 { 4751 4752 newSize.h = (uint32) sqrt (proxyCount * aspectRatio); 4753 4754 newSize.v = Max_int32 (1, Round_int32 (newSize.h / aspectRatio)); 4755 4756 } 4757 4758 else 4759 { 4760 4761 newSize.v = (uint32) sqrt (proxyCount / aspectRatio); 4762 4763 newSize.h = Max_int32 (1, Round_int32 (newSize.v * aspectRatio)); 4764 4765 } 4766 4767 } 4768 4769 // If this is fewer pixels, downsample the stage 3 image to that size. 4770 4771 dng_point oldSize = defaultCropArea.Size (); 4772 4773 if ((uint64) newSize.v * (uint64) newSize.h < 4774 (uint64) oldSize.v * (uint64) oldSize.h) 4775 { 4776 4777 const dng_image &srcImage (*Stage3Image ()); 4778 4779 AutoPtr<dng_image> dstImage (host.Make_dng_image (newSize, 4780 srcImage.Planes (), 4781 srcImage.PixelType ())); 4782 4783 host.ResampleImage (srcImage, 4784 *dstImage); 4785 4786 fStage3Image.Reset (dstImage.Release ()); 4787 4788 fDefaultCropSizeH = dng_urational (newSize.h, 1); 4789 fDefaultCropSizeV = dng_urational (newSize.v, 1); 4790 4791 fDefaultScaleH = dng_urational (1, 1); 4792 fDefaultScaleV = dng_urational (1, 1); 4793 4794 fBestQualityScale = dng_urational (1, 1); 4795 4796 fRawToFullScaleH = 1.0; 4797 fRawToFullScaleV = 1.0; 4798 4799 } 4800 4801 // Convert 32-bit floating point images to 16-bit floating point to 4802 // save space. 4803 4804 if (Stage3Image ()->PixelType () == ttFloat) 4805 { 4806 4807 fRawImage.Reset (host.Make_dng_image (Stage3Image ()->Bounds (), 4808 Stage3Image ()->Planes (), 4809 ttFloat)); 4810 4811 LimitFloatBitDepth (host, 4812 *Stage3Image (), 4813 *fRawImage, 4814 16, 4815 32768.0f); 4816 4817 SetRawFloatBitDepth (16); 4818 4819 SetWhiteLevel (32768); 4820 4821 } 4822 4823 else 4824 { 4825 4826 // Convert 16-bit deep images to 8-bit deep image for saving. 4827 4828 fRawImage.Reset (EncodeRawProxy (host, 4829 *Stage3Image (), 4830 fOpcodeList2)); 4831 4832 if (fRawImage.Get ()) 4833 { 4834 4835 SetWhiteLevel (255); 4836 4837 // Compute JPEG compressed version. 4838 4839 if (fRawImage->PixelType () == ttByte && 4840 host.SaveDNGVersion () >= dngVersion_1_4_0_0) 4841 { 4842 4843 AutoPtr<dng_jpeg_image> jpegImage (new dng_jpeg_image); 4844 4845 jpegImage->Encode (host, 4846 *this, 4847 writer, 4848 *fRawImage); 4849 4850 SetRawJPEGImage (jpegImage); 4851 4852 } 4853 4854 } 4855 4856 } 4857 4858 // Deal with transparency mask. 4859 4860 if (TransparencyMask ()) 4861 { 4862 4863 const bool convertTo8Bit = true; 4864 4865 ResizeTransparencyToMatchStage3 (host, convertTo8Bit); 4866 4867 fRawTransparencyMask.Reset (fTransparencyMask->Clone ()); 4868 4869 } 4870 4871 // Recompute the raw data unique ID, since we changed the image data. 4872 4873 RecomputeRawDataUniqueID (host); 4874 4875 } 4876 4877 /*****************************************************************************/ 4878 4879 dng_linearization_info * dng_negative::MakeLinearizationInfo () 4880 { 4881 4882 dng_linearization_info *info = new dng_linearization_info (); 4883 4884 if (!info) 4885 { 4886 ThrowMemoryFull (); 4887 } 4888 4889 return info; 4890 4891 } 4892 4893 /*****************************************************************************/ 4894 4895 void dng_negative::NeedLinearizationInfo () 4896 { 4897 4898 if (!fLinearizationInfo.Get ()) 4899 { 4900 4901 fLinearizationInfo.Reset (MakeLinearizationInfo ()); 4902 4903 } 4904 4905 } 4906 4907 /*****************************************************************************/ 4908 4909 dng_mosaic_info * dng_negative::MakeMosaicInfo () 4910 { 4911 4912 dng_mosaic_info *info = new dng_mosaic_info (); 4913 4914 if (!info) 4915 { 4916 ThrowMemoryFull (); 4917 } 4918 4919 return info; 4920 4921 } 4922 4923 /*****************************************************************************/ 4924 4925 void dng_negative::NeedMosaicInfo () 4926 { 4927 4928 if (!fMosaicInfo.Get ()) 4929 { 4930 4931 fMosaicInfo.Reset (MakeMosaicInfo ()); 4932 4933 } 4934 4935 } 4936 4937 /*****************************************************************************/ 4938 4939 void dng_negative::SetTransparencyMask (AutoPtr<dng_image> &image, 4940 uint32 bitDepth) 4941 { 4942 4943 fTransparencyMask.Reset (image.Release ()); 4944 4945 fRawTransparencyMaskBitDepth = bitDepth; 4946 4947 } 4948 4949 /*****************************************************************************/ 4950 4951 const dng_image * dng_negative::TransparencyMask () const 4952 { 4953 4954 return fTransparencyMask.Get (); 4955 4956 } 4957 4958 /*****************************************************************************/ 4959 4960 const dng_image * dng_negative::RawTransparencyMask () const 4961 { 4962 4963 if (fRawTransparencyMask.Get ()) 4964 { 4965 4966 return fRawTransparencyMask.Get (); 4967 4968 } 4969 4970 return TransparencyMask (); 4971 4972 } 4973 4974 /*****************************************************************************/ 4975 4976 uint32 dng_negative::RawTransparencyMaskBitDepth () const 4977 { 4978 4979 if (fRawTransparencyMaskBitDepth) 4980 { 4981 4982 return fRawTransparencyMaskBitDepth; 4983 4984 } 4985 4986 const dng_image *mask = RawTransparencyMask (); 4987 4988 if (mask) 4989 { 4990 4991 switch (mask->PixelType ()) 4992 { 4993 4994 case ttByte: 4995 return 8; 4996 4997 case ttShort: 4998 return 16; 4999 5000 case ttFloat: 5001 return 32; 5002 5003 default: 5004 ThrowProgramError (); 5005 5006 } 5007 5008 } 5009 5010 return 0; 5011 5012 } 5013 5014 /*****************************************************************************/ 5015 5016 void dng_negative::ReadTransparencyMask (dng_host &host, 5017 dng_stream &stream, 5018 dng_info &info) 5019 { 5020 5021 if (info.fMaskIndex != -1) 5022 { 5023 5024 // Allocate image we are reading. 5025 5026 dng_ifd &maskIFD = *info.fIFD [info.fMaskIndex].Get (); 5027 5028 fTransparencyMask.Reset (host.Make_dng_image (maskIFD.Bounds (), 5029 1, 5030 maskIFD.PixelType ())); 5031 5032 // Read the image. 5033 5034 maskIFD.ReadImage (host, 5035 stream, 5036 *fTransparencyMask.Get ()); 5037 5038 // Remember the pixel depth. 5039 5040 fRawTransparencyMaskBitDepth = maskIFD.fBitsPerSample [0]; 5041 5042 } 5043 5044 } 5045 5046 /*****************************************************************************/ 5047 5048 void dng_negative::ResizeTransparencyToMatchStage3 (dng_host &host, 5049 bool convertTo8Bit) 5050 { 5051 5052 if (TransparencyMask ()) 5053 { 5054 5055 if ((TransparencyMask ()->Bounds () != fStage3Image->Bounds ()) || 5056 (TransparencyMask ()->PixelType () != ttByte && convertTo8Bit)) 5057 { 5058 5059 AutoPtr<dng_image> newMask (host.Make_dng_image (fStage3Image->Bounds (), 5060 1, 5061 convertTo8Bit ? 5062 ttByte : 5063 TransparencyMask ()->PixelType ())); 5064 5065 host.ResampleImage (*TransparencyMask (), 5066 *newMask); 5067 5068 fTransparencyMask.Reset (newMask.Release ()); 5069 5070 if (!fRawTransparencyMask.Get ()) 5071 { 5072 fRawTransparencyMaskBitDepth = 0; 5073 } 5074 5075 } 5076 5077 } 5078 5079 } 5080 5081 /*****************************************************************************/ 5082 5083 bool dng_negative::NeedFlattenTransparency (dng_host & /* host */) 5084 { 5085 5086 if (TransparencyMask ()) 5087 { 5088 5089 return true; 5090 5091 } 5092 5093 return false; 5094 5095 } 5096 5097 /*****************************************************************************/ 5098 5099 void dng_negative::FlattenTransparency (dng_host & /* host */) 5100 { 5101 5102 ThrowNotYetImplemented (); 5103 5104 } 5105 5106 /*****************************************************************************/ 5107 5108 const dng_image * dng_negative::UnflattenedStage3Image () const 5109 { 5110 5111 if (fUnflattenedStage3Image.Get ()) 5112 { 5113 5114 return fUnflattenedStage3Image.Get (); 5115 5116 } 5117 5118 return fStage3Image.Get (); 5119 5120 } 5121 5122 /*****************************************************************************/ 5123