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_image_writer.cpp#4 $ */
     10 /* $DateTime: 2012/06/14 20:24:41 $ */
     11 /* $Change: 835078 $ */
     12 /* $Author: tknoll $ */
     13 
     14 /*****************************************************************************/
     15 
     16 #include "dng_image_writer.h"
     17 
     18 #include "dng_abort_sniffer.h"
     19 #include "dng_area_task.h"
     20 #include "dng_bottlenecks.h"
     21 #include "dng_camera_profile.h"
     22 #include "dng_color_space.h"
     23 #include "dng_exif.h"
     24 #include "dng_flags.h"
     25 #include "dng_exceptions.h"
     26 #include "dng_host.h"
     27 #include "dng_ifd.h"
     28 #include "dng_image.h"
     29 #include "dng_jpeg_image.h"
     30 #include "dng_lossless_jpeg.h"
     31 #include "dng_memory.h"
     32 #include "dng_memory_stream.h"
     33 #include "dng_negative.h"
     34 #include "dng_pixel_buffer.h"
     35 #include "dng_preview.h"
     36 #include "dng_read_image.h"
     37 #include "dng_safe_arithmetic.h"
     38 #include "dng_stream.h"
     39 #include "dng_string_list.h"
     40 #include "dng_tag_codes.h"
     41 #include "dng_tag_values.h"
     42 #include "dng_utils.h"
     43 
     44 #if qDNGUseXMP
     45 #include "dng_xmp.h"
     46 #endif
     47 
     48 #include "zlib.h"
     49 
     50 #if qDNGUseLibJPEG
     51 #include "dng_jpeglib.h"
     52 #endif
     53 
     54 /*****************************************************************************/
     55 
     56 // Defines for testing DNG 1.2 features.
     57 
     58 //#define qTestRowInterleave 2
     59 
     60 //#define qTestSubTileBlockRows 2
     61 //#define qTestSubTileBlockCols 2
     62 
     63 /*****************************************************************************/
     64 
     65 dng_resolution::dng_resolution ()
     66 
     67 	:	fXResolution ()
     68 	,	fYResolution ()
     69 
     70 	,	fResolutionUnit (0)
     71 
     72 	{
     73 
     74 	}
     75 
     76 /******************************************************************************/
     77 
     78 static void SpoolAdobeData (dng_stream &stream,
     79 							const dng_metadata *metadata,
     80 							const dng_jpeg_preview *preview,
     81 							const dng_memory_block *imageResources)
     82 	{
     83 
     84 	TempBigEndian tempEndian (stream);
     85 
     86 	#if qDNGUseXMP
     87 
     88 	if (metadata && metadata->GetXMP ())
     89 		{
     90 
     91 		bool marked = false;
     92 
     93 		if (metadata->GetXMP ()->GetBoolean (XMP_NS_XAP_RIGHTS,
     94 											 "Marked",
     95 											 marked))
     96 			{
     97 
     98 			stream.Put_uint32 (DNG_CHAR4 ('8','B','I','M'));
     99 			stream.Put_uint16 (1034);
    100 			stream.Put_uint16 (0);
    101 
    102 			stream.Put_uint32 (1);
    103 
    104 			stream.Put_uint8 (marked ? 1 : 0);
    105 
    106 			stream.Put_uint8 (0);
    107 
    108 			}
    109 
    110 		dng_string webStatement;
    111 
    112 		if (metadata->GetXMP ()->GetString (XMP_NS_XAP_RIGHTS,
    113 											"WebStatement",
    114 											webStatement))
    115 			{
    116 
    117 			dng_memory_data buffer;
    118 
    119 			uint32 size = webStatement.Get_SystemEncoding (buffer);
    120 
    121 			if (size > 0)
    122 				{
    123 
    124 				stream.Put_uint32 (DNG_CHAR4 ('8','B','I','M'));
    125 				stream.Put_uint16 (1035);
    126 				stream.Put_uint16 (0);
    127 
    128 				stream.Put_uint32 (size);
    129 
    130 				stream.Put (buffer.Buffer (), size);
    131 
    132 				if (size & 1)
    133 					stream.Put_uint8 (0);
    134 
    135 				}
    136 
    137 			}
    138 
    139 		}
    140 
    141 	#endif
    142 
    143 	if (preview)
    144 		{
    145 
    146 		preview->SpoolAdobeThumbnail (stream);
    147 
    148 		}
    149 
    150 	if (metadata && metadata->IPTCLength ())
    151 		{
    152 
    153 		dng_fingerprint iptcDigest = metadata->IPTCDigest ();
    154 
    155 		if (iptcDigest.IsValid ())
    156 			{
    157 
    158 			stream.Put_uint32 (DNG_CHAR4 ('8','B','I','M'));
    159 			stream.Put_uint16 (1061);
    160 			stream.Put_uint16 (0);
    161 
    162 			stream.Put_uint32 (16);
    163 
    164 			stream.Put (iptcDigest.data, 16);
    165 
    166 			}
    167 
    168 		}
    169 
    170 	if (imageResources)
    171 		{
    172 
    173 		uint32 size = imageResources->LogicalSize ();
    174 
    175 		stream.Put (imageResources->Buffer (), size);
    176 
    177 		if (size & 1)
    178 			stream.Put_uint8 (0);
    179 
    180 		}
    181 
    182 	}
    183 
    184 /******************************************************************************/
    185 
    186 static dng_memory_block * BuildAdobeData (dng_host &host,
    187 										  const dng_metadata *metadata,
    188 										  const dng_jpeg_preview *preview,
    189 										  const dng_memory_block *imageResources)
    190 	{
    191 
    192 	dng_memory_stream stream (host.Allocator ());
    193 
    194 	SpoolAdobeData (stream,
    195 					metadata,
    196 					preview,
    197 					imageResources);
    198 
    199 	return stream.AsMemoryBlock (host.Allocator ());
    200 
    201 	}
    202 
    203 /*****************************************************************************/
    204 
    205 tag_string::tag_string (uint16 code,
    206 				    	const dng_string &s,
    207 				    	bool forceASCII)
    208 
    209 	:	tiff_tag (code, ttAscii, 0)
    210 
    211 	,	fString (s)
    212 
    213 	{
    214 
    215 	if (forceASCII)
    216 		{
    217 
    218 		// Metadata working group recommendation - go ahead
    219 		// write UTF-8 into ASCII tag strings, rather than
    220 		// actually force the strings to ASCII.  There is a matching
    221 		// change on the reading side to assume UTF-8 if the string
    222 		// contains a valid UTF-8 string.
    223 		//
    224 		// fString.ForceASCII ();
    225 
    226 		}
    227 
    228 	else if (!fString.IsASCII ())
    229 		{
    230 
    231 		fType = ttByte;
    232 
    233 		}
    234 
    235 	fCount = fString.Length () + 1;
    236 
    237 	}
    238 
    239 /*****************************************************************************/
    240 
    241 void tag_string::Put (dng_stream &stream) const
    242 	{
    243 
    244 	stream.Put (fString.Get (), Size ());
    245 
    246 	}
    247 
    248 /*****************************************************************************/
    249 
    250 tag_encoded_text::tag_encoded_text (uint16 code,
    251 									const dng_string &text)
    252 
    253 	:	tiff_tag (code, ttUndefined, 0)
    254 
    255 	,	fText (text)
    256 
    257 	,	fUTF16 ()
    258 
    259 	{
    260 
    261 	if (fText.IsASCII ())
    262 		{
    263 
    264 		fCount = 8 + fText.Length ();
    265 
    266 		}
    267 
    268 	else
    269 		{
    270 
    271 		fCount = 8 + fText.Get_UTF16 (fUTF16) * 2;
    272 
    273 		}
    274 
    275 	}
    276 
    277 /*****************************************************************************/
    278 
    279 void tag_encoded_text::Put (dng_stream &stream) const
    280 	{
    281 
    282 	if (fUTF16.Buffer ())
    283 		{
    284 
    285 		stream.Put ("UNICODE\000", 8);
    286 
    287 		uint32 chars = (fCount - 8) >> 1;
    288 
    289 		const uint16 *buf = fUTF16.Buffer_uint16 ();
    290 
    291 		for (uint32 j = 0; j < chars; j++)
    292 			{
    293 
    294 			stream.Put_uint16 (buf [j]);
    295 
    296 			}
    297 
    298 		}
    299 
    300 	else
    301 		{
    302 
    303 		stream.Put ("ASCII\000\000\000", 8);
    304 
    305 		stream.Put (fText.Get (), fCount - 8);
    306 
    307 		}
    308 
    309 	}
    310 
    311 /*****************************************************************************/
    312 
    313 void tag_data_ptr::Put (dng_stream &stream) const
    314 	{
    315 
    316 	// If we are swapping bytes, we need to swap with the right size
    317 	// entries.
    318 
    319 	if (stream.SwapBytes ())
    320 		{
    321 
    322 		switch (Type ())
    323 			{
    324 
    325 			// Two byte entries.
    326 
    327 			case ttShort:
    328 			case ttSShort:
    329 			case ttUnicode:
    330 				{
    331 
    332 				const uint16 *p = (const uint16 *) fData;
    333 
    334 				uint32 entries = (Size () >> 1);
    335 
    336 				for (uint32 j = 0; j < entries; j++)
    337 					{
    338 
    339 					stream.Put_uint16 (p [j]);
    340 
    341 					}
    342 
    343 				return;
    344 
    345 				}
    346 
    347 			// Four byte entries.
    348 
    349 			case ttLong:
    350 			case ttSLong:
    351 			case ttRational:
    352 			case ttSRational:
    353 			case ttIFD:
    354 			case ttFloat:
    355 			case ttComplex:
    356 				{
    357 
    358 				const uint32 *p = (const uint32 *) fData;
    359 
    360 				uint32 entries = (Size () >> 2);
    361 
    362 				for (uint32 j = 0; j < entries; j++)
    363 					{
    364 
    365 					stream.Put_uint32 (p [j]);
    366 
    367 					}
    368 
    369 				return;
    370 
    371 				}
    372 
    373 			// Eight byte entries.
    374 
    375 			case ttDouble:
    376 				{
    377 
    378 				const real64 *p = (const real64 *) fData;
    379 
    380 				uint32 entries = (Size () >> 3);
    381 
    382 				for (uint32 j = 0; j < entries; j++)
    383 					{
    384 
    385 					stream.Put_real64 (p [j]);
    386 
    387 					}
    388 
    389 				return;
    390 
    391 				}
    392 
    393 			// Entries don't need to be byte swapped.  Fall through
    394 			// to non-byte swapped case.
    395 
    396 			default:
    397 				{
    398 
    399 				break;
    400 
    401 				}
    402 
    403 			}
    404 
    405 		}
    406 
    407 	// Non-byte swapped case.
    408 
    409 	stream.Put (fData, Size ());
    410 
    411 	}
    412 
    413 /******************************************************************************/
    414 
    415 tag_matrix::tag_matrix (uint16 code,
    416 		    			const dng_matrix &m)
    417 
    418 	:	tag_srational_ptr (code, fEntry, m.Rows () * m.Cols ())
    419 
    420 	{
    421 
    422 	uint32 index = 0;
    423 
    424 	for (uint32 r = 0; r < m.Rows (); r++)
    425 		for (uint32 c = 0; c < m.Cols (); c++)
    426 			{
    427 
    428 			fEntry [index].Set_real64 (m [r] [c], 10000);
    429 
    430 			index++;
    431 
    432 			}
    433 
    434 	}
    435 
    436 /******************************************************************************/
    437 
    438 tag_icc_profile::tag_icc_profile (const void *profileData,
    439 								  uint32 profileSize)
    440 
    441 	:	tag_data_ptr (tcICCProfile,
    442 					  ttUndefined,
    443 					  0,
    444 					  NULL)
    445 
    446 	{
    447 
    448 	if (profileData && profileSize)
    449 		{
    450 
    451 		SetCount (profileSize);
    452 		SetData  (profileData);
    453 
    454 		}
    455 
    456 	}
    457 
    458 /******************************************************************************/
    459 
    460 void tag_cfa_pattern::Put (dng_stream &stream) const
    461 	{
    462 
    463 	stream.Put_uint16 ((uint16) fCols);
    464 	stream.Put_uint16 ((uint16) fRows);
    465 
    466 	for (uint32 col = 0; col < fCols; col++)
    467 		for (uint32 row = 0; row < fRows; row++)
    468 			{
    469 
    470 			stream.Put_uint8 (fPattern [row * kMaxCFAPattern + col]);
    471 
    472 			}
    473 
    474 	}
    475 
    476 /******************************************************************************/
    477 
    478 tag_exif_date_time::tag_exif_date_time (uint16 code,
    479 		            					const dng_date_time &dt)
    480 
    481 	:	tag_data_ptr (code, ttAscii, 20, fData)
    482 
    483 	{
    484 
    485 	if (dt.IsValid ())
    486 		{
    487 
    488 		sprintf (fData,
    489 				 "%04d:%02d:%02d %02d:%02d:%02d",
    490 				 (int) dt.fYear,
    491 				 (int) dt.fMonth,
    492 				 (int) dt.fDay,
    493 				 (int) dt.fHour,
    494 				 (int) dt.fMinute,
    495 				 (int) dt.fSecond);
    496 
    497 		}
    498 
    499 	}
    500 
    501 /******************************************************************************/
    502 
    503 tag_iptc::tag_iptc (const void *data,
    504 		  			uint32 length)
    505 
    506 	:	tiff_tag (tcIPTC_NAA, ttLong, (length + 3) >> 2)
    507 
    508 	,	fData   (data  )
    509 	,	fLength (length)
    510 
    511 	{
    512 
    513 	}
    514 
    515 /******************************************************************************/
    516 
    517 void tag_iptc::Put (dng_stream &stream) const
    518 	{
    519 
    520 	// Note: For historical compatiblity reasons, the standard TIFF data
    521 	// type for IPTC data is ttLong, but without byte swapping.  This really
    522 	// should be ttUndefined, but doing the right thing would break some
    523 	// existing readers.
    524 
    525 	stream.Put (fData, fLength);
    526 
    527 	// Pad with zeros to get to long word boundary.
    528 
    529 	uint32 extra = fCount * 4 - fLength;
    530 
    531 	while (extra--)
    532 		{
    533 		stream.Put_uint8 (0);
    534 		}
    535 
    536 	}
    537 
    538 /******************************************************************************/
    539 
    540 tag_xmp::tag_xmp (const dng_xmp *xmp)
    541 
    542 	:	tag_uint8_ptr (tcXMP, NULL, 0)
    543 
    544 	,	fBuffer ()
    545 
    546 	{
    547 
    548 	#if qDNGUseXMP
    549 
    550 	if (xmp)
    551 		{
    552 
    553 		fBuffer.Reset (xmp->Serialize (true));
    554 
    555 		if (fBuffer.Get ())
    556 			{
    557 
    558 			SetData (fBuffer->Buffer_uint8 ());
    559 
    560 			SetCount (fBuffer->LogicalSize ());
    561 
    562 			}
    563 
    564 		}
    565 
    566 	#endif
    567 
    568 	}
    569 
    570 /******************************************************************************/
    571 
    572 void dng_tiff_directory::Add (const tiff_tag *tag)
    573 	{
    574 
    575 	if (fEntries >= kMaxEntries)
    576 		{
    577 		ThrowProgramError ();
    578 		}
    579 
    580 	// Tags must be sorted in increasing order of tag code.
    581 
    582 	uint32 index = fEntries;
    583 
    584 	for (uint32 j = 0; j < fEntries; j++)
    585 		{
    586 
    587 		if (tag->Code () < fTag [j]->Code ())
    588 			{
    589 			index = j;
    590 			break;
    591 			}
    592 
    593 		}
    594 
    595 	for (uint32 k = fEntries; k > index; k--)
    596 		{
    597 
    598 		fTag [k] = fTag [k - 1];
    599 
    600 		}
    601 
    602 	fTag [index] = tag;
    603 
    604 	fEntries++;
    605 
    606 	}
    607 
    608 /******************************************************************************/
    609 
    610 uint32 dng_tiff_directory::Size () const
    611 	{
    612 
    613 	if (!fEntries) return 0;
    614 
    615 	uint32 size = fEntries * 12 + 6;
    616 
    617 	for (uint32 index = 0; index < fEntries; index++)
    618 		{
    619 
    620 		uint32 tagSize = fTag [index]->Size ();
    621 
    622 		if (tagSize > 4)
    623 			{
    624 
    625 			size += (tagSize + 1) & ~1;
    626 
    627 			}
    628 
    629 		}
    630 
    631 	return size;
    632 
    633 	}
    634 
    635 /******************************************************************************/
    636 
    637 void dng_tiff_directory::Put (dng_stream &stream,
    638 						      OffsetsBase offsetsBase,
    639 						      uint32 explicitBase) const
    640 	{
    641 
    642 	if (!fEntries) return;
    643 
    644 	uint32 index;
    645 
    646 	uint32 bigData = fEntries * 12 + 6;
    647 
    648 	if (offsetsBase == offsetsRelativeToStream)
    649 		bigData += (uint32) stream.Position ();
    650 
    651 	else if (offsetsBase == offsetsRelativeToExplicitBase)
    652 		bigData += explicitBase;
    653 
    654 	stream.Put_uint16 ((uint16) fEntries);
    655 
    656 	for (index = 0; index < fEntries; index++)
    657 		{
    658 
    659 		const tiff_tag &tag = *fTag [index];
    660 
    661 		stream.Put_uint16 (tag.Code  ());
    662 		stream.Put_uint16 (tag.Type  ());
    663 		stream.Put_uint32 (tag.Count ());
    664 
    665 		uint32 size = tag.Size ();
    666 
    667 		if (size <= 4)
    668 			{
    669 
    670 			tag.Put (stream);
    671 
    672 			while (size < 4)
    673 				{
    674 				stream.Put_uint8 (0);
    675 				size++;
    676 				}
    677 
    678 			}
    679 
    680 		else
    681 			{
    682 
    683 			stream.Put_uint32 (bigData);
    684 
    685 			bigData += (size + 1) & ~1;
    686 
    687 			}
    688 
    689 		}
    690 
    691 	stream.Put_uint32 (fChained);		// Next IFD offset
    692 
    693 	for (index = 0; index < fEntries; index++)
    694 		{
    695 
    696 		const tiff_tag &tag = *fTag [index];
    697 
    698 		uint32 size = tag.Size ();
    699 
    700 		if (size > 4)
    701 			{
    702 
    703 			tag.Put (stream);
    704 
    705 			if (size & 1)
    706 				stream.Put_uint8 (0);
    707 
    708 			}
    709 
    710 		}
    711 
    712 	}
    713 
    714 /******************************************************************************/
    715 
    716 dng_basic_tag_set::dng_basic_tag_set (dng_tiff_directory &directory,
    717 									  const dng_ifd &info)
    718 
    719 	:	fNewSubFileType (tcNewSubFileType, info.fNewSubFileType)
    720 
    721 	,	fImageWidth  (tcImageWidth , info.fImageWidth )
    722 	,	fImageLength (tcImageLength, info.fImageLength)
    723 
    724 	,	fPhotoInterpretation (tcPhotometricInterpretation,
    725 							  (uint16) info.fPhotometricInterpretation)
    726 
    727 	,	fFillOrder (tcFillOrder, 1)
    728 
    729 	,	fSamplesPerPixel (tcSamplesPerPixel, (uint16) info.fSamplesPerPixel)
    730 
    731 	,	fBitsPerSample (tcBitsPerSample,
    732 						fBitsPerSampleData,
    733 						info.fSamplesPerPixel)
    734 
    735 	,	fStrips (info.fUsesStrips)
    736 
    737 	,	fTileWidth (tcTileWidth, info.fTileWidth)
    738 
    739 	,	fTileLength (fStrips ? tcRowsPerStrip : tcTileLength,
    740 					 info.fTileLength)
    741 
    742 	,	fTileInfoBuffer (info.TilesPerImage (), 8)
    743 
    744 	,	fTileOffsetData (fTileInfoBuffer.Buffer_uint32 ())
    745 
    746 	,	fTileOffsets (fStrips ? tcStripOffsets : tcTileOffsets,
    747 					  fTileOffsetData,
    748 					  info.TilesPerImage ())
    749 
    750 	,	fTileByteCountData (fTileOffsetData + info.TilesPerImage ())
    751 
    752 	,	fTileByteCounts (fStrips ? tcStripByteCounts : tcTileByteCounts,
    753 						 fTileByteCountData,
    754 						 info.TilesPerImage ())
    755 
    756 	,	fPlanarConfiguration (tcPlanarConfiguration, pcInterleaved)
    757 
    758 	,	fCompression (tcCompression, (uint16) info.fCompression)
    759 	,	fPredictor   (tcPredictor  , (uint16) info.fPredictor  )
    760 
    761 	,	fExtraSamples (tcExtraSamples,
    762 					   fExtraSamplesData,
    763 					   info.fExtraSamplesCount)
    764 
    765 	,	fSampleFormat (tcSampleFormat,
    766 					   fSampleFormatData,
    767 					   info.fSamplesPerPixel)
    768 
    769 	,	fRowInterleaveFactor (tcRowInterleaveFactor,
    770 							  (uint16) info.fRowInterleaveFactor)
    771 
    772 	,	fSubTileBlockSize (tcSubTileBlockSize,
    773 						   fSubTileBlockSizeData,
    774 						   2)
    775 
    776 	{
    777 
    778 	uint32 j;
    779 
    780 	for (j = 0; j < info.fSamplesPerPixel; j++)
    781 		{
    782 
    783 		fBitsPerSampleData [j] = (uint16) info.fBitsPerSample [0];
    784 
    785 		}
    786 
    787 	directory.Add (&fNewSubFileType);
    788 
    789 	directory.Add (&fImageWidth);
    790 	directory.Add (&fImageLength);
    791 
    792 	directory.Add (&fPhotoInterpretation);
    793 
    794 	directory.Add (&fSamplesPerPixel);
    795 
    796 	directory.Add (&fBitsPerSample);
    797 
    798 	if (info.fBitsPerSample [0] !=  8 &&
    799 	    info.fBitsPerSample [0] != 16 &&
    800 	    info.fBitsPerSample [0] != 32)
    801 		{
    802 
    803 		directory.Add (&fFillOrder);
    804 
    805 		}
    806 
    807 	if (!fStrips)
    808 		{
    809 
    810 		directory.Add (&fTileWidth);
    811 
    812 		}
    813 
    814 	directory.Add (&fTileLength);
    815 
    816 	directory.Add (&fTileOffsets);
    817 	directory.Add (&fTileByteCounts);
    818 
    819 	directory.Add (&fPlanarConfiguration);
    820 
    821 	directory.Add (&fCompression);
    822 
    823 	if (info.fPredictor != cpNullPredictor)
    824 		{
    825 
    826 		directory.Add (&fPredictor);
    827 
    828 		}
    829 
    830 	if (info.fExtraSamplesCount != 0)
    831 		{
    832 
    833 		for (j = 0; j < info.fExtraSamplesCount; j++)
    834 			{
    835 			fExtraSamplesData [j] = (uint16) info.fExtraSamples [j];
    836 			}
    837 
    838 		directory.Add (&fExtraSamples);
    839 
    840 		}
    841 
    842 	if (info.fSampleFormat [0] != sfUnsignedInteger)
    843 		{
    844 
    845 		for (j = 0; j < info.fSamplesPerPixel; j++)
    846 			{
    847 			fSampleFormatData [j] = (uint16) info.fSampleFormat [j];
    848 			}
    849 
    850 		directory.Add (&fSampleFormat);
    851 
    852 		}
    853 
    854 	if (info.fRowInterleaveFactor != 1)
    855 		{
    856 
    857 		directory.Add (&fRowInterleaveFactor);
    858 
    859 		}
    860 
    861 	if (info.fSubTileBlockRows != 1 ||
    862 		info.fSubTileBlockCols != 1)
    863 		{
    864 
    865 		fSubTileBlockSizeData [0] = (uint16) info.fSubTileBlockRows;
    866 		fSubTileBlockSizeData [1] = (uint16) info.fSubTileBlockCols;
    867 
    868 		directory.Add (&fSubTileBlockSize);
    869 
    870 		}
    871 
    872 	}
    873 
    874 /******************************************************************************/
    875 
    876 exif_tag_set::exif_tag_set (dng_tiff_directory &directory,
    877 					  		const dng_exif &exif,
    878 							bool makerNoteSafe,
    879 							const void *makerNoteData,
    880 							uint32 makerNoteLength,
    881 					 	    bool insideDNG)
    882 
    883 	:	fExifIFD ()
    884 	,	fGPSIFD  ()
    885 
    886 	,	fExifLink (tcExifIFD, 0)
    887 	,	fGPSLink  (tcGPSInfo, 0)
    888 
    889 	,	fAddedExifLink (false)
    890 	,	fAddedGPSLink  (false)
    891 
    892 	,	fExifVersion (tcExifVersion, ttUndefined, 4, fExifVersionData)
    893 
    894 	,	fExposureTime      (tcExposureTime     , exif.fExposureTime     )
    895 	,	fShutterSpeedValue (tcShutterSpeedValue, exif.fShutterSpeedValue)
    896 
    897 	,	fFNumber 	   (tcFNumber      , exif.fFNumber      )
    898 	,	fApertureValue (tcApertureValue, exif.fApertureValue)
    899 
    900 	,	fBrightnessValue (tcBrightnessValue, exif.fBrightnessValue)
    901 
    902 	,	fExposureBiasValue (tcExposureBiasValue, exif.fExposureBiasValue)
    903 
    904 	,	fMaxApertureValue (tcMaxApertureValue , exif.fMaxApertureValue)
    905 
    906 	,	fSubjectDistance (tcSubjectDistance, exif.fSubjectDistance)
    907 
    908 	,	fFocalLength (tcFocalLength, exif.fFocalLength)
    909 
    910 	// Special case: the EXIF 2.2 standard represents ISO speed ratings with 2 bytes,
    911 	// which cannot hold ISO speed ratings above 65535 (e.g., 102400). In these
    912 	// cases, we write the maximum representable ISO speed rating value in the EXIF
    913 	// tag, i.e., 65535.
    914 
    915 	,	fISOSpeedRatings (tcISOSpeedRatings,
    916 						  (uint16) Min_uint32 (65535,
    917 											   exif.fISOSpeedRatings [0]))
    918 
    919 	,	fSensitivityType (tcSensitivityType, (uint16) exif.fSensitivityType)
    920 
    921 	,	fStandardOutputSensitivity (tcStandardOutputSensitivity, exif.fStandardOutputSensitivity)
    922 
    923 	,	fRecommendedExposureIndex (tcRecommendedExposureIndex, exif.fRecommendedExposureIndex)
    924 
    925 	,	fISOSpeed (tcISOSpeed, exif.fISOSpeed)
    926 
    927 	,	fISOSpeedLatitudeyyy (tcISOSpeedLatitudeyyy, exif.fISOSpeedLatitudeyyy)
    928 
    929 	,	fISOSpeedLatitudezzz (tcISOSpeedLatitudezzz, exif.fISOSpeedLatitudezzz)
    930 
    931 	,	fFlash (tcFlash, (uint16) exif.fFlash)
    932 
    933 	,	fExposureProgram (tcExposureProgram, (uint16) exif.fExposureProgram)
    934 
    935 	,	fMeteringMode (tcMeteringMode, (uint16) exif.fMeteringMode)
    936 
    937 	,	fLightSource (tcLightSource, (uint16) exif.fLightSource)
    938 
    939 	,	fSensingMethod (tcSensingMethodExif, (uint16) exif.fSensingMethod)
    940 
    941 	,	fFocalLength35mm (tcFocalLengthIn35mmFilm, (uint16) exif.fFocalLengthIn35mmFilm)
    942 
    943 	,	fFileSourceData ((uint8) exif.fFileSource)
    944 	,	fFileSource     (tcFileSource, ttUndefined, 1, &fFileSourceData)
    945 
    946 	,	fSceneTypeData ((uint8) exif.fSceneType)
    947 	,	fSceneType     (tcSceneType, ttUndefined, 1, &fSceneTypeData)
    948 
    949 	,	fCFAPattern (tcCFAPatternExif,
    950 					 exif.fCFARepeatPatternRows,
    951 					 exif.fCFARepeatPatternCols,
    952 					 &exif.fCFAPattern [0] [0])
    953 
    954 	,	fCustomRendered 	  (tcCustomRendered		 , (uint16) exif.fCustomRendered	  )
    955 	,	fExposureMode 		  (tcExposureMode		 , (uint16) exif.fExposureMode		  )
    956 	,	fWhiteBalance 		  (tcWhiteBalance		 , (uint16) exif.fWhiteBalance		  )
    957 	,	fSceneCaptureType 	  (tcSceneCaptureType	 , (uint16) exif.fSceneCaptureType	  )
    958 	,	fGainControl 		  (tcGainControl		 , (uint16) exif.fGainControl		  )
    959 	,	fContrast 			  (tcContrast			 , (uint16) exif.fContrast			  )
    960 	,	fSaturation 		  (tcSaturation			 , (uint16) exif.fSaturation		  )
    961 	,	fSharpness 			  (tcSharpness			 , (uint16) exif.fSharpness			  )
    962 	,	fSubjectDistanceRange (tcSubjectDistanceRange, (uint16) exif.fSubjectDistanceRange)
    963 
    964 	,	fDigitalZoomRatio (tcDigitalZoomRatio, exif.fDigitalZoomRatio)
    965 
    966 	,	fExposureIndex (tcExposureIndexExif, exif.fExposureIndex)
    967 
    968 	,	fImageNumber (tcImageNumber, exif.fImageNumber)
    969 
    970 	,	fSelfTimerMode (tcSelfTimerMode, (uint16) exif.fSelfTimerMode)
    971 
    972 	,	fBatteryLevelA (tcBatteryLevel, exif.fBatteryLevelA)
    973 	,	fBatteryLevelR (tcBatteryLevel, exif.fBatteryLevelR)
    974 
    975 	,	fFocalPlaneXResolution (tcFocalPlaneXResolutionExif, exif.fFocalPlaneXResolution)
    976 	,	fFocalPlaneYResolution (tcFocalPlaneYResolutionExif, exif.fFocalPlaneYResolution)
    977 
    978 	,	fFocalPlaneResolutionUnit (tcFocalPlaneResolutionUnitExif, (uint16) exif.fFocalPlaneResolutionUnit)
    979 
    980 	,	fSubjectArea (tcSubjectArea, fSubjectAreaData, exif.fSubjectAreaCount)
    981 
    982 	,	fLensInfo (tcLensInfo, fLensInfoData, 4)
    983 
    984 	,	fDateTime		   (tcDateTime		   , exif.fDateTime         .DateTime ())
    985 	,	fDateTimeOriginal  (tcDateTimeOriginal , exif.fDateTimeOriginal .DateTime ())
    986 	,	fDateTimeDigitized (tcDateTimeDigitized, exif.fDateTimeDigitized.DateTime ())
    987 
    988 	,	fSubsecTime			 (tcSubsecTime, 		 exif.fDateTime         .Subseconds ())
    989 	,	fSubsecTimeOriginal  (tcSubsecTimeOriginal,  exif.fDateTimeOriginal .Subseconds ())
    990 	,	fSubsecTimeDigitized (tcSubsecTimeDigitized, exif.fDateTimeDigitized.Subseconds ())
    991 
    992 	,	fMake (tcMake, exif.fMake)
    993 
    994 	,	fModel (tcModel, exif.fModel)
    995 
    996 	,	fArtist (tcArtist, exif.fArtist)
    997 
    998 	,	fSoftware (tcSoftware, exif.fSoftware)
    999 
   1000 	,	fCopyright (tcCopyright, exif.fCopyright)
   1001 
   1002 	,	fMakerNoteSafety (tcMakerNoteSafety, makerNoteSafe ? 1 : 0)
   1003 
   1004 	,	fMakerNote (tcMakerNote, ttUndefined, makerNoteLength, makerNoteData)
   1005 
   1006 	,	fImageDescription (tcImageDescription, exif.fImageDescription)
   1007 
   1008 	,	fSerialNumber (tcCameraSerialNumber, exif.fCameraSerialNumber)
   1009 
   1010 	,	fUserComment (tcUserComment, exif.fUserComment)
   1011 
   1012 	,	fImageUniqueID (tcImageUniqueID, ttAscii, 33, fImageUniqueIDData)
   1013 
   1014 	// EXIF 2.3 tags.
   1015 
   1016 	,	fCameraOwnerName   (tcCameraOwnerNameExif,	  exif.fOwnerName		  )
   1017 	,	fBodySerialNumber  (tcCameraSerialNumberExif, exif.fCameraSerialNumber)
   1018 	,	fLensSpecification (tcLensSpecificationExif,  fLensInfoData, 4		  )
   1019 	,	fLensMake		   (tcLensMakeExif,			  exif.fLensMake		  )
   1020 	,	fLensModel		   (tcLensModelExif,		  exif.fLensName		  )
   1021 	,	fLensSerialNumber  (tcLensSerialNumberExif,	  exif.fLensSerialNumber  )
   1022 
   1023 	,	fGPSVersionID (tcGPSVersionID, fGPSVersionData, 4)
   1024 
   1025 	,	fGPSLatitudeRef (tcGPSLatitudeRef, exif.fGPSLatitudeRef)
   1026 	,	fGPSLatitude    (tcGPSLatitude,    exif.fGPSLatitude, 3)
   1027 
   1028 	,	fGPSLongitudeRef (tcGPSLongitudeRef, exif.fGPSLongitudeRef)
   1029 	,	fGPSLongitude    (tcGPSLongitude,    exif.fGPSLongitude, 3)
   1030 
   1031 	,	fGPSAltitudeRef (tcGPSAltitudeRef, (uint8) exif.fGPSAltitudeRef)
   1032 	,	fGPSAltitude    (tcGPSAltitude,            exif.fGPSAltitude   )
   1033 
   1034 	,	fGPSTimeStamp (tcGPSTimeStamp, exif.fGPSTimeStamp, 3)
   1035 
   1036 	,	fGPSSatellites  (tcGPSSatellites , exif.fGPSSatellites )
   1037 	,	fGPSStatus      (tcGPSStatus     , exif.fGPSStatus     )
   1038 	,	fGPSMeasureMode (tcGPSMeasureMode, exif.fGPSMeasureMode)
   1039 
   1040 	,	fGPSDOP (tcGPSDOP, exif.fGPSDOP)
   1041 
   1042 	,	fGPSSpeedRef (tcGPSSpeedRef, exif.fGPSSpeedRef)
   1043 	,	fGPSSpeed    (tcGPSSpeed   , exif.fGPSSpeed   )
   1044 
   1045 	,	fGPSTrackRef (tcGPSTrackRef, exif.fGPSTrackRef)
   1046 	,	fGPSTrack    (tcGPSTrack   , exif.fGPSTrack   )
   1047 
   1048 	,	fGPSImgDirectionRef (tcGPSImgDirectionRef, exif.fGPSImgDirectionRef)
   1049 	,	fGPSImgDirection    (tcGPSImgDirection   , exif.fGPSImgDirection   )
   1050 
   1051 	,	fGPSMapDatum (tcGPSMapDatum, exif.fGPSMapDatum)
   1052 
   1053 	,	fGPSDestLatitudeRef (tcGPSDestLatitudeRef, exif.fGPSDestLatitudeRef)
   1054 	,	fGPSDestLatitude    (tcGPSDestLatitude,    exif.fGPSDestLatitude, 3)
   1055 
   1056 	,	fGPSDestLongitudeRef (tcGPSDestLongitudeRef, exif.fGPSDestLongitudeRef)
   1057 	,	fGPSDestLongitude    (tcGPSDestLongitude,    exif.fGPSDestLongitude, 3)
   1058 
   1059 	,	fGPSDestBearingRef (tcGPSDestBearingRef, exif.fGPSDestBearingRef)
   1060 	,	fGPSDestBearing    (tcGPSDestBearing   , exif.fGPSDestBearing   )
   1061 
   1062 	,	fGPSDestDistanceRef (tcGPSDestDistanceRef, exif.fGPSDestDistanceRef)
   1063 	,	fGPSDestDistance    (tcGPSDestDistance   , exif.fGPSDestDistance   )
   1064 
   1065 	,	fGPSProcessingMethod (tcGPSProcessingMethod, exif.fGPSProcessingMethod)
   1066 	,	fGPSAreaInformation  (tcGPSAreaInformation , exif.fGPSAreaInformation )
   1067 
   1068 	,	fGPSDateStamp (tcGPSDateStamp, exif.fGPSDateStamp)
   1069 
   1070 	,	fGPSDifferential (tcGPSDifferential, (uint16) exif.fGPSDifferential)
   1071 
   1072 	,	fGPSHPositioningError (tcGPSHPositioningError, exif.fGPSHPositioningError)
   1073 
   1074 	{
   1075 
   1076 	if (exif.fExifVersion)
   1077 		{
   1078 
   1079 		fExifVersionData [0] = (uint8) (exif.fExifVersion >> 24);
   1080 		fExifVersionData [1] = (uint8) (exif.fExifVersion >> 16);
   1081 		fExifVersionData [2] = (uint8) (exif.fExifVersion >>  8);
   1082 		fExifVersionData [3] = (uint8) (exif.fExifVersion      );
   1083 
   1084 		fExifIFD.Add (&fExifVersion);
   1085 
   1086 		}
   1087 
   1088 	if (exif.fExposureTime.IsValid ())
   1089 		{
   1090 		fExifIFD.Add (&fExposureTime);
   1091 		}
   1092 
   1093 	if (exif.fShutterSpeedValue.IsValid ())
   1094 		{
   1095 		fExifIFD.Add (&fShutterSpeedValue);
   1096 		}
   1097 
   1098 	if (exif.fFNumber.IsValid ())
   1099 		{
   1100 		fExifIFD.Add (&fFNumber);
   1101 		}
   1102 
   1103 	if (exif.fApertureValue.IsValid ())
   1104 		{
   1105 		fExifIFD.Add (&fApertureValue);
   1106 		}
   1107 
   1108 	if (exif.fBrightnessValue.IsValid ())
   1109 		{
   1110 		fExifIFD.Add (&fBrightnessValue);
   1111 		}
   1112 
   1113 	if (exif.fExposureBiasValue.IsValid ())
   1114 		{
   1115 		fExifIFD.Add (&fExposureBiasValue);
   1116 		}
   1117 
   1118 	if (exif.fMaxApertureValue.IsValid ())
   1119 		{
   1120 		fExifIFD.Add (&fMaxApertureValue);
   1121 		}
   1122 
   1123 	if (exif.fSubjectDistance.IsValid ())
   1124 		{
   1125 		fExifIFD.Add (&fSubjectDistance);
   1126 		}
   1127 
   1128 	if (exif.fFocalLength.IsValid ())
   1129 		{
   1130 		fExifIFD.Add (&fFocalLength);
   1131 		}
   1132 
   1133 	if (exif.fISOSpeedRatings [0] != 0)
   1134 		{
   1135 		fExifIFD.Add (&fISOSpeedRatings);
   1136 		}
   1137 
   1138 	if (exif.fFlash <= 0x0FFFF)
   1139 		{
   1140 		fExifIFD.Add (&fFlash);
   1141 		}
   1142 
   1143 	if (exif.fExposureProgram <= 0x0FFFF)
   1144 		{
   1145 		fExifIFD.Add (&fExposureProgram);
   1146 		}
   1147 
   1148 	if (exif.fMeteringMode <= 0x0FFFF)
   1149 		{
   1150 		fExifIFD.Add (&fMeteringMode);
   1151 		}
   1152 
   1153 	if (exif.fLightSource <= 0x0FFFF)
   1154 		{
   1155 		fExifIFD.Add (&fLightSource);
   1156 		}
   1157 
   1158 	if (exif.fSensingMethod <= 0x0FFFF)
   1159 		{
   1160 		fExifIFD.Add (&fSensingMethod);
   1161 		}
   1162 
   1163 	if (exif.fFocalLengthIn35mmFilm != 0)
   1164 		{
   1165 		fExifIFD.Add (&fFocalLength35mm);
   1166 		}
   1167 
   1168 	if (exif.fFileSource <= 0x0FF)
   1169 		{
   1170 		fExifIFD.Add (&fFileSource);
   1171 		}
   1172 
   1173 	if (exif.fSceneType <= 0x0FF)
   1174 		{
   1175 		fExifIFD.Add (&fSceneType);
   1176 		}
   1177 
   1178 	if (exif.fCFARepeatPatternRows &&
   1179 	    exif.fCFARepeatPatternCols)
   1180 		{
   1181 		fExifIFD.Add (&fCFAPattern);
   1182 		}
   1183 
   1184 	if (exif.fCustomRendered <= 0x0FFFF)
   1185 		{
   1186 		fExifIFD.Add (&fCustomRendered);
   1187 		}
   1188 
   1189 	if (exif.fExposureMode <= 0x0FFFF)
   1190 		{
   1191 		fExifIFD.Add (&fExposureMode);
   1192 		}
   1193 
   1194 	if (exif.fWhiteBalance <= 0x0FFFF)
   1195 		{
   1196 		fExifIFD.Add (&fWhiteBalance);
   1197 		}
   1198 
   1199 	if (exif.fSceneCaptureType <= 0x0FFFF)
   1200 		{
   1201 		fExifIFD.Add (&fSceneCaptureType);
   1202 		}
   1203 
   1204 	if (exif.fGainControl <= 0x0FFFF)
   1205 		{
   1206 		fExifIFD.Add (&fGainControl);
   1207 		}
   1208 
   1209 	if (exif.fContrast <= 0x0FFFF)
   1210 		{
   1211 		fExifIFD.Add (&fContrast);
   1212 		}
   1213 
   1214 	if (exif.fSaturation <= 0x0FFFF)
   1215 		{
   1216 		fExifIFD.Add (&fSaturation);
   1217 		}
   1218 
   1219 	if (exif.fSharpness <= 0x0FFFF)
   1220 		{
   1221 		fExifIFD.Add (&fSharpness);
   1222 		}
   1223 
   1224 	if (exif.fSubjectDistanceRange <= 0x0FFFF)
   1225 		{
   1226 		fExifIFD.Add (&fSubjectDistanceRange);
   1227 		}
   1228 
   1229 	if (exif.fDigitalZoomRatio.IsValid ())
   1230 		{
   1231 		fExifIFD.Add (&fDigitalZoomRatio);
   1232 		}
   1233 
   1234 	if (exif.fExposureIndex.IsValid ())
   1235 		{
   1236 		fExifIFD.Add (&fExposureIndex);
   1237 		}
   1238 
   1239 	if (insideDNG)	// TIFF-EP only tags
   1240 		{
   1241 
   1242 		if (exif.fImageNumber != 0xFFFFFFFF)
   1243 			{
   1244 			directory.Add (&fImageNumber);
   1245 			}
   1246 
   1247 		if (exif.fSelfTimerMode <= 0x0FFFF)
   1248 			{
   1249 			directory.Add (&fSelfTimerMode);
   1250 			}
   1251 
   1252 		if (exif.fBatteryLevelA.NotEmpty ())
   1253 			{
   1254 			directory.Add (&fBatteryLevelA);
   1255 			}
   1256 
   1257 		else if (exif.fBatteryLevelR.IsValid ())
   1258 			{
   1259 			directory.Add (&fBatteryLevelR);
   1260 			}
   1261 
   1262 		}
   1263 
   1264 	if (exif.fFocalPlaneXResolution.IsValid ())
   1265 		{
   1266 		fExifIFD.Add (&fFocalPlaneXResolution);
   1267 		}
   1268 
   1269 	if (exif.fFocalPlaneYResolution.IsValid ())
   1270 		{
   1271 		fExifIFD.Add (&fFocalPlaneYResolution);
   1272 		}
   1273 
   1274 	if (exif.fFocalPlaneResolutionUnit <= 0x0FFFF)
   1275 		{
   1276 		fExifIFD.Add (&fFocalPlaneResolutionUnit);
   1277 		}
   1278 
   1279 	if (exif.fSubjectAreaCount)
   1280 		{
   1281 
   1282 		fSubjectAreaData [0] = (uint16) exif.fSubjectArea [0];
   1283 		fSubjectAreaData [1] = (uint16) exif.fSubjectArea [1];
   1284 		fSubjectAreaData [2] = (uint16) exif.fSubjectArea [2];
   1285 		fSubjectAreaData [3] = (uint16) exif.fSubjectArea [3];
   1286 
   1287 		fExifIFD.Add (&fSubjectArea);
   1288 
   1289 		}
   1290 
   1291 	if (exif.fLensInfo [0].IsValid () &&
   1292 		exif.fLensInfo [1].IsValid ())
   1293 		{
   1294 
   1295 		fLensInfoData [0] = exif.fLensInfo [0];
   1296 		fLensInfoData [1] = exif.fLensInfo [1];
   1297 		fLensInfoData [2] = exif.fLensInfo [2];
   1298 		fLensInfoData [3] = exif.fLensInfo [3];
   1299 
   1300 		if (insideDNG)
   1301 			{
   1302 			directory.Add (&fLensInfo);
   1303 			}
   1304 
   1305 		}
   1306 
   1307 	if (exif.fDateTime.IsValid ())
   1308 		{
   1309 
   1310 		directory.Add (&fDateTime);
   1311 
   1312 		if (exif.fDateTime.Subseconds ().NotEmpty ())
   1313 			{
   1314 			fExifIFD.Add (&fSubsecTime);
   1315 			}
   1316 
   1317 		}
   1318 
   1319 	if (exif.fDateTimeOriginal.IsValid ())
   1320 		{
   1321 
   1322 		fExifIFD.Add (&fDateTimeOriginal);
   1323 
   1324 		if (exif.fDateTimeOriginal.Subseconds ().NotEmpty ())
   1325 			{
   1326 			fExifIFD.Add (&fSubsecTimeOriginal);
   1327 			}
   1328 
   1329 		}
   1330 
   1331 	if (exif.fDateTimeDigitized.IsValid ())
   1332 		{
   1333 
   1334 		fExifIFD.Add (&fDateTimeDigitized);
   1335 
   1336 		if (exif.fDateTimeDigitized.Subseconds ().NotEmpty ())
   1337 			{
   1338 			fExifIFD.Add (&fSubsecTimeDigitized);
   1339 			}
   1340 
   1341 		}
   1342 
   1343 	if (exif.fMake.NotEmpty ())
   1344 		{
   1345 		directory.Add (&fMake);
   1346 		}
   1347 
   1348 	if (exif.fModel.NotEmpty ())
   1349 		{
   1350 		directory.Add (&fModel);
   1351 		}
   1352 
   1353 	if (exif.fArtist.NotEmpty ())
   1354 		{
   1355 		directory.Add (&fArtist);
   1356 		}
   1357 
   1358 	if (exif.fSoftware.NotEmpty ())
   1359 		{
   1360 		directory.Add (&fSoftware);
   1361 		}
   1362 
   1363 	if (exif.fCopyright.NotEmpty ())
   1364 		{
   1365 		directory.Add (&fCopyright);
   1366 		}
   1367 
   1368 	if (exif.fImageDescription.NotEmpty ())
   1369 		{
   1370 		directory.Add (&fImageDescription);
   1371 		}
   1372 
   1373 	if (exif.fCameraSerialNumber.NotEmpty () && insideDNG)
   1374 		{
   1375 		directory.Add (&fSerialNumber);
   1376 		}
   1377 
   1378 	if (makerNoteSafe && makerNoteData)
   1379 		{
   1380 
   1381 		directory.Add (&fMakerNoteSafety);
   1382 
   1383 		fExifIFD.Add (&fMakerNote);
   1384 
   1385 		}
   1386 
   1387 	if (exif.fUserComment.NotEmpty ())
   1388 		{
   1389 		fExifIFD.Add (&fUserComment);
   1390 		}
   1391 
   1392 	if (exif.fImageUniqueID.IsValid ())
   1393 		{
   1394 
   1395 		for (uint32 j = 0; j < 16; j++)
   1396 			{
   1397 
   1398 			sprintf (fImageUniqueIDData + j * 2,
   1399 					 "%02X",
   1400 					 (unsigned) exif.fImageUniqueID.data [j]);
   1401 
   1402 			}
   1403 
   1404 		fExifIFD.Add (&fImageUniqueID);
   1405 
   1406 		}
   1407 
   1408 	if (exif.AtLeastVersion0230 ())
   1409 		{
   1410 
   1411 		if (exif.fSensitivityType != 0)
   1412 			{
   1413 
   1414 			fExifIFD.Add (&fSensitivityType);
   1415 
   1416 			}
   1417 
   1418 		// Sensitivity tags. Do not write these extra tags unless the SensitivityType
   1419 		// and PhotographicSensitivity (i.e., ISOSpeedRatings) values are valid.
   1420 
   1421 		if (exif.fSensitivityType	  != 0 &&
   1422 			exif.fISOSpeedRatings [0] != 0)
   1423 			{
   1424 
   1425 			// Standard Output Sensitivity (SOS).
   1426 
   1427 			if (exif.fStandardOutputSensitivity != 0)
   1428 				{
   1429 				fExifIFD.Add (&fStandardOutputSensitivity);
   1430 				}
   1431 
   1432 			// Recommended Exposure Index (REI).
   1433 
   1434 			if (exif.fRecommendedExposureIndex != 0)
   1435 				{
   1436 				fExifIFD.Add (&fRecommendedExposureIndex);
   1437 				}
   1438 
   1439 			// ISO Speed.
   1440 
   1441 			if (exif.fISOSpeed != 0)
   1442 				{
   1443 
   1444 				fExifIFD.Add (&fISOSpeed);
   1445 
   1446 				if (exif.fISOSpeedLatitudeyyy != 0 &&
   1447 					exif.fISOSpeedLatitudezzz != 0)
   1448 					{
   1449 
   1450 					fExifIFD.Add (&fISOSpeedLatitudeyyy);
   1451 					fExifIFD.Add (&fISOSpeedLatitudezzz);
   1452 
   1453 					}
   1454 
   1455 				}
   1456 
   1457 			}
   1458 
   1459 		if (exif.fOwnerName.NotEmpty ())
   1460 			{
   1461 			fExifIFD.Add (&fCameraOwnerName);
   1462 			}
   1463 
   1464 		if (exif.fCameraSerialNumber.NotEmpty ())
   1465 			{
   1466 			fExifIFD.Add (&fBodySerialNumber);
   1467 			}
   1468 
   1469 		if (exif.fLensInfo [0].IsValid () &&
   1470 			exif.fLensInfo [1].IsValid ())
   1471 			{
   1472 			fExifIFD.Add (&fLensSpecification);
   1473 			}
   1474 
   1475 		if (exif.fLensMake.NotEmpty ())
   1476 			{
   1477 			fExifIFD.Add (&fLensMake);
   1478 			}
   1479 
   1480 		if (exif.fLensName.NotEmpty ())
   1481 			{
   1482 			fExifIFD.Add (&fLensModel);
   1483 			}
   1484 
   1485 		if (exif.fLensSerialNumber.NotEmpty ())
   1486 			{
   1487 			fExifIFD.Add (&fLensSerialNumber);
   1488 			}
   1489 
   1490 		}
   1491 
   1492 	if (exif.fGPSVersionID)
   1493 		{
   1494 
   1495 		fGPSVersionData [0] = (uint8) (exif.fGPSVersionID >> 24);
   1496 		fGPSVersionData [1] = (uint8) (exif.fGPSVersionID >> 16);
   1497 		fGPSVersionData [2] = (uint8) (exif.fGPSVersionID >>  8);
   1498 		fGPSVersionData [3] = (uint8) (exif.fGPSVersionID      );
   1499 
   1500 		fGPSIFD.Add (&fGPSVersionID);
   1501 
   1502 		}
   1503 
   1504 	if (exif.fGPSLatitudeRef.NotEmpty () &&
   1505 		exif.fGPSLatitude [0].IsValid ())
   1506 		{
   1507 		fGPSIFD.Add (&fGPSLatitudeRef);
   1508 		fGPSIFD.Add (&fGPSLatitude   );
   1509 		}
   1510 
   1511 	if (exif.fGPSLongitudeRef.NotEmpty () &&
   1512 		exif.fGPSLongitude [0].IsValid ())
   1513 		{
   1514 		fGPSIFD.Add (&fGPSLongitudeRef);
   1515 		fGPSIFD.Add (&fGPSLongitude   );
   1516 		}
   1517 
   1518 	if (exif.fGPSAltitudeRef <= 0x0FF)
   1519 		{
   1520 		fGPSIFD.Add (&fGPSAltitudeRef);
   1521 		}
   1522 
   1523 	if (exif.fGPSAltitude.IsValid ())
   1524 		{
   1525 		fGPSIFD.Add (&fGPSAltitude);
   1526 		}
   1527 
   1528 	if (exif.fGPSTimeStamp [0].IsValid ())
   1529 		{
   1530 		fGPSIFD.Add (&fGPSTimeStamp);
   1531 		}
   1532 
   1533 	if (exif.fGPSSatellites.NotEmpty ())
   1534 		{
   1535 		fGPSIFD.Add (&fGPSSatellites);
   1536 		}
   1537 
   1538 	if (exif.fGPSStatus.NotEmpty ())
   1539 		{
   1540 		fGPSIFD.Add (&fGPSStatus);
   1541 		}
   1542 
   1543 	if (exif.fGPSMeasureMode.NotEmpty ())
   1544 		{
   1545 		fGPSIFD.Add (&fGPSMeasureMode);
   1546 		}
   1547 
   1548 	if (exif.fGPSDOP.IsValid ())
   1549 		{
   1550 		fGPSIFD.Add (&fGPSDOP);
   1551 		}
   1552 
   1553 	if (exif.fGPSSpeedRef.NotEmpty ())
   1554 		{
   1555 		fGPSIFD.Add (&fGPSSpeedRef);
   1556 		}
   1557 
   1558 	if (exif.fGPSSpeed.IsValid ())
   1559 		{
   1560 		fGPSIFD.Add (&fGPSSpeed);
   1561 		}
   1562 
   1563 	if (exif.fGPSTrackRef.NotEmpty ())
   1564 		{
   1565 		fGPSIFD.Add (&fGPSTrackRef);
   1566 		}
   1567 
   1568 	if (exif.fGPSTrack.IsValid ())
   1569 		{
   1570 		fGPSIFD.Add (&fGPSTrack);
   1571 		}
   1572 
   1573 	if (exif.fGPSImgDirectionRef.NotEmpty ())
   1574 		{
   1575 		fGPSIFD.Add (&fGPSImgDirectionRef);
   1576 		}
   1577 
   1578 	if (exif.fGPSImgDirection.IsValid ())
   1579 		{
   1580 		fGPSIFD.Add (&fGPSImgDirection);
   1581 		}
   1582 
   1583 	if (exif.fGPSMapDatum.NotEmpty ())
   1584 		{
   1585 		fGPSIFD.Add (&fGPSMapDatum);
   1586 		}
   1587 
   1588 	if (exif.fGPSDestLatitudeRef.NotEmpty () &&
   1589 		exif.fGPSDestLatitude [0].IsValid ())
   1590 		{
   1591 		fGPSIFD.Add (&fGPSDestLatitudeRef);
   1592 		fGPSIFD.Add (&fGPSDestLatitude   );
   1593 		}
   1594 
   1595 	if (exif.fGPSDestLongitudeRef.NotEmpty () &&
   1596 		exif.fGPSDestLongitude [0].IsValid ())
   1597 		{
   1598 		fGPSIFD.Add (&fGPSDestLongitudeRef);
   1599 		fGPSIFD.Add (&fGPSDestLongitude   );
   1600 		}
   1601 
   1602 	if (exif.fGPSDestBearingRef.NotEmpty ())
   1603 		{
   1604 		fGPSIFD.Add (&fGPSDestBearingRef);
   1605 		}
   1606 
   1607 	if (exif.fGPSDestBearing.IsValid ())
   1608 		{
   1609 		fGPSIFD.Add (&fGPSDestBearing);
   1610 		}
   1611 
   1612 	if (exif.fGPSDestDistanceRef.NotEmpty ())
   1613 		{
   1614 		fGPSIFD.Add (&fGPSDestDistanceRef);
   1615 		}
   1616 
   1617 	if (exif.fGPSDestDistance.IsValid ())
   1618 		{
   1619 		fGPSIFD.Add (&fGPSDestDistance);
   1620 		}
   1621 
   1622 	if (exif.fGPSProcessingMethod.NotEmpty ())
   1623 		{
   1624 		fGPSIFD.Add (&fGPSProcessingMethod);
   1625 		}
   1626 
   1627 	if (exif.fGPSAreaInformation.NotEmpty ())
   1628 		{
   1629 		fGPSIFD.Add (&fGPSAreaInformation);
   1630 		}
   1631 
   1632 	if (exif.fGPSDateStamp.NotEmpty ())
   1633 		{
   1634 		fGPSIFD.Add (&fGPSDateStamp);
   1635 		}
   1636 
   1637 	if (exif.fGPSDifferential <= 0x0FFFF)
   1638 		{
   1639 		fGPSIFD.Add (&fGPSDifferential);
   1640 		}
   1641 
   1642 	if (exif.AtLeastVersion0230 ())
   1643 		{
   1644 
   1645 		if (exif.fGPSHPositioningError.IsValid ())
   1646 			{
   1647 			fGPSIFD.Add (&fGPSHPositioningError);
   1648 			}
   1649 
   1650 		}
   1651 
   1652 	AddLinks (directory);
   1653 
   1654 	}
   1655 
   1656 /******************************************************************************/
   1657 
   1658 void exif_tag_set::AddLinks (dng_tiff_directory &directory)
   1659 	{
   1660 
   1661 	if (fExifIFD.Size () != 0 && !fAddedExifLink)
   1662 		{
   1663 
   1664 		directory.Add (&fExifLink);
   1665 
   1666 		fAddedExifLink = true;
   1667 
   1668 		}
   1669 
   1670 	if (fGPSIFD.Size () != 0 && !fAddedGPSLink)
   1671 		{
   1672 
   1673 		directory.Add (&fGPSLink);
   1674 
   1675 		fAddedGPSLink = true;
   1676 
   1677 		}
   1678 
   1679 	}
   1680 
   1681 /******************************************************************************/
   1682 
   1683 class range_tag_set
   1684 	{
   1685 
   1686 	private:
   1687 
   1688 		uint32 fActiveAreaData [4];
   1689 
   1690 		tag_uint32_ptr fActiveArea;
   1691 
   1692 		uint32 fMaskedAreaData [kMaxMaskedAreas * 4];
   1693 
   1694 		tag_uint32_ptr fMaskedAreas;
   1695 
   1696 		tag_uint16_ptr fLinearizationTable;
   1697 
   1698 		uint16 fBlackLevelRepeatDimData [2];
   1699 
   1700 		tag_uint16_ptr fBlackLevelRepeatDim;
   1701 
   1702 		dng_urational fBlackLevelData [kMaxBlackPattern *
   1703 								       kMaxBlackPattern *
   1704 								       kMaxSamplesPerPixel];
   1705 
   1706 		tag_urational_ptr fBlackLevel;
   1707 
   1708 		dng_memory_data fBlackLevelDeltaHData;
   1709 		dng_memory_data fBlackLevelDeltaVData;
   1710 
   1711 		tag_srational_ptr fBlackLevelDeltaH;
   1712 		tag_srational_ptr fBlackLevelDeltaV;
   1713 
   1714 		uint16 fWhiteLevelData16 [kMaxSamplesPerPixel];
   1715 		uint32 fWhiteLevelData32 [kMaxSamplesPerPixel];
   1716 
   1717 		tag_uint16_ptr fWhiteLevel16;
   1718 		tag_uint32_ptr fWhiteLevel32;
   1719 
   1720 	public:
   1721 
   1722 		range_tag_set (dng_tiff_directory &directory,
   1723 				       const dng_negative &negative);
   1724 
   1725 	};
   1726 
   1727 /******************************************************************************/
   1728 
   1729 range_tag_set::range_tag_set (dng_tiff_directory &directory,
   1730 				     	      const dng_negative &negative)
   1731 
   1732 	:	fActiveArea (tcActiveArea,
   1733 					 fActiveAreaData,
   1734 					 4)
   1735 
   1736 	,	fMaskedAreas (tcMaskedAreas,
   1737 					  fMaskedAreaData,
   1738 					  0)
   1739 
   1740 	,	fLinearizationTable (tcLinearizationTable,
   1741 							 NULL,
   1742 							 0)
   1743 
   1744 	,	fBlackLevelRepeatDim (tcBlackLevelRepeatDim,
   1745 							  fBlackLevelRepeatDimData,
   1746 							  2)
   1747 
   1748 	,	fBlackLevel (tcBlackLevel,
   1749 					 fBlackLevelData)
   1750 
   1751 	,	fBlackLevelDeltaHData ()
   1752 	,	fBlackLevelDeltaVData ()
   1753 
   1754 	,	fBlackLevelDeltaH (tcBlackLevelDeltaH)
   1755 	,	fBlackLevelDeltaV (tcBlackLevelDeltaV)
   1756 
   1757 	,	fWhiteLevel16 (tcWhiteLevel,
   1758 					   fWhiteLevelData16)
   1759 
   1760 	,	fWhiteLevel32 (tcWhiteLevel,
   1761 					   fWhiteLevelData32)
   1762 
   1763 	{
   1764 
   1765 	const dng_image &rawImage (negative.RawImage ());
   1766 
   1767 	const dng_linearization_info *rangeInfo = negative.GetLinearizationInfo ();
   1768 
   1769 	if (rangeInfo)
   1770 		{
   1771 
   1772 		// ActiveArea:
   1773 
   1774 			{
   1775 
   1776 			const dng_rect &r = rangeInfo->fActiveArea;
   1777 
   1778 			if (r.NotEmpty ())
   1779 				{
   1780 
   1781 				fActiveAreaData [0] = r.t;
   1782 				fActiveAreaData [1] = r.l;
   1783 				fActiveAreaData [2] = r.b;
   1784 				fActiveAreaData [3] = r.r;
   1785 
   1786 				directory.Add (&fActiveArea);
   1787 
   1788 				}
   1789 
   1790 			}
   1791 
   1792 		// MaskedAreas:
   1793 
   1794 		if (rangeInfo->fMaskedAreaCount)
   1795 			{
   1796 
   1797 			fMaskedAreas.SetCount (rangeInfo->fMaskedAreaCount * 4);
   1798 
   1799 			for (uint32 index = 0; index < rangeInfo->fMaskedAreaCount; index++)
   1800 				{
   1801 
   1802 				const dng_rect &r = rangeInfo->fMaskedArea [index];
   1803 
   1804 				fMaskedAreaData [index * 4 + 0] = r.t;
   1805 				fMaskedAreaData [index * 4 + 1] = r.l;
   1806 				fMaskedAreaData [index * 4 + 2] = r.b;
   1807 				fMaskedAreaData [index * 4 + 3] = r.r;
   1808 
   1809 				}
   1810 
   1811 			directory.Add (&fMaskedAreas);
   1812 
   1813 			}
   1814 
   1815 		// LinearizationTable:
   1816 
   1817 		if (rangeInfo->fLinearizationTable.Get ())
   1818 			{
   1819 
   1820 			fLinearizationTable.SetData  (rangeInfo->fLinearizationTable->Buffer_uint16 ()     );
   1821 			fLinearizationTable.SetCount (rangeInfo->fLinearizationTable->LogicalSize   () >> 1);
   1822 
   1823 			directory.Add (&fLinearizationTable);
   1824 
   1825 			}
   1826 
   1827 		// BlackLevelRepeatDim:
   1828 
   1829 			{
   1830 
   1831 			fBlackLevelRepeatDimData [0] = (uint16) rangeInfo->fBlackLevelRepeatRows;
   1832 			fBlackLevelRepeatDimData [1] = (uint16) rangeInfo->fBlackLevelRepeatCols;
   1833 
   1834 			directory.Add (&fBlackLevelRepeatDim);
   1835 
   1836 			}
   1837 
   1838 		// BlackLevel:
   1839 
   1840 			{
   1841 
   1842 			uint32 index = 0;
   1843 
   1844 			for (uint16 v = 0; v < rangeInfo->fBlackLevelRepeatRows; v++)
   1845 				{
   1846 
   1847 				for (uint32 h = 0; h < rangeInfo->fBlackLevelRepeatCols; h++)
   1848 					{
   1849 
   1850 					for (uint32 c = 0; c < rawImage.Planes (); c++)
   1851 						{
   1852 
   1853 						fBlackLevelData [index++] = rangeInfo->BlackLevel (v, h, c);
   1854 
   1855 						}
   1856 
   1857 					}
   1858 
   1859 				}
   1860 
   1861 			fBlackLevel.SetCount (rangeInfo->fBlackLevelRepeatRows *
   1862 								  rangeInfo->fBlackLevelRepeatCols * rawImage.Planes ());
   1863 
   1864 			directory.Add (&fBlackLevel);
   1865 
   1866 			}
   1867 
   1868 		// BlackLevelDeltaH:
   1869 
   1870 		if (rangeInfo->ColumnBlackCount ())
   1871 			{
   1872 
   1873 			uint32 count = rangeInfo->ColumnBlackCount ();
   1874 
   1875 			fBlackLevelDeltaHData.Allocate (count, sizeof (dng_srational));
   1876 
   1877 			dng_srational *blacks = (dng_srational *) fBlackLevelDeltaHData.Buffer ();
   1878 
   1879 			for (uint32 col = 0; col < count; col++)
   1880 				{
   1881 
   1882 				blacks [col] = rangeInfo->ColumnBlack (col);
   1883 
   1884 				}
   1885 
   1886 			fBlackLevelDeltaH.SetData  (blacks);
   1887 			fBlackLevelDeltaH.SetCount (count );
   1888 
   1889 			directory.Add (&fBlackLevelDeltaH);
   1890 
   1891 			}
   1892 
   1893 		// BlackLevelDeltaV:
   1894 
   1895 		if (rangeInfo->RowBlackCount ())
   1896 			{
   1897 
   1898 			uint32 count = rangeInfo->RowBlackCount ();
   1899 
   1900 			fBlackLevelDeltaVData.Allocate (count, sizeof (dng_srational));
   1901 
   1902 			dng_srational *blacks = (dng_srational *) fBlackLevelDeltaVData.Buffer ();
   1903 
   1904 			for (uint32 row = 0; row < count; row++)
   1905 				{
   1906 
   1907 				blacks [row] = rangeInfo->RowBlack (row);
   1908 
   1909 				}
   1910 
   1911 			fBlackLevelDeltaV.SetData  (blacks);
   1912 			fBlackLevelDeltaV.SetCount (count );
   1913 
   1914 			directory.Add (&fBlackLevelDeltaV);
   1915 
   1916 			}
   1917 
   1918 		}
   1919 
   1920 	// WhiteLevel:
   1921 
   1922 	// Only use the 32-bit data type if we must use it since there
   1923 	// are some lazy (non-Adobe) DNG readers out there.
   1924 
   1925 	bool needs32 = false;
   1926 
   1927 	fWhiteLevel16.SetCount (rawImage.Planes ());
   1928 	fWhiteLevel32.SetCount (rawImage.Planes ());
   1929 
   1930 	for (uint32 c = 0; c < fWhiteLevel16.Count (); c++)
   1931 		{
   1932 
   1933 		fWhiteLevelData32 [c] = negative.WhiteLevel (c);
   1934 
   1935 		if (fWhiteLevelData32 [c] > 0x0FFFF)
   1936 			{
   1937 			needs32 = true;
   1938 			}
   1939 
   1940 		fWhiteLevelData16 [c] = (uint16) fWhiteLevelData32 [c];
   1941 
   1942 		}
   1943 
   1944 	if (needs32)
   1945 		{
   1946 		directory.Add (&fWhiteLevel32);
   1947 		}
   1948 
   1949 	else
   1950 		{
   1951 		directory.Add (&fWhiteLevel16);
   1952 		}
   1953 
   1954 	}
   1955 
   1956 /******************************************************************************/
   1957 
   1958 class mosaic_tag_set
   1959 	{
   1960 
   1961 	private:
   1962 
   1963 		uint16 fCFARepeatPatternDimData [2];
   1964 
   1965 		tag_uint16_ptr fCFARepeatPatternDim;
   1966 
   1967 		uint8 fCFAPatternData [kMaxCFAPattern *
   1968 							   kMaxCFAPattern];
   1969 
   1970 		tag_uint8_ptr fCFAPattern;
   1971 
   1972 		uint8 fCFAPlaneColorData [kMaxColorPlanes];
   1973 
   1974 		tag_uint8_ptr fCFAPlaneColor;
   1975 
   1976 		tag_uint16 fCFALayout;
   1977 
   1978 		tag_uint32 fGreenSplit;
   1979 
   1980 	public:
   1981 
   1982 		mosaic_tag_set (dng_tiff_directory &directory,
   1983 				        const dng_mosaic_info &info);
   1984 
   1985 	};
   1986 
   1987 /******************************************************************************/
   1988 
   1989 mosaic_tag_set::mosaic_tag_set (dng_tiff_directory &directory,
   1990 					            const dng_mosaic_info &info)
   1991 
   1992 	:	fCFARepeatPatternDim (tcCFARepeatPatternDim,
   1993 						  	  fCFARepeatPatternDimData,
   1994 						  	  2)
   1995 
   1996 	,	fCFAPattern (tcCFAPattern,
   1997 					 fCFAPatternData)
   1998 
   1999 	,	fCFAPlaneColor (tcCFAPlaneColor,
   2000 						fCFAPlaneColorData)
   2001 
   2002 	,	fCFALayout (tcCFALayout,
   2003 					(uint16) info.fCFALayout)
   2004 
   2005 	,	fGreenSplit (tcBayerGreenSplit,
   2006 					 info.fBayerGreenSplit)
   2007 
   2008 	{
   2009 
   2010 	if (info.IsColorFilterArray ())
   2011 		{
   2012 
   2013 		// CFARepeatPatternDim:
   2014 
   2015 		fCFARepeatPatternDimData [0] = (uint16) info.fCFAPatternSize.v;
   2016 		fCFARepeatPatternDimData [1] = (uint16) info.fCFAPatternSize.h;
   2017 
   2018 		directory.Add (&fCFARepeatPatternDim);
   2019 
   2020 		// CFAPattern:
   2021 
   2022 		fCFAPattern.SetCount (info.fCFAPatternSize.v *
   2023 							  info.fCFAPatternSize.h);
   2024 
   2025 		for (int32 r = 0; r < info.fCFAPatternSize.v; r++)
   2026 			{
   2027 
   2028 			for (int32 c = 0; c < info.fCFAPatternSize.h; c++)
   2029 				{
   2030 
   2031 				fCFAPatternData [r * info.fCFAPatternSize.h + c] = info.fCFAPattern [r] [c];
   2032 
   2033 				}
   2034 
   2035 			}
   2036 
   2037 		directory.Add (&fCFAPattern);
   2038 
   2039 		// CFAPlaneColor:
   2040 
   2041 		fCFAPlaneColor.SetCount (info.fColorPlanes);
   2042 
   2043 		for (uint32 j = 0; j < info.fColorPlanes; j++)
   2044 			{
   2045 
   2046 			fCFAPlaneColorData [j] = info.fCFAPlaneColor [j];
   2047 
   2048 			}
   2049 
   2050 		directory.Add (&fCFAPlaneColor);
   2051 
   2052 		// CFALayout:
   2053 
   2054 		fCFALayout.Set ((uint16) info.fCFALayout);
   2055 
   2056 		directory.Add (&fCFALayout);
   2057 
   2058 		// BayerGreenSplit:  (only include if the pattern is a Bayer pattern)
   2059 
   2060 		if (info.fCFAPatternSize == dng_point (2, 2) &&
   2061 			info.fColorPlanes    == 3)
   2062 			{
   2063 
   2064 			directory.Add (&fGreenSplit);
   2065 
   2066 			}
   2067 
   2068 		}
   2069 
   2070 	}
   2071 
   2072 /******************************************************************************/
   2073 
   2074 class color_tag_set
   2075 	{
   2076 
   2077 	private:
   2078 
   2079 		uint32 fColorChannels;
   2080 
   2081 		tag_matrix fCameraCalibration1;
   2082 		tag_matrix fCameraCalibration2;
   2083 
   2084 		tag_string fCameraCalibrationSignature;
   2085 
   2086 		tag_string fAsShotProfileName;
   2087 
   2088 		dng_urational fAnalogBalanceData [4];
   2089 
   2090 		tag_urational_ptr fAnalogBalance;
   2091 
   2092 		dng_urational fAsShotNeutralData [4];
   2093 
   2094 		tag_urational_ptr fAsShotNeutral;
   2095 
   2096 		dng_urational fAsShotWhiteXYData [2];
   2097 
   2098 		tag_urational_ptr fAsShotWhiteXY;
   2099 
   2100 		tag_urational fLinearResponseLimit;
   2101 
   2102 	public:
   2103 
   2104 		color_tag_set (dng_tiff_directory &directory,
   2105 				       const dng_negative &negative);
   2106 
   2107 	};
   2108 
   2109 /******************************************************************************/
   2110 
   2111 color_tag_set::color_tag_set (dng_tiff_directory &directory,
   2112 				     	  	  const dng_negative &negative)
   2113 
   2114 	:	fColorChannels (negative.ColorChannels ())
   2115 
   2116 	,	fCameraCalibration1 (tcCameraCalibration1,
   2117 						     negative.CameraCalibration1 ())
   2118 
   2119 	,	fCameraCalibration2 (tcCameraCalibration2,
   2120 						     negative.CameraCalibration2 ())
   2121 
   2122 	,	fCameraCalibrationSignature (tcCameraCalibrationSignature,
   2123 									 negative.CameraCalibrationSignature ())
   2124 
   2125 	,	fAsShotProfileName (tcAsShotProfileName,
   2126 							negative.AsShotProfileName ())
   2127 
   2128 	,	fAnalogBalance (tcAnalogBalance,
   2129 						fAnalogBalanceData,
   2130 						fColorChannels)
   2131 
   2132 	,	fAsShotNeutral (tcAsShotNeutral,
   2133 						fAsShotNeutralData,
   2134 						fColorChannels)
   2135 
   2136 	,	fAsShotWhiteXY (tcAsShotWhiteXY,
   2137 						fAsShotWhiteXYData,
   2138 						2)
   2139 
   2140 	,	fLinearResponseLimit (tcLinearResponseLimit,
   2141 						      negative.LinearResponseLimitR ())
   2142 
   2143 	{
   2144 
   2145 	if (fColorChannels > 1)
   2146 		{
   2147 
   2148 		uint32 channels2 = fColorChannels * fColorChannels;
   2149 
   2150 		if (fCameraCalibration1.Count () == channels2)
   2151 			{
   2152 
   2153 			directory.Add (&fCameraCalibration1);
   2154 
   2155 			}
   2156 
   2157 		if (fCameraCalibration2.Count () == channels2)
   2158 			{
   2159 
   2160 			directory.Add (&fCameraCalibration2);
   2161 
   2162 			}
   2163 
   2164 		if (fCameraCalibration1.Count () == channels2 ||
   2165 			fCameraCalibration2.Count () == channels2)
   2166 			{
   2167 
   2168 			if (negative.CameraCalibrationSignature ().NotEmpty ())
   2169 				{
   2170 
   2171 				directory.Add (&fCameraCalibrationSignature);
   2172 
   2173 				}
   2174 
   2175 			}
   2176 
   2177 		if (negative.AsShotProfileName ().NotEmpty ())
   2178 			{
   2179 
   2180 			directory.Add (&fAsShotProfileName);
   2181 
   2182 			}
   2183 
   2184 		for (uint32 j = 0; j < fColorChannels; j++)
   2185 			{
   2186 
   2187 			fAnalogBalanceData [j] = negative.AnalogBalanceR (j);
   2188 
   2189 			}
   2190 
   2191 		directory.Add (&fAnalogBalance);
   2192 
   2193 		if (negative.HasCameraNeutral ())
   2194 			{
   2195 
   2196 			for (uint32 k = 0; k < fColorChannels; k++)
   2197 				{
   2198 
   2199 				fAsShotNeutralData [k] = negative.CameraNeutralR (k);
   2200 
   2201 				}
   2202 
   2203 			directory.Add (&fAsShotNeutral);
   2204 
   2205 			}
   2206 
   2207 		else if (negative.HasCameraWhiteXY ())
   2208 			{
   2209 
   2210 			negative.GetCameraWhiteXY (fAsShotWhiteXYData [0],
   2211 									   fAsShotWhiteXYData [1]);
   2212 
   2213 			directory.Add (&fAsShotWhiteXY);
   2214 
   2215 			}
   2216 
   2217 		directory.Add (&fLinearResponseLimit);
   2218 
   2219 		}
   2220 
   2221 	}
   2222 
   2223 /******************************************************************************/
   2224 
   2225 class profile_tag_set
   2226 	{
   2227 
   2228 	private:
   2229 
   2230 		tag_uint16 fCalibrationIlluminant1;
   2231 		tag_uint16 fCalibrationIlluminant2;
   2232 
   2233 		tag_matrix fColorMatrix1;
   2234 		tag_matrix fColorMatrix2;
   2235 
   2236 		tag_matrix fForwardMatrix1;
   2237 		tag_matrix fForwardMatrix2;
   2238 
   2239 		tag_matrix fReductionMatrix1;
   2240 		tag_matrix fReductionMatrix2;
   2241 
   2242 		tag_string fProfileName;
   2243 
   2244 		tag_string fProfileCalibrationSignature;
   2245 
   2246 		tag_uint32 fEmbedPolicyTag;
   2247 
   2248 		tag_string fCopyrightTag;
   2249 
   2250 		uint32 fHueSatMapDimData [3];
   2251 
   2252 		tag_uint32_ptr fHueSatMapDims;
   2253 
   2254 		tag_data_ptr fHueSatData1;
   2255 		tag_data_ptr fHueSatData2;
   2256 
   2257 		tag_uint32 fHueSatMapEncodingTag;
   2258 
   2259 		uint32 fLookTableDimData [3];
   2260 
   2261 		tag_uint32_ptr fLookTableDims;
   2262 
   2263 		tag_data_ptr fLookTableData;
   2264 
   2265 		tag_uint32 fLookTableEncodingTag;
   2266 
   2267 		tag_srational fBaselineExposureOffsetTag;
   2268 
   2269 		tag_uint32 fDefaultBlackRenderTag;
   2270 
   2271 		dng_memory_data fToneCurveBuffer;
   2272 
   2273 		tag_data_ptr fToneCurveTag;
   2274 
   2275 	public:
   2276 
   2277 		profile_tag_set (dng_tiff_directory &directory,
   2278 						 const dng_camera_profile &profile);
   2279 
   2280 	};
   2281 
   2282 /******************************************************************************/
   2283 
   2284 profile_tag_set::profile_tag_set (dng_tiff_directory &directory,
   2285 				     	  	      const dng_camera_profile &profile)
   2286 
   2287 	:	fCalibrationIlluminant1 (tcCalibrationIlluminant1,
   2288 								 (uint16) profile.CalibrationIlluminant1 ())
   2289 
   2290 	,	fCalibrationIlluminant2 (tcCalibrationIlluminant2,
   2291 								 (uint16) profile.CalibrationIlluminant2 ())
   2292 
   2293 	,	fColorMatrix1 (tcColorMatrix1,
   2294 					   profile.ColorMatrix1 ())
   2295 
   2296 	,	fColorMatrix2 (tcColorMatrix2,
   2297 					   profile.ColorMatrix2 ())
   2298 
   2299 	,	fForwardMatrix1 (tcForwardMatrix1,
   2300 						 profile.ForwardMatrix1 ())
   2301 
   2302 	,	fForwardMatrix2 (tcForwardMatrix2,
   2303 						 profile.ForwardMatrix2 ())
   2304 
   2305 	,	fReductionMatrix1 (tcReductionMatrix1,
   2306 						   profile.ReductionMatrix1 ())
   2307 
   2308 	,	fReductionMatrix2 (tcReductionMatrix2,
   2309 						   profile.ReductionMatrix2 ())
   2310 
   2311 	,	fProfileName (tcProfileName,
   2312 					  profile.Name (),
   2313 					  false)
   2314 
   2315 	,	fProfileCalibrationSignature (tcProfileCalibrationSignature,
   2316 									  profile.ProfileCalibrationSignature (),
   2317 									  false)
   2318 
   2319 	,	fEmbedPolicyTag (tcProfileEmbedPolicy,
   2320 						 profile.EmbedPolicy ())
   2321 
   2322 	,	fCopyrightTag (tcProfileCopyright,
   2323 					   profile.Copyright (),
   2324 					   false)
   2325 
   2326 	,	fHueSatMapDims (tcProfileHueSatMapDims,
   2327 						fHueSatMapDimData,
   2328 						3)
   2329 
   2330 	,	fHueSatData1 (tcProfileHueSatMapData1,
   2331 					  ttFloat,
   2332 					  profile.HueSatDeltas1 ().DeltasCount () * 3,
   2333 					  profile.HueSatDeltas1 ().GetConstDeltas ())
   2334 
   2335 	,	fHueSatData2 (tcProfileHueSatMapData2,
   2336 					  ttFloat,
   2337 					  profile.HueSatDeltas2 ().DeltasCount () * 3,
   2338 					  profile.HueSatDeltas2 ().GetConstDeltas ())
   2339 
   2340 	,	fHueSatMapEncodingTag (tcProfileHueSatMapEncoding,
   2341 							   profile.HueSatMapEncoding ())
   2342 
   2343 	,	fLookTableDims (tcProfileLookTableDims,
   2344 						fLookTableDimData,
   2345 						3)
   2346 
   2347 	,	fLookTableData (tcProfileLookTableData,
   2348 						ttFloat,
   2349 						profile.LookTable ().DeltasCount () * 3,
   2350 					    profile.LookTable ().GetConstDeltas ())
   2351 
   2352 	,	fLookTableEncodingTag (tcProfileLookTableEncoding,
   2353 							   profile.LookTableEncoding ())
   2354 
   2355 	,	fBaselineExposureOffsetTag (tcBaselineExposureOffset,
   2356 									profile.BaselineExposureOffset ())
   2357 
   2358 	,	fDefaultBlackRenderTag (tcDefaultBlackRender,
   2359 								profile.DefaultBlackRender ())
   2360 
   2361 	,	fToneCurveBuffer ()
   2362 
   2363 	,	fToneCurveTag (tcProfileToneCurve,
   2364 					   ttFloat,
   2365 					   0,
   2366 					   NULL)
   2367 
   2368 	{
   2369 
   2370 	if (profile.HasColorMatrix1 ())
   2371 		{
   2372 
   2373 		uint32 colorChannels = profile.ColorMatrix1 ().Rows ();
   2374 
   2375 		directory.Add (&fCalibrationIlluminant1);
   2376 
   2377 		directory.Add (&fColorMatrix1);
   2378 
   2379 		if (fForwardMatrix1.Count () == colorChannels * 3)
   2380 			{
   2381 
   2382 			directory.Add (&fForwardMatrix1);
   2383 
   2384 			}
   2385 
   2386 		if (colorChannels > 3 && fReductionMatrix1.Count () == colorChannels * 3)
   2387 			{
   2388 
   2389 			directory.Add (&fReductionMatrix1);
   2390 
   2391 			}
   2392 
   2393 		if (profile.HasColorMatrix2 ())
   2394 			{
   2395 
   2396 			directory.Add (&fCalibrationIlluminant2);
   2397 
   2398 			directory.Add (&fColorMatrix2);
   2399 
   2400 			if (fForwardMatrix2.Count () == colorChannels * 3)
   2401 				{
   2402 
   2403 				directory.Add (&fForwardMatrix2);
   2404 
   2405 				}
   2406 
   2407 			if (colorChannels > 3 && fReductionMatrix2.Count () == colorChannels * 3)
   2408 				{
   2409 
   2410 				directory.Add (&fReductionMatrix2);
   2411 
   2412 				}
   2413 
   2414 			}
   2415 
   2416 		if (profile.Name ().NotEmpty ())
   2417 			{
   2418 
   2419 			directory.Add (&fProfileName);
   2420 
   2421 			}
   2422 
   2423 		if (profile.ProfileCalibrationSignature ().NotEmpty ())
   2424 			{
   2425 
   2426 			directory.Add (&fProfileCalibrationSignature);
   2427 
   2428 			}
   2429 
   2430 		directory.Add (&fEmbedPolicyTag);
   2431 
   2432 		if (profile.Copyright ().NotEmpty ())
   2433 			{
   2434 
   2435 			directory.Add (&fCopyrightTag);
   2436 
   2437 			}
   2438 
   2439 		bool haveHueSat1 = profile.HueSatDeltas1 ().IsValid ();
   2440 
   2441 		bool haveHueSat2 = profile.HueSatDeltas2 ().IsValid () &&
   2442 						   profile.HasColorMatrix2 ();
   2443 
   2444 		if (haveHueSat1 || haveHueSat2)
   2445 			{
   2446 
   2447 			uint32 hueDivs = 0;
   2448 			uint32 satDivs = 0;
   2449 			uint32 valDivs = 0;
   2450 
   2451 			if (haveHueSat1)
   2452 				{
   2453 
   2454 				profile.HueSatDeltas1 ().GetDivisions (hueDivs,
   2455 													   satDivs,
   2456 													   valDivs);
   2457 
   2458 				}
   2459 
   2460 			else
   2461 				{
   2462 
   2463 				profile.HueSatDeltas2 ().GetDivisions (hueDivs,
   2464 													   satDivs,
   2465 													   valDivs);
   2466 
   2467 				}
   2468 
   2469 			fHueSatMapDimData [0] = hueDivs;
   2470 			fHueSatMapDimData [1] = satDivs;
   2471 			fHueSatMapDimData [2] = valDivs;
   2472 
   2473 			directory.Add (&fHueSatMapDims);
   2474 
   2475 			// Don't bother including the ProfileHueSatMapEncoding tag unless it's
   2476 			// non-linear.
   2477 
   2478 			if (profile.HueSatMapEncoding () != encoding_Linear)
   2479 				{
   2480 
   2481 				directory.Add (&fHueSatMapEncodingTag);
   2482 
   2483 				}
   2484 
   2485 			}
   2486 
   2487 		if (haveHueSat1)
   2488 			{
   2489 
   2490 			directory.Add (&fHueSatData1);
   2491 
   2492 			}
   2493 
   2494 		if (haveHueSat2)
   2495 			{
   2496 
   2497 			directory.Add (&fHueSatData2);
   2498 
   2499 			}
   2500 
   2501 		if (profile.HasLookTable ())
   2502 			{
   2503 
   2504 			uint32 hueDivs = 0;
   2505 			uint32 satDivs = 0;
   2506 			uint32 valDivs = 0;
   2507 
   2508 			profile.LookTable ().GetDivisions (hueDivs,
   2509 											   satDivs,
   2510 											   valDivs);
   2511 
   2512 			fLookTableDimData [0] = hueDivs;
   2513 			fLookTableDimData [1] = satDivs;
   2514 			fLookTableDimData [2] = valDivs;
   2515 
   2516 			directory.Add (&fLookTableDims);
   2517 
   2518 			directory.Add (&fLookTableData);
   2519 
   2520 			// Don't bother including the ProfileLookTableEncoding tag unless it's
   2521 			// non-linear.
   2522 
   2523 			if (profile.LookTableEncoding () != encoding_Linear)
   2524 				{
   2525 
   2526 				directory.Add (&fLookTableEncodingTag);
   2527 
   2528 				}
   2529 
   2530 			}
   2531 
   2532 		// Don't bother including the BaselineExposureOffset tag unless it's both
   2533 		// valid and non-zero.
   2534 
   2535 		if (profile.BaselineExposureOffset ().IsValid ())
   2536 			{
   2537 
   2538 			if (profile.BaselineExposureOffset ().As_real64 () != 0.0)
   2539 				{
   2540 
   2541 				directory.Add (&fBaselineExposureOffsetTag);
   2542 
   2543 				}
   2544 
   2545 			}
   2546 
   2547 		if (profile.DefaultBlackRender () != defaultBlackRender_Auto)
   2548 			{
   2549 
   2550 			directory.Add (&fDefaultBlackRenderTag);
   2551 
   2552 			}
   2553 
   2554 		if (profile.ToneCurve ().IsValid ())
   2555 			{
   2556 
   2557 			// Tone curve stored as pairs of 32-bit coordinates.  Probably could do with
   2558 			// 16-bits here, but should be small number of points so...
   2559 
   2560 			uint32 toneCurvePoints = (uint32) (profile.ToneCurve ().fCoord.size ());
   2561 
   2562 			fToneCurveBuffer.Allocate (SafeUint32Mult(toneCurvePoints, 2),
   2563 									   sizeof (real32));
   2564 
   2565 			real32 *points = fToneCurveBuffer.Buffer_real32 ();
   2566 
   2567 			fToneCurveTag.SetCount (toneCurvePoints * 2);
   2568 			fToneCurveTag.SetData  (points);
   2569 
   2570 			for (uint32 i = 0; i < toneCurvePoints; i++)
   2571 				{
   2572 
   2573 				// Transpose coordinates so they are in a more expected
   2574 				// order (domain -> range).
   2575 
   2576 				points [i * 2    ] = (real32) profile.ToneCurve ().fCoord [i].h;
   2577 				points [i * 2 + 1] = (real32) profile.ToneCurve ().fCoord [i].v;
   2578 
   2579 				}
   2580 
   2581 			directory.Add (&fToneCurveTag);
   2582 
   2583 			}
   2584 
   2585 		}
   2586 
   2587 	}
   2588 
   2589 /******************************************************************************/
   2590 
   2591 tiff_dng_extended_color_profile::tiff_dng_extended_color_profile
   2592 								 (const dng_camera_profile &profile)
   2593 
   2594 	:	fProfile (profile)
   2595 
   2596 	{
   2597 
   2598 	}
   2599 
   2600 /******************************************************************************/
   2601 
   2602 void tiff_dng_extended_color_profile::Put (dng_stream &stream,
   2603 										   bool includeModelRestriction)
   2604 	{
   2605 
   2606 	// Profile header.
   2607 
   2608 	stream.Put_uint16 (stream.BigEndian () ? byteOrderMM : byteOrderII);
   2609 
   2610 	stream.Put_uint16 (magicExtendedProfile);
   2611 
   2612 	stream.Put_uint32 (8);
   2613 
   2614 	// Profile tags.
   2615 
   2616 	profile_tag_set tagSet (*this, fProfile);
   2617 
   2618 	// Camera this profile is for.
   2619 
   2620 	tag_string cameraModelTag (tcUniqueCameraModel,
   2621 							   fProfile.UniqueCameraModelRestriction ());
   2622 
   2623 	if (includeModelRestriction)
   2624 		{
   2625 
   2626 		if (fProfile.UniqueCameraModelRestriction ().NotEmpty ())
   2627 			{
   2628 
   2629 			Add (&cameraModelTag);
   2630 
   2631 			}
   2632 
   2633 		}
   2634 
   2635 	// Write it all out.
   2636 
   2637 	dng_tiff_directory::Put (stream, offsetsRelativeToExplicitBase, 8);
   2638 
   2639 	}
   2640 
   2641 /*****************************************************************************/
   2642 
   2643 tag_dng_noise_profile::tag_dng_noise_profile (const dng_noise_profile &profile)
   2644 
   2645 	:	tag_data_ptr (tcNoiseProfile,
   2646 					  ttDouble,
   2647 					  2 * profile.NumFunctions (),
   2648 					  fValues)
   2649 
   2650 	{
   2651 
   2652 	DNG_REQUIRE (profile.NumFunctions () <= kMaxColorPlanes,
   2653 				 "Too many noise functions in tag_dng_noise_profile.");
   2654 
   2655 	for (uint32 i = 0; i < profile.NumFunctions (); i++)
   2656 		{
   2657 
   2658 		fValues [(2 * i)	] = profile.NoiseFunction (i).Scale	 ();
   2659 		fValues [(2 * i) + 1] = profile.NoiseFunction (i).Offset ();
   2660 
   2661 		}
   2662 
   2663 	}
   2664 
   2665 /*****************************************************************************/
   2666 
   2667 dng_image_writer::dng_image_writer ()
   2668 	{
   2669 
   2670 	}
   2671 
   2672 /*****************************************************************************/
   2673 
   2674 dng_image_writer::~dng_image_writer ()
   2675 	{
   2676 
   2677 	}
   2678 
   2679 /*****************************************************************************/
   2680 
   2681 uint32 dng_image_writer::CompressedBufferSize (const dng_ifd &ifd,
   2682 											   uint32 uncompressedSize)
   2683 	{
   2684 
   2685 	switch (ifd.fCompression)
   2686 		{
   2687 
   2688 		case ccLZW:
   2689 			{
   2690 
   2691 			// Add lots of slop for LZW to expand data.
   2692 
   2693 			return SafeUint32Add (SafeUint32Mult (uncompressedSize, 2), 1024);
   2694 
   2695 			}
   2696 
   2697 		case ccDeflate:
   2698 			{
   2699 
   2700 			// ZLib says maximum is source size + 0.1% + 12 bytes.
   2701 
   2702 			return SafeUint32Add (SafeUint32Add (uncompressedSize,
   2703 												 uncompressedSize >> 8), 64);
   2704 
   2705 			}
   2706 
   2707 		case ccJPEG:
   2708 			{
   2709 
   2710 			// If we are saving lossless JPEG from an 8-bit image, reserve
   2711 			// space to pad the data out to 16-bits.
   2712 
   2713 			if (ifd.fBitsPerSample [0] <= 8)
   2714 				{
   2715 
   2716 				return SafeUint32Mult (uncompressedSize, 2);
   2717 
   2718 				}
   2719 
   2720 			break;
   2721 
   2722 			}
   2723 
   2724 		default:
   2725 			break;
   2726 
   2727 		}
   2728 
   2729 	return 0;
   2730 
   2731 	}
   2732 
   2733 /******************************************************************************/
   2734 
   2735 static void EncodeDelta8 (uint8 *dPtr,
   2736 						  uint32 rows,
   2737 						  uint32 cols,
   2738 						  uint32 channels)
   2739 	{
   2740 
   2741 	const uint32 dRowStep = cols * channels;
   2742 
   2743 	for (uint32 row = 0; row < rows; row++)
   2744 		{
   2745 
   2746 		for (uint32 col = cols - 1; col > 0; col--)
   2747 			{
   2748 
   2749 			for (uint32 channel = 0; channel < channels; channel++)
   2750 				{
   2751 
   2752 				dPtr [col * channels + channel] -= dPtr [(col - 1) * channels + channel];
   2753 
   2754 				}
   2755 
   2756 			}
   2757 
   2758 		dPtr += dRowStep;
   2759 
   2760 		}
   2761 
   2762 	}
   2763 
   2764 /******************************************************************************/
   2765 
   2766 static void EncodeDelta16 (uint16 *dPtr,
   2767 						   uint32 rows,
   2768 						   uint32 cols,
   2769 						   uint32 channels)
   2770 	{
   2771 
   2772 	const uint32 dRowStep = cols * channels;
   2773 
   2774 	for (uint32 row = 0; row < rows; row++)
   2775 		{
   2776 
   2777 		for (uint32 col = cols - 1; col > 0; col--)
   2778 			{
   2779 
   2780 			for (uint32 channel = 0; channel < channels; channel++)
   2781 				{
   2782 
   2783 				dPtr [col * channels + channel] -= dPtr [(col - 1) * channels + channel];
   2784 
   2785 				}
   2786 
   2787 			}
   2788 
   2789 		dPtr += dRowStep;
   2790 
   2791 		}
   2792 
   2793 	}
   2794 
   2795 /******************************************************************************/
   2796 
   2797 static void EncodeDelta32 (uint32 *dPtr,
   2798 						   uint32 rows,
   2799 						   uint32 cols,
   2800 						   uint32 channels)
   2801 	{
   2802 
   2803 	const uint32 dRowStep = cols * channels;
   2804 
   2805 	for (uint32 row = 0; row < rows; row++)
   2806 		{
   2807 
   2808 		for (uint32 col = cols - 1; col > 0; col--)
   2809 			{
   2810 
   2811 			for (uint32 channel = 0; channel < channels; channel++)
   2812 				{
   2813 
   2814 				dPtr [col * channels + channel] -= dPtr [(col - 1) * channels + channel];
   2815 
   2816 				}
   2817 
   2818 			}
   2819 
   2820 		dPtr += dRowStep;
   2821 
   2822 		}
   2823 
   2824 	}
   2825 
   2826 /*****************************************************************************/
   2827 
   2828 inline void EncodeDeltaBytes (uint8 *bytePtr, int32 cols, int32 channels)
   2829 	{
   2830 
   2831 	if (channels == 1)
   2832 		{
   2833 
   2834 		bytePtr += (cols - 1);
   2835 
   2836 		uint8 this0 = bytePtr [0];
   2837 
   2838 		for (int32 col = 1; col < cols; col++)
   2839 			{
   2840 
   2841 			uint8 prev0 = bytePtr [-1];
   2842 
   2843 			this0 -= prev0;
   2844 
   2845 			bytePtr [0] = this0;
   2846 
   2847 			this0 = prev0;
   2848 
   2849 			bytePtr -= 1;
   2850 
   2851 			}
   2852 
   2853 		}
   2854 
   2855 	else if (channels == 3)
   2856 		{
   2857 
   2858 		bytePtr += (cols - 1) * 3;
   2859 
   2860 		uint8 this0 = bytePtr [0];
   2861 		uint8 this1 = bytePtr [1];
   2862 		uint8 this2 = bytePtr [2];
   2863 
   2864 		for (int32 col = 1; col < cols; col++)
   2865 			{
   2866 
   2867 			uint8 prev0 = bytePtr [-3];
   2868 			uint8 prev1 = bytePtr [-2];
   2869 			uint8 prev2 = bytePtr [-1];
   2870 
   2871 			this0 -= prev0;
   2872 			this1 -= prev1;
   2873 			this2 -= prev2;
   2874 
   2875 			bytePtr [0] = this0;
   2876 			bytePtr [1] = this1;
   2877 			bytePtr [2] = this2;
   2878 
   2879 			this0 = prev0;
   2880 			this1 = prev1;
   2881 			this2 = prev2;
   2882 
   2883 			bytePtr -= 3;
   2884 
   2885 			}
   2886 
   2887 		}
   2888 
   2889 	else
   2890 		{
   2891 
   2892 		uint32 rowBytes = cols * channels;
   2893 
   2894 		bytePtr += rowBytes - 1;
   2895 
   2896 		for (uint32 col = channels; col < rowBytes; col++)
   2897 			{
   2898 
   2899 			bytePtr [0] -= bytePtr [-channels];
   2900 
   2901 			bytePtr--;
   2902 
   2903 			}
   2904 
   2905 		}
   2906 
   2907 	}
   2908 
   2909 /*****************************************************************************/
   2910 
   2911 static void EncodeFPDelta (uint8 *buffer,
   2912 						   uint8 *temp,
   2913 						   int32 cols,
   2914 						   int32 channels,
   2915 						   int32 bytesPerSample)
   2916 	{
   2917 
   2918 	int32 rowIncrement = cols * channels;
   2919 
   2920 	if (bytesPerSample == 2)
   2921 		{
   2922 
   2923 		const uint8 *src = buffer;
   2924 
   2925 		#if qDNGBigEndian
   2926 		uint8 *dst0 = temp;
   2927 		uint8 *dst1 = temp + rowIncrement;
   2928 		#else
   2929 		uint8 *dst1 = temp;
   2930 		uint8 *dst0 = temp + rowIncrement;
   2931 		#endif
   2932 
   2933 		for (int32 col = 0; col < rowIncrement; ++col)
   2934 			{
   2935 
   2936 			dst0 [col] = src [0];
   2937 			dst1 [col] = src [1];
   2938 
   2939 			src += 2;
   2940 
   2941 			}
   2942 
   2943 		}
   2944 
   2945 	else if (bytesPerSample == 3)
   2946 		{
   2947 
   2948 		const uint8 *src = buffer;
   2949 
   2950 		uint8 *dst0 = temp;
   2951 		uint8 *dst1 = temp + rowIncrement;
   2952 		uint8 *dst2 = temp + rowIncrement * 2;
   2953 
   2954 		for (int32 col = 0; col < rowIncrement; ++col)
   2955 			{
   2956 
   2957 			dst0 [col] = src [0];
   2958 			dst1 [col] = src [1];
   2959 			dst2 [col] = src [2];
   2960 
   2961 			src += 3;
   2962 
   2963 			}
   2964 
   2965 		}
   2966 
   2967 	else
   2968 		{
   2969 
   2970 		const uint8 *src = buffer;
   2971 
   2972 		#if qDNGBigEndian
   2973 		uint8 *dst0 = temp;
   2974 		uint8 *dst1 = temp + rowIncrement;
   2975 		uint8 *dst2 = temp + rowIncrement * 2;
   2976 		uint8 *dst3 = temp + rowIncrement * 3;
   2977 		#else
   2978 		uint8 *dst3 = temp;
   2979 		uint8 *dst2 = temp + rowIncrement;
   2980 		uint8 *dst1 = temp + rowIncrement * 2;
   2981 		uint8 *dst0 = temp + rowIncrement * 3;
   2982 		#endif
   2983 
   2984 		for (int32 col = 0; col < rowIncrement; ++col)
   2985 			{
   2986 
   2987 			dst0 [col] = src [0];
   2988 			dst1 [col] = src [1];
   2989 			dst2 [col] = src [2];
   2990 			dst3 [col] = src [3];
   2991 
   2992 			src += 4;
   2993 
   2994 			}
   2995 
   2996 		}
   2997 
   2998 	EncodeDeltaBytes (temp, cols*bytesPerSample, channels);
   2999 
   3000 	memcpy (buffer, temp, cols*bytesPerSample*channels);
   3001 
   3002 	}
   3003 
   3004 /*****************************************************************************/
   3005 
   3006 void dng_image_writer::EncodePredictor (dng_host &host,
   3007 									    const dng_ifd &ifd,
   3008 						        	    dng_pixel_buffer &buffer,
   3009 										AutoPtr<dng_memory_block> &tempBuffer)
   3010 	{
   3011 
   3012 	switch (ifd.fPredictor)
   3013 		{
   3014 
   3015 		case cpHorizontalDifference:
   3016 		case cpHorizontalDifferenceX2:
   3017 		case cpHorizontalDifferenceX4:
   3018 			{
   3019 
   3020 			int32 xFactor = 1;
   3021 
   3022 			if (ifd.fPredictor == cpHorizontalDifferenceX2)
   3023 				{
   3024 				xFactor = 2;
   3025 				}
   3026 
   3027 			else if (ifd.fPredictor == cpHorizontalDifferenceX4)
   3028 				{
   3029 				xFactor = 4;
   3030 				}
   3031 
   3032 			switch (buffer.fPixelType)
   3033 				{
   3034 
   3035 				case ttByte:
   3036 					{
   3037 
   3038 					EncodeDelta8 ((uint8 *) buffer.fData,
   3039 								  buffer.fArea.H (),
   3040 								  buffer.fArea.W () / xFactor,
   3041 								  buffer.fPlanes    * xFactor);
   3042 
   3043 					return;
   3044 
   3045 					}
   3046 
   3047 				case ttShort:
   3048 					{
   3049 
   3050 					EncodeDelta16 ((uint16 *) buffer.fData,
   3051 								   buffer.fArea.H (),
   3052 								   buffer.fArea.W () / xFactor,
   3053 								   buffer.fPlanes    * xFactor);
   3054 
   3055 					return;
   3056 
   3057 					}
   3058 
   3059 				case ttLong:
   3060 					{
   3061 
   3062 					EncodeDelta32 ((uint32 *) buffer.fData,
   3063 								   buffer.fArea.H (),
   3064 								   buffer.fArea.W () / xFactor,
   3065 								   buffer.fPlanes    * xFactor);
   3066 
   3067 					return;
   3068 
   3069 					}
   3070 
   3071 				default:
   3072 					break;
   3073 
   3074 				}
   3075 
   3076 			break;
   3077 
   3078 			}
   3079 
   3080 		case cpFloatingPoint:
   3081 		case cpFloatingPointX2:
   3082 		case cpFloatingPointX4:
   3083 			{
   3084 
   3085 			int32 xFactor = 1;
   3086 
   3087 			if (ifd.fPredictor == cpFloatingPointX2)
   3088 				{
   3089 				xFactor = 2;
   3090 				}
   3091 
   3092 			else if (ifd.fPredictor == cpFloatingPointX4)
   3093 				{
   3094 				xFactor = 4;
   3095 				}
   3096 
   3097 			if (buffer.fRowStep < 0)
   3098 				{
   3099 				ThrowProgramError ("Row step may not be negative");
   3100 				}
   3101 			uint32 tempBufferSize = SafeUint32Mult (
   3102 				static_cast<uint32>(buffer.fRowStep),
   3103 				buffer.fPixelSize);
   3104 
   3105 			if (!tempBuffer.Get () || tempBuffer->LogicalSize () < tempBufferSize)
   3106 				{
   3107 
   3108 				tempBuffer.Reset (host.Allocate (tempBufferSize));
   3109 
   3110 				}
   3111 
   3112 			for (int32 row = buffer.fArea.t; row < buffer.fArea.b; row++)
   3113 				{
   3114 
   3115 				EncodeFPDelta ((uint8 *) buffer.DirtyPixel (row, buffer.fArea.l, buffer.fPlane),
   3116 							   tempBuffer->Buffer_uint8 (),
   3117 							   buffer.fArea.W () / xFactor,
   3118 							   buffer.fPlanes    * xFactor,
   3119 							   buffer.fPixelSize);
   3120 
   3121 				}
   3122 
   3123 			return;
   3124 
   3125 			}
   3126 
   3127 		default:
   3128 			break;
   3129 
   3130 		}
   3131 
   3132 	if (ifd.fPredictor != cpNullPredictor)
   3133 		{
   3134 
   3135 		ThrowProgramError ();
   3136 
   3137 		}
   3138 
   3139 	}
   3140 
   3141 /*****************************************************************************/
   3142 
   3143 void dng_image_writer::ByteSwapBuffer (dng_host & /* host */,
   3144 									   dng_pixel_buffer &buffer)
   3145 	{
   3146 
   3147 	uint32 pixels = buffer.fRowStep * buffer.fArea.H ();
   3148 
   3149 	switch (buffer.fPixelSize)
   3150 		{
   3151 
   3152 		case 2:
   3153 			{
   3154 
   3155 			DoSwapBytes16 ((uint16 *) buffer.fData,
   3156 						   pixels);
   3157 
   3158 			break;
   3159 
   3160 			}
   3161 
   3162 		case 4:
   3163 			{
   3164 
   3165 			DoSwapBytes32 ((uint32 *) buffer.fData,
   3166 						   pixels);
   3167 
   3168 			break;
   3169 
   3170 			}
   3171 
   3172 		default:
   3173 			break;
   3174 
   3175 		}
   3176 
   3177 	}
   3178 
   3179 /*****************************************************************************/
   3180 
   3181 void dng_image_writer::ReorderSubTileBlocks (const dng_ifd &ifd,
   3182 											 dng_pixel_buffer &buffer,
   3183 											 AutoPtr<dng_memory_block> &uncompressedBuffer,
   3184 											 AutoPtr<dng_memory_block> &subTileBlockBuffer)
   3185 	{
   3186 
   3187 	uint32 blockRows = ifd.fSubTileBlockRows;
   3188 	uint32 blockCols = ifd.fSubTileBlockCols;
   3189 
   3190 	uint32 rowBlocks = buffer.fArea.H () / blockRows;
   3191 	uint32 colBlocks = buffer.fArea.W () / blockCols;
   3192 
   3193 	int32 rowStep = buffer.fRowStep * buffer.fPixelSize;
   3194 	int32 colStep = buffer.fColStep * buffer.fPixelSize;
   3195 
   3196 	int32 rowBlockStep = rowStep * blockRows;
   3197 	int32 colBlockStep = colStep * blockCols;
   3198 
   3199 	uint32 blockColBytes = blockCols * buffer.fPlanes * buffer.fPixelSize;
   3200 
   3201 	const uint8 *s0 = uncompressedBuffer->Buffer_uint8 ();
   3202 	      uint8 *d0 = subTileBlockBuffer->Buffer_uint8 ();
   3203 
   3204 	for (uint32 rowBlock = 0; rowBlock < rowBlocks; rowBlock++)
   3205 		{
   3206 
   3207 		const uint8 *s1 = s0;
   3208 
   3209 		for (uint32 colBlock = 0; colBlock < colBlocks; colBlock++)
   3210 			{
   3211 
   3212 			const uint8 *s2 = s1;
   3213 
   3214 			for (uint32 blockRow = 0; blockRow < blockRows; blockRow++)
   3215 				{
   3216 
   3217 				for (uint32 j = 0; j < blockColBytes; j++)
   3218 					{
   3219 
   3220 					d0 [j] = s2 [j];
   3221 
   3222 					}
   3223 
   3224 				d0 += blockColBytes;
   3225 
   3226 				s2 += rowStep;
   3227 
   3228 				}
   3229 
   3230 			s1 += colBlockStep;
   3231 
   3232 			}
   3233 
   3234 		s0 += rowBlockStep;
   3235 
   3236 		}
   3237 
   3238 	// Copy back reordered pixels.
   3239 
   3240 	DoCopyBytes (subTileBlockBuffer->Buffer      (),
   3241 				 uncompressedBuffer->Buffer      (),
   3242 				 uncompressedBuffer->LogicalSize ());
   3243 
   3244 	}
   3245 
   3246 /******************************************************************************/
   3247 
   3248 class dng_lzw_compressor
   3249 	{
   3250 
   3251 	private:
   3252 
   3253 		enum
   3254 			{
   3255 			kResetCode = 256,
   3256 			kEndCode   = 257,
   3257 			kTableSize = 4096
   3258 			};
   3259 
   3260 		// Compressor nodes have two son pointers.  The low order bit of
   3261 		// the next code determines which pointer is used.  This cuts the
   3262 		// number of nodes searched for the next code by two on average.
   3263 
   3264 		struct LZWCompressorNode
   3265 			{
   3266 			int16 final;
   3267 			int16 son0;
   3268 			int16 son1;
   3269 			int16 brother;
   3270 			};
   3271 
   3272 		dng_memory_data fBuffer;
   3273 
   3274 		LZWCompressorNode *fTable;
   3275 
   3276 		uint8 *fDstPtr;
   3277 
   3278 		int32 fDstCount;
   3279 
   3280 		int32 fBitOffset;
   3281 
   3282 		int32 fNextCode;
   3283 
   3284 		int32 fCodeSize;
   3285 
   3286 	public:
   3287 
   3288 		dng_lzw_compressor ();
   3289 
   3290 		void Compress (const uint8 *sPtr,
   3291 					   uint8 *dPtr,
   3292 					   uint32 sCount,
   3293 					   uint32 &dCount);
   3294 
   3295 	private:
   3296 
   3297 		void InitTable ();
   3298 
   3299 		int32 SearchTable (int32 w, int32 k) const
   3300 			{
   3301 
   3302 			DNG_ASSERT ((w >= 0) && (w <= kTableSize),
   3303 						"Bad w value in dng_lzw_compressor::SearchTable");
   3304 
   3305 			int32 son0 = fTable [w] . son0;
   3306 			int32 son1 = fTable [w] . son1;
   3307 
   3308 			// Branchless version of:
   3309 			// int32 code = (k & 1) ? son1 : son0;
   3310 
   3311 			int32 code = son0 + ((-((int32) (k & 1))) & (son1 - son0));
   3312 
   3313 			while (code > 0 && fTable [code].final != k)
   3314 				{
   3315 				code = fTable [code].brother;
   3316 				}
   3317 
   3318 			return code;
   3319 
   3320 			}
   3321 
   3322 		void AddTable (int32 w, int32 k);
   3323 
   3324 		void PutCodeWord (int32 code);
   3325 
   3326 		// Hidden copy constructor and assignment operator.
   3327 
   3328 		dng_lzw_compressor (const dng_lzw_compressor &compressor);
   3329 
   3330 		dng_lzw_compressor & operator= (const dng_lzw_compressor &compressor);
   3331 
   3332 	};
   3333 
   3334 /******************************************************************************/
   3335 
   3336 dng_lzw_compressor::dng_lzw_compressor ()
   3337 
   3338 	:	fBuffer    ()
   3339 	,	fTable     (NULL)
   3340 	,	fDstPtr    (NULL)
   3341 	,	fDstCount  (0)
   3342 	,	fBitOffset (0)
   3343 	,	fNextCode  (0)
   3344 	,	fCodeSize  (0)
   3345 
   3346 	{
   3347 
   3348 	fBuffer.Allocate (kTableSize, sizeof (LZWCompressorNode));
   3349 
   3350 	fTable = (LZWCompressorNode *) fBuffer.Buffer ();
   3351 
   3352 	}
   3353 
   3354 /******************************************************************************/
   3355 
   3356 void dng_lzw_compressor::InitTable ()
   3357 	{
   3358 
   3359 	fCodeSize = 9;
   3360 
   3361 	fNextCode = 258;
   3362 
   3363 	LZWCompressorNode *node = &fTable [0];
   3364 
   3365 	for (int32 code = 0; code < 256; ++code)
   3366 		{
   3367 
   3368 		node->final   = (int16) code;
   3369 		node->son0    = -1;
   3370 		node->son1    = -1;
   3371 		node->brother = -1;
   3372 
   3373 		node++;
   3374 
   3375 		}
   3376 
   3377 	}
   3378 
   3379 /******************************************************************************/
   3380 
   3381 void dng_lzw_compressor::AddTable (int32 w, int32 k)
   3382 	{
   3383 
   3384 	DNG_ASSERT ((w >= 0) && (w <= kTableSize),
   3385 				"Bad w value in dng_lzw_compressor::AddTable");
   3386 
   3387 	LZWCompressorNode *node = &fTable [w];
   3388 
   3389 	int32 nextCode = fNextCode;
   3390 
   3391 	DNG_ASSERT ((nextCode >= 0) && (nextCode <= kTableSize),
   3392 				"Bad fNextCode value in dng_lzw_compressor::AddTable");
   3393 
   3394 	LZWCompressorNode *node2 = &fTable [nextCode];
   3395 
   3396 	fNextCode++;
   3397 
   3398 	int32 oldSon;
   3399 
   3400 	if( k&1 )
   3401 		{
   3402 		oldSon = node->son1;
   3403 		node->son1 = (int16) nextCode;
   3404 		}
   3405 	else
   3406 		{
   3407 		oldSon = node->son0;
   3408 		node->son0 = (int16) nextCode;
   3409 		}
   3410 
   3411 	node2->final   = (int16) k;
   3412 	node2->son0    = -1;
   3413 	node2->son1    = -1;
   3414 	node2->brother = (int16) oldSon;
   3415 
   3416 	if (nextCode == (1 << fCodeSize) - 1)
   3417 		{
   3418 		if (fCodeSize != 12)
   3419 			fCodeSize++;
   3420 		}
   3421 
   3422 	}
   3423 
   3424 /******************************************************************************/
   3425 
   3426 void dng_lzw_compressor::PutCodeWord (int32 code)
   3427 	{
   3428 
   3429 	int32 bit = (int32) (fBitOffset & 7);
   3430 
   3431 	int32 offset1 = fBitOffset >> 3;
   3432 	int32 offset2 = (fBitOffset + fCodeSize - 1) >> 3;
   3433 
   3434 	int32 shift1 = (fCodeSize + bit) -  8;
   3435 	int32 shift2 = (fCodeSize + bit) - 16;
   3436 
   3437 	uint8 byte1 = (uint8) (code >> shift1);
   3438 
   3439 	uint8 *dstPtr1 = fDstPtr + offset1;
   3440 	uint8 *dstPtr3 = fDstPtr + offset2;
   3441 
   3442 	if (offset1 + 1 == offset2)
   3443 		{
   3444 
   3445 		uint8 byte2 = (uint8) (code << (-shift2));
   3446 
   3447 		if (bit)
   3448 			*dstPtr1 |= byte1;
   3449 		else
   3450 			*dstPtr1 = byte1;
   3451 
   3452 		*dstPtr3 = byte2;
   3453 
   3454 		}
   3455 
   3456 	else
   3457 		{
   3458 
   3459 		int32 shift3 = (fCodeSize + bit) - 24;
   3460 
   3461 		uint8 byte2 = (uint8) (code >> shift2);
   3462 		uint8 byte3 = (uint8) (code << (-shift3));
   3463 
   3464 		uint8 *dstPtr2 = fDstPtr + (offset1 + 1);
   3465 
   3466 		if (bit)
   3467 			*dstPtr1 |= byte1;
   3468 		else
   3469 			*dstPtr1 = byte1;
   3470 
   3471 		*dstPtr2 = byte2;
   3472 
   3473 		*dstPtr3 = byte3;
   3474 
   3475 		}
   3476 
   3477 	fBitOffset += fCodeSize;
   3478 
   3479 	}
   3480 
   3481 /******************************************************************************/
   3482 
   3483 void dng_lzw_compressor::Compress (const uint8 *sPtr,
   3484 						           uint8 *dPtr,
   3485 						           uint32 sCount,
   3486 						           uint32 &dCount)
   3487 	{
   3488 
   3489 	fDstPtr = dPtr;
   3490 
   3491 	fBitOffset = 0;
   3492 
   3493 	InitTable ();
   3494 
   3495 	PutCodeWord (kResetCode);
   3496 
   3497 	int32 code = -1;
   3498 
   3499 	int32 pixel;
   3500 
   3501 	if (sCount > 0)
   3502 		{
   3503 
   3504 		pixel = *sPtr;
   3505 		sPtr = sPtr + 1;
   3506 		code = pixel;
   3507 
   3508 		sCount--;
   3509 
   3510 		while (sCount--)
   3511 			{
   3512 
   3513 			pixel = *sPtr;
   3514 			sPtr = sPtr + 1;
   3515 
   3516 			int32 newCode = SearchTable (code, pixel);
   3517 
   3518 			if (newCode == -1)
   3519 				{
   3520 
   3521 				PutCodeWord (code);
   3522 
   3523 				if (fNextCode < 4093)
   3524 					{
   3525 					AddTable (code, pixel);
   3526 					}
   3527 				else
   3528 					{
   3529 					PutCodeWord (kResetCode);
   3530 					InitTable ();
   3531 					}
   3532 
   3533 				code = pixel;
   3534 
   3535 				}
   3536 
   3537 			else
   3538 				code = newCode;
   3539 
   3540 			}
   3541 
   3542 		}
   3543 
   3544 	if (code != -1)
   3545 		{
   3546 		PutCodeWord (code);
   3547 		AddTable (code, 0);
   3548 		}
   3549 
   3550 	PutCodeWord (kEndCode);
   3551 
   3552 	dCount = (fBitOffset + 7) >> 3;
   3553 
   3554 	}
   3555 
   3556 /*****************************************************************************/
   3557 
   3558 #if qDNGUseLibJPEG
   3559 
   3560 /*****************************************************************************/
   3561 
   3562 static void dng_error_exit (j_common_ptr cinfo)
   3563 	{
   3564 
   3565 	// Output message.
   3566 
   3567 	(*cinfo->err->output_message) (cinfo);
   3568 
   3569 	// Convert to a dng_exception.
   3570 
   3571 	switch (cinfo->err->msg_code)
   3572 		{
   3573 
   3574 		case JERR_OUT_OF_MEMORY:
   3575 			{
   3576 			ThrowMemoryFull ();
   3577 			break;
   3578 			}
   3579 
   3580 		default:
   3581 			{
   3582 			ThrowBadFormat ();
   3583 			}
   3584 
   3585 		}
   3586 
   3587 	}
   3588 
   3589 /*****************************************************************************/
   3590 
   3591 static void dng_output_message (j_common_ptr cinfo)
   3592 	{
   3593 
   3594 	// Format message to string.
   3595 
   3596 	char buffer [JMSG_LENGTH_MAX];
   3597 
   3598 	(*cinfo->err->format_message) (cinfo, buffer);
   3599 
   3600 	// Report the libjpeg message as a warning.
   3601 
   3602 	ReportWarning ("libjpeg", buffer);
   3603 
   3604 	}
   3605 
   3606 /*****************************************************************************/
   3607 
   3608 struct dng_jpeg_stream_dest
   3609 	{
   3610 
   3611 	struct jpeg_destination_mgr pub;
   3612 
   3613 	dng_stream *fStream;
   3614 
   3615 	uint8 fBuffer [4096];
   3616 
   3617 	};
   3618 
   3619 /*****************************************************************************/
   3620 
   3621 static void dng_init_destination (j_compress_ptr cinfo)
   3622 	{
   3623 
   3624 	dng_jpeg_stream_dest *dest = (dng_jpeg_stream_dest *) cinfo->dest;
   3625 
   3626 	dest->pub.next_output_byte = dest->fBuffer;
   3627 	dest->pub.free_in_buffer   = sizeof (dest->fBuffer);
   3628 
   3629 	}
   3630 
   3631 /*****************************************************************************/
   3632 
   3633 static boolean dng_empty_output_buffer (j_compress_ptr cinfo)
   3634 	{
   3635 
   3636 	dng_jpeg_stream_dest *dest = (dng_jpeg_stream_dest *) cinfo->dest;
   3637 
   3638 	dest->fStream->Put (dest->fBuffer, sizeof (dest->fBuffer));
   3639 
   3640 	dest->pub.next_output_byte = dest->fBuffer;
   3641 	dest->pub.free_in_buffer   = sizeof (dest->fBuffer);
   3642 
   3643 	return TRUE;
   3644 
   3645 	}
   3646 
   3647 /*****************************************************************************/
   3648 
   3649 static void dng_term_destination (j_compress_ptr cinfo)
   3650 	{
   3651 
   3652 	dng_jpeg_stream_dest *dest = (dng_jpeg_stream_dest *) cinfo->dest;
   3653 
   3654 	uint32 datacount = sizeof (dest->fBuffer) -
   3655 					   (uint32) dest->pub.free_in_buffer;
   3656 
   3657 	if (datacount)
   3658 		{
   3659 		dest->fStream->Put (dest->fBuffer, datacount);
   3660 		}
   3661 
   3662 	}
   3663 
   3664 /*****************************************************************************/
   3665 
   3666 static void jpeg_set_adobe_quality (struct jpeg_compress_struct *cinfo,
   3667 									int32 quality)
   3668 	{
   3669 
   3670 	// If out of range, map to default.
   3671 
   3672 	if (quality < 0 || quality > 12)
   3673 		{
   3674 		quality = 10;
   3675 		}
   3676 
   3677 	// Adobe turns off chroma downsampling at high quality levels.
   3678 
   3679 	bool useChromaDownsampling = (quality <= 6);
   3680 
   3681 	// Approximate mapping from Adobe quality levels to LibJPEG levels.
   3682 
   3683 	const int kLibJPEGQuality [13] =
   3684 		{
   3685 		5, 11, 23, 34, 46, 63, 76, 77, 86, 90, 94, 97, 99
   3686 		};
   3687 
   3688 	quality = kLibJPEGQuality [quality];
   3689 
   3690 	jpeg_set_quality (cinfo, quality, TRUE);
   3691 
   3692 	// LibJPEG defaults to always using chroma downsampling.  Turn if off
   3693 	// if we need it off to match Adobe.
   3694 
   3695 	if (!useChromaDownsampling)
   3696 		{
   3697 
   3698 		cinfo->comp_info [0].h_samp_factor = 1;
   3699 		cinfo->comp_info [0].h_samp_factor = 1;
   3700 
   3701 		}
   3702 
   3703 	}
   3704 
   3705 /*****************************************************************************/
   3706 
   3707 #endif
   3708 
   3709 /*****************************************************************************/
   3710 
   3711 void dng_image_writer::WriteData (dng_host &host,
   3712 								  const dng_ifd &ifd,
   3713 						          dng_stream &stream,
   3714 						          dng_pixel_buffer &buffer,
   3715 								  AutoPtr<dng_memory_block> &compressedBuffer)
   3716 	{
   3717 
   3718 	switch (ifd.fCompression)
   3719 		{
   3720 
   3721 		case ccUncompressed:
   3722 			{
   3723 
   3724 			// Special case support for when we save to 8-bits from
   3725 			// 16-bit data.
   3726 
   3727 			if (ifd.fBitsPerSample [0] == 8 && buffer.fPixelType == ttShort)
   3728 				{
   3729 
   3730 				uint32 count = buffer.fRowStep *
   3731 							   buffer.fArea.H ();
   3732 
   3733 				const uint16 *sPtr = (const uint16 *) buffer.fData;
   3734 
   3735 				for (uint32 j = 0; j < count; j++)
   3736 					{
   3737 
   3738 					stream.Put_uint8 ((uint8) sPtr [j]);
   3739 
   3740 					}
   3741 
   3742 				}
   3743 
   3744 			else
   3745 				{
   3746 
   3747 				// Swap bytes if required.
   3748 
   3749 				if (stream.SwapBytes ())
   3750 					{
   3751 
   3752 					ByteSwapBuffer (host, buffer);
   3753 
   3754 					}
   3755 
   3756 				// Write the bytes.
   3757 
   3758 				stream.Put (buffer.fData, buffer.fRowStep *
   3759 										  buffer.fArea.H () *
   3760 										  buffer.fPixelSize);
   3761 
   3762 				}
   3763 
   3764 			break;
   3765 
   3766 			}
   3767 
   3768 		case ccLZW:
   3769 		case ccDeflate:
   3770 			{
   3771 
   3772 			// Both these compression algorithms are byte based.  The floating
   3773 			// point predictor already does byte ordering, so don't ever swap
   3774 			// when using it.
   3775 
   3776 			if (stream.SwapBytes () && ifd.fPredictor != cpFloatingPoint)
   3777 				{
   3778 
   3779 				ByteSwapBuffer (host,
   3780 								buffer);
   3781 
   3782 				}
   3783 
   3784 			// Run the compression algorithm.
   3785 
   3786 			uint32 sBytes = buffer.fRowStep *
   3787 							buffer.fArea.H () *
   3788 							buffer.fPixelSize;
   3789 
   3790 			uint8 *sBuffer = (uint8 *) buffer.fData;
   3791 
   3792 			uint32 dBytes = 0;
   3793 
   3794 			uint8 *dBuffer = compressedBuffer->Buffer_uint8 ();
   3795 
   3796 			if (ifd.fCompression == ccLZW)
   3797 				{
   3798 
   3799 				dng_lzw_compressor lzwCompressor;
   3800 
   3801 				lzwCompressor.Compress (sBuffer,
   3802 										dBuffer,
   3803 										sBytes,
   3804 										dBytes);
   3805 
   3806 				}
   3807 
   3808 			else
   3809 				{
   3810 
   3811 				uLongf dCount = compressedBuffer->LogicalSize ();
   3812 
   3813 				int32 level = Z_DEFAULT_COMPRESSION;
   3814 
   3815 				if (ifd.fCompressionQuality >= Z_BEST_SPEED &&
   3816 					ifd.fCompressionQuality <= Z_BEST_COMPRESSION)
   3817 					{
   3818 
   3819 					level = ifd.fCompressionQuality;
   3820 
   3821 					}
   3822 
   3823 				int zResult = ::compress2 (dBuffer,
   3824 										   &dCount,
   3825 										   sBuffer,
   3826 										   sBytes,
   3827 										   level);
   3828 
   3829 				if (zResult != Z_OK)
   3830 					{
   3831 
   3832 					ThrowMemoryFull ();
   3833 
   3834 					}
   3835 
   3836 				dBytes = (uint32) dCount;
   3837 
   3838 				}
   3839 
   3840 			if (dBytes > compressedBuffer->LogicalSize ())
   3841 				{
   3842 
   3843 				DNG_REPORT ("Compression output buffer overflow");
   3844 
   3845 				ThrowProgramError ();
   3846 
   3847 				}
   3848 
   3849 			stream.Put (dBuffer, dBytes);
   3850 
   3851 			return;
   3852 
   3853 			}
   3854 
   3855 		case ccJPEG:
   3856 			{
   3857 
   3858 			dng_pixel_buffer temp (buffer);
   3859 
   3860 			if (buffer.fPixelType == ttByte)
   3861 				{
   3862 
   3863 				// The lossless JPEG encoder needs 16-bit data, so if we are
   3864 				// are saving 8 bit data, we need to pad it out to 16-bits.
   3865 
   3866 				temp.fData = compressedBuffer->Buffer ();
   3867 
   3868 				temp.fPixelType = ttShort;
   3869 				temp.fPixelSize = 2;
   3870 
   3871 				temp.CopyArea (buffer,
   3872 							   buffer.fArea,
   3873 							   buffer.fPlane,
   3874 							   buffer.fPlanes);
   3875 
   3876 				}
   3877 
   3878 			EncodeLosslessJPEG ((const uint16 *) temp.fData,
   3879 								temp.fArea.H (),
   3880 								temp.fArea.W (),
   3881 								temp.fPlanes,
   3882 								ifd.fBitsPerSample [0],
   3883 								temp.fRowStep,
   3884 								temp.fColStep,
   3885 								stream);
   3886 
   3887 			break;
   3888 
   3889 			}
   3890 
   3891 		#if qDNGUseLibJPEG
   3892 
   3893 		case ccLossyJPEG:
   3894 			{
   3895 
   3896 			struct jpeg_compress_struct cinfo;
   3897 
   3898 			// Setup the error manager.
   3899 
   3900 			struct jpeg_error_mgr jerr;
   3901 
   3902 			cinfo.err = jpeg_std_error (&jerr);
   3903 
   3904 			jerr.error_exit     = dng_error_exit;
   3905 			jerr.output_message = dng_output_message;
   3906 
   3907 			try
   3908 				{
   3909 
   3910 				// Create the compression context.
   3911 
   3912 				jpeg_create_compress (&cinfo);
   3913 
   3914 				// Setup the destination manager to write to stream.
   3915 
   3916 				dng_jpeg_stream_dest dest;
   3917 
   3918 				dest.fStream = &stream;
   3919 
   3920 				dest.pub.init_destination    = dng_init_destination;
   3921 				dest.pub.empty_output_buffer = dng_empty_output_buffer;
   3922 				dest.pub.term_destination    = dng_term_destination;
   3923 
   3924 				cinfo.dest = &dest.pub;
   3925 
   3926 				// Setup basic image info.
   3927 
   3928 				cinfo.image_width      = buffer.fArea.W ();
   3929 				cinfo.image_height     = buffer.fArea.H ();
   3930 				cinfo.input_components = buffer.fPlanes;
   3931 
   3932 				switch (buffer.fPlanes)
   3933 					{
   3934 
   3935 					case 1:
   3936 						cinfo.in_color_space = JCS_GRAYSCALE;
   3937 						break;
   3938 
   3939 					case 3:
   3940 						cinfo.in_color_space = JCS_RGB;
   3941 						break;
   3942 
   3943 					case 4:
   3944 						cinfo.in_color_space = JCS_CMYK;
   3945 						break;
   3946 
   3947 					default:
   3948 						ThrowProgramError ();
   3949 
   3950 					}
   3951 
   3952 				// Setup the compression parameters.
   3953 
   3954 				jpeg_set_defaults (&cinfo);
   3955 
   3956 				jpeg_set_adobe_quality (&cinfo, ifd.fCompressionQuality);
   3957 
   3958 				// Write the JPEG header.
   3959 
   3960 				jpeg_start_compress (&cinfo, TRUE);
   3961 
   3962 				// Write the scanlines.
   3963 
   3964 				for (int32 row = buffer.fArea.t; row < buffer.fArea.b; row++)
   3965 					{
   3966 
   3967 					uint8 *sampArray [1];
   3968 
   3969 					sampArray [0] = buffer.DirtyPixel_uint8 (row,
   3970 															 buffer.fArea.l,
   3971 															 0);
   3972 
   3973 					jpeg_write_scanlines (&cinfo, sampArray, 1);
   3974 
   3975 					}
   3976 
   3977 				// Cleanup.
   3978 
   3979 				jpeg_finish_compress (&cinfo);
   3980 
   3981 				jpeg_destroy_compress (&cinfo);
   3982 
   3983 				}
   3984 
   3985 			catch (...)
   3986 				{
   3987 
   3988 				jpeg_destroy_compress (&cinfo);
   3989 
   3990 				throw;
   3991 
   3992 				}
   3993 
   3994 			return;
   3995 
   3996 			}
   3997 
   3998 		#endif
   3999 
   4000 		default:
   4001 			{
   4002 
   4003 			ThrowProgramError ();
   4004 
   4005 			}
   4006 
   4007 		}
   4008 
   4009 	}
   4010 
   4011 /******************************************************************************/
   4012 
   4013 void dng_image_writer::EncodeJPEGPreview (dng_host &host,
   4014 										  const dng_image &image,
   4015 										  dng_jpeg_preview &preview,
   4016 										  int32 quality)
   4017 	{
   4018 
   4019 	#if qDNGUseLibJPEG
   4020 
   4021 	dng_memory_stream stream (host.Allocator ());
   4022 
   4023 	struct jpeg_compress_struct cinfo;
   4024 
   4025 	// Setup the error manager.
   4026 
   4027 	struct jpeg_error_mgr jerr;
   4028 
   4029 	cinfo.err = jpeg_std_error (&jerr);
   4030 
   4031 	jerr.error_exit     = dng_error_exit;
   4032 	jerr.output_message = dng_output_message;
   4033 
   4034 	try
   4035 		{
   4036 
   4037 		// Create the compression context.
   4038 
   4039 		jpeg_create_compress (&cinfo);
   4040 
   4041 		// Setup the destination manager to write to stream.
   4042 
   4043 		dng_jpeg_stream_dest dest;
   4044 
   4045 		dest.fStream = &stream;
   4046 
   4047 		dest.pub.init_destination    = dng_init_destination;
   4048 		dest.pub.empty_output_buffer = dng_empty_output_buffer;
   4049 		dest.pub.term_destination    = dng_term_destination;
   4050 
   4051 		cinfo.dest = &dest.pub;
   4052 
   4053 		// Setup basic image info.
   4054 
   4055 		cinfo.image_width      = image.Bounds ().W ();
   4056 		cinfo.image_height     = image.Bounds ().H ();
   4057 		cinfo.input_components = image.Planes ();
   4058 
   4059 		switch (image.Planes ())
   4060 			{
   4061 
   4062 			case 1:
   4063 				cinfo.in_color_space = JCS_GRAYSCALE;
   4064 				break;
   4065 
   4066 			case 3:
   4067 				cinfo.in_color_space = JCS_RGB;
   4068 				break;
   4069 
   4070 			default:
   4071 				ThrowProgramError ();
   4072 
   4073 			}
   4074 
   4075 		// Setup the compression parameters.
   4076 
   4077 		jpeg_set_defaults (&cinfo);
   4078 
   4079 		jpeg_set_adobe_quality (&cinfo, quality);
   4080 
   4081 		// Find some preview information based on the compression settings.
   4082 
   4083 		preview.fPreviewSize = image.Size ();
   4084 
   4085 		if (image.Planes () == 1)
   4086 			{
   4087 
   4088 			preview.fPhotometricInterpretation = piBlackIsZero;
   4089 
   4090 			}
   4091 
   4092 		else
   4093 			{
   4094 
   4095 			preview.fPhotometricInterpretation = piYCbCr;
   4096 
   4097 			preview.fYCbCrSubSampling.h  = cinfo.comp_info [0].h_samp_factor;
   4098 			preview.fYCbCrSubSampling.v  = cinfo.comp_info [0].v_samp_factor;
   4099 
   4100 			}
   4101 
   4102 		// Write the JPEG header.
   4103 
   4104 		jpeg_start_compress (&cinfo, TRUE);
   4105 
   4106 		// Write the scanlines.
   4107 
   4108 		dng_pixel_buffer buffer (image.Bounds (), 0, image.Planes (), ttByte,
   4109 			 pcInterleaved, NULL);
   4110 
   4111 		AutoPtr<dng_memory_block> bufferData (host.Allocate (buffer.fRowStep));
   4112 
   4113 		buffer.fData = bufferData->Buffer ();
   4114 
   4115 		for (uint32 row = 0; row < cinfo.image_height; row++)
   4116 			{
   4117 
   4118 			buffer.fArea.t = row;
   4119 			buffer.fArea.b = row + 1;
   4120 
   4121 			image.Get (buffer);
   4122 
   4123 			uint8 *sampArray [1];
   4124 
   4125 			sampArray [0] = buffer.DirtyPixel_uint8 (row,
   4126 													 buffer.fArea.l,
   4127 													 0);
   4128 
   4129 			jpeg_write_scanlines (&cinfo, sampArray, 1);
   4130 
   4131 			}
   4132 
   4133 		// Cleanup.
   4134 
   4135 		jpeg_finish_compress (&cinfo);
   4136 
   4137 		jpeg_destroy_compress (&cinfo);
   4138 
   4139 		}
   4140 
   4141 	catch (...)
   4142 		{
   4143 
   4144 		jpeg_destroy_compress (&cinfo);
   4145 
   4146 		throw;
   4147 
   4148 		}
   4149 
   4150 	preview.fCompressedData.Reset (stream.AsMemoryBlock (host.Allocator ()));
   4151 
   4152 	#else
   4153 
   4154 	(void) host;
   4155 	(void) image;
   4156 	(void) preview;
   4157 	(void) quality;
   4158 
   4159 	ThrowProgramError ("No JPEG encoder");
   4160 
   4161 	#endif
   4162 
   4163 	}
   4164 
   4165 /*****************************************************************************/
   4166 
   4167 void dng_image_writer::WriteTile (dng_host &host,
   4168 						          const dng_ifd &ifd,
   4169 						          dng_stream &stream,
   4170 						          const dng_image &image,
   4171 						          const dng_rect &tileArea,
   4172 						          uint32 fakeChannels,
   4173 								  AutoPtr<dng_memory_block> &compressedBuffer,
   4174 								  AutoPtr<dng_memory_block> &uncompressedBuffer,
   4175 								  AutoPtr<dng_memory_block> &subTileBlockBuffer,
   4176 								  AutoPtr<dng_memory_block> &tempBuffer)
   4177 	{
   4178 
   4179 	// Create pixel buffer to hold uncompressed tile.
   4180 
   4181 	dng_pixel_buffer buffer (tileArea, 0, ifd.fSamplesPerPixel,
   4182 		 image.PixelType(), pcInterleaved, uncompressedBuffer->Buffer());
   4183 
   4184 	// Get the uncompressed data.
   4185 
   4186 	image.Get (buffer, dng_image::edge_zero);
   4187 
   4188 	// Deal with sub-tile blocks.
   4189 
   4190 	if (ifd.fSubTileBlockRows > 1)
   4191 		{
   4192 
   4193 		ReorderSubTileBlocks (ifd,
   4194 							  buffer,
   4195 							  uncompressedBuffer,
   4196 							  subTileBlockBuffer);
   4197 
   4198 		}
   4199 
   4200 	// Floating point depth conversion.
   4201 
   4202 	if (ifd.fSampleFormat [0] == sfFloatingPoint)
   4203 		{
   4204 
   4205 		if (ifd.fBitsPerSample [0] == 16)
   4206 			{
   4207 
   4208 			uint32 *srcPtr = (uint32 *) buffer.fData;
   4209 			uint16 *dstPtr = (uint16 *) buffer.fData;
   4210 
   4211 			uint32 pixels = tileArea.W () * tileArea.H () * buffer.fPlanes;
   4212 
   4213 			for (uint32 j = 0; j < pixels; j++)
   4214 				{
   4215 
   4216 				dstPtr [j] = DNG_FloatToHalf (srcPtr [j]);
   4217 
   4218 				}
   4219 
   4220 			buffer.fPixelSize = 2;
   4221 
   4222 			}
   4223 
   4224 		if (ifd.fBitsPerSample [0] == 24)
   4225 			{
   4226 
   4227 			uint32 *srcPtr = (uint32 *) buffer.fData;
   4228 			uint8  *dstPtr = (uint8  *) buffer.fData;
   4229 
   4230 			uint32 pixels = tileArea.W () * tileArea.H () * buffer.fPlanes;
   4231 
   4232 			if (stream.BigEndian () || ifd.fPredictor == cpFloatingPoint   ||
   4233 									   ifd.fPredictor == cpFloatingPointX2 ||
   4234 									   ifd.fPredictor == cpFloatingPointX4)
   4235 				{
   4236 
   4237 				for (uint32 j = 0; j < pixels; j++)
   4238 					{
   4239 
   4240 					DNG_FloatToFP24 (srcPtr [j], dstPtr);
   4241 
   4242 					dstPtr += 3;
   4243 
   4244 					}
   4245 
   4246 				}
   4247 
   4248 			else
   4249 				{
   4250 
   4251 				for (uint32 j = 0; j < pixels; j++)
   4252 					{
   4253 
   4254 					uint8 output [3];
   4255 
   4256 					DNG_FloatToFP24 (srcPtr [j], output);
   4257 
   4258 					dstPtr [0] = output [2];
   4259 					dstPtr [1] = output [1];
   4260 					dstPtr [2] = output [0];
   4261 
   4262 					dstPtr += 3;
   4263 
   4264 					}
   4265 
   4266 				}
   4267 
   4268 			buffer.fPixelSize = 3;
   4269 
   4270 			}
   4271 
   4272 		}
   4273 
   4274 	// Run predictor.
   4275 
   4276 	EncodePredictor (host,
   4277 					 ifd,
   4278 					 buffer,
   4279 					 tempBuffer);
   4280 
   4281 	// Adjust pixel buffer for fake channels.
   4282 
   4283 	if (fakeChannels > 1)
   4284 		{
   4285 
   4286 		buffer.fPlanes  *= fakeChannels;
   4287 		buffer.fColStep *= fakeChannels;
   4288 
   4289 		buffer.fArea.r = buffer.fArea.l + (buffer.fArea.W () / fakeChannels);
   4290 
   4291 		}
   4292 
   4293 	// Compress (if required) and write out the data.
   4294 
   4295 	WriteData (host,
   4296 			   ifd,
   4297 			   stream,
   4298 			   buffer,
   4299 			   compressedBuffer);
   4300 
   4301 	}
   4302 
   4303 /*****************************************************************************/
   4304 
   4305 class dng_write_tiles_task : public dng_area_task
   4306 	{
   4307 
   4308 	private:
   4309 
   4310 		dng_image_writer &fImageWriter;
   4311 
   4312 		dng_host &fHost;
   4313 
   4314 		const dng_ifd &fIFD;
   4315 
   4316 		dng_basic_tag_set &fBasic;
   4317 
   4318 		dng_stream &fStream;
   4319 
   4320 		const dng_image &fImage;
   4321 
   4322 		uint32 fFakeChannels;
   4323 
   4324 		uint32 fTilesDown;
   4325 
   4326 		uint32 fTilesAcross;
   4327 
   4328 		uint32 fCompressedSize;
   4329 
   4330 		uint32 fUncompressedSize;
   4331 
   4332 		dng_mutex fMutex1;
   4333 
   4334 		uint32 fNextTileIndex;
   4335 
   4336 		dng_mutex fMutex2;
   4337 
   4338 		dng_condition fCondition;
   4339 
   4340 		bool fTaskFailed;
   4341 
   4342 		uint32 fWriteTileIndex;
   4343 
   4344 	public:
   4345 
   4346 		dng_write_tiles_task (dng_image_writer &imageWriter,
   4347 							  dng_host &host,
   4348 							  const dng_ifd &ifd,
   4349 							  dng_basic_tag_set &basic,
   4350 							  dng_stream &stream,
   4351 							  const dng_image &image,
   4352 							  uint32 fakeChannels,
   4353 							  uint32 tilesDown,
   4354 							  uint32 tilesAcross,
   4355 							  uint32 compressedSize,
   4356 							  uint32 uncompressedSize)
   4357 
   4358 			:	fImageWriter      (imageWriter)
   4359 			,	fHost		      (host)
   4360 			,	fIFD		      (ifd)
   4361 			,	fBasic			  (basic)
   4362 			,	fStream		      (stream)
   4363 			,	fImage		      (image)
   4364 			,	fFakeChannels	  (fakeChannels)
   4365 			,	fTilesDown        (tilesDown)
   4366 			,	fTilesAcross	  (tilesAcross)
   4367 			,	fCompressedSize   (compressedSize)
   4368 			,	fUncompressedSize (uncompressedSize)
   4369 			,	fMutex1			  ("dng_write_tiles_task_1")
   4370 			,	fNextTileIndex	  (0)
   4371 			,	fMutex2			  ("dng_write_tiles_task_2")
   4372 			,	fCondition		  ()
   4373 			,	fTaskFailed		  (false)
   4374 			,	fWriteTileIndex	  (0)
   4375 
   4376 			{
   4377 
   4378 			fMinTaskArea = 16 * 16;
   4379 			fUnitCell    = dng_point (16, 16);
   4380 			fMaxTileSize = dng_point (16, 16);
   4381 
   4382 			}
   4383 
   4384 		void Process (uint32 /* threadIndex */,
   4385 					  const dng_rect & /* tile */,
   4386 					  dng_abort_sniffer *sniffer)
   4387 			{
   4388 
   4389 			try
   4390 				{
   4391 
   4392 				AutoPtr<dng_memory_block> compressedBuffer;
   4393 				AutoPtr<dng_memory_block> uncompressedBuffer;
   4394 				AutoPtr<dng_memory_block> subTileBlockBuffer;
   4395 				AutoPtr<dng_memory_block> tempBuffer;
   4396 
   4397 				if (fCompressedSize)
   4398 					{
   4399 					compressedBuffer.Reset (fHost.Allocate (fCompressedSize));
   4400 					}
   4401 
   4402 				if (fUncompressedSize)
   4403 					{
   4404 					uncompressedBuffer.Reset (fHost.Allocate (fUncompressedSize));
   4405 					}
   4406 
   4407 				if (fIFD.fSubTileBlockRows > 1 && fUncompressedSize)
   4408 					{
   4409 					subTileBlockBuffer.Reset (fHost.Allocate (fUncompressedSize));
   4410 					}
   4411 
   4412 				while (true)
   4413 					{
   4414 
   4415 					// Find tile index to compress.
   4416 
   4417 					uint32 tileIndex;
   4418 
   4419 						{
   4420 
   4421 						dng_lock_mutex lock (&fMutex1);
   4422 
   4423 						if (fNextTileIndex == fTilesDown * fTilesAcross)
   4424 							{
   4425 							return;
   4426 							}
   4427 
   4428 						tileIndex = fNextTileIndex++;
   4429 
   4430 						}
   4431 
   4432 					dng_abort_sniffer::SniffForAbort (sniffer);
   4433 
   4434 					// Compress tile.
   4435 
   4436 					uint32 rowIndex = tileIndex / fTilesAcross;
   4437 
   4438 					uint32 colIndex = tileIndex - rowIndex * fTilesAcross;
   4439 
   4440 					dng_rect tileArea = fIFD.TileArea (rowIndex, colIndex);
   4441 
   4442 					dng_memory_stream tileStream (fHost.Allocator ());
   4443 
   4444 					tileStream.SetLittleEndian (fStream.LittleEndian ());
   4445 
   4446 					dng_host host (&fHost.Allocator (),
   4447 								   sniffer);
   4448 
   4449 					fImageWriter.WriteTile (host,
   4450 											fIFD,
   4451 											tileStream,
   4452 											fImage,
   4453 											tileArea,
   4454 											fFakeChannels,
   4455 											compressedBuffer,
   4456 											uncompressedBuffer,
   4457 											subTileBlockBuffer,
   4458 											tempBuffer);
   4459 
   4460 					tileStream.Flush ();
   4461 
   4462 					uint32 tileByteCount = (uint32) tileStream.Length ();
   4463 
   4464 					tileStream.SetReadPosition (0);
   4465 
   4466 					// Wait until it is our turn to write tile.
   4467 
   4468 						{
   4469 
   4470 						dng_lock_mutex lock (&fMutex2);
   4471 
   4472 						while (!fTaskFailed &&
   4473 							   fWriteTileIndex != tileIndex)
   4474 							{
   4475 
   4476 							fCondition.Wait (fMutex2);
   4477 
   4478 							}
   4479 
   4480 						// If the task failed in another thread, that thread already threw an exception.
   4481 
   4482 						if (fTaskFailed)
   4483 							return;
   4484 
   4485 						}
   4486 
   4487 					dng_abort_sniffer::SniffForAbort (sniffer);
   4488 
   4489 					// Remember this offset.
   4490 
   4491 					uint32 tileOffset = (uint32) fStream.Position ();
   4492 
   4493 					fBasic.SetTileOffset (tileIndex, tileOffset);
   4494 
   4495 					// Copy tile stream for tile into main stream.
   4496 
   4497 					tileStream.CopyToStream (fStream, tileByteCount);
   4498 
   4499 					// Update tile count.
   4500 
   4501 					fBasic.SetTileByteCount (tileIndex, tileByteCount);
   4502 
   4503 					// Keep the tiles on even byte offsets.
   4504 
   4505 					if (tileByteCount & 1)
   4506 						{
   4507 						fStream.Put_uint8 (0);
   4508 						}
   4509 
   4510 					// Let other threads know it is safe to write to stream.
   4511 
   4512 						{
   4513 
   4514 						dng_lock_mutex lock (&fMutex2);
   4515 
   4516 						// If the task failed in another thread, that thread already threw an exception.
   4517 
   4518 						if (fTaskFailed)
   4519 							return;
   4520 
   4521 						fWriteTileIndex++;
   4522 
   4523 						fCondition.Broadcast ();
   4524 
   4525 						}
   4526 
   4527 					}
   4528 
   4529 				}
   4530 
   4531 			catch (...)
   4532 				{
   4533 
   4534 				// If first to fail, wake up any threads waiting on condition.
   4535 
   4536 				bool needBroadcast = false;
   4537 
   4538 					{
   4539 
   4540 					dng_lock_mutex lock (&fMutex2);
   4541 
   4542 					needBroadcast = !fTaskFailed;
   4543 					fTaskFailed = true;
   4544 
   4545 					}
   4546 
   4547 				if (needBroadcast)
   4548 					fCondition.Broadcast ();
   4549 
   4550 				throw;
   4551 
   4552 				}
   4553 
   4554 			}
   4555 
   4556 	private:
   4557 
   4558 		// Hidden copy constructor and assignment operator.
   4559 
   4560 		dng_write_tiles_task (const dng_write_tiles_task &);
   4561 
   4562 		dng_write_tiles_task & operator= (const dng_write_tiles_task &);
   4563 
   4564 	};
   4565 
   4566 /*****************************************************************************/
   4567 
   4568 void dng_image_writer::WriteImage (dng_host &host,
   4569 						           const dng_ifd &ifd,
   4570 						           dng_basic_tag_set &basic,
   4571 						           dng_stream &stream,
   4572 						           const dng_image &image,
   4573 						           uint32 fakeChannels)
   4574 	{
   4575 
   4576 	// Deal with row interleaved images.
   4577 
   4578 	if (ifd.fRowInterleaveFactor > 1 &&
   4579 		ifd.fRowInterleaveFactor < ifd.fImageLength)
   4580 		{
   4581 
   4582 		dng_ifd tempIFD (ifd);
   4583 
   4584 		tempIFD.fRowInterleaveFactor = 1;
   4585 
   4586 		dng_row_interleaved_image tempImage (*((dng_image *) &image),
   4587 											 ifd.fRowInterleaveFactor);
   4588 
   4589 		WriteImage (host,
   4590 					tempIFD,
   4591 					basic,
   4592 					stream,
   4593 					tempImage,
   4594 					fakeChannels);
   4595 
   4596 		return;
   4597 
   4598 		}
   4599 
   4600 	// Compute basic information.
   4601 
   4602 	uint32 bytesPerSample = TagTypeSize (image.PixelType ());
   4603 
   4604 	uint32 bytesPerPixel = SafeUint32Mult (ifd.fSamplesPerPixel,
   4605 										   bytesPerSample);
   4606 
   4607 	uint32 tileRowBytes = SafeUint32Mult (ifd.fTileWidth, bytesPerPixel);
   4608 
   4609 	// If we can compute the number of bytes needed to store the
   4610 	// data, we can split the write for each tile into sub-tiles.
   4611 
   4612 	uint32 subTileLength = ifd.fTileLength;
   4613 
   4614 	if (ifd.TileByteCount (ifd.TileArea (0, 0)) != 0)
   4615 		{
   4616 
   4617 		subTileLength = Pin_uint32 (ifd.fSubTileBlockRows,
   4618 									kImageBufferSize / tileRowBytes,
   4619 									ifd.fTileLength);
   4620 
   4621 		// Don't split sub-tiles across subTileBlocks.
   4622 
   4623 		subTileLength = subTileLength / ifd.fSubTileBlockRows
   4624 									  * ifd.fSubTileBlockRows;
   4625 
   4626 		}
   4627 
   4628 	// Find size of uncompressed buffer.
   4629 
   4630 	uint32 uncompressedSize = SafeUint32Mult(subTileLength, tileRowBytes);
   4631 
   4632 	// Find size of compressed buffer, if required.
   4633 
   4634 	uint32 compressedSize = CompressedBufferSize (ifd, uncompressedSize);
   4635 
   4636 	// See if we can do this write using multiple threads.
   4637 
   4638 	uint32 tilesAcross = ifd.TilesAcross ();
   4639 	uint32 tilesDown   = ifd.TilesDown   ();
   4640 
   4641 	bool useMultipleThreads = (tilesDown * tilesAcross >= 2) &&
   4642 							  (host.PerformAreaTaskThreads () > 1) &&
   4643 							  (subTileLength == ifd.fTileLength) &&
   4644 							  (ifd.fCompression != ccUncompressed);
   4645 
   4646 
   4647 #if qImagecore
   4648 	useMultipleThreads = false;
   4649 #endif
   4650 
   4651 	if (useMultipleThreads)
   4652 		{
   4653 
   4654 		uint32 threadCount = Min_uint32 (tilesDown * tilesAcross,
   4655 										 host.PerformAreaTaskThreads ());
   4656 
   4657 		dng_write_tiles_task task (*this,
   4658 								   host,
   4659 								   ifd,
   4660 								   basic,
   4661 								   stream,
   4662 								   image,
   4663 								   fakeChannels,
   4664 								   tilesDown,
   4665 								   tilesAcross,
   4666 								   compressedSize,
   4667 								   uncompressedSize);
   4668 
   4669 		host.PerformAreaTask (task,
   4670 							  dng_rect (0, 0, 16, 16 * threadCount));
   4671 
   4672 		}
   4673 
   4674 	else
   4675 		{
   4676 
   4677 		AutoPtr<dng_memory_block> compressedBuffer;
   4678 		AutoPtr<dng_memory_block> uncompressedBuffer;
   4679 		AutoPtr<dng_memory_block> subTileBlockBuffer;
   4680 		AutoPtr<dng_memory_block> tempBuffer;
   4681 
   4682 		if (compressedSize)
   4683 			{
   4684 			compressedBuffer.Reset (host.Allocate (compressedSize));
   4685 			}
   4686 
   4687 		if (uncompressedSize)
   4688 			{
   4689 			uncompressedBuffer.Reset (host.Allocate (uncompressedSize));
   4690 			}
   4691 
   4692 		if (ifd.fSubTileBlockRows > 1 && uncompressedSize)
   4693 			{
   4694 			subTileBlockBuffer.Reset (host.Allocate (uncompressedSize));
   4695 			}
   4696 
   4697 		// Write out each tile.
   4698 
   4699 		uint32 tileIndex = 0;
   4700 
   4701 		for (uint32 rowIndex = 0; rowIndex < tilesDown; rowIndex++)
   4702 			{
   4703 
   4704 			for (uint32 colIndex = 0; colIndex < tilesAcross; colIndex++)
   4705 				{
   4706 
   4707 				// Remember this offset.
   4708 
   4709 				uint32 tileOffset = (uint32) stream.Position ();
   4710 
   4711 				basic.SetTileOffset (tileIndex, tileOffset);
   4712 
   4713 				// Split tile into sub-tiles if possible.
   4714 
   4715 				dng_rect tileArea = ifd.TileArea (rowIndex, colIndex);
   4716 
   4717 				uint32 subTileCount = (tileArea.H () + subTileLength - 1) /
   4718 									  subTileLength;
   4719 
   4720 				for (uint32 subIndex = 0; subIndex < subTileCount; subIndex++)
   4721 					{
   4722 
   4723 					host.SniffForAbort ();
   4724 
   4725 					dng_rect subArea (tileArea);
   4726 
   4727 					subArea.t = tileArea.t + subIndex * subTileLength;
   4728 
   4729 					subArea.b = Min_int32 (subArea.t + subTileLength,
   4730 										   tileArea.b);
   4731 
   4732 					// Write the sub-tile.
   4733 
   4734 					WriteTile (host,
   4735 							   ifd,
   4736 							   stream,
   4737 							   image,
   4738 							   subArea,
   4739 							   fakeChannels,
   4740 							   compressedBuffer,
   4741 							   uncompressedBuffer,
   4742 							   subTileBlockBuffer,
   4743 							   tempBuffer);
   4744 
   4745 					}
   4746 
   4747 				// Update tile count.
   4748 
   4749 				uint32 tileByteCount = (uint32) stream.Position () - tileOffset;
   4750 
   4751 				basic.SetTileByteCount (tileIndex, tileByteCount);
   4752 
   4753 				tileIndex++;
   4754 
   4755 				// Keep the tiles on even byte offsets.
   4756 
   4757 				if (tileByteCount & 1)
   4758 					{
   4759 					stream.Put_uint8 (0);
   4760 					}
   4761 
   4762 				}
   4763 
   4764 			}
   4765 
   4766 		}
   4767 
   4768 	}
   4769 
   4770 /*****************************************************************************/
   4771 
   4772 #if qDNGUseXMP
   4773 
   4774 static void CopyString (const dng_xmp &oldXMP,
   4775 						dng_xmp &newXMP,
   4776 						const char *ns,
   4777 						const char *path,
   4778 						dng_string *exif = NULL)
   4779 	{
   4780 
   4781 	dng_string s;
   4782 
   4783 	if (oldXMP.GetString (ns, path, s))
   4784 		{
   4785 
   4786 		if (s.NotEmpty ())
   4787 			{
   4788 
   4789 			newXMP.SetString (ns, path, s);
   4790 
   4791 			if (exif)
   4792 				{
   4793 
   4794 				*exif = s;
   4795 
   4796 				}
   4797 
   4798 			}
   4799 
   4800 		}
   4801 
   4802 	}
   4803 
   4804 /*****************************************************************************/
   4805 
   4806 static void CopyStringList (const dng_xmp &oldXMP,
   4807 							dng_xmp &newXMP,
   4808 							const char *ns,
   4809 							const char *path,
   4810 							bool isBag)
   4811 	{
   4812 
   4813 	dng_string_list list;
   4814 
   4815 	if (oldXMP.GetStringList (ns, path, list))
   4816 		{
   4817 
   4818 		if (list.Count ())
   4819 			{
   4820 
   4821 			newXMP.SetStringList (ns, path, list, isBag);
   4822 
   4823 			}
   4824 
   4825 		}
   4826 
   4827 	}
   4828 
   4829 /*****************************************************************************/
   4830 
   4831 static void CopyAltLangDefault (const dng_xmp &oldXMP,
   4832 								dng_xmp &newXMP,
   4833 								const char *ns,
   4834 								const char *path,
   4835 								dng_string *exif = NULL)
   4836 	{
   4837 
   4838 	dng_string s;
   4839 
   4840 	if (oldXMP.GetAltLangDefault (ns, path, s))
   4841 		{
   4842 
   4843 		if (s.NotEmpty ())
   4844 			{
   4845 
   4846 			newXMP.SetAltLangDefault (ns, path, s);
   4847 
   4848 			if (exif)
   4849 				{
   4850 
   4851 				*exif = s;
   4852 
   4853 				}
   4854 
   4855 			}
   4856 
   4857 		}
   4858 
   4859 	}
   4860 
   4861 /*****************************************************************************/
   4862 
   4863 static void CopyStructField (const dng_xmp &oldXMP,
   4864 							 dng_xmp &newXMP,
   4865 							 const char *ns,
   4866 							 const char *path,
   4867 							 const char *field)
   4868 	{
   4869 
   4870 	dng_string s;
   4871 
   4872 	if (oldXMP.GetStructField (ns, path, ns, field, s))
   4873 		{
   4874 
   4875 		if (s.NotEmpty ())
   4876 			{
   4877 
   4878 			newXMP.SetStructField (ns, path, ns, field, s);
   4879 
   4880 			}
   4881 
   4882 		}
   4883 
   4884 	}
   4885 
   4886 /*****************************************************************************/
   4887 
   4888 static void CopyBoolean (const dng_xmp &oldXMP,
   4889 						 dng_xmp &newXMP,
   4890 						 const char *ns,
   4891 						 const char *path)
   4892 	{
   4893 
   4894 	bool b;
   4895 
   4896 	if (oldXMP.GetBoolean (ns, path, b))
   4897 		{
   4898 
   4899 		newXMP.SetBoolean (ns, path, b);
   4900 
   4901 		}
   4902 
   4903 	}
   4904 
   4905 #endif
   4906 
   4907 /*****************************************************************************/
   4908 
   4909 void dng_image_writer::CleanUpMetadata (dng_host &host,
   4910 										dng_metadata &metadata,
   4911 										dng_metadata_subset metadataSubset,
   4912 										const char *dstMIMI,
   4913 										const char *software)
   4914 	{
   4915 
   4916 	#if qDNGUseXMP
   4917 
   4918 	if (metadata.GetXMP () && metadata.GetExif ())
   4919 		{
   4920 
   4921 		dng_xmp  &newXMP  (*metadata.GetXMP  ());
   4922 		dng_exif &newEXIF (*metadata.GetExif ());
   4923 
   4924 		// Update software tag.
   4925 
   4926 		if (software)
   4927 			{
   4928 
   4929 			newEXIF.fSoftware.Set (software);
   4930 
   4931 			newXMP.Set (XMP_NS_XAP,
   4932 						"CreatorTool",
   4933 						software);
   4934 
   4935 			}
   4936 
   4937 		#if qDNGXMPDocOps
   4938 
   4939 		newXMP.DocOpsPrepareForSave (metadata.SourceMIMI ().Get (),
   4940 									 dstMIMI);
   4941 
   4942 		#else
   4943 
   4944 		metadata.UpdateDateTimeToNow ();
   4945 
   4946 		#endif
   4947 
   4948 		// Update EXIF version to at least 2.3 so all the exif tags
   4949 		// can be written.
   4950 
   4951 		if (newEXIF.fExifVersion < DNG_CHAR4 ('0','2','3','0'))
   4952 			{
   4953 
   4954 			newEXIF.fExifVersion = DNG_CHAR4 ('0','2','3','0');
   4955 
   4956 			newXMP.Set (XMP_NS_EXIF, "ExifVersion", "0230");
   4957 
   4958 			}
   4959 
   4960 		// Resync EXIF, remove EXIF tags from XMP.
   4961 
   4962 		newXMP.SyncExif (newEXIF,
   4963 						 metadata.GetOriginalExif (),
   4964 						 false,
   4965 						 true);
   4966 
   4967 		// Deal with ImageIngesterPro bug.  This program is adding lots of
   4968 		// empty metadata strings into the XMP, which is screwing up Adobe CS4.
   4969 		// We are saving a new file, so this is a chance to clean up this mess.
   4970 
   4971 		newXMP.RemoveEmptyStringsAndArrays (XMP_NS_DC);
   4972 		newXMP.RemoveEmptyStringsAndArrays (XMP_NS_XAP);
   4973 		newXMP.RemoveEmptyStringsAndArrays (XMP_NS_PHOTOSHOP);
   4974 		newXMP.RemoveEmptyStringsAndArrays (XMP_NS_IPTC);
   4975 		newXMP.RemoveEmptyStringsAndArrays (XMP_NS_XAP_RIGHTS);
   4976 		newXMP.RemoveEmptyStringsAndArrays ("http://ns.iview-multimedia.com/mediapro/1.0/");
   4977 
   4978 		// Process metadata subset.
   4979 
   4980 		if (metadataSubset == kMetadataSubset_CopyrightOnly ||
   4981 			metadataSubset == kMetadataSubset_CopyrightAndContact)
   4982 			{
   4983 
   4984 			dng_xmp  oldXMP  (newXMP );
   4985 			dng_exif oldEXIF (newEXIF);
   4986 
   4987 			// For these options, we start from nothing, and only fill in the
   4988 			// fields that we absolutely need.
   4989 
   4990 			newXMP.RemoveProperties (NULL);
   4991 
   4992 			newEXIF.SetEmpty ();
   4993 
   4994 			metadata.ClearMakerNote ();
   4995 
   4996 			// Move copyright related fields over.
   4997 
   4998 			CopyAltLangDefault (oldXMP,
   4999 								newXMP,
   5000 								XMP_NS_DC,
   5001 								"rights",
   5002 								&newEXIF.fCopyright);
   5003 
   5004 			CopyAltLangDefault (oldXMP,
   5005 								newXMP,
   5006 								XMP_NS_XAP_RIGHTS,
   5007 								"UsageTerms");
   5008 
   5009 			CopyString (oldXMP,
   5010 						newXMP,
   5011 						XMP_NS_XAP_RIGHTS,
   5012 						"WebStatement");
   5013 
   5014 			CopyBoolean (oldXMP,
   5015 						 newXMP,
   5016 						 XMP_NS_XAP_RIGHTS,
   5017 						 "Marked");
   5018 
   5019 			#if qDNGXMPDocOps
   5020 
   5021 			// Include basic DocOps fields, but not the full history.
   5022 
   5023 			CopyString (oldXMP,
   5024 						newXMP,
   5025 						XMP_NS_MM,
   5026 						"OriginalDocumentID");
   5027 
   5028 			CopyString (oldXMP,
   5029 						newXMP,
   5030 						XMP_NS_MM,
   5031 						"DocumentID");
   5032 
   5033 			CopyString (oldXMP,
   5034 						newXMP,
   5035 						XMP_NS_MM,
   5036 						"InstanceID");
   5037 
   5038 			CopyString (oldXMP,
   5039 						newXMP,
   5040 						XMP_NS_XAP,
   5041 						"MetadataDate");
   5042 
   5043 			#endif
   5044 
   5045 			// Copyright and Contact adds the contact info fields.
   5046 
   5047 			if (metadataSubset == kMetadataSubset_CopyrightAndContact)
   5048 				{
   5049 
   5050 				// Note: Save for Web is not including the dc:creator list, but it
   5051 				// is part of the IPTC contract info metadata panel, so I
   5052 				// think it should be copied as part of the contact info.
   5053 
   5054 				CopyStringList (oldXMP,
   5055 								newXMP,
   5056 								XMP_NS_DC,
   5057 								"creator",
   5058 								false);
   5059 
   5060 				// The first string dc:creator list is mirrored to the
   5061 				// the exif artist tag, so copy that also.
   5062 
   5063 				newEXIF.fArtist = oldEXIF.fArtist;
   5064 
   5065 				// Copy other contact fields.
   5066 
   5067 				CopyString (oldXMP,
   5068 							newXMP,
   5069 							XMP_NS_PHOTOSHOP,
   5070 							"AuthorsPosition");
   5071 
   5072 				CopyStructField (oldXMP,
   5073 								 newXMP,
   5074 								 XMP_NS_IPTC,
   5075 								 "CreatorContactInfo",
   5076 								 "CiEmailWork");
   5077 
   5078 				CopyStructField (oldXMP,
   5079 								 newXMP,
   5080 								 XMP_NS_IPTC,
   5081 								 "CreatorContactInfo",
   5082 								 "CiAdrExtadr");
   5083 
   5084 				CopyStructField (oldXMP,
   5085 								 newXMP,
   5086 								 XMP_NS_IPTC,
   5087 								 "CreatorContactInfo",
   5088 								 "CiAdrCity");
   5089 
   5090 				CopyStructField (oldXMP,
   5091 								 newXMP,
   5092 								 XMP_NS_IPTC,
   5093 								 "CreatorContactInfo",
   5094 								 "CiAdrRegion");
   5095 
   5096 				CopyStructField (oldXMP,
   5097 								 newXMP,
   5098 								 XMP_NS_IPTC,
   5099 								 "CreatorContactInfo",
   5100 								 "CiAdrPcode");
   5101 
   5102 				CopyStructField (oldXMP,
   5103 								 newXMP,
   5104 								 XMP_NS_IPTC,
   5105 								 "CreatorContactInfo",
   5106 								 "CiAdrCtry");
   5107 
   5108 				CopyStructField (oldXMP,
   5109 								 newXMP,
   5110 								 XMP_NS_IPTC,
   5111 								 "CreatorContactInfo",
   5112 								 "CiTelWork");
   5113 
   5114 				CopyStructField (oldXMP,
   5115 								 newXMP,
   5116 								 XMP_NS_IPTC,
   5117 								 "CreatorContactInfo",
   5118 								 "CiUrlWork");
   5119 
   5120 				CopyAltLangDefault (oldXMP,
   5121 									newXMP,
   5122 									XMP_NS_DC,
   5123 									"title");
   5124 
   5125 				}
   5126 
   5127  			}
   5128 
   5129 		else if (metadataSubset == kMetadataSubset_AllExceptCameraInfo        ||
   5130 				 metadataSubset == kMetadataSubset_AllExceptCameraAndLocation ||
   5131 				 metadataSubset == kMetadataSubset_AllExceptLocationInfo)
   5132 			{
   5133 
   5134 			dng_xmp  oldXMP  (newXMP );
   5135 			dng_exif oldEXIF (newEXIF);
   5136 
   5137 			if (metadataSubset == kMetadataSubset_AllExceptCameraInfo ||
   5138 				metadataSubset == kMetadataSubset_AllExceptCameraAndLocation)
   5139 				{
   5140 
   5141 				// This removes most of the EXIF info, so just copy the fields
   5142 				// we are not deleting.
   5143 
   5144 				newEXIF.SetEmpty ();
   5145 
   5146 				newEXIF.fImageDescription  = oldEXIF.fImageDescription;		// Note: Differs from SFW
   5147 				newEXIF.fSoftware          = oldEXIF.fSoftware;
   5148 				newEXIF.fArtist            = oldEXIF.fArtist;
   5149 				newEXIF.fCopyright         = oldEXIF.fCopyright;
   5150 				newEXIF.fCopyright2        = oldEXIF.fCopyright2;
   5151 				newEXIF.fDateTime          = oldEXIF.fDateTime;
   5152 				newEXIF.fDateTimeOriginal  = oldEXIF.fDateTimeOriginal;
   5153 				newEXIF.fDateTimeDigitized = oldEXIF.fDateTimeDigitized;
   5154 				newEXIF.fExifVersion       = oldEXIF.fExifVersion;
   5155 				newEXIF.fImageUniqueID	   = oldEXIF.fImageUniqueID;
   5156 
   5157 				newEXIF.CopyGPSFrom (oldEXIF);
   5158 
   5159 				// Remove exif info from XMP.
   5160 
   5161 				newXMP.RemoveProperties (XMP_NS_EXIF);
   5162 				newXMP.RemoveProperties (XMP_NS_AUX);
   5163 
   5164 				// Remove Camera Raw info
   5165 
   5166 				newXMP.RemoveProperties (XMP_NS_CRS);
   5167 				newXMP.RemoveProperties (XMP_NS_CRSS);
   5168 				newXMP.RemoveProperties (XMP_NS_CRX);
   5169 
   5170 				// Remove DocOps history, since it contains the original
   5171 				// camera format.
   5172 
   5173 				newXMP.Remove (XMP_NS_MM, "History");
   5174 
   5175 				// MakerNote contains camera info.
   5176 
   5177 				metadata.ClearMakerNote ();
   5178 
   5179 				}
   5180 
   5181 			if (metadataSubset == kMetadataSubset_AllExceptLocationInfo ||
   5182 				metadataSubset == kMetadataSubset_AllExceptCameraAndLocation)
   5183 				{
   5184 
   5185 				// Remove GPS fields.
   5186 
   5187 				dng_exif blankExif;
   5188 
   5189 				newEXIF.CopyGPSFrom (blankExif);
   5190 
   5191 				// Remove MakerNote just in case, because we don't know
   5192 				// all of what is in it.
   5193 
   5194 				metadata.ClearMakerNote ();
   5195 
   5196 				// Remove XMP & IPTC location fields.
   5197 
   5198 				newXMP.Remove (XMP_NS_PHOTOSHOP, "City");
   5199 				newXMP.Remove (XMP_NS_PHOTOSHOP, "State");
   5200 				newXMP.Remove (XMP_NS_PHOTOSHOP, "Country");
   5201 				newXMP.Remove (XMP_NS_IPTC, "Location");
   5202 				newXMP.Remove (XMP_NS_IPTC, "CountryCode");
   5203 				newXMP.Remove (XMP_NS_IPTC_EXT, "LocationCreated");
   5204 				newXMP.Remove (XMP_NS_IPTC_EXT, "LocationShown");
   5205 
   5206 				}
   5207 
   5208 			}
   5209 
   5210 		// Rebuild the legacy IPTC block, if needed.
   5211 
   5212 		bool isTIFF = (strcmp (dstMIMI, "image/tiff") == 0);
   5213 		bool isDNG  = (strcmp (dstMIMI, "image/dng" ) == 0);
   5214 
   5215 		if (!isDNG)
   5216 			{
   5217 
   5218 			metadata.RebuildIPTC (host.Allocator (),
   5219 								  isTIFF);
   5220 
   5221 			}
   5222 
   5223 		else
   5224 			{
   5225 
   5226 			metadata.ClearIPTC ();
   5227 
   5228 			}
   5229 
   5230 		// Clear format related XMP.
   5231 
   5232 		newXMP.ClearOrientation ();
   5233 
   5234 		newXMP.ClearImageInfo ();
   5235 
   5236 		newXMP.RemoveProperties (XMP_NS_DNG);
   5237 
   5238 		// All the formats we care about already keep the IPTC digest
   5239 		// elsewhere, do we don't need to write it to the XMP.
   5240 
   5241 		newXMP.ClearIPTCDigest ();
   5242 
   5243 		// Make sure that sidecar specific tags never get written to files.
   5244 
   5245 		newXMP.Remove (XMP_NS_PHOTOSHOP, "SidecarForExtension");
   5246 		newXMP.Remove (XMP_NS_PHOTOSHOP, "EmbeddedXMPDigest");
   5247 
   5248 		}
   5249 
   5250 	#endif
   5251 
   5252 	}
   5253 
   5254 /*****************************************************************************/
   5255 
   5256 void dng_image_writer::WriteTIFF (dng_host &host,
   5257 								  dng_stream &stream,
   5258 								  const dng_image &image,
   5259 								  uint32 photometricInterpretation,
   5260 								  uint32 compression,
   5261 								  dng_negative *negative,
   5262 								  const dng_color_space *space,
   5263 								  const dng_resolution *resolution,
   5264 								  const dng_jpeg_preview *thumbnail,
   5265 								  const dng_memory_block *imageResources,
   5266 								  dng_metadata_subset metadataSubset)
   5267 	{
   5268 
   5269 	WriteTIFF (host,
   5270 			   stream,
   5271 			   image,
   5272 			   photometricInterpretation,
   5273 			   compression,
   5274 			   negative ? &(negative->Metadata ()) : NULL,
   5275 			   space,
   5276 			   resolution,
   5277 			   thumbnail,
   5278 			   imageResources,
   5279 			   metadataSubset);
   5280 
   5281 	}
   5282 
   5283 /*****************************************************************************/
   5284 
   5285 void dng_image_writer::WriteTIFF (dng_host &host,
   5286 								  dng_stream &stream,
   5287 								  const dng_image &image,
   5288 								  uint32 photometricInterpretation,
   5289 								  uint32 compression,
   5290 								  const dng_metadata *metadata,
   5291 								  const dng_color_space *space,
   5292 								  const dng_resolution *resolution,
   5293 								  const dng_jpeg_preview *thumbnail,
   5294 								  const dng_memory_block *imageResources,
   5295 								  dng_metadata_subset metadataSubset)
   5296 	{
   5297 
   5298 	const void *profileData = NULL;
   5299 	uint32 profileSize = 0;
   5300 
   5301 	const uint8 *data = NULL;
   5302 	uint32 size = 0;
   5303 
   5304 	if (space && space->ICCProfile (size, data))
   5305 		{
   5306 
   5307 		profileData = data;
   5308 		profileSize = size;
   5309 
   5310 		}
   5311 
   5312 	WriteTIFFWithProfile (host,
   5313 						  stream,
   5314 						  image,
   5315 						  photometricInterpretation,
   5316 						  compression,
   5317 						  metadata,
   5318 						  profileData,
   5319 						  profileSize,
   5320 						  resolution,
   5321 						  thumbnail,
   5322 						  imageResources,
   5323 						  metadataSubset);
   5324 
   5325 	}
   5326 
   5327 /*****************************************************************************/
   5328 
   5329 void dng_image_writer::WriteTIFFWithProfile (dng_host &host,
   5330 											 dng_stream &stream,
   5331 											 const dng_image &image,
   5332 											 uint32 photometricInterpretation,
   5333 											 uint32 compression,
   5334 											 dng_negative *negative,
   5335 											 const void *profileData,
   5336 											 uint32 profileSize,
   5337 											 const dng_resolution *resolution,
   5338 											 const dng_jpeg_preview *thumbnail,
   5339 											 const dng_memory_block *imageResources,
   5340 											 dng_metadata_subset metadataSubset)
   5341 	{
   5342 
   5343 	WriteTIFFWithProfile (host,
   5344 						  stream,
   5345 						  image,
   5346 						  photometricInterpretation,
   5347 						  compression,
   5348 						  negative ? &(negative->Metadata ()) : NULL,
   5349 						  profileData,
   5350 						  profileSize,
   5351 						  resolution,
   5352 						  thumbnail,
   5353 						  imageResources,
   5354 						  metadataSubset);
   5355 
   5356 	}
   5357 
   5358 /*****************************************************************************/
   5359 
   5360 void dng_image_writer::WriteTIFFWithProfile (dng_host &host,
   5361 											 dng_stream &stream,
   5362 											 const dng_image &image,
   5363 											 uint32 photometricInterpretation,
   5364 											 uint32 compression,
   5365 											 const dng_metadata *constMetadata,
   5366 											 const void *profileData,
   5367 											 uint32 profileSize,
   5368 											 const dng_resolution *resolution,
   5369 											 const dng_jpeg_preview *thumbnail,
   5370 											 const dng_memory_block *imageResources,
   5371 											 dng_metadata_subset metadataSubset)
   5372 	{
   5373 
   5374 	uint32 j;
   5375 
   5376 	AutoPtr<dng_metadata> metadata;
   5377 
   5378 	if (constMetadata)
   5379 		{
   5380 
   5381 		metadata.Reset (constMetadata->Clone (host.Allocator ()));
   5382 
   5383 		CleanUpMetadata (host,
   5384 						 *metadata,
   5385 						 metadataSubset,
   5386 						 "image/tiff");
   5387 
   5388 		}
   5389 
   5390 	dng_ifd ifd;
   5391 
   5392 	ifd.fNewSubFileType = sfMainImage;
   5393 
   5394 	ifd.fImageWidth  = image.Bounds ().W ();
   5395 	ifd.fImageLength = image.Bounds ().H ();
   5396 
   5397 	ifd.fSamplesPerPixel = image.Planes ();
   5398 
   5399 	ifd.fBitsPerSample [0] = TagTypeSize (image.PixelType ()) * 8;
   5400 
   5401 	for (j = 1; j < ifd.fSamplesPerPixel; j++)
   5402 		{
   5403 		ifd.fBitsPerSample [j] = ifd.fBitsPerSample [0];
   5404 		}
   5405 
   5406 	ifd.fPhotometricInterpretation = photometricInterpretation;
   5407 
   5408 	ifd.fCompression = compression;
   5409 
   5410 	if (ifd.fCompression == ccUncompressed)
   5411 		{
   5412 
   5413 		ifd.SetSingleStrip ();
   5414 
   5415 		}
   5416 
   5417 	else
   5418 		{
   5419 
   5420 		ifd.FindStripSize (128 * 1024);
   5421 
   5422 		ifd.fPredictor = cpHorizontalDifference;
   5423 
   5424 		}
   5425 
   5426 	uint32 extraSamples = 0;
   5427 
   5428 	switch (photometricInterpretation)
   5429 		{
   5430 
   5431 		case piBlackIsZero:
   5432 			{
   5433 			extraSamples = image.Planes () - 1;
   5434 			break;
   5435 			}
   5436 
   5437 		case piRGB:
   5438 			{
   5439 			extraSamples = image.Planes () - 3;
   5440 			break;
   5441 			}
   5442 
   5443 		default:
   5444 			break;
   5445 
   5446 		}
   5447 
   5448 	ifd.fExtraSamplesCount = extraSamples;
   5449 
   5450 	if (image.PixelType () == ttFloat)
   5451 		{
   5452 
   5453 		for (j = 0; j < ifd.fSamplesPerPixel; j++)
   5454 			{
   5455 			ifd.fSampleFormat [j] = sfFloatingPoint;
   5456 			}
   5457 
   5458 		}
   5459 
   5460 	dng_tiff_directory mainIFD;
   5461 
   5462 	dng_basic_tag_set basic (mainIFD, ifd);
   5463 
   5464 	// Resolution.
   5465 
   5466 	dng_resolution res;
   5467 
   5468 	if (resolution)
   5469 		{
   5470 		res = *resolution;
   5471 		}
   5472 
   5473 	tag_urational tagXResolution (tcXResolution, res.fXResolution);
   5474 	tag_urational tagYResolution (tcYResolution, res.fYResolution);
   5475 
   5476 	tag_uint16 tagResolutionUnit (tcResolutionUnit, res.fResolutionUnit);
   5477 
   5478 	if (resolution)
   5479 		{
   5480 		mainIFD.Add (&tagXResolution   );
   5481 		mainIFD.Add (&tagYResolution   );
   5482 		mainIFD.Add (&tagResolutionUnit);
   5483 		}
   5484 
   5485 	// ICC Profile.
   5486 
   5487 	tag_icc_profile iccProfileTag (profileData, profileSize);
   5488 
   5489 	if (iccProfileTag.Count ())
   5490 		{
   5491 		mainIFD.Add (&iccProfileTag);
   5492 		}
   5493 
   5494 	// XMP metadata.
   5495 
   5496 	#if qDNGUseXMP
   5497 
   5498 	tag_xmp tagXMP (metadata.Get () ? metadata->GetXMP () : NULL);
   5499 
   5500 	if (tagXMP.Count ())
   5501 		{
   5502 		mainIFD.Add (&tagXMP);
   5503 		}
   5504 
   5505 	#endif
   5506 
   5507 	// IPTC metadata.
   5508 
   5509 	tag_iptc tagIPTC (metadata.Get () ? metadata->IPTCData   () : NULL,
   5510 					  metadata.Get () ? metadata->IPTCLength () : 0);
   5511 
   5512 	if (tagIPTC.Count ())
   5513 		{
   5514 		mainIFD.Add (&tagIPTC);
   5515 		}
   5516 
   5517 	// Adobe data (thumbnail and IPTC digest)
   5518 
   5519 	AutoPtr<dng_memory_block> adobeData (BuildAdobeData (host,
   5520 														 metadata.Get (),
   5521 														 thumbnail,
   5522 														 imageResources));
   5523 
   5524 	tag_uint8_ptr tagAdobe (tcAdobeData,
   5525 							adobeData->Buffer_uint8 (),
   5526 							adobeData->LogicalSize ());
   5527 
   5528 	if (tagAdobe.Count ())
   5529 		{
   5530 		mainIFD.Add (&tagAdobe);
   5531 		}
   5532 
   5533 	// Exif metadata.
   5534 
   5535 	exif_tag_set exifSet (mainIFD,
   5536 						  metadata.Get () && metadata->GetExif () ? *metadata->GetExif ()
   5537 																  : dng_exif (),
   5538 						  metadata.Get () ? metadata->IsMakerNoteSafe () : false,
   5539 						  metadata.Get () ? metadata->MakerNoteData   () : NULL,
   5540 						  metadata.Get () ? metadata->MakerNoteLength () : 0,
   5541 						  false);
   5542 
   5543 	// Find offset to main image data.
   5544 
   5545 	uint32 offsetMainIFD = 8;
   5546 
   5547 	uint32 offsetExifData = offsetMainIFD + mainIFD.Size ();
   5548 
   5549 	exifSet.Locate (offsetExifData);
   5550 
   5551 	uint32 offsetMainData = offsetExifData + exifSet.Size ();
   5552 
   5553 	stream.SetWritePosition (offsetMainData);
   5554 
   5555 	// Write the main image data.
   5556 
   5557 	WriteImage (host,
   5558 				ifd,
   5559 				basic,
   5560 				stream,
   5561 				image);
   5562 
   5563 	// Trim the file to this length.
   5564 
   5565 	stream.SetLength (stream.Position ());
   5566 
   5567 	// TIFF has a 4G size limit.
   5568 
   5569 	if (stream.Length () > 0x0FFFFFFFFL)
   5570 		{
   5571 		ThrowImageTooBigTIFF ();
   5572 		}
   5573 
   5574 	// Write TIFF Header.
   5575 
   5576 	stream.SetWritePosition (0);
   5577 
   5578 	stream.Put_uint16 (stream.BigEndian () ? byteOrderMM : byteOrderII);
   5579 
   5580 	stream.Put_uint16 (42);
   5581 
   5582 	stream.Put_uint32 (offsetMainIFD);
   5583 
   5584 	// Write the IFDs.
   5585 
   5586 	mainIFD.Put (stream);
   5587 
   5588 	exifSet.Put (stream);
   5589 
   5590 	stream.Flush ();
   5591 
   5592 	}
   5593 
   5594 /*****************************************************************************/
   5595 
   5596 void dng_image_writer::WriteDNG (dng_host &host,
   5597 							     dng_stream &stream,
   5598 							     dng_negative &negative,
   5599 							     const dng_preview_list *previewList,
   5600 								 uint32 maxBackwardVersion,
   5601 							     bool uncompressed)
   5602 	{
   5603 
   5604 	WriteDNG (host,
   5605 			  stream,
   5606 			  negative,
   5607 			  negative.Metadata (),
   5608 			  previewList,
   5609 			  maxBackwardVersion,
   5610 			  uncompressed);
   5611 
   5612 	}
   5613 
   5614 /*****************************************************************************/
   5615 
   5616 void dng_image_writer::WriteDNG (dng_host &host,
   5617 							     dng_stream &stream,
   5618 							     const dng_negative &negative,
   5619 								 const dng_metadata &constMetadata,
   5620 								 const dng_preview_list *previewList,
   5621 								 uint32 maxBackwardVersion,
   5622 							     bool uncompressed)
   5623 	{
   5624 
   5625 	uint32 j;
   5626 
   5627 	// Clean up metadata per MWG recommendations.
   5628 
   5629 	AutoPtr<dng_metadata> metadata (constMetadata.Clone (host.Allocator ()));
   5630 
   5631 	CleanUpMetadata (host,
   5632 					 *metadata,
   5633 					 kMetadataSubset_All,
   5634 					 "image/dng");
   5635 
   5636 	// Figure out the compression to use.  Most of the time this is lossless
   5637 	// JPEG.
   5638 
   5639 	uint32 compression = uncompressed ? ccUncompressed : ccJPEG;
   5640 
   5641 	// Was the the original file lossy JPEG compressed?
   5642 
   5643 	const dng_jpeg_image *rawJPEGImage = negative.RawJPEGImage ();
   5644 
   5645 	// If so, can we save it using the requested compression and DNG version?
   5646 
   5647 	if (uncompressed || maxBackwardVersion < dngVersion_1_4_0_0)
   5648 		{
   5649 
   5650 		if (rawJPEGImage || negative.RawJPEGImageDigest ().IsValid ())
   5651 			{
   5652 
   5653 			rawJPEGImage = NULL;
   5654 
   5655 			negative.ClearRawJPEGImageDigest ();
   5656 
   5657 			negative.ClearRawImageDigest ();
   5658 
   5659 			}
   5660 
   5661 		}
   5662 
   5663 	else if (rawJPEGImage)
   5664 		{
   5665 
   5666 		compression = ccLossyJPEG;
   5667 
   5668 		}
   5669 
   5670 	// Are we saving the original size tags?
   5671 
   5672 	bool saveOriginalDefaultFinalSize     = false;
   5673 	bool saveOriginalBestQualityFinalSize = false;
   5674 	bool saveOriginalDefaultCropSize      = false;
   5675 
   5676 		{
   5677 
   5678 		// See if we are saving a proxy image.
   5679 
   5680 		dng_point defaultFinalSize (negative.DefaultFinalHeight (),
   5681 									negative.DefaultFinalWidth  ());
   5682 
   5683 		saveOriginalDefaultFinalSize = (negative.OriginalDefaultFinalSize () !=
   5684 										defaultFinalSize);
   5685 
   5686 		if (saveOriginalDefaultFinalSize)
   5687 			{
   5688 
   5689 			// If the save OriginalDefaultFinalSize tag, this changes the defaults
   5690 			// for the OriginalBestQualityFinalSize and OriginalDefaultCropSize tags.
   5691 
   5692 			saveOriginalBestQualityFinalSize = (negative.OriginalBestQualityFinalSize () !=
   5693 												defaultFinalSize);
   5694 
   5695 			saveOriginalDefaultCropSize = (negative.OriginalDefaultCropSizeV () !=
   5696 										   dng_urational (defaultFinalSize.v, 1)) ||
   5697 										  (negative.OriginalDefaultCropSizeH () !=
   5698 										   dng_urational (defaultFinalSize.h, 1));
   5699 
   5700 			}
   5701 
   5702 		else
   5703 			{
   5704 
   5705 			// Else these two tags default to the normal non-proxy size image values.
   5706 
   5707 			dng_point bestQualityFinalSize (negative.BestQualityFinalHeight (),
   5708 											negative.BestQualityFinalWidth  ());
   5709 
   5710 			saveOriginalBestQualityFinalSize = (negative.OriginalBestQualityFinalSize () !=
   5711 												bestQualityFinalSize);
   5712 
   5713 			saveOriginalDefaultCropSize = (negative.OriginalDefaultCropSizeV () !=
   5714 										   negative.DefaultCropSizeV ()) ||
   5715 										  (negative.OriginalDefaultCropSizeH () !=
   5716 										   negative.DefaultCropSizeH ());
   5717 
   5718 			}
   5719 
   5720 		}
   5721 
   5722 	// Is this a floating point image that we are saving?
   5723 
   5724 	bool isFloatingPoint = (negative.RawImage ().PixelType () == ttFloat);
   5725 
   5726 	// Does this image have a transparency mask?
   5727 
   5728 	bool hasTransparencyMask = (negative.RawTransparencyMask () != NULL);
   5729 
   5730 	// Should we save a compressed 32-bit integer file?
   5731 
   5732 	bool isCompressed32BitInteger = (negative.RawImage ().PixelType () == ttLong) &&
   5733 								    (maxBackwardVersion >= dngVersion_1_4_0_0) &&
   5734 									(!uncompressed);
   5735 
   5736 	// Figure out what main version to use.
   5737 
   5738 	uint32 dngVersion = dngVersion_Current;
   5739 
   5740 	// Don't write version 1.4 files unless we actually use some feature of the 1.4 spec.
   5741 
   5742 	if (dngVersion == dngVersion_1_4_0_0)
   5743 		{
   5744 
   5745 		if (!rawJPEGImage                     &&
   5746 			!isFloatingPoint				  &&
   5747 			!hasTransparencyMask			  &&
   5748 			!isCompressed32BitInteger		  &&
   5749 			!saveOriginalDefaultFinalSize     &&
   5750 			!saveOriginalBestQualityFinalSize &&
   5751 			!saveOriginalDefaultCropSize      )
   5752 			{
   5753 
   5754 			dngVersion = dngVersion_1_3_0_0;
   5755 
   5756 			}
   5757 
   5758 		}
   5759 
   5760 	// Figure out what backward version to use.
   5761 
   5762 	uint32 dngBackwardVersion = dngVersion_1_1_0_0;
   5763 
   5764 	#if defined(qTestRowInterleave) || defined(qTestSubTileBlockRows) || defined(qTestSubTileBlockCols)
   5765 	dngBackwardVersion = Max_uint32 (dngBackwardVersion, dngVersion_1_2_0_0);
   5766 	#endif
   5767 
   5768 	dngBackwardVersion = Max_uint32 (dngBackwardVersion,
   5769 									 negative.OpcodeList1 ().MinVersion (false));
   5770 
   5771 	dngBackwardVersion = Max_uint32 (dngBackwardVersion,
   5772 									 negative.OpcodeList2 ().MinVersion (false));
   5773 
   5774 	dngBackwardVersion = Max_uint32 (dngBackwardVersion,
   5775 									 negative.OpcodeList3 ().MinVersion (false));
   5776 
   5777 	if (negative.GetMosaicInfo () &&
   5778 		negative.GetMosaicInfo ()->fCFALayout >= 6)
   5779 		{
   5780 		dngBackwardVersion = Max_uint32 (dngBackwardVersion, dngVersion_1_3_0_0);
   5781 		}
   5782 
   5783 	if (rawJPEGImage || isFloatingPoint || hasTransparencyMask || isCompressed32BitInteger)
   5784 		{
   5785 		dngBackwardVersion = Max_uint32 (dngBackwardVersion, dngVersion_1_4_0_0);
   5786 		}
   5787 
   5788 	if (dngBackwardVersion > dngVersion)
   5789 		{
   5790 		ThrowProgramError ();
   5791 		}
   5792 
   5793 	// Find best thumbnail from preview list, if any.
   5794 
   5795 	const dng_preview *thumbnail = NULL;
   5796 
   5797 	if (previewList)
   5798 		{
   5799 
   5800 		uint32 thumbArea = 0;
   5801 
   5802 		for (j = 0; j < previewList->Count (); j++)
   5803 			{
   5804 
   5805 			const dng_image_preview *imagePreview = dynamic_cast<const dng_image_preview *>(&previewList->Preview (j));
   5806 
   5807 			if (imagePreview)
   5808 				{
   5809 
   5810 				uint32 thisArea = imagePreview->fImage->Bounds ().W () *
   5811 								  imagePreview->fImage->Bounds ().H ();
   5812 
   5813 				if (!thumbnail || thisArea < thumbArea)
   5814 					{
   5815 
   5816 					thumbnail = &previewList->Preview (j);
   5817 
   5818 					thumbArea = thisArea;
   5819 
   5820 					}
   5821 
   5822 				}
   5823 
   5824 			const dng_jpeg_preview *jpegPreview = dynamic_cast<const dng_jpeg_preview *>(&previewList->Preview (j));
   5825 
   5826 			if (jpegPreview)
   5827 				{
   5828 
   5829 				uint32 thisArea = jpegPreview->fPreviewSize.h *
   5830 								  jpegPreview->fPreviewSize.v;
   5831 
   5832 				if (!thumbnail || thisArea < thumbArea)
   5833 					{
   5834 
   5835 					thumbnail = &previewList->Preview (j);
   5836 
   5837 					thumbArea = thisArea;
   5838 
   5839 					}
   5840 
   5841 				}
   5842 
   5843 			}
   5844 
   5845 		}
   5846 
   5847 	// Create the main IFD
   5848 
   5849 	dng_tiff_directory mainIFD;
   5850 
   5851 	// Create the IFD for the raw data. If there is no thumnail, this is
   5852 	// just a reference the main IFD.  Otherwise allocate a new one.
   5853 
   5854 	AutoPtr<dng_tiff_directory> rawIFD_IfNotMain;
   5855 
   5856 	if (thumbnail)
   5857 		{
   5858 		rawIFD_IfNotMain.Reset (new dng_tiff_directory);
   5859 		}
   5860 
   5861 	dng_tiff_directory &rawIFD (thumbnail ? *rawIFD_IfNotMain : mainIFD);
   5862 
   5863 	// Include DNG version tags.
   5864 
   5865 	uint8 dngVersionData [4];
   5866 
   5867 	dngVersionData [0] = (uint8) (dngVersion >> 24);
   5868 	dngVersionData [1] = (uint8) (dngVersion >> 16);
   5869 	dngVersionData [2] = (uint8) (dngVersion >>  8);
   5870 	dngVersionData [3] = (uint8) (dngVersion      );
   5871 
   5872 	tag_uint8_ptr tagDNGVersion (tcDNGVersion, dngVersionData, 4);
   5873 
   5874 	mainIFD.Add (&tagDNGVersion);
   5875 
   5876 	uint8 dngBackwardVersionData [4];
   5877 
   5878 	dngBackwardVersionData [0] = (uint8) (dngBackwardVersion >> 24);
   5879 	dngBackwardVersionData [1] = (uint8) (dngBackwardVersion >> 16);
   5880 	dngBackwardVersionData [2] = (uint8) (dngBackwardVersion >>  8);
   5881 	dngBackwardVersionData [3] = (uint8) (dngBackwardVersion      );
   5882 
   5883 	tag_uint8_ptr tagDNGBackwardVersion (tcDNGBackwardVersion, dngBackwardVersionData, 4);
   5884 
   5885 	mainIFD.Add (&tagDNGBackwardVersion);
   5886 
   5887 	// The main IFD contains the thumbnail, if there is a thumbnail.
   5888 
   5889 	AutoPtr<dng_basic_tag_set> thmBasic;
   5890 
   5891 	if (thumbnail)
   5892 		{
   5893 		thmBasic.Reset (thumbnail->AddTagSet (mainIFD));
   5894 		}
   5895 
   5896 	// Get the raw image we are writing.
   5897 
   5898 	const dng_image &rawImage (negative.RawImage ());
   5899 
   5900 	// For floating point, we only support ZIP compression.
   5901 
   5902 	if (isFloatingPoint && !uncompressed)
   5903 		{
   5904 
   5905 		compression = ccDeflate;
   5906 
   5907 		}
   5908 
   5909 	// For 32-bit integer images, we only support ZIP and uncompressed.
   5910 
   5911 	if (rawImage.PixelType () == ttLong)
   5912 		{
   5913 
   5914 		if (isCompressed32BitInteger)
   5915 			{
   5916 			compression = ccDeflate;
   5917 			}
   5918 
   5919 		else
   5920 			{
   5921 			compression = ccUncompressed;
   5922 			}
   5923 
   5924 		}
   5925 
   5926 	// Get a copy of the mosaic info.
   5927 
   5928 	dng_mosaic_info mosaicInfo;
   5929 
   5930 	if (negative.GetMosaicInfo ())
   5931 		{
   5932 		mosaicInfo = *(negative.GetMosaicInfo ());
   5933 		}
   5934 
   5935 	// Create a dng_ifd record for the raw image.
   5936 
   5937 	dng_ifd info;
   5938 
   5939 	info.fImageWidth  = rawImage.Width  ();
   5940 	info.fImageLength = rawImage.Height ();
   5941 
   5942 	info.fSamplesPerPixel = rawImage.Planes ();
   5943 
   5944 	info.fPhotometricInterpretation = mosaicInfo.IsColorFilterArray () ? piCFA
   5945 																	   : piLinearRaw;
   5946 
   5947 	info.fCompression = compression;
   5948 
   5949 	if (isFloatingPoint && compression == ccDeflate)
   5950 		{
   5951 
   5952 		info.fPredictor = cpFloatingPoint;
   5953 
   5954 		if (mosaicInfo.IsColorFilterArray ())
   5955 			{
   5956 
   5957 			if (mosaicInfo.fCFAPatternSize.h == 2)
   5958 				{
   5959 				info.fPredictor = cpFloatingPointX2;
   5960 				}
   5961 
   5962 			else if (mosaicInfo.fCFAPatternSize.h == 4)
   5963 				{
   5964 				info.fPredictor = cpFloatingPointX4;
   5965 				}
   5966 
   5967 			}
   5968 
   5969 		}
   5970 
   5971 	if (isCompressed32BitInteger)
   5972 		{
   5973 
   5974 		info.fPredictor = cpHorizontalDifference;
   5975 
   5976 		if (mosaicInfo.IsColorFilterArray ())
   5977 			{
   5978 
   5979 			if (mosaicInfo.fCFAPatternSize.h == 2)
   5980 				{
   5981 				info.fPredictor = cpHorizontalDifferenceX2;
   5982 				}
   5983 
   5984 			else if (mosaicInfo.fCFAPatternSize.h == 4)
   5985 				{
   5986 				info.fPredictor = cpHorizontalDifferenceX4;
   5987 				}
   5988 
   5989 			}
   5990 
   5991 		}
   5992 
   5993 	uint32 rawPixelType = rawImage.PixelType ();
   5994 
   5995 	if (rawPixelType == ttShort)
   5996 		{
   5997 
   5998 		// See if we are using a linearization table with <= 256 entries, in which
   5999 		// case the useful data will all fit within 8-bits.
   6000 
   6001 		const dng_linearization_info *rangeInfo = negative.GetLinearizationInfo ();
   6002 
   6003 		if (rangeInfo)
   6004 			{
   6005 
   6006 			if (rangeInfo->fLinearizationTable.Get ())
   6007 				{
   6008 
   6009 				uint32 entries = rangeInfo->fLinearizationTable->LogicalSize () >> 1;
   6010 
   6011 				if (entries <= 256)
   6012 					{
   6013 
   6014 					rawPixelType = ttByte;
   6015 
   6016 					}
   6017 
   6018 				}
   6019 
   6020 			}
   6021 
   6022 		}
   6023 
   6024 	switch (rawPixelType)
   6025 		{
   6026 
   6027 		case ttByte:
   6028 			{
   6029 			info.fBitsPerSample [0] = 8;
   6030 			break;
   6031 			}
   6032 
   6033 		case ttShort:
   6034 			{
   6035 			info.fBitsPerSample [0] = 16;
   6036 			break;
   6037 			}
   6038 
   6039 		case ttLong:
   6040 			{
   6041 			info.fBitsPerSample [0] = 32;
   6042 			break;
   6043 			}
   6044 
   6045 		case ttFloat:
   6046 			{
   6047 
   6048 			if (negative.RawFloatBitDepth () == 16)
   6049 				{
   6050 				info.fBitsPerSample [0] = 16;
   6051 				}
   6052 
   6053 			else if (negative.RawFloatBitDepth () == 24)
   6054 				{
   6055 				info.fBitsPerSample [0] = 24;
   6056 				}
   6057 
   6058 			else
   6059 				{
   6060 				info.fBitsPerSample [0] = 32;
   6061 				}
   6062 
   6063 			for (j = 0; j < info.fSamplesPerPixel; j++)
   6064 				{
   6065 				info.fSampleFormat [j] = sfFloatingPoint;
   6066 				}
   6067 
   6068 			break;
   6069 
   6070 			}
   6071 
   6072 		default:
   6073 			{
   6074 			ThrowProgramError ();
   6075 			}
   6076 
   6077 		}
   6078 
   6079 	// For lossless JPEG compression, we often lie about the
   6080 	// actual channel count to get the predictors to work across
   6081 	// same color mosaic pixels.
   6082 
   6083 	uint32 fakeChannels = 1;
   6084 
   6085 	if (info.fCompression == ccJPEG)
   6086 		{
   6087 
   6088 		if (mosaicInfo.IsColorFilterArray ())
   6089 			{
   6090 
   6091 			if (mosaicInfo.fCFAPatternSize.h == 4)
   6092 				{
   6093 				fakeChannels = 4;
   6094 				}
   6095 
   6096 			else if (mosaicInfo.fCFAPatternSize.h == 2)
   6097 				{
   6098 				fakeChannels = 2;
   6099 				}
   6100 
   6101 			// However, lossless JEPG is limited to four channels,
   6102 			// so compromise might be required.
   6103 
   6104 			while (fakeChannels * info.fSamplesPerPixel > 4 &&
   6105 				   fakeChannels > 1)
   6106 				{
   6107 
   6108 				fakeChannels >>= 1;
   6109 
   6110 				}
   6111 
   6112 			}
   6113 
   6114 		}
   6115 
   6116 	// Figure out tile sizes.
   6117 
   6118 	if (rawJPEGImage)
   6119 		{
   6120 
   6121 		DNG_ASSERT (rawPixelType == ttByte,
   6122 					"Unexpected jpeg pixel type");
   6123 
   6124 		DNG_ASSERT (info.fImageWidth  == (uint32) rawJPEGImage->fImageSize.h &&
   6125 					info.fImageLength == (uint32) rawJPEGImage->fImageSize.v,
   6126 					"Unexpected jpeg image size");
   6127 
   6128 		info.fTileWidth  = rawJPEGImage->fTileSize.h;
   6129 		info.fTileLength = rawJPEGImage->fTileSize.v;
   6130 
   6131 		info.fUsesStrips = rawJPEGImage->fUsesStrips;
   6132 
   6133 		info.fUsesTiles = !info.fUsesStrips;
   6134 
   6135 		}
   6136 
   6137 	else if (info.fCompression == ccJPEG)
   6138 		{
   6139 
   6140 		info.FindTileSize (128 * 1024);
   6141 
   6142 		}
   6143 
   6144 	else if (info.fCompression == ccDeflate)
   6145 		{
   6146 
   6147 		info.FindTileSize (512 * 1024);
   6148 
   6149 		}
   6150 
   6151 	else if (info.fCompression == ccLossyJPEG)
   6152 		{
   6153 
   6154 		ThrowProgramError ("No JPEG compressed image");
   6155 
   6156 		}
   6157 
   6158 	// Don't use tiles for uncompressed images.
   6159 
   6160 	else
   6161 		{
   6162 
   6163 		info.SetSingleStrip ();
   6164 
   6165 		}
   6166 
   6167 	#ifdef qTestRowInterleave
   6168 
   6169 	info.fRowInterleaveFactor = qTestRowInterleave;
   6170 
   6171 	#endif
   6172 
   6173 	#if defined(qTestSubTileBlockRows) && defined(qTestSubTileBlockCols)
   6174 
   6175 	info.fSubTileBlockRows = qTestSubTileBlockRows;
   6176 	info.fSubTileBlockCols = qTestSubTileBlockCols;
   6177 
   6178 	if (fakeChannels == 2)
   6179 		fakeChannels = 4;
   6180 
   6181 	#endif
   6182 
   6183 	// Basic information.
   6184 
   6185 	dng_basic_tag_set rawBasic (rawIFD, info);
   6186 
   6187 	// JPEG tables, if any.
   6188 
   6189 	tag_data_ptr tagJPEGTables (tcJPEGTables,
   6190 								ttUndefined,
   6191 								0,
   6192 								NULL);
   6193 
   6194 	if (rawJPEGImage && rawJPEGImage->fJPEGTables.Get ())
   6195 		{
   6196 
   6197 		tagJPEGTables.SetData (rawJPEGImage->fJPEGTables->Buffer ());
   6198 
   6199 		tagJPEGTables.SetCount (rawJPEGImage->fJPEGTables->LogicalSize ());
   6200 
   6201 		rawIFD.Add (&tagJPEGTables);
   6202 
   6203 		}
   6204 
   6205 	// DefaultScale tag.
   6206 
   6207 	dng_urational defaultScaleData [2];
   6208 
   6209 	defaultScaleData [0] = negative.DefaultScaleH ();
   6210 	defaultScaleData [1] = negative.DefaultScaleV ();
   6211 
   6212 	tag_urational_ptr tagDefaultScale (tcDefaultScale,
   6213 								       defaultScaleData,
   6214 								       2);
   6215 
   6216 	rawIFD.Add (&tagDefaultScale);
   6217 
   6218 	// Best quality scale tag.
   6219 
   6220 	tag_urational tagBestQualityScale (tcBestQualityScale,
   6221 									   negative.BestQualityScale ());
   6222 
   6223 	rawIFD.Add (&tagBestQualityScale);
   6224 
   6225 	// DefaultCropOrigin tag.
   6226 
   6227 	dng_urational defaultCropOriginData [2];
   6228 
   6229 	defaultCropOriginData [0] = negative.DefaultCropOriginH ();
   6230 	defaultCropOriginData [1] = negative.DefaultCropOriginV ();
   6231 
   6232 	tag_urational_ptr tagDefaultCropOrigin (tcDefaultCropOrigin,
   6233 								            defaultCropOriginData,
   6234 								            2);
   6235 
   6236 	rawIFD.Add (&tagDefaultCropOrigin);
   6237 
   6238 	// DefaultCropSize tag.
   6239 
   6240 	dng_urational defaultCropSizeData [2];
   6241 
   6242 	defaultCropSizeData [0] = negative.DefaultCropSizeH ();
   6243 	defaultCropSizeData [1] = negative.DefaultCropSizeV ();
   6244 
   6245 	tag_urational_ptr tagDefaultCropSize (tcDefaultCropSize,
   6246 								          defaultCropSizeData,
   6247 								          2);
   6248 
   6249 	rawIFD.Add (&tagDefaultCropSize);
   6250 
   6251 	// DefaultUserCrop tag.
   6252 
   6253 	dng_urational defaultUserCropData [4];
   6254 
   6255 	defaultUserCropData [0] = negative.DefaultUserCropT ();
   6256 	defaultUserCropData [1] = negative.DefaultUserCropL ();
   6257 	defaultUserCropData [2] = negative.DefaultUserCropB ();
   6258 	defaultUserCropData [3] = negative.DefaultUserCropR ();
   6259 
   6260 	tag_urational_ptr tagDefaultUserCrop (tcDefaultUserCrop,
   6261 										  defaultUserCropData,
   6262 										  4);
   6263 
   6264 	rawIFD.Add (&tagDefaultUserCrop);
   6265 
   6266 	// Range mapping tag set.
   6267 
   6268 	range_tag_set rangeSet (rawIFD, negative);
   6269 
   6270 	// Mosaic pattern information.
   6271 
   6272 	mosaic_tag_set mosaicSet (rawIFD, mosaicInfo);
   6273 
   6274 	// Chroma blur radius.
   6275 
   6276 	tag_urational tagChromaBlurRadius (tcChromaBlurRadius,
   6277 									   negative.ChromaBlurRadius ());
   6278 
   6279 	if (negative.ChromaBlurRadius ().IsValid ())
   6280 		{
   6281 
   6282 		rawIFD.Add (&tagChromaBlurRadius);
   6283 
   6284 		}
   6285 
   6286 	// Anti-alias filter strength.
   6287 
   6288 	tag_urational tagAntiAliasStrength (tcAntiAliasStrength,
   6289 									    negative.AntiAliasStrength ());
   6290 
   6291 	if (negative.AntiAliasStrength ().IsValid ())
   6292 		{
   6293 
   6294 		rawIFD.Add (&tagAntiAliasStrength);
   6295 
   6296 		}
   6297 
   6298 	// Profile and other color related tags.
   6299 
   6300 	AutoPtr<profile_tag_set> profileSet;
   6301 
   6302 	AutoPtr<color_tag_set> colorSet;
   6303 
   6304 	dng_std_vector<uint32> extraProfileIndex;
   6305 
   6306 	if (!negative.IsMonochrome ())
   6307 		{
   6308 
   6309 		const dng_camera_profile &mainProfile (*negative.ComputeCameraProfileToEmbed (constMetadata));
   6310 
   6311 		profileSet.Reset (new profile_tag_set (mainIFD,
   6312 											   mainProfile));
   6313 
   6314 		colorSet.Reset (new color_tag_set (mainIFD,
   6315 										   negative));
   6316 
   6317 		// Build list of profile indices to include in extra profiles tag.
   6318 
   6319 		uint32 profileCount = negative.ProfileCount ();
   6320 
   6321 		for (uint32 index = 0; index < profileCount; index++)
   6322 			{
   6323 
   6324 			const dng_camera_profile &profile (negative.ProfileByIndex (index));
   6325 
   6326 			if (&profile != &mainProfile)
   6327 				{
   6328 
   6329 				if (profile.WasReadFromDNG ())
   6330 					{
   6331 
   6332 					extraProfileIndex.push_back (index);
   6333 
   6334 					}
   6335 
   6336 				}
   6337 
   6338 			}
   6339 
   6340 		}
   6341 
   6342 	// Extra camera profiles tag.
   6343 
   6344 	uint32 extraProfileCount = (uint32) extraProfileIndex.size ();
   6345 
   6346 	dng_memory_data extraProfileOffsets (extraProfileCount, sizeof (uint32));
   6347 
   6348 	tag_uint32_ptr extraProfileTag (tcExtraCameraProfiles,
   6349 									extraProfileOffsets.Buffer_uint32 (),
   6350 									extraProfileCount);
   6351 
   6352 	if (extraProfileCount)
   6353 		{
   6354 
   6355 		mainIFD.Add (&extraProfileTag);
   6356 
   6357 		}
   6358 
   6359 	// Other tags.
   6360 
   6361 	tag_uint16 tagOrientation (tcOrientation,
   6362 						       (uint16) negative.ComputeOrientation (constMetadata).GetTIFF ());
   6363 
   6364 	mainIFD.Add (&tagOrientation);
   6365 
   6366 	tag_srational tagBaselineExposure (tcBaselineExposure,
   6367 								       negative.BaselineExposureR ());
   6368 
   6369 	mainIFD.Add (&tagBaselineExposure);
   6370 
   6371 	tag_urational tagBaselineNoise (tcBaselineNoise,
   6372 							        negative.BaselineNoiseR ());
   6373 
   6374 	mainIFD.Add (&tagBaselineNoise);
   6375 
   6376 	tag_urational tagNoiseReductionApplied (tcNoiseReductionApplied,
   6377 											negative.NoiseReductionApplied ());
   6378 
   6379 	if (negative.NoiseReductionApplied ().IsValid ())
   6380 		{
   6381 
   6382 		mainIFD.Add (&tagNoiseReductionApplied);
   6383 
   6384 		}
   6385 
   6386 	tag_dng_noise_profile tagNoiseProfile (negative.NoiseProfile ());
   6387 
   6388 	if (negative.NoiseProfile ().IsValidForNegative (negative))
   6389 		{
   6390 
   6391 		mainIFD.Add (&tagNoiseProfile);
   6392 
   6393 		}
   6394 
   6395 	tag_urational tagBaselineSharpness (tcBaselineSharpness,
   6396 								        negative.BaselineSharpnessR ());
   6397 
   6398 	mainIFD.Add (&tagBaselineSharpness);
   6399 
   6400 	tag_string tagUniqueName (tcUniqueCameraModel,
   6401 						      negative.ModelName (),
   6402 						      true);
   6403 
   6404 	mainIFD.Add (&tagUniqueName);
   6405 
   6406 	tag_string tagLocalName (tcLocalizedCameraModel,
   6407 						     negative.LocalName (),
   6408 						     false);
   6409 
   6410 	if (negative.LocalName ().NotEmpty ())
   6411 		{
   6412 
   6413 		mainIFD.Add (&tagLocalName);
   6414 
   6415 		}
   6416 
   6417 	tag_urational tagShadowScale (tcShadowScale,
   6418 							      negative.ShadowScaleR ());
   6419 
   6420 	mainIFD.Add (&tagShadowScale);
   6421 
   6422 	tag_uint16 tagColorimetricReference (tcColorimetricReference,
   6423 										 (uint16) negative.ColorimetricReference ());
   6424 
   6425 	if (negative.ColorimetricReference () != crSceneReferred)
   6426 		{
   6427 
   6428 		mainIFD.Add (&tagColorimetricReference);
   6429 
   6430 		}
   6431 
   6432 	bool useNewDigest = (maxBackwardVersion >= dngVersion_1_4_0_0);
   6433 
   6434 	if (compression == ccLossyJPEG)
   6435 		{
   6436 
   6437 		negative.FindRawJPEGImageDigest (host);
   6438 
   6439 		}
   6440 
   6441 	else
   6442 		{
   6443 
   6444 		if (useNewDigest)
   6445 			{
   6446 			negative.FindNewRawImageDigest (host);
   6447 			}
   6448 		else
   6449 			{
   6450 			negative.FindRawImageDigest (host);
   6451 			}
   6452 
   6453 		}
   6454 
   6455 	tag_uint8_ptr tagRawImageDigest (useNewDigest ? tcNewRawImageDigest : tcRawImageDigest,
   6456 									 compression == ccLossyJPEG ?
   6457 									 negative.RawJPEGImageDigest ().data :
   6458 									 (useNewDigest ? negative.NewRawImageDigest ().data
   6459 												   : negative.RawImageDigest    ().data),
   6460 							   		 16);
   6461 
   6462 	mainIFD.Add (&tagRawImageDigest);
   6463 
   6464 	negative.FindRawDataUniqueID (host);
   6465 
   6466 	tag_uint8_ptr tagRawDataUniqueID (tcRawDataUniqueID,
   6467 							   		  negative.RawDataUniqueID ().data,
   6468 							   		  16);
   6469 
   6470 	if (negative.RawDataUniqueID ().IsValid ())
   6471 		{
   6472 
   6473 		mainIFD.Add (&tagRawDataUniqueID);
   6474 
   6475 		}
   6476 
   6477 	tag_string tagOriginalRawFileName (tcOriginalRawFileName,
   6478 						   			   negative.OriginalRawFileName (),
   6479 						   			   false);
   6480 
   6481 	if (negative.HasOriginalRawFileName ())
   6482 		{
   6483 
   6484 		mainIFD.Add (&tagOriginalRawFileName);
   6485 
   6486 		}
   6487 
   6488 	negative.FindOriginalRawFileDigest ();
   6489 
   6490 	tag_data_ptr tagOriginalRawFileData (tcOriginalRawFileData,
   6491 										 ttUndefined,
   6492 										 negative.OriginalRawFileDataLength (),
   6493 										 negative.OriginalRawFileData       ());
   6494 
   6495 	tag_uint8_ptr tagOriginalRawFileDigest (tcOriginalRawFileDigest,
   6496 											negative.OriginalRawFileDigest ().data,
   6497 											16);
   6498 
   6499 	if (negative.OriginalRawFileData ())
   6500 		{
   6501 
   6502 		mainIFD.Add (&tagOriginalRawFileData);
   6503 
   6504 		mainIFD.Add (&tagOriginalRawFileDigest);
   6505 
   6506 		}
   6507 
   6508 	// XMP metadata.
   6509 
   6510 	#if qDNGUseXMP
   6511 
   6512 	tag_xmp tagXMP (metadata->GetXMP ());
   6513 
   6514 	if (tagXMP.Count ())
   6515 		{
   6516 
   6517 		mainIFD.Add (&tagXMP);
   6518 
   6519 		}
   6520 
   6521 	#endif
   6522 
   6523 	// Exif tags.
   6524 
   6525 	exif_tag_set exifSet (mainIFD,
   6526 						  *metadata->GetExif (),
   6527 						  metadata->IsMakerNoteSafe (),
   6528 						  metadata->MakerNoteData   (),
   6529 						  metadata->MakerNoteLength (),
   6530 						  true);
   6531 
   6532 	// Private data.
   6533 
   6534 	tag_uint8_ptr tagPrivateData (tcDNGPrivateData,
   6535 						   		  negative.PrivateData (),
   6536 						   		  negative.PrivateLength ());
   6537 
   6538 	if (negative.PrivateLength ())
   6539 		{
   6540 
   6541 		mainIFD.Add (&tagPrivateData);
   6542 
   6543 		}
   6544 
   6545 	// Proxy size tags.
   6546 
   6547 	uint32 originalDefaultFinalSizeData [2];
   6548 
   6549 	originalDefaultFinalSizeData [0] = negative.OriginalDefaultFinalSize ().h;
   6550 	originalDefaultFinalSizeData [1] = negative.OriginalDefaultFinalSize ().v;
   6551 
   6552 	tag_uint32_ptr tagOriginalDefaultFinalSize (tcOriginalDefaultFinalSize,
   6553 												originalDefaultFinalSizeData,
   6554 												2);
   6555 
   6556 	if (saveOriginalDefaultFinalSize)
   6557 		{
   6558 
   6559 		mainIFD.Add (&tagOriginalDefaultFinalSize);
   6560 
   6561 		}
   6562 
   6563 	uint32 originalBestQualityFinalSizeData [2];
   6564 
   6565 	originalBestQualityFinalSizeData [0] = negative.OriginalBestQualityFinalSize ().h;
   6566 	originalBestQualityFinalSizeData [1] = negative.OriginalBestQualityFinalSize ().v;
   6567 
   6568 	tag_uint32_ptr tagOriginalBestQualityFinalSize (tcOriginalBestQualityFinalSize,
   6569 													originalBestQualityFinalSizeData,
   6570 													2);
   6571 
   6572 	if (saveOriginalBestQualityFinalSize)
   6573 		{
   6574 
   6575 		mainIFD.Add (&tagOriginalBestQualityFinalSize);
   6576 
   6577 		}
   6578 
   6579 	dng_urational originalDefaultCropSizeData [2];
   6580 
   6581 	originalDefaultCropSizeData [0] = negative.OriginalDefaultCropSizeH ();
   6582 	originalDefaultCropSizeData [1] = negative.OriginalDefaultCropSizeV ();
   6583 
   6584 	tag_urational_ptr tagOriginalDefaultCropSize (tcOriginalDefaultCropSize,
   6585 												  originalDefaultCropSizeData,
   6586 												  2);
   6587 
   6588 	if (saveOriginalDefaultCropSize)
   6589 		{
   6590 
   6591 		mainIFD.Add (&tagOriginalDefaultCropSize);
   6592 
   6593 		}
   6594 
   6595 	// Opcode list 1.
   6596 
   6597 	AutoPtr<dng_memory_block> opcodeList1Data (negative.OpcodeList1 ().Spool (host));
   6598 
   6599 	tag_data_ptr tagOpcodeList1 (tcOpcodeList1,
   6600 								 ttUndefined,
   6601 								 opcodeList1Data.Get () ? opcodeList1Data->LogicalSize () : 0,
   6602 								 opcodeList1Data.Get () ? opcodeList1Data->Buffer      () : NULL);
   6603 
   6604 	if (opcodeList1Data.Get ())
   6605 		{
   6606 
   6607 		rawIFD.Add (&tagOpcodeList1);
   6608 
   6609 		}
   6610 
   6611 	// Opcode list 2.
   6612 
   6613 	AutoPtr<dng_memory_block> opcodeList2Data (negative.OpcodeList2 ().Spool (host));
   6614 
   6615 	tag_data_ptr tagOpcodeList2 (tcOpcodeList2,
   6616 								 ttUndefined,
   6617 								 opcodeList2Data.Get () ? opcodeList2Data->LogicalSize () : 0,
   6618 								 opcodeList2Data.Get () ? opcodeList2Data->Buffer      () : NULL);
   6619 
   6620 	if (opcodeList2Data.Get ())
   6621 		{
   6622 
   6623 		rawIFD.Add (&tagOpcodeList2);
   6624 
   6625 		}
   6626 
   6627 	// Opcode list 3.
   6628 
   6629 	AutoPtr<dng_memory_block> opcodeList3Data (negative.OpcodeList3 ().Spool (host));
   6630 
   6631 	tag_data_ptr tagOpcodeList3 (tcOpcodeList3,
   6632 								 ttUndefined,
   6633 								 opcodeList3Data.Get () ? opcodeList3Data->LogicalSize () : 0,
   6634 								 opcodeList3Data.Get () ? opcodeList3Data->Buffer      () : NULL);
   6635 
   6636 	if (opcodeList3Data.Get ())
   6637 		{
   6638 
   6639 		rawIFD.Add (&tagOpcodeList3);
   6640 
   6641 		}
   6642 
   6643 	// Transparency mask, if any.
   6644 
   6645 	AutoPtr<dng_ifd> maskInfo;
   6646 
   6647 	AutoPtr<dng_tiff_directory> maskIFD;
   6648 
   6649 	AutoPtr<dng_basic_tag_set> maskBasic;
   6650 
   6651 	if (hasTransparencyMask)
   6652 		{
   6653 
   6654 		// Create mask IFD.
   6655 
   6656 		maskInfo.Reset (new dng_ifd);
   6657 
   6658 		maskInfo->fNewSubFileType = sfTransparencyMask;
   6659 
   6660 		maskInfo->fImageWidth  = negative.RawTransparencyMask ()->Bounds ().W ();
   6661 		maskInfo->fImageLength = negative.RawTransparencyMask ()->Bounds ().H ();
   6662 
   6663 		maskInfo->fSamplesPerPixel = 1;
   6664 
   6665 		maskInfo->fBitsPerSample [0] = negative.RawTransparencyMaskBitDepth ();
   6666 
   6667 		maskInfo->fPhotometricInterpretation = piTransparencyMask;
   6668 
   6669 		maskInfo->fCompression = uncompressed ? ccUncompressed  : ccDeflate;
   6670 		maskInfo->fPredictor   = uncompressed ? cpNullPredictor : cpHorizontalDifference;
   6671 
   6672 		if (negative.RawTransparencyMask ()->PixelType () == ttFloat)
   6673 			{
   6674 
   6675 			maskInfo->fSampleFormat [0] = sfFloatingPoint;
   6676 
   6677 			if (maskInfo->fCompression == ccDeflate)
   6678 				{
   6679 				maskInfo->fPredictor = cpFloatingPoint;
   6680 				}
   6681 
   6682 			}
   6683 
   6684 		if (maskInfo->fCompression == ccDeflate)
   6685 			{
   6686 			maskInfo->FindTileSize (512 * 1024);
   6687 			}
   6688 		else
   6689 			{
   6690 			maskInfo->SetSingleStrip ();
   6691 			}
   6692 
   6693 		// Create mask tiff directory.
   6694 
   6695 		maskIFD.Reset (new dng_tiff_directory);
   6696 
   6697 		// Add mask basic tag set.
   6698 
   6699 		maskBasic.Reset (new dng_basic_tag_set (*maskIFD, *maskInfo));
   6700 
   6701 		}
   6702 
   6703 	// Add other subfiles.
   6704 
   6705 	uint32 subFileCount = thumbnail ? 1 : 0;
   6706 
   6707 	if (hasTransparencyMask)
   6708 		{
   6709 		subFileCount++;
   6710 		}
   6711 
   6712 	// Add previews.
   6713 
   6714 	uint32 previewCount = previewList ? previewList->Count () : 0;
   6715 
   6716 	AutoPtr<dng_tiff_directory> previewIFD [kMaxDNGPreviews];
   6717 
   6718 	AutoPtr<dng_basic_tag_set> previewBasic [kMaxDNGPreviews];
   6719 
   6720 	for (j = 0; j < previewCount; j++)
   6721 		{
   6722 
   6723 		if (thumbnail != &previewList->Preview (j))
   6724 			{
   6725 
   6726 			previewIFD [j] . Reset (new dng_tiff_directory);
   6727 
   6728 			previewBasic [j] . Reset (previewList->Preview (j).AddTagSet (*previewIFD [j]));
   6729 
   6730 			subFileCount++;
   6731 
   6732 			}
   6733 
   6734 		}
   6735 
   6736 	// And a link to the raw and JPEG image IFDs.
   6737 
   6738 	uint32 subFileData [kMaxDNGPreviews + 2];
   6739 
   6740 	tag_uint32_ptr tagSubFile (tcSubIFDs,
   6741 							   subFileData,
   6742 							   subFileCount);
   6743 
   6744 	if (subFileCount)
   6745 		{
   6746 
   6747 		mainIFD.Add (&tagSubFile);
   6748 
   6749 		}
   6750 
   6751 	// Skip past the header and IFDs for now.
   6752 
   6753 	uint32 currentOffset = 8;
   6754 
   6755 	currentOffset += mainIFD.Size ();
   6756 
   6757 	uint32 subFileIndex = 0;
   6758 
   6759 	if (thumbnail)
   6760 		{
   6761 
   6762 		subFileData [subFileIndex++] = currentOffset;
   6763 
   6764 		currentOffset += rawIFD.Size ();
   6765 
   6766 		}
   6767 
   6768 	if (hasTransparencyMask)
   6769 		{
   6770 
   6771 		subFileData [subFileIndex++] = currentOffset;
   6772 
   6773 		currentOffset += maskIFD->Size ();
   6774 
   6775 		}
   6776 
   6777 	for (j = 0; j < previewCount; j++)
   6778 		{
   6779 
   6780 		if (thumbnail != &previewList->Preview (j))
   6781 			{
   6782 
   6783 			subFileData [subFileIndex++] = currentOffset;
   6784 
   6785 			currentOffset += previewIFD [j]->Size ();
   6786 
   6787 			}
   6788 
   6789 		}
   6790 
   6791 	exifSet.Locate (currentOffset);
   6792 
   6793 	currentOffset += exifSet.Size ();
   6794 
   6795 	stream.SetWritePosition (currentOffset);
   6796 
   6797 	// Write the extra profiles.
   6798 
   6799 	if (extraProfileCount)
   6800 		{
   6801 
   6802 		for (j = 0; j < extraProfileCount; j++)
   6803 			{
   6804 
   6805 			extraProfileOffsets.Buffer_uint32 () [j] = (uint32) stream.Position ();
   6806 
   6807 			uint32 index = extraProfileIndex [j];
   6808 
   6809 			const dng_camera_profile &profile (negative.ProfileByIndex (index));
   6810 
   6811 			tiff_dng_extended_color_profile extraWriter (profile);
   6812 
   6813 			extraWriter.Put (stream, false);
   6814 
   6815 			}
   6816 
   6817 		}
   6818 
   6819 	// Write the thumbnail data.
   6820 
   6821 	if (thumbnail)
   6822 		{
   6823 
   6824 		thumbnail->WriteData (host,
   6825 							  *this,
   6826 							  *thmBasic,
   6827 							  stream);
   6828 
   6829 		}
   6830 
   6831 	// Write the preview data.
   6832 
   6833 	for (j = 0; j < previewCount; j++)
   6834 		{
   6835 
   6836 		if (thumbnail != &previewList->Preview (j))
   6837 			{
   6838 
   6839 			previewList->Preview (j).WriteData (host,
   6840 												*this,
   6841 												*previewBasic [j],
   6842 												stream);
   6843 
   6844 			}
   6845 
   6846 		}
   6847 
   6848 	// Write the raw data.
   6849 
   6850 	if (rawJPEGImage)
   6851 		{
   6852 
   6853 		uint32 tileCount = info.TilesAcross () *
   6854 						   info.TilesDown   ();
   6855 
   6856 		for (uint32 tileIndex = 0; tileIndex < tileCount; tileIndex++)
   6857 			{
   6858 
   6859 			// Remember this offset.
   6860 
   6861 			uint32 tileOffset = (uint32) stream.Position ();
   6862 
   6863 			rawBasic.SetTileOffset (tileIndex, tileOffset);
   6864 
   6865 			// Write JPEG data.
   6866 
   6867 			stream.Put (rawJPEGImage->fJPEGData [tileIndex]->Buffer      (),
   6868 						rawJPEGImage->fJPEGData [tileIndex]->LogicalSize ());
   6869 
   6870 			// Update tile count.
   6871 
   6872 			uint32 tileByteCount = (uint32) stream.Position () - tileOffset;
   6873 
   6874 			rawBasic.SetTileByteCount (tileIndex, tileByteCount);
   6875 
   6876 			// Keep the tiles on even byte offsets.
   6877 
   6878 			if (tileByteCount & 1)
   6879 				{
   6880 				stream.Put_uint8 (0);
   6881 				}
   6882 
   6883 			}
   6884 
   6885 		}
   6886 
   6887 	else
   6888 		{
   6889 
   6890 		#if qDNGValidate
   6891 		dng_timer timer ("Write raw image time");
   6892 		#endif
   6893 
   6894 		WriteImage (host,
   6895 					info,
   6896 					rawBasic,
   6897 					stream,
   6898 					rawImage,
   6899 					fakeChannels);
   6900 
   6901 		}
   6902 
   6903 	// Write transparency mask image.
   6904 
   6905 	if (hasTransparencyMask)
   6906 		{
   6907 
   6908 		#if qDNGValidate
   6909 		dng_timer timer ("Write transparency mask time");
   6910 		#endif
   6911 
   6912 		WriteImage (host,
   6913 					*maskInfo,
   6914 					*maskBasic,
   6915 					stream,
   6916 					*negative.RawTransparencyMask ());
   6917 
   6918 		}
   6919 
   6920 	// Trim the file to this length.
   6921 
   6922 	stream.SetLength (stream.Position ());
   6923 
   6924 	// DNG has a 4G size limit.
   6925 
   6926 	if (stream.Length () > 0x0FFFFFFFFL)
   6927 		{
   6928 		ThrowImageTooBigDNG ();
   6929 		}
   6930 
   6931 	// Write TIFF Header.
   6932 
   6933 	stream.SetWritePosition (0);
   6934 
   6935 	stream.Put_uint16 (stream.BigEndian () ? byteOrderMM : byteOrderII);
   6936 
   6937 	stream.Put_uint16 (42);
   6938 
   6939 	stream.Put_uint32 (8);
   6940 
   6941 	// Write the IFDs.
   6942 
   6943 	mainIFD.Put (stream);
   6944 
   6945 	if (thumbnail)
   6946 		{
   6947 
   6948 		rawIFD.Put (stream);
   6949 
   6950 		}
   6951 
   6952 	if (hasTransparencyMask)
   6953 		{
   6954 
   6955 		maskIFD->Put (stream);
   6956 
   6957 		}
   6958 
   6959 	for (j = 0; j < previewCount; j++)
   6960 		{
   6961 
   6962 		if (thumbnail != &previewList->Preview (j))
   6963 			{
   6964 
   6965 			previewIFD [j]->Put (stream);
   6966 
   6967 			}
   6968 
   6969 		}
   6970 
   6971 	exifSet.Put (stream);
   6972 
   6973 	stream.Flush ();
   6974 
   6975 	}
   6976 
   6977 /*****************************************************************************/
   6978