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