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_shared.cpp#2 $ */
10 /* $DateTime: 2012/06/14 20:24:41 $ */
11 /* $Change: 835078 $ */
12 /* $Author: tknoll $ */
13
14 /*****************************************************************************/
15
16 #include "dng_shared.h"
17
18 #include "dng_camera_profile.h"
19 #include "dng_exceptions.h"
20 #include "dng_globals.h"
21 #include "dng_memory.h"
22 #include "dng_parse_utils.h"
23 #include "dng_safe_arithmetic.h"
24 #include "dng_tag_codes.h"
25 #include "dng_tag_types.h"
26 #include "dng_tag_values.h"
27 #include "dng_utils.h"
28
29 /*****************************************************************************/
30
dng_camera_profile_info()31 dng_camera_profile_info::dng_camera_profile_info ()
32
33 : fBigEndian (false)
34
35 , fColorPlanes (0)
36
37 , fCalibrationIlluminant1 (lsUnknown)
38 , fCalibrationIlluminant2 (lsUnknown)
39
40 , fColorMatrix1 ()
41 , fColorMatrix2 ()
42
43 , fForwardMatrix1 ()
44 , fForwardMatrix2 ()
45
46 , fReductionMatrix1 ()
47 , fReductionMatrix2 ()
48
49 , fProfileCalibrationSignature ()
50
51 , fProfileName ()
52
53 , fProfileCopyright ()
54
55 , fEmbedPolicy (pepAllowCopying)
56
57 , fProfileHues (0)
58 , fProfileSats (0)
59 , fProfileVals (0)
60
61 , fHueSatDeltas1Offset (0)
62 , fHueSatDeltas1Count (0)
63
64 , fHueSatDeltas2Offset (0)
65 , fHueSatDeltas2Count (0)
66
67 , fHueSatMapEncoding (encoding_Linear)
68
69 , fLookTableHues (0)
70 , fLookTableSats (0)
71 , fLookTableVals (0)
72
73 , fLookTableOffset (0)
74 , fLookTableCount (0)
75
76 , fLookTableEncoding (encoding_Linear)
77
78 , fBaselineExposureOffset (0, 100)
79
80 , fDefaultBlackRender (defaultBlackRender_Auto)
81
82 , fToneCurveOffset (0)
83 , fToneCurveCount (0)
84
85 , fUniqueCameraModel ()
86
87 {
88
89 }
90
91 /*****************************************************************************/
92
~dng_camera_profile_info()93 dng_camera_profile_info::~dng_camera_profile_info ()
94 {
95
96 }
97
98 /*****************************************************************************/
99
ParseTag(dng_stream & stream,uint32 parentCode,uint32 tagCode,uint32 tagType,uint32 tagCount,uint64 tagOffset)100 bool dng_camera_profile_info::ParseTag (dng_stream &stream,
101 uint32 parentCode,
102 uint32 tagCode,
103 uint32 tagType,
104 uint32 tagCount,
105 uint64 tagOffset)
106 {
107
108 switch (tagCode)
109 {
110
111 case tcCalibrationIlluminant1:
112 {
113
114 CheckTagType (parentCode, tagCode, tagType, ttShort);
115
116 CheckTagCount (parentCode, tagCode, tagCount, 1);
117
118 fCalibrationIlluminant1 = stream.TagValue_uint32 (tagType);
119
120 #if qDNGValidate
121
122 if (gVerbose)
123 {
124
125 printf ("CalibrationIlluminant1: %s\n",
126 LookupLightSource (fCalibrationIlluminant1));
127
128 }
129
130 #endif
131
132 break;
133
134 }
135
136 case tcCalibrationIlluminant2:
137 {
138
139 CheckTagType (parentCode, tagCode, tagType, ttShort);
140
141 CheckTagCount (parentCode, tagCode, tagCount, 1);
142
143 fCalibrationIlluminant2 = stream.TagValue_uint32 (tagType);
144
145 #if qDNGValidate
146
147 if (gVerbose)
148 {
149
150 printf ("CalibrationIlluminant2: %s\n",
151 LookupLightSource (fCalibrationIlluminant2));
152
153 }
154
155 #endif
156
157 break;
158
159 }
160
161 case tcColorMatrix1:
162 {
163
164 CheckTagType (parentCode, tagCode, tagType, ttSRational);
165
166 if (fColorPlanes == 0)
167 {
168
169 fColorPlanes = Pin_uint32 (0, tagCount / 3, kMaxColorPlanes);
170
171 }
172
173 if (!CheckColorImage (parentCode, tagCode, fColorPlanes))
174 return false;
175
176 if (!ParseMatrixTag (stream,
177 parentCode,
178 tagCode,
179 tagType,
180 tagCount,
181 fColorPlanes,
182 3,
183 fColorMatrix1))
184 return false;
185
186 #if qDNGValidate
187
188 if (gVerbose)
189 {
190
191 printf ("ColorMatrix1:\n");
192
193 DumpMatrix (fColorMatrix1);
194
195 }
196
197 #endif
198
199 break;
200
201 }
202
203 case tcColorMatrix2:
204 {
205
206 CheckTagType (parentCode, tagCode, tagType, ttSRational);
207
208 // Kludge - Hasselblad FFF files are very DNG-like, but sometimes
209 // only have a ColorMatrix2 tag and no ColorMatrix1 tag.
210
211 bool hasselbladHack = (fColorPlanes == 0);
212
213 if (hasselbladHack)
214 {
215
216 fColorPlanes = Pin_uint32 (0, tagCount / 3, kMaxColorPlanes);
217
218 #if qDNGValidate
219
220 ReportWarning ("ColorMatrix2 without ColorMatrix1");
221
222 #endif
223
224 }
225
226 if (!CheckColorImage (parentCode, tagCode, fColorPlanes))
227 return false;
228
229 if (!ParseMatrixTag (stream,
230 parentCode,
231 tagCode,
232 tagType,
233 tagCount,
234 fColorPlanes,
235 3,
236 fColorMatrix2))
237 return false;
238
239 #if qDNGValidate
240
241 if (gVerbose)
242 {
243
244 printf ("ColorMatrix2:\n");
245
246 DumpMatrix (fColorMatrix2);
247
248 }
249
250 #endif
251
252 if (hasselbladHack)
253 {
254
255 fColorMatrix1 = fColorMatrix2;
256
257 fColorMatrix2 = dng_matrix ();
258
259 }
260
261 break;
262
263 }
264
265 case tcForwardMatrix1:
266 {
267
268 CheckTagType (parentCode, tagCode, tagType, ttSRational);
269
270 if (!CheckColorImage (parentCode, tagCode, fColorPlanes))
271 return false;
272
273 if (!ParseMatrixTag (stream,
274 parentCode,
275 tagCode,
276 tagType,
277 tagCount,
278 3,
279 fColorPlanes,
280 fForwardMatrix1))
281 return false;
282
283 #if qDNGValidate
284
285 if (gVerbose)
286 {
287
288 printf ("ForwardMatrix1:\n");
289
290 DumpMatrix (fForwardMatrix1);
291
292 }
293
294 #endif
295
296 break;
297
298 }
299
300 case tcForwardMatrix2:
301 {
302
303 CheckTagType (parentCode, tagCode, tagType, ttSRational);
304
305 if (!CheckColorImage (parentCode, tagCode, fColorPlanes))
306 return false;
307
308 if (!ParseMatrixTag (stream,
309 parentCode,
310 tagCode,
311 tagType,
312 tagCount,
313 3,
314 fColorPlanes,
315 fForwardMatrix2))
316 return false;
317
318 #if qDNGValidate
319
320 if (gVerbose)
321 {
322
323 printf ("ForwardMatrix2:\n");
324
325 DumpMatrix (fForwardMatrix2);
326
327 }
328
329 #endif
330
331 break;
332
333 }
334
335 case tcReductionMatrix1:
336 {
337
338 CheckTagType (parentCode, tagCode, tagType, ttSRational);
339
340 if (!CheckColorImage (parentCode, tagCode, fColorPlanes))
341 return false;
342
343 if (!ParseMatrixTag (stream,
344 parentCode,
345 tagCode,
346 tagType,
347 tagCount,
348 3,
349 fColorPlanes,
350 fReductionMatrix1))
351 return false;
352
353 #if qDNGValidate
354
355 if (gVerbose)
356 {
357
358 printf ("ReductionMatrix1:\n");
359
360 DumpMatrix (fReductionMatrix1);
361
362 }
363
364 #endif
365
366 break;
367
368 }
369
370 case tcReductionMatrix2:
371 {
372
373 CheckTagType (parentCode, tagCode, tagType, ttSRational);
374
375 if (!CheckColorImage (parentCode, tagCode, fColorPlanes))
376 return false;
377
378 if (!ParseMatrixTag (stream,
379 parentCode,
380 tagCode,
381 tagType,
382 tagCount,
383 3,
384 fColorPlanes,
385 fReductionMatrix2))
386 return false;
387
388 #if qDNGValidate
389
390 if (gVerbose)
391 {
392
393 printf ("ReductionMatrix2:\n");
394
395 DumpMatrix (fReductionMatrix2);
396
397 }
398
399 #endif
400
401 break;
402
403 }
404
405 case tcProfileCalibrationSignature:
406 {
407
408 CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
409
410 ParseStringTag (stream,
411 parentCode,
412 tagCode,
413 tagCount,
414 fProfileCalibrationSignature,
415 false);
416
417 #if qDNGValidate
418
419 if (gVerbose)
420 {
421
422 printf ("ProfileCalibrationSignature: ");
423
424 DumpString (fProfileCalibrationSignature);
425
426 printf ("\n");
427
428 }
429
430 #endif
431
432 break;
433
434 }
435
436 case tcProfileName:
437 {
438
439 CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
440
441 ParseStringTag (stream,
442 parentCode,
443 tagCode,
444 tagCount,
445 fProfileName,
446 false);
447
448 #if qDNGValidate
449
450 if (gVerbose)
451 {
452
453 printf ("ProfileName: ");
454
455 DumpString (fProfileName);
456
457 printf ("\n");
458
459 }
460
461 #endif
462
463 break;
464
465 }
466
467 case tcProfileCopyright:
468 {
469
470 CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
471
472 ParseStringTag (stream,
473 parentCode,
474 tagCode,
475 tagCount,
476 fProfileCopyright,
477 false);
478
479 #if qDNGValidate
480
481 if (gVerbose)
482 {
483
484 printf ("ProfileCopyright: ");
485
486 DumpString (fProfileCopyright);
487
488 printf ("\n");
489
490 }
491
492 #endif
493
494 break;
495
496 }
497
498 case tcProfileEmbedPolicy:
499 {
500
501 CheckTagType (parentCode, tagCode, tagType, ttLong);
502
503 CheckTagCount (parentCode, tagCode, tagCount, 1);
504
505 fEmbedPolicy = stream.TagValue_uint32 (tagType);
506
507 #if qDNGValidate
508
509 if (gVerbose)
510 {
511
512 const char *policy;
513
514 switch (fEmbedPolicy)
515 {
516
517 case pepAllowCopying:
518 policy = "Allow copying";
519 break;
520
521 case pepEmbedIfUsed:
522 policy = "Embed if used";
523 break;
524
525 case pepEmbedNever:
526 policy = "Embed never";
527 break;
528
529 case pepNoRestrictions:
530 policy = "No restrictions";
531 break;
532
533 default:
534 policy = "INVALID VALUE";
535
536 }
537
538 printf ("ProfileEmbedPolicy: %s\n", policy);
539
540 }
541
542 #endif
543
544 break;
545
546 }
547
548 case tcProfileHueSatMapDims:
549 {
550
551 CheckTagType (parentCode, tagCode, tagType, ttLong);
552
553 CheckTagCount (parentCode, tagCode, tagCount, 2, 3);
554
555 fProfileHues = stream.TagValue_uint32 (tagType);
556 fProfileSats = stream.TagValue_uint32 (tagType);
557
558 if (tagCount > 2)
559 fProfileVals = stream.TagValue_uint32 (tagType);
560 else
561 fProfileVals = 1;
562
563 #if qDNGValidate
564
565 if (gVerbose)
566 {
567
568 printf ("ProfileHueSatMapDims: Hues = %u, Sats = %u, Vals = %u\n",
569 (unsigned) fProfileHues,
570 (unsigned) fProfileSats,
571 (unsigned) fProfileVals);
572
573 }
574
575 #endif
576
577 break;
578
579 }
580
581 case tcProfileHueSatMapData1:
582 {
583
584 if (!CheckTagType (parentCode, tagCode, tagType, ttFloat))
585 return false;
586
587 bool skipSat0 = (tagCount ==
588 SafeUint32Mult(fProfileHues,
589 SafeUint32Sub(fProfileSats, 1u),
590 fProfileVals,
591 3u));
592
593 if (!skipSat0)
594 {
595
596 if (!CheckTagCount (parentCode, tagCode, tagCount,
597 SafeUint32Mult(fProfileHues, fProfileSats, fProfileVals, 3)))
598 return false;
599
600 }
601
602 fBigEndian = stream.BigEndian ();
603
604 fHueSatDeltas1Offset = tagOffset;
605 fHueSatDeltas1Count = tagCount;
606
607 #if qDNGValidate
608
609 if (gVerbose)
610 {
611
612 printf ("ProfileHueSatMapData1:\n");
613
614 DumpHueSatMap (stream,
615 fProfileHues,
616 fProfileSats,
617 fProfileVals,
618 skipSat0);
619
620 }
621
622 #endif
623
624 break;
625
626 }
627
628 case tcProfileHueSatMapData2:
629 {
630
631 if (!CheckTagType (parentCode, tagCode, tagType, ttFloat))
632 return false;
633
634 bool skipSat0 = (tagCount ==
635 SafeUint32Mult(fProfileHues,
636 SafeUint32Sub(fProfileSats, 1u),
637 fProfileVals,
638 3u));
639
640 if (!skipSat0)
641 {
642
643 if (!CheckTagCount (parentCode, tagCode, tagCount,
644 SafeUint32Mult(fProfileHues, fProfileSats, fProfileVals, 3)))
645 return false;
646
647 }
648
649 fBigEndian = stream.BigEndian ();
650
651 fHueSatDeltas2Offset = tagOffset;
652 fHueSatDeltas2Count = tagCount;
653
654 #if qDNGValidate
655
656 if (gVerbose)
657 {
658
659 printf ("ProfileHueSatMapData2:\n");
660
661 DumpHueSatMap (stream,
662 fProfileHues,
663 fProfileSats,
664 fProfileVals,
665 skipSat0);
666
667 }
668
669 #endif
670
671 break;
672
673 }
674
675 case tcProfileHueSatMapEncoding:
676 {
677
678 CheckTagType (parentCode, tagCode, tagType, ttLong);
679
680 CheckTagCount (parentCode, tagCode, tagCount, 1);
681
682 fHueSatMapEncoding = stream.TagValue_uint32 (tagType);
683
684 #if qDNGValidate
685
686 if (gVerbose)
687 {
688
689 const char *encoding = NULL;
690
691 switch (fHueSatMapEncoding)
692 {
693
694 case encoding_Linear:
695 encoding = "Linear";
696 break;
697
698 case encoding_sRGB:
699 encoding = "sRGB";
700 break;
701
702 default:
703 encoding = "INVALID VALUE";
704
705 }
706
707 printf ("ProfileHueSatMapEncoding: %s\n", encoding);
708
709 }
710
711 #endif
712
713 break;
714
715 }
716
717 case tcProfileLookTableDims:
718 {
719
720 CheckTagType (parentCode, tagCode, tagType, ttLong);
721
722 CheckTagCount (parentCode, tagCode, tagCount, 2, 3);
723
724 fLookTableHues = stream.TagValue_uint32 (tagType);
725 fLookTableSats = stream.TagValue_uint32 (tagType);
726
727 if (tagCount > 2)
728 fLookTableVals = stream.TagValue_uint32 (tagType);
729 else
730 fLookTableVals = 1;
731
732 #if qDNGValidate
733
734 if (gVerbose)
735 {
736
737 printf ("ProfileLookTableDims: Hues = %u, Sats = %u, Vals = %u\n",
738 (unsigned) fLookTableHues,
739 (unsigned) fLookTableSats,
740 (unsigned) fLookTableVals);
741
742 }
743
744 #endif
745
746 break;
747
748 }
749
750 case tcProfileLookTableData:
751 {
752
753 if (!CheckTagType (parentCode, tagCode, tagType, ttFloat))
754 return false;
755
756 bool skipSat0 = (tagCount ==
757 SafeUint32Mult(fLookTableHues,
758 SafeUint32Sub(fLookTableSats, 1u),
759 fLookTableVals,
760 3u));
761
762 if (!skipSat0)
763 {
764
765 if (!CheckTagCount (parentCode, tagCode, tagCount,
766 SafeUint32Mult(fLookTableHues,
767 fLookTableSats,
768 fLookTableVals, 3)))
769 return false;
770
771 }
772
773 fBigEndian = stream.BigEndian ();
774
775 fLookTableOffset = tagOffset;
776 fLookTableCount = tagCount;
777
778 #if qDNGValidate
779
780 if (gVerbose)
781 {
782
783 printf ("ProfileLookTableData:\n");
784
785 DumpHueSatMap (stream,
786 fLookTableHues,
787 fLookTableSats,
788 fLookTableVals,
789 skipSat0);
790
791 }
792
793 #endif
794
795 break;
796
797 }
798
799 case tcProfileLookTableEncoding:
800 {
801
802 CheckTagType (parentCode, tagCode, tagType, ttLong);
803
804 CheckTagCount (parentCode, tagCode, tagCount, 1);
805
806 fLookTableEncoding = stream.TagValue_uint32 (tagType);
807
808 #if qDNGValidate
809
810 if (gVerbose)
811 {
812
813 const char *encoding = NULL;
814
815 switch (fLookTableEncoding)
816 {
817
818 case encoding_Linear:
819 encoding = "Linear";
820 break;
821
822 case encoding_sRGB:
823 encoding = "sRGB";
824 break;
825
826 default:
827 encoding = "INVALID VALUE";
828
829 }
830
831 printf ("ProfileLookTableEncoding: %s\n", encoding);
832
833 }
834
835 #endif
836
837 break;
838
839 }
840
841 case tcBaselineExposureOffset:
842 {
843
844 CheckTagType (parentCode, tagCode, tagType, ttSRational);
845
846 CheckTagCount (parentCode, tagCode, tagCount, 1);
847
848 fBaselineExposureOffset = stream.TagValue_srational (tagType);
849
850 #if qDNGValidate
851
852 if (gVerbose)
853 {
854
855 printf ("BaselineExposureOffset: %+0.2f\n",
856 fBaselineExposureOffset.As_real64 ());
857
858 }
859
860 #endif
861
862 break;
863
864 }
865
866 case tcDefaultBlackRender:
867 {
868
869 CheckTagType (parentCode, tagCode, tagType, ttLong);
870
871 CheckTagCount (parentCode, tagCode, tagCount, 1);
872
873 fDefaultBlackRender = stream.TagValue_uint32 (tagType);
874
875 #if qDNGValidate
876
877 if (gVerbose)
878 {
879
880 const char *setting = NULL;
881
882 switch (fDefaultBlackRender)
883 {
884
885 case defaultBlackRender_Auto:
886 setting = "Auto";
887 break;
888
889 case defaultBlackRender_None:
890 setting = "None";
891 break;
892
893 default:
894 setting = "INVALID VALUE";
895
896 }
897
898 printf ("DefaultBlackRender: %s\n",
899 setting);
900
901 }
902
903 #endif
904
905 break;
906
907 }
908
909 case tcProfileToneCurve:
910 {
911
912 if (!CheckTagType (parentCode, tagCode, tagType, ttFloat))
913 return false;
914
915 if (!CheckTagCount (parentCode, tagCode, tagCount, 4, tagCount))
916 return false;
917
918 if ((tagCount & 1) != 0)
919 {
920
921 #if qDNGValidate
922
923 {
924
925 char message [256];
926
927 sprintf (message,
928 "%s %s has odd count (%u)",
929 LookupParentCode (parentCode),
930 LookupTagCode (parentCode, tagCode),
931 (unsigned) tagCount);
932
933 ReportWarning (message);
934
935 }
936
937 #endif
938
939 return false;
940
941 }
942
943 fBigEndian = stream.BigEndian ();
944
945 fToneCurveOffset = tagOffset;
946 fToneCurveCount = tagCount;
947
948 #if qDNGValidate
949
950 if (gVerbose)
951 {
952
953 DumpTagValues (stream,
954 "Coord",
955 parentCode,
956 tagCode,
957 tagType,
958 tagCount);
959
960
961 }
962
963 #endif
964
965 break;
966
967 }
968
969 case tcUniqueCameraModel:
970 {
971
972 // Note: This code is only used when parsing stand-alone
973 // profiles. The embedded profiles are assumed to be restricted
974 // to the model they are embedded in.
975
976 CheckTagType (parentCode, tagCode, tagType, ttAscii);
977
978 ParseStringTag (stream,
979 parentCode,
980 tagCode,
981 tagCount,
982 fUniqueCameraModel,
983 false);
984
985 bool didTrim = fUniqueCameraModel.TrimTrailingBlanks ();
986
987 #if qDNGValidate
988
989 if (didTrim)
990 {
991
992 ReportWarning ("UniqueCameraModel string has trailing blanks");
993
994 }
995
996 if (gVerbose)
997 {
998
999 printf ("UniqueCameraModel: ");
1000
1001 DumpString (fUniqueCameraModel);
1002
1003 printf ("\n");
1004
1005 }
1006
1007 #else
1008
1009 (void) didTrim; // Unused
1010
1011 #endif
1012
1013 break;
1014
1015 }
1016
1017 default:
1018 {
1019
1020 return false;
1021
1022 }
1023
1024 }
1025
1026 return true;
1027
1028 }
1029
1030 /*****************************************************************************/
1031
ParseExtended(dng_stream & stream)1032 bool dng_camera_profile_info::ParseExtended (dng_stream &stream)
1033 {
1034
1035 try
1036 {
1037
1038 // Offsets are relative to the start of this structure, not the entire file.
1039
1040 uint64 startPosition = stream.Position ();
1041
1042 // Read header. Like a TIFF header, but with different magic number
1043 // Plus all offsets are relative to the start of the IFD, not to the
1044 // stream or file.
1045
1046 uint16 byteOrder = stream.Get_uint16 ();
1047
1048 if (byteOrder == byteOrderMM)
1049 fBigEndian = true;
1050
1051 else if (byteOrder == byteOrderII)
1052 fBigEndian = false;
1053
1054 else
1055 return false;
1056
1057 TempBigEndian setEndianness (stream, fBigEndian);
1058
1059 uint16 magicNumber = stream.Get_uint16 ();
1060
1061 if (magicNumber != magicExtendedProfile)
1062 {
1063 return false;
1064 }
1065
1066 uint32 offset = stream.Get_uint32 ();
1067
1068 stream.Skip (SafeUint32Sub(offset, 8u));
1069
1070 // Start on IFD entries.
1071
1072 uint32 ifdEntries = stream.Get_uint16 ();
1073
1074 if (ifdEntries < 1)
1075 {
1076 return false;
1077 }
1078
1079 for (uint32 tag_index = 0; tag_index < ifdEntries; tag_index++)
1080 {
1081
1082 stream.SetReadPosition (startPosition + 8 + 2 + tag_index * 12);
1083
1084 uint16 tagCode = stream.Get_uint16 ();
1085 uint32 tagType = stream.Get_uint16 ();
1086 uint32 tagCount = stream.Get_uint32 ();
1087
1088 uint64 tagOffset = stream.Position ();
1089
1090 if (SafeUint32Mult(TagTypeSize (tagType), tagCount) > 4)
1091 {
1092
1093 tagOffset = startPosition + stream.Get_uint32 ();
1094
1095 stream.SetReadPosition (tagOffset);
1096
1097 }
1098
1099 if (!ParseTag (stream,
1100 0,
1101 tagCode,
1102 tagType,
1103 tagCount,
1104 tagOffset))
1105 {
1106
1107 #if qDNGValidate
1108
1109 if (gVerbose)
1110 {
1111
1112 stream.SetReadPosition (tagOffset);
1113
1114 printf ("*");
1115
1116 DumpTagValues (stream,
1117 LookupTagType (tagType),
1118 0,
1119 tagCode,
1120 tagType,
1121 tagCount);
1122
1123 }
1124
1125 #endif
1126
1127 }
1128
1129 }
1130
1131 return true;
1132
1133 }
1134
1135 catch (...)
1136 {
1137
1138 // Eat parsing errors.
1139
1140 }
1141
1142 return false;
1143
1144 }
1145
1146 /*****************************************************************************/
1147
dng_shared()1148 dng_shared::dng_shared ()
1149
1150 : fExifIFD (0)
1151 , fGPSInfo (0)
1152 , fInteroperabilityIFD (0)
1153 , fKodakDCRPrivateIFD (0)
1154 , fKodakKDCPrivateIFD (0)
1155
1156 , fXMPCount (0)
1157 , fXMPOffset (0)
1158
1159 , fIPTC_NAA_Count (0)
1160 , fIPTC_NAA_Offset (0)
1161
1162 , fMakerNoteCount (0)
1163 , fMakerNoteOffset (0)
1164 , fMakerNoteSafety (0)
1165
1166 , fDNGVersion (0)
1167 , fDNGBackwardVersion (0)
1168
1169 , fUniqueCameraModel ()
1170 , fLocalizedCameraModel ()
1171
1172 , fCameraProfile ()
1173
1174 , fExtraCameraProfiles ()
1175
1176 , fCameraCalibration1 ()
1177 , fCameraCalibration2 ()
1178
1179 , fCameraCalibrationSignature ()
1180
1181 , fAnalogBalance ()
1182
1183 , fAsShotNeutral ()
1184
1185 , fAsShotWhiteXY ()
1186
1187 , fBaselineExposure (0, 1)
1188 , fBaselineNoise (1, 1)
1189 , fNoiseReductionApplied (0, 0)
1190 , fBaselineSharpness (1, 1)
1191 , fLinearResponseLimit (1, 1)
1192 , fShadowScale (1, 1)
1193
1194 , fHasBaselineExposure (false)
1195 , fHasShadowScale (false)
1196
1197 , fDNGPrivateDataCount (0)
1198 , fDNGPrivateDataOffset (0)
1199
1200 , fRawImageDigest ()
1201 , fNewRawImageDigest ()
1202
1203 , fRawDataUniqueID ()
1204
1205 , fOriginalRawFileName ()
1206
1207 , fOriginalRawFileDataCount (0)
1208 , fOriginalRawFileDataOffset (0)
1209
1210 , fOriginalRawFileDigest ()
1211
1212 , fAsShotICCProfileCount (0)
1213 , fAsShotICCProfileOffset (0)
1214
1215 , fAsShotPreProfileMatrix ()
1216
1217 , fCurrentICCProfileCount (0)
1218 , fCurrentICCProfileOffset (0)
1219
1220 , fCurrentPreProfileMatrix ()
1221
1222 , fColorimetricReference (crSceneReferred)
1223
1224 , fAsShotProfileName ()
1225
1226 , fNoiseProfile ()
1227
1228 , fOriginalDefaultFinalSize ()
1229 , fOriginalBestQualityFinalSize ()
1230
1231 , fOriginalDefaultCropSizeH ()
1232 , fOriginalDefaultCropSizeV ()
1233
1234 {
1235
1236 }
1237
1238 /*****************************************************************************/
1239
~dng_shared()1240 dng_shared::~dng_shared ()
1241 {
1242
1243 }
1244
1245 /*****************************************************************************/
1246
ParseTag(dng_stream & stream,dng_exif & exif,uint32 parentCode,bool,uint32 tagCode,uint32 tagType,uint32 tagCount,uint64 tagOffset,int64)1247 bool dng_shared::ParseTag (dng_stream &stream,
1248 dng_exif &exif,
1249 uint32 parentCode,
1250 bool /* isMainIFD */,
1251 uint32 tagCode,
1252 uint32 tagType,
1253 uint32 tagCount,
1254 uint64 tagOffset,
1255 int64 /* offsetDelta */)
1256 {
1257
1258 if (parentCode == 0)
1259 {
1260
1261 if (Parse_ifd0 (stream,
1262 exif,
1263 parentCode,
1264 tagCode,
1265 tagType,
1266 tagCount,
1267 tagOffset))
1268 {
1269
1270 return true;
1271
1272 }
1273
1274 }
1275
1276 if (parentCode == 0 ||
1277 parentCode == tcExifIFD)
1278 {
1279
1280 if (Parse_ifd0_exif (stream,
1281 exif,
1282 parentCode,
1283 tagCode,
1284 tagType,
1285 tagCount,
1286 tagOffset))
1287 {
1288
1289 return true;
1290
1291 }
1292
1293 }
1294
1295 return false;
1296
1297 }
1298
1299 /*****************************************************************************/
1300
1301 // Parses tags that should only appear in IFD 0.
1302
Parse_ifd0(dng_stream & stream,dng_exif &,uint32 parentCode,uint32 tagCode,uint32 tagType,uint32 tagCount,uint64 tagOffset)1303 bool dng_shared::Parse_ifd0 (dng_stream &stream,
1304 dng_exif & /* exif */,
1305 uint32 parentCode,
1306 uint32 tagCode,
1307 uint32 tagType,
1308 uint32 tagCount,
1309 uint64 tagOffset)
1310 {
1311
1312 switch (tagCode)
1313 {
1314
1315 case tcXMP:
1316 {
1317
1318 CheckTagType (parentCode, tagCode, tagType, ttByte, ttUndefined);
1319
1320 fXMPCount = tagCount;
1321 fXMPOffset = fXMPCount ? tagOffset : 0;
1322
1323 #if qDNGValidate
1324
1325 if (gVerbose)
1326 {
1327
1328 printf ("XMP: Count = %u, Offset = %u\n",
1329 (unsigned) fXMPCount,
1330 (unsigned) fXMPOffset);
1331
1332 if (fXMPCount)
1333 {
1334
1335 DumpXMP (stream, fXMPCount);
1336
1337 }
1338
1339 }
1340
1341 #endif
1342
1343 break;
1344
1345 }
1346
1347 case tcIPTC_NAA:
1348 {
1349
1350 CheckTagType (parentCode, tagCode, tagType, ttLong, ttAscii, ttUndefined);
1351
1352 fIPTC_NAA_Count = SafeUint32Mult(tagCount,
1353 TagTypeSize(tagType));
1354 fIPTC_NAA_Offset = fIPTC_NAA_Count ? tagOffset : 0;
1355
1356 #if qDNGValidate
1357
1358 if (gVerbose)
1359 {
1360
1361 printf ("IPTC/NAA: Count = %u, Offset = %u\n",
1362 (unsigned) fIPTC_NAA_Count,
1363 (unsigned) fIPTC_NAA_Offset);
1364
1365 if (fIPTC_NAA_Count)
1366 {
1367
1368 DumpHexAscii (stream, fIPTC_NAA_Count);
1369
1370 }
1371
1372 // Compute and output the digest.
1373
1374 dng_memory_data buffer (fIPTC_NAA_Count);
1375
1376 stream.SetReadPosition (fIPTC_NAA_Offset);
1377
1378 stream.Get (buffer.Buffer (), fIPTC_NAA_Count);
1379
1380 const uint8 *data = buffer.Buffer_uint8 ();
1381
1382 uint32 count = fIPTC_NAA_Count;
1383
1384 // Method 1: Counting all bytes (this is correct).
1385
1386 {
1387
1388 dng_md5_printer printer;
1389
1390 printer.Process (data, count);
1391
1392 printf ("IPTCDigest: ");
1393
1394 DumpFingerprint (printer.Result ());
1395
1396 printf ("\n");
1397
1398 }
1399
1400 // Method 2: Ignoring zero padding.
1401
1402 {
1403
1404 uint32 removed = 0;
1405
1406 while ((removed < 3) && (count > 0) && (data [count - 1] == 0))
1407 {
1408 removed++;
1409 count--;
1410 }
1411
1412 if (removed != 0)
1413 {
1414
1415 dng_md5_printer printer;
1416
1417 printer.Process (data, count);
1418
1419 printf ("IPTCDigest (ignoring zero padding): ");
1420
1421 DumpFingerprint (printer.Result ());
1422
1423 printf ("\n");
1424
1425 }
1426
1427 }
1428
1429 }
1430
1431 #endif
1432
1433 break;
1434
1435 }
1436
1437 case tcExifIFD:
1438 {
1439
1440 CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD);
1441
1442 CheckTagCount (parentCode, tagCode, tagCount, 1);
1443
1444 fExifIFD = stream.TagValue_uint32 (tagType);
1445
1446 #if qDNGValidate
1447
1448 if (gVerbose)
1449 {
1450 printf ("ExifIFD: %u\n", (unsigned) fExifIFD);
1451 }
1452
1453 #endif
1454
1455 break;
1456
1457 }
1458
1459 case tcGPSInfo:
1460 {
1461
1462 CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD);
1463
1464 CheckTagCount (parentCode, tagCode, tagCount, 1);
1465
1466 fGPSInfo = stream.TagValue_uint32 (tagType);
1467
1468 #if qDNGValidate
1469
1470 if (gVerbose)
1471 {
1472 printf ("GPSInfo: %u\n", (unsigned) fGPSInfo);
1473 }
1474
1475 #endif
1476
1477 break;
1478
1479 }
1480
1481 case tcKodakDCRPrivateIFD:
1482 {
1483
1484 CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD);
1485
1486 CheckTagCount (parentCode, tagCode, tagCount, 1);
1487
1488 fKodakDCRPrivateIFD = stream.TagValue_uint32 (tagType);
1489
1490 #if qDNGValidate
1491
1492 if (gVerbose)
1493 {
1494 printf ("KodakDCRPrivateIFD: %u\n", (unsigned) fKodakDCRPrivateIFD);
1495 }
1496
1497 #endif
1498
1499 break;
1500
1501 }
1502
1503 case tcKodakKDCPrivateIFD:
1504 {
1505
1506 CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD);
1507
1508 CheckTagCount (parentCode, tagCode, tagCount, 1);
1509
1510 fKodakKDCPrivateIFD = stream.TagValue_uint32 (tagType);
1511
1512 #if qDNGValidate
1513
1514 if (gVerbose)
1515 {
1516 printf ("KodakKDCPrivateIFD: %u\n", (unsigned) fKodakKDCPrivateIFD);
1517 }
1518
1519 #endif
1520
1521 break;
1522
1523 }
1524
1525 case tcDNGVersion:
1526 {
1527
1528 CheckTagType (parentCode, tagCode, tagType, ttByte);
1529
1530 CheckTagCount (parentCode, tagCode, tagCount, 4);
1531
1532 uint32 b0 = stream.Get_uint8 ();
1533 uint32 b1 = stream.Get_uint8 ();
1534 uint32 b2 = stream.Get_uint8 ();
1535 uint32 b3 = stream.Get_uint8 ();
1536
1537 fDNGVersion = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
1538
1539 #if qDNGValidate
1540
1541 if (gVerbose)
1542 {
1543 printf ("DNGVersion: %u.%u.%u.%u\n",
1544 (unsigned) b0,
1545 (unsigned) b1,
1546 (unsigned) b2,
1547 (unsigned) b3);
1548 }
1549
1550 #endif
1551
1552 break;
1553
1554 }
1555
1556 case tcDNGBackwardVersion:
1557 {
1558
1559 CheckTagType (parentCode, tagCode, tagType, ttByte);
1560
1561 CheckTagCount (parentCode, tagCode, tagCount, 4);
1562
1563 uint32 b0 = stream.Get_uint8 ();
1564 uint32 b1 = stream.Get_uint8 ();
1565 uint32 b2 = stream.Get_uint8 ();
1566 uint32 b3 = stream.Get_uint8 ();
1567
1568 fDNGBackwardVersion = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
1569
1570 #if qDNGValidate
1571
1572 if (gVerbose)
1573 {
1574 printf ("DNGBackwardVersion: %u.%u.%u.%u\n",
1575 (unsigned) b0,
1576 (unsigned) b1,
1577 (unsigned) b2,
1578 (unsigned) b3);
1579 }
1580
1581 #endif
1582
1583 break;
1584
1585 }
1586
1587 case tcUniqueCameraModel:
1588 {
1589
1590 CheckTagType (parentCode, tagCode, tagType, ttAscii);
1591
1592 ParseStringTag (stream,
1593 parentCode,
1594 tagCode,
1595 tagCount,
1596 fUniqueCameraModel,
1597 false);
1598
1599 bool didTrim = fUniqueCameraModel.TrimTrailingBlanks ();
1600
1601 #if qDNGValidate
1602
1603 if (didTrim)
1604 {
1605
1606 ReportWarning ("UniqueCameraModel string has trailing blanks");
1607
1608 }
1609
1610 if (gVerbose)
1611 {
1612
1613 printf ("UniqueCameraModel: ");
1614
1615 DumpString (fUniqueCameraModel);
1616
1617 printf ("\n");
1618
1619 }
1620
1621 #else
1622
1623 (void) didTrim; // Unused
1624
1625 #endif
1626
1627 break;
1628
1629 }
1630
1631 case tcLocalizedCameraModel:
1632 {
1633
1634 CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
1635
1636 ParseStringTag (stream,
1637 parentCode,
1638 tagCode,
1639 tagCount,
1640 fLocalizedCameraModel,
1641 false);
1642
1643 bool didTrim = fLocalizedCameraModel.TrimTrailingBlanks ();
1644
1645 #if qDNGValidate
1646
1647 if (didTrim)
1648 {
1649
1650 ReportWarning ("LocalizedCameraModel string has trailing blanks");
1651
1652 }
1653
1654 if (gVerbose)
1655 {
1656
1657 printf ("LocalizedCameraModel: ");
1658
1659 DumpString (fLocalizedCameraModel);
1660
1661 printf ("\n");
1662
1663 }
1664
1665 #else
1666
1667 (void) didTrim; // Unused
1668
1669 #endif
1670
1671 break;
1672
1673 }
1674
1675 case tcCameraCalibration1:
1676 {
1677
1678 CheckTagType (parentCode, tagCode, tagType, ttSRational);
1679
1680 if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
1681 return false;
1682
1683 if (!ParseMatrixTag (stream,
1684 parentCode,
1685 tagCode,
1686 tagType,
1687 tagCount,
1688 fCameraProfile.fColorPlanes,
1689 fCameraProfile.fColorPlanes,
1690 fCameraCalibration1))
1691 return false;
1692
1693 #if qDNGValidate
1694
1695 if (gVerbose)
1696 {
1697
1698 printf ("CameraCalibration1:\n");
1699
1700 DumpMatrix (fCameraCalibration1);
1701
1702 }
1703
1704 #endif
1705
1706 break;
1707
1708 }
1709
1710 case tcCameraCalibration2:
1711 {
1712
1713 CheckTagType (parentCode, tagCode, tagType, ttSRational);
1714
1715 if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
1716 return false;
1717
1718 if (!ParseMatrixTag (stream,
1719 parentCode,
1720 tagCode,
1721 tagType,
1722 tagCount,
1723 fCameraProfile.fColorPlanes,
1724 fCameraProfile.fColorPlanes,
1725 fCameraCalibration2))
1726 return false;
1727
1728 #if qDNGValidate
1729
1730 if (gVerbose)
1731 {
1732
1733 printf ("CameraCalibration2:\n");
1734
1735 DumpMatrix (fCameraCalibration2);
1736
1737 }
1738
1739 #endif
1740
1741 break;
1742
1743 }
1744
1745 case tcCameraCalibrationSignature:
1746 {
1747
1748 CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
1749
1750 ParseStringTag (stream,
1751 parentCode,
1752 tagCode,
1753 tagCount,
1754 fCameraCalibrationSignature,
1755 false);
1756
1757 #if qDNGValidate
1758
1759 if (gVerbose)
1760 {
1761
1762 printf ("CameraCalibrationSignature: ");
1763
1764 DumpString (fCameraCalibrationSignature);
1765
1766 printf ("\n");
1767
1768 }
1769
1770 #endif
1771
1772 break;
1773
1774 }
1775
1776 case tcAnalogBalance:
1777 {
1778
1779 CheckTagType (parentCode, tagCode, tagType, ttRational);
1780
1781 // Kludge - Hasselblad FFF files are very DNG-like, but sometimes
1782 // they don't have any ColorMatrix tags.
1783
1784 bool hasselbladHack = (fDNGVersion == 0 &&
1785 fCameraProfile.fColorPlanes == 0);
1786
1787 if (hasselbladHack)
1788 {
1789
1790 fCameraProfile.fColorPlanes = Pin_uint32 (0, tagCount, kMaxColorPlanes);
1791
1792 #if qDNGValidate
1793
1794 ReportWarning ("AnalogBalance without ColorMatrix1");
1795
1796 #endif
1797
1798 }
1799
1800 if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
1801 return false;
1802
1803 if (!ParseVectorTag (stream,
1804 parentCode,
1805 tagCode,
1806 tagType,
1807 tagCount,
1808 fCameraProfile.fColorPlanes,
1809 fAnalogBalance))
1810 return false;
1811
1812 #if qDNGValidate
1813
1814 if (gVerbose)
1815 {
1816
1817 printf ("AnalogBalance:");
1818
1819 DumpVector (fAnalogBalance);
1820
1821 }
1822
1823 #endif
1824
1825 break;
1826
1827 }
1828
1829 case tcAsShotNeutral:
1830 {
1831
1832 CheckTagType (parentCode, tagCode, tagType, ttRational);
1833
1834 // Kludge - Hasselblad FFF files are very DNG-like, but sometimes
1835 // they don't have any ColorMatrix tags.
1836
1837 bool hasselbladHack = (fDNGVersion == 0 &&
1838 fCameraProfile.fColorPlanes == 0);
1839
1840 if (hasselbladHack)
1841 {
1842
1843 fCameraProfile.fColorPlanes = Pin_uint32 (0, tagCount, kMaxColorPlanes);
1844
1845 #if qDNGValidate
1846
1847 ReportWarning ("AsShotNeutral without ColorMatrix1");
1848
1849 #endif
1850
1851 }
1852
1853 if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
1854 return false;
1855
1856 if (!ParseVectorTag (stream,
1857 parentCode,
1858 tagCode,
1859 tagType,
1860 tagCount,
1861 fCameraProfile.fColorPlanes,
1862 fAsShotNeutral))
1863 return false;
1864
1865 #if qDNGValidate
1866
1867 if (gVerbose)
1868 {
1869
1870 printf ("AsShotNeutral:");
1871
1872 DumpVector (fAsShotNeutral);
1873
1874 }
1875
1876 #endif
1877
1878 break;
1879
1880 }
1881
1882 case tcAsShotWhiteXY:
1883 {
1884
1885 CheckTagType (parentCode, tagCode, tagType, ttRational);
1886
1887 if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
1888 return false;
1889
1890 if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
1891 return false;
1892
1893 fAsShotWhiteXY.x = stream.TagValue_real64 (tagType);
1894 fAsShotWhiteXY.y = stream.TagValue_real64 (tagType);
1895
1896 #if qDNGValidate
1897
1898 if (gVerbose)
1899 {
1900
1901 printf ("AsShotWhiteXY: %0.4f %0.4f\n",
1902 fAsShotWhiteXY.x,
1903 fAsShotWhiteXY.y);
1904
1905 }
1906
1907 #endif
1908
1909 break;
1910
1911 }
1912
1913 case tcBaselineExposure:
1914 {
1915
1916 CheckTagType (parentCode, tagCode, tagType, ttSRational);
1917
1918 CheckTagCount (parentCode, tagCode, tagCount, 1);
1919
1920 fBaselineExposure = stream.TagValue_srational (tagType);
1921
1922 fHasBaselineExposure = true;
1923
1924 #if qDNGValidate
1925
1926 if (gVerbose)
1927 {
1928
1929 printf ("BaselineExposure: %+0.2f\n",
1930 fBaselineExposure.As_real64 ());
1931
1932 }
1933
1934 #endif
1935
1936 break;
1937
1938 }
1939
1940 case tcBaselineNoise:
1941 {
1942
1943 CheckTagType (parentCode, tagCode, tagType, ttRational);
1944
1945 CheckTagCount (parentCode, tagCode, tagCount, 1);
1946
1947 fBaselineNoise = stream.TagValue_urational (tagType);
1948
1949 #if qDNGValidate
1950
1951 if (gVerbose)
1952 {
1953
1954 printf ("BaselineNoise: %0.2f\n",
1955 fBaselineNoise.As_real64 ());
1956
1957 }
1958
1959 #endif
1960
1961 break;
1962
1963 }
1964
1965 case tcNoiseReductionApplied:
1966 {
1967
1968 if (!CheckTagType (parentCode, tagCode, tagType, ttRational))
1969 return false;
1970
1971 if (!CheckTagCount (parentCode, tagCode, tagCount, 1))
1972 return false;
1973
1974 fNoiseReductionApplied = stream.TagValue_urational (tagType);
1975
1976 #if qDNGValidate
1977
1978 if (gVerbose)
1979 {
1980
1981 printf ("NoiseReductionApplied: %u/%u\n",
1982 (unsigned) fNoiseReductionApplied.n,
1983 (unsigned) fNoiseReductionApplied.d);
1984
1985 }
1986
1987 #endif
1988
1989 break;
1990
1991 }
1992
1993 case tcNoiseProfile:
1994 {
1995
1996 if (!CheckTagType (parentCode, tagCode, tagType, ttDouble))
1997 return false;
1998
1999 // Must be an even, positive number of doubles in a noise profile.
2000
2001 if (!tagCount || (tagCount & 1))
2002 return false;
2003
2004 // Determine number of planes (i.e., half the number of doubles).
2005
2006 const uint32 numPlanes = Pin_uint32 (0,
2007 tagCount >> 1,
2008 kMaxColorPlanes);
2009
2010 // Parse the noise function parameters.
2011
2012 dng_std_vector<dng_noise_function> noiseFunctions;
2013
2014 for (uint32 i = 0; i < numPlanes; i++)
2015 {
2016
2017 const real64 scale = stream.TagValue_real64 (tagType);
2018 const real64 offset = stream.TagValue_real64 (tagType);
2019
2020 noiseFunctions.push_back (dng_noise_function (scale, offset));
2021
2022 }
2023
2024 // Store the noise profile.
2025
2026 fNoiseProfile = dng_noise_profile (noiseFunctions);
2027
2028 // Debug.
2029
2030 #if qDNGValidate
2031
2032 if (gVerbose)
2033 {
2034
2035 printf ("NoiseProfile:\n");
2036
2037 printf (" Planes: %u\n", (unsigned) numPlanes);
2038
2039 for (uint32 plane = 0; plane < numPlanes; plane++)
2040 {
2041
2042 printf (" Noise function for plane %u: scale = %.8lf, offset = %.8lf\n",
2043 (unsigned) plane,
2044 noiseFunctions [plane].Scale (),
2045 noiseFunctions [plane].Offset ());
2046
2047 }
2048
2049 }
2050
2051 #endif
2052
2053 break;
2054
2055 }
2056
2057 case tcBaselineSharpness:
2058 {
2059
2060 CheckTagType (parentCode, tagCode, tagType, ttRational);
2061
2062 CheckTagCount (parentCode, tagCode, tagCount, 1);
2063
2064 fBaselineSharpness = stream.TagValue_urational (tagType);
2065
2066 #if qDNGValidate
2067
2068 if (gVerbose)
2069 {
2070
2071 printf ("BaselineSharpness: %0.2f\n",
2072 fBaselineSharpness.As_real64 ());
2073
2074 }
2075
2076 #endif
2077
2078 break;
2079
2080 }
2081
2082 case tcLinearResponseLimit:
2083 {
2084
2085 CheckTagType (parentCode, tagCode, tagType, ttRational);
2086
2087 CheckTagCount (parentCode, tagCode, tagCount, 1);
2088
2089 fLinearResponseLimit = stream.TagValue_urational (tagType);
2090
2091 #if qDNGValidate
2092
2093 if (gVerbose)
2094 {
2095
2096 printf ("LinearResponseLimit: %0.2f\n",
2097 fLinearResponseLimit.As_real64 ());
2098
2099 }
2100
2101 #endif
2102
2103 break;
2104
2105 }
2106
2107 case tcShadowScale:
2108 {
2109
2110 CheckTagType (parentCode, tagCode, tagType, ttRational);
2111
2112 CheckTagCount (parentCode, tagCode, tagCount, 1);
2113
2114 fShadowScale = stream.TagValue_urational (tagType);
2115
2116 fHasShadowScale = true;
2117
2118 #if qDNGValidate
2119
2120 if (gVerbose)
2121 {
2122
2123 printf ("ShadowScale: %0.4f\n",
2124 fShadowScale.As_real64 ());
2125
2126 }
2127
2128 #endif
2129
2130 break;
2131
2132 }
2133
2134 case tcDNGPrivateData:
2135 {
2136
2137 CheckTagType (parentCode, tagCode, tagType, ttByte);
2138
2139 fDNGPrivateDataCount = tagCount;
2140 fDNGPrivateDataOffset = tagOffset;
2141
2142 #if qDNGValidate
2143
2144 if (gVerbose)
2145 {
2146
2147 printf ("DNGPrivateData: Count = %u, Offset = %u\n",
2148 (unsigned) fDNGPrivateDataCount,
2149 (unsigned) fDNGPrivateDataOffset);
2150
2151 DumpHexAscii (stream, tagCount);
2152
2153 }
2154
2155 #endif
2156
2157 break;
2158
2159 }
2160
2161 case tcMakerNoteSafety:
2162 {
2163
2164 CheckTagType (parentCode, tagCode, tagType, ttShort);
2165
2166 CheckTagCount (parentCode, tagCode, tagCount, 1);
2167
2168 fMakerNoteSafety = stream.TagValue_uint32 (tagType);
2169
2170 #if qDNGValidate
2171
2172 if (gVerbose)
2173 {
2174
2175 printf ("MakerNoteSafety: %s\n",
2176 LookupMakerNoteSafety (fMakerNoteSafety));
2177
2178 }
2179
2180 #endif
2181
2182 break;
2183
2184 }
2185
2186 case tcRawImageDigest:
2187 {
2188
2189 if (!CheckTagType (parentCode, tagCode, tagType, ttByte))
2190 return false;
2191
2192 if (!CheckTagCount (parentCode, tagCode, tagCount, 16))
2193 return false;
2194
2195 stream.Get (fRawImageDigest.data, 16);
2196
2197 #if qDNGValidate
2198
2199 if (gVerbose)
2200 {
2201
2202 printf ("RawImageDigest: ");
2203
2204 DumpFingerprint (fRawImageDigest);
2205
2206 printf ("\n");
2207
2208 }
2209
2210 #endif
2211
2212 break;
2213
2214 }
2215
2216 case tcNewRawImageDigest:
2217 {
2218
2219 if (!CheckTagType (parentCode, tagCode, tagType, ttByte))
2220 return false;
2221
2222 if (!CheckTagCount (parentCode, tagCode, tagCount, 16))
2223 return false;
2224
2225 stream.Get (fNewRawImageDigest.data, 16);
2226
2227 #if qDNGValidate
2228
2229 if (gVerbose)
2230 {
2231
2232 printf ("NewRawImageDigest: ");
2233
2234 DumpFingerprint (fNewRawImageDigest);
2235
2236 printf ("\n");
2237
2238 }
2239
2240 #endif
2241
2242 break;
2243
2244 }
2245
2246 case tcRawDataUniqueID:
2247 {
2248
2249 if (!CheckTagType (parentCode, tagCode, tagType, ttByte))
2250 return false;
2251
2252 if (!CheckTagCount (parentCode, tagCode, tagCount, 16))
2253 return false;
2254
2255 stream.Get (fRawDataUniqueID.data, 16);
2256
2257 #if qDNGValidate
2258
2259 if (gVerbose)
2260 {
2261
2262 printf ("RawDataUniqueID: ");
2263
2264 DumpFingerprint (fRawDataUniqueID);
2265
2266 printf ("\n");
2267
2268 }
2269
2270 #endif
2271
2272 break;
2273
2274 }
2275
2276 case tcOriginalRawFileName:
2277 {
2278
2279 CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
2280
2281 ParseStringTag (stream,
2282 parentCode,
2283 tagCode,
2284 tagCount,
2285 fOriginalRawFileName,
2286 false);
2287
2288 #if qDNGValidate
2289
2290 if (gVerbose)
2291 {
2292
2293 printf ("OriginalRawFileName: ");
2294
2295 DumpString (fOriginalRawFileName);
2296
2297 printf ("\n");
2298
2299 }
2300
2301 #endif
2302
2303 break;
2304
2305 }
2306
2307 case tcOriginalRawFileData:
2308 {
2309
2310 CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2311
2312 fOriginalRawFileDataCount = tagCount;
2313 fOriginalRawFileDataOffset = tagOffset;
2314
2315 #if qDNGValidate
2316
2317 if (gVerbose)
2318 {
2319
2320 printf ("OriginalRawFileData: Count = %u, Offset = %u\n",
2321 (unsigned) fOriginalRawFileDataCount,
2322 (unsigned) fOriginalRawFileDataOffset);
2323
2324 DumpHexAscii (stream, tagCount);
2325
2326 }
2327
2328 #endif
2329
2330 break;
2331
2332 }
2333
2334 case tcOriginalRawFileDigest:
2335 {
2336
2337 if (!CheckTagType (parentCode, tagCode, tagType, ttByte))
2338 return false;
2339
2340 if (!CheckTagCount (parentCode, tagCode, tagCount, 16))
2341 return false;
2342
2343 stream.Get (fOriginalRawFileDigest.data, 16);
2344
2345 #if qDNGValidate
2346
2347 if (gVerbose)
2348 {
2349
2350 printf ("OriginalRawFileDigest: ");
2351
2352 DumpFingerprint (fOriginalRawFileDigest);
2353
2354 printf ("\n");
2355
2356 }
2357
2358 #endif
2359
2360 break;
2361
2362 }
2363
2364 case tcAsShotICCProfile:
2365 {
2366
2367 CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2368
2369 fAsShotICCProfileCount = tagCount;
2370 fAsShotICCProfileOffset = tagOffset;
2371
2372 #if qDNGValidate
2373
2374 if (gVerbose)
2375 {
2376
2377 printf ("AsShotICCProfile: Count = %u, Offset = %u\n",
2378 (unsigned) fAsShotICCProfileCount,
2379 (unsigned) fAsShotICCProfileOffset);
2380
2381 DumpHexAscii (stream, tagCount);
2382
2383 }
2384
2385 #endif
2386
2387 break;
2388
2389 }
2390
2391 case tcAsShotPreProfileMatrix:
2392 {
2393
2394 CheckTagType (parentCode, tagCode, tagType, ttSRational);
2395
2396 if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
2397 return false;
2398
2399 uint32 rows = fCameraProfile.fColorPlanes;
2400
2401 if (tagCount == fCameraProfile.fColorPlanes * 3)
2402 {
2403 rows = 3;
2404 }
2405
2406 if (!ParseMatrixTag (stream,
2407 parentCode,
2408 tagCode,
2409 tagType,
2410 tagCount,
2411 rows,
2412 fCameraProfile.fColorPlanes,
2413 fAsShotPreProfileMatrix))
2414 return false;
2415
2416 #if qDNGValidate
2417
2418 if (gVerbose)
2419 {
2420
2421 printf ("AsShotPreProfileMatrix:\n");
2422
2423 DumpMatrix (fAsShotPreProfileMatrix);
2424
2425 }
2426
2427 #endif
2428
2429 break;
2430
2431 }
2432
2433 case tcCurrentICCProfile:
2434 {
2435
2436 CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2437
2438 fCurrentICCProfileCount = tagCount;
2439 fCurrentICCProfileOffset = tagOffset;
2440
2441 #if qDNGValidate
2442
2443 if (gVerbose)
2444 {
2445
2446 printf ("CurrentICCProfile: Count = %u, Offset = %u\n",
2447 (unsigned) fCurrentICCProfileCount,
2448 (unsigned) fCurrentICCProfileOffset);
2449
2450 DumpHexAscii (stream, tagCount);
2451
2452 }
2453
2454 #endif
2455
2456 break;
2457
2458 }
2459
2460 case tcCurrentPreProfileMatrix:
2461 {
2462
2463 CheckTagType (parentCode, tagCode, tagType, ttSRational);
2464
2465 if (!CheckColorImage (parentCode, tagCode, fCameraProfile.fColorPlanes))
2466 return false;
2467
2468 uint32 rows = fCameraProfile.fColorPlanes;
2469
2470 if (tagCount == fCameraProfile.fColorPlanes * 3)
2471 {
2472 rows = 3;
2473 }
2474
2475 if (!ParseMatrixTag (stream,
2476 parentCode,
2477 tagCode,
2478 tagType,
2479 tagCount,
2480 rows,
2481 fCameraProfile.fColorPlanes,
2482 fCurrentPreProfileMatrix))
2483 return false;
2484
2485 #if qDNGValidate
2486
2487 if (gVerbose)
2488 {
2489
2490 printf ("CurrentPreProfileMatrix:\n");
2491
2492 DumpMatrix (fCurrentPreProfileMatrix);
2493
2494 }
2495
2496 #endif
2497
2498 break;
2499
2500 }
2501
2502 case tcColorimetricReference:
2503 {
2504
2505 CheckTagType (parentCode, tagCode, tagType, ttShort);
2506
2507 CheckTagCount (parentCode, tagCode, tagCount, 1);
2508
2509 fColorimetricReference = stream.TagValue_uint32 (tagType);
2510
2511 #if qDNGValidate
2512
2513 if (gVerbose)
2514 {
2515
2516 printf ("ColorimetricReference: %s\n",
2517 LookupColorimetricReference (fColorimetricReference));
2518
2519 }
2520
2521 #endif
2522
2523 break;
2524
2525 }
2526
2527 case tcExtraCameraProfiles:
2528 {
2529
2530 CheckTagType (parentCode, tagCode, tagType, ttLong);
2531
2532 CheckTagCount (parentCode, tagCode, tagCount, 1, tagCount);
2533
2534 #if qDNGValidate
2535
2536 if (gVerbose)
2537 {
2538
2539 printf ("ExtraCameraProfiles: %u\n", (unsigned) tagCount);
2540
2541 }
2542
2543 #endif
2544
2545 fExtraCameraProfiles.reserve (tagCount);
2546
2547 for (uint32 index = 0; index < tagCount; index++)
2548 {
2549
2550 #if qDNGValidate
2551
2552 if (gVerbose)
2553 {
2554
2555 printf ("\nExtraCameraProfile [%u]:\n\n", (unsigned) index);
2556
2557 }
2558
2559 #endif
2560
2561 stream.SetReadPosition (tagOffset + index * 4);
2562
2563 uint32 profileOffset = stream.TagValue_uint32 (tagType);
2564
2565 dng_camera_profile_info profileInfo;
2566
2567 stream.SetReadPosition (profileOffset);
2568
2569 if (profileInfo.ParseExtended (stream))
2570 {
2571
2572 fExtraCameraProfiles.push_back (profileInfo);
2573
2574 }
2575
2576 else
2577 {
2578
2579 #if qDNGValidate
2580
2581 ReportWarning ("Unable to parse extra camera profile");
2582
2583 #endif
2584
2585 }
2586
2587 }
2588
2589 #if qDNGValidate
2590
2591 if (gVerbose)
2592 {
2593
2594 printf ("\nDone with ExtraCameraProfiles\n\n");
2595
2596 }
2597
2598 #endif
2599
2600 break;
2601
2602 }
2603
2604 case tcAsShotProfileName:
2605 {
2606
2607 CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
2608
2609 ParseStringTag (stream,
2610 parentCode,
2611 tagCode,
2612 tagCount,
2613 fAsShotProfileName,
2614 false);
2615
2616 #if qDNGValidate
2617
2618 if (gVerbose)
2619 {
2620
2621 printf ("AsShotProfileName: ");
2622
2623 DumpString (fAsShotProfileName);
2624
2625 printf ("\n");
2626
2627 }
2628
2629 #endif
2630
2631 break;
2632
2633 }
2634
2635 case tcOriginalDefaultFinalSize:
2636 {
2637
2638 CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
2639
2640 if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
2641 return false;
2642
2643 fOriginalDefaultFinalSize.h = stream.TagValue_int32 (tagType);
2644 fOriginalDefaultFinalSize.v = stream.TagValue_int32 (tagType);
2645
2646 #if qDNGValidate
2647
2648 if (gVerbose)
2649 {
2650
2651 printf ("OriginalDefaultFinalSize: H = %d V = %d\n",
2652 (int) fOriginalDefaultFinalSize.h,
2653 (int) fOriginalDefaultFinalSize.v);
2654
2655 }
2656
2657 #endif
2658
2659 break;
2660
2661 }
2662
2663 case tcOriginalBestQualityFinalSize:
2664 {
2665
2666 CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
2667
2668 if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
2669 return false;
2670
2671 fOriginalBestQualityFinalSize.h = stream.TagValue_int32 (tagType);
2672 fOriginalBestQualityFinalSize.v = stream.TagValue_int32 (tagType);
2673
2674 #if qDNGValidate
2675
2676 if (gVerbose)
2677 {
2678
2679 printf ("OriginalBestQualityFinalSize: H = %d V = %d\n",
2680 (int) fOriginalBestQualityFinalSize.h,
2681 (int) fOriginalBestQualityFinalSize.v);
2682
2683 }
2684
2685 #endif
2686
2687 break;
2688
2689 }
2690
2691 case tcOriginalDefaultCropSize:
2692 {
2693
2694 CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong, ttRational);
2695
2696 if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
2697 return false;
2698
2699 fOriginalDefaultCropSizeH = stream.TagValue_urational (tagType);
2700 fOriginalDefaultCropSizeV = stream.TagValue_urational (tagType);
2701
2702 #if qDNGValidate
2703
2704 if (gVerbose)
2705 {
2706
2707 printf ("OriginalDefaultCropSize: H = %0.2f V = %0.2f\n",
2708 fOriginalDefaultCropSizeH.As_real64 (),
2709 fOriginalDefaultCropSizeV.As_real64 ());
2710
2711 }
2712
2713 #endif
2714
2715 break;
2716
2717 }
2718
2719 default:
2720 {
2721
2722 // The main camera profile tags also appear in IFD 0
2723
2724 return fCameraProfile.ParseTag (stream,
2725 parentCode,
2726 tagCode,
2727 tagType,
2728 tagCount,
2729 tagOffset);
2730
2731 }
2732
2733 }
2734
2735 return true;
2736
2737 }
2738
2739 /*****************************************************************************/
2740
2741 // Parses tags that should only appear in IFD 0 or EXIF IFD.
2742
Parse_ifd0_exif(dng_stream & stream,dng_exif &,uint32 parentCode,uint32 tagCode,uint32 tagType,uint32 tagCount,uint64 tagOffset)2743 bool dng_shared::Parse_ifd0_exif (dng_stream &stream,
2744 dng_exif & /* exif */,
2745 uint32 parentCode,
2746 uint32 tagCode,
2747 uint32 tagType,
2748 uint32 tagCount,
2749 uint64 tagOffset)
2750 {
2751
2752 switch (tagCode)
2753 {
2754
2755 case tcMakerNote:
2756 {
2757
2758 CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2759
2760 fMakerNoteCount = tagCount;
2761 fMakerNoteOffset = tagOffset;
2762
2763 #if qDNGValidate
2764
2765 if (gVerbose)
2766 {
2767
2768 printf ("MakerNote: Count = %u, Offset = %u\n",
2769 (unsigned) fMakerNoteCount,
2770 (unsigned) fMakerNoteOffset);
2771
2772 DumpHexAscii (stream, tagCount);
2773
2774 }
2775
2776 #endif
2777
2778 break;
2779
2780 }
2781
2782 case tcInteroperabilityIFD:
2783 {
2784
2785 CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD);
2786
2787 CheckTagCount (parentCode, tagCode, tagCount, 1);
2788
2789 fInteroperabilityIFD = stream.TagValue_uint32 (tagType);
2790
2791 #if qDNGValidate
2792
2793 if (gVerbose)
2794 {
2795 printf ("InteroperabilityIFD: %u\n", (unsigned) fInteroperabilityIFD);
2796 }
2797
2798 #endif
2799
2800 break;
2801
2802 }
2803
2804 default:
2805 {
2806
2807 return false;
2808
2809 }
2810
2811 }
2812
2813 return true;
2814
2815 }
2816
2817 /*****************************************************************************/
2818
PostParse(dng_host &,dng_exif &)2819 void dng_shared::PostParse (dng_host & /* host */,
2820 dng_exif & /* exif */)
2821 {
2822
2823 // Fill in default values for DNG images.
2824
2825 if (fDNGVersion != 0)
2826 {
2827
2828 // Support for DNG versions before 1.0.0.0.
2829
2830 if (fDNGVersion < dngVersion_1_0_0_0)
2831 {
2832
2833 #if qDNGValidate
2834
2835 ReportWarning ("DNGVersion less than 1.0.0.0");
2836
2837 #endif
2838
2839 // The CalibrationIlluminant tags were added just before
2840 // DNG version 1.0.0.0, and were hardcoded before that.
2841
2842 fCameraProfile.fCalibrationIlluminant1 = lsStandardLightA;
2843 fCameraProfile.fCalibrationIlluminant2 = lsD65;
2844
2845 fDNGVersion = dngVersion_1_0_0_0;
2846
2847 }
2848
2849 // Default value for DNGBackwardVersion tag.
2850
2851 if (fDNGBackwardVersion == 0)
2852 {
2853
2854 fDNGBackwardVersion = fDNGVersion & 0xFFFF0000;
2855
2856 }
2857
2858 // Check DNGBackwardVersion value.
2859
2860 if (fDNGBackwardVersion < dngVersion_1_0_0_0)
2861 {
2862
2863 #if qDNGValidate
2864
2865 ReportWarning ("DNGBackwardVersion less than 1.0.0.0");
2866
2867 #endif
2868
2869 fDNGBackwardVersion = dngVersion_1_0_0_0;
2870
2871 }
2872
2873 if (fDNGBackwardVersion > fDNGVersion)
2874 {
2875
2876 #if qDNGValidate
2877
2878 ReportWarning ("DNGBackwardVersion > DNGVersion");
2879
2880 #endif
2881
2882 fDNGBackwardVersion = fDNGVersion;
2883
2884 }
2885
2886 // Check UniqueCameraModel.
2887
2888 if (fUniqueCameraModel.IsEmpty ())
2889 {
2890
2891 #if qDNGValidate
2892
2893 ReportWarning ("Missing or invalid UniqueCameraModel");
2894
2895 #endif
2896
2897 fUniqueCameraModel.Set ("Digital Negative");
2898
2899 }
2900
2901 // If we don't know the color depth yet, it must be a monochrome DNG.
2902
2903 if (fCameraProfile.fColorPlanes == 0)
2904 {
2905
2906 fCameraProfile.fColorPlanes = 1;
2907
2908 }
2909
2910 // Check color info.
2911
2912 if (fCameraProfile.fColorPlanes > 1)
2913 {
2914
2915 // Check illuminant pair.
2916
2917 if (fCameraProfile.fColorMatrix2.NotEmpty ())
2918 {
2919
2920 if (fCameraProfile.fCalibrationIlluminant1 == lsUnknown ||
2921 (fCameraProfile.fCalibrationIlluminant2 == lsUnknown ||
2922 (fCameraProfile.fCalibrationIlluminant1 == fCameraProfile.fCalibrationIlluminant2)))
2923 {
2924
2925 #if qDNGValidate
2926
2927 ReportWarning ("Invalid CalibrationIlluminant pair");
2928
2929 #endif
2930
2931 fCameraProfile.fColorMatrix2 = dng_matrix ();
2932
2933 }
2934
2935 }
2936
2937 // If the colorimetric reference is the ICC profile PCS, then the
2938 // data must already be white balanced. The "AsShotWhiteXY" is required
2939 // to be the ICC Profile PCS white point.
2940
2941 if (fColorimetricReference == crICCProfilePCS)
2942 {
2943
2944 if (fAsShotNeutral.NotEmpty ())
2945 {
2946
2947 #if qDNGValidate
2948
2949 ReportWarning ("AsShotNeutral not allowed for this "
2950 "ColorimetricReference value");
2951
2952 #endif
2953
2954 fAsShotNeutral.Clear ();
2955
2956 }
2957
2958 dng_xy_coord pcs = PCStoXY ();
2959
2960 #if qDNGValidate
2961
2962 if (fAsShotWhiteXY.IsValid ())
2963 {
2964
2965 if (Abs_real64 (fAsShotWhiteXY.x - pcs.x) > 0.01 ||
2966 Abs_real64 (fAsShotWhiteXY.y - pcs.y) > 0.01)
2967 {
2968
2969 ReportWarning ("AsShotWhiteXY does not match the ICC Profile PCS");
2970
2971 }
2972
2973 }
2974
2975 #endif
2976
2977 fAsShotWhiteXY = pcs;
2978
2979 }
2980
2981 else
2982 {
2983
2984 // Warn if both AsShotNeutral and AsShotWhiteXY are specified.
2985
2986 if (fAsShotNeutral.NotEmpty () && fAsShotWhiteXY.IsValid ())
2987 {
2988
2989 #if qDNGValidate
2990
2991 ReportWarning ("Both AsShotNeutral and AsShotWhiteXY included");
2992
2993 #endif
2994
2995 fAsShotWhiteXY = dng_xy_coord ();
2996
2997 }
2998
2999 // Warn if neither AsShotNeutral nor AsShotWhiteXY are specified.
3000
3001 #if qDNGValidate
3002
3003 if (fAsShotNeutral.IsEmpty () && !fAsShotWhiteXY.IsValid ())
3004 {
3005
3006 ReportWarning ("Neither AsShotNeutral nor AsShotWhiteXY included",
3007 "legal but not recommended");
3008
3009 }
3010
3011 #endif
3012
3013 }
3014
3015 // Default values of calibration signatures are required for legacy
3016 // compatiblity.
3017
3018 if (fCameraProfile.fCalibrationIlluminant1 == lsStandardLightA &&
3019 fCameraProfile.fCalibrationIlluminant2 == lsD65 &&
3020 fCameraCalibration1.Rows () == fCameraProfile.fColorPlanes &&
3021 fCameraCalibration1.Cols () == fCameraProfile.fColorPlanes &&
3022 fCameraCalibration2.Rows () == fCameraProfile.fColorPlanes &&
3023 fCameraCalibration2.Cols () == fCameraProfile.fColorPlanes &&
3024 fCameraCalibrationSignature.IsEmpty () &&
3025 fCameraProfile.fProfileCalibrationSignature.IsEmpty () )
3026 {
3027
3028 fCameraCalibrationSignature.Set (kAdobeCalibrationSignature);
3029
3030 fCameraProfile.fProfileCalibrationSignature.Set (kAdobeCalibrationSignature);
3031
3032 }
3033
3034 }
3035
3036 // Check BaselineNoise.
3037
3038 if (fBaselineNoise.As_real64 () <= 0.0)
3039 {
3040
3041 #if qDNGValidate
3042
3043 ReportWarning ("Invalid BaselineNoise");
3044
3045 #endif
3046
3047 fBaselineNoise = dng_urational (1, 1);
3048
3049 }
3050
3051 // Check BaselineSharpness.
3052
3053 if (fBaselineSharpness.As_real64 () <= 0.0)
3054 {
3055
3056 #if qDNGValidate
3057
3058 ReportWarning ("Invalid BaselineSharpness");
3059
3060 #endif
3061
3062 fBaselineSharpness = dng_urational (1, 1);
3063
3064 }
3065
3066 // Check NoiseProfile.
3067
3068 if (!fNoiseProfile.IsValid () && fNoiseProfile.NumFunctions () != 0)
3069 {
3070
3071 #if qDNGValidate
3072
3073 ReportWarning ("Invalid NoiseProfile");
3074
3075 #endif
3076
3077 fNoiseProfile = dng_noise_profile ();
3078
3079 }
3080
3081 // Check LinearResponseLimit.
3082
3083 if (fLinearResponseLimit.As_real64 () < 0.5 ||
3084 fLinearResponseLimit.As_real64 () > 1.0)
3085 {
3086
3087 #if qDNGValidate
3088
3089 ReportWarning ("Invalid LinearResponseLimit");
3090
3091 #endif
3092
3093 fLinearResponseLimit = dng_urational (1, 1);
3094
3095 }
3096
3097 // Check ShadowScale.
3098
3099 if (fShadowScale.As_real64 () <= 0.0)
3100 {
3101
3102 #if qDNGValidate
3103
3104 ReportWarning ("Invalid ShadowScale");
3105
3106 #endif
3107
3108 fShadowScale = dng_urational (1, 1);
3109
3110 }
3111
3112 }
3113
3114 }
3115
3116 /*****************************************************************************/
3117
IsValidDNG()3118 bool dng_shared::IsValidDNG ()
3119 {
3120
3121 // Check DNGVersion value.
3122
3123 if (fDNGVersion < dngVersion_1_0_0_0)
3124 {
3125
3126 #if qDNGValidate
3127
3128 if (fDNGVersion != dngVersion_None)
3129 {
3130
3131 ReportError ("Invalid DNGVersion");
3132
3133 }
3134
3135 #if qDNGValidateTarget
3136
3137 else
3138 {
3139
3140 ReportError ("Missing DNGVersion");
3141
3142 }
3143
3144 #endif
3145
3146 #endif
3147
3148 return false;
3149
3150 }
3151
3152 // Check DNGBackwardVersion value.
3153
3154 if (fDNGBackwardVersion > dngVersion_Current)
3155 {
3156
3157 #if qDNGValidate
3158
3159 ReportError ("DNGBackwardVersion (or DNGVersion) is too high");
3160
3161 #endif
3162
3163 ThrowUnsupportedDNG ();
3164
3165 }
3166
3167 // Check color transform info.
3168
3169 if (fCameraProfile.fColorPlanes > 1)
3170 {
3171
3172 // CameraCalibration1 is optional, but it must be valid if present.
3173
3174 if (fCameraCalibration1.Cols () != 0 ||
3175 fCameraCalibration1.Rows () != 0)
3176 {
3177
3178 if (fCameraCalibration1.Cols () != fCameraProfile.fColorPlanes ||
3179 fCameraCalibration1.Rows () != fCameraProfile.fColorPlanes)
3180 {
3181
3182 #if qDNGValidate
3183
3184 ReportError ("CameraCalibration1 is wrong size");
3185
3186 #endif
3187
3188 return false;
3189
3190 }
3191
3192 // Make sure it is invertable.
3193
3194 try
3195 {
3196
3197 (void) Invert (fCameraCalibration1);
3198
3199 }
3200
3201 catch (...)
3202 {
3203
3204 #if qDNGValidate
3205
3206 ReportError ("CameraCalibration1 is not invertable");
3207
3208 #endif
3209
3210 return false;
3211
3212 }
3213
3214 }
3215
3216 // CameraCalibration2 is optional, but it must be valid if present.
3217
3218 if (fCameraCalibration2.Cols () != 0 ||
3219 fCameraCalibration2.Rows () != 0)
3220 {
3221
3222 if (fCameraCalibration2.Cols () != fCameraProfile.fColorPlanes ||
3223 fCameraCalibration2.Rows () != fCameraProfile.fColorPlanes)
3224 {
3225
3226 #if qDNGValidate
3227
3228 ReportError ("CameraCalibration2 is wrong size");
3229
3230 #endif
3231
3232 return false;
3233
3234 }
3235
3236 // Make sure it is invertable.
3237
3238 try
3239 {
3240
3241 (void) Invert (fCameraCalibration2);
3242
3243 }
3244
3245 catch (...)
3246 {
3247
3248 #if qDNGValidate
3249
3250 ReportError ("CameraCalibration2 is not invertable");
3251
3252 #endif
3253
3254 return false;
3255
3256 }
3257
3258 }
3259
3260 // Check analog balance
3261
3262 dng_matrix analogBalance;
3263
3264 if (fAnalogBalance.NotEmpty ())
3265 {
3266
3267 analogBalance = fAnalogBalance.AsDiagonal ();
3268
3269 try
3270 {
3271
3272 (void) Invert (analogBalance);
3273
3274 }
3275
3276 catch (...)
3277 {
3278
3279 #if qDNGValidate
3280
3281 ReportError ("AnalogBalance is not invertable");
3282
3283 #endif
3284
3285 return false;
3286
3287 }
3288
3289 }
3290
3291 }
3292
3293 return true;
3294
3295 }
3296
3297 /*****************************************************************************/
3298