1/*****************************************************************************/
2// Copyright 2006-2012 Adobe Systems Incorporated
3// All Rights Reserved.
4//
5// NOTICE:  Adobe permits you to use, modify, and distribute this file in
6// accordance with the terms of the Adobe license agreement accompanying it.
7/*****************************************************************************/
8
9/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_ifd.cpp#3 $ */
10/* $DateTime: 2012/06/05 11:05:39 $ */
11/* $Change: 833352 $ */
12/* $Author: tknoll $ */
13
14/*****************************************************************************/
15
16#include "dng_ifd.h"
17
18#include "dng_exceptions.h"
19#include "dng_flags.h"
20#include "dng_globals.h"
21#include "dng_ifd.h"
22#include "dng_types.h"
23#include "dng_parse_utils.h"
24#include "dng_read_image.h"
25#include "dng_stream.h"
26#include "dng_tag_codes.h"
27#include "dng_tag_types.h"
28#include "dng_tag_values.h"
29#include "dng_utils.h"
30
31/*****************************************************************************/
32
33dng_preview_info::dng_preview_info ()
34
35	:	fIsPrimary          (true)
36	,	fApplicationName    ()
37	,	fApplicationVersion ()
38	,	fSettingsName       ()
39	,	fSettingsDigest     ()
40	,	fColorSpace			(previewColorSpace_MaxEnum)
41	,	fDateTime			()
42	,	fRawToPreviewGain   (1.0)
43	,	fCacheVersion		(0)
44
45	{
46
47	}
48
49/*****************************************************************************/
50
51dng_preview_info::~dng_preview_info ()
52	{
53
54	}
55
56/*****************************************************************************/
57
58dng_ifd::dng_ifd ()
59
60	:	fUsesNewSubFileType (false)
61	,	fNewSubFileType     (0)
62
63	,	fImageWidth  (0)
64	,	fImageLength (0)
65
66	,	fCompression (ccUncompressed)
67	,	fPredictor   (cpNullPredictor)
68
69	,	fPhotometricInterpretation (0xFFFFFFFF)
70
71	,	fFillOrder (1)
72
73	,	fOrientation          (0)
74	,	fOrientationType      (0)
75	,	fOrientationOffset    (kDNGStreamInvalidOffset)
76	,	fOrientationBigEndian (false)
77
78	,	fSamplesPerPixel (1)
79
80	,	fPlanarConfiguration (pcInterleaved)
81
82	,	fXResolution    (0.0)
83	,	fYResolution    (0.0)
84	,	fResolutionUnit (0)
85
86	,	fUsesStrips (false)
87	,	fUsesTiles  (false)
88
89	,	fTileWidth  (0)
90	,	fTileLength (0)
91
92	,	fTileOffsetsType   (0)
93	,	fTileOffsetsCount  (0)
94	,	fTileOffsetsOffset (0)
95
96	,	fTileByteCountsType   (0)
97	,	fTileByteCountsCount  (0)
98	,	fTileByteCountsOffset (0)
99
100	,	fSubIFDsCount  (0)
101	,	fSubIFDsOffset (0)
102
103	,	fExtraSamplesCount (0)
104
105	,	fJPEGTablesCount  (0)
106	,	fJPEGTablesOffset (0)
107
108	,	fJPEGInterchangeFormat		 (0)
109	,	fJPEGInterchangeFormatLength (0)
110
111	,	fYCbCrCoefficientR (0.0)
112	,	fYCbCrCoefficientG (0.0)
113	,	fYCbCrCoefficientB (0.0)
114
115	,	fYCbCrSubSampleH (0)
116	,	fYCbCrSubSampleV (0)
117
118	,	fYCbCrPositioning (0)
119
120	,	fCFARepeatPatternRows (0)
121	,	fCFARepeatPatternCols (0)
122
123	,	fCFALayout (1)
124
125	,	fLinearizationTableType   (0)
126	,	fLinearizationTableCount  (0)
127	,	fLinearizationTableOffset (0)
128
129	,	fBlackLevelRepeatRows (1)
130	,	fBlackLevelRepeatCols (1)
131
132	,	fBlackLevelDeltaHType   (0)
133	,	fBlackLevelDeltaHCount  (0)
134	,	fBlackLevelDeltaHOffset (0)
135
136	,	fBlackLevelDeltaVType   (0)
137	,	fBlackLevelDeltaVCount  (0)
138	,	fBlackLevelDeltaVOffset (0)
139
140	,	fDefaultScaleH (1, 1)
141	,	fDefaultScaleV (1, 1)
142
143	,	fBestQualityScale (1, 1)
144
145	,	fDefaultCropOriginH (0, 1)
146	,	fDefaultCropOriginV (0, 1)
147
148	,	fDefaultCropSizeH ()
149	,	fDefaultCropSizeV ()
150
151	,	fDefaultUserCropT (0, 1)
152	,	fDefaultUserCropL (0, 1)
153	,	fDefaultUserCropB (1, 1)
154	,	fDefaultUserCropR (1, 1)
155
156	,	fBayerGreenSplit (0)
157
158	,	fChromaBlurRadius ()
159
160	,	fAntiAliasStrength (1, 1)
161
162	,	fActiveArea ()
163
164	,	fMaskedAreaCount (0)
165
166	,	fRowInterleaveFactor (1)
167
168	,	fSubTileBlockRows (1)
169	,	fSubTileBlockCols (1)
170
171	,	fPreviewInfo ()
172
173	,	fOpcodeList1Count  (0)
174	,	fOpcodeList1Offset (0)
175
176	,	fOpcodeList2Count  (0)
177	,	fOpcodeList2Offset (0)
178
179	,	fOpcodeList3Count  (0)
180	,	fOpcodeList3Offset (0)
181
182	,	fLosslessJPEGBug16 (false)
183
184	,	fSampleBitShift (0)
185
186	,	fThisIFD (0)
187	,	fNextIFD (0)
188
189	,	fCompressionQuality (-1)
190
191	,	fPatchFirstJPEGByte (false)
192
193	{
194
195	uint32 j;
196	uint32 k;
197	uint32 n;
198
199	for (j = 0; j < kMaxSamplesPerPixel; j++)
200		{
201		fBitsPerSample [j] = 0;
202		}
203
204	for (j = 0; j < kMaxTileInfo; j++)
205		{
206		fTileOffset    [j] = 0;
207		fTileByteCount [j] = 0;
208		}
209
210	for (j = 0; j < kMaxSamplesPerPixel; j++)
211		{
212		fExtraSamples [j] = esUnspecified;
213		}
214
215	for (j = 0; j < kMaxSamplesPerPixel; j++)
216		{
217		fSampleFormat [j] = sfUnsignedInteger;
218		}
219
220	for (j = 0; j < 6; j++)
221		{
222		fReferenceBlackWhite [j] = 0.0;
223		}
224
225	for (j = 0; j < kMaxCFAPattern; j++)
226		for (k = 0; k < kMaxCFAPattern; k++)
227			{
228			fCFAPattern [j] [k] = 255;
229			}
230
231	for (j = 0; j < kMaxColorPlanes; j++)
232		{
233		fCFAPlaneColor [j] = (uint8) (j < 3 ? j : 255);
234		}
235
236	for (j = 0; j < kMaxBlackPattern; j++)
237		for (k = 0; k < kMaxBlackPattern; k++)
238			for (n = 0; n < kMaxSamplesPerPixel; n++)
239				{
240				fBlackLevel [j] [k] [n] = 0.0;
241				}
242
243	for (j = 0; j < kMaxSamplesPerPixel; j++)
244		{
245		fWhiteLevel [j] = -1.0;		// Don't know real default yet.
246		}
247
248	}
249
250/*****************************************************************************/
251
252dng_ifd::~dng_ifd ()
253	{
254
255	}
256
257/*****************************************************************************/
258
259// Parses tags that should only appear in IFDs that contain images.
260
261bool dng_ifd::ParseTag (dng_stream &stream,
262						uint32 parentCode,
263						uint32 tagCode,
264						uint32 tagType,
265						uint32 tagCount,
266						uint64 tagOffset)
267	{
268
269	uint32 j;
270	uint32 k;
271	uint32 n;
272
273	switch (tagCode)
274		{
275
276		case tcNewSubFileType:
277			{
278
279			CheckTagType (parentCode, tagCode, tagType, ttLong);
280
281			CheckTagCount (parentCode, tagCode, tagCount, 1);
282
283			fUsesNewSubFileType = true;
284
285			fNewSubFileType = stream.TagValue_uint32 (tagType);
286
287			fPreviewInfo.fIsPrimary = (fNewSubFileType == sfPreviewImage);
288
289			#if qDNGValidate
290
291			if (gVerbose)
292				{
293
294				printf ("NewSubFileType: %s\n",
295						LookupNewSubFileType (fNewSubFileType));
296
297				}
298
299			#endif
300
301			break;
302
303			}
304
305		case tcImageWidth:
306			{
307
308			CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
309
310			CheckTagCount (parentCode, tagCode, tagCount, 1);
311
312			fImageWidth = stream.TagValue_uint32 (tagType);
313
314			#if qDNGValidate
315
316			if (gVerbose)
317				{
318				printf ("ImageWidth: %u\n", (unsigned) fImageWidth);
319				}
320
321			#endif
322
323			break;
324
325			}
326
327		case tcImageLength:
328			{
329
330			CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
331
332			CheckTagCount (parentCode, tagCode, tagCount, 1);
333
334			fImageLength = stream.TagValue_uint32 (tagType);
335
336			#if qDNGValidate
337
338			if (gVerbose)
339				{
340				printf ("ImageLength: %u\n", (unsigned) fImageLength);
341				}
342
343			#endif
344
345			break;
346
347			}
348
349		case tcBitsPerSample:
350			{
351
352			CheckTagType (parentCode, tagCode, tagType, ttShort);
353
354			CheckTagCount (parentCode, tagCode, tagCount, 1, 0x0FFFF);
355
356			#if qDNGValidate
357
358			if (gVerbose)
359				{
360				printf ("BitsPerSample:");
361				}
362
363			#endif
364
365			bool extrasMatch = true;
366
367			for (j = 0; j < tagCount; j++)
368				{
369
370				uint32 x = stream.TagValue_uint32 (tagType);
371
372				const uint32 maxBitsPerSample = 32;
373
374				if (j < kMaxSamplesPerPixel)
375					{
376
377					if (x > maxBitsPerSample)
378						{
379						ThrowBadFormat ("BitsPerSample out of bounds.");
380						}
381
382					fBitsPerSample [j] = x;
383					}
384
385				else if (x != fBitsPerSample [kMaxSamplesPerPixel - 1])
386					{
387					extrasMatch = false;
388					}
389
390				#if qDNGValidate
391
392				if (gVerbose)
393					{
394					printf (" %u", (unsigned) x);
395					}
396
397				#endif
398
399				}
400
401			#if qDNGValidate
402
403			if (gVerbose)
404				{
405				printf ("\n");
406				}
407
408			#endif
409
410			if (!extrasMatch)
411				{
412
413				#if qDNGValidate
414
415				ReportError ("BitsPerSample not constant");
416
417				#endif
418
419				ThrowBadFormat ();
420
421				}
422
423			break;
424
425			}
426
427		case tcCompression:
428			{
429
430			CheckTagType (parentCode, tagCode, tagType, ttShort);
431
432			CheckTagCount (parentCode, tagCode, tagCount, 1);
433
434			fCompression = stream.TagValue_uint32 (tagType);
435
436			#if qDNGValidate
437
438			if (gVerbose)
439				{
440
441				printf ("Compression: %s\n",
442					    LookupCompression (fCompression));
443
444				}
445
446			#endif
447
448			// Correct a common TIFF writer mistake.
449
450			if (fCompression == 0)
451				{
452
453				#if qDNGValidate
454
455					{
456
457					char message [256];
458
459					sprintf (message,
460							 "%s has invalid zero compression code",
461							 LookupParentCode (parentCode));
462
463					ReportWarning (message);
464
465					}
466
467				#endif
468
469				fCompression = ccUncompressed;
470
471				}
472
473			break;
474
475			}
476
477		case tcPhotometricInterpretation:
478			{
479
480			CheckTagType (parentCode, tagCode, tagType, ttShort);
481
482			CheckTagCount (parentCode, tagCode, tagCount, 1);
483
484			fPhotometricInterpretation = stream.TagValue_uint32 (tagType);
485
486			#if qDNGValidate
487
488			if (gVerbose)
489				{
490
491				printf ("PhotometricInterpretation: %s\n",
492						LookupPhotometricInterpretation (fPhotometricInterpretation));
493
494				}
495
496			#endif
497
498			break;
499
500			}
501
502		case tcFillOrder:
503			{
504
505			CheckTagType (parentCode, tagCode, tagType, ttShort);
506
507			CheckTagCount (parentCode, tagCode, tagCount, 1);
508
509			fFillOrder = stream.TagValue_uint32 (tagType);
510
511			#if qDNGValidate
512
513			if (gVerbose)
514				{
515				printf ("FillOrder: %u\n", (unsigned) fFillOrder);
516				}
517
518			#endif
519
520			break;
521
522			}
523
524		case tcStripOffsets:
525			{
526
527			CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
528
529			fUsesStrips = true;
530
531			fTileOffsetsType   = tagType;
532			fTileOffsetsCount  = tagCount;
533			fTileOffsetsOffset = tagOffset;
534
535			if (tagCount <= kMaxTileInfo)
536				{
537
538				for (j = 0; j < tagCount; j++)
539					{
540
541					fTileOffset [j] = stream.TagValue_uint32 (tagType);
542
543					}
544
545				}
546
547			#if qDNGValidate
548
549			if (gVerbose)
550				{
551
552				stream.SetReadPosition (tagOffset);
553
554				DumpTagValues (stream,
555							   "Offset",
556							   parentCode,
557							   tagCode,
558							   tagType,
559							   tagCount);
560
561				}
562
563			#endif
564
565			break;
566
567			}
568
569		case tcOrientation:
570			{
571
572			CheckTagType (parentCode, tagCode, tagType, ttShort);
573
574			CheckTagCount (parentCode, tagCode, tagCount, 1);
575
576			fOrientationType      = tagType;
577			fOrientationOffset    = stream.PositionInOriginalFile ();
578			fOrientationBigEndian = stream.BigEndian ();
579
580			fOrientation = stream.TagValue_uint32 (tagType);
581
582			#if qDNGValidate
583
584			if (gVerbose)
585				{
586
587				printf ("Orientation: %s\n",
588					    LookupOrientation (fOrientation));
589
590				}
591
592			#endif
593
594			break;
595
596			}
597
598		case tcSamplesPerPixel:
599			{
600
601			CheckTagType (parentCode, tagCode, tagType, ttShort);
602
603			CheckTagCount (parentCode, tagCode, tagCount, 1);
604
605			fSamplesPerPixel = stream.TagValue_uint32 (tagType);
606
607			#if qDNGValidate
608
609			if (gVerbose)
610				{
611				printf ("SamplesPerPixel: %u\n", (unsigned) fSamplesPerPixel);
612				}
613
614			#endif
615
616			break;
617
618			}
619
620		case tcRowsPerStrip:
621			{
622
623			CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
624
625			CheckTagCount (parentCode, tagCode, tagCount, 1);
626
627			fUsesStrips = true;
628
629			fTileLength = stream.TagValue_uint32 (tagType);
630
631			#if qDNGValidate
632
633			if (gVerbose)
634				{
635				printf ("RowsPerStrip: %u\n", (unsigned) fTileLength);
636				}
637
638			#endif
639
640			break;
641
642			}
643
644		case tcStripByteCounts:
645			{
646
647			CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
648
649			fUsesStrips = true;
650
651			fTileByteCountsType   = tagType;
652			fTileByteCountsCount  = tagCount;
653			fTileByteCountsOffset = tagOffset;
654
655			if (tagCount <= kMaxTileInfo)
656				{
657
658				for (j = 0; j < tagCount; j++)
659					{
660
661					fTileByteCount [j] = stream.TagValue_uint32 (tagType);
662
663					}
664
665				}
666
667			#if qDNGValidate
668
669			if (gVerbose)
670				{
671
672				stream.SetReadPosition (tagOffset);
673
674				DumpTagValues (stream,
675							   "Count",
676							   parentCode,
677							   tagCode,
678							   tagType,
679							   tagCount);
680
681				}
682
683			#endif
684
685			break;
686
687			}
688
689		case tcXResolution:
690			{
691
692			CheckTagType (parentCode, tagCode, tagType, ttRational);
693
694			CheckTagCount (parentCode, tagCode, tagCount, 1);
695
696			fXResolution = stream.TagValue_real64 (tagType);
697
698			#if qDNGValidate
699
700			if (gVerbose)
701				{
702				printf ("XResolution: %0.2f\n", fXResolution);
703				}
704
705			#endif
706
707			break;
708
709			}
710
711		case tcYResolution:
712			{
713
714			CheckTagType (parentCode, tagCode, tagType, ttRational);
715
716			CheckTagCount (parentCode, tagCode, tagCount, 1);
717
718			fYResolution = stream.TagValue_real64 (tagType);
719
720			#if qDNGValidate
721
722			if (gVerbose)
723				{
724				printf ("YResolution: %0.2f\n", fYResolution);
725				}
726
727			#endif
728
729			break;
730
731			}
732
733		case tcPlanarConfiguration:
734			{
735
736			CheckTagType (parentCode, tagCode, tagType, ttShort);
737
738			CheckTagCount (parentCode, tagCode, tagCount, 1);
739
740			fPlanarConfiguration = stream.TagValue_uint32 (tagType);
741
742			#if qDNGValidate
743
744			if (gVerbose)
745				{
746				printf ("PlanarConfiguration: %u\n", (unsigned) fPlanarConfiguration);
747				}
748
749			#endif
750
751			break;
752
753			}
754
755		case tcResolutionUnit:
756			{
757
758			CheckTagType (parentCode, tagCode, tagType, ttShort);
759
760			CheckTagCount (parentCode, tagCode, tagCount, 1);
761
762			fResolutionUnit = stream.TagValue_uint32 (tagType);
763
764			#if qDNGValidate
765
766			if (gVerbose)
767				{
768
769				printf ("ResolutionUnit: %s\n",
770					    LookupResolutionUnit (fResolutionUnit));
771
772				}
773
774			#endif
775
776			break;
777
778			}
779
780		case tcPredictor:
781			{
782
783			CheckTagType (parentCode, tagCode, tagType, ttShort);
784
785			CheckTagCount (parentCode, tagCode, tagCount, 1);
786
787			fPredictor = stream.TagValue_uint32 (tagType);
788
789			#if qDNGValidate
790
791			if (gVerbose)
792				{
793
794				printf ("Predictor: %s\n",
795						LookupPredictor (fPredictor));
796
797				}
798
799			#endif
800
801			break;
802
803			}
804
805		case tcTileWidth:
806			{
807
808			CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
809
810			CheckTagCount (parentCode, tagCode, tagCount, 1);
811
812			fUsesTiles = true;
813
814			fTileWidth = stream.TagValue_uint32 (tagType);
815
816			#if qDNGValidate
817
818			if (gVerbose)
819				{
820				printf ("TileWidth: %u\n", (unsigned) fTileWidth);
821				}
822
823			#endif
824
825			break;
826
827			}
828
829		case tcTileLength:
830			{
831
832			CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
833
834			CheckTagCount (parentCode, tagCode, tagCount, 1);
835
836			fUsesTiles = true;
837
838			fTileLength = stream.TagValue_uint32 (tagType);
839
840			#if qDNGValidate
841
842			if (gVerbose)
843				{
844				printf ("TileLength: %u\n", (unsigned) fTileLength);
845				}
846
847			#endif
848
849			break;
850
851			}
852
853		case tcTileOffsets:
854			{
855
856			CheckTagType (parentCode, tagCode, tagType, ttLong);
857
858			fUsesTiles = true;
859
860			fTileOffsetsType   = tagType;
861			fTileOffsetsCount  = tagCount;
862			fTileOffsetsOffset = tagOffset;
863
864			if (tagCount <= kMaxTileInfo)
865				{
866
867				for (j = 0; j < tagCount; j++)
868					{
869
870					fTileOffset [j] = stream.TagValue_uint32 (tagType);
871
872					}
873
874				}
875
876			#if qDNGValidate
877
878			if (gVerbose)
879				{
880
881				stream.SetReadPosition (tagOffset);
882
883				DumpTagValues (stream,
884							   "Offset",
885							   parentCode,
886							   tagCode,
887							   tagType,
888							   tagCount);
889
890				}
891
892			#endif
893
894			break;
895
896			}
897
898		case tcTileByteCounts:
899			{
900
901			CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
902
903			fUsesTiles = true;
904
905			fTileByteCountsType   = tagType;
906			fTileByteCountsCount  = tagCount;
907			fTileByteCountsOffset = tagOffset;
908
909			if (tagCount <= kMaxTileInfo)
910				{
911
912				for (j = 0; j < tagCount; j++)
913					{
914
915					fTileByteCount [j] = stream.TagValue_uint32 (tagType);
916
917					}
918
919				}
920
921			#if qDNGValidate
922
923			if (gVerbose)
924				{
925
926				stream.SetReadPosition (tagOffset);
927
928				DumpTagValues (stream,
929							   "Count",
930							   parentCode,
931							   tagCode,
932							   tagType,
933							   tagCount);
934
935				}
936
937			#endif
938
939			break;
940
941			}
942
943		case tcSubIFDs:
944			{
945
946			CheckTagType (parentCode, tagCode, tagType, ttLong, ttIFD);
947
948			fSubIFDsCount  = tagCount;
949			fSubIFDsOffset = tagOffset;
950
951			#if qDNGValidate
952
953			if (gVerbose)
954				{
955
956				DumpTagValues (stream,
957							   "IFD",
958							   parentCode,
959							   tagCode,
960							   ttLong,
961							   tagCount);
962
963				}
964
965			#endif
966
967			break;
968
969			}
970
971		case tcExtraSamples:
972			{
973
974			CheckTagType (parentCode, tagCode, tagType, ttShort);
975
976			CheckTagCount (parentCode, tagCode, tagCount, 1, fSamplesPerPixel);
977
978			#if qDNGValidate
979
980			if (gVerbose)
981				{
982				printf ("ExtraSamples:");
983				}
984
985			#endif
986
987			fExtraSamplesCount = tagCount;
988
989			for (j = 0; j < tagCount; j++)
990				{
991
992				uint32 x = stream.TagValue_uint32 (tagType);
993
994				if (j < kMaxSamplesPerPixel)
995					{
996					fExtraSamples [j] = x;
997					}
998
999				#if qDNGValidate
1000
1001				if (gVerbose)
1002					{
1003					printf (" %u", (unsigned) x);
1004					}
1005
1006				#endif
1007
1008				}
1009
1010			#if qDNGValidate
1011
1012			if (gVerbose)
1013				{
1014				printf ("\n");
1015				}
1016
1017			#endif
1018
1019			break;
1020
1021			}
1022
1023		case tcSampleFormat:
1024			{
1025
1026			CheckTagType (parentCode, tagCode, tagType, ttShort);
1027
1028			CheckTagCount (parentCode, tagCode, tagCount, fSamplesPerPixel);
1029
1030			#if qDNGValidate
1031
1032			if (gVerbose)
1033				{
1034				printf ("SampleFormat:");
1035				}
1036
1037			#endif
1038
1039			bool extrasMatch = true;
1040
1041			for (j = 0; j < tagCount; j++)
1042				{
1043
1044				uint32 x = stream.TagValue_uint32 (tagType);
1045
1046				if (j < kMaxSamplesPerPixel)
1047					{
1048					fSampleFormat [j] = x;
1049					}
1050
1051				else if (x != fSampleFormat [kMaxSamplesPerPixel - 1])
1052					{
1053					extrasMatch = false;
1054					}
1055
1056				#if qDNGValidate
1057
1058				if (gVerbose)
1059					{
1060					printf (" %s", LookupSampleFormat (x));
1061					}
1062
1063				#endif
1064
1065				}
1066
1067			#if qDNGValidate
1068
1069			if (gVerbose)
1070				{
1071				printf ("\n");
1072				}
1073
1074			#endif
1075
1076			if (!extrasMatch)
1077				{
1078
1079				#if qDNGValidate
1080
1081				ReportError ("SampleFormat not constant");
1082
1083				#endif
1084
1085				ThrowBadFormat ();
1086
1087				}
1088
1089			break;
1090
1091			}
1092
1093		case tcJPEGTables:
1094			{
1095
1096			CheckTagType (parentCode, tagCode, tagType, ttUndefined);
1097
1098			fJPEGTablesCount  = tagCount;
1099			fJPEGTablesOffset = tagOffset;
1100
1101			#if qDNGValidate
1102
1103			if (gVerbose)
1104				{
1105
1106				printf ("JPEGTables: count = %u, offset = %u\n",
1107						(unsigned) fJPEGTablesCount,
1108						(unsigned) fJPEGTablesOffset);
1109
1110				}
1111
1112			#endif
1113
1114			break;
1115
1116			}
1117
1118		case tcJPEGInterchangeFormat:
1119			{
1120
1121			CheckTagType (parentCode, tagCode, tagType, ttLong);
1122
1123			CheckTagCount (parentCode, tagCode, tagCount, 1);
1124
1125			fJPEGInterchangeFormat = stream.TagValue_uint32 (tagType);
1126
1127			#if qDNGValidate
1128
1129			if (gVerbose)
1130				{
1131				printf ("JPEGInterchangeFormat: %u\n",
1132						(unsigned) fJPEGInterchangeFormat);
1133				}
1134
1135			#endif
1136
1137			break;
1138
1139			}
1140
1141		case tcJPEGInterchangeFormatLength:
1142			{
1143
1144			CheckTagType (parentCode, tagCode, tagType, ttLong);
1145
1146			CheckTagCount (parentCode, tagCode, tagCount, 1);
1147
1148			fJPEGInterchangeFormatLength = stream.TagValue_uint32 (tagType);
1149
1150			#if qDNGValidate
1151
1152			if (gVerbose)
1153				{
1154				printf ("JPEGInterchangeFormatLength: %u\n",
1155						(unsigned) fJPEGInterchangeFormatLength);
1156				}
1157
1158			#endif
1159
1160			break;
1161
1162			}
1163
1164		case tcYCbCrCoefficients:
1165			{
1166
1167			CheckTagType (parentCode, tagCode, tagType, ttRational);
1168
1169			if (!CheckTagCount (parentCode, tagCode, tagCount, 3))
1170				{
1171				return false;
1172				}
1173
1174			fYCbCrCoefficientR = stream.TagValue_real64 (tagType);
1175			fYCbCrCoefficientG = stream.TagValue_real64 (tagType);
1176			fYCbCrCoefficientB = stream.TagValue_real64 (tagType);
1177
1178			#if qDNGValidate
1179
1180			if (gVerbose)
1181				{
1182
1183				printf ("YCbCrCoefficients: R = %0.3f, G = %0.3f, B = %0.3f\n",
1184						fYCbCrCoefficientR,
1185						fYCbCrCoefficientG,
1186						fYCbCrCoefficientB);
1187
1188				}
1189
1190			#endif
1191
1192			break;
1193
1194			}
1195
1196		case tcYCbCrSubSampling:
1197			{
1198
1199			CheckTagType (parentCode, tagCode, tagType, ttShort);
1200
1201			if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
1202				{
1203				return false;
1204				}
1205
1206			fYCbCrSubSampleH = stream.TagValue_uint32 (tagType);
1207			fYCbCrSubSampleV = stream.TagValue_uint32 (tagType);
1208
1209			#if qDNGValidate
1210
1211			if (gVerbose)
1212				{
1213
1214				printf ("YCbCrSubSampling: H = %u, V = %u\n",
1215						(unsigned) fYCbCrSubSampleH,
1216						(unsigned) fYCbCrSubSampleV);
1217
1218				}
1219
1220			#endif
1221
1222			break;
1223
1224			}
1225
1226		case tcYCbCrPositioning:
1227			{
1228
1229			CheckTagType (parentCode, tagCode, tagType, ttShort);
1230
1231			CheckTagCount (parentCode, tagCode, tagCount, 1);
1232
1233			fYCbCrPositioning = stream.TagValue_uint32 (tagType);
1234
1235			#if qDNGValidate
1236
1237			if (gVerbose)
1238				{
1239
1240				printf ("YCbCrPositioning: %u\n",
1241						(unsigned) fYCbCrPositioning);
1242
1243				}
1244
1245			#endif
1246
1247			break;
1248
1249			}
1250
1251		case tcReferenceBlackWhite:
1252			{
1253
1254			CheckTagType (parentCode, tagCode, tagType, ttRational);
1255
1256			if (!CheckTagCount (parentCode, tagCode, tagCount, 6))
1257				{
1258				return false;
1259				}
1260
1261			for (j = 0; j < 6; j++)
1262				{
1263				fReferenceBlackWhite [j] = stream.TagValue_real64 (tagType);
1264				}
1265
1266			#if qDNGValidate
1267
1268			if (gVerbose)
1269				{
1270
1271				printf ("ReferenceBlackWhite: %0.1f %0.1f %0.1f %0.1f %0.1f %0.1f\n",
1272						fReferenceBlackWhite [0],
1273						fReferenceBlackWhite [1],
1274						fReferenceBlackWhite [2],
1275						fReferenceBlackWhite [3],
1276						fReferenceBlackWhite [4],
1277						fReferenceBlackWhite [5]);
1278
1279				}
1280
1281			#endif
1282
1283			break;
1284
1285			}
1286
1287		case tcCFARepeatPatternDim:
1288			{
1289
1290			CheckCFA (parentCode, tagCode, fPhotometricInterpretation);
1291
1292			CheckTagType (parentCode, tagCode, tagType, ttShort);
1293
1294			if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
1295				{
1296				return false;
1297				}
1298
1299			fCFARepeatPatternRows = stream.TagValue_uint32 (tagType);
1300			fCFARepeatPatternCols = stream.TagValue_uint32 (tagType);
1301
1302			#if qDNGValidate
1303
1304			if (gVerbose)
1305				{
1306
1307				printf ("CFARepeatPatternDim: Rows = %u, Cols = %u\n",
1308						(unsigned) fCFARepeatPatternRows,
1309						(unsigned) fCFARepeatPatternCols);
1310
1311				}
1312
1313			#endif
1314
1315			break;
1316
1317			}
1318
1319		case tcCFAPattern:
1320			{
1321
1322			CheckCFA (parentCode, tagCode, fPhotometricInterpretation);
1323
1324			if (!CheckTagType (parentCode, tagCode, tagType, ttByte))
1325				{
1326				return false;
1327				}
1328
1329			if (!CheckTagCount (parentCode, tagCode, tagCount,
1330								SafeUint32Mult(fCFARepeatPatternRows, fCFARepeatPatternCols)))
1331				{
1332				return false;
1333				}
1334
1335			if (fCFARepeatPatternRows < 1 || fCFARepeatPatternRows > kMaxCFAPattern ||
1336				fCFARepeatPatternCols < 1 || fCFARepeatPatternCols > kMaxCFAPattern)
1337				{
1338				return false;
1339				}
1340
1341			// Note that the Exif spec stores this array in a different
1342			// scan order than the TIFF-EP spec.
1343
1344			for (j = 0; j < fCFARepeatPatternRows; j++)
1345				for (k = 0; k < fCFARepeatPatternCols; k++)
1346					{
1347
1348					fCFAPattern [j] [k] = stream.Get_uint8 ();
1349
1350					}
1351
1352			#if qDNGValidate
1353
1354			if (gVerbose)
1355				{
1356
1357				printf ("CFAPattern:\n");
1358
1359				for (j = 0; j < fCFARepeatPatternRows; j++)
1360					{
1361
1362					int32 spaces = 4;
1363
1364					for (k = 0; k < fCFARepeatPatternCols; k++)
1365						{
1366
1367						while (spaces-- > 0)
1368							{
1369							printf (" ");
1370							}
1371
1372						const char *name = LookupCFAColor (fCFAPattern [j] [k]);
1373
1374						spaces = 9 - (int32) strlen (name);
1375
1376						printf ("%s", name);
1377
1378						}
1379
1380					printf ("\n");
1381
1382					}
1383
1384				}
1385
1386			#endif
1387
1388			break;
1389
1390			}
1391
1392		case tcCFAPlaneColor:
1393			{
1394
1395			CheckCFA (parentCode, tagCode, fPhotometricInterpretation);
1396
1397			if (!CheckTagType (parentCode, tagCode, tagType, ttByte))
1398				{
1399				return false;
1400				}
1401
1402			if (!CheckTagCount (parentCode, tagCode, tagCount, 3, kMaxColorPlanes))
1403				{
1404				return false;
1405				}
1406
1407			for (j = 0; j < kMaxColorPlanes; j++)
1408				{
1409
1410				if (j < tagCount)
1411					fCFAPlaneColor [j] = stream.Get_uint8 ();
1412
1413				else
1414					fCFAPlaneColor [j] = 255;
1415
1416				}
1417
1418			#if qDNGValidate
1419
1420			if (gVerbose)
1421				{
1422
1423				printf ("CFAPlaneColor:");
1424
1425				for (j = 0; j < tagCount; j++)
1426					{
1427
1428					printf (" %s", LookupCFAColor (fCFAPlaneColor [j]));
1429
1430					}
1431
1432				printf ("\n");
1433
1434				}
1435
1436			#endif
1437
1438			break;
1439
1440			}
1441
1442		case tcCFALayout:
1443			{
1444
1445			CheckCFA (parentCode, tagCode, fPhotometricInterpretation);
1446
1447			CheckTagType (parentCode, tagCode, tagType, ttShort);
1448
1449			CheckTagCount (parentCode, tagCode, tagCount, 1);
1450
1451			fCFALayout = stream.TagValue_uint32 (tagType);
1452
1453			#if qDNGValidate
1454
1455			if (gVerbose)
1456				{
1457
1458				printf ("CFALayout: %s\n",
1459						LookupCFALayout (fCFALayout));
1460
1461				}
1462
1463			#endif
1464
1465			break;
1466
1467			}
1468
1469		case tcLinearizationTable:
1470			{
1471
1472			CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation);
1473
1474			CheckTagType (parentCode, tagCode, tagType, ttShort);
1475
1476			fLinearizationTableType   = tagType;
1477			fLinearizationTableCount  = tagCount;
1478			fLinearizationTableOffset = tagOffset;
1479
1480			#if qDNGValidate
1481
1482			if (gVerbose)
1483				{
1484
1485				DumpTagValues (stream,
1486							   "Table",
1487							   parentCode,
1488							   tagCode,
1489							   tagType,
1490							   tagCount);
1491
1492				}
1493
1494			#endif
1495
1496			break;
1497
1498			}
1499
1500		case tcBlackLevelRepeatDim:
1501			{
1502
1503			CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation);
1504
1505			CheckTagType (parentCode, tagCode, tagType, ttShort);
1506
1507			if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
1508				{
1509				return false;
1510				}
1511
1512			fBlackLevelRepeatRows = stream.TagValue_uint32 (tagType);
1513			fBlackLevelRepeatCols = stream.TagValue_uint32 (tagType);
1514
1515			#if qDNGValidate
1516
1517			if (gVerbose)
1518				{
1519
1520				printf ("BlackLevelRepeatDim: Rows = %u, Cols = %u\n",
1521						(unsigned) fBlackLevelRepeatRows,
1522						(unsigned) fBlackLevelRepeatCols);
1523
1524				}
1525
1526			#endif
1527
1528			break;
1529
1530			}
1531
1532		case tcBlackLevel:
1533			{
1534
1535			CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation);
1536
1537			CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong, ttRational);
1538
1539			if (!CheckTagCount (parentCode, tagCode, tagCount, SafeUint32Mult(fBlackLevelRepeatRows,
1540															   fBlackLevelRepeatCols,
1541															   fSamplesPerPixel)))
1542				{
1543				return false;
1544				}
1545
1546			if (fBlackLevelRepeatRows < 1 || fBlackLevelRepeatRows > kMaxBlackPattern   ||
1547				fBlackLevelRepeatCols < 1 || fBlackLevelRepeatCols > kMaxBlackPattern   ||
1548				fSamplesPerPixel      < 1 || fSamplesPerPixel      > kMaxSamplesPerPixel)
1549				{
1550				return false;
1551				}
1552
1553			for (j = 0; j < fBlackLevelRepeatRows; j++)
1554				for (k = 0; k < fBlackLevelRepeatCols; k++)
1555					for (n = 0; n < fSamplesPerPixel; n++)
1556						{
1557
1558						fBlackLevel [j] [k] [n] = stream.TagValue_real64 (tagType);
1559
1560						}
1561
1562			#if qDNGValidate
1563
1564			if (gVerbose)
1565				{
1566
1567				printf ("BlackLevel:");
1568
1569				if (fBlackLevelRepeatRows == 1 &&
1570					fBlackLevelRepeatCols == 1)
1571					{
1572
1573					for (n = 0; n < fSamplesPerPixel; n++)
1574						{
1575						printf (" %0.2f", fBlackLevel [0] [0] [n]);
1576						}
1577
1578					printf ("\n");
1579
1580					}
1581
1582				else
1583					{
1584
1585					printf ("\n");
1586
1587					for (n = 0; n < fSamplesPerPixel; n++)
1588						{
1589
1590						if (fSamplesPerPixel > 1)
1591							{
1592							printf ("    Sample: %u\n", (unsigned) n);
1593							}
1594
1595						for (j = 0; j < fBlackLevelRepeatRows; j++)
1596							{
1597
1598							printf ("   ");
1599
1600							for (k = 0; k < fBlackLevelRepeatCols; k++)
1601								{
1602
1603								printf (" %8.2f", fBlackLevel [j] [k] [n]);
1604
1605								}
1606
1607							printf ("\n");
1608
1609							}
1610
1611						}
1612
1613					}
1614
1615				}
1616
1617			#endif
1618
1619			break;
1620
1621			}
1622
1623		case tcBlackLevelDeltaH:
1624			{
1625
1626			CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation);
1627
1628			CheckTagType (parentCode, tagCode, tagType, ttSRational);
1629
1630			fBlackLevelDeltaHType   = tagType;
1631			fBlackLevelDeltaHCount  = tagCount;
1632			fBlackLevelDeltaHOffset = tagOffset;
1633
1634			#if qDNGValidate
1635
1636			if (gVerbose)
1637				{
1638
1639				DumpTagValues (stream,
1640							   "Delta",
1641							   parentCode,
1642							   tagCode,
1643							   tagType,
1644							   tagCount);
1645
1646				}
1647
1648			#endif
1649
1650			break;
1651
1652			}
1653
1654		case tcBlackLevelDeltaV:
1655			{
1656
1657			CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation);
1658
1659			CheckTagType (parentCode, tagCode, tagType, ttSRational);
1660
1661			fBlackLevelDeltaVType   = tagType;
1662			fBlackLevelDeltaVCount  = tagCount;
1663			fBlackLevelDeltaVOffset = tagOffset;
1664
1665			#if qDNGValidate
1666
1667			if (gVerbose)
1668				{
1669
1670				DumpTagValues (stream,
1671							   "Delta",
1672							   parentCode,
1673							   tagCode,
1674							   tagType,
1675							   tagCount);
1676
1677				}
1678
1679			#endif
1680
1681			break;
1682
1683			}
1684
1685		case tcWhiteLevel:
1686			{
1687
1688			CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation);
1689
1690			CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
1691
1692			if (!CheckTagCount (parentCode, tagCode, tagCount, fSamplesPerPixel))
1693				return false;
1694
1695			for (j = 0; j < tagCount && j < kMaxSamplesPerPixel; j++)
1696				{
1697
1698				fWhiteLevel [j] = stream.TagValue_real64 (tagType);
1699
1700				}
1701
1702			#if qDNGValidate
1703
1704			if (gVerbose)
1705				{
1706
1707				printf ("WhiteLevel:");
1708
1709				for (j = 0; j < tagCount && j < kMaxSamplesPerPixel; j++)
1710					{
1711
1712					printf (" %0.0f", fWhiteLevel [j]);
1713
1714					}
1715
1716				printf ("\n");
1717
1718				}
1719
1720			#endif
1721
1722			break;
1723
1724			}
1725
1726		case tcDefaultScale:
1727			{
1728
1729			CheckMainIFD (parentCode, tagCode, fNewSubFileType);
1730
1731			CheckTagType (parentCode, tagCode, tagType, ttRational);
1732
1733			if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
1734				return false;
1735
1736			fDefaultScaleH = stream.TagValue_urational (tagType);
1737			fDefaultScaleV = stream.TagValue_urational (tagType);
1738
1739			#if qDNGValidate
1740
1741			if (gVerbose)
1742				{
1743
1744				printf ("DefaultScale: H = %0.4f V = %0.4f\n",
1745						fDefaultScaleH.As_real64 (),
1746						fDefaultScaleV.As_real64 ());
1747
1748				}
1749
1750			#endif
1751
1752			break;
1753
1754			}
1755
1756		case tcDefaultCropOrigin:
1757			{
1758
1759			CheckMainIFD (parentCode, tagCode, fNewSubFileType);
1760
1761			CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong, ttRational);
1762
1763			if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
1764				return false;
1765
1766			fDefaultCropOriginH = stream.TagValue_urational (tagType);
1767			fDefaultCropOriginV = stream.TagValue_urational (tagType);
1768
1769			#if qDNGValidate
1770
1771			if (gVerbose)
1772				{
1773
1774				printf ("DefaultCropOrigin: H = %0.2f V = %0.2f\n",
1775						fDefaultCropOriginH.As_real64 (),
1776						fDefaultCropOriginV.As_real64 ());
1777
1778				}
1779
1780			#endif
1781
1782			break;
1783
1784			}
1785
1786		case tcDefaultCropSize:
1787			{
1788
1789			CheckMainIFD (parentCode, tagCode, fNewSubFileType);
1790
1791			CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong, ttRational);
1792
1793			if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
1794				return false;
1795
1796			fDefaultCropSizeH = stream.TagValue_urational (tagType);
1797			fDefaultCropSizeV = stream.TagValue_urational (tagType);
1798
1799			#if qDNGValidate
1800
1801			if (gVerbose)
1802				{
1803
1804				printf ("DefaultCropSize: H = %0.2f V = %0.2f\n",
1805						fDefaultCropSizeH.As_real64 (),
1806						fDefaultCropSizeV.As_real64 ());
1807
1808				}
1809
1810			#endif
1811
1812			break;
1813
1814			}
1815
1816		case tcDefaultUserCrop:
1817			{
1818
1819			CheckMainIFD (parentCode, tagCode, fNewSubFileType);
1820
1821			CheckTagType (parentCode, tagCode, tagType, ttRational);
1822
1823			if (!CheckTagCount (parentCode, tagCode, tagCount, 4))
1824				return false;
1825
1826			fDefaultUserCropT = stream.TagValue_urational (tagType);
1827			fDefaultUserCropL = stream.TagValue_urational (tagType);
1828			fDefaultUserCropB = stream.TagValue_urational (tagType);
1829			fDefaultUserCropR = stream.TagValue_urational (tagType);
1830
1831			#if qDNGValidate
1832
1833			if (gVerbose)
1834				{
1835
1836				printf ("DefaultUserCrop: T = %0.2lf L = %0.2lf B = %0.2lf R = %0.2lf\n",
1837						(double) fDefaultUserCropT.As_real64 (),
1838						(double) fDefaultUserCropL.As_real64 (),
1839						(double) fDefaultUserCropB.As_real64 (),
1840						(double) fDefaultUserCropR.As_real64 ());
1841
1842
1843				}
1844
1845			#endif	// qDNGValidate
1846
1847			break;
1848
1849			}
1850
1851		case tcBayerGreenSplit:
1852			{
1853
1854			CheckCFA (parentCode, tagCode, fPhotometricInterpretation);
1855
1856			CheckTagType (parentCode, tagCode, tagType, ttLong);
1857
1858			CheckTagCount (parentCode, tagCode, tagCount, 1);
1859
1860			fBayerGreenSplit = stream.TagValue_uint32 (tagType);
1861
1862			#if qDNGValidate
1863
1864			if (gVerbose)
1865				{
1866				printf ("BayerGreenSplit: %u\n", (unsigned) fBayerGreenSplit);
1867				}
1868
1869			#endif
1870
1871			break;
1872
1873			}
1874
1875		case tcChromaBlurRadius:
1876			{
1877
1878			CheckMainIFD (parentCode, tagCode, fNewSubFileType);
1879
1880			CheckTagType (parentCode, tagCode, tagType, ttRational);
1881
1882			CheckTagCount (parentCode, tagCode, tagCount, 1);
1883
1884			fChromaBlurRadius = stream.TagValue_urational (tagType);
1885
1886			#if qDNGValidate
1887
1888			if (gVerbose)
1889				{
1890
1891				printf ("ChromaBlurRadius: %0.2f\n",
1892						fChromaBlurRadius.As_real64 ());
1893
1894				}
1895
1896			#endif
1897
1898			break;
1899
1900			}
1901
1902		case tcAntiAliasStrength:
1903			{
1904
1905			CheckMainIFD (parentCode, tagCode, fNewSubFileType);
1906
1907			CheckTagType (parentCode, tagCode, tagType, ttRational);
1908
1909			CheckTagCount (parentCode, tagCode, tagCount, 1);
1910
1911			fAntiAliasStrength = stream.TagValue_urational (tagType);
1912
1913			#if qDNGValidate
1914
1915			if (gVerbose)
1916				{
1917
1918				printf ("AntiAliasStrength: %0.2f\n",
1919						fAntiAliasStrength.As_real64 ());
1920
1921				}
1922
1923			#endif
1924
1925			break;
1926
1927			}
1928
1929		case tcBestQualityScale:
1930			{
1931
1932			CheckMainIFD (parentCode, tagCode, fNewSubFileType);
1933
1934			CheckTagType (parentCode, tagCode, tagType, ttRational);
1935
1936			CheckTagCount (parentCode, tagCode, tagCount, 1);
1937
1938			fBestQualityScale = stream.TagValue_urational (tagType);
1939
1940			#if qDNGValidate
1941
1942			if (gVerbose)
1943				{
1944
1945				printf ("BestQualityScale: %0.4f\n",
1946						fBestQualityScale.As_real64 ());
1947
1948				}
1949
1950			#endif
1951
1952			break;
1953
1954			}
1955
1956		case tcActiveArea:
1957			{
1958
1959			CheckMainIFD (parentCode, tagCode, fNewSubFileType);
1960
1961			CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
1962
1963			if (!CheckTagCount (parentCode, tagCode, tagCount, 4))
1964				return false;
1965
1966			fActiveArea.t = stream.TagValue_int32 (tagType);
1967			fActiveArea.l = stream.TagValue_int32 (tagType);
1968			fActiveArea.b = stream.TagValue_int32 (tagType);
1969			fActiveArea.r = stream.TagValue_int32 (tagType);
1970
1971			#if qDNGValidate
1972
1973			if (gVerbose)
1974				{
1975
1976				printf ("ActiveArea: T = %d L = %d B = %d R = %d\n",
1977						(int) fActiveArea.t,
1978						(int) fActiveArea.l,
1979						(int) fActiveArea.b,
1980						(int) fActiveArea.r);
1981
1982				}
1983
1984			#endif
1985
1986			break;
1987
1988			}
1989
1990		case tcMaskedAreas:
1991			{
1992
1993			CheckMainIFD (parentCode, tagCode, fNewSubFileType);
1994
1995			CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
1996
1997			uint32 rect_count = tagCount / 4;
1998
1999			if (!CheckTagCount (parentCode, tagCode, tagCount, rect_count * 4))
2000				return false;
2001
2002			fMaskedAreaCount = rect_count;
2003
2004			if (fMaskedAreaCount > kMaxMaskedAreas)
2005				fMaskedAreaCount = kMaxMaskedAreas;
2006
2007			for (j = 0; j < fMaskedAreaCount; j++)
2008				{
2009
2010				fMaskedArea [j].t = stream.TagValue_int32 (tagType);
2011				fMaskedArea [j].l = stream.TagValue_int32 (tagType);
2012				fMaskedArea [j].b = stream.TagValue_int32 (tagType);
2013				fMaskedArea [j].r = stream.TagValue_int32 (tagType);
2014
2015				}
2016
2017			#if qDNGValidate
2018
2019			if (gVerbose)
2020				{
2021
2022				printf ("MaskedAreas: %u\n", (unsigned) fMaskedAreaCount);
2023
2024				for (j = 0; j < fMaskedAreaCount; j++)
2025					{
2026
2027					printf ("    Area [%u]: T = %d L = %d B = %d R = %d\n",
2028							(unsigned) j,
2029							(int) fMaskedArea [j].t,
2030							(int) fMaskedArea [j].l,
2031							(int) fMaskedArea [j].b,
2032							(int) fMaskedArea [j].r);
2033
2034					}
2035
2036				}
2037
2038			#endif
2039
2040			break;
2041
2042			}
2043
2044		case tcPreviewApplicationName:
2045			{
2046
2047			CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
2048
2049			ParseStringTag (stream,
2050							parentCode,
2051							tagCode,
2052							tagCount,
2053							fPreviewInfo.fApplicationName,
2054							false);
2055
2056			#if qDNGValidate
2057
2058			if (gVerbose)
2059				{
2060
2061				printf ("PreviewApplicationName: ");
2062
2063				DumpString (fPreviewInfo.fApplicationName);
2064
2065				printf ("\n");
2066
2067				}
2068
2069			#endif
2070
2071			break;
2072
2073			}
2074
2075		case tcPreviewApplicationVersion:
2076			{
2077
2078			CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
2079
2080			ParseStringTag (stream,
2081							parentCode,
2082							tagCode,
2083							tagCount,
2084							fPreviewInfo.fApplicationVersion,
2085							false);
2086
2087			#if qDNGValidate
2088
2089			if (gVerbose)
2090				{
2091
2092				printf ("PreviewApplicationVersion: ");
2093
2094				DumpString (fPreviewInfo.fApplicationVersion);
2095
2096				printf ("\n");
2097
2098				}
2099
2100			#endif
2101
2102			break;
2103
2104			}
2105
2106		case tcPreviewSettingsName:
2107			{
2108
2109			CheckTagType (parentCode, tagCode, tagType, ttAscii, ttByte);
2110
2111			ParseStringTag (stream,
2112							parentCode,
2113							tagCode,
2114							tagCount,
2115							fPreviewInfo.fSettingsName,
2116							false);
2117
2118			#if qDNGValidate
2119
2120			if (gVerbose)
2121				{
2122
2123				printf ("PreviewSettingsName: ");
2124
2125				DumpString (fPreviewInfo.fSettingsName);
2126
2127				printf ("\n");
2128
2129				}
2130
2131			#endif
2132
2133			break;
2134
2135			}
2136
2137		case tcPreviewSettingsDigest:
2138			{
2139
2140			if (!CheckTagType (parentCode, tagCode, tagType, ttByte))
2141				return false;
2142
2143			if (!CheckTagCount (parentCode, tagCode, tagCount, 16))
2144				return false;
2145
2146			stream.Get (fPreviewInfo.fSettingsDigest.data, 16);
2147
2148			#if qDNGValidate
2149
2150			if (gVerbose)
2151				{
2152
2153				printf ("PreviewSettingsDigest: ");
2154
2155				DumpFingerprint (fPreviewInfo.fSettingsDigest);
2156
2157				printf ("\n");
2158
2159				}
2160
2161			#endif
2162
2163			break;
2164
2165			}
2166
2167		case tcPreviewColorSpace:
2168			{
2169
2170			CheckTagType (parentCode, tagCode, tagType, ttLong);
2171
2172			CheckTagCount (parentCode, tagCode, tagCount, 1);
2173
2174			fPreviewInfo.fColorSpace = (PreviewColorSpaceEnum)
2175									   stream.TagValue_uint32 (tagType);
2176
2177			#if qDNGValidate
2178
2179			if (gVerbose)
2180				{
2181
2182				printf ("PreviewColorSpace: %s\n",
2183						LookupPreviewColorSpace ((uint32) fPreviewInfo.fColorSpace));
2184
2185				}
2186
2187			#endif
2188
2189			break;
2190
2191			}
2192
2193		case tcPreviewDateTime:
2194			{
2195
2196			CheckTagType (parentCode, tagCode, tagType, ttAscii);
2197
2198			ParseStringTag (stream,
2199							parentCode,
2200							tagCode,
2201							tagCount,
2202							fPreviewInfo.fDateTime,
2203							false);
2204
2205			#if qDNGValidate
2206
2207			if (gVerbose)
2208				{
2209
2210				printf ("PreviewDateTime: ");
2211
2212				DumpString (fPreviewInfo.fDateTime);
2213
2214				printf ("\n");
2215
2216				}
2217
2218			#endif
2219
2220			break;
2221
2222			}
2223
2224		case tcRowInterleaveFactor:
2225			{
2226
2227			CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
2228
2229			if (!CheckTagCount (parentCode, tagCode, tagCount, 1))
2230				return false;
2231
2232			fRowInterleaveFactor = stream.TagValue_uint32 (tagType);
2233
2234			#if qDNGValidate
2235
2236			if (gVerbose)
2237				{
2238
2239				printf ("RowInterleaveFactor: %u\n",
2240						(unsigned) fRowInterleaveFactor);
2241
2242				}
2243
2244			#endif
2245
2246			break;
2247
2248			}
2249
2250		case tcSubTileBlockSize:
2251			{
2252
2253			CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
2254
2255			if (!CheckTagCount (parentCode, tagCode, tagCount, 2))
2256				return false;
2257
2258			fSubTileBlockRows = stream.TagValue_uint32 (tagType);
2259			fSubTileBlockCols = stream.TagValue_uint32 (tagType);
2260
2261			#if qDNGValidate
2262
2263			if (gVerbose)
2264				{
2265
2266				printf ("SubTileBlockSize: rows = %u, cols = %u\n",
2267						(unsigned) fSubTileBlockRows,
2268						(unsigned) fSubTileBlockCols);
2269
2270				}
2271
2272			#endif
2273
2274			break;
2275
2276			}
2277
2278		case tcOpcodeList1:
2279			{
2280
2281			CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation);
2282
2283			CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2284
2285			fOpcodeList1Count  = tagCount;
2286			fOpcodeList1Offset = tagOffset;
2287
2288			#if qDNGValidate
2289
2290			if (gVerbose)
2291				{
2292
2293				printf ("OpcodeList1: count = %u, offset = %u\n",
2294						(unsigned) fOpcodeList1Count,
2295						(unsigned) fOpcodeList1Offset);
2296
2297				}
2298
2299			#endif
2300
2301			break;
2302
2303			}
2304
2305		case tcOpcodeList2:
2306			{
2307
2308			CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation);
2309
2310			CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2311
2312			fOpcodeList2Count  = tagCount;
2313			fOpcodeList2Offset = tagOffset;
2314
2315			#if qDNGValidate
2316
2317			if (gVerbose)
2318				{
2319
2320				printf ("OpcodeList2: count = %u, offset = %u\n",
2321						(unsigned) fOpcodeList2Count,
2322						(unsigned) fOpcodeList2Offset);
2323
2324				}
2325
2326			#endif
2327
2328			break;
2329
2330			}
2331
2332		case tcOpcodeList3:
2333			{
2334
2335			CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation);
2336
2337			CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2338
2339			fOpcodeList3Count  = tagCount;
2340			fOpcodeList3Offset = tagOffset;
2341
2342			#if qDNGValidate
2343
2344			if (gVerbose)
2345				{
2346
2347				printf ("OpcodeList3: count = %u, offset = %u\n",
2348						(unsigned) fOpcodeList3Count,
2349						(unsigned) fOpcodeList3Offset);
2350
2351				}
2352
2353			#endif
2354
2355			break;
2356
2357			}
2358
2359		case tcRawToPreviewGain:
2360			{
2361
2362			#if qDNGValidate
2363
2364			if (fNewSubFileType != sfPreviewImage)
2365				{
2366
2367				char message [256];
2368
2369				sprintf (message,
2370						 "%s %s is not allowed IFDs with NewSubFileType != PreviewImage",
2371						 LookupParentCode (parentCode),
2372						 LookupTagCode (parentCode, tagCode));
2373
2374				ReportWarning (message);
2375
2376				}
2377
2378			#endif
2379
2380			CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation);
2381
2382			CheckTagType (parentCode, tagCode, tagType, ttDouble);
2383
2384			if (!CheckTagCount (parentCode, tagCode, tagCount, 1))
2385				return false;
2386
2387			fPreviewInfo.fRawToPreviewGain = stream.TagValue_real64 (tagType);
2388
2389			#if qDNGValidate
2390
2391			if (gVerbose)
2392				{
2393
2394				printf ("RawToPreviewGain = %f\n",
2395						fPreviewInfo.fRawToPreviewGain);
2396
2397				}
2398
2399			#endif
2400
2401			break;
2402
2403			}
2404
2405		case tcCacheVersion:
2406			{
2407
2408			#if qDNGValidate
2409
2410			if (fNewSubFileType != sfPreviewImage)
2411				{
2412
2413				char message [256];
2414
2415				sprintf (message,
2416						 "%s %s is not allowed IFDs with NewSubFileType != PreviewImage",
2417						 LookupParentCode (parentCode),
2418						 LookupTagCode (parentCode, tagCode));
2419
2420				ReportWarning (message);
2421
2422				}
2423
2424			#endif
2425
2426			CheckRawIFD (parentCode, tagCode, fPhotometricInterpretation);
2427
2428			CheckTagType (parentCode, tagCode, tagType, ttLong);
2429
2430			if (!CheckTagCount (parentCode, tagCode, tagCount, 1))
2431				return false;
2432
2433			fPreviewInfo.fCacheVersion = stream.TagValue_uint32 (tagType);
2434
2435			#if qDNGValidate
2436
2437			if (gVerbose)
2438				{
2439
2440				printf ("CacheVersion = 0x%x\n",
2441						(unsigned) fPreviewInfo.fCacheVersion);
2442
2443				}
2444
2445			#endif
2446
2447			break;
2448
2449			}
2450
2451		default:
2452			{
2453
2454			return false;
2455
2456			}
2457
2458		}
2459
2460	return true;
2461
2462	}
2463
2464/*****************************************************************************/
2465
2466void dng_ifd::PostParse ()
2467	{
2468
2469	uint32 j;
2470	uint32 k;
2471
2472	// There is only one PlanarConfiguration for single sample imaages.
2473
2474	if (fSamplesPerPixel == 1)
2475		{
2476		fPlanarConfiguration = pcInterleaved;
2477		}
2478
2479	// Default tile size.
2480
2481	if (fTileWidth == 0)
2482		{
2483		fTileWidth = fImageWidth;
2484		}
2485
2486	if (fTileLength == 0)
2487		{
2488		fTileLength = fImageLength;
2489		}
2490
2491	// Default ActiveArea.
2492
2493	dng_rect imageArea (0, 0, fImageLength, fImageWidth);
2494
2495	if (fActiveArea.IsZero ())
2496		{
2497		fActiveArea = imageArea;
2498		}
2499
2500	// Default crop size.
2501
2502	if (fDefaultCropSizeH.d == 0)
2503		{
2504		fDefaultCropSizeH = dng_urational (fActiveArea.W (), 1);
2505		}
2506
2507	if (fDefaultCropSizeV.d == 0)
2508		{
2509		fDefaultCropSizeV = dng_urational (fActiveArea.H (), 1);
2510		}
2511
2512	// Default white level.
2513
2514	uint32 defaultWhite = (fSampleFormat [0] == sfFloatingPoint) ?
2515						  1 :
2516						  (uint32) ((((uint64) 1) << fBitsPerSample [0]) - 1);
2517
2518	for (j = 0; j < kMaxSamplesPerPixel; j++)
2519		{
2520
2521		if (fWhiteLevel [j] < 0.0)
2522			{
2523			fWhiteLevel [j] = (real64) defaultWhite;
2524			}
2525
2526		}
2527
2528	// Check AntiAliasStrength.
2529
2530	if (fAntiAliasStrength.As_real64 () < 0.0 ||
2531		fAntiAliasStrength.As_real64 () > 1.0)
2532		{
2533
2534		#if qDNGValidate
2535
2536		ReportWarning ("Invalid AntiAliasStrength");
2537
2538		#endif
2539
2540		fAntiAliasStrength = dng_urational (1, 1);
2541
2542		}
2543
2544	// Check MaskedAreas.
2545
2546	for (j = 0; j < fMaskedAreaCount; j++)
2547		{
2548
2549		const dng_rect &r = fMaskedArea [j];
2550
2551		if (r.IsEmpty () || ((r & imageArea) != r))
2552			{
2553
2554			#if qDNGValidate
2555
2556			ReportWarning ("Invalid MaskedArea");
2557
2558			#endif
2559
2560			fMaskedAreaCount = 0;
2561
2562			break;
2563
2564			}
2565
2566		if ((r & fActiveArea).NotEmpty ())
2567			{
2568
2569			#if qDNGValidate
2570
2571			ReportWarning ("MaskedArea overlaps ActiveArea");
2572
2573			#endif
2574
2575			fMaskedAreaCount = 0;
2576
2577			break;
2578
2579			}
2580
2581		for (k = 0; k < j; k++)
2582			{
2583
2584			if ((r & fMaskedArea [k]).NotEmpty ())
2585				{
2586
2587				#if qDNGValidate
2588
2589				ReportWarning ("MaskedAreas overlap each other");
2590
2591				#endif
2592
2593				fMaskedAreaCount = 0;
2594
2595				break;
2596
2597				}
2598
2599			}
2600
2601		}
2602
2603	}
2604
2605/*****************************************************************************/
2606
2607bool dng_ifd::IsValidCFA (dng_shared &shared,
2608						  uint32 parentCode)
2609	{
2610
2611	uint32 j;
2612	uint32 k;
2613	uint32 n;
2614
2615	#if !qDNGValidate
2616
2617	(void) parentCode;			// Unused
2618
2619	#endif
2620
2621	if (fCFARepeatPatternRows < 1 || fCFARepeatPatternRows > kMaxCFAPattern ||
2622		fCFARepeatPatternCols < 1 || fCFARepeatPatternCols > kMaxCFAPattern)
2623		{
2624
2625		#if qDNGValidate
2626
2627		ReportError ("Missing or invalid CFAPatternRepeatDim",
2628					 LookupParentCode (parentCode));
2629
2630		#endif
2631
2632		return false;
2633
2634		}
2635
2636	uint32 count [kMaxColorPlanes];
2637
2638	for (n = 0; n < shared.fCameraProfile.fColorPlanes; n++)
2639		{
2640		count [n] = 0;
2641		}
2642
2643	for (j = 0; j < fCFARepeatPatternRows; j++)
2644		{
2645
2646		for (k = 0; k < fCFARepeatPatternCols; k++)
2647			{
2648
2649			bool found = false;
2650
2651			for (n = 0; n < shared.fCameraProfile.fColorPlanes; n++)
2652				{
2653
2654				if (fCFAPattern [j] [k] == fCFAPlaneColor [n])
2655					{
2656					found = true;
2657					count [n] ++;
2658					break;
2659					}
2660
2661				}
2662
2663			if (!found)
2664				{
2665
2666				#if qDNGValidate
2667
2668				ReportError ("CFAPattern contains colors not included in the CFAPlaneColor tag",
2669							 LookupParentCode (parentCode));
2670
2671				#endif
2672
2673				return false;
2674
2675				}
2676
2677			}
2678
2679		}
2680
2681	for (n = 0; n < shared.fCameraProfile.fColorPlanes; n++)
2682		{
2683
2684		if (count [n] == 0)
2685			{
2686
2687			#if qDNGValidate
2688
2689			ReportError ("CFAPattern does not contain all the colors in the CFAPlaneColor tag",
2690						 LookupParentCode (parentCode));
2691
2692			#endif
2693
2694			return false;
2695
2696			}
2697
2698		}
2699
2700	if (fCFALayout < 1 || fCFALayout > 9)
2701		{
2702
2703		#if qDNGValidate
2704
2705		ReportError ("Invalid CFALayout",
2706					 LookupParentCode (parentCode));
2707
2708		#endif
2709
2710		return false;
2711
2712		}
2713
2714	return true;
2715
2716	}
2717
2718/*****************************************************************************/
2719
2720bool dng_ifd::IsValidDNG (dng_shared &shared,
2721					      uint32 parentCode)
2722	{
2723
2724	uint32 j;
2725
2726	bool isFloatingPoint = (fSampleFormat [0] == sfFloatingPoint);
2727
2728	dng_rect imageArea (0, 0, fImageLength, fImageWidth);
2729
2730	uint32 defaultWhite = isFloatingPoint ?
2731						  1 :
2732						  (uint32) ((((uint64) 1) << fBitsPerSample [0]) - 1);
2733
2734	bool isMonochrome = (shared.fCameraProfile.fColorPlanes == 1);
2735	bool isColor      = !isMonochrome;
2736
2737	bool isMainIFD = (fNewSubFileType == sfMainImage);
2738
2739	// Check NewSubFileType.
2740
2741	if (!fUsesNewSubFileType)
2742		{
2743
2744		#if qDNGValidate
2745
2746		ReportError ("Missing NewSubFileType",
2747					 LookupParentCode (parentCode));
2748
2749		#endif
2750
2751		return false;
2752
2753		}
2754
2755	if (fNewSubFileType != sfMainImage		  &&
2756		fNewSubFileType != sfPreviewImage	  &&
2757		fNewSubFileType != sfTransparencyMask &&
2758		fNewSubFileType != sfPreviewMask      &&
2759		fNewSubFileType != sfAltPreviewImage)
2760		{
2761
2762		#if qDNGValidate
2763
2764		ReportError ("Unexpected NewSubFileType",
2765					 LookupParentCode (parentCode));
2766
2767		#endif
2768
2769		return false;
2770
2771		}
2772
2773	// Check ImageWidth and ImageLength.
2774
2775	if (fImageWidth < 1)
2776		{
2777
2778		#if qDNGValidate
2779
2780		ReportError ("Missing or invalid ImageWidth",
2781					 LookupParentCode (parentCode));
2782
2783		#endif
2784
2785		return false;
2786
2787		}
2788
2789	if (fImageLength < 1)
2790		{
2791
2792		#if qDNGValidate
2793
2794		ReportError ("Missing or invalid ImageLength",
2795					 LookupParentCode (parentCode));
2796
2797		#endif
2798
2799		return false;
2800
2801		}
2802
2803	if (fImageWidth  > kMaxImageSide ||
2804		fImageLength > kMaxImageSide)
2805		{
2806
2807		#if qDNGValidate
2808
2809		ReportWarning ("Image size is larger than supported");
2810
2811		#endif
2812
2813		return false;
2814
2815		}
2816
2817	// Check PhotometricInterpretation.
2818
2819	if (fNewSubFileType == sfTransparencyMask ||
2820		fNewSubFileType == sfPreviewMask)
2821		{
2822
2823		if (fPhotometricInterpretation != piTransparencyMask)
2824			{
2825
2826			#if qDNGValidate
2827
2828			ReportError ("NewSubFileType requires PhotometricInterpretation = TransparencyMask",
2829						 LookupParentCode (parentCode));
2830
2831			#endif
2832
2833			return false;
2834
2835			}
2836
2837		}
2838
2839	else
2840		{
2841
2842		switch (fPhotometricInterpretation)
2843			{
2844
2845			case piBlackIsZero:
2846			case piRGB:
2847			case piYCbCr:
2848				{
2849
2850				if (isMainIFD)
2851					{
2852
2853					#if qDNGValidate
2854
2855					ReportError ("PhotometricInterpretation requires NewSubFileType = 1",
2856								 LookupParentCode (parentCode));
2857
2858					#endif
2859
2860					return false;
2861
2862					}
2863
2864				break;
2865
2866				}
2867
2868			case piCFA:
2869				{
2870
2871				if (!isMainIFD)
2872					{
2873
2874					#if qDNGValidate
2875
2876					ReportError ("PhotometricInterpretation requires NewSubFileType = 0",
2877								 LookupParentCode (parentCode));
2878
2879					#endif
2880
2881					return false;
2882
2883					}
2884
2885				break;
2886
2887				}
2888
2889			case piLinearRaw:
2890				break;
2891
2892			default:
2893				{
2894
2895				#if qDNGValidate
2896
2897				ReportError ("Missing or invalid PhotometricInterpretation",
2898							 LookupParentCode (parentCode));
2899
2900				#endif
2901
2902				return false;
2903
2904				}
2905
2906			}
2907
2908		}
2909
2910	switch (fPhotometricInterpretation)
2911		{
2912
2913		case piBlackIsZero:
2914			{
2915
2916			// Allow black in white previews even in color images since the
2917			// raw processing software may be converting to grayscale.
2918
2919			if (isColor && isMainIFD)
2920				{
2921
2922				#if qDNGValidate
2923
2924				ReportError ("PhotometricInterpretation forbids use of ColorMatrix1 tag",
2925							 LookupParentCode (parentCode));
2926
2927				#endif
2928
2929				return false;
2930
2931				}
2932
2933			break;
2934
2935			}
2936
2937		case piRGB:
2938		case piYCbCr:
2939			{
2940
2941			// Allow color previews even in monochrome DNG files, since the
2942			// raw procesing software may be adding color effects.
2943
2944			break;
2945
2946			}
2947
2948		case piCFA:
2949			{
2950
2951			if (isMonochrome)
2952				{
2953
2954				#if qDNGValidate
2955
2956				ReportError ("PhotometricInterpretation requires use of ColorMatrix1 tag",
2957							 LookupParentCode (parentCode));
2958
2959				#endif
2960
2961				return false;
2962
2963				}
2964
2965			break;
2966
2967			}
2968
2969		}
2970
2971	if (isFloatingPoint)
2972		{
2973
2974		if (fPhotometricInterpretation != piCFA &&
2975			fPhotometricInterpretation != piLinearRaw &&
2976			fPhotometricInterpretation != piTransparencyMask)
2977			{
2978
2979			#if qDNGValidate
2980
2981			ReportError ("Floating point data requires PhotometricInterpretation CFA or LinearRaw or TransparencyMask",
2982						 LookupParentCode (parentCode));
2983
2984			#endif
2985
2986			return false;
2987
2988			}
2989
2990		}
2991
2992	// Check SamplesPerPixel and BitsPerSample.
2993
2994	uint32 minSamplesPerPixel = 1;
2995	uint32 maxSamplesPerPixel = 1;
2996
2997	uint32 minBitsPerSample = 8;
2998	uint32 maxBitsPerSample = 16;
2999
3000	switch (fPhotometricInterpretation)
3001		{
3002
3003		case piBlackIsZero:
3004			break;
3005
3006		case piRGB:
3007		case piYCbCr:
3008			{
3009			minSamplesPerPixel = 3;
3010			maxSamplesPerPixel = 3;
3011			break;
3012			}
3013
3014		case piCFA:
3015			{
3016			maxSamplesPerPixel = kMaxSamplesPerPixel;
3017			maxBitsPerSample   = 32;
3018			break;
3019			}
3020
3021		case piLinearRaw:
3022			{
3023			minSamplesPerPixel = shared.fCameraProfile.fColorPlanes;
3024			maxSamplesPerPixel = shared.fCameraProfile.fColorPlanes;
3025			maxBitsPerSample   = 32;
3026			break;
3027			}
3028
3029		case piTransparencyMask:
3030			{
3031			minBitsPerSample = 8;
3032			maxBitsPerSample = 16;
3033			break;
3034			}
3035
3036		}
3037
3038	if (isFloatingPoint)
3039		{
3040		minBitsPerSample = 16;
3041		maxBitsPerSample = 32;
3042		}
3043
3044	if (fSamplesPerPixel < minSamplesPerPixel ||
3045		fSamplesPerPixel > maxSamplesPerPixel)
3046		{
3047
3048		#if qDNGValidate
3049
3050		ReportError ("Missing or invalid SamplesPerPixel",
3051					 LookupParentCode (parentCode));
3052
3053		#endif
3054
3055		return false;
3056
3057		}
3058
3059	for (j = 0; j < kMaxSamplesPerPixel; j++)
3060		{
3061
3062		if (j < fSamplesPerPixel)
3063			{
3064
3065			if (fBitsPerSample [j] < minBitsPerSample ||
3066				fBitsPerSample [j] > maxBitsPerSample)
3067				{
3068
3069				#if qDNGValidate
3070
3071				ReportError ("Missing or invalid BitsPerSample",
3072							 LookupParentCode (parentCode));
3073
3074				#endif
3075
3076				return false;
3077
3078				}
3079
3080			if (isFloatingPoint &&
3081				fBitsPerSample [j] != 16 &&
3082				fBitsPerSample [j] != 24 &&
3083				fBitsPerSample [j] != 32)
3084				{
3085
3086				#if qDNGValidate
3087
3088				ReportError ("Invalid BitsPerSample for floating point",
3089							 LookupParentCode (parentCode));
3090
3091				#endif
3092
3093				return false;
3094
3095				}
3096
3097			if (minBitsPerSample   ==  8 &&
3098				maxBitsPerSample   == 16 &&
3099				fBitsPerSample [j] !=  8 &&
3100				fBitsPerSample [j] != 16)
3101				{
3102
3103				#if qDNGValidate
3104
3105				ReportError ("Rendered previews and integer masks require 8 or 16 bits per sample",
3106							 LookupParentCode (parentCode));
3107
3108				#endif
3109
3110				return false;
3111
3112				}
3113
3114			if (j > 0 && fBitsPerSample [j] != fBitsPerSample [0])
3115				{
3116
3117				#if qDNGValidate
3118
3119				ReportError ("BitsPerSample not equal for all samples",
3120							 LookupParentCode (parentCode));
3121
3122				#endif
3123
3124				return false;
3125
3126				}
3127
3128			}
3129
3130		else
3131			{
3132
3133			if (fBitsPerSample [j] != 0)
3134				{
3135
3136				#if qDNGValidate
3137
3138				ReportError ("Too many values specified in BitsPerSample",
3139							 LookupParentCode (parentCode));
3140
3141				#endif
3142
3143				return false;
3144
3145				}
3146
3147			}
3148
3149		}
3150
3151	// Check Compression.
3152
3153	switch (fCompression)
3154		{
3155
3156		case ccUncompressed:
3157			break;
3158
3159		case ccJPEG:
3160			{
3161
3162			if (fPhotometricInterpretation == piRGB)
3163				{
3164
3165				#if qDNGValidate
3166
3167				ReportError ("JPEG previews should use PhotometricInterpretation = YCbYb",
3168							 LookupParentCode (parentCode));
3169
3170				#endif
3171
3172				return false;
3173
3174				}
3175
3176			if (fBitsPerSample [0] > 16)
3177				{
3178
3179				#if qDNGValidate
3180
3181				ReportError ("JPEG compression is limited to 16 bits/sample",
3182							 LookupParentCode (parentCode));
3183
3184				#endif
3185
3186				return false;
3187
3188				}
3189
3190			break;
3191
3192			}
3193
3194		case ccLossyJPEG:
3195			{
3196
3197			if (fPhotometricInterpretation != piLinearRaw)
3198				{
3199
3200				#if qDNGValidate
3201
3202				ReportError ("Lossy JPEG compression code requires PhotometricInterpretation = LinearRaw",
3203							 LookupParentCode (parentCode));
3204
3205				#endif
3206
3207				return false;
3208
3209				}
3210
3211			if (fBitsPerSample [0] != 8)
3212				{
3213
3214				#if qDNGValidate
3215
3216				ReportError ("Lossy JPEG compression is limited to 8 bits/sample",
3217							 LookupParentCode (parentCode));
3218
3219				#endif
3220
3221				return false;
3222
3223				}
3224
3225			break;
3226
3227			}
3228
3229		case ccDeflate:
3230			{
3231
3232			if (!isFloatingPoint &&
3233				fBitsPerSample [0] != 32 &&
3234				fPhotometricInterpretation != piTransparencyMask)
3235				{
3236
3237				#if qDNGValidate
3238
3239				ReportError ("ZIP compression is limited to floating point and 32-bit integer and transparency masks",
3240							 LookupParentCode (parentCode));
3241
3242				#endif
3243
3244				}
3245
3246			break;
3247
3248			}
3249
3250		default:
3251			{
3252
3253			#if qDNGValidate
3254
3255			ReportError ("Unsupported Compression",
3256						 LookupParentCode (parentCode));
3257
3258			#endif
3259
3260			return false;
3261
3262			}
3263
3264		}
3265
3266	// Check Predictor.
3267
3268	if (isFloatingPoint && fCompression == ccDeflate &&
3269				(fPredictor == cpFloatingPoint   ||
3270				 fPredictor == cpFloatingPointX2 ||
3271				 fPredictor == cpFloatingPointX4))
3272		{
3273
3274		// These combinations are supported.
3275
3276		}
3277
3278	else if (!isFloatingPoint && fCompression == ccDeflate &&
3279				(fPredictor == cpHorizontalDifference   ||
3280				 fPredictor == cpHorizontalDifferenceX2 ||
3281				 fPredictor == cpHorizontalDifferenceX4))
3282		{
3283
3284		// These combinations are supported.
3285
3286		}
3287
3288	else if (fPredictor != cpNullPredictor)
3289		{
3290
3291		#if qDNGValidate
3292
3293		ReportError ("Unsupported Predictor",
3294					 LookupParentCode (parentCode));
3295
3296		#endif
3297
3298		return false;
3299
3300		}
3301
3302	// Check FillOrder.
3303
3304	if (fFillOrder != 1)
3305		{
3306
3307		#if qDNGValidate
3308
3309		ReportError ("Unsupported FillOrder",
3310					 LookupParentCode (parentCode));
3311
3312		#endif
3313
3314		return false;
3315
3316		}
3317
3318	// Check PlanarConfiguration.
3319
3320	if (fPlanarConfiguration != pcInterleaved)
3321		{
3322
3323		#if qDNGValidate
3324
3325		ReportError ("Unsupported PlanarConfiguration",
3326					 LookupParentCode (parentCode));
3327
3328		#endif
3329
3330		return false;
3331
3332		}
3333
3334	// Check ExtraSamples.
3335
3336	if (fExtraSamplesCount != 0)
3337		{
3338
3339		#if qDNGValidate
3340
3341		ReportError ("Unsupported ExtraSamples",
3342					 LookupParentCode (parentCode));
3343
3344		#endif
3345
3346		return false;
3347
3348		}
3349
3350	// Check SampleFormat.
3351
3352	for (j = 0; j < fSamplesPerPixel; j++)
3353		{
3354
3355		if (fSampleFormat [j] != (isFloatingPoint ? sfFloatingPoint : sfUnsignedInteger))
3356			{
3357
3358			#if qDNGValidate
3359
3360			ReportError ("Unsupported SampleFormat",
3361						 LookupParentCode (parentCode));
3362
3363			#endif
3364
3365			return false;
3366
3367			}
3368
3369		}
3370
3371	// Check Orientation.
3372
3373	if (fOrientation > 9)
3374		{
3375
3376		#if qDNGValidate
3377
3378		ReportError ("Unknown Orientation",
3379					 LookupParentCode (parentCode));
3380
3381		#endif
3382
3383		return false;
3384
3385		}
3386
3387	#if qDNGValidate
3388
3389	if (fOrientation != 0 && parentCode != 0)
3390		{
3391
3392		ReportWarning ("Unexpected Orientation tag",
3393					   LookupParentCode (parentCode));
3394
3395		}
3396
3397	if (fOrientation == 0 && parentCode == 0)
3398		{
3399
3400		ReportWarning ("Missing Orientation tag",
3401					   LookupParentCode (parentCode));
3402
3403		}
3404
3405	#endif
3406
3407	// Check Strips vs. Tiles.
3408
3409	if (!fUsesStrips && !fUsesTiles)
3410		{
3411
3412		#if qDNGValidate
3413
3414		ReportError ("IFD uses neither strips nor tiles",
3415					 LookupParentCode (parentCode));
3416
3417		#endif
3418
3419		return false;
3420
3421		}
3422
3423	if (fUsesStrips && fUsesTiles)
3424		{
3425
3426		#if qDNGValidate
3427
3428		ReportError ("IFD uses both strips and tiles",
3429					 LookupParentCode (parentCode));
3430
3431		#endif
3432
3433		return false;
3434
3435		}
3436
3437	// Check tile info.
3438
3439	uint32 tilesWide = SafeUint32DivideUp(fImageWidth, fTileWidth);
3440	uint32 tilesHigh = SafeUint32DivideUp(fImageLength, fTileLength);
3441
3442	uint32 tileCount = tilesWide * tilesHigh;
3443
3444	if (fTileOffsetsCount != tileCount)
3445		{
3446
3447		#if qDNGValidate
3448
3449		ReportError ("Missing or invalid Strip/TileOffsets",
3450					 LookupParentCode (parentCode));
3451
3452		#endif
3453
3454		return false;
3455
3456		}
3457
3458	if (fTileByteCountsCount != tileCount)
3459		{
3460
3461		#if qDNGValidate
3462
3463		ReportError ("Missing or invalid Strip/TileByteCounts",
3464					 LookupParentCode (parentCode));
3465
3466		#endif
3467
3468		return false;
3469
3470		}
3471
3472	// Check CFA pattern.
3473
3474	if (fPhotometricInterpretation == piCFA)
3475		{
3476
3477		if (!IsValidCFA (shared, parentCode))
3478			{
3479
3480			return false;
3481
3482			}
3483
3484		}
3485
3486	// Check ActiveArea.
3487
3488	if (((fActiveArea & imageArea) != fActiveArea) || fActiveArea.IsEmpty ())
3489		{
3490
3491		#if qDNGValidate
3492
3493		ReportError ("Invalid ActiveArea",
3494					 LookupParentCode (parentCode));
3495
3496		#endif
3497
3498		return false;
3499
3500		}
3501
3502	if (fActiveArea != imageArea)
3503		{
3504
3505		if (shared.fDNGBackwardVersion < dngVersion_1_1_0_0)
3506			{
3507
3508			#if qDNGValidate
3509
3510			ReportError ("Non-default ActiveArea tag not allowed in this DNG version",
3511						 LookupParentCode (parentCode));
3512
3513			#endif
3514
3515			return false;
3516
3517			}
3518
3519		}
3520
3521	// Check LinearizationTable.
3522
3523	if (fLinearizationTableCount)
3524		{
3525
3526		if (fLinearizationTableType != ttShort)
3527			{
3528
3529			#if qDNGValidate
3530
3531			ReportError ("Invalidate LinearizationTable type",
3532						 LookupParentCode (parentCode));
3533
3534			#endif
3535
3536			return false;
3537
3538			}
3539
3540		if (fLinearizationTableCount < 2 ||
3541			fLinearizationTableCount > 65536)
3542			{
3543
3544			#if qDNGValidate
3545
3546			ReportError ("Invalidate LinearizationTable count",
3547						 LookupParentCode (parentCode));
3548
3549			#endif
3550
3551			return false;
3552
3553			}
3554
3555		if (isFloatingPoint || fBitsPerSample [0] > 16)
3556			{
3557
3558			#if qDNGValidate
3559
3560			ReportError ("Linearization table not allowed for this data type",
3561						 LookupParentCode (parentCode));
3562
3563			#endif
3564
3565			return false;
3566
3567			}
3568
3569		}
3570
3571	// Check BlackLevelRepeatDim.
3572
3573	if (fBlackLevelRepeatRows < 1 || fBlackLevelRepeatRows > kMaxBlackPattern ||
3574		fBlackLevelRepeatCols < 1 || fBlackLevelRepeatCols > kMaxBlackPattern)
3575		{
3576
3577		#if qDNGValidate
3578
3579		ReportError ("Invalid BlackLevelRepeatDim",
3580					 LookupParentCode (parentCode));
3581
3582		#endif
3583
3584		return false;
3585
3586		}
3587
3588	// Check BlackLevelDeltaH.
3589
3590	if (fBlackLevelDeltaHCount != 0 &&
3591		fBlackLevelDeltaHCount != fActiveArea.W ())
3592		{
3593
3594		#if qDNGValidate
3595
3596		ReportError ("Invalid BlackLevelDeltaH count",
3597					 LookupParentCode (parentCode));
3598
3599		#endif
3600
3601		return false;
3602
3603		}
3604
3605	// Check BlackLevelDeltaV.
3606
3607	if (fBlackLevelDeltaVCount != 0 &&
3608		fBlackLevelDeltaVCount != fActiveArea.H ())
3609		{
3610
3611		#if qDNGValidate
3612
3613		ReportError ("Invalid BlackLevelDeltaV count",
3614					 LookupParentCode (parentCode));
3615
3616		#endif
3617
3618		return false;
3619
3620		}
3621
3622	// Check WhiteLevel.
3623
3624	real64 maxWhite = fLinearizationTableCount ? 65535.0
3625											   : (real64) defaultWhite;
3626
3627	for (j = 0; j < fSamplesPerPixel; j++)
3628		{
3629
3630		if (fWhiteLevel [j] < 1.0 || (fWhiteLevel [j] > maxWhite && !isFloatingPoint))
3631			{
3632
3633			#if qDNGValidate
3634
3635			ReportError ("Invalid WhiteLevel",
3636						 LookupParentCode (parentCode));
3637
3638			#endif
3639
3640			return false;
3641
3642			}
3643
3644		}
3645
3646	// Check BlackLevel.
3647
3648	for (j = 0; j < kMaxBlackPattern; j++)
3649		{
3650
3651		for (uint32 k = 0; k < kMaxBlackPattern; k++)
3652			{
3653
3654			for (uint32 s = 0; s < kMaxSamplesPerPixel; s++)
3655				{
3656
3657				const real64 black = fBlackLevel [j][k][s];
3658
3659				if (black >= fWhiteLevel [s])
3660					{
3661
3662					#if qDNGValidate
3663
3664					ReportError ("Invalid BlackLevel",
3665								 LookupParentCode (parentCode));
3666
3667					#endif
3668
3669					return false;
3670
3671					}
3672
3673				}
3674
3675			}
3676
3677		}
3678
3679	// Check DefaultScale.
3680
3681	if (fDefaultScaleH.As_real64 () <= 0.0 ||
3682		fDefaultScaleV.As_real64 () <= 0.0)
3683		{
3684
3685		#if qDNGValidate
3686
3687		ReportError ("Invalid DefaultScale");
3688
3689		#endif
3690
3691		return false;
3692
3693		}
3694
3695	// Check BestQualityScale.
3696
3697	if (fBestQualityScale.As_real64 () < 1.0)
3698		{
3699
3700		#if qDNGValidate
3701
3702		ReportError ("Invalid BestQualityScale");
3703
3704		#endif
3705
3706		return false;
3707
3708		}
3709
3710	// Check DefaultCropOrigin.
3711
3712	if (fDefaultCropOriginH.As_real64 () < 0.0 ||
3713		fDefaultCropOriginV.As_real64 () < 0.0 ||
3714		fDefaultCropOriginH.As_real64 () >= (real64) fActiveArea.W () ||
3715		fDefaultCropOriginV.As_real64 () >= (real64) fActiveArea.H ())
3716		{
3717
3718		#if qDNGValidate
3719
3720		ReportError ("Invalid DefaultCropOrigin");
3721
3722		#endif
3723
3724		return false;
3725
3726		}
3727
3728	// Check DefaultCropSize.
3729
3730	if (fDefaultCropSizeH.As_real64 () <= 0.0 					   ||
3731		fDefaultCropSizeV.As_real64 () <= 0.0 					   ||
3732		fDefaultCropSizeH.As_real64 () > (real64) fActiveArea.W () ||
3733		fDefaultCropSizeV.As_real64 () > (real64) fActiveArea.H ())
3734		{
3735
3736		#if qDNGValidate
3737
3738		ReportError ("Invalid DefaultCropSize");
3739
3740		#endif
3741
3742		return false;
3743
3744		}
3745
3746	// Check DefaultCrop area.
3747
3748	if (fDefaultCropOriginH.As_real64 () +
3749		fDefaultCropSizeH  .As_real64 () > (real64) fActiveArea.W () ||
3750		fDefaultCropOriginV.As_real64 () +
3751		fDefaultCropSizeV  .As_real64 () > (real64) fActiveArea.H ())
3752		{
3753
3754		#if qDNGValidate
3755
3756		ReportError ("Default crop extends outside ActiveArea");
3757
3758		#endif
3759
3760		return false;
3761
3762		}
3763
3764	// Check DefaultUserCrop.
3765
3766	if (fDefaultUserCropT.As_real64 () < 0.0 ||
3767		fDefaultUserCropL.As_real64 () < 0.0 ||
3768		fDefaultUserCropB.As_real64 () > 1.0 ||
3769		fDefaultUserCropR.As_real64 () > 1.0 ||
3770		fDefaultUserCropT.As_real64 () >= fDefaultUserCropB.As_real64 () ||
3771		fDefaultUserCropL.As_real64 () >= fDefaultUserCropR.As_real64 ())
3772		{
3773
3774		#if qDNGValidate
3775
3776		ReportError ("Invalid DefaultUserCrop");
3777
3778		#endif	// qDNGValidate
3779
3780		return false;
3781
3782		}
3783
3784	// The default crop and default user crop tags are not allowed for the
3785	// non-main image. If they are there, at least require that they be NOPs.
3786
3787	if (!isMainIFD)
3788		{
3789
3790		if (Round_int32 (fDefaultCropOriginH.As_real64 ()) != 0 ||
3791			Round_int32 (fDefaultCropOriginV.As_real64 ()) != 0)
3792			{
3793
3794			#if qDNGValidate
3795
3796			ReportError ("non-default DefaultCropOrigin on non-main image");
3797
3798			#endif
3799
3800			return false;
3801
3802			}
3803
3804		if (Round_int32 (fDefaultCropSizeH.As_real64 ()) != (int32) fImageWidth ||
3805			Round_int32 (fDefaultCropSizeV.As_real64 ()) != (int32) fImageLength)
3806			{
3807
3808			#if qDNGValidate
3809
3810			ReportError ("non-default DefaultCropSize on non-main image");
3811
3812			#endif
3813
3814			return false;
3815
3816			}
3817
3818		if (fDefaultUserCropT.As_real64 () != 0.0 ||
3819			fDefaultUserCropL.As_real64 () != 0.0 ||
3820			fDefaultUserCropB.As_real64 () != 1.0 ||
3821			fDefaultUserCropR.As_real64 () != 1.0)
3822			{
3823
3824			#if qDNGValidate
3825
3826			ReportError ("non-default DefaultCUserCrop on non-main image");
3827
3828			#endif	// qDNGValidate
3829
3830			return false;
3831
3832			}
3833
3834		}
3835
3836	// Warning if too little padding on CFA image.
3837
3838	#if qDNGValidate
3839
3840	if (fPhotometricInterpretation == piCFA)
3841		{
3842
3843		const real64 kMinPad = 1.9;
3844
3845		if (fDefaultCropOriginH.As_real64 () < kMinPad)
3846			{
3847
3848			ReportWarning ("Too little padding on left edge of CFA image",
3849						   "possible interpolation artifacts");
3850
3851			}
3852
3853		if (fDefaultCropOriginV.As_real64 () < kMinPad)
3854			{
3855
3856			ReportWarning ("Too little padding on top edge of CFA image",
3857						   "possible interpolation artifacts");
3858
3859			}
3860
3861		if (fDefaultCropOriginH.As_real64 () +
3862			fDefaultCropSizeH  .As_real64 () > (real64) fActiveArea.W () - kMinPad)
3863			{
3864
3865			ReportWarning ("Too little padding on right edge of CFA image",
3866						   "possible interpolation artifacts");
3867
3868			}
3869
3870		if (fDefaultCropOriginV.As_real64 () +
3871			fDefaultCropSizeV  .As_real64 () > (real64) fActiveArea.H () - kMinPad)
3872			{
3873
3874			ReportWarning ("Too little padding on bottom edge of CFA image",
3875						   "possible interpolation artifacts");
3876
3877			}
3878
3879		}
3880
3881	#endif
3882
3883	// Check RowInterleaveFactor
3884
3885	if (fRowInterleaveFactor != 1)
3886		{
3887
3888		if (fRowInterleaveFactor < 1 ||
3889			fRowInterleaveFactor > fImageLength)
3890			{
3891
3892			#if qDNGValidate
3893
3894			ReportError ("RowInterleaveFactor out of valid range",
3895						 LookupParentCode (parentCode));
3896
3897			#endif
3898
3899			return false;
3900
3901			}
3902
3903		if (shared.fDNGBackwardVersion < dngVersion_1_2_0_0)
3904			{
3905
3906			#if qDNGValidate
3907
3908			ReportError ("Non-default RowInterleaveFactor tag not allowed in this DNG version",
3909						 LookupParentCode (parentCode));
3910
3911			#endif
3912
3913			return false;
3914
3915			}
3916
3917		}
3918
3919	// Check SubTileBlockSize
3920
3921	if (fSubTileBlockRows != 1 || fSubTileBlockCols != 1)
3922		{
3923
3924		if (fSubTileBlockRows < 2 || fSubTileBlockRows > fTileLength ||
3925			fSubTileBlockCols < 1 || fSubTileBlockCols > fTileWidth)
3926			{
3927
3928			#if qDNGValidate
3929
3930			ReportError ("SubTileBlockSize out of valid range",
3931						 LookupParentCode (parentCode));
3932
3933			#endif
3934
3935			return false;
3936
3937			}
3938
3939		if ((fTileLength % fSubTileBlockRows) != 0 ||
3940			(fTileWidth  % fSubTileBlockCols) != 0)
3941			{
3942
3943			#if qDNGValidate
3944
3945			ReportError ("TileSize not exact multiple of SubTileBlockSize",
3946						 LookupParentCode (parentCode));
3947
3948			#endif
3949
3950			return false;
3951
3952			}
3953
3954		if (shared.fDNGBackwardVersion < dngVersion_1_2_0_0)
3955			{
3956
3957			#if qDNGValidate
3958
3959			ReportError ("Non-default SubTileBlockSize tag not allowed in this DNG version",
3960						 LookupParentCode (parentCode));
3961
3962			#endif
3963
3964			return false;
3965
3966			}
3967
3968		}
3969
3970	return true;
3971
3972	}
3973
3974/*****************************************************************************/
3975
3976uint32 dng_ifd::TilesAcross () const
3977	{
3978
3979	if (fTileWidth)
3980		{
3981
3982		return (SafeUint32Sub(SafeUint32Add(fImageWidth, fTileWidth), 1)) / fTileWidth;
3983
3984		}
3985
3986	return 0;
3987
3988	}
3989
3990/*****************************************************************************/
3991
3992uint32 dng_ifd::TilesDown () const
3993	{
3994
3995	if (fTileLength)
3996		{
3997
3998		return (SafeUint32Sub(SafeUint32Add(fImageLength, fTileLength), 1)) / fTileLength;
3999
4000		}
4001
4002	return 0;
4003
4004	}
4005
4006/*****************************************************************************/
4007
4008uint32 dng_ifd::TilesPerImage () const
4009	{
4010
4011	uint32 total = TilesAcross () * TilesDown ();
4012
4013	if (fPlanarConfiguration == pcPlanar)
4014		{
4015
4016		total *= fSamplesPerPixel;
4017
4018		}
4019
4020	return total;
4021
4022	}
4023
4024/*****************************************************************************/
4025
4026dng_rect dng_ifd::TileArea (uint32 rowIndex,
4027						    uint32 colIndex) const
4028	{
4029
4030	dng_rect r;
4031
4032	r.t = rowIndex * fTileLength;
4033	r.b = r.t      + fTileLength;
4034
4035	r.l = colIndex * fTileWidth;
4036	r.r = r.l      + fTileWidth;
4037
4038	// If this IFD is using strips rather than tiles, the last strip
4039	// is trimmed so it does not extend beyond the end of the image.
4040
4041	if (fUsesStrips)
4042		{
4043
4044		r.b = Min_uint32 (r.b, fImageLength);
4045
4046		}
4047
4048	return r;
4049
4050	}
4051
4052/*****************************************************************************/
4053
4054uint32 dng_ifd::TileByteCount (const dng_rect &tile) const
4055	{
4056
4057	if (fCompression == ccUncompressed)
4058		{
4059
4060		uint32 bitsPerRow = SafeUint32Mult(tile.W (), fBitsPerSample [0]);
4061
4062		if (fPlanarConfiguration == pcInterleaved)
4063			{
4064
4065			bitsPerRow = SafeUint32Mult(bitsPerRow, fSamplesPerPixel);
4066
4067			}
4068
4069		uint32 bytesPerRow = SafeUint32DivideUp(bitsPerRow, 8);
4070
4071		if (fPlanarConfiguration == pcRowInterleaved)
4072			{
4073
4074			bytesPerRow = SafeUint32Mult(bytesPerRow, fSamplesPerPixel);
4075
4076			}
4077
4078		return SafeUint32Mult(bytesPerRow, tile.H ());
4079
4080		}
4081
4082	return 0;
4083
4084	}
4085
4086/*****************************************************************************/
4087
4088void dng_ifd::SetSingleStrip ()
4089	{
4090
4091	fTileWidth  = fImageWidth;
4092	fTileLength = fImageLength;
4093
4094	fUsesTiles  = false;
4095	fUsesStrips = true;
4096
4097	}
4098
4099/*****************************************************************************/
4100
4101void dng_ifd::FindTileSize (uint32 bytesPerTile,
4102						    uint32 cellH,
4103						    uint32 cellV)
4104	{
4105
4106	uint32 bytesPerSample = fSamplesPerPixel *
4107							((fBitsPerSample [0] + 7) >> 3);
4108
4109	uint32 samplesPerTile = bytesPerTile / bytesPerSample;
4110
4111	uint32 tileSide = Round_uint32 (sqrt ((real64) samplesPerTile));
4112
4113	fTileWidth = Min_uint32 (fImageWidth, tileSide);
4114
4115	uint32 across = TilesAcross ();
4116
4117	fTileWidth = (fImageWidth + across - 1) / across;
4118
4119	fTileWidth = ((fTileWidth + cellH - 1) / cellH) * cellH;
4120
4121	fTileLength = Pin_uint32 (1,
4122						      samplesPerTile / fTileWidth,
4123						      fImageLength);
4124
4125	uint32 down = TilesDown ();
4126
4127	fTileLength = (fImageLength + down - 1) / down;
4128
4129	fTileLength = ((fTileLength + cellV - 1) / cellV) * cellV;
4130
4131	fUsesTiles  = true;
4132	fUsesStrips = false;
4133
4134	}
4135
4136/*****************************************************************************/
4137
4138void dng_ifd::FindStripSize (uint32 bytesPerStrip,
4139						     uint32 cellV)
4140	{
4141
4142	uint32 bytesPerSample = fSamplesPerPixel *
4143							((fBitsPerSample [0] + 7) >> 3);
4144
4145	uint32 samplesPerStrip = bytesPerStrip / bytesPerSample;
4146
4147	fTileWidth = fImageWidth;
4148
4149	fTileLength = Pin_uint32 (1,
4150						      samplesPerStrip / fTileWidth,
4151						      fImageLength);
4152
4153	uint32 down = TilesDown ();
4154
4155	fTileLength = (fImageLength + down - 1) / down;
4156
4157	fTileLength = ((fTileLength + cellV - 1) / cellV) * cellV;
4158
4159	fUsesTiles  = false;
4160	fUsesStrips = true;
4161
4162	}
4163
4164/*****************************************************************************/
4165
4166uint32 dng_ifd::PixelType () const
4167	{
4168
4169	if (fSampleFormat [0] == sfFloatingPoint)
4170		{
4171		return ttFloat;
4172		}
4173
4174	if (fBitsPerSample [0] <= 8)
4175		{
4176		return ttByte;
4177		}
4178
4179	else if (fBitsPerSample [0] <= 16)
4180		{
4181		return ttShort;
4182		}
4183
4184	return ttLong;
4185
4186	}
4187
4188/*****************************************************************************/
4189
4190bool dng_ifd::IsBaselineJPEG () const
4191	{
4192
4193	if (fBitsPerSample [0] != 8)
4194		{
4195		return false;
4196		}
4197
4198	if (fSampleFormat [0] != sfUnsignedInteger)
4199		{
4200		return false;
4201		}
4202
4203	if (fCompression == ccLossyJPEG)
4204		{
4205		return true;
4206		}
4207
4208	if (fCompression != ccJPEG)
4209		{
4210		return false;
4211		}
4212
4213	switch (fPhotometricInterpretation)
4214		{
4215
4216		case piBlackIsZero:
4217			{
4218			return (fSamplesPerPixel == 1);
4219			}
4220
4221		case piYCbCr:
4222			{
4223			return (fSamplesPerPixel     == 3            ) &&
4224				   (fPlanarConfiguration == pcInterleaved);
4225			}
4226
4227		default:
4228			break;
4229
4230		}
4231
4232	return false;
4233
4234	}
4235
4236/*****************************************************************************/
4237
4238bool dng_ifd::CanRead () const
4239	{
4240
4241	dng_read_image reader;
4242
4243	return reader.CanRead (*this);
4244
4245	}
4246
4247/*****************************************************************************/
4248
4249void dng_ifd::ReadImage (dng_host &host,
4250						 dng_stream &stream,
4251						 dng_image &image,
4252						 dng_jpeg_image *jpegImage,
4253						 dng_fingerprint *jpegDigest) const
4254	{
4255
4256	dng_read_image reader;
4257
4258	reader.Read (host,
4259				 *this,
4260				 stream,
4261				 image,
4262				 jpegImage,
4263				 jpegDigest);
4264
4265	}
4266
4267/*****************************************************************************/
4268