1 /*****************************************************************************/
2 // Copyright 2006-2019 Adobe Systems Incorporated
3 // All Rights Reserved.
4 //
5 // NOTICE: Adobe permits you to use, modify, and distribute this file in
6 // accordance with the terms of the Adobe license agreement accompanying it.
7 /*****************************************************************************/
8
9 #include "dng_camera_profile.h"
10
11 #include "dng_1d_table.h"
12 #include "dng_assertions.h"
13 #include "dng_color_space.h"
14 #include "dng_host.h"
15 #include "dng_exceptions.h"
16 #include "dng_image_writer.h"
17 #include "dng_info.h"
18 #include "dng_parse_utils.h"
19 #include "dng_tag_codes.h"
20 #include "dng_tag_types.h"
21 #include "dng_temperature.h"
22 #include "dng_xy_coord.h"
23
24 /*****************************************************************************/
25
26 const char * kProfileName_Embedded = "Embedded";
27
28 const char * kAdobeCalibrationSignature = "com.adobe";
29
30 /*****************************************************************************/
31
dng_camera_profile()32 dng_camera_profile::dng_camera_profile ()
33
34 : fName ()
35 , fCalibrationIlluminant1 (lsUnknown)
36 , fCalibrationIlluminant2 (lsUnknown)
37 , fColorMatrix1 ()
38 , fColorMatrix2 ()
39 , fForwardMatrix1 ()
40 , fForwardMatrix2 ()
41 , fReductionMatrix1 ()
42 , fReductionMatrix2 ()
43 , fFingerprint ()
44 , fCopyright ()
45 , fEmbedPolicy (pepAllowCopying)
46 , fHueSatDeltas1 ()
47 , fHueSatDeltas2 ()
48 , fHueSatMapEncoding (encoding_Linear)
49 , fLookTable ()
50 , fLookTableEncoding (encoding_Linear)
51 , fBaselineExposureOffset (0, 100)
52 , fDefaultBlackRender (defaultBlackRender_Auto)
53 , fToneCurve ()
54 , fProfileCalibrationSignature ()
55 , fUniqueCameraModelRestriction ()
56 , fWasReadFromDNG (false)
57 , fWasReadFromDisk (false)
58 , fWasBuiltinMatrix (false)
59 , fWasStubbed (false)
60
61 {
62
63 fToneCurve.SetInvalid ();
64
65 }
66
67 /*****************************************************************************/
68
~dng_camera_profile()69 dng_camera_profile::~dng_camera_profile ()
70 {
71
72 }
73
74 /*****************************************************************************/
75
IlluminantToTemperature(uint32 light)76 real64 dng_camera_profile::IlluminantToTemperature (uint32 light)
77 {
78
79 switch (light)
80 {
81
82 case lsStandardLightA:
83 case lsTungsten:
84 {
85 return 2850.0;
86 }
87
88 case lsISOStudioTungsten:
89 {
90 return 3200.0;
91 }
92
93 case lsD50:
94 {
95 return 5000.0;
96 }
97
98 case lsD55:
99 case lsDaylight:
100 case lsFineWeather:
101 case lsFlash:
102 case lsStandardLightB:
103 {
104 return 5500.0;
105 }
106
107 case lsD65:
108 case lsStandardLightC:
109 case lsCloudyWeather:
110 {
111 return 6500.0;
112 }
113
114 case lsD75:
115 case lsShade:
116 {
117 return 7500.0;
118 }
119
120 case lsDaylightFluorescent:
121 {
122 return (5700.0 + 7100.0) * 0.5;
123 }
124
125 case lsDayWhiteFluorescent:
126 {
127 return (4600.0 + 5500.0) * 0.5;
128 }
129
130 case lsCoolWhiteFluorescent:
131 case lsFluorescent:
132 {
133 return (3800.0 + 4500.0) * 0.5;
134 }
135
136 case lsWhiteFluorescent:
137 {
138 return (3250.0 + 3800.0) * 0.5;
139 }
140
141 case lsWarmWhiteFluorescent:
142 {
143 return (2600.0 + 3250.0) * 0.5;
144 }
145
146 default:
147 {
148 return 0.0;
149 }
150
151 }
152
153 }
154
155 /******************************************************************************/
156
NormalizeColorMatrix(dng_matrix & m)157 void dng_camera_profile::NormalizeColorMatrix (dng_matrix &m)
158 {
159
160 if (m.NotEmpty ())
161 {
162
163 // Find scale factor to normalize the matrix.
164
165 dng_vector coord = m * PCStoXYZ ();
166
167 real64 maxCoord = coord.MaxEntry ();
168
169 if (maxCoord > 0.0 && (maxCoord < 0.99 || maxCoord > 1.01))
170 {
171
172 m.Scale (1.0 / maxCoord);
173
174 }
175
176 // Round to four decimal places.
177
178 m.Round (10000);
179
180 }
181
182 }
183
184 /******************************************************************************/
185
SetColorMatrix1(const dng_matrix & m)186 void dng_camera_profile::SetColorMatrix1 (const dng_matrix &m)
187 {
188
189 fColorMatrix1 = m;
190
191 NormalizeColorMatrix (fColorMatrix1);
192
193 ClearFingerprint ();
194
195 }
196
197 /******************************************************************************/
198
SetColorMatrix2(const dng_matrix & m)199 void dng_camera_profile::SetColorMatrix2 (const dng_matrix &m)
200 {
201
202 fColorMatrix2 = m;
203
204 NormalizeColorMatrix (fColorMatrix2);
205
206 ClearFingerprint ();
207
208 }
209
210 /******************************************************************************/
211
212 // Make sure the forward matrix maps to exactly the PCS.
213
NormalizeForwardMatrix(dng_matrix & m)214 void dng_camera_profile::NormalizeForwardMatrix (dng_matrix &m)
215 {
216
217 if (m.NotEmpty ())
218 {
219
220 dng_vector cameraOne;
221
222 cameraOne.SetIdentity (m.Cols ());
223
224 dng_vector xyz = m * cameraOne;
225
226 m = PCStoXYZ ().AsDiagonal () *
227 Invert (xyz.AsDiagonal ()) *
228 m;
229
230 }
231
232 }
233
234 /******************************************************************************/
235
SetForwardMatrix1(const dng_matrix & m)236 void dng_camera_profile::SetForwardMatrix1 (const dng_matrix &m)
237 {
238
239 fForwardMatrix1 = m;
240
241 fForwardMatrix1.Round (10000);
242
243 ClearFingerprint ();
244
245 }
246
247 /******************************************************************************/
248
SetForwardMatrix2(const dng_matrix & m)249 void dng_camera_profile::SetForwardMatrix2 (const dng_matrix &m)
250 {
251
252 fForwardMatrix2 = m;
253
254 fForwardMatrix2.Round (10000);
255
256 ClearFingerprint ();
257
258 }
259
260 /*****************************************************************************/
261
SetReductionMatrix1(const dng_matrix & m)262 void dng_camera_profile::SetReductionMatrix1 (const dng_matrix &m)
263 {
264
265 fReductionMatrix1 = m;
266
267 fReductionMatrix1.Round (10000);
268
269 ClearFingerprint ();
270
271 }
272
273 /******************************************************************************/
274
SetReductionMatrix2(const dng_matrix & m)275 void dng_camera_profile::SetReductionMatrix2 (const dng_matrix &m)
276 {
277
278 fReductionMatrix2 = m;
279
280 fReductionMatrix2.Round (10000);
281
282 ClearFingerprint ();
283
284 }
285
286 /*****************************************************************************/
287
HasColorMatrix1() const288 bool dng_camera_profile::HasColorMatrix1 () const
289 {
290
291 return fColorMatrix1.Cols () == 3 &&
292 fColorMatrix1.Rows () > 1;
293
294 }
295
296 /*****************************************************************************/
297
HasColorMatrix2() const298 bool dng_camera_profile::HasColorMatrix2 () const
299 {
300
301 return fColorMatrix2.Cols () == 3 &&
302 fColorMatrix2.Rows () == fColorMatrix1.Rows ();
303
304 }
305
306 /*****************************************************************************/
307
SetHueSatDeltas1(const dng_hue_sat_map & deltas1)308 void dng_camera_profile::SetHueSatDeltas1 (const dng_hue_sat_map &deltas1)
309 {
310
311 fHueSatDeltas1 = deltas1;
312
313 ClearFingerprint ();
314
315 }
316
317 /*****************************************************************************/
318
SetHueSatDeltas2(const dng_hue_sat_map & deltas2)319 void dng_camera_profile::SetHueSatDeltas2 (const dng_hue_sat_map &deltas2)
320 {
321
322 fHueSatDeltas2 = deltas2;
323
324 ClearFingerprint ();
325
326 }
327
328 /*****************************************************************************/
329
SetLookTable(const dng_hue_sat_map & table)330 void dng_camera_profile::SetLookTable (const dng_hue_sat_map &table)
331 {
332
333 fLookTable = table;
334
335 ClearFingerprint ();
336
337 }
338
339 /*****************************************************************************/
340
FingerprintMatrix(dng_md5_printer_stream & printer,const dng_matrix & matrix)341 static void FingerprintMatrix (dng_md5_printer_stream &printer,
342 const dng_matrix &matrix)
343 {
344
345 tag_matrix tag (0, matrix);
346
347 // Tag's Put routine doesn't write the header, only the data
348
349 tag.Put (printer);
350
351 }
352
353 /*****************************************************************************/
354
FingerprintHueSatMap(dng_md5_printer_stream & printer,const dng_hue_sat_map & map)355 static void FingerprintHueSatMap (dng_md5_printer_stream &printer,
356 const dng_hue_sat_map &map)
357 {
358
359 if (map.IsNull ())
360 return;
361
362 uint32 hues;
363 uint32 sats;
364 uint32 vals;
365
366 map.GetDivisions (hues, sats, vals);
367
368 printer.Put_uint32 (hues);
369 printer.Put_uint32 (sats);
370 printer.Put_uint32 (vals);
371
372 for (uint32 val = 0; val < vals; val++)
373 for (uint32 hue = 0; hue < hues; hue++)
374 for (uint32 sat = 0; sat < sats; sat++)
375 {
376
377 dng_hue_sat_map::HSBModify modify;
378
379 map.GetDelta (hue, sat, val, modify);
380
381 printer.Put_real32 (modify.fHueShift);
382 printer.Put_real32 (modify.fSatScale);
383 printer.Put_real32 (modify.fValScale);
384
385 }
386
387 }
388
389 /*****************************************************************************/
390
CalculateFingerprint() const391 void dng_camera_profile::CalculateFingerprint () const
392 {
393
394 DNG_ASSERT (!fWasStubbed, "CalculateFingerprint on stubbed profile");
395
396 dng_md5_printer_stream printer;
397
398 // MD5 hash is always calculated on little endian data.
399
400 printer.SetLittleEndian ();
401
402 // The data that we fingerprint closely matches that saved
403 // by the profile_tag_set class in dng_image_writer.cpp, with
404 // the exception of the fingerprint itself.
405
406 if (HasColorMatrix1 ())
407 {
408
409 uint32 colorChannels = ColorMatrix1 ().Rows ();
410
411 printer.Put_uint16 ((uint16) fCalibrationIlluminant1);
412
413 FingerprintMatrix (printer, fColorMatrix1);
414
415 if (fForwardMatrix1.Rows () == fColorMatrix1.Cols () &&
416 fForwardMatrix1.Cols () == fColorMatrix1.Rows ())
417 {
418
419 FingerprintMatrix (printer, fForwardMatrix1);
420
421 }
422
423 if (colorChannels > 3 && fReductionMatrix1.Rows () *
424 fReductionMatrix1.Cols () == colorChannels * 3)
425 {
426
427 FingerprintMatrix (printer, fReductionMatrix1);
428
429 }
430
431 if (HasColorMatrix2 ())
432 {
433
434 printer.Put_uint16 ((uint16) fCalibrationIlluminant2);
435
436 FingerprintMatrix (printer, fColorMatrix2);
437
438 if (fForwardMatrix2.Rows () == fColorMatrix2.Cols () &&
439 fForwardMatrix2.Cols () == fColorMatrix2.Rows ())
440 {
441
442 FingerprintMatrix (printer, fForwardMatrix2);
443
444 }
445
446 if (colorChannels > 3 && fReductionMatrix2.Rows () *
447 fReductionMatrix2.Cols () == colorChannels * 3)
448 {
449
450 FingerprintMatrix (printer, fReductionMatrix2);
451
452 }
453
454 }
455
456 printer.Put (fName.Get (),
457 fName.Length ());
458
459 printer.Put (fProfileCalibrationSignature.Get (),
460 fProfileCalibrationSignature.Length ());
461
462 printer.Put_uint32 (fEmbedPolicy);
463
464 printer.Put (fCopyright.Get (),
465 fCopyright.Length ());
466
467 bool haveHueSat1 = HueSatDeltas1 ().IsValid ();
468
469 bool haveHueSat2 = HueSatDeltas2 ().IsValid () &&
470 HasColorMatrix2 ();
471
472 if (haveHueSat1)
473 {
474
475 FingerprintHueSatMap (printer, fHueSatDeltas1);
476
477 }
478
479 if (haveHueSat2)
480 {
481
482 FingerprintHueSatMap (printer, fHueSatDeltas2);
483
484 }
485
486 if (haveHueSat1 || haveHueSat2)
487 {
488
489 if (fHueSatMapEncoding != 0)
490 {
491
492 printer.Put_uint32 (fHueSatMapEncoding);
493
494 }
495
496 }
497
498 if (fLookTable.IsValid ())
499 {
500
501 FingerprintHueSatMap (printer, fLookTable);
502
503 if (fLookTableEncoding != 0)
504 {
505
506 printer.Put_uint32 (fLookTableEncoding);
507
508 }
509
510 }
511
512 if (fBaselineExposureOffset.IsValid ())
513 {
514
515 if (fBaselineExposureOffset.As_real64 () != 0.0)
516 {
517
518 printer.Put_real64 (fBaselineExposureOffset.As_real64 ());
519
520 }
521
522 }
523
524 if (fDefaultBlackRender != 0)
525 {
526
527 printer.Put_int32 (fDefaultBlackRender);
528
529 }
530
531 if (fToneCurve.IsValid ())
532 {
533
534 for (uint32 i = 0; i < fToneCurve.fCoord.size (); i++)
535 {
536
537 printer.Put_real32 ((real32) fToneCurve.fCoord [i].h);
538 printer.Put_real32 ((real32) fToneCurve.fCoord [i].v);
539
540 }
541
542 }
543
544 }
545
546 fFingerprint = printer.Result ();
547
548 }
549
550 /******************************************************************************/
551
UniqueID() const552 dng_fingerprint dng_camera_profile::UniqueID () const
553 {
554
555 dng_md5_printer_stream printer;
556
557 // MD5 hash is always calculated on little endian data.
558
559 printer.SetLittleEndian ();
560
561 // Start with the existing fingerprint.
562
563 if (!fFingerprint.IsValid ())
564 CalculateFingerprint ();
565
566 printer.Put (fFingerprint.data,
567 (uint32) sizeof (fFingerprint.data));
568
569 // Also include the UniqueCameraModelRestriction tag.
570
571 printer.Put (fUniqueCameraModelRestriction.Get (),
572 fUniqueCameraModelRestriction.Length ());
573
574 // Add any other needed fields here.
575
576 // ...
577
578 return printer.Result ();
579
580 }
581
582 /******************************************************************************/
583
ValidForwardMatrix(const dng_matrix & m)584 bool dng_camera_profile::ValidForwardMatrix (const dng_matrix &m)
585 {
586
587 const real64 kThreshold = 0.01;
588
589 if (m.NotEmpty ())
590 {
591
592 dng_vector cameraOne;
593
594 cameraOne.SetIdentity (m.Cols ());
595
596 dng_vector xyz = m * cameraOne;
597
598 dng_vector pcs = PCStoXYZ ();
599
600 if (Abs_real64 (xyz [0] - pcs [0]) > kThreshold ||
601 Abs_real64 (xyz [1] - pcs [1]) > kThreshold ||
602 Abs_real64 (xyz [2] - pcs [2]) > kThreshold)
603 {
604
605 return false;
606
607 }
608
609 }
610
611 return true;
612
613 }
614
615 /******************************************************************************/
616
IsValid(uint32 channels) const617 bool dng_camera_profile::IsValid (uint32 channels) const
618 {
619
620 // For Monochrome images, we ignore the camera profile.
621
622 if (channels == 1)
623 {
624
625 return true;
626
627 }
628
629 // ColorMatrix1 is required for all color images.
630
631 if (fColorMatrix1.Cols () != 3 ||
632 fColorMatrix1.Rows () != channels)
633 {
634
635 #if qDNGValidate
636
637 ReportError ("ColorMatrix1 is wrong size");
638
639 #endif
640
641 return false;
642
643 }
644
645 // ColorMatrix2 is optional, but it must be valid if present.
646
647 if (fColorMatrix2.Cols () != 0 ||
648 fColorMatrix2.Rows () != 0)
649 {
650
651 if (fColorMatrix2.Cols () != 3 ||
652 fColorMatrix2.Rows () != channels)
653 {
654
655 #if qDNGValidate
656
657 ReportError ("ColorMatrix2 is wrong size");
658
659 #endif
660
661 return false;
662
663 }
664
665 }
666
667 // ForwardMatrix1 is optional, but it must be valid if present.
668
669 if (fForwardMatrix1.Cols () != 0 ||
670 fForwardMatrix1.Rows () != 0)
671 {
672
673 if (fForwardMatrix1.Rows () != 3 ||
674 fForwardMatrix1.Cols () != channels)
675 {
676
677 #if qDNGValidate
678
679 ReportError ("ForwardMatrix1 is wrong size");
680
681 #endif
682
683 return false;
684
685 }
686
687 // Make sure ForwardMatrix1 does a valid mapping.
688
689 if (!ValidForwardMatrix (fForwardMatrix1))
690 {
691
692 #if qDNGValidate
693
694 ReportError ("ForwardMatrix1 does not map equal camera values to XYZ D50");
695
696 #endif
697
698 return false;
699
700 }
701
702 }
703
704 // ForwardMatrix2 is optional, but it must be valid if present.
705
706 if (fForwardMatrix2.Cols () != 0 ||
707 fForwardMatrix2.Rows () != 0)
708 {
709
710 if (fForwardMatrix2.Rows () != 3 ||
711 fForwardMatrix2.Cols () != channels)
712 {
713
714 #if qDNGValidate
715
716 ReportError ("ForwardMatrix2 is wrong size");
717
718 #endif
719
720 return false;
721
722 }
723
724 // Make sure ForwardMatrix2 does a valid mapping.
725
726 if (!ValidForwardMatrix (fForwardMatrix2))
727 {
728
729 #if qDNGValidate
730
731 ReportError ("ForwardMatrix2 does not map equal camera values to XYZ D50");
732
733 #endif
734
735 return false;
736
737 }
738
739 }
740
741 // ReductionMatrix1 is optional, but it must be valid if present.
742
743 if (fReductionMatrix1.Cols () != 0 ||
744 fReductionMatrix1.Rows () != 0)
745 {
746
747 if (fReductionMatrix1.Cols () != channels ||
748 fReductionMatrix1.Rows () != 3)
749 {
750
751 #if qDNGValidate
752
753 ReportError ("ReductionMatrix1 is wrong size");
754
755 #endif
756
757 return false;
758
759 }
760
761 }
762
763 // ReductionMatrix2 is optional, but it must be valid if present.
764
765 if (fReductionMatrix2.Cols () != 0 ||
766 fReductionMatrix2.Rows () != 0)
767 {
768
769 if (fReductionMatrix2.Cols () != channels ||
770 fReductionMatrix2.Rows () != 3)
771 {
772
773 #if qDNGValidate
774
775 ReportError ("ReductionMatrix2 is wrong size");
776
777 #endif
778
779 return false;
780
781 }
782
783 }
784
785 // Make sure ColorMatrix1 is invertable.
786
787 try
788 {
789
790 if (fReductionMatrix1.NotEmpty ())
791 {
792
793 (void) Invert (fColorMatrix1,
794 fReductionMatrix1);
795
796 }
797
798 else
799 {
800
801 (void) Invert (fColorMatrix1);
802
803 }
804
805 }
806
807 catch (...)
808 {
809
810 #if qDNGValidate
811
812 ReportError ("ColorMatrix1 is not invertable");
813
814 #endif
815
816 return false;
817
818 }
819
820 // Make sure ColorMatrix2 is invertable.
821
822 if (fColorMatrix2.NotEmpty ())
823 {
824
825 try
826 {
827
828 if (fReductionMatrix2.NotEmpty ())
829 {
830
831 (void) Invert (fColorMatrix2,
832 fReductionMatrix2);
833
834 }
835
836 else
837 {
838
839 (void) Invert (fColorMatrix2);
840
841 }
842
843 }
844
845 catch (...)
846 {
847
848 #if qDNGValidate
849
850 ReportError ("ColorMatrix2 is not invertable");
851
852 #endif
853
854 return false;
855
856 }
857
858 }
859
860 return true;
861
862 }
863
864 /*****************************************************************************/
865
EqualData(const dng_camera_profile & profile) const866 bool dng_camera_profile::EqualData (const dng_camera_profile &profile) const
867 {
868
869 return fCalibrationIlluminant1 == profile.fCalibrationIlluminant1 &&
870 fCalibrationIlluminant2 == profile.fCalibrationIlluminant2 &&
871 fColorMatrix1 == profile.fColorMatrix1 &&
872 fColorMatrix2 == profile.fColorMatrix2 &&
873 fForwardMatrix1 == profile.fForwardMatrix1 &&
874 fForwardMatrix2 == profile.fForwardMatrix2 &&
875 fReductionMatrix1 == profile.fReductionMatrix1 &&
876 fReductionMatrix2 == profile.fReductionMatrix2 &&
877 fHueSatDeltas1 == profile.fHueSatDeltas1 &&
878 fHueSatDeltas2 == profile.fHueSatDeltas2 &&
879 fHueSatMapEncoding == profile.fHueSatMapEncoding &&
880 fLookTable == profile.fLookTable &&
881 fLookTableEncoding == profile.fLookTableEncoding &&
882 fDefaultBlackRender == profile.fDefaultBlackRender &&
883 fToneCurve == profile.fToneCurve &&
884 fBaselineExposureOffset.As_real64 () == profile.fBaselineExposureOffset.As_real64 () &&
885 fProfileCalibrationSignature == profile.fProfileCalibrationSignature;
886
887 }
888
889 /*****************************************************************************/
890
ReadHueSatMap(dng_stream & stream,dng_hue_sat_map & hueSatMap,uint32 hues,uint32 sats,uint32 vals,bool skipSat0)891 void dng_camera_profile::ReadHueSatMap (dng_stream &stream,
892 dng_hue_sat_map &hueSatMap,
893 uint32 hues,
894 uint32 sats,
895 uint32 vals,
896 bool skipSat0)
897 {
898
899 hueSatMap.SetDivisions (hues, sats, vals);
900
901 for (uint32 val = 0; val < vals; val++)
902 {
903
904 for (uint32 hue = 0; hue < hues; hue++)
905 {
906
907 for (uint32 sat = skipSat0 ? 1 : 0; sat < sats; sat++)
908 {
909
910 dng_hue_sat_map::HSBModify modify;
911
912 modify.fHueShift = stream.Get_real32 ();
913 modify.fSatScale = stream.Get_real32 ();
914 modify.fValScale = stream.Get_real32 ();
915
916 hueSatMap.SetDelta (hue, sat, val, modify);
917
918 }
919
920 }
921
922 }
923
924 hueSatMap.AssignNewUniqueRuntimeFingerprint ();
925
926 }
927
928 /*****************************************************************************/
929
930 DNG_ATTRIB_NO_SANITIZE("unsigned-integer-overflow")
Parse(dng_stream & stream,dng_camera_profile_info & profileInfo)931 void dng_camera_profile::Parse (dng_stream &stream,
932 dng_camera_profile_info &profileInfo)
933 {
934
935 SetUniqueCameraModelRestriction (profileInfo.fUniqueCameraModel.Get ());
936
937 if (profileInfo.fProfileName.NotEmpty ())
938 {
939
940 SetName (profileInfo.fProfileName.Get ());
941
942 }
943
944 SetCopyright (profileInfo.fProfileCopyright.Get ());
945
946 SetEmbedPolicy (profileInfo.fEmbedPolicy);
947
948 SetCalibrationIlluminant1 (profileInfo.fCalibrationIlluminant1);
949
950 SetColorMatrix1 (profileInfo.fColorMatrix1);
951
952 if (profileInfo.fForwardMatrix1.NotEmpty ())
953 {
954
955 SetForwardMatrix1 (profileInfo.fForwardMatrix1);
956
957 }
958
959 if (profileInfo.fReductionMatrix1.NotEmpty ())
960 {
961
962 SetReductionMatrix1 (profileInfo.fReductionMatrix1);
963
964 }
965
966 if (profileInfo.fColorMatrix2.NotEmpty ())
967 {
968
969 SetCalibrationIlluminant2 (profileInfo.fCalibrationIlluminant2);
970
971 SetColorMatrix2 (profileInfo.fColorMatrix2);
972
973 if (profileInfo.fForwardMatrix2.NotEmpty ())
974 {
975
976 SetForwardMatrix2 (profileInfo.fForwardMatrix2);
977
978 }
979
980 if (profileInfo.fReductionMatrix2.NotEmpty ())
981 {
982
983 SetReductionMatrix2 (profileInfo.fReductionMatrix2);
984
985 }
986
987 }
988
989 SetProfileCalibrationSignature (profileInfo.fProfileCalibrationSignature.Get ());
990
991 if (profileInfo.fHueSatDeltas1Offset != 0 &&
992 profileInfo.fHueSatDeltas1Count != 0)
993 {
994
995 TempBigEndian setEndianness (stream, profileInfo.fBigEndian);
996
997 stream.SetReadPosition (profileInfo.fHueSatDeltas1Offset);
998
999 bool skipSat0 = (profileInfo.fHueSatDeltas1Count == profileInfo.fProfileHues *
1000 (profileInfo.fProfileSats - 1) *
1001 profileInfo.fProfileVals * 3);
1002
1003 ReadHueSatMap (stream,
1004 fHueSatDeltas1,
1005 profileInfo.fProfileHues,
1006 profileInfo.fProfileSats,
1007 profileInfo.fProfileVals,
1008 skipSat0);
1009
1010 }
1011
1012 if (profileInfo.fHueSatDeltas2Offset != 0 &&
1013 profileInfo.fHueSatDeltas2Count != 0)
1014 {
1015
1016 TempBigEndian setEndianness (stream, profileInfo.fBigEndian);
1017
1018 stream.SetReadPosition (profileInfo.fHueSatDeltas2Offset);
1019
1020 bool skipSat0 = (profileInfo.fHueSatDeltas2Count == profileInfo.fProfileHues *
1021 (profileInfo.fProfileSats - 1) *
1022 profileInfo.fProfileVals * 3);
1023
1024 ReadHueSatMap (stream,
1025 fHueSatDeltas2,
1026 profileInfo.fProfileHues,
1027 profileInfo.fProfileSats,
1028 profileInfo.fProfileVals,
1029 skipSat0);
1030
1031 }
1032
1033 if (profileInfo.fLookTableOffset != 0 &&
1034 profileInfo.fLookTableCount != 0)
1035 {
1036
1037 TempBigEndian setEndianness (stream, profileInfo.fBigEndian);
1038
1039 stream.SetReadPosition (profileInfo.fLookTableOffset);
1040
1041 bool skipSat0 = (profileInfo.fLookTableCount == profileInfo.fLookTableHues *
1042 (profileInfo.fLookTableSats - 1) *
1043 profileInfo.fLookTableVals * 3);
1044
1045 ReadHueSatMap (stream,
1046 fLookTable,
1047 profileInfo.fLookTableHues,
1048 profileInfo.fLookTableSats,
1049 profileInfo.fLookTableVals,
1050 skipSat0);
1051
1052 }
1053
1054 if ((profileInfo.fToneCurveCount & 1) == 0)
1055 {
1056
1057 TempBigEndian setEndianness (stream, profileInfo.fBigEndian);
1058
1059 stream.SetReadPosition (profileInfo.fToneCurveOffset);
1060
1061 uint32 points = profileInfo.fToneCurveCount / 2;
1062
1063 if (points > kMaxToneCurvePoints)
1064 {
1065 ThrowProgramError ("Too many tone curve points");
1066 }
1067
1068 fToneCurve.fCoord.resize (points);
1069
1070 for (size_t i = 0; i < points; i++)
1071 {
1072
1073 dng_point_real64 point;
1074
1075 point.h = stream.Get_real32 ();
1076 point.v = stream.Get_real32 ();
1077
1078 fToneCurve.fCoord [i] = point;
1079
1080 }
1081
1082 }
1083
1084 SetHueSatMapEncoding (profileInfo.fHueSatMapEncoding);
1085
1086 SetLookTableEncoding (profileInfo.fLookTableEncoding);
1087
1088 SetBaselineExposureOffset (profileInfo.fBaselineExposureOffset.As_real64 ());
1089
1090 SetDefaultBlackRender (profileInfo.fDefaultBlackRender);
1091
1092 }
1093
1094 /*****************************************************************************/
1095
ParseExtended(dng_stream & stream)1096 bool dng_camera_profile::ParseExtended (dng_stream &stream)
1097 {
1098
1099 try
1100 {
1101
1102 dng_camera_profile_info profileInfo;
1103
1104 if (!profileInfo.ParseExtended (stream))
1105 {
1106 return false;
1107 }
1108
1109 Parse (stream, profileInfo);
1110
1111 return true;
1112
1113 }
1114
1115 catch (...)
1116 {
1117
1118 // Eat parsing errors.
1119
1120 }
1121
1122 return false;
1123
1124 }
1125
1126 /*****************************************************************************/
1127
SetFourColorBayer()1128 void dng_camera_profile::SetFourColorBayer ()
1129 {
1130
1131 uint32 j;
1132
1133 if (!IsValid (3))
1134 {
1135 ThrowProgramError ();
1136 }
1137
1138 if (fColorMatrix1.NotEmpty ())
1139 {
1140
1141 dng_matrix m (4, 3);
1142
1143 for (j = 0; j < 3; j++)
1144 {
1145 m [0] [j] = fColorMatrix1 [0] [j];
1146 m [1] [j] = fColorMatrix1 [1] [j];
1147 m [2] [j] = fColorMatrix1 [2] [j];
1148 m [3] [j] = fColorMatrix1 [1] [j];
1149 }
1150
1151 fColorMatrix1 = m;
1152
1153 }
1154
1155 if (fColorMatrix2.NotEmpty ())
1156 {
1157
1158 dng_matrix m (4, 3);
1159
1160 for (j = 0; j < 3; j++)
1161 {
1162 m [0] [j] = fColorMatrix2 [0] [j];
1163 m [1] [j] = fColorMatrix2 [1] [j];
1164 m [2] [j] = fColorMatrix2 [2] [j];
1165 m [3] [j] = fColorMatrix2 [1] [j];
1166 }
1167
1168 fColorMatrix2 = m;
1169
1170 }
1171
1172 fReductionMatrix1.Clear ();
1173 fReductionMatrix2.Clear ();
1174
1175 fForwardMatrix1.Clear ();
1176 fForwardMatrix2.Clear ();
1177
1178 }
1179
1180 /*****************************************************************************/
1181
HueSatMapForWhite(const dng_xy_coord & white) const1182 dng_hue_sat_map * dng_camera_profile::HueSatMapForWhite (const dng_xy_coord &white) const
1183 {
1184
1185 if (fHueSatDeltas1.IsValid ())
1186 {
1187
1188 // If we only have the first table, just use it for any color temperature.
1189
1190 if (!fHueSatDeltas2.IsValid ())
1191 {
1192
1193 return new dng_hue_sat_map (fHueSatDeltas1);
1194
1195 }
1196
1197 // Else we need to interpolate based on color temperature.
1198
1199 real64 temperature1 = CalibrationTemperature1 ();
1200 real64 temperature2 = CalibrationTemperature2 ();
1201
1202 if (temperature1 <= 0.0 ||
1203 temperature2 <= 0.0 ||
1204 temperature1 == temperature2)
1205 {
1206
1207 return new dng_hue_sat_map (fHueSatDeltas1);
1208
1209 }
1210
1211 bool reverseOrder = temperature1 > temperature2;
1212
1213 if (reverseOrder)
1214 {
1215 real64 temp = temperature1;
1216 temperature1 = temperature2;
1217 temperature2 = temp;
1218 }
1219
1220 // Convert to temperature/offset space.
1221
1222 dng_temperature td (white);
1223
1224 // Find fraction to weight the first calibration.
1225
1226 real64 g;
1227
1228 if (td.Temperature () <= temperature1)
1229 g = 1.0;
1230
1231 else if (td.Temperature () >= temperature2)
1232 g = 0.0;
1233
1234 else
1235 {
1236
1237 real64 invT = 1.0 / td.Temperature ();
1238
1239 g = (invT - (1.0 / temperature2)) /
1240 ((1.0 / temperature1) - (1.0 / temperature2));
1241
1242 }
1243
1244 // Fix up if we swapped the order.
1245
1246 if (reverseOrder)
1247 {
1248 g = 1.0 - g;
1249 }
1250
1251 // Do the interpolation.
1252
1253 return dng_hue_sat_map::Interpolate (HueSatDeltas1 (),
1254 HueSatDeltas2 (),
1255 g);
1256
1257 }
1258
1259 return NULL;
1260
1261 }
1262
1263 /*****************************************************************************/
1264
Stub()1265 void dng_camera_profile::Stub ()
1266 {
1267
1268 (void) Fingerprint ();
1269
1270 dng_hue_sat_map nullTable;
1271
1272 fHueSatDeltas1 = nullTable;
1273 fHueSatDeltas2 = nullTable;
1274
1275 fLookTable = nullTable;
1276
1277 fToneCurve.SetInvalid ();
1278
1279 fWasStubbed = true;
1280
1281 }
1282
1283 /*****************************************************************************/
1284
SplitCameraProfileName(const dng_string & name,dng_string & baseName,int32 & version)1285 void SplitCameraProfileName (const dng_string &name,
1286 dng_string &baseName,
1287 int32 &version)
1288 {
1289
1290 baseName = name;
1291
1292 version = 0;
1293
1294 uint32 len = baseName.Length ();
1295
1296 if (len == 7 && baseName.StartsWith ("ACR ", true))
1297 {
1298
1299 if (name.Get () [len - 3] >= '0' &&
1300 name.Get () [len - 3] <= '9' &&
1301 name.Get () [len - 2] == '.' &&
1302 name.Get () [len - 1] >= '0' &&
1303 name.Get () [len - 1] <= '9')
1304
1305 baseName.Truncate (3);
1306
1307 version = ((int32) (name.Get () [len - 3] - '0')) * 10 +
1308 ((int32) (name.Get () [len - 1] - '0'));
1309
1310 return;
1311
1312 }
1313
1314 if (len > 5 && baseName.EndsWith (" beta"))
1315 {
1316
1317 baseName.Truncate (len - 5);
1318
1319 version += -10;
1320
1321 }
1322
1323 else if (len > 7)
1324 {
1325
1326 char lastChar = name.Get () [len - 1];
1327
1328 if (lastChar >= '0' && lastChar <= '9')
1329 {
1330
1331 dng_string temp = name;
1332
1333 temp.Truncate (len - 1);
1334
1335 if (temp.EndsWith (" beta "))
1336 {
1337
1338 baseName.Truncate (len - 7);
1339
1340 version += ((int32) (lastChar - '0')) - 10;
1341
1342 }
1343
1344 }
1345
1346 }
1347
1348 len = baseName.Length ();
1349
1350 if (len > 3)
1351 {
1352
1353 char lastChar = name.Get () [len - 1];
1354
1355 if (lastChar >= '0' && lastChar <= '9')
1356 {
1357
1358 dng_string temp = name;
1359
1360 temp.Truncate (len - 1);
1361
1362 if (temp.EndsWith (" v"))
1363 {
1364
1365 baseName.Truncate (len - 3);
1366
1367 version += ((int32) (lastChar - '0')) * 100;
1368
1369 }
1370
1371 }
1372
1373 }
1374
1375 }
1376
1377 /*****************************************************************************/
1378
BuildHueSatMapEncodingTable(dng_memory_allocator & allocator,uint32 encoding,AutoPtr<dng_1d_table> & encodeTable,AutoPtr<dng_1d_table> & decodeTable,bool subSample)1379 void BuildHueSatMapEncodingTable (dng_memory_allocator &allocator,
1380 uint32 encoding,
1381 AutoPtr<dng_1d_table> &encodeTable,
1382 AutoPtr<dng_1d_table> &decodeTable,
1383 bool subSample)
1384 {
1385
1386 encodeTable.Reset ();
1387 decodeTable.Reset ();
1388
1389 switch (encoding)
1390 {
1391
1392 case encoding_Linear:
1393 {
1394
1395 break;
1396
1397 }
1398
1399 case encoding_sRGB:
1400 {
1401
1402 encodeTable.Reset (new dng_1d_table);
1403 decodeTable.Reset (new dng_1d_table);
1404
1405 const dng_1d_function & curve = dng_function_GammaEncode_sRGB::Get ();
1406
1407 encodeTable->Initialize (allocator,
1408 curve,
1409 subSample);
1410
1411 const dng_1d_inverse inverse (curve);
1412
1413 decodeTable->Initialize (allocator,
1414 inverse,
1415 subSample);
1416
1417 break;
1418
1419 }
1420
1421 default:
1422 {
1423
1424 DNG_REPORT ("Unsupported hue sat map / look table encoding.");
1425
1426 break;
1427
1428 }
1429
1430 }
1431
1432 }
1433
1434 /*****************************************************************************/
1435