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