File indexing completed on 2025-01-19 03:55:08
0001 /*****************************************************************************/ 0002 // Copyright 2006-2019 Adobe Systems Incorporated 0003 // All Rights Reserved. 0004 // 0005 // NOTICE: Adobe permits you to use, modify, and distribute this file in 0006 // accordance with the terms of the Adobe license agreement accompanying it. 0007 /*****************************************************************************/ 0008 0009 #include "dng_negative.h" 0010 0011 #include "dng_1d_table.h" 0012 #include "dng_abort_sniffer.h" 0013 #include "dng_area_task.h" 0014 #include "dng_assertions.h" 0015 #include "dng_bottlenecks.h" 0016 #include "dng_camera_profile.h" 0017 #include "dng_color_space.h" 0018 #include "dng_color_spec.h" 0019 #include "dng_exceptions.h" 0020 #include "dng_globals.h" 0021 #include "dng_host.h" 0022 #include "dng_image.h" 0023 #include "dng_image_writer.h" 0024 #include "dng_info.h" 0025 #include "dng_jpeg_image.h" 0026 #include "dng_linearization_info.h" 0027 #include "dng_memory.h" 0028 #include "dng_memory_stream.h" 0029 #include "dng_misc_opcodes.h" 0030 #include "dng_mosaic_info.h" 0031 #include "dng_preview.h" 0032 #include "dng_resample.h" 0033 #include "dng_safe_arithmetic.h" 0034 #include "dng_simple_image.h" 0035 #include "dng_tag_codes.h" 0036 #include "dng_tag_values.h" 0037 #include "dng_tile_iterator.h" 0038 #include "dng_uncopyable.h" 0039 #include "dng_utils.h" 0040 #include "dng_xmp.h" 0041 0042 /*****************************************************************************/ 0043 0044 dng_noise_profile::dng_noise_profile () 0045 0046 : fNoiseFunctions () 0047 0048 { 0049 0050 } 0051 0052 /*****************************************************************************/ 0053 0054 dng_noise_profile::dng_noise_profile (const dng_std_vector<dng_noise_function> &functions) 0055 0056 : fNoiseFunctions (functions) 0057 0058 { 0059 0060 } 0061 0062 /*****************************************************************************/ 0063 0064 bool dng_noise_profile::IsValid () const 0065 { 0066 0067 if (NumFunctions () == 0 || NumFunctions () > kMaxColorPlanes) 0068 { 0069 return false; 0070 } 0071 0072 for (uint32 plane = 0; plane < NumFunctions (); plane++) 0073 { 0074 0075 if (!NoiseFunction (plane).IsValid ()) 0076 { 0077 return false; 0078 } 0079 0080 } 0081 0082 return true; 0083 0084 } 0085 0086 /*****************************************************************************/ 0087 0088 bool dng_noise_profile::IsValidForNegative (const dng_negative &negative) const 0089 { 0090 0091 if (!(NumFunctions () == 1 || NumFunctions () == negative.ColorChannels ())) 0092 { 0093 return false; 0094 } 0095 0096 return IsValid (); 0097 0098 } 0099 0100 /*****************************************************************************/ 0101 0102 const dng_noise_function & dng_noise_profile::NoiseFunction (uint32 plane) const 0103 { 0104 0105 if (NumFunctions () == 1) 0106 { 0107 return fNoiseFunctions.front (); 0108 } 0109 0110 DNG_REQUIRE (plane < NumFunctions (), 0111 "Bad plane index argument for NoiseFunction ()."); 0112 0113 return fNoiseFunctions [plane]; 0114 0115 } 0116 0117 /*****************************************************************************/ 0118 0119 uint32 dng_noise_profile::NumFunctions () const 0120 { 0121 return (uint32) fNoiseFunctions.size (); 0122 } 0123 0124 /*****************************************************************************/ 0125 0126 bool dng_noise_profile::operator== (const dng_noise_profile &profile) const 0127 { 0128 0129 if (IsValid ()) 0130 { 0131 0132 if (!profile.IsValid ()) 0133 { 0134 return false; 0135 } 0136 0137 if (NumFunctions () != profile.NumFunctions ()) 0138 { 0139 return false; 0140 } 0141 0142 for (uint32 plane = 0; plane < NumFunctions (); plane++) 0143 { 0144 0145 if (NoiseFunction (plane).Scale () != profile.NoiseFunction (plane).Scale () || 0146 NoiseFunction (plane).Offset () != profile.NoiseFunction (plane).Offset ()) 0147 { 0148 return false; 0149 } 0150 0151 } 0152 0153 return true; 0154 0155 } 0156 0157 else 0158 return !profile.IsValid (); 0159 0160 } 0161 0162 /*****************************************************************************/ 0163 0164 dng_metadata::dng_metadata (dng_host &host) 0165 0166 : fHasBaseOrientation (false) 0167 , fBaseOrientation () 0168 , fIsMakerNoteSafe (false) 0169 , fMakerNote () 0170 , fExif (host.Make_dng_exif ()) 0171 , fOriginalExif () 0172 , fIPTCBlock () 0173 , fIPTCOffset (kDNGStreamInvalidOffset) 0174 , fXMP (host.Make_dng_xmp ()) 0175 , fEmbeddedXMPDigest () 0176 , fXMPinSidecar (false) 0177 , fXMPisNewer (false) 0178 , fSourceMIME () 0179 0180 { 0181 } 0182 0183 /*****************************************************************************/ 0184 0185 dng_metadata::~dng_metadata () 0186 { 0187 } 0188 0189 /******************************************************************************/ 0190 0191 template< class T > 0192 T * CloneAutoPtr (const AutoPtr< T > &ptr) 0193 { 0194 0195 return ptr.Get () ? ptr->Clone () : NULL; 0196 0197 } 0198 0199 /******************************************************************************/ 0200 0201 template< class T, typename U > 0202 T * CloneAutoPtr (const AutoPtr< T > &ptr, U &u) 0203 { 0204 0205 return ptr.Get () ? ptr->Clone (u) : NULL; 0206 0207 } 0208 0209 /******************************************************************************/ 0210 0211 dng_metadata::dng_metadata (const dng_metadata &rhs, 0212 dng_memory_allocator &allocator) 0213 0214 : fHasBaseOrientation (rhs.fHasBaseOrientation) 0215 , fBaseOrientation (rhs.fBaseOrientation) 0216 , fIsMakerNoteSafe (rhs.fIsMakerNoteSafe) 0217 , fMakerNote (CloneAutoPtr (rhs.fMakerNote, allocator)) 0218 , fExif (CloneAutoPtr (rhs.fExif)) 0219 , fOriginalExif (CloneAutoPtr (rhs.fOriginalExif)) 0220 , fIPTCBlock (CloneAutoPtr (rhs.fIPTCBlock, allocator)) 0221 , fIPTCOffset (rhs.fIPTCOffset) 0222 , fXMP (CloneAutoPtr (rhs.fXMP)) 0223 , fEmbeddedXMPDigest (rhs.fEmbeddedXMPDigest) 0224 , fXMPinSidecar (rhs.fXMPinSidecar) 0225 , fXMPisNewer (rhs.fXMPisNewer) 0226 , fSourceMIME (rhs.fSourceMIME) 0227 0228 { 0229 0230 } 0231 0232 /******************************************************************************/ 0233 0234 dng_metadata * dng_metadata::Clone (dng_memory_allocator &allocator) const 0235 { 0236 0237 return new dng_metadata (*this, allocator); 0238 0239 } 0240 0241 /******************************************************************************/ 0242 0243 void dng_metadata::SetBaseOrientation (const dng_orientation &orientation) 0244 { 0245 0246 fHasBaseOrientation = true; 0247 0248 fBaseOrientation = orientation; 0249 0250 } 0251 0252 /******************************************************************************/ 0253 0254 void dng_metadata::ApplyOrientation (const dng_orientation &orientation) 0255 { 0256 0257 fBaseOrientation += orientation; 0258 0259 fXMP->SetOrientation (fBaseOrientation); 0260 0261 } 0262 0263 /*****************************************************************************/ 0264 0265 void dng_metadata::ResetExif (dng_exif * newExif) 0266 { 0267 0268 fExif.Reset (newExif); 0269 0270 } 0271 0272 /******************************************************************************/ 0273 0274 dng_memory_block * dng_metadata::BuildExifBlock (dng_memory_allocator &allocator, 0275 const dng_resolution *resolution, 0276 bool includeIPTC, 0277 const dng_jpeg_preview *thumbnail) const 0278 { 0279 0280 dng_memory_stream stream (allocator); 0281 0282 { 0283 0284 // Create the main IFD 0285 0286 dng_tiff_directory mainIFD; 0287 0288 // Optionally include the resolution tags. 0289 0290 dng_resolution res; 0291 0292 if (resolution) 0293 { 0294 res = *resolution; 0295 } 0296 0297 tag_urational tagXResolution (tcXResolution, res.fXResolution); 0298 tag_urational tagYResolution (tcYResolution, res.fYResolution); 0299 0300 tag_uint16 tagResolutionUnit (tcResolutionUnit, res.fResolutionUnit); 0301 0302 if (resolution) 0303 { 0304 mainIFD.Add (&tagXResolution ); 0305 mainIFD.Add (&tagYResolution ); 0306 mainIFD.Add (&tagResolutionUnit); 0307 } 0308 0309 // Optionally include IPTC block. 0310 0311 tag_iptc tagIPTC (IPTCData (), 0312 IPTCLength ()); 0313 0314 if (includeIPTC && tagIPTC.Count ()) 0315 { 0316 mainIFD.Add (&tagIPTC); 0317 } 0318 0319 // Exif tags. 0320 0321 exif_tag_set exifSet (mainIFD, 0322 *GetExif (), 0323 IsMakerNoteSafe (), 0324 MakerNoteData (), 0325 MakerNoteLength (), 0326 false); 0327 0328 // Figure out the Exif IFD offset. 0329 0330 uint32 exifOffset = 8 + mainIFD.Size (); 0331 0332 exifSet.Locate (exifOffset); 0333 0334 // Thumbnail IFD (if any). 0335 0336 dng_tiff_directory thumbIFD; 0337 0338 tag_uint16 thumbCompression (tcCompression, ccOldJPEG); 0339 0340 tag_urational thumbXResolution (tcXResolution, dng_urational (72, 1)); 0341 tag_urational thumbYResolution (tcYResolution, dng_urational (72, 1)); 0342 0343 tag_uint16 thumbResolutionUnit (tcResolutionUnit, ruInch); 0344 0345 tag_uint32 thumbDataOffset (tcJPEGInterchangeFormat , 0); 0346 tag_uint32 thumbDataLength (tcJPEGInterchangeFormatLength, 0); 0347 0348 if (thumbnail) 0349 { 0350 0351 thumbIFD.Add (&thumbCompression); 0352 0353 thumbIFD.Add (&thumbXResolution); 0354 thumbIFD.Add (&thumbYResolution); 0355 thumbIFD.Add (&thumbResolutionUnit); 0356 0357 thumbIFD.Add (&thumbDataOffset); 0358 thumbIFD.Add (&thumbDataLength); 0359 0360 thumbDataLength.Set (thumbnail->fCompressedData->LogicalSize ()); 0361 0362 uint32 thumbOffset = exifOffset + exifSet.Size (); 0363 0364 mainIFD.SetChained (thumbOffset); 0365 0366 thumbDataOffset.Set (thumbOffset + thumbIFD.Size ()); 0367 0368 } 0369 0370 // Don't write anything unless the main IFD has some tags. 0371 0372 if (mainIFD.Size () != 0) 0373 { 0374 0375 // Write TIFF Header. 0376 0377 stream.SetWritePosition (0); 0378 0379 stream.Put_uint16 (stream.BigEndian () ? byteOrderMM : byteOrderII); 0380 0381 stream.Put_uint16 (42); 0382 0383 stream.Put_uint32 (8); 0384 0385 // Write the IFDs. 0386 0387 mainIFD.Put (stream); 0388 0389 exifSet.Put (stream); 0390 0391 if (thumbnail) 0392 { 0393 0394 thumbIFD.Put (stream); 0395 0396 stream.Put (thumbnail->fCompressedData->Buffer (), 0397 thumbnail->fCompressedData->LogicalSize ()); 0398 0399 } 0400 0401 // Trim the file to this length. 0402 0403 stream.Flush (); 0404 0405 stream.SetLength (stream.Position ()); 0406 0407 } 0408 0409 } 0410 0411 return stream.AsMemoryBlock (allocator); 0412 0413 } 0414 0415 /******************************************************************************/ 0416 0417 void dng_metadata::SetIPTC (AutoPtr<dng_memory_block> &block, uint64 offset) 0418 { 0419 0420 fIPTCBlock.Reset (block.Release ()); 0421 0422 fIPTCOffset = offset; 0423 0424 } 0425 0426 /******************************************************************************/ 0427 0428 void dng_metadata::SetIPTC (AutoPtr<dng_memory_block> &block) 0429 { 0430 0431 SetIPTC (block, kDNGStreamInvalidOffset); 0432 0433 } 0434 0435 /******************************************************************************/ 0436 0437 void dng_metadata::ClearIPTC () 0438 { 0439 0440 fIPTCBlock.Reset (); 0441 0442 fIPTCOffset = kDNGStreamInvalidOffset; 0443 0444 } 0445 0446 /*****************************************************************************/ 0447 0448 const void * dng_metadata::IPTCData () const 0449 { 0450 0451 if (fIPTCBlock.Get ()) 0452 { 0453 0454 return fIPTCBlock->Buffer (); 0455 0456 } 0457 0458 return NULL; 0459 0460 } 0461 0462 /*****************************************************************************/ 0463 0464 uint32 dng_metadata::IPTCLength () const 0465 { 0466 0467 if (fIPTCBlock.Get ()) 0468 { 0469 0470 return fIPTCBlock->LogicalSize (); 0471 0472 } 0473 0474 return 0; 0475 0476 } 0477 0478 /*****************************************************************************/ 0479 0480 uint64 dng_metadata::IPTCOffset () const 0481 { 0482 0483 if (fIPTCBlock.Get ()) 0484 { 0485 0486 return fIPTCOffset; 0487 0488 } 0489 0490 return kDNGStreamInvalidOffset; 0491 0492 } 0493 0494 /*****************************************************************************/ 0495 0496 dng_fingerprint dng_metadata::IPTCDigest (bool includePadding) const 0497 { 0498 0499 if (IPTCLength ()) 0500 { 0501 0502 dng_md5_printer printer; 0503 0504 const uint8 *data = (const uint8 *) IPTCData (); 0505 0506 uint32 count = IPTCLength (); 0507 0508 // Because of some stupid ways of storing the IPTC data, the IPTC 0509 // data might be padded with up to three zeros. The official Adobe 0510 // logic is to include these zeros in the digest. However, older 0511 // versions of the Camera Raw code did not include the padding zeros 0512 // in the digest, so we support both methods and allow either to 0513 // match. 0514 0515 if (!includePadding) 0516 { 0517 0518 uint32 removed = 0; 0519 0520 while ((removed < 3) && (count > 0) && (data [count - 1] == 0)) 0521 { 0522 removed++; 0523 count--; 0524 } 0525 0526 } 0527 0528 printer.Process (data, count); 0529 0530 return printer.Result (); 0531 0532 } 0533 0534 return dng_fingerprint (); 0535 0536 } 0537 0538 /******************************************************************************/ 0539 0540 void dng_metadata::RebuildIPTC (dng_memory_allocator &allocator, 0541 bool padForTIFF) 0542 { 0543 0544 ClearIPTC (); 0545 0546 fXMP->RebuildIPTC (*this, allocator, padForTIFF); 0547 0548 dng_fingerprint digest = IPTCDigest (); 0549 0550 fXMP->SetIPTCDigest (digest); 0551 0552 } 0553 0554 /*****************************************************************************/ 0555 0556 void dng_metadata::ResetXMP (dng_xmp * newXMP) 0557 { 0558 0559 fXMP.Reset (newXMP); 0560 0561 } 0562 0563 /*****************************************************************************/ 0564 0565 void dng_metadata::ResetXMPSidecarNewer (dng_xmp * newXMP, 0566 bool inSidecar, 0567 bool isNewer ) 0568 { 0569 0570 fXMP.Reset (newXMP); 0571 0572 fXMPinSidecar = inSidecar; 0573 0574 fXMPisNewer = isNewer; 0575 0576 } 0577 0578 /*****************************************************************************/ 0579 0580 bool dng_metadata::SetXMP (dng_host &host, 0581 const void *buffer, 0582 uint32 count, 0583 bool xmpInSidecar, 0584 bool xmpIsNewer) 0585 { 0586 0587 bool result = false; 0588 0589 try 0590 { 0591 0592 AutoPtr<dng_xmp> tempXMP (host.Make_dng_xmp ()); 0593 0594 tempXMP->Parse (host, buffer, count); 0595 0596 ResetXMPSidecarNewer (tempXMP.Release (), xmpInSidecar, xmpIsNewer); 0597 0598 result = true; 0599 0600 } 0601 0602 catch (dng_exception &except) 0603 { 0604 0605 // Don't ignore transient errors. 0606 0607 if (host.IsTransientError (except.ErrorCode ())) 0608 { 0609 0610 throw; 0611 0612 } 0613 0614 // Eat other parsing errors. 0615 0616 } 0617 0618 catch (...) 0619 { 0620 0621 // Eat unknown parsing exceptions. 0622 0623 } 0624 0625 return result; 0626 0627 } 0628 0629 /*****************************************************************************/ 0630 0631 void dng_metadata::SetEmbeddedXMP (dng_host &host, 0632 const void *buffer, 0633 uint32 count) 0634 { 0635 0636 if (SetXMP (host, buffer, count)) 0637 { 0638 0639 dng_md5_printer printer; 0640 0641 printer.Process (buffer, count); 0642 0643 fEmbeddedXMPDigest = printer.Result (); 0644 0645 // Remove any sidecar specific tags from embedded XMP. 0646 0647 if (fXMP.Get ()) 0648 { 0649 0650 fXMP->Remove (XMP_NS_PHOTOSHOP, "SidecarForExtension"); 0651 fXMP->Remove (XMP_NS_PHOTOSHOP, "EmbeddedXMPDigest"); 0652 0653 } 0654 0655 } 0656 0657 else 0658 { 0659 0660 fEmbeddedXMPDigest.Clear (); 0661 0662 } 0663 0664 } 0665 0666 /*****************************************************************************/ 0667 0668 void dng_metadata::SynchronizeMetadata () 0669 { 0670 0671 DNG_REQUIRE (fExif.Get (), 0672 "Expected valid fExif field in " 0673 "dng_metadata::SynchronizeMetadata"); 0674 0675 if (!fOriginalExif.Get ()) 0676 { 0677 0678 fOriginalExif.Reset (fExif->Clone ()); 0679 0680 } 0681 0682 fXMP->ValidateMetadata (); 0683 0684 fXMP->IngestIPTC (*this, fXMPisNewer); 0685 0686 fXMP->SyncExif (*fExif.Get ()); 0687 0688 fXMP->SyncOrientation (*this, fXMPinSidecar); 0689 0690 } 0691 0692 /*****************************************************************************/ 0693 0694 void dng_metadata::UpdateDateTime (const dng_date_time_info &dt) 0695 { 0696 0697 fExif->UpdateDateTime (dt); 0698 0699 fXMP->UpdateDateTime (dt); 0700 0701 } 0702 0703 /*****************************************************************************/ 0704 0705 void dng_metadata::UpdateDateTimeToNow () 0706 { 0707 0708 dng_date_time_info dt; 0709 0710 CurrentDateTimeAndZone (dt); 0711 0712 UpdateDateTime (dt); 0713 0714 fXMP->UpdateMetadataDate (dt); 0715 0716 } 0717 0718 /*****************************************************************************/ 0719 0720 void dng_metadata::UpdateMetadataDateTimeToNow () 0721 { 0722 0723 dng_date_time_info dt; 0724 0725 CurrentDateTimeAndZone (dt); 0726 0727 fXMP->UpdateMetadataDate (dt); 0728 0729 } 0730 0731 /*****************************************************************************/ 0732 0733 dng_negative::dng_negative (dng_host &host) 0734 0735 : fAllocator (host.Allocator ()) 0736 0737 , fModelName () 0738 , fLocalName () 0739 , fDefaultCropSizeH () 0740 , fDefaultCropSizeV () 0741 , fDefaultCropOriginH (0, 1) 0742 , fDefaultCropOriginV (0, 1) 0743 , fDefaultUserCropT (0, 1) 0744 , fDefaultUserCropL (0, 1) 0745 , fDefaultUserCropB (1, 1) 0746 , fDefaultUserCropR (1, 1) 0747 , fDefaultScaleH (1, 1) 0748 , fDefaultScaleV (1, 1) 0749 , fBestQualityScale (1, 1) 0750 , fOriginalDefaultFinalSize () 0751 , fOriginalBestQualityFinalSize () 0752 , fOriginalDefaultCropSizeH () 0753 , fOriginalDefaultCropSizeV () 0754 , fRawToFullScaleH (1.0) 0755 , fRawToFullScaleV (1.0) 0756 , fBaselineNoise (100, 100) 0757 , fNoiseReductionApplied (0, 0) 0758 , fRawNoiseReductionApplied (0, 0) 0759 , fNoiseProfile () 0760 , fRawNoiseProfile () 0761 , fBaselineExposure ( 0, 100) 0762 , fBaselineSharpness (100, 100) 0763 , fRawBaselineSharpness (0, 0) 0764 , fChromaBlurRadius () 0765 , fAntiAliasStrength (100, 100) 0766 , fLinearResponseLimit (100, 100) 0767 , fShadowScale (1, 1) 0768 , fColorimetricReference (crSceneReferred) 0769 , fFloatingPoint (false) 0770 , fColorChannels (0) 0771 , fAnalogBalance () 0772 , fCameraNeutral () 0773 , fCameraWhiteXY () 0774 , fCameraCalibration1 () 0775 , fCameraCalibration2 () 0776 , fCameraCalibrationSignature () 0777 , fCameraProfile () 0778 , fAsShotProfileName () 0779 , fRawImageDigest () 0780 , fNewRawImageDigest () 0781 , fRawDataUniqueID () 0782 , fOriginalRawFileName () 0783 , fHasOriginalRawFileData (false) 0784 , fOriginalRawFileData () 0785 , fOriginalRawFileDigest () 0786 , fDNGPrivateData () 0787 , fMetadata (host) 0788 , fLinearizationInfo () 0789 , fMosaicInfo () 0790 , fOpcodeList1 (1) 0791 , fOpcodeList2 (2) 0792 , fOpcodeList3 (3) 0793 , fStage1Image () 0794 , fStage2Image () 0795 , fStage3Image () 0796 , fStage3Gain (1.0) 0797 , fStage3BlackLevel (0) 0798 , fIsPreview (false) 0799 , fIsDamaged (false) 0800 , fRawImageStage (rawImageStageNone) 0801 , fRawImage () 0802 , fRawImageBlackLevel (0) 0803 , fRawFloatBitDepth (0) 0804 , fRawJPEGImage () 0805 , fRawJPEGImageDigest () 0806 , fTransparencyMask () 0807 , fRawTransparencyMask () 0808 , fRawTransparencyMaskBitDepth (0) 0809 , fUnflattenedStage3Image () 0810 , fHasDepthMap (false) 0811 , fDepthMap () 0812 , fRawDepthMap () 0813 , fDepthFormat (depthFormatUnknown) 0814 , fDepthNear (0, 0) 0815 , fDepthFar (0, 0) 0816 , fDepthUnits (depthUnitsUnknown) 0817 , fDepthMeasureType (depthMeasureUnknown) 0818 , fEnhanceParams () 0819 0820 { 0821 0822 } 0823 0824 /*****************************************************************************/ 0825 0826 dng_negative::~dng_negative () 0827 { 0828 0829 // Delete any camera profiles owned by this negative. 0830 0831 ClearProfiles (); 0832 0833 } 0834 0835 /******************************************************************************/ 0836 0837 void dng_negative::Initialize () 0838 { 0839 0840 } 0841 0842 /******************************************************************************/ 0843 0844 dng_negative * dng_negative::Make (dng_host &host) 0845 { 0846 0847 AutoPtr<dng_negative> result (new dng_negative (host)); 0848 0849 if (!result.Get ()) 0850 { 0851 ThrowMemoryFull (); 0852 } 0853 0854 result->Initialize (); 0855 0856 return result.Release (); 0857 0858 } 0859 0860 /******************************************************************************/ 0861 0862 dng_metadata * dng_negative::CloneInternalMetadata () const 0863 { 0864 0865 return InternalMetadata ().Clone (Allocator ()); 0866 0867 } 0868 0869 /******************************************************************************/ 0870 0871 dng_orientation dng_negative::ComputeOrientation (const dng_metadata &metadata) const 0872 { 0873 0874 return metadata.BaseOrientation (); 0875 0876 } 0877 0878 /******************************************************************************/ 0879 0880 void dng_negative::SetAnalogBalance (const dng_vector &b) 0881 { 0882 0883 real64 minEntry = b.MinEntry (); 0884 0885 if (b.NotEmpty () && minEntry > 0.0) 0886 { 0887 0888 fAnalogBalance = b; 0889 0890 fAnalogBalance.Scale (1.0 / minEntry); 0891 0892 fAnalogBalance.Round (1000000.0); 0893 0894 } 0895 0896 else 0897 { 0898 0899 fAnalogBalance.Clear (); 0900 0901 } 0902 0903 } 0904 0905 /*****************************************************************************/ 0906 0907 real64 dng_negative::AnalogBalance (uint32 channel) const 0908 { 0909 0910 DNG_ASSERT (channel < ColorChannels (), "Channel out of bounds"); 0911 0912 if (channel < fAnalogBalance.Count ()) 0913 { 0914 0915 return fAnalogBalance [channel]; 0916 0917 } 0918 0919 return 1.0; 0920 0921 } 0922 0923 /*****************************************************************************/ 0924 0925 dng_urational dng_negative::AnalogBalanceR (uint32 channel) const 0926 { 0927 0928 dng_urational result; 0929 0930 result.Set_real64 (AnalogBalance (channel), 1000000); 0931 0932 return result; 0933 0934 } 0935 0936 /******************************************************************************/ 0937 0938 void dng_negative::SetCameraNeutral (const dng_vector &n) 0939 { 0940 0941 real64 maxEntry = n.MaxEntry (); 0942 0943 if (n.NotEmpty () && maxEntry > 0.0) 0944 { 0945 0946 fCameraNeutral = n; 0947 0948 fCameraNeutral.Scale (1.0 / maxEntry); 0949 0950 fCameraNeutral.Round (1000000.0); 0951 0952 } 0953 0954 else 0955 { 0956 0957 fCameraNeutral.Clear (); 0958 0959 } 0960 0961 } 0962 0963 /*****************************************************************************/ 0964 0965 dng_urational dng_negative::CameraNeutralR (uint32 channel) const 0966 { 0967 0968 dng_urational result; 0969 0970 result.Set_real64 (CameraNeutral () [channel], 1000000); 0971 0972 return result; 0973 0974 } 0975 0976 /******************************************************************************/ 0977 0978 void dng_negative::SetCameraWhiteXY (const dng_xy_coord &coord) 0979 { 0980 0981 if (coord.IsValid ()) 0982 { 0983 0984 fCameraWhiteXY.x = Round_int32 (coord.x * 1000000.0) / 1000000.0; 0985 fCameraWhiteXY.y = Round_int32 (coord.y * 1000000.0) / 1000000.0; 0986 0987 } 0988 0989 else 0990 { 0991 0992 fCameraWhiteXY.Clear (); 0993 0994 } 0995 0996 } 0997 0998 /*****************************************************************************/ 0999 1000 const dng_xy_coord & dng_negative::CameraWhiteXY () const 1001 { 1002 1003 DNG_ASSERT (HasCameraWhiteXY (), "Using undefined CameraWhiteXY"); 1004 1005 return fCameraWhiteXY; 1006 1007 } 1008 1009 /*****************************************************************************/ 1010 1011 void dng_negative::GetCameraWhiteXY (dng_urational &x, 1012 dng_urational &y) const 1013 { 1014 1015 dng_xy_coord coord = CameraWhiteXY (); 1016 1017 x.Set_real64 (coord.x, 1000000); 1018 y.Set_real64 (coord.y, 1000000); 1019 1020 } 1021 1022 /*****************************************************************************/ 1023 1024 void dng_negative::SetCameraCalibration1 (const dng_matrix &m) 1025 { 1026 1027 fCameraCalibration1 = m; 1028 1029 fCameraCalibration1.Round (10000); 1030 1031 } 1032 1033 /******************************************************************************/ 1034 1035 void dng_negative::SetCameraCalibration2 (const dng_matrix &m) 1036 { 1037 1038 fCameraCalibration2 = m; 1039 1040 fCameraCalibration2.Round (10000); 1041 1042 } 1043 1044 /******************************************************************************/ 1045 1046 void dng_negative::AddProfile (AutoPtr<dng_camera_profile> &profile) 1047 { 1048 1049 // Make sure we have a profile to add. 1050 1051 if (!profile.Get ()) 1052 { 1053 1054 return; 1055 1056 } 1057 1058 // We must have some profile name. Use "embedded" if nothing else. 1059 1060 if (profile->Name ().IsEmpty ()) 1061 { 1062 1063 profile->SetName (kProfileName_Embedded); 1064 1065 } 1066 1067 // Special case support for reading older DNG files which did not store 1068 // the profile name in the main IFD profile. 1069 1070 if (fCameraProfile.size ()) 1071 { 1072 1073 // See the first profile has a default "embedded" name, and has 1074 // the same data as the profile we are adding. 1075 1076 if (fCameraProfile [0]->NameIsEmbedded () && 1077 fCameraProfile [0]->EqualData (*profile.Get ())) 1078 { 1079 1080 // If the profile we are deleting was read from DNG 1081 // then the new profile should be marked as such also. 1082 1083 if (fCameraProfile [0]->WasReadFromDNG ()) 1084 { 1085 1086 profile->SetWasReadFromDNG (); 1087 1088 } 1089 1090 // If the profile we are deleting wasn't read from disk then the new 1091 // profile should be marked as such also. 1092 1093 if (!fCameraProfile [0]->WasReadFromDisk ()) 1094 { 1095 1096 profile->SetWasReadFromDisk (false); 1097 1098 } 1099 1100 // Delete the profile with default name. 1101 1102 delete fCameraProfile [0]; 1103 1104 fCameraProfile [0] = NULL; 1105 1106 fCameraProfile.erase (fCameraProfile.begin ()); 1107 1108 } 1109 1110 } 1111 1112 // Duplicate detection logic. We give a preference to last added profile 1113 // so the profiles end up in a more consistent order no matter what profiles 1114 // happen to be embedded in the DNG. 1115 1116 for (uint32 index = 0; index < (uint32) fCameraProfile.size (); index++) 1117 { 1118 1119 // Instead of checking for matching fingerprints, we check that the two 1120 // profiles have the same color and have the same name. This allows two 1121 // profiles that are identical except for copyright string and embed policy 1122 // to be considered duplicates. 1123 1124 const bool equalColorAndSameName = (fCameraProfile [index]->EqualData (*profile.Get ()) && 1125 fCameraProfile [index]->Name () == profile->Name ()); 1126 1127 if (equalColorAndSameName) 1128 { 1129 1130 // If the profile we are deleting was read from DNG 1131 // then the new profile should be marked as such also. 1132 1133 if (fCameraProfile [index]->WasReadFromDNG ()) 1134 { 1135 1136 profile->SetWasReadFromDNG (); 1137 1138 } 1139 1140 // If the profile we are deleting wasn't read from disk then the new 1141 // profile should be marked as such also. 1142 1143 if (!fCameraProfile [index]->WasReadFromDisk ()) 1144 { 1145 1146 profile->SetWasReadFromDisk (false); 1147 1148 } 1149 1150 // Delete the duplicate profile. 1151 1152 delete fCameraProfile [index]; 1153 1154 fCameraProfile [index] = NULL; 1155 1156 fCameraProfile.erase (fCameraProfile.begin () + index); 1157 1158 break; 1159 1160 } 1161 1162 } 1163 1164 // Now add to profile list. 1165 1166 fCameraProfile.push_back (NULL); 1167 1168 fCameraProfile [fCameraProfile.size () - 1] = profile.Release (); 1169 1170 } 1171 1172 /******************************************************************************/ 1173 1174 void dng_negative::ClearProfiles () 1175 { 1176 1177 // Delete any camera profiles owned by this negative. 1178 1179 for (uint32 index = 0; index < (uint32) fCameraProfile.size (); index++) 1180 { 1181 1182 if (fCameraProfile [index]) 1183 { 1184 1185 delete fCameraProfile [index]; 1186 1187 fCameraProfile [index] = NULL; 1188 1189 } 1190 1191 } 1192 1193 // Now empty list. 1194 1195 fCameraProfile.clear (); 1196 1197 } 1198 1199 /*****************************************************************************/ 1200 1201 void dng_negative::ClearProfiles (bool clearBuiltinMatrixProfiles, 1202 bool clearReadFromDisk) 1203 { 1204 1205 // If neither flag is set, then there's nothing to do. 1206 1207 if (!clearBuiltinMatrixProfiles && 1208 !clearReadFromDisk) 1209 { 1210 return; 1211 } 1212 1213 // Delete any camera profiles in this negative that match the specified criteria. 1214 1215 dng_std_vector<dng_camera_profile *>::iterator iter = fCameraProfile.begin (); 1216 dng_std_vector<dng_camera_profile *>::iterator next; 1217 1218 for (; iter != fCameraProfile.end (); iter = next) 1219 { 1220 1221 dng_camera_profile *profile = *iter; 1222 1223 // If the profile is invalid (i.e., NULL pointer), or meets one of the 1224 // specified criteria, then axe it. 1225 1226 if (!profile || 1227 (clearBuiltinMatrixProfiles && profile->WasBuiltinMatrix ()) || 1228 (clearReadFromDisk && profile->WasReadFromDisk ())) 1229 { 1230 1231 delete profile; 1232 1233 next = fCameraProfile.erase (iter); 1234 1235 } 1236 1237 // Otherwise, just advance to the next element. 1238 1239 else 1240 { 1241 1242 next = iter + 1; 1243 1244 } 1245 1246 } 1247 1248 } 1249 1250 /******************************************************************************/ 1251 1252 uint32 dng_negative::ProfileCount () const 1253 { 1254 1255 return (uint32) fCameraProfile.size (); 1256 1257 } 1258 1259 /******************************************************************************/ 1260 1261 const dng_camera_profile & dng_negative::ProfileByIndex (uint32 index) const 1262 { 1263 1264 DNG_ASSERT (index < ProfileCount (), 1265 "Invalid index for ProfileByIndex"); 1266 1267 return *fCameraProfile [index]; 1268 1269 } 1270 1271 /*****************************************************************************/ 1272 1273 const dng_camera_profile * dng_negative::ProfileByID (const dng_camera_profile_id &id, 1274 bool useDefaultIfNoMatch) const 1275 { 1276 1277 uint32 index; 1278 1279 // If this negative does not have any profiles, we are not going to 1280 // find a match. 1281 1282 uint32 profileCount = ProfileCount (); 1283 1284 if (profileCount == 0) 1285 { 1286 return NULL; 1287 } 1288 1289 // If we have both a profile name and fingerprint, try matching both. 1290 1291 if (id.Name ().NotEmpty () && id.Fingerprint ().IsValid ()) 1292 { 1293 1294 for (index = 0; index < profileCount; index++) 1295 { 1296 1297 const dng_camera_profile &profile = ProfileByIndex (index); 1298 1299 if (id.Name () == profile.Name () && 1300 id.Fingerprint () == profile.Fingerprint ()) 1301 { 1302 1303 return &profile; 1304 1305 } 1306 1307 } 1308 1309 } 1310 1311 // If we have a name, try matching that. 1312 1313 if (id.Name ().NotEmpty ()) 1314 { 1315 1316 for (index = 0; index < profileCount; index++) 1317 { 1318 1319 const dng_camera_profile &profile = ProfileByIndex (index); 1320 1321 if (id.Name () == profile.Name ()) 1322 { 1323 1324 return &profile; 1325 1326 } 1327 1328 } 1329 1330 } 1331 1332 // If we have a valid fingerprint, try matching that. 1333 1334 if (id.Fingerprint ().IsValid ()) 1335 { 1336 1337 for (index = 0; index < profileCount; index++) 1338 { 1339 1340 const dng_camera_profile &profile = ProfileByIndex (index); 1341 1342 if (id.Fingerprint () == profile.Fingerprint ()) 1343 { 1344 1345 return &profile; 1346 1347 } 1348 1349 } 1350 1351 } 1352 1353 // Try "upgrading" profile name versions. 1354 1355 if (id.Name ().NotEmpty ()) 1356 { 1357 1358 dng_string baseName; 1359 int32 version; 1360 1361 SplitCameraProfileName (id.Name (), 1362 baseName, 1363 version); 1364 1365 int32 bestIndex = -1; 1366 int32 bestVersion = 0; 1367 1368 for (index = 0; index < profileCount; index++) 1369 { 1370 1371 const dng_camera_profile &profile = ProfileByIndex (index); 1372 1373 if (profile.Name ().StartsWith (baseName.Get ())) 1374 { 1375 1376 dng_string testBaseName; 1377 int32 testVersion; 1378 1379 SplitCameraProfileName (profile.Name (), 1380 testBaseName, 1381 testVersion); 1382 1383 if (bestIndex == -1 || testVersion > bestVersion) 1384 { 1385 1386 bestIndex = index; 1387 bestVersion = testVersion; 1388 1389 } 1390 1391 } 1392 1393 } 1394 1395 if (bestIndex != -1) 1396 { 1397 1398 return &ProfileByIndex (bestIndex); 1399 1400 } 1401 1402 } 1403 1404 // Did not find a match any way. See if we should return a default value. 1405 1406 if (useDefaultIfNoMatch) 1407 { 1408 1409 return &ProfileByIndex (0); 1410 1411 } 1412 1413 // Found nothing. 1414 1415 return NULL; 1416 1417 } 1418 1419 /*****************************************************************************/ 1420 1421 const dng_camera_profile * dng_negative::ComputeCameraProfileToEmbed 1422 (const dng_metadata & /* metadata */) const 1423 { 1424 1425 uint32 index; 1426 1427 uint32 count = ProfileCount (); 1428 1429 if (count == 0) 1430 { 1431 1432 return NULL; 1433 1434 } 1435 1436 // First try to look for the first profile that was already in the DNG 1437 // when we read it. 1438 1439 for (index = 0; index < count; index++) 1440 { 1441 1442 const dng_camera_profile &profile (ProfileByIndex (index)); 1443 1444 if (profile.WasReadFromDNG ()) 1445 { 1446 1447 return &profile; 1448 1449 } 1450 1451 } 1452 1453 // Next we look for the first profile that is legal to embed. 1454 1455 for (index = 0; index < count; index++) 1456 { 1457 1458 const dng_camera_profile &profile (ProfileByIndex (index)); 1459 1460 if (profile.IsLegalToEmbed ()) 1461 { 1462 1463 return &profile; 1464 1465 } 1466 1467 } 1468 1469 // Else just return the first profile. 1470 1471 return fCameraProfile [0]; 1472 1473 } 1474 1475 /*****************************************************************************/ 1476 1477 dng_color_spec * dng_negative::MakeColorSpec (const dng_camera_profile_id &id) const 1478 { 1479 1480 dng_color_spec *spec = new dng_color_spec (*this, ProfileByID (id)); 1481 1482 if (!spec) 1483 { 1484 ThrowMemoryFull (); 1485 } 1486 1487 return spec; 1488 1489 } 1490 1491 /*****************************************************************************/ 1492 1493 dng_fingerprint dng_negative::FindImageDigest (dng_host &host, 1494 const dng_image &image) 1495 { 1496 1497 dng_md5_printer printer; 1498 1499 dng_pixel_buffer buffer (image.Bounds (), 1500 0, 1501 image.Planes (), 1502 image.PixelType (), 1503 pcInterleaved, 1504 NULL); 1505 1506 // Sometimes we expand 8-bit data to 16-bit data while reading or 1507 // writing, so always compute the digest of 8-bit data as 16-bits. 1508 1509 if (buffer.fPixelType == ttByte) 1510 { 1511 buffer.fPixelType = ttShort; 1512 buffer.fPixelSize = 2; 1513 } 1514 1515 const uint32 kBufferRows = 16; 1516 1517 uint32 bufferBytes = 0; 1518 1519 if (!SafeUint32Mult (kBufferRows, buffer.fRowStep, &bufferBytes) || 1520 !SafeUint32Mult (bufferBytes, buffer.fPixelSize, &bufferBytes)) 1521 { 1522 1523 ThrowOverflow ("Arithmetic overflow computing buffer size."); 1524 1525 } 1526 1527 AutoPtr<dng_memory_block> bufferData (host.Allocate (bufferBytes)); 1528 1529 buffer.fData = bufferData->Buffer (); 1530 1531 dng_rect area; 1532 1533 dng_tile_iterator iter (dng_point (kBufferRows, 1534 image.Width ()), 1535 image.Bounds ()); 1536 1537 while (iter.GetOneTile (area)) 1538 { 1539 1540 host.SniffForAbort (); 1541 1542 buffer.fArea = area; 1543 1544 image.Get (buffer); 1545 1546 uint32 count = buffer.fArea.H () * 1547 buffer.fRowStep * 1548 buffer.fPixelSize; 1549 1550 #if qDNGBigEndian 1551 1552 // We need to use the same byte order to compute 1553 // the digest, no matter the native order. Little-endian 1554 // is more common now, so use that. 1555 1556 switch (buffer.fPixelSize) 1557 { 1558 1559 case 1: 1560 break; 1561 1562 case 2: 1563 { 1564 DoSwapBytes16 ((uint16 *) buffer.fData, count >> 1); 1565 break; 1566 } 1567 1568 case 4: 1569 { 1570 DoSwapBytes32 ((uint32 *) buffer.fData, count >> 2); 1571 break; 1572 } 1573 1574 default: 1575 { 1576 DNG_REPORT ("Unexpected pixel size"); 1577 break; 1578 } 1579 1580 } 1581 1582 #endif 1583 1584 printer.Process (buffer.fData, 1585 count); 1586 1587 } 1588 1589 return printer.Result (); 1590 1591 } 1592 1593 /*****************************************************************************/ 1594 1595 void dng_negative::FindRawImageDigest (dng_host &host) const 1596 { 1597 1598 if (fRawImageDigest.IsNull ()) 1599 { 1600 1601 // Since we are adding the floating point and transparency support 1602 // in DNG 1.4, and there are no legacy floating point or transparent 1603 // DNGs, switch to using the more MP friendly algorithm to compute 1604 // the digest for these images. 1605 1606 if (RawImage ().PixelType () == ttFloat || RawTransparencyMask ()) 1607 { 1608 1609 FindNewRawImageDigest (host); 1610 1611 fRawImageDigest = fNewRawImageDigest; 1612 1613 } 1614 1615 else 1616 { 1617 1618 #if qDNGValidate 1619 1620 dng_timer timeScope ("FindRawImageDigest time"); 1621 1622 #endif 1623 1624 fRawImageDigest = FindImageDigest (host, RawImage ()); 1625 1626 } 1627 1628 } 1629 1630 } 1631 1632 /*****************************************************************************/ 1633 1634 class dng_find_new_raw_image_digest_task : public dng_area_task 1635 { 1636 1637 private: 1638 1639 enum 1640 { 1641 kTileSize = 256 1642 }; 1643 1644 const dng_image &fImage; 1645 1646 uint32 fPixelType; 1647 uint32 fPixelSize; 1648 1649 uint32 fTilesAcross; 1650 uint32 fTilesDown; 1651 1652 uint32 fTileCount; 1653 1654 AutoArray<dng_fingerprint> fTileHash; 1655 1656 AutoPtr<dng_memory_block> fBufferData [kMaxMPThreads]; 1657 1658 public: 1659 1660 dng_find_new_raw_image_digest_task (const dng_image &image, 1661 uint32 pixelType) 1662 1663 : dng_area_task ("dng_find_new_raw_image_digest_task") 1664 1665 , fImage (image) 1666 , fPixelType (pixelType) 1667 , fPixelSize (TagTypeSize (pixelType)) 1668 , fTilesAcross (0) 1669 , fTilesDown (0) 1670 , fTileCount (0) 1671 , fTileHash (NULL) 1672 1673 { 1674 1675 fMinTaskArea = 1; 1676 1677 fUnitCell = dng_point (Min_int32 (kTileSize, fImage.Bounds ().H ()), 1678 Min_int32 (kTileSize, fImage.Bounds ().W ())); 1679 1680 fMaxTileSize = fUnitCell; 1681 1682 } 1683 1684 virtual void Start (uint32 threadCount, 1685 const dng_rect & /* dstArea */, 1686 const dng_point &tileSize, 1687 dng_memory_allocator *allocator, 1688 dng_abort_sniffer * /* sniffer */) 1689 { 1690 1691 if (tileSize != fUnitCell) 1692 { 1693 ThrowProgramError (); 1694 } 1695 1696 fTilesAcross = (fImage.Bounds ().W () + fUnitCell.h - 1) / fUnitCell.h; 1697 fTilesDown = (fImage.Bounds ().H () + fUnitCell.v - 1) / fUnitCell.v; 1698 1699 fTileCount = fTilesAcross * fTilesDown; 1700 1701 fTileHash.Reset (new dng_fingerprint [fTileCount]); 1702 1703 const uint32 bufferSize = 1704 ComputeBufferSize (fPixelType, 1705 tileSize, 1706 fImage.Planes (), 1707 padNone); 1708 1709 for (uint32 index = 0; index < threadCount; index++) 1710 { 1711 1712 fBufferData [index].Reset (allocator->Allocate (bufferSize)); 1713 1714 } 1715 1716 } 1717 1718 virtual void Process (uint32 threadIndex, 1719 const dng_rect &tile, 1720 dng_abort_sniffer * /* sniffer */) 1721 { 1722 1723 int32 colIndex = (tile.l - fImage.Bounds ().l) / fUnitCell.h; 1724 int32 rowIndex = (tile.t - fImage.Bounds ().t) / fUnitCell.v; 1725 1726 DNG_ASSERT (tile.l == fImage.Bounds ().l + colIndex * fUnitCell.h && 1727 tile.t == fImage.Bounds ().t + rowIndex * fUnitCell.v, 1728 "Bad tile origin"); 1729 1730 uint32 tileIndex = rowIndex * fTilesAcross + colIndex; 1731 1732 dng_pixel_buffer buffer (tile, 1733 0, 1734 fImage.Planes (), 1735 fPixelType, 1736 pcPlanar, 1737 fBufferData [threadIndex]->Buffer ()); 1738 1739 fImage.Get (buffer); 1740 1741 uint32 count = buffer.fPlaneStep * 1742 buffer.fPlanes * 1743 buffer.fPixelSize; 1744 1745 #if qDNGBigEndian 1746 1747 // We need to use the same byte order to compute 1748 // the digest, no matter the native order. Little-endian 1749 // is more common now, so use that. 1750 1751 switch (buffer.fPixelSize) 1752 { 1753 1754 case 1: 1755 break; 1756 1757 case 2: 1758 { 1759 DoSwapBytes16 ((uint16 *) buffer.fData, count >> 1); 1760 break; 1761 } 1762 1763 case 4: 1764 { 1765 DoSwapBytes32 ((uint32 *) buffer.fData, count >> 2); 1766 break; 1767 } 1768 1769 default: 1770 { 1771 DNG_REPORT ("Unexpected pixel size"); 1772 break; 1773 } 1774 1775 } 1776 1777 #endif 1778 1779 dng_md5_printer printer; 1780 1781 printer.Process (buffer.fData, count); 1782 1783 fTileHash [tileIndex] = printer.Result (); 1784 1785 } 1786 1787 dng_fingerprint Result () 1788 { 1789 1790 dng_md5_printer printer; 1791 1792 for (uint32 tileIndex = 0; tileIndex < fTileCount; tileIndex++) 1793 { 1794 1795 printer.Process (fTileHash [tileIndex] . data, 16); 1796 1797 } 1798 1799 return printer.Result (); 1800 1801 } 1802 1803 }; 1804 1805 /*****************************************************************************/ 1806 1807 void dng_negative::FindNewRawImageDigest (dng_host &host) const 1808 { 1809 1810 if (fNewRawImageDigest.IsNull ()) 1811 { 1812 1813 #if qDNGValidate 1814 1815 dng_timer timeScope ("FindNewRawImageDigest time"); 1816 1817 #endif 1818 1819 // Find fast digest of the raw image. 1820 1821 { 1822 1823 const dng_image &rawImage = RawImage (); 1824 1825 // Find pixel type that will be saved in the file. When saving DNGs, we convert 1826 // some 16-bit data to 8-bit data, so we need to do the matching logic here. 1827 1828 uint32 rawPixelType = rawImage.PixelType (); 1829 1830 if (rawPixelType == ttShort) 1831 { 1832 1833 // See if we are using a linearization table with <= 256 entries, in which 1834 // case the useful data will all fit within 8-bits. 1835 1836 const dng_linearization_info *rangeInfo = GetLinearizationInfo (); 1837 1838 if (rangeInfo) 1839 { 1840 1841 if (rangeInfo->fLinearizationTable.Get ()) 1842 { 1843 1844 uint32 entries = rangeInfo->fLinearizationTable->LogicalSize () >> 1; 1845 1846 if (entries <= 256) 1847 { 1848 1849 rawPixelType = ttByte; 1850 1851 } 1852 1853 } 1854 1855 } 1856 1857 } 1858 1859 // Find the fast digest on the raw image. 1860 1861 dng_find_new_raw_image_digest_task task (rawImage, rawPixelType); 1862 1863 host.PerformAreaTask (task, rawImage.Bounds ()); 1864 1865 fNewRawImageDigest = task.Result (); 1866 1867 } 1868 1869 // If there is a transparancy mask, we need to include that in the 1870 // digest also. 1871 1872 if (RawTransparencyMask () != NULL) 1873 { 1874 1875 // Find the fast digest on the raw mask. 1876 1877 dng_fingerprint maskDigest; 1878 1879 { 1880 1881 dng_find_new_raw_image_digest_task task (*RawTransparencyMask (), 1882 RawTransparencyMask ()->PixelType ()); 1883 1884 host.PerformAreaTask (task, RawTransparencyMask ()->Bounds ()); 1885 1886 maskDigest = task.Result (); 1887 1888 } 1889 1890 // Combine the two digests into a single digest. 1891 1892 dng_md5_printer printer; 1893 1894 printer.Process (fNewRawImageDigest.data, 16); 1895 1896 printer.Process (maskDigest.data, 16); 1897 1898 fNewRawImageDigest = printer.Result (); 1899 1900 } 1901 1902 } 1903 1904 } 1905 1906 /*****************************************************************************/ 1907 1908 void dng_negative::ValidateRawImageDigest (dng_host &host) 1909 { 1910 1911 if (Stage1Image () && !IsPreview () && (fRawImageDigest .IsValid () || 1912 fNewRawImageDigest.IsValid ())) 1913 { 1914 1915 bool isNewDigest = fNewRawImageDigest.IsValid (); 1916 1917 dng_fingerprint &rawDigest = isNewDigest ? fNewRawImageDigest 1918 : fRawImageDigest; 1919 1920 // For lossy compressed JPEG images, we need to compare the stored 1921 // digest to the digest computed from the compressed data, since 1922 // decompressing lossy JPEG data is itself a lossy process. 1923 1924 if (RawJPEGImageDigest ().IsValid () || RawJPEGImage ()) 1925 { 1926 1927 // Compute the raw JPEG image digest if we have not done so 1928 // already. 1929 1930 FindRawJPEGImageDigest (host); 1931 1932 if (rawDigest != RawJPEGImageDigest ()) 1933 { 1934 1935 #if qDNGValidate 1936 1937 ReportError ("RawImageDigest does not match raw jpeg image"); 1938 1939 #else 1940 1941 SetIsDamaged (true); 1942 1943 #endif 1944 1945 } 1946 1947 } 1948 1949 // Else we can compare the stored digest to the image in memory. 1950 1951 else 1952 { 1953 1954 dng_fingerprint oldDigest = rawDigest; 1955 1956 try 1957 { 1958 1959 rawDigest.Clear (); 1960 1961 if (isNewDigest) 1962 { 1963 1964 FindNewRawImageDigest (host); 1965 1966 } 1967 1968 else 1969 { 1970 1971 FindRawImageDigest (host); 1972 1973 } 1974 1975 } 1976 1977 catch (...) 1978 { 1979 1980 rawDigest = oldDigest; 1981 1982 throw; 1983 1984 } 1985 1986 if (oldDigest != rawDigest) 1987 { 1988 1989 #if qDNGValidate 1990 1991 if (isNewDigest) 1992 { 1993 ReportError ("NewRawImageDigest does not match raw image"); 1994 } 1995 else 1996 { 1997 ReportError ("RawImageDigest does not match raw image"); 1998 } 1999 2000 SetIsDamaged (true); 2001 2002 #else 2003 2004 if (!isNewDigest) 2005 { 2006 2007 // Note that Lightroom 1.4 Windows had a bug that corrupts the 2008 // first four bytes of the RawImageDigest tag. So if the last 2009 // twelve bytes match, this is very likely the result of the 2010 // bug, and not an actual corrupt file. So don't report this 2011 // to the user--just fix it. 2012 2013 { 2014 2015 bool matchLast12 = true; 2016 2017 for (uint32 j = 4; j < 16; j++) 2018 { 2019 matchLast12 = matchLast12 && (oldDigest.data [j] == fRawImageDigest.data [j]); 2020 } 2021 2022 if (matchLast12) 2023 { 2024 return; 2025 } 2026 2027 } 2028 2029 // Sometimes Lightroom 1.4 would corrupt more than the first four 2030 // bytes, but for all those files that I have seen so far the 2031 // resulting first four bytes are 0x08 0x00 0x00 0x00. 2032 2033 if (oldDigest.data [0] == 0x08 && 2034 oldDigest.data [1] == 0x00 && 2035 oldDigest.data [2] == 0x00 && 2036 oldDigest.data [3] == 0x00) 2037 { 2038 return; 2039 } 2040 2041 } 2042 2043 SetIsDamaged (true); 2044 2045 #endif 2046 2047 } 2048 2049 } 2050 2051 } 2052 2053 } 2054 2055 /*****************************************************************************/ 2056 2057 dng_fingerprint dng_negative::RawDataUniqueID () const 2058 { 2059 2060 dng_lock_std_mutex lock (fRawDataUniqueIDMutex); 2061 2062 if (fRawDataUniqueID.IsValid () && fEnhanceParams.NotEmpty ()) 2063 { 2064 2065 dng_md5_printer printer; 2066 2067 printer.Process (fRawDataUniqueID.data, 16); 2068 2069 printer.Process (fEnhanceParams.Get (), 2070 fEnhanceParams.Length ()); 2071 2072 return printer.Result (); 2073 2074 } 2075 2076 return fRawDataUniqueID; 2077 2078 } 2079 2080 /*****************************************************************************/ 2081 2082 // If the raw data unique ID is missing, compute one based on a MD5 hash of 2083 // the raw image hash and the model name, plus other commonly changed 2084 // data that can affect rendering. 2085 2086 void dng_negative::FindRawDataUniqueID (dng_host &host) const 2087 { 2088 2089 if (RawDataUniqueID ().IsNull ()) 2090 { 2091 2092 dng_md5_printer_stream printer; 2093 2094 // If we have a raw jpeg image, it is much faster to 2095 // use its digest as part of the unique ID since 2096 // the data size is much smaller. We cannot use it 2097 // if there a transparency mask, since that is not 2098 // included in the RawJPEGImageDigest. 2099 2100 if (RawJPEGImage () && !RawTransparencyMask ()) 2101 { 2102 2103 FindRawJPEGImageDigest (host); 2104 2105 printer.Put (fRawJPEGImageDigest.data, 16); 2106 2107 } 2108 2109 // Include the new raw image digest in the unique ID. 2110 2111 else 2112 { 2113 2114 FindNewRawImageDigest (host); 2115 2116 printer.Put (fNewRawImageDigest.data, 16); 2117 2118 } 2119 2120 // Include model name. 2121 2122 printer.Put (ModelName ().Get (), 2123 ModelName ().Length ()); 2124 2125 // Include default crop area, since DNG Recover Edges can modify 2126 // these values and they affect rendering. 2127 2128 printer.Put_uint32 (fDefaultCropSizeH.n); 2129 printer.Put_uint32 (fDefaultCropSizeH.d); 2130 2131 printer.Put_uint32 (fDefaultCropSizeV.n); 2132 printer.Put_uint32 (fDefaultCropSizeV.d); 2133 2134 printer.Put_uint32 (fDefaultCropOriginH.n); 2135 printer.Put_uint32 (fDefaultCropOriginH.d); 2136 2137 printer.Put_uint32 (fDefaultCropOriginV.n); 2138 printer.Put_uint32 (fDefaultCropOriginV.d); 2139 2140 // Include default user crop. 2141 2142 printer.Put_uint32 (fDefaultUserCropT.n); 2143 printer.Put_uint32 (fDefaultUserCropT.d); 2144 2145 printer.Put_uint32 (fDefaultUserCropL.n); 2146 printer.Put_uint32 (fDefaultUserCropL.d); 2147 2148 printer.Put_uint32 (fDefaultUserCropB.n); 2149 printer.Put_uint32 (fDefaultUserCropB.d); 2150 2151 printer.Put_uint32 (fDefaultUserCropR.n); 2152 printer.Put_uint32 (fDefaultUserCropR.d); 2153 2154 // Include opcode lists, since lens correction utilities can modify 2155 // these values and they affect rendering. 2156 2157 fOpcodeList1.FingerprintToStream (printer); 2158 fOpcodeList2.FingerprintToStream (printer); 2159 fOpcodeList3.FingerprintToStream (printer); 2160 2161 dng_lock_std_mutex lock (fRawDataUniqueIDMutex); 2162 2163 fRawDataUniqueID = printer.Result (); 2164 2165 } 2166 2167 } 2168 2169 /******************************************************************************/ 2170 2171 // Forces recomputation of RawDataUniqueID, useful to call 2172 // after modifying the opcode lists, etc. 2173 2174 void dng_negative::RecomputeRawDataUniqueID (dng_host &host) 2175 { 2176 2177 fRawDataUniqueID.Clear (); 2178 2179 FindRawDataUniqueID (host); 2180 2181 } 2182 2183 /******************************************************************************/ 2184 2185 void dng_negative::FindOriginalRawFileDigest () const 2186 { 2187 2188 if (fOriginalRawFileDigest.IsNull () && fOriginalRawFileData.Get ()) 2189 { 2190 2191 dng_md5_printer printer; 2192 2193 printer.Process (fOriginalRawFileData->Buffer (), 2194 fOriginalRawFileData->LogicalSize ()); 2195 2196 fOriginalRawFileDigest = printer.Result (); 2197 2198 } 2199 2200 } 2201 2202 /*****************************************************************************/ 2203 2204 void dng_negative::ValidateOriginalRawFileDigest () 2205 { 2206 2207 if (fOriginalRawFileDigest.IsValid () && fOriginalRawFileData.Get ()) 2208 { 2209 2210 dng_fingerprint oldDigest = fOriginalRawFileDigest; 2211 2212 try 2213 { 2214 2215 fOriginalRawFileDigest.Clear (); 2216 2217 FindOriginalRawFileDigest (); 2218 2219 } 2220 2221 catch (...) 2222 { 2223 2224 fOriginalRawFileDigest = oldDigest; 2225 2226 throw; 2227 2228 } 2229 2230 if (oldDigest != fOriginalRawFileDigest) 2231 { 2232 2233 #if qDNGValidate 2234 2235 ReportError ("OriginalRawFileDigest does not match OriginalRawFileData"); 2236 2237 #else 2238 2239 SetIsDamaged (true); 2240 2241 #endif 2242 2243 // Don't "repair" the original image data digest. Once it is 2244 // bad, it stays bad. The user cannot tell by looking at the image 2245 // whether the damage is acceptable and can be ignored in the 2246 // future. 2247 2248 fOriginalRawFileDigest = oldDigest; 2249 2250 } 2251 2252 } 2253 2254 } 2255 2256 /******************************************************************************/ 2257 2258 dng_rect dng_negative::DefaultCropArea () const 2259 { 2260 2261 // First compute the area using simple rounding. 2262 2263 dng_rect result; 2264 2265 result.l = Round_int32 (fDefaultCropOriginH.As_real64 () * fRawToFullScaleH); 2266 result.t = Round_int32 (fDefaultCropOriginV.As_real64 () * fRawToFullScaleV); 2267 2268 result.r = result.l + Round_int32 (fDefaultCropSizeH.As_real64 () * fRawToFullScaleH); 2269 result.b = result.t + Round_int32 (fDefaultCropSizeV.As_real64 () * fRawToFullScaleV); 2270 2271 // Sometimes the simple rounding causes the resulting default crop 2272 // area to slide off the scaled image area. So we force this not 2273 // to happen. We only do this if the image is not stubbed. 2274 2275 const dng_image *image = Stage3Image (); 2276 2277 if (image) 2278 { 2279 2280 dng_point imageSize = image->Size (); 2281 2282 if (result.r > imageSize.h) 2283 { 2284 result.l -= result.r - imageSize.h; 2285 result.r = imageSize.h; 2286 } 2287 2288 if (result.b > imageSize.v) 2289 { 2290 result.t -= result.b - imageSize.v; 2291 result.b = imageSize.v; 2292 } 2293 2294 } 2295 2296 return result; 2297 2298 } 2299 2300 /*****************************************************************************/ 2301 2302 real64 dng_negative::TotalBaselineExposure (const dng_camera_profile_id &profileID) const 2303 { 2304 2305 real64 total = BaselineExposure (); 2306 2307 const dng_camera_profile *profile = ProfileByID (profileID); 2308 2309 if (profile) 2310 { 2311 2312 real64 offset = profile->BaselineExposureOffset ().As_real64 (); 2313 2314 total += offset; 2315 2316 } 2317 2318 return total; 2319 2320 } 2321 2322 /******************************************************************************/ 2323 2324 void dng_negative::SetShadowScale (const dng_urational &scale) 2325 { 2326 2327 if (scale.d > 0) 2328 { 2329 2330 real64 s = scale.As_real64 (); 2331 2332 if (s > 0.0 && s <= 1.0) 2333 { 2334 2335 fShadowScale = scale; 2336 2337 } 2338 2339 } 2340 2341 } 2342 2343 /******************************************************************************/ 2344 2345 void dng_negative::SetActiveArea (const dng_rect &area) 2346 { 2347 2348 NeedLinearizationInfo (); 2349 2350 dng_linearization_info &info = *fLinearizationInfo.Get (); 2351 2352 info.fActiveArea = area; 2353 2354 } 2355 2356 /******************************************************************************/ 2357 2358 void dng_negative::SetMaskedAreas (uint32 count, 2359 const dng_rect *area) 2360 { 2361 2362 DNG_ASSERT (count <= kMaxMaskedAreas, "Too many masked areas"); 2363 2364 NeedLinearizationInfo (); 2365 2366 dng_linearization_info &info = *fLinearizationInfo.Get (); 2367 2368 info.fMaskedAreaCount = Min_uint32 (count, kMaxMaskedAreas); 2369 2370 for (uint32 index = 0; index < info.fMaskedAreaCount; index++) 2371 { 2372 2373 info.fMaskedArea [index] = area [index]; 2374 2375 } 2376 2377 } 2378 2379 /*****************************************************************************/ 2380 2381 void dng_negative::SetLinearization (AutoPtr<dng_memory_block> &curve) 2382 { 2383 2384 NeedLinearizationInfo (); 2385 2386 dng_linearization_info &info = *fLinearizationInfo.Get (); 2387 2388 info.fLinearizationTable.Reset (curve.Release ()); 2389 2390 } 2391 2392 /*****************************************************************************/ 2393 2394 void dng_negative::SetBlackLevel (real64 black, 2395 int32 plane) 2396 { 2397 2398 NeedLinearizationInfo (); 2399 2400 dng_linearization_info &info = *fLinearizationInfo.Get (); 2401 2402 info.fBlackLevelRepeatRows = 1; 2403 info.fBlackLevelRepeatCols = 1; 2404 2405 if (plane < 0) 2406 { 2407 2408 for (uint32 j = 0; j < kMaxSamplesPerPixel; j++) 2409 { 2410 2411 info.fBlackLevel [0] [0] [j] = black; 2412 2413 } 2414 2415 } 2416 2417 else 2418 { 2419 2420 info.fBlackLevel [0] [0] [plane] = black; 2421 2422 } 2423 2424 info.RoundBlacks (); 2425 2426 } 2427 2428 /*****************************************************************************/ 2429 2430 void dng_negative::SetQuadBlacks (real64 black0, 2431 real64 black1, 2432 real64 black2, 2433 real64 black3, 2434 int32 plane) 2435 { 2436 2437 NeedLinearizationInfo (); 2438 2439 dng_linearization_info &info = *fLinearizationInfo.Get (); 2440 2441 info.fBlackLevelRepeatRows = 2; 2442 info.fBlackLevelRepeatCols = 2; 2443 2444 if (plane < 0) 2445 { 2446 2447 for (uint32 j = 0; j < kMaxSamplesPerPixel; j++) 2448 { 2449 2450 info.fBlackLevel [0] [0] [j] = black0; 2451 info.fBlackLevel [0] [1] [j] = black1; 2452 info.fBlackLevel [1] [0] [j] = black2; 2453 info.fBlackLevel [1] [1] [j] = black3; 2454 2455 } 2456 2457 } 2458 2459 else 2460 { 2461 2462 info.fBlackLevel [0] [0] [plane] = black0; 2463 info.fBlackLevel [0] [1] [plane] = black1; 2464 info.fBlackLevel [1] [0] [plane] = black2; 2465 info.fBlackLevel [1] [1] [plane] = black3; 2466 2467 } 2468 2469 info.RoundBlacks (); 2470 2471 } 2472 2473 /*****************************************************************************/ 2474 2475 void dng_negative::Set6x6Blacks (real64 blacks6x6 [36], 2476 int32 plane) 2477 { 2478 2479 NeedLinearizationInfo (); 2480 2481 dng_linearization_info &info = *fLinearizationInfo.Get (); 2482 2483 info.fBlackLevelRepeatRows = 6; 2484 info.fBlackLevelRepeatCols = 6; 2485 2486 if (plane < 0) 2487 { 2488 2489 // Apply the black levels to each image plane up to kMaxSamplesPerPixel. 2490 2491 for (uint32 p = 0; p < kMaxSamplesPerPixel; p++) 2492 { 2493 2494 uint32 m = 0; 2495 2496 for (uint32 r = 0; r < info.fBlackLevelRepeatRows; r++) 2497 for (uint32 c = 0; c < info.fBlackLevelRepeatCols; c++) 2498 { 2499 2500 info.fBlackLevel [r] [c] [p] = blacks6x6 [m]; 2501 2502 m++; 2503 2504 } 2505 } 2506 } 2507 2508 else 2509 { 2510 2511 uint32 m = 0; 2512 2513 // Apply the black levels to a single plane. 2514 2515 for (uint32 r = 0; r < info.fBlackLevelRepeatRows; r++) 2516 for (uint32 c = 0; c < info.fBlackLevelRepeatCols; c++) 2517 { 2518 2519 info.fBlackLevel [r] [c] [plane] = blacks6x6 [m]; 2520 2521 m++; 2522 2523 } 2524 2525 } 2526 2527 info.RoundBlacks (); 2528 2529 } 2530 2531 /*****************************************************************************/ 2532 2533 void dng_negative::SetRowBlacks (const real64 *blacks, 2534 uint32 count) 2535 { 2536 2537 if (count) 2538 { 2539 2540 NeedLinearizationInfo (); 2541 2542 dng_linearization_info &info = *fLinearizationInfo.Get (); 2543 2544 dng_safe_uint32 byteCount = 2545 dng_safe_uint32 (count) * (uint32) sizeof (real64); 2546 2547 info.fBlackDeltaV.Reset (Allocator ().Allocate (byteCount.Get ())); 2548 2549 DoCopyBytes (blacks, 2550 info.fBlackDeltaV->Buffer (), 2551 byteCount.Get ()); 2552 2553 info.RoundBlacks (); 2554 2555 } 2556 2557 else if (fLinearizationInfo.Get ()) 2558 { 2559 2560 dng_linearization_info &info = *fLinearizationInfo.Get (); 2561 2562 info.fBlackDeltaV.Reset (); 2563 2564 } 2565 2566 } 2567 2568 /*****************************************************************************/ 2569 2570 void dng_negative::SetColumnBlacks (const real64 *blacks, 2571 uint32 count) 2572 { 2573 2574 if (count) 2575 { 2576 2577 NeedLinearizationInfo (); 2578 2579 dng_linearization_info &info = *fLinearizationInfo.Get (); 2580 2581 dng_safe_uint32 byteCount = 2582 dng_safe_uint32 (count) * (uint32) sizeof (real64); 2583 2584 info.fBlackDeltaH.Reset (Allocator ().Allocate (byteCount.Get ())); 2585 2586 DoCopyBytes (blacks, 2587 info.fBlackDeltaH->Buffer (), 2588 byteCount.Get ()); 2589 2590 info.RoundBlacks (); 2591 2592 } 2593 2594 else if (fLinearizationInfo.Get ()) 2595 { 2596 2597 dng_linearization_info &info = *fLinearizationInfo.Get (); 2598 2599 info.fBlackDeltaH.Reset (); 2600 2601 } 2602 2603 } 2604 2605 /*****************************************************************************/ 2606 2607 uint32 dng_negative::WhiteLevel (uint32 plane) const 2608 { 2609 2610 if (fLinearizationInfo.Get ()) 2611 { 2612 2613 const dng_linearization_info &info = *fLinearizationInfo.Get (); 2614 2615 return Round_uint32 (info.fWhiteLevel [plane]); 2616 2617 } 2618 2619 if (RawImage ().PixelType () == ttFloat) 2620 { 2621 2622 return 1; 2623 2624 } 2625 2626 return 0x0FFFF; 2627 2628 } 2629 2630 /*****************************************************************************/ 2631 2632 void dng_negative::SetWhiteLevel (uint32 white, 2633 int32 plane) 2634 { 2635 2636 NeedLinearizationInfo (); 2637 2638 dng_linearization_info &info = *fLinearizationInfo.Get (); 2639 2640 if (plane < 0) 2641 { 2642 2643 for (uint32 j = 0; j < kMaxSamplesPerPixel; j++) 2644 { 2645 2646 info.fWhiteLevel [j] = (real64) white; 2647 2648 } 2649 2650 } 2651 2652 else 2653 { 2654 2655 info.fWhiteLevel [plane] = (real64) white; 2656 2657 } 2658 2659 } 2660 2661 /******************************************************************************/ 2662 2663 void dng_negative::SetColorKeys (ColorKeyCode color0, 2664 ColorKeyCode color1, 2665 ColorKeyCode color2, 2666 ColorKeyCode color3) 2667 { 2668 2669 NeedMosaicInfo (); 2670 2671 dng_mosaic_info &info = *fMosaicInfo.Get (); 2672 2673 info.fCFAPlaneColor [0] = color0; 2674 info.fCFAPlaneColor [1] = color1; 2675 info.fCFAPlaneColor [2] = color2; 2676 info.fCFAPlaneColor [3] = color3; 2677 2678 } 2679 2680 /******************************************************************************/ 2681 2682 void dng_negative::SetBayerMosaic (uint32 phase) 2683 { 2684 2685 NeedMosaicInfo (); 2686 2687 dng_mosaic_info &info = *fMosaicInfo.Get (); 2688 2689 ColorKeyCode color0 = (ColorKeyCode) info.fCFAPlaneColor [0]; 2690 ColorKeyCode color1 = (ColorKeyCode) info.fCFAPlaneColor [1]; 2691 ColorKeyCode color2 = (ColorKeyCode) info.fCFAPlaneColor [2]; 2692 2693 info.fCFAPatternSize = dng_point (2, 2); 2694 2695 switch (phase) 2696 { 2697 2698 case 0: 2699 { 2700 info.fCFAPattern [0] [0] = color1; 2701 info.fCFAPattern [0] [1] = color0; 2702 info.fCFAPattern [1] [0] = color2; 2703 info.fCFAPattern [1] [1] = color1; 2704 break; 2705 } 2706 2707 case 1: 2708 { 2709 info.fCFAPattern [0] [0] = color0; 2710 info.fCFAPattern [0] [1] = color1; 2711 info.fCFAPattern [1] [0] = color1; 2712 info.fCFAPattern [1] [1] = color2; 2713 break; 2714 } 2715 2716 case 2: 2717 { 2718 info.fCFAPattern [0] [0] = color2; 2719 info.fCFAPattern [0] [1] = color1; 2720 info.fCFAPattern [1] [0] = color1; 2721 info.fCFAPattern [1] [1] = color0; 2722 break; 2723 } 2724 2725 case 3: 2726 { 2727 info.fCFAPattern [0] [0] = color1; 2728 info.fCFAPattern [0] [1] = color2; 2729 info.fCFAPattern [1] [0] = color0; 2730 info.fCFAPattern [1] [1] = color1; 2731 break; 2732 } 2733 2734 } 2735 2736 info.fColorPlanes = 3; 2737 2738 info.fCFALayout = 1; 2739 2740 } 2741 2742 /******************************************************************************/ 2743 2744 void dng_negative::SetFujiMosaic (uint32 phase) 2745 { 2746 2747 NeedMosaicInfo (); 2748 2749 dng_mosaic_info &info = *fMosaicInfo.Get (); 2750 2751 ColorKeyCode color0 = (ColorKeyCode) info.fCFAPlaneColor [0]; 2752 ColorKeyCode color1 = (ColorKeyCode) info.fCFAPlaneColor [1]; 2753 ColorKeyCode color2 = (ColorKeyCode) info.fCFAPlaneColor [2]; 2754 2755 info.fCFAPatternSize = dng_point (2, 4); 2756 2757 switch (phase) 2758 { 2759 2760 case 0: 2761 { 2762 info.fCFAPattern [0] [0] = color0; 2763 info.fCFAPattern [0] [1] = color1; 2764 info.fCFAPattern [0] [2] = color2; 2765 info.fCFAPattern [0] [3] = color1; 2766 info.fCFAPattern [1] [0] = color2; 2767 info.fCFAPattern [1] [1] = color1; 2768 info.fCFAPattern [1] [2] = color0; 2769 info.fCFAPattern [1] [3] = color1; 2770 break; 2771 } 2772 2773 case 1: 2774 { 2775 info.fCFAPattern [0] [0] = color2; 2776 info.fCFAPattern [0] [1] = color1; 2777 info.fCFAPattern [0] [2] = color0; 2778 info.fCFAPattern [0] [3] = color1; 2779 info.fCFAPattern [1] [0] = color0; 2780 info.fCFAPattern [1] [1] = color1; 2781 info.fCFAPattern [1] [2] = color2; 2782 info.fCFAPattern [1] [3] = color1; 2783 break; 2784 } 2785 2786 } 2787 2788 info.fColorPlanes = 3; 2789 2790 info.fCFALayout = 2; 2791 2792 } 2793 2794 /*****************************************************************************/ 2795 2796 void dng_negative::SetFujiMosaic6x6 (uint32 phase) 2797 { 2798 2799 NeedMosaicInfo (); 2800 2801 dng_mosaic_info &info = *fMosaicInfo.Get (); 2802 2803 ColorKeyCode color0 = (ColorKeyCode) info.fCFAPlaneColor [0]; 2804 ColorKeyCode color1 = (ColorKeyCode) info.fCFAPlaneColor [1]; 2805 ColorKeyCode color2 = (ColorKeyCode) info.fCFAPlaneColor [2]; 2806 2807 const uint32 patSize = 6; 2808 2809 info.fCFAPatternSize = dng_point (patSize, patSize); 2810 2811 info.fCFAPattern [0] [0] = color1; 2812 info.fCFAPattern [0] [1] = color2; 2813 info.fCFAPattern [0] [2] = color1; 2814 info.fCFAPattern [0] [3] = color1; 2815 info.fCFAPattern [0] [4] = color0; 2816 info.fCFAPattern [0] [5] = color1; 2817 2818 info.fCFAPattern [1] [0] = color0; 2819 info.fCFAPattern [1] [1] = color1; 2820 info.fCFAPattern [1] [2] = color0; 2821 info.fCFAPattern [1] [3] = color2; 2822 info.fCFAPattern [1] [4] = color1; 2823 info.fCFAPattern [1] [5] = color2; 2824 2825 info.fCFAPattern [2] [0] = color1; 2826 info.fCFAPattern [2] [1] = color2; 2827 info.fCFAPattern [2] [2] = color1; 2828 info.fCFAPattern [2] [3] = color1; 2829 info.fCFAPattern [2] [4] = color0; 2830 info.fCFAPattern [2] [5] = color1; 2831 2832 info.fCFAPattern [3] [0] = color1; 2833 info.fCFAPattern [3] [1] = color0; 2834 info.fCFAPattern [3] [2] = color1; 2835 info.fCFAPattern [3] [3] = color1; 2836 info.fCFAPattern [3] [4] = color2; 2837 info.fCFAPattern [3] [5] = color1; 2838 2839 info.fCFAPattern [4] [0] = color2; 2840 info.fCFAPattern [4] [1] = color1; 2841 info.fCFAPattern [4] [2] = color2; 2842 info.fCFAPattern [4] [3] = color0; 2843 info.fCFAPattern [4] [4] = color1; 2844 info.fCFAPattern [4] [5] = color0; 2845 2846 info.fCFAPattern [5] [0] = color1; 2847 info.fCFAPattern [5] [1] = color0; 2848 info.fCFAPattern [5] [2] = color1; 2849 info.fCFAPattern [5] [3] = color1; 2850 info.fCFAPattern [5] [4] = color2; 2851 info.fCFAPattern [5] [5] = color1; 2852 2853 DNG_REQUIRE (phase >= 0 && phase < patSize * patSize, 2854 "Bad phase in SetFujiMosaic6x6."); 2855 2856 if (phase > 0) 2857 { 2858 2859 dng_mosaic_info temp = info; 2860 2861 uint32 phaseRow = phase / patSize; 2862 2863 uint32 phaseCol = phase - (phaseRow * patSize); 2864 2865 for (uint32 dstRow = 0; dstRow < patSize; dstRow++) 2866 { 2867 2868 uint32 srcRow = (dstRow + phaseRow) % patSize; 2869 2870 for (uint32 dstCol = 0; dstCol < patSize; dstCol++) 2871 { 2872 2873 uint32 srcCol = (dstCol + phaseCol) % patSize; 2874 2875 temp.fCFAPattern [dstRow] [dstCol] = info.fCFAPattern [srcRow] [srcCol]; 2876 2877 } 2878 2879 } 2880 2881 info = temp; 2882 2883 } 2884 2885 info.fColorPlanes = 3; 2886 2887 info.fCFALayout = 1; 2888 2889 } 2890 2891 /******************************************************************************/ 2892 2893 void dng_negative::SetQuadMosaic (uint32 pattern) 2894 { 2895 2896 // The pattern of the four colors is assumed to be repeat at least every two 2897 // columns and eight rows. The pattern is encoded as a 32-bit integer, 2898 // with every two bits encoding a color, in scan order for two columns and 2899 // eight rows (lsb is first). The usual color coding is: 2900 // 2901 // 0 = Green 2902 // 1 = Magenta 2903 // 2 = Cyan 2904 // 3 = Yellow 2905 // 2906 // Examples: 2907 // 2908 // PowerShot 600 uses 0xe1e4e1e4: 2909 // 2910 // 0 1 2 3 4 5 2911 // 0 G M G M G M 2912 // 1 C Y C Y C Y 2913 // 2 M G M G M G 2914 // 3 C Y C Y C Y 2915 // 2916 // PowerShot A5 uses 0x1e4e1e4e: 2917 // 2918 // 0 1 2 3 4 5 2919 // 0 C Y C Y C Y 2920 // 1 G M G M G M 2921 // 2 C Y C Y C Y 2922 // 3 M G M G M G 2923 // 2924 // PowerShot A50 uses 0x1b4e4b1e: 2925 // 2926 // 0 1 2 3 4 5 2927 // 0 C Y C Y C Y 2928 // 1 M G M G M G 2929 // 2 Y C Y C Y C 2930 // 3 G M G M G M 2931 // 4 C Y C Y C Y 2932 // 5 G M G M G M 2933 // 6 Y C Y C Y C 2934 // 7 M G M G M G 2935 // 2936 // PowerShot Pro70 uses 0x1e4b4e1b: 2937 // 2938 // 0 1 2 3 4 5 2939 // 0 Y C Y C Y C 2940 // 1 M G M G M G 2941 // 2 C Y C Y C Y 2942 // 3 G M G M G M 2943 // 4 Y C Y C Y C 2944 // 5 G M G M G M 2945 // 6 C Y C Y C Y 2946 // 7 M G M G M G 2947 // 2948 // PowerShots Pro90 and G1 use 0xb4b4b4b4: 2949 // 2950 // 0 1 2 3 4 5 2951 // 0 G M G M G M 2952 // 1 Y C Y C Y C 2953 2954 NeedMosaicInfo (); 2955 2956 dng_mosaic_info &info = *fMosaicInfo.Get (); 2957 2958 if (((pattern >> 16) & 0x0FFFF) != (pattern & 0x0FFFF)) 2959 { 2960 info.fCFAPatternSize = dng_point (8, 2); 2961 } 2962 2963 else if (((pattern >> 8) & 0x0FF) != (pattern & 0x0FF)) 2964 { 2965 info.fCFAPatternSize = dng_point (4, 2); 2966 } 2967 2968 else 2969 { 2970 info.fCFAPatternSize = dng_point (2, 2); 2971 } 2972 2973 for (int32 row = 0; row < info.fCFAPatternSize.v; row++) 2974 { 2975 2976 for (int32 col = 0; col < info.fCFAPatternSize.h; col++) 2977 { 2978 2979 uint32 index = (pattern >> ((((row << 1) & 14) + (col & 1)) << 1)) & 3; 2980 2981 info.fCFAPattern [row] [col] = info.fCFAPlaneColor [index]; 2982 2983 } 2984 2985 } 2986 2987 info.fColorPlanes = 4; 2988 2989 info.fCFALayout = 1; 2990 2991 } 2992 2993 /******************************************************************************/ 2994 2995 void dng_negative::SetGreenSplit (uint32 split) 2996 { 2997 2998 NeedMosaicInfo (); 2999 3000 dng_mosaic_info &info = *fMosaicInfo.Get (); 3001 3002 info.fBayerGreenSplit = split; 3003 3004 } 3005 3006 /*****************************************************************************/ 3007 3008 void dng_negative::Parse (dng_host &host, 3009 dng_stream &stream, 3010 dng_info &info) 3011 { 3012 3013 // Shared info. 3014 3015 dng_shared &shared = *(info.fShared.Get ()); 3016 3017 // Find IFD holding the main raw information. 3018 3019 dng_ifd &rawIFD = *info.fIFD [info.fMainIndex]; 3020 3021 // Model name. 3022 3023 SetModelName (shared.fUniqueCameraModel.Get ()); 3024 3025 // Localized model name. 3026 3027 SetLocalName (shared.fLocalizedCameraModel.Get ()); 3028 3029 // Base orientation. 3030 3031 { 3032 3033 uint32 orientation = info.fIFD [0]->fOrientation; 3034 3035 if (orientation >= 1 && orientation <= 8) 3036 { 3037 3038 SetBaseOrientation (dng_orientation::TIFFtoDNG (orientation)); 3039 3040 } 3041 3042 } 3043 3044 // Default crop rectangle. 3045 3046 SetDefaultCropSize (rawIFD.fDefaultCropSizeH, 3047 rawIFD.fDefaultCropSizeV); 3048 3049 SetDefaultCropOrigin (rawIFD.fDefaultCropOriginH, 3050 rawIFD.fDefaultCropOriginV); 3051 3052 // Default user crop rectangle. 3053 3054 SetDefaultUserCrop (rawIFD.fDefaultUserCropT, 3055 rawIFD.fDefaultUserCropL, 3056 rawIFD.fDefaultUserCropB, 3057 rawIFD.fDefaultUserCropR); 3058 3059 // Default scale. 3060 3061 SetDefaultScale (rawIFD.fDefaultScaleH, 3062 rawIFD.fDefaultScaleV); 3063 3064 // Best quality scale. 3065 3066 SetBestQualityScale (rawIFD.fBestQualityScale); 3067 3068 // Baseline noise. 3069 3070 SetBaselineNoise (shared.fBaselineNoise.As_real64 ()); 3071 3072 // NoiseReductionApplied. 3073 3074 // Kludge: DNG spec says that NoiseReductionApplied tag should be in the 3075 // Raw IFD, not main IFD. However, our original DNG SDK implementation 3076 // read/wrote this tag from/to the main IFD. We now support reading the 3077 // NoiseReductionApplied tag from both locations, but prefer the raw IFD 3078 // (correct location). 3079 3080 if (rawIFD.fNoiseReductionApplied.IsValid ()) 3081 { 3082 3083 SetNoiseReductionApplied (rawIFD.fNoiseReductionApplied); 3084 3085 } 3086 3087 else 3088 { 3089 3090 const dng_ifd &ifd0 = *info.fIFD [0]; 3091 3092 SetNoiseReductionApplied (ifd0.fNoiseReductionApplied); 3093 3094 } 3095 3096 // NoiseProfile. 3097 3098 // Kludge: DNG spec says that NoiseProfile tag should be in the Raw IFD, 3099 // not main IFD. However, our original DNG SDK implementation read/wrote 3100 // this tag from/to the main IFD. We now support reading the NoiseProfile 3101 // tag from both locations, but prefer the raw IFD (correct location). 3102 3103 if (rawIFD.fNoiseProfile.IsValid ()) 3104 { 3105 3106 SetNoiseProfile (rawIFD.fNoiseProfile); 3107 3108 } 3109 3110 else 3111 { 3112 3113 const dng_ifd &ifd0 = *info.fIFD [0]; 3114 3115 SetNoiseProfile (ifd0.fNoiseProfile); 3116 3117 } 3118 3119 // Baseline exposure. 3120 3121 SetBaselineExposure (shared.fBaselineExposure.As_real64 ()); 3122 3123 // Baseline sharpness. 3124 3125 SetBaselineSharpness (shared.fBaselineSharpness.As_real64 ()); 3126 3127 // Chroma blur radius. 3128 3129 SetChromaBlurRadius (rawIFD.fChromaBlurRadius); 3130 3131 // Anti-alias filter strength. 3132 3133 SetAntiAliasStrength (rawIFD.fAntiAliasStrength); 3134 3135 // Linear response limit. 3136 3137 SetLinearResponseLimit (shared.fLinearResponseLimit.As_real64 ()); 3138 3139 // Shadow scale. 3140 3141 SetShadowScale (shared.fShadowScale); 3142 3143 // Colorimetric reference. 3144 3145 SetColorimetricReference (shared.fColorimetricReference); 3146 3147 // Floating point flag. 3148 3149 SetFloatingPoint (rawIFD.fSampleFormat [0] == sfFloatingPoint); 3150 3151 // Color channels. 3152 3153 SetColorChannels (shared.fCameraProfile.fColorPlanes); 3154 3155 // Analog balance. 3156 3157 if (shared.fAnalogBalance.NotEmpty ()) 3158 { 3159 3160 SetAnalogBalance (shared.fAnalogBalance); 3161 3162 } 3163 3164 // Camera calibration matrices 3165 3166 if (shared.fCameraCalibration1.NotEmpty ()) 3167 { 3168 3169 SetCameraCalibration1 (shared.fCameraCalibration1); 3170 3171 } 3172 3173 if (shared.fCameraCalibration2.NotEmpty ()) 3174 { 3175 3176 SetCameraCalibration2 (shared.fCameraCalibration2); 3177 3178 } 3179 3180 if (shared.fCameraCalibration1.NotEmpty () || 3181 shared.fCameraCalibration2.NotEmpty ()) 3182 { 3183 3184 SetCameraCalibrationSignature (shared.fCameraCalibrationSignature.Get ()); 3185 3186 } 3187 3188 // Embedded camera profiles. 3189 3190 if (shared.fCameraProfile.fColorPlanes > 1) 3191 { 3192 3193 if (qDNGValidate || host.NeedsMeta () || host.NeedsImage ()) 3194 { 3195 3196 // Add profile from main IFD. 3197 3198 { 3199 3200 AutoPtr<dng_camera_profile> profile (new dng_camera_profile ()); 3201 3202 dng_camera_profile_info &profileInfo = shared.fCameraProfile; 3203 3204 profile->Parse (stream, profileInfo); 3205 3206 // The main embedded profile must be valid. 3207 3208 if (!profile->IsValid (shared.fCameraProfile.fColorPlanes)) 3209 { 3210 3211 ThrowBadFormat (); 3212 3213 } 3214 3215 profile->SetWasReadFromDNG (); 3216 3217 AddProfile (profile); 3218 3219 } 3220 3221 // Extra profiles. 3222 3223 for (uint32 index = 0; index < (uint32) shared.fExtraCameraProfiles.size (); index++) 3224 { 3225 3226 try 3227 { 3228 3229 AutoPtr<dng_camera_profile> profile (new dng_camera_profile ()); 3230 3231 dng_camera_profile_info &profileInfo = shared.fExtraCameraProfiles [index]; 3232 3233 profile->Parse (stream, profileInfo); 3234 3235 if (!profile->IsValid (shared.fCameraProfile.fColorPlanes)) 3236 { 3237 3238 ThrowBadFormat (); 3239 3240 } 3241 3242 profile->SetWasReadFromDNG (); 3243 3244 AddProfile (profile); 3245 3246 } 3247 3248 catch (dng_exception &except) 3249 { 3250 3251 // Don't ignore transient errors. 3252 3253 if (host.IsTransientError (except.ErrorCode ())) 3254 { 3255 3256 throw; 3257 3258 } 3259 3260 // Eat other parsing errors. 3261 3262 #if qDNGValidate 3263 3264 ReportWarning ("Unable to parse extra profile"); 3265 3266 #endif 3267 3268 } 3269 3270 } 3271 3272 } 3273 3274 // As shot profile name. 3275 3276 if (shared.fAsShotProfileName.NotEmpty ()) 3277 { 3278 3279 SetAsShotProfileName (shared.fAsShotProfileName.Get ()); 3280 3281 } 3282 3283 } 3284 3285 // Raw image data digest. 3286 3287 if (shared.fRawImageDigest.IsValid ()) 3288 { 3289 3290 SetRawImageDigest (shared.fRawImageDigest); 3291 3292 } 3293 3294 // New raw image data digest. 3295 3296 if (shared.fNewRawImageDigest.IsValid ()) 3297 { 3298 3299 SetNewRawImageDigest (shared.fNewRawImageDigest); 3300 3301 } 3302 3303 // Raw data unique ID. 3304 3305 if (shared.fRawDataUniqueID.IsValid ()) 3306 { 3307 3308 SetRawDataUniqueID (shared.fRawDataUniqueID); 3309 3310 } 3311 3312 // Original raw file name. 3313 3314 if (shared.fOriginalRawFileName.NotEmpty ()) 3315 { 3316 3317 SetOriginalRawFileName (shared.fOriginalRawFileName.Get ()); 3318 3319 } 3320 3321 // Original raw file data. 3322 3323 if (shared.fOriginalRawFileDataCount) 3324 { 3325 3326 SetHasOriginalRawFileData (true); 3327 3328 if (host.KeepOriginalFile ()) 3329 { 3330 3331 uint32 count = shared.fOriginalRawFileDataCount; 3332 3333 AutoPtr<dng_memory_block> block (host.Allocate (count)); 3334 3335 stream.SetReadPosition (shared.fOriginalRawFileDataOffset); 3336 3337 stream.Get (block->Buffer (), count); 3338 3339 SetOriginalRawFileData (block); 3340 3341 SetOriginalRawFileDigest (shared.fOriginalRawFileDigest); 3342 3343 ValidateOriginalRawFileDigest (); 3344 3345 } 3346 3347 } 3348 3349 // DNG private data. 3350 3351 if (shared.fDNGPrivateDataCount && (host.SaveDNGVersion () != dngVersion_None)) 3352 { 3353 3354 uint32 length = shared.fDNGPrivateDataCount; 3355 3356 AutoPtr<dng_memory_block> block (host.Allocate (length)); 3357 3358 stream.SetReadPosition (shared.fDNGPrivateDataOffset); 3359 3360 stream.Get (block->Buffer (), length); 3361 3362 SetPrivateData (block); 3363 3364 } 3365 3366 // Hand off EXIF metadata to negative. 3367 3368 ResetExif (info.fExif.Release ()); 3369 3370 // Parse linearization info. 3371 3372 NeedLinearizationInfo (); 3373 3374 fLinearizationInfo.Get ()->Parse (host, 3375 stream, 3376 info); 3377 3378 // Parse mosaic info. 3379 3380 if (rawIFD.fPhotometricInterpretation == piCFA) 3381 { 3382 3383 NeedMosaicInfo (); 3384 3385 fMosaicInfo.Get ()->Parse (host, 3386 stream, 3387 info); 3388 3389 } 3390 3391 // Fill in original sizes. 3392 3393 if (shared.fOriginalDefaultFinalSize.h > 0 && 3394 shared.fOriginalDefaultFinalSize.v > 0) 3395 { 3396 3397 SetOriginalDefaultFinalSize (shared.fOriginalDefaultFinalSize); 3398 3399 SetOriginalBestQualityFinalSize (shared.fOriginalDefaultFinalSize); 3400 3401 SetOriginalDefaultCropSize (dng_urational (shared.fOriginalDefaultFinalSize.h, 1), 3402 dng_urational (shared.fOriginalDefaultFinalSize.v, 1)); 3403 3404 } 3405 3406 if (shared.fOriginalBestQualityFinalSize.h > 0 && 3407 shared.fOriginalBestQualityFinalSize.v > 0) 3408 { 3409 3410 SetOriginalBestQualityFinalSize (shared.fOriginalBestQualityFinalSize); 3411 3412 } 3413 3414 if (shared.fOriginalDefaultCropSizeH.As_real64 () >= 1.0 && 3415 shared.fOriginalDefaultCropSizeV.As_real64 () >= 1.0) 3416 { 3417 3418 SetOriginalDefaultCropSize (shared.fOriginalDefaultCropSizeH, 3419 shared.fOriginalDefaultCropSizeV); 3420 3421 } 3422 3423 if (shared.fDepthFormat <= depthFormatUnknown) 3424 { 3425 3426 SetDepthFormat (shared.fDepthFormat); 3427 3428 } 3429 3430 if (shared.fDepthNear != dng_urational (0, 0)) 3431 { 3432 3433 SetDepthNear (shared.fDepthNear); 3434 3435 } 3436 3437 if (shared.fDepthFar != dng_urational (0, 0)) 3438 { 3439 3440 SetDepthFar (shared.fDepthFar); 3441 3442 } 3443 3444 if (shared.fDepthUnits != depthUnitsUnknown) 3445 { 3446 3447 SetDepthUnits (shared.fDepthUnits); 3448 3449 } 3450 3451 if (shared.fDepthMeasureType != depthMeasureUnknown) 3452 { 3453 3454 SetDepthMeasureType (shared.fDepthMeasureType); 3455 3456 } 3457 3458 } 3459 3460 /*****************************************************************************/ 3461 3462 void dng_negative::SetDefaultOriginalSizes () 3463 { 3464 3465 // Fill in original sizes if we don't have them already. 3466 3467 if (OriginalDefaultFinalSize () == dng_point ()) 3468 { 3469 3470 SetOriginalDefaultFinalSize (dng_point (DefaultFinalHeight (), 3471 DefaultFinalWidth ())); 3472 3473 } 3474 3475 if (OriginalBestQualityFinalSize () == dng_point ()) 3476 { 3477 3478 SetOriginalBestQualityFinalSize (dng_point (BestQualityFinalHeight (), 3479 BestQualityFinalWidth ())); 3480 3481 } 3482 3483 if (OriginalDefaultCropSizeH ().NotValid () || 3484 OriginalDefaultCropSizeV ().NotValid ()) 3485 { 3486 3487 SetOriginalDefaultCropSize (DefaultCropSizeH (), 3488 DefaultCropSizeV ()); 3489 3490 } 3491 3492 } 3493 3494 /*****************************************************************************/ 3495 3496 void dng_negative::SetOriginalSizes (const dng_point &size) 3497 { 3498 3499 SetOriginalDefaultFinalSize (size); 3500 3501 SetOriginalBestQualityFinalSize (size); 3502 3503 SetOriginalDefaultCropSize (dng_urational (size.h, 1), 3504 dng_urational (size.v, 1)); 3505 3506 } 3507 3508 /*****************************************************************************/ 3509 3510 void dng_negative::PostParse (dng_host &host, 3511 dng_stream &stream, 3512 dng_info &info) 3513 { 3514 3515 // Shared info. 3516 3517 dng_shared &shared = *(info.fShared.Get ()); 3518 3519 if (host.NeedsMeta ()) 3520 { 3521 3522 // Fill in original sizes if we don't have them already. 3523 3524 SetDefaultOriginalSizes (); 3525 3526 // MakerNote. 3527 3528 if (shared.fMakerNoteCount) 3529 { 3530 3531 // See if we know if the MakerNote is safe or not. 3532 3533 SetMakerNoteSafety (shared.fMakerNoteSafety == 1); 3534 3535 // If the MakerNote is safe, preserve it as a MakerNote. 3536 3537 if (IsMakerNoteSafe ()) 3538 { 3539 3540 AutoPtr<dng_memory_block> block (host.Allocate (shared.fMakerNoteCount)); 3541 3542 stream.SetReadPosition (shared.fMakerNoteOffset); 3543 3544 stream.Get (block->Buffer (), shared.fMakerNoteCount); 3545 3546 SetMakerNote (block); 3547 3548 } 3549 3550 } 3551 3552 // IPTC metadata. 3553 3554 if (shared.fIPTC_NAA_Count) 3555 { 3556 3557 AutoPtr<dng_memory_block> block (host.Allocate (shared.fIPTC_NAA_Count)); 3558 3559 stream.SetReadPosition (shared.fIPTC_NAA_Offset); 3560 3561 uint64 iptcOffset = stream.PositionInOriginalFile(); 3562 3563 stream.Get (block->Buffer (), 3564 block->LogicalSize ()); 3565 3566 SetIPTC (block, iptcOffset); 3567 3568 } 3569 3570 // XMP metadata. 3571 3572 if (shared.fXMPCount) 3573 { 3574 3575 AutoPtr<dng_memory_block> block (host.Allocate (shared.fXMPCount)); 3576 3577 stream.SetReadPosition (shared.fXMPOffset); 3578 3579 stream.Get (block->Buffer (), 3580 block->LogicalSize ()); 3581 3582 Metadata ().SetEmbeddedXMP (host, 3583 block->Buffer (), 3584 block->LogicalSize ()); 3585 3586 #if qDNGValidate 3587 3588 if (!Metadata ().HaveValidEmbeddedXMP ()) 3589 { 3590 ReportError ("The embedded XMP is invalid"); 3591 } 3592 3593 #endif 3594 3595 } 3596 3597 // Color info. 3598 3599 if (!IsMonochrome ()) 3600 { 3601 3602 // If the ColorimetricReference is the ICC profile PCS, 3603 // then the data must be already be white balanced to the 3604 // ICC profile PCS white point. 3605 3606 if (ColorimetricReference () == crICCProfilePCS) 3607 { 3608 3609 ClearCameraNeutral (); 3610 3611 SetCameraWhiteXY (PCStoXY ()); 3612 3613 } 3614 3615 else 3616 { 3617 3618 // AsShotNeutral. 3619 3620 if (shared.fAsShotNeutral.Count () == ColorChannels ()) 3621 { 3622 3623 SetCameraNeutral (shared.fAsShotNeutral); 3624 3625 } 3626 3627 // AsShotWhiteXY. 3628 3629 if (shared.fAsShotWhiteXY.IsValid () && !HasCameraNeutral ()) 3630 { 3631 3632 SetCameraWhiteXY (shared.fAsShotWhiteXY); 3633 3634 } 3635 3636 } 3637 3638 } 3639 3640 } 3641 3642 } 3643 3644 /*****************************************************************************/ 3645 3646 bool dng_negative::SetFourColorBayer () 3647 { 3648 3649 if (ColorChannels () != 3) 3650 { 3651 return false; 3652 } 3653 3654 if (!fMosaicInfo.Get ()) 3655 { 3656 return false; 3657 } 3658 3659 if (!fMosaicInfo.Get ()->SetFourColorBayer ()) 3660 { 3661 return false; 3662 } 3663 3664 SetColorChannels (4); 3665 3666 if (fCameraNeutral.Count () == 3) 3667 { 3668 3669 dng_vector n (4); 3670 3671 n [0] = fCameraNeutral [0]; 3672 n [1] = fCameraNeutral [1]; 3673 n [2] = fCameraNeutral [2]; 3674 n [3] = fCameraNeutral [1]; 3675 3676 fCameraNeutral = n; 3677 3678 } 3679 3680 fCameraCalibration1.Clear (); 3681 fCameraCalibration2.Clear (); 3682 3683 fCameraCalibrationSignature.Clear (); 3684 3685 for (uint32 index = 0; index < (uint32) fCameraProfile.size (); index++) 3686 { 3687 3688 fCameraProfile [index]->SetFourColorBayer (); 3689 3690 } 3691 3692 return true; 3693 3694 } 3695 3696 /*****************************************************************************/ 3697 3698 const dng_image & dng_negative::RawImage () const 3699 { 3700 3701 if (fRawImage.Get ()) 3702 { 3703 return *fRawImage.Get (); 3704 } 3705 3706 if (fStage1Image.Get ()) 3707 { 3708 return *fStage1Image.Get (); 3709 } 3710 3711 if (fUnflattenedStage3Image.Get ()) 3712 { 3713 return *fUnflattenedStage3Image.Get (); 3714 } 3715 3716 DNG_REQUIRE (fStage3Image.Get (), 3717 "dng_negative::RawImage with no raw image"); 3718 3719 return *fStage3Image.Get (); 3720 3721 } 3722 3723 /*****************************************************************************/ 3724 3725 uint16 dng_negative::RawImageBlackLevel () const 3726 { 3727 3728 if (fRawImage.Get ()) 3729 { 3730 return fRawImageBlackLevel; 3731 } 3732 3733 if (fStage1Image.Get ()) 3734 { 3735 return 0; 3736 } 3737 3738 return fStage3BlackLevel; 3739 3740 } 3741 3742 /*****************************************************************************/ 3743 3744 const dng_jpeg_image * dng_negative::RawJPEGImage () const 3745 { 3746 3747 return fRawJPEGImage.Get (); 3748 3749 } 3750 3751 /*****************************************************************************/ 3752 3753 void dng_negative::SetRawJPEGImage (AutoPtr<dng_jpeg_image> &jpegImage) 3754 { 3755 3756 fRawJPEGImage.Reset (jpegImage.Release ()); 3757 3758 } 3759 3760 /*****************************************************************************/ 3761 3762 void dng_negative::ClearRawJPEGImage () 3763 { 3764 3765 fRawJPEGImage.Reset (); 3766 3767 } 3768 3769 /*****************************************************************************/ 3770 3771 void dng_negative::FindRawJPEGImageDigest (dng_host &host) const 3772 { 3773 3774 if (fRawJPEGImageDigest.IsNull ()) 3775 { 3776 3777 if (fRawJPEGImage.Get ()) 3778 { 3779 3780 #if qDNGValidate 3781 3782 dng_timer timer ("FindRawJPEGImageDigest time"); 3783 3784 #endif 3785 3786 fRawJPEGImageDigest = fRawJPEGImage->FindDigest (host); 3787 3788 } 3789 3790 else 3791 { 3792 3793 ThrowProgramError ("No raw JPEG image"); 3794 3795 } 3796 3797 } 3798 3799 } 3800 3801 /*****************************************************************************/ 3802 3803 void dng_negative::ReadOpcodeLists (dng_host &host, 3804 dng_stream &stream, 3805 dng_info &info) 3806 { 3807 3808 dng_ifd &rawIFD = *info.fIFD [info.fMainIndex]; 3809 3810 if (rawIFD.fOpcodeList1Count) 3811 { 3812 3813 #if qDNGValidate 3814 3815 if (gVerbose) 3816 { 3817 printf ("\nParsing OpcodeList1: "); 3818 } 3819 3820 #endif 3821 3822 fOpcodeList1.Parse (host, 3823 stream, 3824 rawIFD.fOpcodeList1Count, 3825 rawIFD.fOpcodeList1Offset); 3826 3827 } 3828 3829 if (rawIFD.fOpcodeList2Count) 3830 { 3831 3832 #if qDNGValidate 3833 3834 if (gVerbose) 3835 { 3836 printf ("\nParsing OpcodeList2: "); 3837 } 3838 3839 #endif 3840 3841 fOpcodeList2.Parse (host, 3842 stream, 3843 rawIFD.fOpcodeList2Count, 3844 rawIFD.fOpcodeList2Offset); 3845 3846 } 3847 3848 if (rawIFD.fOpcodeList3Count) 3849 { 3850 3851 #if qDNGValidate 3852 3853 if (gVerbose) 3854 { 3855 printf ("\nParsing OpcodeList3: "); 3856 } 3857 3858 #endif 3859 3860 fOpcodeList3.Parse (host, 3861 stream, 3862 rawIFD.fOpcodeList3Count, 3863 rawIFD.fOpcodeList3Offset); 3864 3865 } 3866 3867 } 3868 3869 /*****************************************************************************/ 3870 3871 void dng_negative::ReadStage1Image (dng_host &host, 3872 dng_stream &stream, 3873 dng_info &info) 3874 { 3875 3876 // Allocate image we are reading. 3877 3878 dng_ifd &rawIFD = *info.fIFD [info.fMainIndex]; 3879 3880 fStage1Image.Reset (host.Make_dng_image (rawIFD.Bounds (), 3881 rawIFD.fSamplesPerPixel, 3882 rawIFD.PixelType ())); 3883 3884 // See if we should grab the compressed JPEG data. 3885 3886 AutoPtr<dng_jpeg_image> jpegImage; 3887 3888 if (host.SaveDNGVersion () >= dngVersion_1_4_0_0 && 3889 !host.PreferredSize () && 3890 !host.ForPreview () && 3891 rawIFD.fCompression == ccLossyJPEG) 3892 { 3893 3894 jpegImage.Reset (new dng_jpeg_image); 3895 3896 } 3897 3898 // See if we need to compute the digest of the compressed JPEG data 3899 // while reading. 3900 3901 bool needJPEGDigest = (RawImageDigest ().IsValid () || 3902 NewRawImageDigest ().IsValid ()) && 3903 rawIFD.fCompression == ccLossyJPEG && 3904 jpegImage.Get () == NULL; 3905 3906 dng_fingerprint jpegDigest; 3907 3908 // Read the image. 3909 3910 rawIFD.ReadImage (host, 3911 stream, 3912 *fStage1Image.Get (), 3913 jpegImage.Get (), 3914 needJPEGDigest ? &jpegDigest : NULL); 3915 3916 // Remember the raw floating point bit depth, if reading from 3917 // a floating point image. 3918 3919 if (fStage1Image->PixelType () == ttFloat) 3920 { 3921 3922 SetRawFloatBitDepth (rawIFD.fBitsPerSample [0]); 3923 3924 } 3925 3926 // Remember the compressed JPEG data if we read it. 3927 3928 if (jpegImage.Get ()) 3929 { 3930 3931 SetRawJPEGImage (jpegImage); 3932 3933 } 3934 3935 // Remember the compressed JPEG digest if we computed it. 3936 3937 if (jpegDigest.IsValid ()) 3938 { 3939 3940 SetRawJPEGImageDigest (jpegDigest); 3941 3942 } 3943 3944 // We are are reading the main image, we should read the opcode lists 3945 // also. 3946 3947 ReadOpcodeLists (host, 3948 stream, 3949 info); 3950 3951 } 3952 3953 /*****************************************************************************/ 3954 3955 void dng_negative::ReadEnhancedImage (dng_host &host, 3956 dng_stream &stream, 3957 dng_info &info) 3958 { 3959 3960 // Allocate image we are reading. 3961 3962 dng_ifd &enhancedIFD = *info.fIFD [info.fEnhancedIndex]; 3963 3964 fStage3Image.Reset (host.Make_dng_image (enhancedIFD.Bounds (), 3965 enhancedIFD.fSamplesPerPixel, 3966 enhancedIFD.PixelType ())); 3967 3968 // Read the image. 3969 3970 enhancedIFD.ReadImage (host, 3971 stream, 3972 *fStage3Image.Get ()); 3973 3974 // Remember the enhance parameters. 3975 3976 SetEnhanceParams (enhancedIFD.fEnhanceParams); 3977 3978 // Stage 3 black level. 3979 3980 SetStage3BlackLevel ((uint16) Round_uint32 (enhancedIFD.fBlackLevel [0] [0] [0])); 3981 3982 // We are are reading the enhanced image, we should read the opcode lists 3983 // also, since we at least need to know about lens opcodes. 3984 3985 ReadOpcodeLists (host, 3986 stream, 3987 info); 3988 3989 // Should we read the raw image also? 3990 3991 bool needRawImage = host.SaveDNGVersion () != 0 && 3992 !host.SaveLinearDNG (*this); 3993 3994 // Read in raw image data if required. 3995 3996 if (needRawImage) 3997 { 3998 3999 dng_ifd &mainIFD = *info.fIFD [info.fMainIndex]; 4000 4001 fRawImage.Reset (host.Make_dng_image (mainIFD.Bounds (), 4002 mainIFD.fSamplesPerPixel, 4003 mainIFD.PixelType ())); 4004 4005 mainIFD.ReadImage (host, 4006 stream, 4007 *fRawImage.Get ()); 4008 4009 } 4010 4011 // Baseline sharpness. 4012 4013 if (enhancedIFD.fBaselineSharpness.IsValid ()) 4014 { 4015 4016 SetRawBaselineSharpness (); 4017 4018 fBaselineSharpness = enhancedIFD.fBaselineSharpness; 4019 4020 } 4021 4022 // Noise reduction applied. 4023 4024 if (enhancedIFD.fNoiseReductionApplied.IsValid ()) 4025 { 4026 4027 SetRawNoiseReductionApplied (); 4028 4029 fNoiseReductionApplied = enhancedIFD.fNoiseReductionApplied; 4030 4031 } 4032 4033 // Noise profile. 4034 4035 if (enhancedIFD.fNoiseProfile.IsValidForNegative (*this)) 4036 { 4037 4038 SetRawNoiseProfile (); 4039 4040 fNoiseProfile = enhancedIFD.fNoiseProfile; 4041 4042 } 4043 4044 // Raw to full scale. 4045 4046 if (fLinearizationInfo.Get ()) 4047 { 4048 4049 if (fLinearizationInfo->fActiveArea.W ()) 4050 { 4051 fRawToFullScaleH = (real64) fStage3Image->Bounds ().W () / 4052 (real64) fLinearizationInfo->fActiveArea.W (); 4053 } 4054 4055 if (fLinearizationInfo->fActiveArea.H ()) 4056 { 4057 fRawToFullScaleV = (real64) fStage3Image->Bounds ().H () / 4058 (real64) fLinearizationInfo->fActiveArea.H (); 4059 } 4060 4061 } 4062 4063 if (!needRawImage) 4064 { 4065 4066 ClearLinearizationInfo (); 4067 4068 ClearMosaicInfo (); 4069 4070 fOpcodeList1.Clear (); 4071 fOpcodeList2.Clear (); 4072 fOpcodeList3.Clear (); 4073 4074 fRawImageDigest .Clear (); 4075 fNewRawImageDigest.Clear (); 4076 4077 fRawBaselineSharpness .Clear (); 4078 fRawNoiseReductionApplied.Clear (); 4079 4080 fRawNoiseProfile = dng_noise_profile (); 4081 4082 if (fRawDataUniqueID.IsValid ()) 4083 { 4084 fRawDataUniqueID = RawDataUniqueID (); 4085 } 4086 4087 fEnhanceParams.Clear (); 4088 4089 } 4090 4091 } 4092 4093 /*****************************************************************************/ 4094 4095 void dng_negative::SetStage1Image (AutoPtr<dng_image> &image) 4096 { 4097 4098 fStage1Image.Reset (image.Release ()); 4099 4100 } 4101 4102 /*****************************************************************************/ 4103 4104 void dng_negative::SetStage2Image (AutoPtr<dng_image> &image) 4105 { 4106 4107 fStage2Image.Reset (image.Release ()); 4108 4109 } 4110 4111 /*****************************************************************************/ 4112 4113 void dng_negative::SetStage3Image (AutoPtr<dng_image> &image) 4114 { 4115 4116 fStage3Image.Reset (image.Release ()); 4117 4118 SetFloatingPoint (fStage3Image.Get () && 4119 (fStage3Image->PixelType () == ttFloat)); 4120 4121 } 4122 4123 /*****************************************************************************/ 4124 4125 void dng_negative::DoBuildStage2 (dng_host &host) 4126 { 4127 4128 dng_image &stage1 = *fStage1Image.Get (); 4129 4130 dng_linearization_info &info = *fLinearizationInfo.Get (); 4131 4132 uint32 pixelType = ttShort; 4133 4134 if (stage1.PixelType () == ttLong || 4135 stage1.PixelType () == ttFloat) 4136 { 4137 4138 pixelType = ttFloat; 4139 4140 } 4141 4142 fStage2Image.Reset (host.Make_dng_image (info.fActiveArea.Size (), 4143 stage1.Planes (), 4144 pixelType)); 4145 4146 info.Linearize (host, 4147 *this, 4148 stage1, 4149 *fStage2Image.Get ()); 4150 4151 } 4152 4153 /*****************************************************************************/ 4154 4155 void dng_negative::DoPostOpcodeList2 (dng_host & /* host */) 4156 { 4157 4158 // Nothing by default. 4159 4160 } 4161 4162 /*****************************************************************************/ 4163 4164 bool dng_negative::NeedDefloatStage2 (dng_host &host) 4165 { 4166 4167 if (fStage2Image->PixelType () == ttFloat) 4168 { 4169 4170 if (fRawImageStage >= rawImageStagePostOpcode2 && 4171 host.SaveDNGVersion () != dngVersion_None && 4172 host.SaveDNGVersion () < dngVersion_1_4_0_0) 4173 { 4174 4175 return true; 4176 4177 } 4178 4179 } 4180 4181 return false; 4182 4183 } 4184 4185 /*****************************************************************************/ 4186 4187 void dng_negative::DefloatStage2 (dng_host & /* host */) 4188 { 4189 4190 ThrowNotYetImplemented ("dng_negative::DefloatStage2"); 4191 4192 } 4193 4194 /*****************************************************************************/ 4195 4196 void dng_negative::BuildStage2Image (dng_host &host) 4197 { 4198 4199 // If reading the negative to save in DNG format, figure out 4200 // when to grab a copy of the raw data. 4201 4202 if (host.SaveDNGVersion () != dngVersion_None) 4203 { 4204 4205 // Transparency masks are only supported in DNG version 1.4 and 4206 // later. In this case, the flattening of the transparency mask happens 4207 // on the stage3 image. 4208 4209 if (TransparencyMask () && host.SaveDNGVersion () < dngVersion_1_4_0_0) 4210 { 4211 fRawImageStage = rawImageStagePostOpcode3; 4212 } 4213 4214 else if (fOpcodeList3.MinVersion (false) > host.SaveDNGVersion () || 4215 fOpcodeList3.AlwaysApply ()) 4216 { 4217 fRawImageStage = rawImageStagePostOpcode3; 4218 } 4219 4220 // If we are not doing a full resolution read, then always save the DNG 4221 // from the processed stage 3 image. 4222 4223 else if (host.PreferredSize ()) 4224 { 4225 fRawImageStage = rawImageStagePostOpcode3; 4226 } 4227 4228 else if (host.SaveLinearDNG (*this)) 4229 { 4230 4231 // If the opcode list 3 has optional tags that are beyond the 4232 // the minimum version, and we are saving a linear DNG anyway, 4233 // then go ahead and apply them. 4234 4235 if (fOpcodeList3.MinVersion (true) > host.SaveDNGVersion ()) 4236 { 4237 fRawImageStage = rawImageStagePostOpcode3; 4238 } 4239 4240 else 4241 { 4242 fRawImageStage = rawImageStagePreOpcode3; 4243 } 4244 4245 } 4246 4247 else if (fOpcodeList2.MinVersion (false) > host.SaveDNGVersion () || 4248 fOpcodeList2.AlwaysApply ()) 4249 { 4250 fRawImageStage = rawImageStagePostOpcode2; 4251 } 4252 4253 else if (fOpcodeList1.MinVersion (false) > host.SaveDNGVersion () || 4254 fOpcodeList1.AlwaysApply ()) 4255 { 4256 fRawImageStage = rawImageStagePostOpcode1; 4257 } 4258 4259 else 4260 { 4261 fRawImageStage = rawImageStagePreOpcode1; 4262 } 4263 4264 // We should not save floating point stage1 images unless the target 4265 // DNG version is high enough to understand floating point images. 4266 // We handle this by converting from floating point to integer if 4267 // required after building stage2 image. 4268 4269 if (fStage1Image->PixelType () == ttFloat) 4270 { 4271 4272 if (fRawImageStage < rawImageStagePostOpcode2) 4273 { 4274 4275 if (host.SaveDNGVersion () < dngVersion_1_4_0_0) 4276 { 4277 4278 fRawImageStage = rawImageStagePostOpcode2; 4279 4280 } 4281 4282 } 4283 4284 } 4285 4286 // If the host is requesting a negative read for fast conversion to 4287 // DNG, then check whether we can actually do a fast interpolation or 4288 // not. For now, keep the logic simple. If the raw image stage is the 4289 // pre-opcode stage 1 image (original), then proceed with trying a 4290 // fast/downsampled interpolation when building the stage 3 image. 4291 // Otherwise, turn off the attempted optimization. 4292 4293 if (host.ForFastSaveToDNG () && 4294 (fRawImageStage > rawImageStagePreOpcode1)) 4295 { 4296 4297 // Disable/revert the optimization attempt, and do a normal 4298 // interpolation when building the stage 3 image. 4299 4300 host.SetForFastSaveToDNG (false, 0); 4301 4302 } 4303 4304 } 4305 4306 // Grab clone of raw image if required. 4307 4308 if (fRawImageStage == rawImageStagePreOpcode1) 4309 { 4310 4311 fRawImage.Reset (fStage1Image->Clone ()); 4312 4313 if (fTransparencyMask.Get ()) 4314 { 4315 fRawTransparencyMask.Reset (fTransparencyMask->Clone ()); 4316 } 4317 4318 if (fDepthMap.Get ()) 4319 { 4320 fRawDepthMap.Reset (fDepthMap->Clone ()); 4321 } 4322 4323 } 4324 4325 else 4326 { 4327 4328 // If we are not keeping the most raw image, we need 4329 // to recompute the raw image digest. 4330 4331 ClearRawImageDigest (); 4332 4333 // If we don't grab the unprocessed stage 1 image, then 4334 // the raw JPEG image is no longer valid. 4335 4336 ClearRawJPEGImage (); 4337 4338 // Nor is the digest of the raw JPEG data. 4339 4340 ClearRawJPEGImageDigest (); 4341 4342 // We also don't know the raw floating point bit depth. 4343 4344 SetRawFloatBitDepth (0); 4345 4346 } 4347 4348 // Process opcode list 1. 4349 4350 host.ApplyOpcodeList (fOpcodeList1, *this, fStage1Image); 4351 4352 // See if we are done with the opcode list 1. 4353 4354 if (fRawImageStage > rawImageStagePreOpcode1) 4355 { 4356 4357 fOpcodeList1.Clear (); 4358 4359 } 4360 4361 // Grab clone of raw image if required. 4362 4363 if (fRawImageStage == rawImageStagePostOpcode1) 4364 { 4365 4366 fRawImage.Reset (fStage1Image->Clone ()); 4367 4368 if (fTransparencyMask.Get ()) 4369 { 4370 fRawTransparencyMask.Reset (fTransparencyMask->Clone ()); 4371 } 4372 4373 if (fDepthMap.Get ()) 4374 { 4375 fRawDepthMap.Reset (fDepthMap->Clone ()); 4376 } 4377 4378 } 4379 4380 // Finalize linearization info. 4381 4382 { 4383 4384 NeedLinearizationInfo (); 4385 4386 dng_linearization_info &info = *fLinearizationInfo.Get (); 4387 4388 info.PostParse (host, *this); 4389 4390 } 4391 4392 // Perform the linearization. 4393 4394 DoBuildStage2 (host); 4395 4396 // Delete the stage1 image now that we have computed the stage 2 image. 4397 4398 fStage1Image.Reset (); 4399 4400 // Are we done with the linearization info. 4401 4402 if (fRawImageStage > rawImageStagePostOpcode1) 4403 { 4404 4405 ClearLinearizationInfo (); 4406 4407 } 4408 4409 // Process opcode list 2. 4410 4411 host.ApplyOpcodeList (fOpcodeList2, *this, fStage2Image); 4412 4413 // See if we are done with the opcode list 2. 4414 4415 if (fRawImageStage > rawImageStagePostOpcode1) 4416 { 4417 4418 fOpcodeList2.Clear (); 4419 4420 } 4421 4422 // Hook for any required processing just after opcode list 2. 4423 4424 DoPostOpcodeList2 (host); 4425 4426 // Convert from floating point to integer if required. 4427 4428 if (NeedDefloatStage2 (host)) 4429 { 4430 4431 DefloatStage2 (host); 4432 4433 } 4434 4435 // Grab clone of raw image if required. 4436 4437 if (fRawImageStage == rawImageStagePostOpcode2) 4438 { 4439 4440 fRawImage.Reset (fStage2Image->Clone ()); 4441 4442 fRawImageBlackLevel = fStage3BlackLevel; 4443 4444 if (fTransparencyMask.Get ()) 4445 { 4446 fRawTransparencyMask.Reset (fTransparencyMask->Clone ()); 4447 } 4448 4449 if (fDepthMap.Get ()) 4450 { 4451 fRawDepthMap.Reset (fDepthMap->Clone ()); 4452 } 4453 4454 } 4455 4456 } 4457 4458 /*****************************************************************************/ 4459 4460 void dng_negative::DoInterpolateStage3 (dng_host &host, 4461 int32 srcPlane, 4462 dng_matrix *scaleTransforms) 4463 { 4464 4465 dng_image &stage2 = *fStage2Image.Get (); 4466 4467 dng_mosaic_info &info = *fMosaicInfo.Get (); 4468 4469 dng_point downScale; 4470 4471 const bool fastSaveToDNG = host.ForFastSaveToDNG (); 4472 4473 const uint32 fastSaveSize = host.FastSaveToDNGSize (); 4474 4475 if (fastSaveToDNG && (fastSaveSize > 0)) 4476 { 4477 4478 downScale = info.DownScale (host.MinimumSize (), 4479 host.FastSaveToDNGSize (), 4480 host.CropFactor ()); 4481 4482 } 4483 4484 else 4485 { 4486 4487 downScale = info.DownScale (host.MinimumSize (), 4488 host.PreferredSize (), 4489 host.CropFactor ()); 4490 4491 } 4492 4493 if (downScale != dng_point (1, 1)) 4494 { 4495 SetIsPreview (true); 4496 } 4497 4498 dng_point dstSize = info.DstSize (downScale); 4499 4500 fStage3Image.Reset (host.Make_dng_image (dng_rect (dstSize), 4501 info.fColorPlanes, 4502 stage2.PixelType ())); 4503 4504 if (srcPlane < 0 || srcPlane >= (int32) stage2.Planes ()) 4505 { 4506 srcPlane = 0; 4507 } 4508 4509 info.Interpolate (host, 4510 *this, 4511 stage2, 4512 *fStage3Image.Get (), 4513 downScale, 4514 srcPlane, 4515 scaleTransforms); 4516 4517 } 4518 4519 /*****************************************************************************/ 4520 4521 // Interpolate and merge a multi-channel CFA image. 4522 4523 void dng_negative::DoMergeStage3 (dng_host &host, 4524 dng_matrix *scaleTransforms) 4525 { 4526 4527 // The DNG SDK does not provide multi-channel CFA image merging code. 4528 // It just grabs the first channel and uses that. 4529 4530 DoInterpolateStage3 (host, 0, scaleTransforms); 4531 4532 // Just grabbing the first channel would often result in the very 4533 // bright image using the baseline exposure value. 4534 4535 fStage3Gain = pow (2.0, BaselineExposure ()); 4536 4537 } 4538 4539 /*****************************************************************************/ 4540 4541 void dng_negative::DoBuildStage3 (dng_host &host, 4542 int32 srcPlane, 4543 dng_matrix *scaleTransforms) 4544 { 4545 4546 // If we don't have a mosaic pattern, then just move the stage 2 4547 // image on to stage 3. 4548 4549 dng_mosaic_info *info = fMosaicInfo.Get (); 4550 4551 if (!info || !info->IsColorFilterArray ()) 4552 { 4553 4554 fStage3Image.Reset (fStage2Image.Release ()); 4555 4556 } 4557 4558 else 4559 { 4560 4561 // Remember the size of the stage 2 image. 4562 4563 dng_point stage2_size = fStage2Image->Size (); 4564 4565 // Special case multi-channel CFA interpolation. 4566 4567 if ((fStage2Image->Planes () > 1) && (srcPlane < 0)) 4568 { 4569 4570 DoMergeStage3 (host, 4571 scaleTransforms); 4572 4573 } 4574 4575 // Else do a single channel interpolation. 4576 4577 else 4578 { 4579 4580 DoInterpolateStage3 (host, 4581 srcPlane, 4582 scaleTransforms); 4583 4584 } 4585 4586 // Calculate the ratio of the stage 3 image size to stage 2 image size. 4587 4588 dng_point stage3_size = fStage3Image->Size (); 4589 4590 fRawToFullScaleH = (real64) stage3_size.h / (real64) stage2_size.h; 4591 fRawToFullScaleV = (real64) stage3_size.v / (real64) stage2_size.v; 4592 4593 } 4594 4595 } 4596 4597 /*****************************************************************************/ 4598 4599 void dng_negative::BuildStage3Image (dng_host &host, 4600 int32 srcPlane) 4601 { 4602 4603 // Finalize the mosaic information. 4604 4605 dng_mosaic_info *info = fMosaicInfo.Get (); 4606 4607 if (info) 4608 { 4609 4610 info->PostParse (host, *this); 4611 4612 } 4613 4614 // Do the interpolation as required. 4615 4616 DoBuildStage3 (host, srcPlane, NULL); 4617 4618 // Delete the stage2 image now that we have computed the stage 3 image, 4619 // unless the host wants to preserve it. 4620 4621 if (!host.WantsPreserveStage2 ()) 4622 { 4623 4624 fStage2Image.Reset (); 4625 4626 } 4627 4628 // Are we done with the mosaic info? 4629 4630 if (fRawImageStage >= rawImageStagePreOpcode3) 4631 { 4632 4633 // If we're preserving the stage 2 image, also preserve the mosaic 4634 // info. 4635 4636 if (!host.WantsPreserveStage2 ()) 4637 { 4638 4639 ClearMosaicInfo (); 4640 4641 } 4642 4643 // To support saving linear DNG files, to need to account for 4644 // and upscaling during interpolation. 4645 4646 if (fRawToFullScaleH > 1.0) 4647 { 4648 4649 uint32 adjust = Round_uint32 (fRawToFullScaleH); 4650 4651 fDefaultCropSizeH .n *= adjust; 4652 fDefaultCropOriginH.n *= adjust; 4653 fDefaultScaleH .d *= adjust; 4654 4655 fRawToFullScaleH /= (real64) adjust; 4656 4657 } 4658 4659 if (fRawToFullScaleV > 1.0) 4660 { 4661 4662 uint32 adjust = Round_uint32 (fRawToFullScaleV); 4663 4664 fDefaultCropSizeV .n *= adjust; 4665 fDefaultCropOriginV.n *= adjust; 4666 fDefaultScaleV .d *= adjust; 4667 4668 fRawToFullScaleV /= (real64) adjust; 4669 4670 } 4671 4672 } 4673 4674 // Resample the transparency mask if required. 4675 4676 ResizeTransparencyToMatchStage3 (host); 4677 4678 // Grab clone of raw image if required. 4679 4680 if (fRawImageStage == rawImageStagePreOpcode3) 4681 { 4682 4683 fRawImage.Reset (fStage3Image->Clone ()); 4684 4685 fRawImageBlackLevel = fStage3BlackLevel; 4686 4687 if (fTransparencyMask.Get ()) 4688 { 4689 fRawTransparencyMask.Reset (fTransparencyMask->Clone ()); 4690 } 4691 4692 if (fDepthMap.Get ()) 4693 { 4694 fRawDepthMap.Reset (fDepthMap->Clone ()); 4695 } 4696 4697 } 4698 4699 // Process opcode list 3. 4700 4701 host.ApplyOpcodeList (fOpcodeList3, *this, fStage3Image); 4702 4703 // See if we are done with the opcode list 3. 4704 4705 if (fRawImageStage > rawImageStagePreOpcode3) 4706 { 4707 4708 // Currently re-use the same flag for preserving the opcode list. 4709 4710 if (!host.WantsPreserveStage2 ()) 4711 { 4712 4713 fOpcodeList3.Clear (); 4714 4715 } 4716 4717 } 4718 4719 // Just in case the opcode list 3 changed the image size, resample the 4720 // transparency mask again if required. This is nearly always going 4721 // to be a fast NOP operation. 4722 4723 ResizeTransparencyToMatchStage3 (host); 4724 4725 // Depth maps are often lower resolution than the main image, 4726 // so make sure we upsample if required. 4727 4728 ResizeDepthToMatchStage3 (host); 4729 4730 // Update Floating Point flag. 4731 4732 SetFloatingPoint (fStage3Image->PixelType () == ttFloat); 4733 4734 // Don't need to grab a copy of raw data at this stage since 4735 // it is kept around as the stage 3 image. 4736 4737 } 4738 4739 /******************************************************************************/ 4740 4741 // RESEARCH: Instead of using a constant slope, consider using a family 4742 // of slopes ranging from the original one (1/16) to a limit of 1/128, 4743 // depending on the histogram distribution. 4744 4745 static const real64 kSceneProxyCurveSlope = 1.0 / 128.0; 4746 4747 static inline real64 SceneProxyCurve (real64 x) 4748 { 4749 4750 // The following code evaluates the inverse of: 4751 // 4752 // f (x) = (s * x) + ((1 - s) * x^3) 4753 // 4754 // where s is the slope of the function at the origin (x==0). 4755 4756 static const real64 s = kSceneProxyCurveSlope; 4757 4758 static const real64 k0 = pow (2.0, 1.0 / 3.0); 4759 4760 static const real64 k1 = 108.0 * s * s * s * (1.0 - s) * (1.0 - s) * (1.0 - s); 4761 4762 real64 k2 = (27.0 * x) - (54.0 * s * x) + (27.0 * x * s * s); 4763 4764 real64 k3 = pow (k2 + sqrt (k1 + k2 * k2), 1.0 / 3.0); 4765 4766 real64 y = (k3 / (3.0 * k0 * (1.0 - s))) - (k0 * s / k3); 4767 4768 y = Pin_real64 (0.0, y, 1.0); 4769 4770 DNG_ASSERT (Abs_real64 (x - (kSceneProxyCurveSlope * y + 4771 (1.0 - kSceneProxyCurveSlope) * y * y * y)) < 0.0000001, 4772 "SceneProxyCurve round trip error"); 4773 4774 return y; 4775 4776 } 4777 4778 /*****************************************************************************/ 4779 4780 static const real64 kOutputProxyCurveSlope = 1.0 / 16.0; 4781 4782 static inline real64 OutputProxyCurve (real64 x) 4783 { 4784 4785 DNG_ASSERT (kOutputProxyCurveSlope == 1.0 / 16.0, 4786 "OutputProxyCurve unexpected slope"); 4787 4788 real64 y = (sqrt (960.0 * x + 1.0) - 1.0) / 30.0; 4789 4790 DNG_ASSERT (Abs_real64 (x - (kOutputProxyCurveSlope * y + 4791 (1.0 - kOutputProxyCurveSlope) * y * y)) < 0.0000001, 4792 "OutputProxyCurve round trip error"); 4793 4794 return y; 4795 4796 } 4797 4798 /*****************************************************************************/ 4799 4800 class dng_gamma_encode_proxy : public dng_1d_function 4801 { 4802 4803 private: 4804 4805 real64 fLower; 4806 real64 fUpper; 4807 4808 bool fIsSceneReferred; 4809 4810 real64 fStage3BlackLevel; 4811 4812 real64 fBlackLevel; 4813 4814 public: 4815 4816 dng_gamma_encode_proxy (real64 lower, 4817 real64 upper, 4818 bool isSceneReferred, 4819 real64 stage3BlackLevel, 4820 real64 blackLevel) 4821 4822 : fLower (lower) 4823 , fUpper (upper) 4824 , fIsSceneReferred (isSceneReferred) 4825 , fStage3BlackLevel (stage3BlackLevel) 4826 , fBlackLevel (blackLevel / 255.0) 4827 4828 { 4829 4830 } 4831 4832 virtual real64 Evaluate (real64 x) const 4833 { 4834 4835 real64 y; 4836 4837 if (fIsSceneReferred) 4838 { 4839 4840 if (fLower < fStage3BlackLevel) 4841 { 4842 4843 x = Pin_real64 (-1.0, 4844 (x - fStage3BlackLevel) / (fUpper - fStage3BlackLevel), 4845 1.0); 4846 4847 if (x >= 0.0) 4848 { 4849 4850 y = SceneProxyCurve (x); 4851 4852 } 4853 4854 else 4855 { 4856 4857 y = -SceneProxyCurve (-x); 4858 4859 } 4860 4861 y = Pin_real64 (0.0, y * (1.0 - fBlackLevel) + fBlackLevel, 1.0); 4862 4863 } 4864 4865 else 4866 { 4867 4868 x = Pin_real64 (0.0, (x - fLower) / (fUpper - fLower), 1.0); 4869 4870 y = SceneProxyCurve (x); 4871 4872 } 4873 4874 } 4875 4876 else 4877 { 4878 4879 x = Pin_real64 (0.0, (x - fLower) / (fUpper - fLower), 1.0); 4880 4881 y = OutputProxyCurve (x); 4882 4883 } 4884 4885 return y; 4886 4887 } 4888 4889 }; 4890 4891 /*****************************************************************************/ 4892 4893 class dng_encode_proxy_task: public dng_area_task, 4894 private dng_uncopyable 4895 { 4896 4897 private: 4898 4899 const dng_image &fSrcImage; 4900 4901 dng_image &fDstImage; 4902 4903 AutoPtr<dng_memory_block> fTable16 [kMaxColorPlanes]; 4904 4905 public: 4906 4907 dng_encode_proxy_task (dng_host &host, 4908 const dng_image &srcImage, 4909 dng_image &dstImage, 4910 const real64 *lower, 4911 const real64 *upper, 4912 bool isSceneReferred, 4913 real64 stage3BlackLevel, 4914 real64 *blackLevel); 4915 4916 virtual dng_rect RepeatingTile1 () const 4917 { 4918 return fSrcImage.RepeatingTile (); 4919 } 4920 4921 virtual dng_rect RepeatingTile2 () const 4922 { 4923 return fDstImage.RepeatingTile (); 4924 } 4925 4926 virtual void Process (uint32 threadIndex, 4927 const dng_rect &tile, 4928 dng_abort_sniffer *sniffer); 4929 4930 }; 4931 4932 /*****************************************************************************/ 4933 4934 dng_encode_proxy_task::dng_encode_proxy_task (dng_host &host, 4935 const dng_image &srcImage, 4936 dng_image &dstImage, 4937 const real64 *lower, 4938 const real64 *upper, 4939 bool isSceneReferred, 4940 real64 stage3BlackLevel, 4941 real64 *blackLevel) 4942 4943 : dng_area_task ("dng_encode_proxy_task") 4944 4945 , fSrcImage (srcImage) 4946 , fDstImage (dstImage) 4947 4948 { 4949 4950 for (uint32 plane = 0; plane < fSrcImage.Planes (); plane++) 4951 { 4952 4953 fTable16 [plane] . Reset (host.Allocate (0x10000 * sizeof (uint16))); 4954 4955 dng_gamma_encode_proxy gamma (lower [plane], 4956 upper [plane], 4957 isSceneReferred, 4958 stage3BlackLevel, 4959 blackLevel [plane]); 4960 4961 // Compute fast approximation of encoding table. 4962 4963 dng_1d_table table32; 4964 4965 table32.Initialize (host.Allocator (), gamma); 4966 4967 table32.Expand16 (fTable16 [plane]->Buffer_uint16 ()); 4968 4969 // The gamma curve has some fairly high curvature near 4970 // the black point, and the above approximation can actually 4971 // change results. So use exact math near the black point. 4972 // Still very fast, since we are only computing a small 4973 // faction of the range exactly. 4974 4975 { 4976 4977 const int32 kHighResRadius = 1024; 4978 4979 uint32 zeroPt = Round_uint32 (stage3BlackLevel * 65535.0); 4980 4981 uint32 highResLower = Max_int32 (0 , zeroPt - kHighResRadius); 4982 uint32 highResUpper = Min_int32 (0x10000, zeroPt + kHighResRadius); 4983 4984 for (uint32 j = highResLower; j < highResUpper; j++) 4985 { 4986 4987 real64 x = j * (1.0 / 65535.0); 4988 4989 real64 y = gamma.Evaluate (x); 4990 4991 uint16 z = Pin_uint16 (Round_int32 (y * 65535.0)); 4992 4993 fTable16 [plane]->Buffer_uint16 () [j] = z; 4994 4995 } 4996 4997 } 4998 4999 } 5000 5001 } 5002 5003 /*****************************************************************************/ 5004 5005 void dng_encode_proxy_task::Process (uint32 /* threadIndex */, 5006 const dng_rect &tile, 5007 dng_abort_sniffer * /* sniffer */) 5008 { 5009 5010 dng_const_tile_buffer srcBuffer (fSrcImage, tile); 5011 dng_dirty_tile_buffer dstBuffer (fDstImage, tile); 5012 5013 int32 sColStep = srcBuffer.fColStep; 5014 int32 dColStep = dstBuffer.fColStep; 5015 5016 const uint16 *noise = dng_dither::Get ().NoiseBuffer16 (); 5017 5018 for (uint32 plane = 0; plane < fSrcImage.Planes (); plane++) 5019 { 5020 5021 const uint16 *map = fTable16 [plane]->Buffer_uint16 (); 5022 5023 for (int32 row = tile.t; row < tile.b; row++) 5024 { 5025 5026 const uint16 *sPtr = srcBuffer.ConstPixel_uint16 (row, tile.l, plane); 5027 5028 uint8 *dPtr = dstBuffer.DirtyPixel_uint8 (row, tile.l, plane); 5029 5030 const uint16 *rPtr = &noise [(row & dng_dither::kRNGMask) * dng_dither::kRNGSize]; 5031 5032 for (int32 col = tile.l; col < tile.r; col++) 5033 { 5034 5035 uint32 x = *sPtr; 5036 5037 uint32 r = rPtr [col & dng_dither::kRNGMask]; 5038 5039 x = map [x]; 5040 5041 x = (((x << 8) - x) + r) >> 16; 5042 5043 *dPtr = (uint8) x; 5044 5045 sPtr += sColStep; 5046 dPtr += dColStep; 5047 5048 } 5049 5050 } 5051 5052 } 5053 5054 } 5055 5056 /******************************************************************************/ 5057 5058 bool dng_negative::SupportsPreservedBlackLevels (dng_host & /* host */) 5059 { 5060 5061 return false; 5062 5063 } 5064 5065 /******************************************************************************/ 5066 5067 dng_image * dng_negative::EncodeRawProxy (dng_host &host, 5068 const dng_image &srcImage, 5069 dng_opcode_list &opcodeList, 5070 real64 *blackLevel) const 5071 { 5072 5073 if (srcImage.PixelType () != ttShort) 5074 { 5075 return NULL; 5076 } 5077 5078 real64 lower [kMaxColorPlanes]; 5079 real64 upper [kMaxColorPlanes]; 5080 5081 { 5082 5083 const real64 kClipFraction = 0.00001; 5084 5085 uint64 pixels = (uint64) srcImage.Bounds ().H () * 5086 (uint64) srcImage.Bounds ().W (); 5087 5088 uint32 limit = Round_int32 ((real64) pixels * kClipFraction); 5089 5090 AutoPtr<dng_memory_block> histData (host.Allocate (65536 * sizeof (uint32))); 5091 5092 uint32 *hist = histData->Buffer_uint32 (); 5093 5094 for (uint32 plane = 0; plane < srcImage.Planes (); plane++) 5095 { 5096 5097 HistogramArea (host, 5098 srcImage, 5099 srcImage.Bounds (), 5100 hist, 5101 65535, 5102 plane); 5103 5104 uint32 total = 0; 5105 5106 uint32 upperIndex = 65535; 5107 5108 while (total + hist [upperIndex] <= limit && upperIndex > 255) 5109 { 5110 5111 total += hist [upperIndex]; 5112 5113 upperIndex--; 5114 5115 } 5116 5117 total = 0; 5118 5119 uint32 lowerIndex = 0; 5120 5121 while (total + hist [lowerIndex] <= limit && lowerIndex < upperIndex - 255) 5122 { 5123 5124 total += hist [lowerIndex]; 5125 5126 lowerIndex++; 5127 5128 } 5129 5130 lower [plane] = lowerIndex / 65535.0; 5131 upper [plane] = upperIndex / 65535.0; 5132 5133 } 5134 5135 } 5136 5137 bool isSceneReferred = (ColorimetricReference () == crSceneReferred); 5138 5139 real64 stage3BlackLevel = Stage3BlackLevelNormalized (); 5140 5141 for (uint32 n = 0; n < kMaxSamplesPerPixel; n++) 5142 { 5143 blackLevel [n] = 0.0; 5144 } 5145 5146 if (isSceneReferred && stage3BlackLevel > 0.0) 5147 { 5148 5149 for (uint32 plane = 0; plane < srcImage.Planes (); plane++) 5150 { 5151 5152 if (lower [plane] < stage3BlackLevel) 5153 { 5154 5155 upper [plane] = Max_real64 (upper [plane], 5156 stage3BlackLevel + 5157 (stage3BlackLevel - lower [plane]) * 5158 (1.0 / kMaxStage3BlackLevelNormalized - 1.0)); 5159 5160 upper [plane] = Min_real64 (upper [plane], 1.0); 5161 5162 real64 negRange = SceneProxyCurve ((stage3BlackLevel - lower [plane]) / 5163 (upper [plane] - stage3BlackLevel)); 5164 5165 real64 outBlack = negRange / (1.0 + negRange); 5166 5167 blackLevel [plane] = Min_real64 (kMaxStage3BlackLevelNormalized * 255.0, 5168 ceil (outBlack * 255.0)); 5169 5170 } 5171 5172 } 5173 5174 } 5175 5176 // Apply the gamma encoding, using dither when downsampling to 8-bit. 5177 5178 AutoPtr<dng_image> dstImage (host.Make_dng_image (srcImage.Bounds (), 5179 srcImage.Planes (), 5180 ttByte)); 5181 5182 { 5183 5184 dng_encode_proxy_task task (host, 5185 srcImage, 5186 *dstImage, 5187 lower, 5188 upper, 5189 isSceneReferred, 5190 stage3BlackLevel, 5191 blackLevel); 5192 5193 host.PerformAreaTask (task, 5194 srcImage.Bounds ()); 5195 5196 } 5197 5198 // Add opcodes to undo the gamma encoding. 5199 5200 { 5201 5202 for (uint32 plane = 0; plane < srcImage.Planes (); plane++) 5203 { 5204 5205 dng_area_spec areaSpec (srcImage.Bounds (), 5206 plane); 5207 5208 real64 coefficient [4]; 5209 5210 coefficient [0] = 0.0; 5211 5212 if (isSceneReferred) 5213 { 5214 coefficient [1] = kSceneProxyCurveSlope; 5215 coefficient [2] = 0.0; 5216 coefficient [3] = 1.0 - coefficient [1]; 5217 } 5218 else 5219 { 5220 coefficient [1] = kOutputProxyCurveSlope; 5221 coefficient [2] = 1.0 - coefficient [1]; 5222 coefficient [3] = 0.0; 5223 } 5224 5225 if (lower [plane] < stage3BlackLevel) 5226 { 5227 5228 real64 rescale = (upper [plane] - stage3BlackLevel) / (1.0 - stage3BlackLevel); 5229 5230 coefficient [0] *= rescale; 5231 coefficient [1] *= rescale; 5232 coefficient [2] *= rescale; 5233 coefficient [3] *= rescale; 5234 5235 } 5236 5237 else 5238 { 5239 5240 real64 rescale = (upper [plane] - lower [plane]) / (1.0 - stage3BlackLevel); 5241 5242 coefficient [0] *= rescale; 5243 coefficient [1] *= rescale; 5244 coefficient [2] *= rescale; 5245 coefficient [3] *= rescale; 5246 5247 coefficient [0] += (lower [plane] - stage3BlackLevel) / (1.0 - stage3BlackLevel); 5248 5249 } 5250 5251 AutoPtr<dng_opcode> opcode (new dng_opcode_MapPolynomial (areaSpec, 5252 isSceneReferred ? 3 : 2, 5253 coefficient)); 5254 5255 opcodeList.Append (opcode); 5256 5257 } 5258 5259 } 5260 5261 return dstImage.Release (); 5262 5263 } 5264 5265 /******************************************************************************/ 5266 5267 void dng_negative::AdjustProfileForStage3 () 5268 { 5269 5270 // For dng_sdk, the stage3 image's color space is always the same as the 5271 // raw image's color space. 5272 5273 } 5274 5275 /******************************************************************************/ 5276 5277 void dng_negative::ConvertToProxy (dng_host &host, 5278 dng_image_writer &writer, 5279 uint32 proxySize, 5280 uint64 proxyCount) 5281 { 5282 5283 if (!proxySize) 5284 { 5285 proxySize = kMaxImageSide; 5286 } 5287 5288 if (!proxyCount) 5289 { 5290 proxyCount = (uint64) proxySize * proxySize; 5291 } 5292 5293 // Don't need to keep private data around in non-full size proxies. 5294 5295 if (proxySize < kMaxImageSide || 5296 proxyCount < kMaxImageSide * kMaxImageSide) 5297 { 5298 5299 ClearMakerNote (); 5300 5301 ClearPrivateData (); 5302 5303 } 5304 5305 // See if we already have an acceptable proxy image. 5306 5307 if (fRawImage.Get () && 5308 fRawImage->PixelType () == ttByte && 5309 fRawImage->Bounds () == DefaultCropArea () && 5310 fRawImage->Bounds ().H () <= proxySize && 5311 fRawImage->Bounds ().W () <= proxySize && 5312 (uint64) fRawImage->Bounds ().H () * 5313 (uint64) fRawImage->Bounds ().W () <= proxyCount && 5314 fRawToFullScaleH == 1.0 && 5315 fRawToFullScaleV == 1.0 && 5316 (!GetMosaicInfo () || !GetMosaicInfo ()->IsColorFilterArray ()) && 5317 fRawJPEGImage.Get () && 5318 (!RawTransparencyMask () || RawTransparencyMask ()->PixelType () == ttByte)) 5319 { 5320 5321 return; 5322 5323 } 5324 5325 if (fRawImage.Get () && 5326 fRawImage->PixelType () == ttFloat && 5327 fRawImage->Bounds ().H () <= proxySize && 5328 fRawImage->Bounds ().W () <= proxySize && 5329 (uint64) fRawImage->Bounds ().H () * 5330 (uint64) fRawImage->Bounds ().W () <= proxyCount && 5331 fRawToFullScaleH == 1.0 && 5332 fRawToFullScaleV == 1.0 && 5333 RawFloatBitDepth () == 16 && 5334 (!RawTransparencyMask () || RawTransparencyMask ()->PixelType () == ttByte)) 5335 { 5336 5337 return; 5338 5339 } 5340 5341 // Clear any grabbed raw image, since we are going to start 5342 // building the proxy with the stage3 image. 5343 5344 fRawImage.Reset (); 5345 5346 fRawImageBlackLevel = 0; 5347 5348 ClearRawJPEGImage (); 5349 5350 SetRawFloatBitDepth (0); 5351 5352 ClearLinearizationInfo (); 5353 5354 ClearMosaicInfo (); 5355 5356 fOpcodeList1.Clear (); 5357 fOpcodeList2.Clear (); 5358 fOpcodeList3.Clear (); 5359 5360 // Adjust the profile to match the stage 3 image, if required. 5361 5362 AdjustProfileForStage3 (); 5363 5364 // Not saving the raw-most image, do the old raw digest is no 5365 // longer valid. 5366 5367 ClearRawImageDigest (); 5368 5369 ClearRawJPEGImageDigest (); 5370 5371 // Trim off extra pixels outside the default crop area. 5372 5373 dng_rect defaultCropArea = DefaultCropArea (); 5374 5375 if (Stage3Image ()->Bounds () != defaultCropArea) 5376 { 5377 5378 fStage3Image->Trim (defaultCropArea); 5379 5380 if (fTransparencyMask.Get ()) 5381 { 5382 fTransparencyMask->Trim (defaultCropArea); 5383 } 5384 5385 if (fDepthMap.Get ()) 5386 { 5387 fDepthMap->Trim (defaultCropArea); 5388 fRawDepthMap.Reset (); 5389 } 5390 5391 fDefaultCropOriginH = dng_urational (0, 1); 5392 fDefaultCropOriginV = dng_urational (0, 1); 5393 5394 } 5395 5396 // Figure out the requested proxy pixel size. 5397 5398 real64 aspectRatio = AspectRatio (); 5399 5400 dng_point newSize (proxySize, proxySize); 5401 5402 if (aspectRatio >= 1.0) 5403 { 5404 newSize.v = Max_int32 (1, Round_int32 (proxySize / aspectRatio)); 5405 } 5406 else 5407 { 5408 newSize.h = Max_int32 (1, Round_int32 (proxySize * aspectRatio)); 5409 } 5410 5411 newSize.v = Min_int32 (newSize.v, DefaultFinalHeight ()); 5412 newSize.h = Min_int32 (newSize.h, DefaultFinalWidth ()); 5413 5414 if ((uint64) newSize.v * 5415 (uint64) newSize.h > proxyCount) 5416 { 5417 5418 if (aspectRatio >= 1.0) 5419 { 5420 5421 newSize.h = (uint32) sqrt (proxyCount * aspectRatio); 5422 5423 newSize.v = Max_int32 (1, Round_int32 (newSize.h / aspectRatio)); 5424 5425 } 5426 5427 else 5428 { 5429 5430 newSize.v = (uint32) sqrt (proxyCount / aspectRatio); 5431 5432 newSize.h = Max_int32 (1, Round_int32 (newSize.v * aspectRatio)); 5433 5434 } 5435 5436 } 5437 5438 // If this is fewer pixels, downsample the stage 3 image to that size. 5439 5440 dng_point oldSize = defaultCropArea.Size (); 5441 5442 real64 pixelAspect = PixelAspectRatio (); 5443 5444 if ((uint64) newSize.v * (uint64) newSize.h < 5445 (uint64) oldSize.v * (uint64) oldSize.h || 5446 pixelAspect < 0.99 || 5447 pixelAspect > 1.01) 5448 { 5449 5450 const dng_image &srcImage (*Stage3Image ()); 5451 5452 AutoPtr<dng_image> dstImage (host.Make_dng_image (newSize, 5453 srcImage.Planes (), 5454 srcImage.PixelType ())); 5455 5456 host.ResampleImage (srcImage, 5457 *dstImage); 5458 5459 fStage3Image.Reset (dstImage.Release ()); 5460 5461 fDefaultCropSizeH = dng_urational (newSize.h, 1); 5462 fDefaultCropSizeV = dng_urational (newSize.v, 1); 5463 5464 fDefaultScaleH = dng_urational (1, 1); 5465 fDefaultScaleV = dng_urational (1, 1); 5466 5467 fBestQualityScale = dng_urational (1, 1); 5468 5469 fRawToFullScaleH = 1.0; 5470 fRawToFullScaleV = 1.0; 5471 5472 } 5473 5474 // If there is still a raw to full scale factor, we need to 5475 // remove it and adjust the crop coordinates. 5476 5477 else if (fRawToFullScaleH != 1.0 || 5478 fRawToFullScaleV != 1.0) 5479 { 5480 5481 fDefaultCropSizeH = dng_urational (oldSize.h, 1); 5482 fDefaultCropSizeV = dng_urational (oldSize.v, 1); 5483 5484 fDefaultScaleH = dng_urational (1, 1); 5485 fDefaultScaleV = dng_urational (1, 1); 5486 5487 fBestQualityScale = dng_urational (1, 1); 5488 5489 fRawToFullScaleH = 1.0; 5490 fRawToFullScaleV = 1.0; 5491 5492 } 5493 5494 // Convert 32-bit floating point images to 16-bit floating point to 5495 // save space. 5496 5497 if (Stage3Image ()->PixelType () == ttFloat) 5498 { 5499 5500 fRawImage.Reset (host.Make_dng_image (Stage3Image ()->Bounds (), 5501 Stage3Image ()->Planes (), 5502 ttFloat)); 5503 5504 fRawImageBlackLevel = 0; 5505 5506 LimitFloatBitDepth (host, 5507 *Stage3Image (), 5508 *fRawImage, 5509 16, 5510 32768.0f); 5511 5512 SetRawFloatBitDepth (16); 5513 5514 SetWhiteLevel (32768); 5515 5516 } 5517 5518 else 5519 { 5520 5521 // Convert 16-bit deep images to 8-bit deep image for saving. 5522 5523 real64 blackLevel [kMaxSamplesPerPixel]; 5524 5525 fRawImage.Reset (EncodeRawProxy (host, 5526 *Stage3Image (), 5527 fOpcodeList2, 5528 blackLevel)); 5529 5530 fRawImageBlackLevel = 0; 5531 5532 if (fRawImage.Get ()) 5533 { 5534 5535 SetWhiteLevel (255); 5536 5537 for (uint32 plane = 0; plane < fRawImage->Planes (); plane++) 5538 { 5539 SetBlackLevel (blackLevel [plane], plane); 5540 } 5541 5542 // Compute JPEG compressed version. 5543 5544 if (fRawImage->PixelType () == ttByte && 5545 host.SaveDNGVersion () >= dngVersion_1_4_0_0) 5546 { 5547 5548 AutoPtr<dng_jpeg_image> jpegImage (new dng_jpeg_image); 5549 5550 jpegImage->Encode (host, 5551 *this, 5552 writer, 5553 *fRawImage); 5554 5555 SetRawJPEGImage (jpegImage); 5556 5557 } 5558 5559 } 5560 5561 } 5562 5563 // Deal with transparency mask. 5564 5565 if (TransparencyMask ()) 5566 { 5567 5568 const bool convertTo8Bit = true; 5569 5570 ResizeTransparencyToMatchStage3 (host, convertTo8Bit); 5571 5572 fRawTransparencyMask.Reset (fTransparencyMask->Clone ()); 5573 5574 } 5575 5576 // Deal with depth map. 5577 5578 if (DepthMap ()) 5579 { 5580 5581 ResizeDepthToMatchStage3 (host); 5582 5583 if (fRawDepthMap.Get ()) 5584 { 5585 5586 if (fRawDepthMap->Bounds ().W () > fDepthMap->Bounds ().W () || 5587 fRawDepthMap->Bounds ().H () > fDepthMap->Bounds ().H ()) 5588 { 5589 fRawDepthMap.Reset (); 5590 } 5591 5592 } 5593 5594 } 5595 5596 // Recompute the raw data unique ID, since we changed the image data. 5597 5598 RecomputeRawDataUniqueID (host); 5599 5600 } 5601 5602 /*****************************************************************************/ 5603 5604 bool dng_negative::IsProxy () const 5605 { 5606 5607 return (DefaultCropSizeH () != OriginalDefaultCropSizeH ()) && 5608 (DefaultCropSizeV () != OriginalDefaultCropSizeV ()); 5609 5610 } 5611 5612 /*****************************************************************************/ 5613 5614 dng_linearization_info * dng_negative::MakeLinearizationInfo () 5615 { 5616 5617 dng_linearization_info *info = new dng_linearization_info (); 5618 5619 if (!info) 5620 { 5621 ThrowMemoryFull (); 5622 } 5623 5624 return info; 5625 5626 } 5627 5628 /*****************************************************************************/ 5629 5630 void dng_negative::NeedLinearizationInfo () 5631 { 5632 5633 if (!fLinearizationInfo.Get ()) 5634 { 5635 5636 fLinearizationInfo.Reset (MakeLinearizationInfo ()); 5637 5638 } 5639 5640 } 5641 5642 /*****************************************************************************/ 5643 5644 dng_mosaic_info * dng_negative::MakeMosaicInfo () 5645 { 5646 5647 dng_mosaic_info *info = new dng_mosaic_info (); 5648 5649 if (!info) 5650 { 5651 ThrowMemoryFull (); 5652 } 5653 5654 return info; 5655 5656 } 5657 5658 /*****************************************************************************/ 5659 5660 void dng_negative::NeedMosaicInfo () 5661 { 5662 5663 if (!fMosaicInfo.Get ()) 5664 { 5665 5666 fMosaicInfo.Reset (MakeMosaicInfo ()); 5667 5668 } 5669 5670 } 5671 5672 /*****************************************************************************/ 5673 5674 void dng_negative::SetTransparencyMask (AutoPtr<dng_image> &image, 5675 uint32 bitDepth) 5676 { 5677 5678 fTransparencyMask.Reset (image.Release ()); 5679 5680 fRawTransparencyMaskBitDepth = bitDepth; 5681 5682 } 5683 5684 /*****************************************************************************/ 5685 5686 const dng_image * dng_negative::TransparencyMask () const 5687 { 5688 5689 return fTransparencyMask.Get (); 5690 5691 } 5692 5693 /*****************************************************************************/ 5694 5695 const dng_image * dng_negative::RawTransparencyMask () const 5696 { 5697 5698 if (fRawTransparencyMask.Get ()) 5699 { 5700 5701 return fRawTransparencyMask.Get (); 5702 5703 } 5704 5705 return TransparencyMask (); 5706 5707 } 5708 5709 /*****************************************************************************/ 5710 5711 uint32 dng_negative::RawTransparencyMaskBitDepth () const 5712 { 5713 5714 if (fRawTransparencyMaskBitDepth) 5715 { 5716 5717 return fRawTransparencyMaskBitDepth; 5718 5719 } 5720 5721 const dng_image *mask = RawTransparencyMask (); 5722 5723 if (mask) 5724 { 5725 5726 switch (mask->PixelType ()) 5727 { 5728 5729 case ttByte: 5730 return 8; 5731 5732 case ttShort: 5733 return 16; 5734 5735 case ttFloat: 5736 return 32; 5737 5738 default: 5739 ThrowProgramError (); 5740 5741 } 5742 5743 } 5744 5745 return 0; 5746 5747 } 5748 5749 /*****************************************************************************/ 5750 5751 void dng_negative::ReadTransparencyMask (dng_host &host, 5752 dng_stream &stream, 5753 dng_info &info) 5754 { 5755 5756 if (info.fMaskIndex != -1) 5757 { 5758 5759 // Allocate image we are reading. 5760 5761 dng_ifd &maskIFD = *info.fIFD [info.fMaskIndex]; 5762 5763 fTransparencyMask.Reset (host.Make_dng_image (maskIFD.Bounds (), 5764 1, 5765 maskIFD.PixelType ())); 5766 5767 // Read the image. 5768 5769 maskIFD.ReadImage (host, 5770 stream, 5771 *fTransparencyMask.Get ()); 5772 5773 // Remember the pixel depth. 5774 5775 fRawTransparencyMaskBitDepth = maskIFD.fBitsPerSample [0]; 5776 5777 } 5778 5779 } 5780 5781 /*****************************************************************************/ 5782 5783 void dng_negative::ResizeTransparencyToMatchStage3 (dng_host &host, 5784 bool convertTo8Bit) 5785 { 5786 5787 if (TransparencyMask ()) 5788 { 5789 5790 if ((TransparencyMask ()->Bounds () != fStage3Image->Bounds ()) || 5791 (TransparencyMask ()->PixelType () != ttByte && convertTo8Bit)) 5792 { 5793 5794 AutoPtr<dng_image> newMask (host.Make_dng_image (fStage3Image->Bounds (), 5795 1, 5796 convertTo8Bit ? 5797 ttByte : 5798 TransparencyMask ()->PixelType ())); 5799 5800 host.ResampleImage (*TransparencyMask (), 5801 *newMask); 5802 5803 fTransparencyMask.Reset (newMask.Release ()); 5804 5805 if (!fRawTransparencyMask.Get ()) 5806 { 5807 fRawTransparencyMaskBitDepth = 0; 5808 } 5809 5810 else if (convertTo8Bit) 5811 { 5812 fRawTransparencyMaskBitDepth = 8; 5813 } 5814 5815 } 5816 5817 } 5818 5819 } 5820 5821 /*****************************************************************************/ 5822 5823 bool dng_negative::NeedFlattenTransparency (dng_host & /* host */) 5824 { 5825 5826 return false; 5827 5828 } 5829 5830 /*****************************************************************************/ 5831 5832 void dng_negative::FlattenTransparency (dng_host & /* host */) 5833 { 5834 5835 ThrowNotYetImplemented (); 5836 5837 } 5838 5839 /*****************************************************************************/ 5840 5841 const dng_image * dng_negative::UnflattenedStage3Image () const 5842 { 5843 5844 if (fUnflattenedStage3Image.Get ()) 5845 { 5846 5847 return fUnflattenedStage3Image.Get (); 5848 5849 } 5850 5851 return fStage3Image.Get (); 5852 5853 } 5854 5855 /*****************************************************************************/ 5856 5857 void dng_negative::SetDepthMap (AutoPtr<dng_image> &depthMap) 5858 { 5859 5860 fDepthMap.Reset (depthMap.Release ()); 5861 5862 SetHasDepthMap (fDepthMap.Get () != NULL); 5863 5864 } 5865 5866 /*****************************************************************************/ 5867 5868 void dng_negative::ReadDepthMap (dng_host &host, 5869 dng_stream &stream, 5870 dng_info &info) 5871 { 5872 5873 if (info.fDepthIndex != -1) 5874 { 5875 5876 // Allocate image we are reading. 5877 5878 dng_ifd &depthIFD = *info.fIFD [info.fDepthIndex]; 5879 5880 fDepthMap.Reset (host.Make_dng_image (depthIFD.Bounds (), 5881 1, 5882 depthIFD.PixelType ())); 5883 5884 // Read the image. 5885 5886 depthIFD.ReadImage (host, 5887 stream, 5888 *fDepthMap.Get ()); 5889 5890 SetHasDepthMap (fDepthMap.Get () != NULL); 5891 5892 } 5893 5894 } 5895 5896 /*****************************************************************************/ 5897 5898 void dng_negative::ResizeDepthToMatchStage3 (dng_host &host) 5899 { 5900 5901 if (DepthMap ()) 5902 { 5903 5904 if (DepthMap ()->Bounds () != fStage3Image->Bounds ()) 5905 { 5906 5907 // If we are upsampling, and have not grabbed the raw depth map 5908 // yet, do so now. 5909 5910 if (!fRawDepthMap.Get ()) 5911 { 5912 5913 uint64 imagePixels = fStage3Image->Bounds ().H () * (uint64) 5914 fStage3Image->Bounds ().W (); 5915 5916 uint64 depthPixels = DepthMap ()->Bounds ().H () * (uint64) 5917 DepthMap ()->Bounds ().W (); 5918 5919 if (depthPixels < imagePixels) 5920 { 5921 fRawDepthMap.Reset (fDepthMap->Clone ()); 5922 } 5923 5924 } 5925 5926 AutoPtr<dng_image> newMap (host.Make_dng_image (fStage3Image->Bounds (), 5927 1, 5928 DepthMap ()->PixelType ())); 5929 5930 host.ResampleImage (*DepthMap (), 5931 *newMap); 5932 5933 fDepthMap.Reset (newMap.Release ()); 5934 5935 } 5936 5937 } 5938 5939 } 5940 5941 /*****************************************************************************/