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
65dng_resolution::dng_resolution ()
66
67	:	fXResolution ()
68	,	fYResolution ()
69
70	,	fResolutionUnit (0)
71
72	{
73
74	}
75
76/******************************************************************************/
77
78static 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
186static 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
205tag_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
241void tag_string::Put (dng_stream &stream) const
242	{
243
244	stream.Put (fString.Get (), Size ());
245
246	}
247
248/*****************************************************************************/
249
250tag_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
279void 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
313void 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
415tag_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
438tag_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
460void 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
478tag_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
503tag_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
517void 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
540tag_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
572void 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
610uint32 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
637void 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
716dng_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
876exif_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
1658void 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
1683class 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
1729range_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
1958class 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
1989mosaic_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
2074class 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
2111color_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
2225class 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
2284profile_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
2591tiff_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
2602void 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
2643tag_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
2667dng_image_writer::dng_image_writer ()
2668	{
2669
2670	}
2671
2672/*****************************************************************************/
2673
2674dng_image_writer::~dng_image_writer ()
2675	{
2676
2677	}
2678
2679/*****************************************************************************/
2680
2681uint32 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
2735static 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
2766static 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
2797static 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
2828inline 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
2911static 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
3006void 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
3143void 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
3181void 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
3248class 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
3336dng_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
3356void 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
3381void 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
3426void 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
3483void 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
3562static 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
3591static 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
3608struct 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
3621static 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
3633static 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
3649static 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
3666static 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
3711void 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
4013void 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
4167void 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
4305class 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
4568void 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
4774static 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
4806static 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
4831static 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
4863static 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
4888static 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
4909void 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
5256void 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
5285void 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
5329void 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
5360void 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
5596void 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
5616void 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