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