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 
32 const char * kProfileName_Embedded = "Embedded";
33 
34 const char * kAdobeCalibrationSignature = "com.adobe";
35 
36 /*****************************************************************************/
37 
dng_camera_profile()38 dng_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 
~dng_camera_profile()75 dng_camera_profile::~dng_camera_profile ()
76 	{
77 
78 	}
79 
80 /*****************************************************************************/
81 
IlluminantToTemperature(uint32 light)82 real64 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 
NormalizeColorMatrix(dng_matrix & m)163 void 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 
SetColorMatrix1(const dng_matrix & m)192 void 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 
SetColorMatrix2(const dng_matrix & m)205 void 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 
NormalizeForwardMatrix(dng_matrix & m)220 void 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 
SetForwardMatrix1(const dng_matrix & m)242 void 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 
SetForwardMatrix2(const dng_matrix & m)255 void 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 
SetReductionMatrix1(const dng_matrix & m)268 void 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 
SetReductionMatrix2(const dng_matrix & m)281 void 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 
HasColorMatrix1() const294 bool dng_camera_profile::HasColorMatrix1 () const
295 	{
296 
297 	return fColorMatrix1.Cols () == 3 &&
298 		   fColorMatrix1.Rows ()  > 1;
299 
300 	}
301 
302 /*****************************************************************************/
303 
HasColorMatrix2() const304 bool dng_camera_profile::HasColorMatrix2 () const
305 	{
306 
307 	return fColorMatrix2.Cols () == 3 &&
308 		   fColorMatrix2.Rows () == fColorMatrix1.Rows ();
309 
310 	}
311 
312 /*****************************************************************************/
313 
SetHueSatDeltas1(const dng_hue_sat_map & deltas1)314 void dng_camera_profile::SetHueSatDeltas1 (const dng_hue_sat_map &deltas1)
315 	{
316 
317 	fHueSatDeltas1 = deltas1;
318 
319 	ClearFingerprint ();
320 
321 	}
322 
323 /*****************************************************************************/
324 
SetHueSatDeltas2(const dng_hue_sat_map & deltas2)325 void dng_camera_profile::SetHueSatDeltas2 (const dng_hue_sat_map &deltas2)
326 	{
327 
328 	fHueSatDeltas2 = deltas2;
329 
330 	ClearFingerprint ();
331 
332 	}
333 
334 /*****************************************************************************/
335 
SetLookTable(const dng_hue_sat_map & table)336 void dng_camera_profile::SetLookTable (const dng_hue_sat_map &table)
337 	{
338 
339 	fLookTable = table;
340 
341 	ClearFingerprint ();
342 
343 	}
344 
345 /*****************************************************************************/
346 
FingerprintMatrix(dng_md5_printer_stream & printer,const dng_matrix & matrix)347 static 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 
FingerprintHueSatMap(dng_md5_printer_stream & printer,const dng_hue_sat_map & map)361 static 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 
CalculateFingerprint() const397 void 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 
ValidForwardMatrix(const dng_matrix & m)558 bool 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 
IsValid(uint32 channels) const591 bool 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 
EqualData(const dng_camera_profile & profile) const840 bool 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 
ReadHueSatMap(dng_stream & stream,dng_hue_sat_map & hueSatMap,uint32 hues,uint32 sats,uint32 vals,bool skipSat0)865 void 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 
Parse(dng_stream & stream,dng_camera_profile_info & profileInfo)902 void 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 
ParseExtended(dng_stream & stream)1065 bool 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 
SetFourColorBayer()1097 void 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 
HueSatMapForWhite(const dng_xy_coord & white) const1151 dng_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 
Stub()1234 void 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 
SplitCameraProfileName(const dng_string & name,dng_string & baseName,int32 & version)1254 void 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 
BuildHueSatMapEncodingTable(dng_memory_allocator & allocator,uint32 encoding,AutoPtr<dng_1d_table> & encodeTable,AutoPtr<dng_1d_table> & decodeTable,bool subSample)1330 void 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