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 /*****************************************************************************/