1/*****************************************************************************/
2// Copyright 2007-2011 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_preview.cpp#1 $ */
10/* $DateTime: 2012/05/30 13:28:51 $ */
11/* $Change: 832332 $ */
12/* $Author: tknoll $ */
13
14/*****************************************************************************/
15
16#include "dng_preview.h"
17
18#include "dng_assertions.h"
19#include "dng_image.h"
20#include "dng_image_writer.h"
21#include "dng_memory.h"
22#include "dng_stream.h"
23#include "dng_tag_codes.h"
24#include "dng_tag_values.h"
25
26/*****************************************************************************/
27
28class dng_preview_tag_set: public dng_basic_tag_set
29	{
30
31	private:
32
33		tag_string fApplicationNameTag;
34
35		tag_string fApplicationVersionTag;
36
37		tag_string fSettingsNameTag;
38
39		dng_fingerprint fSettingsDigest;
40
41		tag_uint8_ptr fSettingsDigestTag;
42
43		tag_uint32 fColorSpaceTag;
44
45		tag_string fDateTimeTag;
46
47		tag_real64 fRawToPreviewGainTag;
48
49		tag_uint32 fCacheVersionTag;
50
51	public:
52
53		dng_preview_tag_set (dng_tiff_directory &directory,
54							 const dng_preview &preview,
55							 const dng_ifd &ifd);
56
57		virtual ~dng_preview_tag_set ();
58
59	};
60
61/*****************************************************************************/
62
63dng_preview_tag_set::dng_preview_tag_set (dng_tiff_directory &directory,
64										  const dng_preview &preview,
65										  const dng_ifd &ifd)
66
67	:	dng_basic_tag_set (directory, ifd)
68
69	,	fApplicationNameTag (tcPreviewApplicationName,
70							 preview.fInfo.fApplicationName,
71							 false)
72
73	,	fApplicationVersionTag (tcPreviewApplicationVersion,
74							    preview.fInfo.fApplicationVersion,
75								false)
76
77	,	fSettingsNameTag (tcPreviewSettingsName,
78						  preview.fInfo.fSettingsName,
79						  false)
80
81	,	fSettingsDigest (preview.fInfo.fSettingsDigest)
82
83	,	fSettingsDigestTag (tcPreviewSettingsDigest,
84							fSettingsDigest.data,
85							16)
86
87	,	fColorSpaceTag (tcPreviewColorSpace,
88						preview.fInfo.fColorSpace)
89
90	,	fDateTimeTag (tcPreviewDateTime,
91					  preview.fInfo.fDateTime,
92					  true)
93
94	,	fRawToPreviewGainTag (tcRawToPreviewGain,
95							  preview.fInfo.fRawToPreviewGain)
96
97	,	fCacheVersionTag (tcCacheVersion,
98					      preview.fInfo.fCacheVersion)
99
100	{
101
102	if (preview.fInfo.fApplicationName.NotEmpty ())
103		{
104
105		directory.Add (&fApplicationNameTag);
106
107		}
108
109	if (preview.fInfo.fApplicationVersion.NotEmpty ())
110		{
111
112		directory.Add (&fApplicationVersionTag);
113
114		}
115
116	if (preview.fInfo.fSettingsName.NotEmpty ())
117		{
118
119		directory.Add (&fSettingsNameTag);
120
121		}
122
123	if (preview.fInfo.fSettingsDigest.IsValid ())
124		{
125
126		directory.Add (&fSettingsDigestTag);
127
128		}
129
130	if (preview.fInfo.fColorSpace != previewColorSpace_MaxEnum)
131		{
132
133		directory.Add (&fColorSpaceTag);
134
135		}
136
137	if (preview.fInfo.fDateTime.NotEmpty ())
138		{
139
140		directory.Add (&fDateTimeTag);
141
142		}
143
144	if (preview.fInfo.fRawToPreviewGain != 1.0)
145		{
146
147		directory.Add (&fRawToPreviewGainTag);
148
149		}
150
151	if (preview.fInfo.fCacheVersion != 0)
152		{
153
154		directory.Add (&fCacheVersionTag);
155
156		}
157
158	}
159
160/*****************************************************************************/
161
162dng_preview_tag_set::~dng_preview_tag_set ()
163	{
164
165	}
166
167/*****************************************************************************/
168
169dng_preview::dng_preview ()
170
171	:	fInfo ()
172
173	{
174
175	}
176
177/*****************************************************************************/
178
179dng_preview::~dng_preview ()
180	{
181
182	}
183
184/*****************************************************************************/
185
186dng_image_preview::dng_image_preview ()
187
188	:	fImage ()
189	,	fIFD   ()
190
191	{
192
193	}
194
195/*****************************************************************************/
196
197dng_image_preview::~dng_image_preview ()
198	{
199
200	}
201
202/*****************************************************************************/
203
204dng_basic_tag_set * dng_image_preview::AddTagSet (dng_tiff_directory &directory) const
205	{
206
207	fIFD.fNewSubFileType = fInfo.fIsPrimary ? sfPreviewImage
208											: sfAltPreviewImage;
209
210	fIFD.fImageWidth  = fImage->Width  ();
211	fIFD.fImageLength = fImage->Height ();
212
213	fIFD.fSamplesPerPixel = fImage->Planes ();
214
215	fIFD.fPhotometricInterpretation = fIFD.fSamplesPerPixel == 1 ? piBlackIsZero
216																 : piRGB;
217
218	fIFD.fBitsPerSample [0] = TagTypeSize (fImage->PixelType ()) * 8;
219
220	for (uint32 j = 1; j < fIFD.fSamplesPerPixel; j++)
221		{
222		fIFD.fBitsPerSample [j] = fIFD.fBitsPerSample [0];
223		}
224
225	fIFD.SetSingleStrip ();
226
227	return new dng_preview_tag_set (directory, *this, fIFD);
228
229	}
230
231/*****************************************************************************/
232
233void dng_image_preview::WriteData (dng_host &host,
234								   dng_image_writer &writer,
235								   dng_basic_tag_set &basic,
236								   dng_stream &stream) const
237	{
238
239	writer.WriteImage (host,
240					   fIFD,
241					   basic,
242					   stream,
243				       *fImage.Get ());
244
245	}
246
247/*****************************************************************************/
248
249class dng_jpeg_preview_tag_set: public dng_preview_tag_set
250	{
251
252	private:
253
254		dng_urational fCoefficientsData [3];
255
256		tag_urational_ptr fCoefficientsTag;
257
258		uint16 fSubSamplingData [2];
259
260		tag_uint16_ptr fSubSamplingTag;
261
262		tag_uint16 fPositioningTag;
263
264		dng_urational fReferenceData [6];
265
266		tag_urational_ptr fReferenceTag;
267
268	public:
269
270		dng_jpeg_preview_tag_set (dng_tiff_directory &directory,
271								  const dng_jpeg_preview &preview,
272								  const dng_ifd &ifd);
273
274		virtual ~dng_jpeg_preview_tag_set ();
275
276	};
277
278/******************************************************************************/
279
280dng_jpeg_preview_tag_set::dng_jpeg_preview_tag_set (dng_tiff_directory &directory,
281													const dng_jpeg_preview &preview,
282													const dng_ifd &ifd)
283
284	:	dng_preview_tag_set (directory, preview, ifd)
285
286	,	fCoefficientsTag (tcYCbCrCoefficients, fCoefficientsData, 3)
287
288	,	fSubSamplingTag (tcYCbCrSubSampling, fSubSamplingData, 2)
289
290	,	fPositioningTag (tcYCbCrPositioning, preview.fYCbCrPositioning)
291
292	,	fReferenceTag (tcReferenceBlackWhite, fReferenceData, 6)
293
294	{
295
296	if (preview.fPhotometricInterpretation == piYCbCr)
297		{
298
299		fCoefficientsData [0] = dng_urational (299, 1000);
300		fCoefficientsData [1] = dng_urational (587, 1000);
301		fCoefficientsData [2] = dng_urational (114, 1000);
302
303		directory.Add (&fCoefficientsTag);
304
305		fSubSamplingData [0] = (uint16) preview.fYCbCrSubSampling.h;
306		fSubSamplingData [1] = (uint16) preview.fYCbCrSubSampling.v;
307
308		directory.Add (&fSubSamplingTag);
309
310		directory.Add (&fPositioningTag);
311
312		fReferenceData [0] = dng_urational (  0, 1);
313		fReferenceData [1] = dng_urational (255, 1);
314		fReferenceData [2] = dng_urational (128, 1);
315		fReferenceData [3] = dng_urational (255, 1);
316		fReferenceData [4] = dng_urational (128, 1);
317		fReferenceData [5] = dng_urational (255, 1);
318
319		directory.Add (&fReferenceTag);
320
321		}
322
323	}
324
325/*****************************************************************************/
326
327dng_jpeg_preview_tag_set::~dng_jpeg_preview_tag_set ()
328	{
329
330	}
331
332/*****************************************************************************/
333
334dng_jpeg_preview::dng_jpeg_preview ()
335
336	:	fPreviewSize 			   ()
337	,	fPhotometricInterpretation (piYCbCr)
338	,	fYCbCrSubSampling 		   (1, 1)
339	,	fYCbCrPositioning		   (2)
340	,	fCompressedData			   ()
341
342	{
343
344	}
345
346/*****************************************************************************/
347
348dng_jpeg_preview::~dng_jpeg_preview ()
349	{
350
351	}
352
353/*****************************************************************************/
354
355dng_basic_tag_set * dng_jpeg_preview::AddTagSet (dng_tiff_directory &directory) const
356	{
357
358	dng_ifd ifd;
359
360	ifd.fNewSubFileType = fInfo.fIsPrimary ? sfPreviewImage
361										   : sfAltPreviewImage;
362
363	ifd.fImageWidth  = fPreviewSize.h;
364	ifd.fImageLength = fPreviewSize.v;
365
366	ifd.fPhotometricInterpretation = fPhotometricInterpretation;
367
368	ifd.fBitsPerSample [0] = 8;
369	ifd.fBitsPerSample [1] = 8;
370	ifd.fBitsPerSample [2] = 8;
371
372	ifd.fSamplesPerPixel = (fPhotometricInterpretation == piBlackIsZero ? 1 : 3);
373
374	ifd.fCompression = ccJPEG;
375	ifd.fPredictor   = cpNullPredictor;
376
377	ifd.SetSingleStrip ();
378
379	return new dng_jpeg_preview_tag_set (directory, *this, ifd);
380
381	}
382
383/*****************************************************************************/
384
385void dng_jpeg_preview::WriteData (dng_host & /* host */,
386								  dng_image_writer & /* writer */,
387								  dng_basic_tag_set &basic,
388								  dng_stream &stream) const
389	{
390
391	basic.SetTileOffset (0, (uint32) stream.Position ());
392
393	basic.SetTileByteCount (0, fCompressedData->LogicalSize ());
394
395	stream.Put (fCompressedData->Buffer      (),
396				fCompressedData->LogicalSize ());
397
398	if (fCompressedData->LogicalSize () & 1)
399		{
400		stream.Put_uint8 (0);
401		}
402
403	}
404
405/*****************************************************************************/
406
407void dng_jpeg_preview::SpoolAdobeThumbnail (dng_stream &stream) const
408	{
409
410	DNG_ASSERT (fCompressedData.Get (),
411				"SpoolAdobeThumbnail: no data");
412
413	DNG_ASSERT (fPhotometricInterpretation == piYCbCr,
414				"SpoolAdobeThumbnail: Non-YCbCr");
415
416	uint32 compressedSize = fCompressedData->LogicalSize ();
417
418	stream.Put_uint32 (DNG_CHAR4 ('8','B','I','M'));
419	stream.Put_uint16 (1036);
420	stream.Put_uint16 (0);
421
422	stream.Put_uint32 (compressedSize + 28);
423
424	uint32 widthBytes = (fPreviewSize.h * 24 + 31) / 32 * 4;
425
426	stream.Put_uint32 (1);
427	stream.Put_uint32 (fPreviewSize.h);
428	stream.Put_uint32 (fPreviewSize.v);
429	stream.Put_uint32 (widthBytes);
430	stream.Put_uint32 (widthBytes * fPreviewSize.v);
431	stream.Put_uint32 (compressedSize);
432	stream.Put_uint16 (24);
433	stream.Put_uint16 (1);
434
435	stream.Put (fCompressedData->Buffer (),
436			    compressedSize);
437
438	if (compressedSize & 1)
439		{
440		stream.Put_uint8 (0);
441		}
442
443	}
444
445/*****************************************************************************/
446
447class dng_raw_preview_tag_set: public dng_preview_tag_set
448	{
449
450	private:
451
452		tag_data_ptr fOpcodeList2Tag;
453
454		tag_uint32_ptr fWhiteLevelTag;
455
456		uint32 fWhiteLevelData [kMaxColorPlanes];
457
458	public:
459
460		dng_raw_preview_tag_set (dng_tiff_directory &directory,
461								 const dng_raw_preview &preview,
462								 const dng_ifd &ifd);
463
464		virtual ~dng_raw_preview_tag_set ();
465
466	};
467
468/*****************************************************************************/
469
470dng_raw_preview_tag_set::dng_raw_preview_tag_set (dng_tiff_directory &directory,
471												  const dng_raw_preview &preview,
472												  const dng_ifd &ifd)
473
474	:	dng_preview_tag_set (directory, preview, ifd)
475
476	,	fOpcodeList2Tag (tcOpcodeList2,
477						 ttUndefined,
478						 0,
479						 NULL)
480
481	,	fWhiteLevelTag (tcWhiteLevel,
482						fWhiteLevelData,
483						preview.fImage->Planes ())
484
485	{
486
487	if (preview.fOpcodeList2Data.Get ())
488		{
489
490		fOpcodeList2Tag.SetData  (preview.fOpcodeList2Data->Buffer      ());
491		fOpcodeList2Tag.SetCount (preview.fOpcodeList2Data->LogicalSize ());
492
493		directory.Add (&fOpcodeList2Tag);
494
495		}
496
497	if (preview.fImage->PixelType () == ttFloat)
498		{
499
500		for (uint32 j = 0; j < kMaxColorPlanes; j++)
501			{
502			fWhiteLevelData [j] = 32768;
503			}
504
505		directory.Add (&fWhiteLevelTag);
506
507		}
508
509	}
510
511/*****************************************************************************/
512
513dng_raw_preview_tag_set::~dng_raw_preview_tag_set ()
514	{
515
516	}
517
518/*****************************************************************************/
519
520dng_raw_preview::dng_raw_preview ()
521
522	:	fImage				()
523	,	fOpcodeList2Data	()
524	,	fCompressionQuality (-1)
525	,	fIFD				()
526
527	{
528
529	}
530
531/*****************************************************************************/
532
533dng_raw_preview::~dng_raw_preview ()
534	{
535
536	}
537
538/*****************************************************************************/
539
540dng_basic_tag_set * dng_raw_preview::AddTagSet (dng_tiff_directory &directory) const
541	{
542
543	fIFD.fNewSubFileType = sfPreviewImage;
544
545	fIFD.fImageWidth  = fImage->Width  ();
546	fIFD.fImageLength = fImage->Height ();
547
548	fIFD.fSamplesPerPixel = fImage->Planes ();
549
550	fIFD.fPhotometricInterpretation = piLinearRaw;
551
552	if (fImage->PixelType () == ttFloat)
553		{
554
555		fIFD.fCompression = ccDeflate;
556
557		fIFD.fCompressionQuality = fCompressionQuality;
558
559		fIFD.fPredictor = cpFloatingPoint;
560
561		for (uint32 j = 0; j < fIFD.fSamplesPerPixel; j++)
562			{
563			fIFD.fBitsPerSample [j] = 16;
564			fIFD.fSampleFormat  [j] = sfFloatingPoint;
565			}
566
567		fIFD.FindTileSize (512 * 1024);
568
569		}
570
571	else
572		{
573
574		fIFD.fCompression = ccLossyJPEG;
575
576		fIFD.fCompressionQuality = fCompressionQuality;
577
578		fIFD.fBitsPerSample [0] = TagTypeSize (fImage->PixelType ()) * 8;
579
580		for (uint32 j = 1; j < fIFD.fSamplesPerPixel; j++)
581			{
582			fIFD.fBitsPerSample [j] = fIFD.fBitsPerSample [0];
583			}
584
585		fIFD.FindTileSize (512 * 512 * fIFD.fSamplesPerPixel);
586
587		}
588
589	return new dng_raw_preview_tag_set (directory, *this, fIFD);
590
591	}
592
593/*****************************************************************************/
594
595void dng_raw_preview::WriteData (dng_host &host,
596								 dng_image_writer &writer,
597								 dng_basic_tag_set &basic,
598								 dng_stream &stream) const
599	{
600
601	writer.WriteImage (host,
602					   fIFD,
603					   basic,
604					   stream,
605				       *fImage.Get ());
606
607	}
608
609/*****************************************************************************/
610
611dng_mask_preview::dng_mask_preview ()
612
613	:	fImage				()
614	,	fCompressionQuality (-1)
615	,	fIFD				()
616
617	{
618
619	}
620
621/*****************************************************************************/
622
623dng_mask_preview::~dng_mask_preview ()
624	{
625
626	}
627
628/*****************************************************************************/
629
630dng_basic_tag_set * dng_mask_preview::AddTagSet (dng_tiff_directory &directory) const
631	{
632
633	fIFD.fNewSubFileType = sfPreviewMask;
634
635	fIFD.fImageWidth  = fImage->Width  ();
636	fIFD.fImageLength = fImage->Height ();
637
638	fIFD.fSamplesPerPixel = 1;
639
640	fIFD.fPhotometricInterpretation = piTransparencyMask;
641
642	fIFD.fCompression = ccDeflate;
643	fIFD.fPredictor   = cpHorizontalDifference;
644
645	fIFD.fCompressionQuality = fCompressionQuality;
646
647	fIFD.fBitsPerSample [0] = TagTypeSize (fImage->PixelType ()) * 8;
648
649	fIFD.FindTileSize (512 * 512 * fIFD.fSamplesPerPixel);
650
651	return new dng_basic_tag_set (directory, fIFD);
652
653	}
654
655/*****************************************************************************/
656
657void dng_mask_preview::WriteData (dng_host &host,
658								  dng_image_writer &writer,
659								  dng_basic_tag_set &basic,
660								  dng_stream &stream) const
661	{
662
663	writer.WriteImage (host,
664					   fIFD,
665					   basic,
666					   stream,
667				       *fImage.Get ());
668
669	}
670
671/*****************************************************************************/
672
673dng_preview_list::dng_preview_list ()
674
675	:	fCount (0)
676
677	{
678
679	}
680
681/*****************************************************************************/
682
683dng_preview_list::~dng_preview_list ()
684	{
685
686	}
687
688/*****************************************************************************/
689
690void dng_preview_list::Append (AutoPtr<dng_preview> &preview)
691	{
692
693	if (preview.Get ())
694		{
695
696		DNG_ASSERT (fCount < kMaxDNGPreviews, "DNG preview list overflow");
697
698		if (fCount < kMaxDNGPreviews)
699			{
700
701			fPreview [fCount++] . Reset (preview.Release ());
702
703			}
704
705		}
706
707	}
708
709/*****************************************************************************/
710