Home | History | Annotate | Download | only in source
      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 
     33 dng_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 
     51 dng_preview_info::~dng_preview_info ()
     52 	{
     53 
     54 	}
     55 
     56 /*****************************************************************************/
     57 
     58 dng_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 
    252 dng_ifd::~dng_ifd ()
    253 	{
    254 
    255 	}
    256 
    257 /*****************************************************************************/
    258 
    259 // Parses tags that should only appear in IFDs that contain images.
    260 
    261 bool 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 
   2466 void 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 
   2607 bool 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 
   2720 bool 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 
   3976 uint32 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 
   3992 uint32 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 
   4008 uint32 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 
   4026 dng_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 
   4054 uint32 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 
   4088 void dng_ifd::SetSingleStrip ()
   4089 	{
   4090 
   4091 	fTileWidth  = fImageWidth;
   4092 	fTileLength = fImageLength;
   4093 
   4094 	fUsesTiles  = false;
   4095 	fUsesStrips = true;
   4096 
   4097 	}
   4098 
   4099 /*****************************************************************************/
   4100 
   4101 void 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 
   4138 void 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 
   4166 uint32 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 
   4190 bool 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 
   4238 bool dng_ifd::CanRead () const
   4239 	{
   4240 
   4241 	dng_read_image reader;
   4242 
   4243 	return reader.CanRead (*this);
   4244 
   4245 	}
   4246 
   4247 /*****************************************************************************/
   4248 
   4249 void 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