1 /*****************************************************************************/
2 // Copyright 2006-2008 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_2/dng_sdk/source/dng_negative.cpp#2 $ */
10 /* $DateTime: 2008/04/02 14:06:57 $ */
11 /* $Change: 440485 $ */
12 /* $Author: tknoll $ */
13
14 /*****************************************************************************/
15
16 #include "dng_negative.h"
17
18 #include "dng_abort_sniffer.h"
19 #include "dng_bottlenecks.h"
20 #include "dng_camera_profile.h"
21 #include "dng_color_spec.h"
22 #include "dng_exceptions.h"
23 #include "dng_host.h"
24 #include "dng_image.h"
25 #include "dng_image_writer.h"
26 #include "dng_info.h"
27 #include "dng_linearization_info.h"
28 #include "dng_memory_stream.h"
29 #include "dng_mosaic_info.h"
30 #include "dng_simple_image.h"
31 #include "dng_tag_codes.h"
32 #include "dng_tag_values.h"
33 #include "dng_tile_iterator.h"
34 #include "dng_xmp.h"
35
36 /*****************************************************************************/
37
dng_negative(dng_memory_allocator & allocator)38 dng_negative::dng_negative (dng_memory_allocator &allocator)
39
40 : fAllocator (allocator)
41
42 , fModelName ()
43 , fLocalName ()
44 , fHasBaseOrientation (false)
45 , fBaseOrientation ()
46 , fDefaultCropSizeH ()
47 , fDefaultCropSizeV ()
48 , fDefaultCropOriginH (0, 1)
49 , fDefaultCropOriginV (0, 1)
50 , fDefaultScaleH (1, 1)
51 , fDefaultScaleV (1, 1)
52 , fBestQualityScale (1, 1)
53 , fRawToFullScaleH (1.0)
54 , fRawToFullScaleV (1.0)
55 , fBaselineNoise (100, 100)
56 , fNoiseReductionApplied (0, 0)
57 , fBaselineExposure ( 0, 100)
58 , fBaselineSharpness (100, 100)
59 , fChromaBlurRadius ()
60 , fAntiAliasStrength (100, 100)
61 , fLinearResponseLimit (100, 100)
62 , fShadowScale (1, 1)
63 , fColorimetricReference (crSceneReferred)
64 , fColorChannels (0)
65 , fAnalogBalance ()
66 , fCameraNeutral ()
67 , fCameraWhiteXY ()
68 , fCameraCalibration1 ()
69 , fCameraCalibration2 ()
70 , fCameraCalibrationSignature ()
71 , fCameraProfile ()
72 , fAsShotProfileName ()
73 , fRawImageDigest ()
74 , fRawDataUniqueID ()
75 , fOriginalRawFileName ()
76 , fHasOriginalRawFileData (false)
77 , fOriginalRawFileData ()
78 , fOriginalRawFileDigest ()
79 , fDNGPrivateData ()
80 , fIsMakerNoteSafe (false)
81 , fMakerNote ()
82 , fExif ()
83 , fOriginalExif ()
84 , fIPTCBlock ()
85 , fIPTCOffset (kDNGStreamInvalidOffset)
86 , fXMP ()
87 , fValidEmbeddedXMP (false)
88 , fXMPinSidecar (false)
89 , fXMPisNewer (false)
90 , fLinearizationInfo ()
91 , fMosaicInfo ()
92 , fStage1Image ()
93 , fStage2Image ()
94 , fStage3Image ()
95 , fStage3Gain (1.0)
96 , fIsPreview (false)
97 , fIsDamaged (false)
98
99 {
100
101 }
102
103 /*****************************************************************************/
104
~dng_negative()105 dng_negative::~dng_negative ()
106 {
107
108 // Delete any camera profiles owned by this negative.
109
110 ClearProfiles ();
111
112 }
113
114 /******************************************************************************/
115
Initialize()116 void dng_negative::Initialize ()
117 {
118
119 fExif.Reset (MakeExif ());
120
121 fXMP.Reset (MakeXMP ());
122
123 }
124
125 /******************************************************************************/
126
Make(dng_memory_allocator & allocator)127 dng_negative * dng_negative::Make (dng_memory_allocator &allocator)
128 {
129
130 AutoPtr<dng_negative> result (new dng_negative (allocator));
131
132 if (!result.Get ())
133 {
134 ThrowMemoryFull ();
135 }
136
137 result->Initialize ();
138
139 return result.Release ();
140
141 }
142
143 /******************************************************************************/
144
SetBaseOrientation(const dng_orientation & orientation)145 void dng_negative::SetBaseOrientation (const dng_orientation &orientation)
146 {
147
148 fHasBaseOrientation = true;
149
150 fBaseOrientation = orientation;
151
152 }
153
154 /******************************************************************************/
155
Orientation() const156 dng_orientation dng_negative::Orientation () const
157 {
158
159 return BaseOrientation ();
160
161 }
162
163 /******************************************************************************/
164
ApplyOrientation(const dng_orientation & orientation)165 void dng_negative::ApplyOrientation (const dng_orientation &orientation)
166 {
167
168 fBaseOrientation += orientation;
169
170 fXMP->SetOrientation (fBaseOrientation);
171
172 }
173
174 /******************************************************************************/
175
SetAnalogBalance(const dng_vector & b)176 void dng_negative::SetAnalogBalance (const dng_vector &b)
177 {
178
179 real64 minEntry = b.MinEntry ();
180
181 if (b.NotEmpty () && minEntry > 0.0)
182 {
183
184 fAnalogBalance = b;
185
186 fAnalogBalance.Scale (1.0 / minEntry);
187
188 fAnalogBalance.Round (1000000.0);
189
190 }
191
192 else
193 {
194
195 fAnalogBalance.Clear ();
196
197 }
198
199 }
200
201 /*****************************************************************************/
202
AnalogBalance(uint32 channel) const203 real64 dng_negative::AnalogBalance (uint32 channel) const
204 {
205
206 DNG_ASSERT (channel < ColorChannels (), "Channel out of bounds");
207
208 if (channel < fAnalogBalance.Count ())
209 {
210
211 return fAnalogBalance [channel];
212
213 }
214
215 return 1.0;
216
217 }
218
219 /*****************************************************************************/
220
AnalogBalanceR(uint32 channel) const221 dng_urational dng_negative::AnalogBalanceR (uint32 channel) const
222 {
223
224 dng_urational result;
225
226 result.Set_real64 (AnalogBalance (channel), 1000000);
227
228 return result;
229
230 }
231
232 /******************************************************************************/
233
SetCameraNeutral(const dng_vector & n)234 void dng_negative::SetCameraNeutral (const dng_vector &n)
235 {
236
237 real64 maxEntry = n.MaxEntry ();
238
239 if (n.NotEmpty () && maxEntry > 0.0)
240 {
241
242 fCameraNeutral = n;
243
244 fCameraNeutral.Scale (1.0 / maxEntry);
245
246 fCameraNeutral.Round (1000000.0);
247
248 }
249
250 else
251 {
252
253 fCameraNeutral.Clear ();
254
255 }
256
257 }
258
259 /*****************************************************************************/
260
CameraNeutralR(uint32 channel) const261 dng_urational dng_negative::CameraNeutralR (uint32 channel) const
262 {
263
264 dng_urational result;
265
266 result.Set_real64 (CameraNeutral () [channel], 1000000);
267
268 return result;
269
270 }
271
272 /******************************************************************************/
273
SetCameraWhiteXY(const dng_xy_coord & coord)274 void dng_negative::SetCameraWhiteXY (const dng_xy_coord &coord)
275 {
276
277 if (coord.IsValid ())
278 {
279
280 fCameraWhiteXY.x = Round_int32 (coord.x * 1000000.0) / 1000000.0;
281 fCameraWhiteXY.y = Round_int32 (coord.y * 1000000.0) / 1000000.0;
282
283 }
284
285 else
286 {
287
288 fCameraWhiteXY.Clear ();
289
290 }
291
292 }
293
294 /*****************************************************************************/
295
CameraWhiteXY() const296 const dng_xy_coord & dng_negative::CameraWhiteXY () const
297 {
298
299 DNG_ASSERT (HasCameraWhiteXY (), "Using undefined CameraWhiteXY");
300
301 return fCameraWhiteXY;
302
303 }
304
305 /*****************************************************************************/
306
GetCameraWhiteXY(dng_urational & x,dng_urational & y) const307 void dng_negative::GetCameraWhiteXY (dng_urational &x,
308 dng_urational &y) const
309 {
310
311 dng_xy_coord coord = CameraWhiteXY ();
312
313 x.Set_real64 (coord.x, 1000000);
314 y.Set_real64 (coord.y, 1000000);
315
316 }
317
318 /*****************************************************************************/
319
SetCameraCalibration1(const dng_matrix & m)320 void dng_negative::SetCameraCalibration1 (const dng_matrix &m)
321 {
322
323 fCameraCalibration1 = m;
324
325 fCameraCalibration1.Round (10000);
326
327 }
328
329 /******************************************************************************/
330
SetCameraCalibration2(const dng_matrix & m)331 void dng_negative::SetCameraCalibration2 (const dng_matrix &m)
332 {
333
334 fCameraCalibration2 = m;
335
336 fCameraCalibration2.Round (10000);
337
338 }
339
340 /******************************************************************************/
341
AddProfile(AutoPtr<dng_camera_profile> & profile)342 void dng_negative::AddProfile (AutoPtr<dng_camera_profile> &profile)
343 {
344
345 // Make sure we have a profile to add.
346
347 if (!profile.Get ())
348 {
349
350 return;
351
352 }
353
354 // We must have some profile name. Use "embedded" if nothing else.
355
356 if (profile->Name ().IsEmpty ())
357 {
358
359 profile->SetName (kProfileName_Embedded);
360
361 }
362
363 // Special case support for reading older DNG files which did not store
364 // the profile name in the main IFD profile.
365
366 if (fCameraProfile.size ())
367 {
368
369 // See the first profile has a default "embedded" name, and has
370 // the same data as the profile we are adding.
371
372 if (fCameraProfile [0]->NameIsEmbedded () &&
373 fCameraProfile [0]->EqualData (*profile.Get ()))
374 {
375
376 // If the profile we are deleting was read from DNG
377 // then the new profile should be marked as such also.
378
379 if (fCameraProfile [0]->WasReadFromDNG ())
380 {
381
382 profile->SetWasReadFromDNG ();
383
384 }
385
386 // Delete the profile with default name.
387
388 delete fCameraProfile [0];
389
390 fCameraProfile [0] = NULL;
391
392 fCameraProfile.erase (fCameraProfile.begin ());
393
394 }
395
396 }
397
398 // Duplicate detection logic. We give a preference to last added profile
399 // so the profiles end up in a more consistent order no matter what profiles
400 // happen to be embedded in the DNG.
401
402 for (uint32 index = 0; index < (uint32) fCameraProfile.size (); index++)
403 {
404
405 if (fCameraProfile [index]->Fingerprint () == profile->Fingerprint ())
406 {
407
408 // If the profile we are deleting was read from DNG
409 // then the new profile should be marked as such also.
410
411 if (fCameraProfile [index]->WasReadFromDNG ())
412 {
413
414 profile->SetWasReadFromDNG ();
415
416 }
417
418 // Delete the profile with default name.
419
420 delete fCameraProfile [index];
421
422 fCameraProfile [index] = NULL;
423
424 fCameraProfile.erase (fCameraProfile.begin () + index);
425
426 break;
427
428 }
429
430 }
431
432 // Now add to profile list.
433
434 fCameraProfile.push_back (NULL);
435
436 fCameraProfile [fCameraProfile.size () - 1] = profile.Release ();
437
438 }
439
440 /******************************************************************************/
441
ClearProfiles()442 void dng_negative::ClearProfiles ()
443 {
444
445 // Delete any camera profiles owned by this negative.
446
447 for (uint32 index = 0; index < (uint32) fCameraProfile.size (); index++)
448 {
449
450 if (fCameraProfile [index])
451 {
452
453 delete fCameraProfile [index];
454
455 fCameraProfile [index] = NULL;
456
457 }
458
459 }
460
461 // Now empty list.
462
463 fCameraProfile.clear ();
464
465 }
466
467 /******************************************************************************/
468
ProfileCount() const469 uint32 dng_negative::ProfileCount () const
470 {
471
472 return (uint32) fCameraProfile.size ();
473
474 }
475
476 /******************************************************************************/
477
ProfileByIndex(uint32 index) const478 const dng_camera_profile & dng_negative::ProfileByIndex (uint32 index) const
479 {
480
481 DNG_ASSERT (index < ProfileCount (),
482 "Invalid index for ProfileByIndex");
483
484 return *fCameraProfile [index];
485
486 }
487
488 /*****************************************************************************/
489
ProfileByID(const dng_camera_profile_id & id,bool useDefaultIfNoMatch) const490 const dng_camera_profile * dng_negative::ProfileByID (const dng_camera_profile_id &id,
491 bool useDefaultIfNoMatch) const
492 {
493
494 // If this negative does not have any profiles, we are not going to
495 // find a match.
496
497 uint32 profileCount = ProfileCount ();
498
499 if (profileCount == 0)
500 {
501 return NULL;
502 }
503
504 // If we have both a profile name and fingerprint, try matching both.
505
506 if (id.Name ().NotEmpty () && id.Fingerprint ().IsValid ())
507 {
508
509 for (uint32 index = 0; index < profileCount; index++)
510 {
511
512 const dng_camera_profile &profile = ProfileByIndex (index);
513
514 if (id.Name () == profile.Name () &&
515 id.Fingerprint () == profile.Fingerprint ())
516 {
517
518 return &profile;
519
520 }
521
522 }
523
524 }
525
526 // If we have a name, try matching that.
527
528 if (id.Name ().NotEmpty ())
529 {
530
531 for (uint32 index = 0; index < profileCount; index++)
532 {
533
534 const dng_camera_profile &profile = ProfileByIndex (index);
535
536 if (id.Name () == profile.Name ())
537 {
538
539 return &profile;
540
541 }
542
543 }
544
545 }
546
547 // If we have a valid fingerprint, try matching that.
548
549 if (id.Fingerprint ().IsValid ())
550 {
551
552 for (uint32 index = 0; index < profileCount; index++)
553 {
554
555 const dng_camera_profile &profile = ProfileByIndex (index);
556
557 if (id.Fingerprint () == profile.Fingerprint ())
558 {
559
560 return &profile;
561
562 }
563
564 }
565
566 }
567
568 // Did not find a match either way. See if we should return a default
569 // value.
570
571 if (useDefaultIfNoMatch)
572 {
573
574 return &ProfileByIndex (0);
575
576 }
577
578 // Found nothing.
579
580 return NULL;
581
582 }
583
584 /*****************************************************************************/
585
CameraProfileToEmbed() const586 const dng_camera_profile * dng_negative::CameraProfileToEmbed () const
587 {
588
589 uint32 index;
590
591 uint32 count = ProfileCount ();
592
593 if (count == 0)
594 {
595
596 return NULL;
597
598 }
599
600 // First try to look for the first profile that was already in the DNG
601 // when we read it.
602
603 for (index = 0; index < count; index++)
604 {
605
606 const dng_camera_profile &profile (ProfileByIndex (index));
607
608 if (profile.WasReadFromDNG ())
609 {
610
611 return &profile;
612
613 }
614
615 }
616
617 // Next we look for the first profile that is legal to embed.
618
619 for (index = 0; index < count; index++)
620 {
621
622 const dng_camera_profile &profile (ProfileByIndex (index));
623
624 if (profile.IsLegalToEmbed ())
625 {
626
627 return &profile;
628
629 }
630
631 }
632
633 // Else just return the first profile.
634
635 return fCameraProfile [0];
636
637 }
638
639 /*****************************************************************************/
640
MakeColorSpec(const dng_camera_profile_id & id) const641 dng_color_spec * dng_negative::MakeColorSpec (const dng_camera_profile_id &id) const
642 {
643
644 dng_color_spec *spec = new dng_color_spec (*this, ProfileByID (id));
645
646 if (!spec)
647 {
648 ThrowMemoryFull ();
649 }
650
651 return spec;
652
653 }
654
655 /*****************************************************************************/
656
FindRawImageDigest(dng_host & host) const657 void dng_negative::FindRawImageDigest (dng_host &host) const
658 {
659
660 if (fRawImageDigest.IsNull ())
661 {
662
663 const dng_image &image = RawImage ();
664
665 dng_md5_printer printer;
666
667 dng_pixel_buffer buffer;
668
669 buffer.fPlane = 0;
670 buffer.fPlanes = image.Planes ();
671
672 buffer.fRowStep = image.Planes () * image.Width ();
673 buffer.fColStep = image.Planes ();
674 buffer.fPlaneStep = 1;
675
676 buffer.fPixelType = image.PixelType ();
677 buffer.fPixelSize = image.PixelSize ();
678
679 // Sometimes we expand 8-bit data to 16-bit data while reading or
680 // writing, so always compute the digest of 8-bit data as 16-bits.
681
682 if (buffer.fPixelType == ttByte)
683 {
684 buffer.fPixelType = ttShort;
685 buffer.fPixelSize = 2;
686 }
687
688 const uint32 kBufferRows = 16;
689
690 uint32 bufferBytes = kBufferRows * buffer.fRowStep * buffer.fPixelSize;
691
692 AutoPtr<dng_memory_block> bufferData (host.Allocate (bufferBytes));
693
694 buffer.fData = bufferData->Buffer ();
695
696 dng_rect area;
697
698 dng_tile_iterator iter (dng_point (kBufferRows,
699 image.Width ()),
700 image.Bounds ());
701
702 while (iter.GetOneTile (area))
703 {
704
705 host.SniffForAbort ();
706
707 buffer.fArea = area;
708
709 image.Get (buffer);
710
711 uint32 count = buffer.fArea.H () *
712 buffer.fRowStep *
713 buffer.fPixelSize;
714
715 #if qDNGBigEndian
716
717 // We need to use the same byte order to compute
718 // the digest, no matter the native order. Little-endian
719 // is more common now, so use that.
720
721 switch (buffer.fPixelSize)
722 {
723
724 case 1:
725 break;
726
727 case 2:
728 {
729 DoSwapBytes16 ((uint16 *) buffer.fData, count >> 1);
730 break;
731 }
732
733 case 4:
734 {
735 DoSwapBytes32 ((uint32 *) buffer.fData, count >> 2);
736 break;
737 }
738
739 default:
740 {
741 DNG_REPORT ("Unexpected pixel size");
742 break;
743 }
744
745 }
746
747 #endif
748
749 printer.Process (buffer.fData,
750 count);
751
752 }
753
754 fRawImageDigest = printer.Result ();
755
756 }
757
758 }
759
760 /*****************************************************************************/
761
ValidateRawImageDigest(dng_host & host)762 void dng_negative::ValidateRawImageDigest (dng_host &host)
763 {
764
765 if (Stage1Image () && !IsPreview () && fRawImageDigest.IsValid ())
766 {
767
768 dng_fingerprint oldDigest = fRawImageDigest;
769
770 try
771 {
772
773 fRawImageDigest.Clear ();
774
775 FindRawImageDigest (host);
776
777 }
778
779 catch (...)
780 {
781
782 fRawImageDigest = oldDigest;
783
784 throw;
785
786 }
787
788 if (oldDigest != fRawImageDigest)
789 {
790
791 #if qDNGValidate
792
793 ReportError ("RawImageDigest does not match raw image");
794
795 #else
796
797 #if 0 // FIX_ME_TFK: Disable for now so the warning code get more testing.
798
799 // Note that Lightroom 1.4 Windows had a bug that corrupts the
800 // first four bytes of the RawImageDigest tag. So if the last
801 // twelve bytes match, this is very likely the result of the
802 // bug, and not an actual corrupt file. So don't report this
803 // to the user--just fix it.
804
805 {
806
807 bool matchLast12 = true;
808
809 for (uint32 j = 4; j < 16; j++)
810 {
811 matchLast12 = matchLast12 && (oldDigest.data [j] == fRawImageDigest.data [j]);
812 }
813
814 if (matchLast12)
815 {
816 return;
817 }
818
819 }
820
821 #endif
822
823 SetIsDamaged (true);
824
825 #endif
826
827 }
828
829 }
830
831 }
832
833 /*****************************************************************************/
834
835 // If the raw data unique ID is missing, compute one based on a MD5 hash of
836 // the raw image data and the model name.
837
FindRawDataUniqueID(dng_host & host) const838 void dng_negative::FindRawDataUniqueID (dng_host &host) const
839 {
840
841 if (fRawDataUniqueID.IsNull ())
842 {
843
844 FindRawImageDigest (host);
845
846 dng_md5_printer printer;
847
848 printer.Process (fRawImageDigest.data, 16);
849
850 printer.Process (ModelName ().Get (),
851 ModelName ().Length ());
852
853 fRawDataUniqueID = printer.Result ();
854
855 }
856
857 }
858
859 /******************************************************************************/
860
FindOriginalRawFileDigest() const861 void dng_negative::FindOriginalRawFileDigest () const
862 {
863
864 if (fOriginalRawFileDigest.IsNull () && fOriginalRawFileData.Get ())
865 {
866
867 dng_md5_printer printer;
868
869 printer.Process (fOriginalRawFileData->Buffer (),
870 fOriginalRawFileData->LogicalSize ());
871
872 fOriginalRawFileDigest = printer.Result ();
873
874 }
875
876 }
877
878 /*****************************************************************************/
879
ValidateOriginalRawFileDigest()880 void dng_negative::ValidateOriginalRawFileDigest ()
881 {
882
883 if (fOriginalRawFileDigest.IsValid () && fOriginalRawFileData.Get ())
884 {
885
886 dng_fingerprint oldDigest = fOriginalRawFileDigest;
887
888 try
889 {
890
891 fOriginalRawFileDigest.Clear ();
892
893 FindOriginalRawFileDigest ();
894
895 }
896
897 catch (...)
898 {
899
900 fOriginalRawFileDigest = oldDigest;
901
902 throw;
903
904 }
905
906 if (oldDigest != fOriginalRawFileDigest)
907 {
908
909 #if qDNGValidate
910
911 ReportError ("OriginalRawFileDigest does not match OriginalRawFileData");
912
913 #else
914
915 SetIsDamaged (true);
916
917 #endif
918
919 // Don't "repair" the original image data digest. Once it is
920 // bad, it stays bad. The user cannot tell by looking at the image
921 // whether the damage is acceptable and can be ignored in the
922 // future.
923
924 fOriginalRawFileDigest = oldDigest;
925
926 }
927
928 }
929
930 }
931
932 /******************************************************************************/
933
DefaultCropArea(real64 scaleH,real64 scaleV) const934 dng_rect dng_negative::DefaultCropArea (real64 scaleH,
935 real64 scaleV) const
936 {
937
938 const dng_image *image = Stage3Image ();
939
940 DNG_ASSERT (image, "DefaultCropArea on NULL image");
941
942 dng_point scaledSize;
943
944 scaledSize.h = Round_int32 (image->Width () * scaleH);
945 scaledSize.v = Round_int32 (image->Height () * scaleV);
946
947 // First compute the area using simple rounding.
948
949 dng_rect result;
950
951 result.l = Round_int32 (fDefaultCropOriginH.As_real64 () * fRawToFullScaleH * scaleH);
952 result.t = Round_int32 (fDefaultCropOriginV.As_real64 () * fRawToFullScaleV * scaleV);
953
954 result.r = result.l + Round_int32 (fDefaultCropSizeH.As_real64 () * fRawToFullScaleH * scaleH);
955 result.b = result.t + Round_int32 (fDefaultCropSizeV.As_real64 () * fRawToFullScaleV * scaleV);
956
957 // Sometimes the simple rounding causes the resulting default crop
958 // area to slide off the scaled image area. So we force this not
959 // to happen.
960
961 if (result.r > scaledSize.h)
962 {
963 result.l -= result.r - scaledSize.h;
964 result.r = scaledSize.h;
965 }
966
967 if (result.b > scaledSize.v)
968 {
969 result.t -= result.b - scaledSize.v;
970 result.b = scaledSize.v;
971 }
972
973 return result;
974
975 }
976
977 /******************************************************************************/
978
SetShadowScale(const dng_urational & scale)979 void dng_negative::SetShadowScale (const dng_urational &scale)
980 {
981
982 if (scale.d > 0)
983 {
984
985 real64 s = scale.As_real64 ();
986
987 if (s > 0.0 && s <= 1.0)
988 {
989
990 fShadowScale = scale;
991
992 }
993
994 }
995
996 }
997
998 /******************************************************************************/
999
BuildExifBlock(const dng_resolution * resolution,bool includeIPTC) const1000 dng_memory_block * dng_negative::BuildExifBlock (const dng_resolution *resolution,
1001 bool includeIPTC) const
1002 {
1003
1004 dng_memory_stream stream (Allocator ());
1005
1006 {
1007
1008 // Create the main IFD
1009
1010 dng_tiff_directory mainIFD;
1011
1012 // Optionally include the resolution tags.
1013
1014 dng_resolution res;
1015
1016 if (resolution)
1017 {
1018 res = *resolution;
1019 }
1020
1021 tag_urational tagXResolution (tcXResolution, res.fXResolution);
1022 tag_urational tagYResolution (tcYResolution, res.fYResolution);
1023
1024 tag_uint16 tagResolutionUnit (tcResolutionUnit, res.fResolutionUnit);
1025
1026 if (resolution)
1027 {
1028 mainIFD.Add (&tagXResolution );
1029 mainIFD.Add (&tagYResolution );
1030 mainIFD.Add (&tagResolutionUnit);
1031 }
1032
1033 // Optionally include IPTC block.
1034
1035 tag_iptc tagIPTC (IPTCData (),
1036 IPTCLength ());
1037
1038 if (includeIPTC && tagIPTC.Count ())
1039 {
1040
1041 mainIFD.Add (&tagIPTC);
1042
1043 }
1044
1045 // Exif tags.
1046
1047 exif_tag_set exifSet (mainIFD,
1048 *GetExif (),
1049 IsMakerNoteSafe (),
1050 MakerNoteData (),
1051 MakerNoteLength (),
1052 false);
1053
1054 // Figure out the Exif IFD offset.
1055
1056 exifSet.Locate (8 + mainIFD.Size ());
1057
1058 // Write TIFF Header.
1059
1060 stream.SetWritePosition (0);
1061
1062 stream.Put_uint16 (stream.BigEndian () ? byteOrderMM : byteOrderII);
1063
1064 stream.Put_uint16 (42);
1065
1066 stream.Put_uint32 (8);
1067
1068 // Write the IFDs.
1069
1070 mainIFD.Put (stream);
1071
1072 exifSet.Put (stream);
1073
1074 // Trim the file to this length.
1075
1076 stream.Flush ();
1077
1078 stream.SetLength (stream.Position ());
1079
1080 }
1081
1082 return stream.AsMemoryBlock (Allocator ());
1083
1084 }
1085
1086 /******************************************************************************/
1087
SetIPTC(AutoPtr<dng_memory_block> & block,uint64 offset)1088 void dng_negative::SetIPTC (AutoPtr<dng_memory_block> &block, uint64 offset)
1089 {
1090
1091 fIPTCBlock.Reset (block.Release ());
1092
1093 fIPTCOffset = offset;
1094
1095 }
1096
1097 /******************************************************************************/
1098
SetIPTC(AutoPtr<dng_memory_block> & block)1099 void dng_negative::SetIPTC (AutoPtr<dng_memory_block> &block)
1100 {
1101
1102 SetIPTC (block, kDNGStreamInvalidOffset);
1103
1104 }
1105
1106 /******************************************************************************/
1107
ClearIPTC()1108 void dng_negative::ClearIPTC ()
1109 {
1110
1111 fIPTCBlock.Reset ();
1112
1113 fIPTCOffset = kDNGStreamInvalidOffset;
1114
1115 }
1116
1117 /*****************************************************************************/
1118
IPTCData() const1119 const void * dng_negative::IPTCData () const
1120 {
1121
1122 if (fIPTCBlock.Get ())
1123 {
1124
1125 return fIPTCBlock->Buffer ();
1126
1127 }
1128
1129 return NULL;
1130
1131 }
1132
1133 /*****************************************************************************/
1134
IPTCLength() const1135 uint32 dng_negative::IPTCLength () const
1136 {
1137
1138 if (fIPTCBlock.Get ())
1139 {
1140
1141 return fIPTCBlock->LogicalSize ();
1142
1143 }
1144
1145 return 0;
1146
1147 }
1148
1149 /*****************************************************************************/
1150
IPTCOffset() const1151 uint64 dng_negative::IPTCOffset () const
1152 {
1153
1154 if (fIPTCBlock.Get ())
1155 {
1156
1157 return fIPTCOffset;
1158
1159 }
1160
1161 return kDNGStreamInvalidOffset;
1162
1163 }
1164
1165 /*****************************************************************************/
1166
IPTCDigest() const1167 dng_fingerprint dng_negative::IPTCDigest () const
1168 {
1169
1170 if (IPTCLength ())
1171 {
1172
1173 dng_md5_printer printer;
1174
1175 const uint8 *data = (const uint8 *) IPTCData ();
1176
1177 uint32 count = IPTCLength ();
1178
1179 // Because of some stupid ways of storing the IPTC data, the IPTC
1180 // data might be padded with up to three zeros. Don't include
1181 // these zero pad bytes in the digest.
1182
1183 uint32 removed = 0;
1184
1185 while ((removed < 3) && (count > 0) && (data [count - 1] == 0))
1186 {
1187 removed++;
1188 count--;
1189 }
1190
1191 printer.Process (data, count);
1192
1193 return printer.Result ();
1194
1195 }
1196
1197 return dng_fingerprint ();
1198
1199 }
1200
1201 /******************************************************************************/
1202
RebuildIPTC()1203 void dng_negative::RebuildIPTC ()
1204 {
1205
1206 ClearIPTC ();
1207
1208 fXMP->RebuildIPTC (*this);
1209
1210 dng_fingerprint digest = IPTCDigest ();
1211
1212 fXMP->SetIPTCDigest (digest);
1213
1214 }
1215
1216 /*****************************************************************************/
1217
SetXMP(dng_host & host,const void * buffer,uint32 count,bool xmpInSidecar,bool xmpIsNewer)1218 bool dng_negative::SetXMP (dng_host &host,
1219 const void *buffer,
1220 uint32 count,
1221 bool xmpInSidecar,
1222 bool xmpIsNewer)
1223 {
1224
1225 bool result = false;
1226
1227 try
1228 {
1229
1230 AutoPtr<dng_xmp> tempXMP (MakeXMP ());
1231
1232 tempXMP->Parse (host, buffer, count);
1233
1234 fXMP.Reset (tempXMP.Release ());
1235
1236 fXMPinSidecar = xmpInSidecar;
1237
1238 fXMPisNewer = xmpIsNewer;
1239
1240 result = true;
1241
1242 }
1243
1244 catch (dng_exception &except)
1245 {
1246
1247 // Don't ignore transient errors.
1248
1249 if (host.IsTransientError (except.ErrorCode ()))
1250 {
1251
1252 throw;
1253
1254 }
1255
1256 // Eat other parsing errors.
1257
1258 }
1259
1260 catch (...)
1261 {
1262
1263 // Eat unknown parsing exceptions.
1264
1265 }
1266
1267 return result;
1268
1269 }
1270
1271 /******************************************************************************/
1272
SetActiveArea(const dng_rect & area)1273 void dng_negative::SetActiveArea (const dng_rect &area)
1274 {
1275
1276 NeedLinearizationInfo ();
1277
1278 dng_linearization_info &info = *fLinearizationInfo.Get ();
1279
1280 info.fActiveArea = area;
1281
1282 }
1283
1284 /******************************************************************************/
1285
SetMaskedAreas(uint32 count,const dng_rect * area)1286 void dng_negative::SetMaskedAreas (uint32 count,
1287 const dng_rect *area)
1288 {
1289
1290 DNG_ASSERT (count <= kMaxMaskedAreas, "Too many masked areas");
1291
1292 NeedLinearizationInfo ();
1293
1294 dng_linearization_info &info = *fLinearizationInfo.Get ();
1295
1296 info.fMaskedAreaCount = Min_uint32 (count, kMaxMaskedAreas);
1297
1298 for (uint32 index = 0; index < info.fMaskedAreaCount; index++)
1299 {
1300
1301 info.fMaskedArea [index] = area [index];
1302
1303 }
1304
1305 }
1306
1307 /*****************************************************************************/
1308
SetLinearization(AutoPtr<dng_memory_block> & curve)1309 void dng_negative::SetLinearization (AutoPtr<dng_memory_block> &curve)
1310 {
1311
1312 NeedLinearizationInfo ();
1313
1314 dng_linearization_info &info = *fLinearizationInfo.Get ();
1315
1316 info.fLinearizationTable.Reset (curve.Release ());
1317
1318 }
1319
1320 /*****************************************************************************/
1321
SetBlackLevel(real64 black,int32 plane)1322 void dng_negative::SetBlackLevel (real64 black,
1323 int32 plane)
1324 {
1325
1326 NeedLinearizationInfo ();
1327
1328 dng_linearization_info &info = *fLinearizationInfo.Get ();
1329
1330 info.fBlackLevelRepeatRows = 1;
1331 info.fBlackLevelRepeatCols = 1;
1332
1333 if (plane < 0)
1334 {
1335
1336 for (uint32 j = 0; j < kMaxSamplesPerPixel; j++)
1337 {
1338
1339 info.fBlackLevel [0] [0] [j] = black;
1340
1341 }
1342
1343 }
1344
1345 else
1346 {
1347
1348 info.fBlackLevel [0] [0] [plane] = black;
1349
1350 }
1351
1352 info.RoundBlacks ();
1353
1354 }
1355
1356 /*****************************************************************************/
1357
SetQuadBlacks(real64 black0,real64 black1,real64 black2,real64 black3)1358 void dng_negative::SetQuadBlacks (real64 black0,
1359 real64 black1,
1360 real64 black2,
1361 real64 black3)
1362 {
1363
1364 NeedLinearizationInfo ();
1365
1366 dng_linearization_info &info = *fLinearizationInfo.Get ();
1367
1368 info.fBlackLevelRepeatRows = 2;
1369 info.fBlackLevelRepeatCols = 2;
1370
1371 for (uint32 j = 0; j < kMaxSamplesPerPixel; j++)
1372 {
1373
1374 info.fBlackLevel [0] [0] [j] = black0;
1375 info.fBlackLevel [0] [1] [j] = black1;
1376 info.fBlackLevel [1] [0] [j] = black2;
1377 info.fBlackLevel [1] [1] [j] = black3;
1378
1379 }
1380
1381 info.RoundBlacks ();
1382
1383 }
1384
1385 /*****************************************************************************/
1386
SetRowBlacks(const real64 * blacks,uint32 count)1387 void dng_negative::SetRowBlacks (const real64 *blacks,
1388 uint32 count)
1389 {
1390
1391 if (count)
1392 {
1393
1394 NeedLinearizationInfo ();
1395
1396 dng_linearization_info &info = *fLinearizationInfo.Get ();
1397
1398 uint32 byteCount = count * sizeof (real64);
1399
1400 info.fBlackDeltaV.Reset (Allocator ().Allocate (byteCount));
1401
1402 DoCopyBytes (blacks,
1403 info.fBlackDeltaV->Buffer (),
1404 byteCount);
1405
1406 info.RoundBlacks ();
1407
1408 }
1409
1410 else if (fLinearizationInfo.Get ())
1411 {
1412
1413 dng_linearization_info &info = *fLinearizationInfo.Get ();
1414
1415 info.fBlackDeltaV.Reset ();
1416
1417 }
1418
1419 }
1420
1421 /*****************************************************************************/
1422
SetColumnBlacks(const real64 * blacks,uint32 count)1423 void dng_negative::SetColumnBlacks (const real64 *blacks,
1424 uint32 count)
1425 {
1426
1427 if (count)
1428 {
1429
1430 NeedLinearizationInfo ();
1431
1432 dng_linearization_info &info = *fLinearizationInfo.Get ();
1433
1434 uint32 byteCount = count * sizeof (real64);
1435
1436 info.fBlackDeltaH.Reset (Allocator ().Allocate (byteCount));
1437
1438 DoCopyBytes (blacks,
1439 info.fBlackDeltaH->Buffer (),
1440 byteCount);
1441
1442 info.RoundBlacks ();
1443
1444 }
1445
1446 else if (fLinearizationInfo.Get ())
1447 {
1448
1449 dng_linearization_info &info = *fLinearizationInfo.Get ();
1450
1451 info.fBlackDeltaH.Reset ();
1452
1453 }
1454
1455 }
1456
1457 /*****************************************************************************/
1458
WhiteLevel(uint32 plane) const1459 uint32 dng_negative::WhiteLevel (uint32 plane) const
1460 {
1461
1462 if (fLinearizationInfo.Get ())
1463 {
1464
1465 const dng_linearization_info &info = *fLinearizationInfo.Get ();
1466
1467 return Round_uint32 (info.fWhiteLevel [plane]);
1468
1469 }
1470
1471 return 0x0FFFF;
1472
1473 }
1474
1475 /*****************************************************************************/
1476
SetWhiteLevel(uint32 white,int32 plane)1477 void dng_negative::SetWhiteLevel (uint32 white,
1478 int32 plane)
1479 {
1480
1481 NeedLinearizationInfo ();
1482
1483 dng_linearization_info &info = *fLinearizationInfo.Get ();
1484
1485 if (plane < 0)
1486 {
1487
1488 for (uint32 j = 0; j < kMaxSamplesPerPixel; j++)
1489 {
1490
1491 info.fWhiteLevel [j] = (real64) white;
1492
1493 }
1494
1495 }
1496
1497 else
1498 {
1499
1500 info.fWhiteLevel [plane] = (real64) white;
1501
1502 }
1503
1504 }
1505
1506 /******************************************************************************/
1507
SetColorKeys(ColorKeyCode color0,ColorKeyCode color1,ColorKeyCode color2,ColorKeyCode color3)1508 void dng_negative::SetColorKeys (ColorKeyCode color0,
1509 ColorKeyCode color1,
1510 ColorKeyCode color2,
1511 ColorKeyCode color3)
1512 {
1513
1514 NeedMosaicInfo ();
1515
1516 dng_mosaic_info &info = *fMosaicInfo.Get ();
1517
1518 info.fCFAPlaneColor [0] = color0;
1519 info.fCFAPlaneColor [1] = color1;
1520 info.fCFAPlaneColor [2] = color2;
1521 info.fCFAPlaneColor [3] = color3;
1522
1523 }
1524
1525 /******************************************************************************/
1526
SetBayerMosaic(uint32 phase)1527 void dng_negative::SetBayerMosaic (uint32 phase)
1528 {
1529
1530 NeedMosaicInfo ();
1531
1532 dng_mosaic_info &info = *fMosaicInfo.Get ();
1533
1534 ColorKeyCode color0 = (ColorKeyCode) info.fCFAPlaneColor [0];
1535 ColorKeyCode color1 = (ColorKeyCode) info.fCFAPlaneColor [1];
1536 ColorKeyCode color2 = (ColorKeyCode) info.fCFAPlaneColor [2];
1537
1538 info.fCFAPatternSize = dng_point (2, 2);
1539
1540 switch (phase)
1541 {
1542
1543 case 0:
1544 {
1545 info.fCFAPattern [0] [0] = color1;
1546 info.fCFAPattern [0] [1] = color0;
1547 info.fCFAPattern [1] [0] = color2;
1548 info.fCFAPattern [1] [1] = color1;
1549 break;
1550 }
1551
1552 case 1:
1553 {
1554 info.fCFAPattern [0] [0] = color0;
1555 info.fCFAPattern [0] [1] = color1;
1556 info.fCFAPattern [1] [0] = color1;
1557 info.fCFAPattern [1] [1] = color2;
1558 break;
1559 }
1560
1561 case 2:
1562 {
1563 info.fCFAPattern [0] [0] = color2;
1564 info.fCFAPattern [0] [1] = color1;
1565 info.fCFAPattern [1] [0] = color1;
1566 info.fCFAPattern [1] [1] = color0;
1567 break;
1568 }
1569
1570 case 3:
1571 {
1572 info.fCFAPattern [0] [0] = color1;
1573 info.fCFAPattern [0] [1] = color2;
1574 info.fCFAPattern [1] [0] = color0;
1575 info.fCFAPattern [1] [1] = color1;
1576 break;
1577 }
1578
1579 }
1580
1581 info.fColorPlanes = 3;
1582
1583 info.fCFALayout = 1;
1584
1585 }
1586
1587 /******************************************************************************/
1588
SetFujiMosaic(uint32 phase)1589 void dng_negative::SetFujiMosaic (uint32 phase)
1590 {
1591
1592 NeedMosaicInfo ();
1593
1594 dng_mosaic_info &info = *fMosaicInfo.Get ();
1595
1596 ColorKeyCode color0 = (ColorKeyCode) info.fCFAPlaneColor [0];
1597 ColorKeyCode color1 = (ColorKeyCode) info.fCFAPlaneColor [1];
1598 ColorKeyCode color2 = (ColorKeyCode) info.fCFAPlaneColor [2];
1599
1600 info.fCFAPatternSize = dng_point (2, 4);
1601
1602 switch (phase)
1603 {
1604
1605 case 0:
1606 {
1607 info.fCFAPattern [0] [0] = color0;
1608 info.fCFAPattern [0] [1] = color1;
1609 info.fCFAPattern [0] [2] = color2;
1610 info.fCFAPattern [0] [3] = color1;
1611 info.fCFAPattern [1] [0] = color2;
1612 info.fCFAPattern [1] [1] = color1;
1613 info.fCFAPattern [1] [2] = color0;
1614 info.fCFAPattern [1] [3] = color1;
1615 break;
1616 }
1617
1618 case 1:
1619 {
1620 info.fCFAPattern [0] [0] = color2;
1621 info.fCFAPattern [0] [1] = color1;
1622 info.fCFAPattern [0] [2] = color0;
1623 info.fCFAPattern [0] [3] = color1;
1624 info.fCFAPattern [1] [0] = color0;
1625 info.fCFAPattern [1] [1] = color1;
1626 info.fCFAPattern [1] [2] = color2;
1627 info.fCFAPattern [1] [3] = color1;
1628 break;
1629 }
1630
1631 }
1632
1633 info.fColorPlanes = 3;
1634
1635 info.fCFALayout = 2;
1636
1637 }
1638
1639 /******************************************************************************/
1640
SetQuadMosaic(uint32 pattern)1641 void dng_negative::SetQuadMosaic (uint32 pattern)
1642 {
1643
1644 // The pattern of the four colors is assumed to be repeat at least every two
1645 // columns and eight rows. The pattern is encoded as a 32-bit integer,
1646 // with every two bits encoding a color, in scan order for two columns and
1647 // eight rows (lsb is first). The usual color coding is:
1648 //
1649 // 0 = Green
1650 // 1 = Magenta
1651 // 2 = Cyan
1652 // 3 = Yellow
1653 //
1654 // Examples:
1655 //
1656 // PowerShot 600 uses 0xe1e4e1e4:
1657 //
1658 // 0 1 2 3 4 5
1659 // 0 G M G M G M
1660 // 1 C Y C Y C Y
1661 // 2 M G M G M G
1662 // 3 C Y C Y C Y
1663 //
1664 // PowerShot A5 uses 0x1e4e1e4e:
1665 //
1666 // 0 1 2 3 4 5
1667 // 0 C Y C Y C Y
1668 // 1 G M G M G M
1669 // 2 C Y C Y C Y
1670 // 3 M G M G M G
1671 //
1672 // PowerShot A50 uses 0x1b4e4b1e:
1673 //
1674 // 0 1 2 3 4 5
1675 // 0 C Y C Y C Y
1676 // 1 M G M G M G
1677 // 2 Y C Y C Y C
1678 // 3 G M G M G M
1679 // 4 C Y C Y C Y
1680 // 5 G M G M G M
1681 // 6 Y C Y C Y C
1682 // 7 M G M G M G
1683 //
1684 // PowerShot Pro70 uses 0x1e4b4e1b:
1685 //
1686 // 0 1 2 3 4 5
1687 // 0 Y C Y C Y C
1688 // 1 M G M G M G
1689 // 2 C Y C Y C Y
1690 // 3 G M G M G M
1691 // 4 Y C Y C Y C
1692 // 5 G M G M G M
1693 // 6 C Y C Y C Y
1694 // 7 M G M G M G
1695 //
1696 // PowerShots Pro90 and G1 use 0xb4b4b4b4:
1697 //
1698 // 0 1 2 3 4 5
1699 // 0 G M G M G M
1700 // 1 Y C Y C Y C
1701
1702 NeedMosaicInfo ();
1703
1704 dng_mosaic_info &info = *fMosaicInfo.Get ();
1705
1706 if (((pattern >> 16) & 0x0FFFF) != (pattern & 0x0FFFF))
1707 {
1708 info.fCFAPatternSize = dng_point (8, 2);
1709 }
1710
1711 else if (((pattern >> 8) & 0x0FF) != (pattern & 0x0FF))
1712 {
1713 info.fCFAPatternSize = dng_point (4, 2);
1714 }
1715
1716 else
1717 {
1718 info.fCFAPatternSize = dng_point (2, 2);
1719 }
1720
1721 for (int32 row = 0; row < info.fCFAPatternSize.v; row++)
1722 {
1723
1724 for (int32 col = 0; col < info.fCFAPatternSize.h; col++)
1725 {
1726
1727 uint32 index = (pattern >> ((((row << 1) & 14) + (col & 1)) << 1)) & 3;
1728
1729 info.fCFAPattern [row] [col] = info.fCFAPlaneColor [index];
1730
1731 }
1732
1733 }
1734
1735 info.fColorPlanes = 4;
1736
1737 info.fCFALayout = 1;
1738
1739 }
1740
1741 /******************************************************************************/
1742
SetGreenSplit(uint32 split)1743 void dng_negative::SetGreenSplit (uint32 split)
1744 {
1745
1746 NeedMosaicInfo ();
1747
1748 dng_mosaic_info &info = *fMosaicInfo.Get ();
1749
1750 info.fBayerGreenSplit = split;
1751
1752 }
1753
1754 /*****************************************************************************/
1755
Parse(dng_host & host,dng_stream & stream,dng_info & info)1756 void dng_negative::Parse (dng_host &host,
1757 dng_stream &stream,
1758 dng_info &info)
1759 {
1760
1761 // Shared info.
1762
1763 dng_shared &shared = *(info.fShared.Get ());
1764
1765 // Find IFD holding the main raw information.
1766
1767 dng_ifd &rawIFD = *info.fIFD [info.fMainIndex].Get ();
1768
1769 // Model name.
1770
1771 SetModelName (shared.fUniqueCameraModel.Get ());
1772
1773 // Localized model name.
1774
1775 SetLocalName (shared.fLocalizedCameraModel.Get ());
1776
1777 // Base orientation.
1778
1779 {
1780
1781 uint32 orientation = info.fIFD [0]->fOrientation;
1782
1783 if (orientation >= 1 && orientation <= 8)
1784 {
1785
1786 SetBaseOrientation (dng_orientation::TIFFtoDNG (orientation));
1787
1788 }
1789
1790 }
1791
1792 // Default crop rectangle.
1793
1794 SetDefaultCropSize (rawIFD.fDefaultCropSizeH,
1795 rawIFD.fDefaultCropSizeV);
1796
1797 SetDefaultCropOrigin (rawIFD.fDefaultCropOriginH,
1798 rawIFD.fDefaultCropOriginV);
1799
1800 // Default scale.
1801
1802 SetDefaultScale (rawIFD.fDefaultScaleH,
1803 rawIFD.fDefaultScaleV);
1804
1805 // Best quality scale.
1806
1807 SetBestQualityScale (rawIFD.fBestQualityScale);
1808
1809 // Baseline noise.
1810
1811 SetBaselineNoise (shared.fBaselineNoise.As_real64 ());
1812
1813 // NoiseReductionApplied.
1814
1815 SetNoiseReductionApplied (shared.fNoiseReductionApplied);
1816
1817 // Baseline exposure.
1818
1819 SetBaselineExposure (shared.fBaselineExposure.As_real64 ());
1820
1821 // Baseline sharpness.
1822
1823 SetBaselineSharpness (shared.fBaselineSharpness.As_real64 ());
1824
1825 // Chroma blur radius.
1826
1827 SetChromaBlurRadius (rawIFD.fChromaBlurRadius);
1828
1829 // Anti-alias filter strength.
1830
1831 SetAntiAliasStrength (rawIFD.fAntiAliasStrength);
1832
1833 // Linear response limit.
1834
1835 SetLinearResponseLimit (shared.fLinearResponseLimit.As_real64 ());
1836
1837 // Shadow scale.
1838
1839 SetShadowScale (shared.fShadowScale);
1840
1841 // Colorimetric reference.
1842
1843 SetColorimetricReference (shared.fColorimetricReference);
1844
1845 // Color channels.
1846
1847 SetColorChannels (shared.fCameraProfile.fColorPlanes);
1848
1849 // Analog balance.
1850
1851 if (shared.fAnalogBalance.NotEmpty ())
1852 {
1853
1854 SetAnalogBalance (shared.fAnalogBalance);
1855
1856 }
1857
1858 // Camera calibration matrices
1859
1860 if (shared.fCameraCalibration1.NotEmpty ())
1861 {
1862
1863 SetCameraCalibration1 (shared.fCameraCalibration1);
1864
1865 }
1866
1867 if (shared.fCameraCalibration2.NotEmpty ())
1868 {
1869
1870 SetCameraCalibration2 (shared.fCameraCalibration2);
1871
1872 }
1873
1874 if (shared.fCameraCalibration1.NotEmpty () ||
1875 shared.fCameraCalibration2.NotEmpty ())
1876 {
1877
1878 SetCameraCalibrationSignature (shared.fCameraCalibrationSignature.Get ());
1879
1880 }
1881
1882 // Embedded camera profiles.
1883
1884 if (shared.fCameraProfile.fColorPlanes > 1)
1885 {
1886
1887 if (qDNGValidate || host.NeedsMeta () || host.NeedsImage ())
1888 {
1889
1890 // Add profile from main IFD.
1891
1892 {
1893
1894 AutoPtr<dng_camera_profile> profile (new dng_camera_profile ());
1895
1896 dng_camera_profile_info &profileInfo = shared.fCameraProfile;
1897
1898 profile->Parse (stream, profileInfo);
1899
1900 // The main embedded profile must be valid.
1901
1902 if (!profile->IsValid (shared.fCameraProfile.fColorPlanes))
1903 {
1904
1905 ThrowBadFormat ();
1906
1907 }
1908
1909 profile->SetWasReadFromDNG ();
1910
1911 AddProfile (profile);
1912
1913 }
1914
1915 // Extra profiles.
1916
1917 for (uint32 index = 0; index < (uint32) shared.fExtraCameraProfiles.size (); index++)
1918 {
1919
1920 try
1921 {
1922
1923 AutoPtr<dng_camera_profile> profile (new dng_camera_profile ());
1924
1925 dng_camera_profile_info &profileInfo = shared.fExtraCameraProfiles [index];
1926
1927 profile->Parse (stream, profileInfo);
1928
1929 if (!profile->IsValid (shared.fCameraProfile.fColorPlanes))
1930 {
1931
1932 ThrowBadFormat ();
1933
1934 }
1935
1936 profile->SetWasReadFromDNG ();
1937
1938 AddProfile (profile);
1939
1940 }
1941
1942 catch (dng_exception &except)
1943 {
1944
1945 // Don't ignore transient errors.
1946
1947 if (host.IsTransientError (except.ErrorCode ()))
1948 {
1949
1950 throw;
1951
1952 }
1953
1954 // Eat other parsing errors.
1955
1956 #if qDNGValidate
1957
1958 ReportWarning ("Unable to parse extra profile");
1959
1960 #endif
1961
1962 }
1963
1964 }
1965
1966 }
1967
1968 // As shot profile name.
1969
1970 if (shared.fAsShotProfileName.NotEmpty ())
1971 {
1972
1973 SetAsShotProfileName (shared.fAsShotProfileName.Get ());
1974
1975 }
1976
1977 }
1978
1979 // Raw image data digest.
1980
1981 if (shared.fRawImageDigest.IsValid ())
1982 {
1983
1984 SetRawImageDigest (shared.fRawImageDigest);
1985
1986 }
1987
1988 // Raw data unique ID.
1989
1990 if (shared.fRawDataUniqueID.IsValid ())
1991 {
1992
1993 SetRawDataUniqueID (shared.fRawDataUniqueID);
1994
1995 }
1996
1997 // Original raw file name.
1998
1999 if (shared.fOriginalRawFileName.NotEmpty ())
2000 {
2001
2002 SetOriginalRawFileName (shared.fOriginalRawFileName.Get ());
2003
2004 }
2005
2006 // Original raw file data.
2007
2008 if (shared.fOriginalRawFileDataCount)
2009 {
2010
2011 SetHasOriginalRawFileData (true);
2012
2013 if (host.KeepOriginalFile ())
2014 {
2015
2016 uint32 count = shared.fOriginalRawFileDataCount;
2017
2018 AutoPtr<dng_memory_block> block (host.Allocate (count));
2019
2020 stream.SetReadPosition (shared.fOriginalRawFileDataOffset);
2021
2022 stream.Get (block->Buffer (), count);
2023
2024 SetOriginalRawFileData (block);
2025
2026 SetOriginalRawFileDigest (shared.fOriginalRawFileDigest);
2027
2028 ValidateOriginalRawFileDigest ();
2029
2030 }
2031
2032 }
2033
2034 // DNG private data.
2035
2036 if (shared.fDNGPrivateDataCount && host.KeepDNGPrivate ())
2037 {
2038
2039 uint32 length = shared.fDNGPrivateDataCount;
2040
2041 AutoPtr<dng_memory_block> block (host.Allocate (length));
2042
2043 stream.SetReadPosition (shared.fDNGPrivateDataOffset);
2044
2045 stream.Get (block->Buffer (), length);
2046
2047 SetPrivateData (block);
2048
2049 }
2050
2051 // Hand off EXIF metadata to negative.
2052
2053 fExif.Reset (info.fExif.Release ());
2054
2055 // Parse linearization info.
2056
2057 NeedLinearizationInfo ();
2058
2059 fLinearizationInfo.Get ()->Parse (host,
2060 stream,
2061 info);
2062
2063 // Parse mosaic info.
2064
2065 if (rawIFD.fPhotometricInterpretation == piCFA)
2066 {
2067
2068 NeedMosaicInfo ();
2069
2070 fMosaicInfo.Get ()->Parse (host,
2071 stream,
2072 info);
2073
2074 }
2075
2076 }
2077
2078 /*****************************************************************************/
2079
PostParse(dng_host & host,dng_stream & stream,dng_info & info)2080 void dng_negative::PostParse (dng_host &host,
2081 dng_stream &stream,
2082 dng_info &info)
2083 {
2084
2085 // Shared info.
2086
2087 dng_shared &shared = *(info.fShared.Get ());
2088
2089 if (host.NeedsMeta ())
2090 {
2091
2092 // MakerNote.
2093
2094 if (shared.fMakerNoteCount)
2095 {
2096
2097 // See if we know if the MakerNote is safe or not.
2098
2099 SetMakerNoteSafety (shared.fMakerNoteSafety == 1);
2100
2101 // If the MakerNote is safe, preserve it as a MakerNote.
2102
2103 if (IsMakerNoteSafe ())
2104 {
2105
2106 AutoPtr<dng_memory_block> block (host.Allocate (shared.fMakerNoteCount));
2107
2108 stream.SetReadPosition (shared.fMakerNoteOffset);
2109
2110 stream.Get (block->Buffer (), shared.fMakerNoteCount);
2111
2112 SetMakerNote (block);
2113
2114 }
2115
2116 }
2117
2118 // IPTC metadata.
2119
2120 if (shared.fIPTC_NAA_Count)
2121 {
2122
2123 AutoPtr<dng_memory_block> block (host.Allocate (shared.fIPTC_NAA_Count));
2124
2125 stream.SetReadPosition (shared.fIPTC_NAA_Offset);
2126
2127 uint64 iptcOffset = stream.PositionInOriginalFile();
2128
2129 stream.Get (block->Buffer (),
2130 block->LogicalSize ());
2131
2132 SetIPTC (block, iptcOffset);
2133
2134 }
2135
2136 // XMP metadata.
2137
2138 if (shared.fXMPCount)
2139 {
2140
2141 AutoPtr<dng_memory_block> block (host.Allocate (shared.fXMPCount));
2142
2143 stream.SetReadPosition (shared.fXMPOffset);
2144
2145 stream.Get (block->Buffer (),
2146 block->LogicalSize ());
2147
2148 fValidEmbeddedXMP = SetXMP (host,
2149 block->Buffer (),
2150 block->LogicalSize ());
2151
2152 #if qDNGValidate
2153
2154 if (!fValidEmbeddedXMP)
2155 {
2156 ReportError ("The embedded XMP is invalid");
2157 }
2158
2159 #endif
2160
2161 }
2162
2163 // Color info.
2164
2165 if (!IsMonochrome ())
2166 {
2167
2168 // If the ColorimetricReference is the ICC profile PCS,
2169 // then the data must be already be white balanced to the
2170 // ICC profile PCS white point.
2171
2172 if (ColorimetricReference () == crICCProfilePCS)
2173 {
2174
2175 ClearCameraNeutral ();
2176
2177 SetCameraWhiteXY (PCStoXY ());
2178
2179 }
2180
2181 else
2182 {
2183
2184 // AsShotNeutral.
2185
2186 if (shared.fAsShotNeutral.Count () == ColorChannels ())
2187 {
2188
2189 SetCameraNeutral (shared.fAsShotNeutral);
2190
2191 }
2192
2193 // AsShotWhiteXY.
2194
2195 if (shared.fAsShotWhiteXY.IsValid () && !HasCameraNeutral ())
2196 {
2197
2198 SetCameraWhiteXY (shared.fAsShotWhiteXY);
2199
2200 }
2201
2202 }
2203
2204 }
2205
2206 }
2207
2208 }
2209
2210 /*****************************************************************************/
2211
SynchronizeMetadata()2212 void dng_negative::SynchronizeMetadata ()
2213 {
2214
2215 if (!fOriginalExif.Get ())
2216 {
2217
2218 fOriginalExif.Reset (fExif->Clone ());
2219
2220 }
2221
2222 fXMP->IngestIPTC (*this, fXMPisNewer);
2223
2224 fXMP->SyncExif (*fExif.Get ());
2225
2226 fXMP->SyncOrientation (*this, fXMPinSidecar);
2227
2228 }
2229
2230 /*****************************************************************************/
2231
UpdateDateTime(const dng_date_time_info & dt)2232 void dng_negative::UpdateDateTime (const dng_date_time_info &dt)
2233 {
2234
2235 fExif->UpdateDateTime (dt);
2236
2237 fXMP->UpdateDateTime (dt);
2238
2239 }
2240
2241 /*****************************************************************************/
2242
UpdateDateTimeToNow()2243 void dng_negative::UpdateDateTimeToNow ()
2244 {
2245
2246 dng_date_time_info dt;
2247
2248 CurrentDateTimeAndZone (dt);
2249
2250 UpdateDateTime (dt);
2251
2252 }
2253
2254 /*****************************************************************************/
2255
SetFourColorBayer()2256 bool dng_negative::SetFourColorBayer ()
2257 {
2258
2259 if (ColorChannels () != 3)
2260 {
2261 return false;
2262 }
2263
2264 if (!fMosaicInfo.Get ())
2265 {
2266 return false;
2267 }
2268
2269 if (!fMosaicInfo.Get ()->SetFourColorBayer ())
2270 {
2271 return false;
2272 }
2273
2274 SetColorChannels (4);
2275
2276 if (fCameraNeutral.Count () == 3)
2277 {
2278
2279 dng_vector n (4);
2280
2281 n [0] = fCameraNeutral [0];
2282 n [1] = fCameraNeutral [1];
2283 n [2] = fCameraNeutral [2];
2284 n [3] = fCameraNeutral [1];
2285
2286 fCameraNeutral = n;
2287
2288 }
2289
2290 fCameraCalibration1.Clear ();
2291 fCameraCalibration2.Clear ();
2292
2293 fCameraCalibrationSignature.Clear ();
2294
2295 for (uint32 index = 0; index < (uint32) fCameraProfile.size (); index++)
2296 {
2297
2298 fCameraProfile [index]->SetFourColorBayer ();
2299
2300 }
2301
2302 return true;
2303
2304 }
2305
2306 /*****************************************************************************/
2307
RawImage() const2308 const dng_image & dng_negative::RawImage () const
2309 {
2310
2311 if (fStage1Image.Get ())
2312 {
2313 return *fStage1Image.Get ();
2314 }
2315
2316 if (fStage2Image.Get ())
2317 {
2318 return *fStage2Image.Get ();
2319 }
2320
2321 DNG_ASSERT (fStage3Image.Get (),
2322 "dng_negative::RawImage with no raw image");
2323
2324 return *fStage3Image.Get ();
2325
2326 }
2327
2328 /*****************************************************************************/
2329
ReadStage1Image(dng_host & host,dng_stream & stream,dng_info & info)2330 void dng_negative::ReadStage1Image (dng_host &host,
2331 dng_stream &stream,
2332 dng_info &info)
2333 {
2334
2335 dng_ifd &rawIFD = *info.fIFD [info.fMainIndex].Get ();
2336
2337 fStage1Image.Reset (host.Make_dng_image (rawIFD.Bounds (),
2338 rawIFD.fSamplesPerPixel,
2339 rawIFD.PixelType ()));
2340
2341 rawIFD.ReadImage (host,
2342 stream,
2343 *fStage1Image.Get ());
2344
2345 }
2346
2347 /*****************************************************************************/
2348
SetStage1Image(AutoPtr<dng_image> & image)2349 void dng_negative::SetStage1Image (AutoPtr<dng_image> &image)
2350 {
2351
2352 fStage1Image.Reset (image.Release ());
2353
2354 }
2355
2356 /*****************************************************************************/
2357
DoBuildStage2(dng_host & host,uint32 pixelType)2358 void dng_negative::DoBuildStage2 (dng_host &host,
2359 uint32 pixelType)
2360 {
2361
2362 dng_image &stage1 = *fStage1Image.Get ();
2363
2364 dng_linearization_info &info = *fLinearizationInfo.Get ();
2365
2366 fStage2Image.Reset (host.Make_dng_image (info.fActiveArea.Size (),
2367 stage1.Planes (),
2368 pixelType));
2369
2370 info.Linearize (host,
2371 stage1,
2372 *fStage2Image.Get ());
2373
2374 }
2375
2376 /*****************************************************************************/
2377
BuildStage2Image(dng_host & host,uint32 pixelType)2378 void dng_negative::BuildStage2Image (dng_host &host,
2379 uint32 pixelType)
2380 {
2381
2382 // Finalize linearization info.
2383
2384 {
2385
2386 NeedLinearizationInfo ();
2387
2388 dng_linearization_info &info = *fLinearizationInfo.Get ();
2389
2390 info.PostParse (host, *this);
2391
2392 }
2393
2394 // Perform the linearization.
2395
2396 DoBuildStage2 (host,
2397 pixelType);
2398
2399 // Delete the stage1 image now if we are not keeping it around.
2400
2401 if (!host.KeepStage1 ())
2402 {
2403
2404 ClearStage1 ();
2405
2406 }
2407
2408 }
2409
2410 /*****************************************************************************/
2411
ClearStage1()2412 void dng_negative::ClearStage1 ()
2413 {
2414
2415 if (fStage1Image.Get ())
2416 {
2417
2418 fStage1Image.Reset ();
2419
2420 ClearRawImageDigest ();
2421
2422 }
2423
2424 // If we are not keeping the stage 1 image, then the linearization
2425 // information is now useless.
2426
2427 ClearLinearizationInfo ();
2428
2429 }
2430
2431 /*****************************************************************************/
2432
DoBuildStage3(dng_host & host,int32 srcPlane)2433 void dng_negative::DoBuildStage3 (dng_host &host,
2434 int32 srcPlane)
2435 {
2436
2437 dng_image &stage2 = *fStage2Image.Get ();
2438
2439 dng_mosaic_info &info = *fMosaicInfo.Get ();
2440
2441 dng_point downScale = info.DownScale (host.MinimumSize (),
2442 host.PreferredSize (),
2443 host.CropFactor ());
2444
2445 if (downScale != dng_point (1, 1))
2446 {
2447 SetIsPreview (true);
2448 }
2449
2450 dng_point dstSize = info.DstSize (downScale);
2451
2452 fStage3Image.Reset (host.Make_dng_image (dng_rect (dstSize),
2453 info.fColorPlanes,
2454 stage2.PixelType ()));
2455
2456 if (srcPlane < 0 || srcPlane >= (int32) stage2.Planes ())
2457 {
2458 srcPlane = 0;
2459 }
2460
2461 info.Interpolate (host,
2462 *this,
2463 stage2,
2464 *fStage3Image.Get (),
2465 downScale,
2466 srcPlane);
2467
2468 }
2469
2470 /*****************************************************************************/
2471
2472 // Interpolate and merge a multi-channel CFA image.
2473
DoMergeStage3(dng_host & host)2474 void dng_negative::DoMergeStage3 (dng_host &host)
2475 {
2476
2477 // The DNG SDK does not provide multi-channel CFA image merging code.
2478 // It just grabs the first channel and uses that.
2479
2480 DoBuildStage3 (host, 0);
2481
2482 // Just grabbing the first channel would often result in the very
2483 // bright image using the baseline exposure value.
2484
2485 fStage3Gain = pow (2.0, BaselineExposure ());
2486
2487 }
2488
2489 /*****************************************************************************/
2490
BuildStage3Image(dng_host & host,int32 srcPlane)2491 void dng_negative::BuildStage3Image (dng_host &host,
2492 int32 srcPlane)
2493 {
2494
2495 // Finalize the mosaic information.
2496
2497 dng_mosaic_info *info = fMosaicInfo.Get ();
2498
2499 if (info)
2500 {
2501
2502 info->PostParse (host, *this);
2503
2504 }
2505
2506 // If we don't have a mosaic pattern, then just move the stage 2
2507 // image on to stage 3.
2508
2509 if (!info || !info->IsColorFilterArray ())
2510 {
2511
2512 fStage3Image.Reset (fStage2Image.Release ());
2513
2514 }
2515
2516 else
2517 {
2518
2519 // Remember the size of the stage 2 image.
2520
2521 dng_point stage2_size = fStage2Image->Size ();
2522
2523 // Special case multi-channel CFA interpolation.
2524
2525 if ((fStage2Image->Planes () > 1) && (srcPlane < 0))
2526 {
2527
2528 DoMergeStage3 (host);
2529
2530 }
2531
2532 // Else do a single channel interpolation.
2533
2534 else
2535 {
2536
2537 DoBuildStage3 (host, srcPlane);
2538
2539 }
2540
2541 // Calculate the ratio of the stage 3 image size to stage 2 image size.
2542
2543 dng_point stage3_size = fStage3Image->Size ();
2544
2545 fRawToFullScaleH = (real64) stage3_size.h / (real64) stage2_size.h;
2546 fRawToFullScaleV = (real64) stage3_size.v / (real64) stage2_size.v;
2547
2548 }
2549
2550 // Delete the stage2 image if we are done with it.
2551
2552 if (!host.KeepStage2 ())
2553 {
2554
2555 ClearStage2 ();
2556
2557 }
2558
2559 }
2560
2561 /*****************************************************************************/
2562
ClearStage2()2563 void dng_negative::ClearStage2 ()
2564 {
2565
2566 if (fStage2Image.Get ())
2567 {
2568
2569 fStage2Image.Reset ();
2570
2571 ClearRawImageDigest ();
2572
2573 }
2574
2575 // If we did not keep the stage 1 image, and we are not keeping
2576 // the stage 2 image either, then the mosaic information is now
2577 // useless.
2578
2579 if (!fStage1Image.Get ())
2580 {
2581
2582 ClearMosaicInfo ();
2583
2584 // To support saving linear DNG files, to need to account for
2585 // and upscaling during interpolation.
2586
2587 if (fRawToFullScaleH > 1.0)
2588 {
2589
2590 uint32 adjust = Round_uint32 (fRawToFullScaleH);
2591
2592 fDefaultCropSizeH .n *= adjust;
2593 fDefaultCropOriginH.n *= adjust;
2594 fDefaultScaleH .d *= adjust;
2595
2596 fRawToFullScaleH /= (real64) adjust;
2597
2598 }
2599
2600 if (fRawToFullScaleV > 1.0)
2601 {
2602
2603 uint32 adjust = Round_uint32 (fRawToFullScaleV);
2604
2605 fDefaultCropSizeV .n *= adjust;
2606 fDefaultCropOriginV.n *= adjust;
2607 fDefaultScaleV .d *= adjust;
2608
2609 fRawToFullScaleV /= (real64) adjust;
2610
2611 }
2612
2613 }
2614
2615 }
2616
2617 /*****************************************************************************/
2618
ClearStage3()2619 void dng_negative::ClearStage3 ()
2620 {
2621
2622 fStage3Image.Reset ();
2623
2624 }
2625
2626 /*****************************************************************************/
2627
MakeExif()2628 dng_exif * dng_negative::MakeExif ()
2629 {
2630
2631 dng_exif *exif = new dng_exif ();
2632
2633 if (!exif)
2634 {
2635 ThrowMemoryFull ();
2636 }
2637
2638 return exif;
2639
2640 }
2641
2642 /*****************************************************************************/
2643
MakeXMP()2644 dng_xmp * dng_negative::MakeXMP ()
2645 {
2646
2647 dng_xmp *xmp = new dng_xmp (Allocator ());
2648
2649 if (!xmp)
2650 {
2651 ThrowMemoryFull ();
2652 }
2653
2654 return xmp;
2655
2656 }
2657
2658 /*****************************************************************************/
2659
MakeLinearizationInfo()2660 dng_linearization_info * dng_negative::MakeLinearizationInfo ()
2661 {
2662
2663 dng_linearization_info *info = new dng_linearization_info ();
2664
2665 if (!info)
2666 {
2667 ThrowMemoryFull ();
2668 }
2669
2670 return info;
2671
2672 }
2673
2674 /*****************************************************************************/
2675
NeedLinearizationInfo()2676 void dng_negative::NeedLinearizationInfo ()
2677 {
2678
2679 if (!fLinearizationInfo.Get ())
2680 {
2681
2682 fLinearizationInfo.Reset (MakeLinearizationInfo ());
2683
2684 }
2685
2686 }
2687
2688 /*****************************************************************************/
2689
MakeMosaicInfo()2690 dng_mosaic_info * dng_negative::MakeMosaicInfo ()
2691 {
2692
2693 dng_mosaic_info *info = new dng_mosaic_info ();
2694
2695 if (!info)
2696 {
2697 ThrowMemoryFull ();
2698 }
2699
2700 return info;
2701
2702 }
2703
2704 /*****************************************************************************/
2705
NeedMosaicInfo()2706 void dng_negative::NeedMosaicInfo ()
2707 {
2708
2709 if (!fMosaicInfo.Get ())
2710 {
2711
2712 fMosaicInfo.Reset (MakeMosaicInfo ());
2713
2714 }
2715
2716 }
2717
2718 /*****************************************************************************/
2719