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
28 class 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
dng_preview_tag_set(dng_tiff_directory & directory,const dng_preview & preview,const dng_ifd & ifd)63 dng_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
~dng_preview_tag_set()162 dng_preview_tag_set::~dng_preview_tag_set ()
163 {
164
165 }
166
167 /*****************************************************************************/
168
dng_preview()169 dng_preview::dng_preview ()
170
171 : fInfo ()
172
173 {
174
175 }
176
177 /*****************************************************************************/
178
~dng_preview()179 dng_preview::~dng_preview ()
180 {
181
182 }
183
184 /*****************************************************************************/
185
dng_image_preview()186 dng_image_preview::dng_image_preview ()
187
188 : fImage ()
189 , fIFD ()
190
191 {
192
193 }
194
195 /*****************************************************************************/
196
~dng_image_preview()197 dng_image_preview::~dng_image_preview ()
198 {
199
200 }
201
202 /*****************************************************************************/
203
AddTagSet(dng_tiff_directory & directory) const204 dng_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
WriteData(dng_host & host,dng_image_writer & writer,dng_basic_tag_set & basic,dng_stream & stream) const233 void 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
249 class 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
dng_jpeg_preview_tag_set(dng_tiff_directory & directory,const dng_jpeg_preview & preview,const dng_ifd & ifd)280 dng_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
~dng_jpeg_preview_tag_set()327 dng_jpeg_preview_tag_set::~dng_jpeg_preview_tag_set ()
328 {
329
330 }
331
332 /*****************************************************************************/
333
dng_jpeg_preview()334 dng_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
~dng_jpeg_preview()348 dng_jpeg_preview::~dng_jpeg_preview ()
349 {
350
351 }
352
353 /*****************************************************************************/
354
AddTagSet(dng_tiff_directory & directory) const355 dng_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
WriteData(dng_host &,dng_image_writer &,dng_basic_tag_set & basic,dng_stream & stream) const385 void 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
SpoolAdobeThumbnail(dng_stream & stream) const407 void 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
447 class 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
dng_raw_preview_tag_set(dng_tiff_directory & directory,const dng_raw_preview & preview,const dng_ifd & ifd)470 dng_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
~dng_raw_preview_tag_set()513 dng_raw_preview_tag_set::~dng_raw_preview_tag_set ()
514 {
515
516 }
517
518 /*****************************************************************************/
519
dng_raw_preview()520 dng_raw_preview::dng_raw_preview ()
521
522 : fImage ()
523 , fOpcodeList2Data ()
524 , fCompressionQuality (-1)
525 , fIFD ()
526
527 {
528
529 }
530
531 /*****************************************************************************/
532
~dng_raw_preview()533 dng_raw_preview::~dng_raw_preview ()
534 {
535
536 }
537
538 /*****************************************************************************/
539
AddTagSet(dng_tiff_directory & directory) const540 dng_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
WriteData(dng_host & host,dng_image_writer & writer,dng_basic_tag_set & basic,dng_stream & stream) const595 void 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
dng_mask_preview()611 dng_mask_preview::dng_mask_preview ()
612
613 : fImage ()
614 , fCompressionQuality (-1)
615 , fIFD ()
616
617 {
618
619 }
620
621 /*****************************************************************************/
622
~dng_mask_preview()623 dng_mask_preview::~dng_mask_preview ()
624 {
625
626 }
627
628 /*****************************************************************************/
629
AddTagSet(dng_tiff_directory & directory) const630 dng_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
WriteData(dng_host & host,dng_image_writer & writer,dng_basic_tag_set & basic,dng_stream & stream) const657 void 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
dng_preview_list()673 dng_preview_list::dng_preview_list ()
674
675 : fCount (0)
676
677 {
678
679 }
680
681 /*****************************************************************************/
682
~dng_preview_list()683 dng_preview_list::~dng_preview_list ()
684 {
685
686 }
687
688 /*****************************************************************************/
689
Append(AutoPtr<dng_preview> & preview)690 void 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