1 /*****************************************************************************/
2 // Copyright 2006-2019 Adobe Systems Incorporated
3 // All Rights Reserved.
4 //
5 // NOTICE: Adobe permits you to use, modify, and distribute this file in
6 // accordance with the terms of the Adobe license agreement accompanying it.
7 /*****************************************************************************/
8
9 #include "dng_negative.h"
10
11 #include "dng_1d_table.h"
12 #include "dng_abort_sniffer.h"
13 #include "dng_area_task.h"
14 #include "dng_assertions.h"
15 #include "dng_bottlenecks.h"
16 #include "dng_camera_profile.h"
17 #include "dng_color_space.h"
18 #include "dng_color_spec.h"
19 #include "dng_exceptions.h"
20 #include "dng_globals.h"
21 #include "dng_host.h"
22 #include "dng_image.h"
23 #include "dng_image_writer.h"
24 #include "dng_info.h"
25 #include "dng_jpeg_image.h"
26 #include "dng_linearization_info.h"
27 #include "dng_memory.h"
28 #include "dng_memory_stream.h"
29 #include "dng_misc_opcodes.h"
30 #include "dng_mosaic_info.h"
31 #include "dng_preview.h"
32 #include "dng_resample.h"
33 #include "dng_safe_arithmetic.h"
34 #include "dng_simple_image.h"
35 #include "dng_tag_codes.h"
36 #include "dng_tag_values.h"
37 #include "dng_tile_iterator.h"
38 #include "dng_uncopyable.h"
39 #include "dng_utils.h"
40 #include "dng_xmp.h"
41
42 /*****************************************************************************/
43
dng_noise_profile()44 dng_noise_profile::dng_noise_profile ()
45
46 : fNoiseFunctions ()
47
48 {
49
50 }
51
52 /*****************************************************************************/
53
dng_noise_profile(const dng_std_vector<dng_noise_function> & functions)54 dng_noise_profile::dng_noise_profile (const dng_std_vector<dng_noise_function> &functions)
55
56 : fNoiseFunctions (functions)
57
58 {
59
60 }
61
62 /*****************************************************************************/
63
IsValid() const64 bool dng_noise_profile::IsValid () const
65 {
66
67 if (NumFunctions () == 0 || NumFunctions () > kMaxColorPlanes)
68 {
69 return false;
70 }
71
72 for (uint32 plane = 0; plane < NumFunctions (); plane++)
73 {
74
75 if (!NoiseFunction (plane).IsValid ())
76 {
77 return false;
78 }
79
80 }
81
82 return true;
83
84 }
85
86 /*****************************************************************************/
87
IsValidForNegative(const dng_negative & negative) const88 bool dng_noise_profile::IsValidForNegative (const dng_negative &negative) const
89 {
90
91 if (!(NumFunctions () == 1 || NumFunctions () == negative.ColorChannels ()))
92 {
93 return false;
94 }
95
96 return IsValid ();
97
98 }
99
100 /*****************************************************************************/
101
NoiseFunction(uint32 plane) const102 const dng_noise_function & dng_noise_profile::NoiseFunction (uint32 plane) const
103 {
104
105 if (NumFunctions () == 1)
106 {
107 return fNoiseFunctions.front ();
108 }
109
110 DNG_REQUIRE (plane < NumFunctions (),
111 "Bad plane index argument for NoiseFunction ().");
112
113 return fNoiseFunctions [plane];
114
115 }
116
117 /*****************************************************************************/
118
NumFunctions() const119 uint32 dng_noise_profile::NumFunctions () const
120 {
121 return (uint32) fNoiseFunctions.size ();
122 }
123
124 /*****************************************************************************/
125
operator ==(const dng_noise_profile & profile) const126 bool dng_noise_profile::operator== (const dng_noise_profile &profile) const
127 {
128
129 if (IsValid ())
130 {
131
132 if (!profile.IsValid ())
133 {
134 return false;
135 }
136
137 if (NumFunctions () != profile.NumFunctions ())
138 {
139 return false;
140 }
141
142 for (uint32 plane = 0; plane < NumFunctions (); plane++)
143 {
144
145 if (NoiseFunction (plane).Scale () != profile.NoiseFunction (plane).Scale () ||
146 NoiseFunction (plane).Offset () != profile.NoiseFunction (plane).Offset ())
147 {
148 return false;
149 }
150
151 }
152
153 return true;
154
155 }
156
157 else
158 return !profile.IsValid ();
159
160 }
161
162 /*****************************************************************************/
163
dng_metadata(dng_host & host)164 dng_metadata::dng_metadata (dng_host &host)
165
166 : fHasBaseOrientation (false)
167 , fBaseOrientation ()
168 , fIsMakerNoteSafe (false)
169 , fMakerNote ()
170 , fExif (host.Make_dng_exif ())
171 , fOriginalExif ()
172 , fIPTCBlock ()
173 , fIPTCOffset (kDNGStreamInvalidOffset)
174 , fXMP (host.Make_dng_xmp ())
175 , fEmbeddedXMPDigest ()
176 , fXMPinSidecar (false)
177 , fXMPisNewer (false)
178 , fSourceMIME ()
179
180 {
181 }
182
183 /*****************************************************************************/
184
~dng_metadata()185 dng_metadata::~dng_metadata ()
186 {
187 }
188
189 /******************************************************************************/
190
191 template< class T >
CloneAutoPtr(const AutoPtr<T> & ptr)192 T * CloneAutoPtr (const AutoPtr< T > &ptr)
193 {
194
195 return ptr.Get () ? ptr->Clone () : NULL;
196
197 }
198
199 /******************************************************************************/
200
201 template< class T, typename U >
202 T * CloneAutoPtr (const AutoPtr< T > &ptr, U &u)
203 {
204
205 return ptr.Get () ? ptr->Clone (u) : NULL;
206
207 }
208
209 /******************************************************************************/
210
dng_metadata(const dng_metadata & rhs,dng_memory_allocator & allocator)211 dng_metadata::dng_metadata (const dng_metadata &rhs,
212 dng_memory_allocator &allocator)
213
214 : fHasBaseOrientation (rhs.fHasBaseOrientation)
215 , fBaseOrientation (rhs.fBaseOrientation)
216 , fIsMakerNoteSafe (rhs.fIsMakerNoteSafe)
217 , fMakerNote (CloneAutoPtr (rhs.fMakerNote, allocator))
218 , fExif (CloneAutoPtr (rhs.fExif))
219 , fOriginalExif (CloneAutoPtr (rhs.fOriginalExif))
220 , fIPTCBlock (CloneAutoPtr (rhs.fIPTCBlock, allocator))
221 , fIPTCOffset (rhs.fIPTCOffset)
222 , fXMP (CloneAutoPtr (rhs.fXMP))
223 , fEmbeddedXMPDigest (rhs.fEmbeddedXMPDigest)
224 , fXMPinSidecar (rhs.fXMPinSidecar)
225 , fXMPisNewer (rhs.fXMPisNewer)
226 , fSourceMIME (rhs.fSourceMIME)
227
228 {
229
230 }
231
232 /******************************************************************************/
233
Clone(dng_memory_allocator & allocator) const234 dng_metadata * dng_metadata::Clone (dng_memory_allocator &allocator) const
235 {
236
237 return new dng_metadata (*this, allocator);
238
239 }
240
241 /******************************************************************************/
242
SetBaseOrientation(const dng_orientation & orientation)243 void dng_metadata::SetBaseOrientation (const dng_orientation &orientation)
244 {
245
246 fHasBaseOrientation = true;
247
248 fBaseOrientation = orientation;
249
250 }
251
252 /******************************************************************************/
253
ApplyOrientation(const dng_orientation & orientation)254 void dng_metadata::ApplyOrientation (const dng_orientation &orientation)
255 {
256
257 fBaseOrientation += orientation;
258
259 fXMP->SetOrientation (fBaseOrientation);
260
261 }
262
263 /*****************************************************************************/
264
ResetExif(dng_exif * newExif)265 void dng_metadata::ResetExif (dng_exif * newExif)
266 {
267
268 fExif.Reset (newExif);
269
270 }
271
272 /******************************************************************************/
273
BuildExifBlock(dng_memory_allocator & allocator,const dng_resolution * resolution,bool includeIPTC,const dng_jpeg_preview * thumbnail) const274 dng_memory_block * dng_metadata::BuildExifBlock (dng_memory_allocator &allocator,
275 const dng_resolution *resolution,
276 bool includeIPTC,
277 const dng_jpeg_preview *thumbnail) const
278 {
279
280 dng_memory_stream stream (allocator);
281
282 {
283
284 // Create the main IFD
285
286 dng_tiff_directory mainIFD;
287
288 // Optionally include the resolution tags.
289
290 dng_resolution res;
291
292 if (resolution)
293 {
294 res = *resolution;
295 }
296
297 tag_urational tagXResolution (tcXResolution, res.fXResolution);
298 tag_urational tagYResolution (tcYResolution, res.fYResolution);
299
300 tag_uint16 tagResolutionUnit (tcResolutionUnit, res.fResolutionUnit);
301
302 if (resolution)
303 {
304 mainIFD.Add (&tagXResolution );
305 mainIFD.Add (&tagYResolution );
306 mainIFD.Add (&tagResolutionUnit);
307 }
308
309 // Optionally include IPTC block.
310
311 tag_iptc tagIPTC (IPTCData (),
312 IPTCLength ());
313
314 if (includeIPTC && tagIPTC.Count ())
315 {
316 mainIFD.Add (&tagIPTC);
317 }
318
319 // Exif tags.
320
321 exif_tag_set exifSet (mainIFD,
322 *GetExif (),
323 IsMakerNoteSafe (),
324 MakerNoteData (),
325 MakerNoteLength (),
326 false);
327
328 // Figure out the Exif IFD offset.
329
330 uint32 exifOffset = 8 + mainIFD.Size ();
331
332 exifSet.Locate (exifOffset);
333
334 // Thumbnail IFD (if any).
335
336 dng_tiff_directory thumbIFD;
337
338 tag_uint16 thumbCompression (tcCompression, ccOldJPEG);
339
340 tag_urational thumbXResolution (tcXResolution, dng_urational (72, 1));
341 tag_urational thumbYResolution (tcYResolution, dng_urational (72, 1));
342
343 tag_uint16 thumbResolutionUnit (tcResolutionUnit, ruInch);
344
345 tag_uint32 thumbDataOffset (tcJPEGInterchangeFormat , 0);
346 tag_uint32 thumbDataLength (tcJPEGInterchangeFormatLength, 0);
347
348 if (thumbnail)
349 {
350
351 thumbIFD.Add (&thumbCompression);
352
353 thumbIFD.Add (&thumbXResolution);
354 thumbIFD.Add (&thumbYResolution);
355 thumbIFD.Add (&thumbResolutionUnit);
356
357 thumbIFD.Add (&thumbDataOffset);
358 thumbIFD.Add (&thumbDataLength);
359
360 thumbDataLength.Set (thumbnail->fCompressedData->LogicalSize ());
361
362 uint32 thumbOffset = exifOffset + exifSet.Size ();
363
364 mainIFD.SetChained (thumbOffset);
365
366 thumbDataOffset.Set (thumbOffset + thumbIFD.Size ());
367
368 }
369
370 // Don't write anything unless the main IFD has some tags.
371
372 if (mainIFD.Size () != 0)
373 {
374
375 // Write TIFF Header.
376
377 stream.SetWritePosition (0);
378
379 stream.Put_uint16 (stream.BigEndian () ? byteOrderMM : byteOrderII);
380
381 stream.Put_uint16 (42);
382
383 stream.Put_uint32 (8);
384
385 // Write the IFDs.
386
387 mainIFD.Put (stream);
388
389 exifSet.Put (stream);
390
391 if (thumbnail)
392 {
393
394 thumbIFD.Put (stream);
395
396 stream.Put (thumbnail->fCompressedData->Buffer (),
397 thumbnail->fCompressedData->LogicalSize ());
398
399 }
400
401 // Trim the file to this length.
402
403 stream.Flush ();
404
405 stream.SetLength (stream.Position ());
406
407 }
408
409 }
410
411 return stream.AsMemoryBlock (allocator);
412
413 }
414
415 /******************************************************************************/
416
SetIPTC(AutoPtr<dng_memory_block> & block,uint64 offset)417 void dng_metadata::SetIPTC (AutoPtr<dng_memory_block> &block, uint64 offset)
418 {
419
420 fIPTCBlock.Reset (block.Release ());
421
422 fIPTCOffset = offset;
423
424 }
425
426 /******************************************************************************/
427
SetIPTC(AutoPtr<dng_memory_block> & block)428 void dng_metadata::SetIPTC (AutoPtr<dng_memory_block> &block)
429 {
430
431 SetIPTC (block, kDNGStreamInvalidOffset);
432
433 }
434
435 /******************************************************************************/
436
ClearIPTC()437 void dng_metadata::ClearIPTC ()
438 {
439
440 fIPTCBlock.Reset ();
441
442 fIPTCOffset = kDNGStreamInvalidOffset;
443
444 }
445
446 /*****************************************************************************/
447
IPTCData() const448 const void * dng_metadata::IPTCData () const
449 {
450
451 if (fIPTCBlock.Get ())
452 {
453
454 return fIPTCBlock->Buffer ();
455
456 }
457
458 return NULL;
459
460 }
461
462 /*****************************************************************************/
463
IPTCLength() const464 uint32 dng_metadata::IPTCLength () const
465 {
466
467 if (fIPTCBlock.Get ())
468 {
469
470 return fIPTCBlock->LogicalSize ();
471
472 }
473
474 return 0;
475
476 }
477
478 /*****************************************************************************/
479
IPTCOffset() const480 uint64 dng_metadata::IPTCOffset () const
481 {
482
483 if (fIPTCBlock.Get ())
484 {
485
486 return fIPTCOffset;
487
488 }
489
490 return kDNGStreamInvalidOffset;
491
492 }
493
494 /*****************************************************************************/
495
IPTCDigest(bool includePadding) const496 dng_fingerprint dng_metadata::IPTCDigest (bool includePadding) const
497 {
498
499 if (IPTCLength ())
500 {
501
502 dng_md5_printer printer;
503
504 const uint8 *data = (const uint8 *) IPTCData ();
505
506 uint32 count = IPTCLength ();
507
508 // Because of some stupid ways of storing the IPTC data, the IPTC
509 // data might be padded with up to three zeros. The official Adobe
510 // logic is to include these zeros in the digest. However, older
511 // versions of the Camera Raw code did not include the padding zeros
512 // in the digest, so we support both methods and allow either to
513 // match.
514
515 if (!includePadding)
516 {
517
518 uint32 removed = 0;
519
520 while ((removed < 3) && (count > 0) && (data [count - 1] == 0))
521 {
522 removed++;
523 count--;
524 }
525
526 }
527
528 printer.Process (data, count);
529
530 return printer.Result ();
531
532 }
533
534 return dng_fingerprint ();
535
536 }
537
538 /******************************************************************************/
539
RebuildIPTC(dng_memory_allocator & allocator,bool padForTIFF)540 void dng_metadata::RebuildIPTC (dng_memory_allocator &allocator,
541 bool padForTIFF)
542 {
543
544 ClearIPTC ();
545
546 fXMP->RebuildIPTC (*this, allocator, padForTIFF);
547
548 dng_fingerprint digest = IPTCDigest ();
549
550 fXMP->SetIPTCDigest (digest);
551
552 }
553
554 /*****************************************************************************/
555
ResetXMP(dng_xmp * newXMP)556 void dng_metadata::ResetXMP (dng_xmp * newXMP)
557 {
558
559 fXMP.Reset (newXMP);
560
561 }
562
563 /*****************************************************************************/
564
ResetXMPSidecarNewer(dng_xmp * newXMP,bool inSidecar,bool isNewer)565 void dng_metadata::ResetXMPSidecarNewer (dng_xmp * newXMP,
566 bool inSidecar,
567 bool isNewer )
568 {
569
570 fXMP.Reset (newXMP);
571
572 fXMPinSidecar = inSidecar;
573
574 fXMPisNewer = isNewer;
575
576 }
577
578 /*****************************************************************************/
579
SetXMP(dng_host & host,const void * buffer,uint32 count,bool xmpInSidecar,bool xmpIsNewer)580 bool dng_metadata::SetXMP (dng_host &host,
581 const void *buffer,
582 uint32 count,
583 bool xmpInSidecar,
584 bool xmpIsNewer)
585 {
586
587 bool result = false;
588
589 try
590 {
591
592 AutoPtr<dng_xmp> tempXMP (host.Make_dng_xmp ());
593
594 tempXMP->Parse (host, buffer, count);
595
596 ResetXMPSidecarNewer (tempXMP.Release (), xmpInSidecar, xmpIsNewer);
597
598 result = true;
599
600 }
601
602 catch (dng_exception &except)
603 {
604
605 // Don't ignore transient errors.
606
607 if (host.IsTransientError (except.ErrorCode ()))
608 {
609
610 throw;
611
612 }
613
614 // Eat other parsing errors.
615
616 }
617
618 catch (...)
619 {
620
621 // Eat unknown parsing exceptions.
622
623 }
624
625 return result;
626
627 }
628
629 /*****************************************************************************/
630
SetEmbeddedXMP(dng_host & host,const void * buffer,uint32 count)631 void dng_metadata::SetEmbeddedXMP (dng_host &host,
632 const void *buffer,
633 uint32 count)
634 {
635
636 if (SetXMP (host, buffer, count))
637 {
638
639 dng_md5_printer printer;
640
641 printer.Process (buffer, count);
642
643 fEmbeddedXMPDigest = printer.Result ();
644
645 // Remove any sidecar specific tags from embedded XMP.
646
647 if (fXMP.Get ())
648 {
649
650 fXMP->Remove (XMP_NS_PHOTOSHOP, "SidecarForExtension");
651 fXMP->Remove (XMP_NS_PHOTOSHOP, "EmbeddedXMPDigest");
652
653 }
654
655 }
656
657 else
658 {
659
660 fEmbeddedXMPDigest.Clear ();
661
662 }
663
664 }
665
666 /*****************************************************************************/
667
SynchronizeMetadata()668 void dng_metadata::SynchronizeMetadata ()
669 {
670
671 DNG_REQUIRE (fExif.Get (),
672 "Expected valid fExif field in "
673 "dng_metadata::SynchronizeMetadata");
674
675 if (!fOriginalExif.Get ())
676 {
677
678 fOriginalExif.Reset (fExif->Clone ());
679
680 }
681
682 fXMP->ValidateMetadata ();
683
684 fXMP->IngestIPTC (*this, fXMPisNewer);
685
686 fXMP->SyncExif (*fExif.Get ());
687
688 fXMP->SyncOrientation (*this, fXMPinSidecar);
689
690 }
691
692 /*****************************************************************************/
693
UpdateDateTime(const dng_date_time_info & dt)694 void dng_metadata::UpdateDateTime (const dng_date_time_info &dt)
695 {
696
697 fExif->UpdateDateTime (dt);
698
699 fXMP->UpdateDateTime (dt);
700
701 }
702
703 /*****************************************************************************/
704
UpdateDateTimeToNow()705 void dng_metadata::UpdateDateTimeToNow ()
706 {
707
708 dng_date_time_info dt;
709
710 CurrentDateTimeAndZone (dt);
711
712 UpdateDateTime (dt);
713
714 fXMP->UpdateMetadataDate (dt);
715
716 }
717
718 /*****************************************************************************/
719
UpdateMetadataDateTimeToNow()720 void dng_metadata::UpdateMetadataDateTimeToNow ()
721 {
722
723 dng_date_time_info dt;
724
725 CurrentDateTimeAndZone (dt);
726
727 fXMP->UpdateMetadataDate (dt);
728
729 }
730
731 /*****************************************************************************/
732
dng_negative(dng_host & host)733 dng_negative::dng_negative (dng_host &host)
734
735 : fAllocator (host.Allocator ())
736
737 , fModelName ()
738 , fLocalName ()
739 , fDefaultCropSizeH ()
740 , fDefaultCropSizeV ()
741 , fDefaultCropOriginH (0, 1)
742 , fDefaultCropOriginV (0, 1)
743 , fDefaultUserCropT (0, 1)
744 , fDefaultUserCropL (0, 1)
745 , fDefaultUserCropB (1, 1)
746 , fDefaultUserCropR (1, 1)
747 , fDefaultScaleH (1, 1)
748 , fDefaultScaleV (1, 1)
749 , fBestQualityScale (1, 1)
750 , fOriginalDefaultFinalSize ()
751 , fOriginalBestQualityFinalSize ()
752 , fOriginalDefaultCropSizeH ()
753 , fOriginalDefaultCropSizeV ()
754 , fRawToFullScaleH (1.0)
755 , fRawToFullScaleV (1.0)
756 , fBaselineNoise (100, 100)
757 , fNoiseReductionApplied (0, 0)
758 , fRawNoiseReductionApplied (0, 0)
759 , fNoiseProfile ()
760 , fRawNoiseProfile ()
761 , fBaselineExposure ( 0, 100)
762 , fBaselineSharpness (100, 100)
763 , fRawBaselineSharpness (0, 0)
764 , fChromaBlurRadius ()
765 , fAntiAliasStrength (100, 100)
766 , fLinearResponseLimit (100, 100)
767 , fShadowScale (1, 1)
768 , fColorimetricReference (crSceneReferred)
769 , fFloatingPoint (false)
770 , fColorChannels (0)
771 , fAnalogBalance ()
772 , fCameraNeutral ()
773 , fCameraWhiteXY ()
774 , fCameraCalibration1 ()
775 , fCameraCalibration2 ()
776 , fCameraCalibrationSignature ()
777 , fCameraProfile ()
778 , fAsShotProfileName ()
779 , fRawImageDigest ()
780 , fNewRawImageDigest ()
781 , fRawDataUniqueID ()
782 , fOriginalRawFileName ()
783 , fHasOriginalRawFileData (false)
784 , fOriginalRawFileData ()
785 , fOriginalRawFileDigest ()
786 , fDNGPrivateData ()
787 , fMetadata (host)
788 , fLinearizationInfo ()
789 , fMosaicInfo ()
790 , fOpcodeList1 (1)
791 , fOpcodeList2 (2)
792 , fOpcodeList3 (3)
793 , fStage1Image ()
794 , fStage2Image ()
795 , fStage3Image ()
796 , fStage3Gain (1.0)
797 , fStage3BlackLevel (0)
798 , fIsPreview (false)
799 , fIsDamaged (false)
800 , fRawImageStage (rawImageStageNone)
801 , fRawImage ()
802 , fRawImageBlackLevel (0)
803 , fRawFloatBitDepth (0)
804 , fRawJPEGImage ()
805 , fRawJPEGImageDigest ()
806 , fTransparencyMask ()
807 , fRawTransparencyMask ()
808 , fRawTransparencyMaskBitDepth (0)
809 , fUnflattenedStage3Image ()
810 , fHasDepthMap (false)
811 , fDepthMap ()
812 , fRawDepthMap ()
813 , fDepthFormat (depthFormatUnknown)
814 , fDepthNear (0, 0)
815 , fDepthFar (0, 0)
816 , fDepthUnits (depthUnitsUnknown)
817 , fDepthMeasureType (depthMeasureUnknown)
818 , fEnhanceParams ()
819
820 {
821
822 }
823
824 /*****************************************************************************/
825
~dng_negative()826 dng_negative::~dng_negative ()
827 {
828
829 // Delete any camera profiles owned by this negative.
830
831 ClearProfiles ();
832
833 }
834
835 /******************************************************************************/
836
Initialize()837 void dng_negative::Initialize ()
838 {
839
840 }
841
842 /******************************************************************************/
843
Make(dng_host & host)844 dng_negative * dng_negative::Make (dng_host &host)
845 {
846
847 AutoPtr<dng_negative> result (new dng_negative (host));
848
849 if (!result.Get ())
850 {
851 ThrowMemoryFull ();
852 }
853
854 result->Initialize ();
855
856 return result.Release ();
857
858 }
859
860 /******************************************************************************/
861
CloneInternalMetadata() const862 dng_metadata * dng_negative::CloneInternalMetadata () const
863 {
864
865 return InternalMetadata ().Clone (Allocator ());
866
867 }
868
869 /******************************************************************************/
870
ComputeOrientation(const dng_metadata & metadata) const871 dng_orientation dng_negative::ComputeOrientation (const dng_metadata &metadata) const
872 {
873
874 return metadata.BaseOrientation ();
875
876 }
877
878 /******************************************************************************/
879
SetAnalogBalance(const dng_vector & b)880 void dng_negative::SetAnalogBalance (const dng_vector &b)
881 {
882
883 real64 minEntry = b.MinEntry ();
884
885 if (b.NotEmpty () && minEntry > 0.0)
886 {
887
888 fAnalogBalance = b;
889
890 fAnalogBalance.Scale (1.0 / minEntry);
891
892 fAnalogBalance.Round (1000000.0);
893
894 }
895
896 else
897 {
898
899 fAnalogBalance.Clear ();
900
901 }
902
903 }
904
905 /*****************************************************************************/
906
AnalogBalance(uint32 channel) const907 real64 dng_negative::AnalogBalance (uint32 channel) const
908 {
909
910 DNG_ASSERT (channel < ColorChannels (), "Channel out of bounds");
911
912 if (channel < fAnalogBalance.Count ())
913 {
914
915 return fAnalogBalance [channel];
916
917 }
918
919 return 1.0;
920
921 }
922
923 /*****************************************************************************/
924
AnalogBalanceR(uint32 channel) const925 dng_urational dng_negative::AnalogBalanceR (uint32 channel) const
926 {
927
928 dng_urational result;
929
930 result.Set_real64 (AnalogBalance (channel), 1000000);
931
932 return result;
933
934 }
935
936 /******************************************************************************/
937
SetCameraNeutral(const dng_vector & n)938 void dng_negative::SetCameraNeutral (const dng_vector &n)
939 {
940
941 real64 maxEntry = n.MaxEntry ();
942
943 if (n.NotEmpty () && maxEntry > 0.0)
944 {
945
946 fCameraNeutral = n;
947
948 fCameraNeutral.Scale (1.0 / maxEntry);
949
950 fCameraNeutral.Round (1000000.0);
951
952 }
953
954 else
955 {
956
957 fCameraNeutral.Clear ();
958
959 }
960
961 }
962
963 /*****************************************************************************/
964
CameraNeutralR(uint32 channel) const965 dng_urational dng_negative::CameraNeutralR (uint32 channel) const
966 {
967
968 dng_urational result;
969
970 result.Set_real64 (CameraNeutral () [channel], 1000000);
971
972 return result;
973
974 }
975
976 /******************************************************************************/
977
SetCameraWhiteXY(const dng_xy_coord & coord)978 void dng_negative::SetCameraWhiteXY (const dng_xy_coord &coord)
979 {
980
981 if (coord.IsValid ())
982 {
983
984 fCameraWhiteXY.x = Round_int32 (coord.x * 1000000.0) / 1000000.0;
985 fCameraWhiteXY.y = Round_int32 (coord.y * 1000000.0) / 1000000.0;
986
987 }
988
989 else
990 {
991
992 fCameraWhiteXY.Clear ();
993
994 }
995
996 }
997
998 /*****************************************************************************/
999
CameraWhiteXY() const1000 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
GetCameraWhiteXY(dng_urational & x,dng_urational & y) const1011 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
SetCameraCalibration1(const dng_matrix & m)1024 void dng_negative::SetCameraCalibration1 (const dng_matrix &m)
1025 {
1026
1027 fCameraCalibration1 = m;
1028
1029 fCameraCalibration1.Round (10000);
1030
1031 }
1032
1033 /******************************************************************************/
1034
SetCameraCalibration2(const dng_matrix & m)1035 void dng_negative::SetCameraCalibration2 (const dng_matrix &m)
1036 {
1037
1038 fCameraCalibration2 = m;
1039
1040 fCameraCalibration2.Round (10000);
1041
1042 }
1043
1044 /******************************************************************************/
1045
AddProfile(AutoPtr<dng_camera_profile> & profile)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
ClearProfiles()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
ClearProfiles(bool clearBuiltinMatrixProfiles,bool clearReadFromDisk)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
ProfileCount() const1252 uint32 dng_negative::ProfileCount () const
1253 {
1254
1255 return (uint32) fCameraProfile.size ();
1256
1257 }
1258
1259 /******************************************************************************/
1260
ProfileByIndex(uint32 index) const1261 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
ProfileByID(const dng_camera_profile_id & id,bool useDefaultIfNoMatch) const1273 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
ComputeCameraProfileToEmbed(const dng_metadata &) const1421 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
MakeColorSpec(const dng_camera_profile_id & id) const1477 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
FindImageDigest(dng_host & host,const dng_image & image)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
FindRawImageDigest(dng_host & host) const1595 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
dng_find_new_raw_image_digest_task(const dng_image & image,uint32 pixelType)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
Start(uint32 threadCount,const dng_rect &,const dng_point & tileSize,dng_memory_allocator * allocator,dng_abort_sniffer *)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
Process(uint32 threadIndex,const dng_rect & tile,dng_abort_sniffer *)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
Result()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
FindNewRawImageDigest(dng_host & host) const1807 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
ValidateRawImageDigest(dng_host & host)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
RawDataUniqueID() const2057 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
FindRawDataUniqueID(dng_host & host) const2086 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
RecomputeRawDataUniqueID(dng_host & host)2174 void dng_negative::RecomputeRawDataUniqueID (dng_host &host)
2175 {
2176
2177 fRawDataUniqueID.Clear ();
2178
2179 FindRawDataUniqueID (host);
2180
2181 }
2182
2183 /******************************************************************************/
2184
FindOriginalRawFileDigest() const2185 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
ValidateOriginalRawFileDigest()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
DefaultCropArea() const2258 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
TotalBaselineExposure(const dng_camera_profile_id & profileID) const2302 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
SetShadowScale(const dng_urational & scale)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
SetActiveArea(const dng_rect & area)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
SetMaskedAreas(uint32 count,const dng_rect * area)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
SetLinearization(AutoPtr<dng_memory_block> & curve)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
SetBlackLevel(real64 black,int32 plane)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
SetQuadBlacks(real64 black0,real64 black1,real64 black2,real64 black3,int32 plane)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
Set6x6Blacks(real64 blacks6x6[36],int32 plane)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
SetRowBlacks(const real64 * blacks,uint32 count)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
SetColumnBlacks(const real64 * blacks,uint32 count)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
WhiteLevel(uint32 plane) const2607 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
SetWhiteLevel(uint32 white,int32 plane)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
SetColorKeys(ColorKeyCode color0,ColorKeyCode color1,ColorKeyCode color2,ColorKeyCode color3)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
SetBayerMosaic(uint32 phase)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
SetFujiMosaic(uint32 phase)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
SetFujiMosaic6x6(uint32 phase)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
SetQuadMosaic(uint32 pattern)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
SetGreenSplit(uint32 split)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
Parse(dng_host & host,dng_stream & stream,dng_info & info)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
SetDefaultOriginalSizes()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
SetOriginalSizes(const dng_point & size)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
PostParse(dng_host & host,dng_stream & stream,dng_info & info)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
SetFourColorBayer()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
RawImage() const3698 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
RawImageBlackLevel() const3725 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
RawJPEGImage() const3744 const dng_jpeg_image * dng_negative::RawJPEGImage () const
3745 {
3746
3747 return fRawJPEGImage.Get ();
3748
3749 }
3750
3751 /*****************************************************************************/
3752
SetRawJPEGImage(AutoPtr<dng_jpeg_image> & jpegImage)3753 void dng_negative::SetRawJPEGImage (AutoPtr<dng_jpeg_image> &jpegImage)
3754 {
3755
3756 fRawJPEGImage.Reset (jpegImage.Release ());
3757
3758 }
3759
3760 /*****************************************************************************/
3761
ClearRawJPEGImage()3762 void dng_negative::ClearRawJPEGImage ()
3763 {
3764
3765 fRawJPEGImage.Reset ();
3766
3767 }
3768
3769 /*****************************************************************************/
3770
FindRawJPEGImageDigest(dng_host & host) const3771 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
ReadOpcodeLists(dng_host & host,dng_stream & stream,dng_info & info)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
ReadStage1Image(dng_host & host,dng_stream & stream,dng_info & info)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
ReadEnhancedImage(dng_host & host,dng_stream & stream,dng_info & info)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
SetStage1Image(AutoPtr<dng_image> & image)4095 void dng_negative::SetStage1Image (AutoPtr<dng_image> &image)
4096 {
4097
4098 fStage1Image.Reset (image.Release ());
4099
4100 }
4101
4102 /*****************************************************************************/
4103
SetStage2Image(AutoPtr<dng_image> & image)4104 void dng_negative::SetStage2Image (AutoPtr<dng_image> &image)
4105 {
4106
4107 fStage2Image.Reset (image.Release ());
4108
4109 }
4110
4111 /*****************************************************************************/
4112
SetStage3Image(AutoPtr<dng_image> & image)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
DoBuildStage2(dng_host & host)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
DoPostOpcodeList2(dng_host &)4155 void dng_negative::DoPostOpcodeList2 (dng_host & /* host */)
4156 {
4157
4158 // Nothing by default.
4159
4160 }
4161
4162 /*****************************************************************************/
4163
NeedDefloatStage2(dng_host & host)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
DefloatStage2(dng_host &)4187 void dng_negative::DefloatStage2 (dng_host & /* host */)
4188 {
4189
4190 ThrowNotYetImplemented ("dng_negative::DefloatStage2");
4191
4192 }
4193
4194 /*****************************************************************************/
4195
BuildStage2Image(dng_host & host)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 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
DoInterpolateStage3(dng_host & host,int32 srcPlane,dng_matrix * scaleTransforms)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
DoMergeStage3(dng_host & host,dng_matrix * scaleTransforms)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
DoBuildStage3(dng_host & host,int32 srcPlane,dng_matrix * scaleTransforms)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
BuildStage3Image(dng_host & host,int32 srcPlane)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
SceneProxyCurve(real64 x)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
OutputProxyCurve(real64 x)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
dng_gamma_encode_proxy(real64 lower,real64 upper,bool isSceneReferred,real64 stage3BlackLevel,real64 blackLevel)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
Evaluate(real64 x) const4832 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
RepeatingTile1() const4916 virtual dng_rect RepeatingTile1 () const
4917 {
4918 return fSrcImage.RepeatingTile ();
4919 }
4920
RepeatingTile2() const4921 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
dng_encode_proxy_task(dng_host & host,const dng_image & srcImage,dng_image & dstImage,const real64 * lower,const real64 * upper,bool isSceneReferred,real64 stage3BlackLevel,real64 * blackLevel)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
Process(uint32,const dng_rect & tile,dng_abort_sniffer *)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
SupportsPreservedBlackLevels(dng_host &)5058 bool dng_negative::SupportsPreservedBlackLevels (dng_host & /* host */)
5059 {
5060
5061 return false;
5062
5063 }
5064
5065 /******************************************************************************/
5066
EncodeRawProxy(dng_host & host,const dng_image & srcImage,dng_opcode_list & opcodeList,real64 * blackLevel) const5067 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
AdjustProfileForStage3()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
ConvertToProxy(dng_host & host,dng_image_writer & writer,uint32 proxySize,uint64 proxyCount)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
IsProxy() const5604 bool dng_negative::IsProxy () const
5605 {
5606
5607 return (DefaultCropSizeH () != OriginalDefaultCropSizeH ()) &&
5608 (DefaultCropSizeV () != OriginalDefaultCropSizeV ());
5609
5610 }
5611
5612 /*****************************************************************************/
5613
MakeLinearizationInfo()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
NeedLinearizationInfo()5630 void dng_negative::NeedLinearizationInfo ()
5631 {
5632
5633 if (!fLinearizationInfo.Get ())
5634 {
5635
5636 fLinearizationInfo.Reset (MakeLinearizationInfo ());
5637
5638 }
5639
5640 }
5641
5642 /*****************************************************************************/
5643
MakeMosaicInfo()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
NeedMosaicInfo()5660 void dng_negative::NeedMosaicInfo ()
5661 {
5662
5663 if (!fMosaicInfo.Get ())
5664 {
5665
5666 fMosaicInfo.Reset (MakeMosaicInfo ());
5667
5668 }
5669
5670 }
5671
5672 /*****************************************************************************/
5673
SetTransparencyMask(AutoPtr<dng_image> & image,uint32 bitDepth)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
TransparencyMask() const5686 const dng_image * dng_negative::TransparencyMask () const
5687 {
5688
5689 return fTransparencyMask.Get ();
5690
5691 }
5692
5693 /*****************************************************************************/
5694
RawTransparencyMask() const5695 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
RawTransparencyMaskBitDepth() const5711 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
ReadTransparencyMask(dng_host & host,dng_stream & stream,dng_info & info)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
ResizeTransparencyToMatchStage3(dng_host & host,bool convertTo8Bit)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
NeedFlattenTransparency(dng_host &)5823 bool dng_negative::NeedFlattenTransparency (dng_host & /* host */)
5824 {
5825
5826 return false;
5827
5828 }
5829
5830 /*****************************************************************************/
5831
FlattenTransparency(dng_host &)5832 void dng_negative::FlattenTransparency (dng_host & /* host */)
5833 {
5834
5835 ThrowNotYetImplemented ();
5836
5837 }
5838
5839 /*****************************************************************************/
5840
UnflattenedStage3Image() const5841 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
SetDepthMap(AutoPtr<dng_image> & depthMap)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
ReadDepthMap(dng_host & host,dng_stream & stream,dng_info & info)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
ResizeDepthToMatchStage3(dng_host & host)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 /*****************************************************************************/
5942