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