/*****************************************************************************/ // Copyright 2007-2011 Adobe Systems Incorporated // All Rights Reserved. // // NOTICE: Adobe permits you to use, modify, and distribute this file in // accordance with the terms of the Adobe license agreement accompanying it. /*****************************************************************************/ /* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_preview.cpp#1 $ */ /* $DateTime: 2012/05/30 13:28:51 $ */ /* $Change: 832332 $ */ /* $Author: tknoll $ */ /*****************************************************************************/ #include "dng_preview.h" #include "dng_assertions.h" #include "dng_image.h" #include "dng_image_writer.h" #include "dng_memory.h" #include "dng_stream.h" #include "dng_tag_codes.h" #include "dng_tag_values.h" /*****************************************************************************/ class dng_preview_tag_set: public dng_basic_tag_set { private: tag_string fApplicationNameTag; tag_string fApplicationVersionTag; tag_string fSettingsNameTag; dng_fingerprint fSettingsDigest; tag_uint8_ptr fSettingsDigestTag; tag_uint32 fColorSpaceTag; tag_string fDateTimeTag; tag_real64 fRawToPreviewGainTag; tag_uint32 fCacheVersionTag; public: dng_preview_tag_set (dng_tiff_directory &directory, const dng_preview &preview, const dng_ifd &ifd); virtual ~dng_preview_tag_set (); }; /*****************************************************************************/ dng_preview_tag_set::dng_preview_tag_set (dng_tiff_directory &directory, const dng_preview &preview, const dng_ifd &ifd) : dng_basic_tag_set (directory, ifd) , fApplicationNameTag (tcPreviewApplicationName, preview.fInfo.fApplicationName, false) , fApplicationVersionTag (tcPreviewApplicationVersion, preview.fInfo.fApplicationVersion, false) , fSettingsNameTag (tcPreviewSettingsName, preview.fInfo.fSettingsName, false) , fSettingsDigest (preview.fInfo.fSettingsDigest) , fSettingsDigestTag (tcPreviewSettingsDigest, fSettingsDigest.data, 16) , fColorSpaceTag (tcPreviewColorSpace, preview.fInfo.fColorSpace) , fDateTimeTag (tcPreviewDateTime, preview.fInfo.fDateTime, true) , fRawToPreviewGainTag (tcRawToPreviewGain, preview.fInfo.fRawToPreviewGain) , fCacheVersionTag (tcCacheVersion, preview.fInfo.fCacheVersion) { if (preview.fInfo.fApplicationName.NotEmpty ()) { directory.Add (&fApplicationNameTag); } if (preview.fInfo.fApplicationVersion.NotEmpty ()) { directory.Add (&fApplicationVersionTag); } if (preview.fInfo.fSettingsName.NotEmpty ()) { directory.Add (&fSettingsNameTag); } if (preview.fInfo.fSettingsDigest.IsValid ()) { directory.Add (&fSettingsDigestTag); } if (preview.fInfo.fColorSpace != previewColorSpace_MaxEnum) { directory.Add (&fColorSpaceTag); } if (preview.fInfo.fDateTime.NotEmpty ()) { directory.Add (&fDateTimeTag); } if (preview.fInfo.fRawToPreviewGain != 1.0) { directory.Add (&fRawToPreviewGainTag); } if (preview.fInfo.fCacheVersion != 0) { directory.Add (&fCacheVersionTag); } } /*****************************************************************************/ dng_preview_tag_set::~dng_preview_tag_set () { } /*****************************************************************************/ dng_preview::dng_preview () : fInfo () { } /*****************************************************************************/ dng_preview::~dng_preview () { } /*****************************************************************************/ dng_image_preview::dng_image_preview () : fImage () , fIFD () { } /*****************************************************************************/ dng_image_preview::~dng_image_preview () { } /*****************************************************************************/ dng_basic_tag_set * dng_image_preview::AddTagSet (dng_tiff_directory &directory) const { fIFD.fNewSubFileType = fInfo.fIsPrimary ? sfPreviewImage : sfAltPreviewImage; fIFD.fImageWidth = fImage->Width (); fIFD.fImageLength = fImage->Height (); fIFD.fSamplesPerPixel = fImage->Planes (); fIFD.fPhotometricInterpretation = fIFD.fSamplesPerPixel == 1 ? piBlackIsZero : piRGB; fIFD.fBitsPerSample [0] = TagTypeSize (fImage->PixelType ()) * 8; for (uint32 j = 1; j < fIFD.fSamplesPerPixel; j++) { fIFD.fBitsPerSample [j] = fIFD.fBitsPerSample [0]; } fIFD.SetSingleStrip (); return new dng_preview_tag_set (directory, *this, fIFD); } /*****************************************************************************/ void dng_image_preview::WriteData (dng_host &host, dng_image_writer &writer, dng_basic_tag_set &basic, dng_stream &stream) const { writer.WriteImage (host, fIFD, basic, stream, *fImage.Get ()); } /*****************************************************************************/ class dng_jpeg_preview_tag_set: public dng_preview_tag_set { private: dng_urational fCoefficientsData [3]; tag_urational_ptr fCoefficientsTag; uint16 fSubSamplingData [2]; tag_uint16_ptr fSubSamplingTag; tag_uint16 fPositioningTag; dng_urational fReferenceData [6]; tag_urational_ptr fReferenceTag; public: dng_jpeg_preview_tag_set (dng_tiff_directory &directory, const dng_jpeg_preview &preview, const dng_ifd &ifd); virtual ~dng_jpeg_preview_tag_set (); }; /******************************************************************************/ dng_jpeg_preview_tag_set::dng_jpeg_preview_tag_set (dng_tiff_directory &directory, const dng_jpeg_preview &preview, const dng_ifd &ifd) : dng_preview_tag_set (directory, preview, ifd) , fCoefficientsTag (tcYCbCrCoefficients, fCoefficientsData, 3) , fSubSamplingTag (tcYCbCrSubSampling, fSubSamplingData, 2) , fPositioningTag (tcYCbCrPositioning, preview.fYCbCrPositioning) , fReferenceTag (tcReferenceBlackWhite, fReferenceData, 6) { if (preview.fPhotometricInterpretation == piYCbCr) { fCoefficientsData [0] = dng_urational (299, 1000); fCoefficientsData [1] = dng_urational (587, 1000); fCoefficientsData [2] = dng_urational (114, 1000); directory.Add (&fCoefficientsTag); fSubSamplingData [0] = (uint16) preview.fYCbCrSubSampling.h; fSubSamplingData [1] = (uint16) preview.fYCbCrSubSampling.v; directory.Add (&fSubSamplingTag); directory.Add (&fPositioningTag); fReferenceData [0] = dng_urational ( 0, 1); fReferenceData [1] = dng_urational (255, 1); fReferenceData [2] = dng_urational (128, 1); fReferenceData [3] = dng_urational (255, 1); fReferenceData [4] = dng_urational (128, 1); fReferenceData [5] = dng_urational (255, 1); directory.Add (&fReferenceTag); } } /*****************************************************************************/ dng_jpeg_preview_tag_set::~dng_jpeg_preview_tag_set () { } /*****************************************************************************/ dng_jpeg_preview::dng_jpeg_preview () : fPreviewSize () , fPhotometricInterpretation (piYCbCr) , fYCbCrSubSampling (1, 1) , fYCbCrPositioning (2) , fCompressedData () { } /*****************************************************************************/ dng_jpeg_preview::~dng_jpeg_preview () { } /*****************************************************************************/ dng_basic_tag_set * dng_jpeg_preview::AddTagSet (dng_tiff_directory &directory) const { dng_ifd ifd; ifd.fNewSubFileType = fInfo.fIsPrimary ? sfPreviewImage : sfAltPreviewImage; ifd.fImageWidth = fPreviewSize.h; ifd.fImageLength = fPreviewSize.v; ifd.fPhotometricInterpretation = fPhotometricInterpretation; ifd.fBitsPerSample [0] = 8; ifd.fBitsPerSample [1] = 8; ifd.fBitsPerSample [2] = 8; ifd.fSamplesPerPixel = (fPhotometricInterpretation == piBlackIsZero ? 1 : 3); ifd.fCompression = ccJPEG; ifd.fPredictor = cpNullPredictor; ifd.SetSingleStrip (); return new dng_jpeg_preview_tag_set (directory, *this, ifd); } /*****************************************************************************/ void dng_jpeg_preview::WriteData (dng_host & /* host */, dng_image_writer & /* writer */, dng_basic_tag_set &basic, dng_stream &stream) const { basic.SetTileOffset (0, (uint32) stream.Position ()); basic.SetTileByteCount (0, fCompressedData->LogicalSize ()); stream.Put (fCompressedData->Buffer (), fCompressedData->LogicalSize ()); if (fCompressedData->LogicalSize () & 1) { stream.Put_uint8 (0); } } /*****************************************************************************/ void dng_jpeg_preview::SpoolAdobeThumbnail (dng_stream &stream) const { DNG_ASSERT (fCompressedData.Get (), "SpoolAdobeThumbnail: no data"); DNG_ASSERT (fPhotometricInterpretation == piYCbCr, "SpoolAdobeThumbnail: Non-YCbCr"); uint32 compressedSize = fCompressedData->LogicalSize (); stream.Put_uint32 (DNG_CHAR4 ('8','B','I','M')); stream.Put_uint16 (1036); stream.Put_uint16 (0); stream.Put_uint32 (compressedSize + 28); uint32 widthBytes = (fPreviewSize.h * 24 + 31) / 32 * 4; stream.Put_uint32 (1); stream.Put_uint32 (fPreviewSize.h); stream.Put_uint32 (fPreviewSize.v); stream.Put_uint32 (widthBytes); stream.Put_uint32 (widthBytes * fPreviewSize.v); stream.Put_uint32 (compressedSize); stream.Put_uint16 (24); stream.Put_uint16 (1); stream.Put (fCompressedData->Buffer (), compressedSize); if (compressedSize & 1) { stream.Put_uint8 (0); } } /*****************************************************************************/ class dng_raw_preview_tag_set: public dng_preview_tag_set { private: tag_data_ptr fOpcodeList2Tag; tag_uint32_ptr fWhiteLevelTag; uint32 fWhiteLevelData [kMaxColorPlanes]; public: dng_raw_preview_tag_set (dng_tiff_directory &directory, const dng_raw_preview &preview, const dng_ifd &ifd); virtual ~dng_raw_preview_tag_set (); }; /*****************************************************************************/ dng_raw_preview_tag_set::dng_raw_preview_tag_set (dng_tiff_directory &directory, const dng_raw_preview &preview, const dng_ifd &ifd) : dng_preview_tag_set (directory, preview, ifd) , fOpcodeList2Tag (tcOpcodeList2, ttUndefined, 0, NULL) , fWhiteLevelTag (tcWhiteLevel, fWhiteLevelData, preview.fImage->Planes ()) { if (preview.fOpcodeList2Data.Get ()) { fOpcodeList2Tag.SetData (preview.fOpcodeList2Data->Buffer ()); fOpcodeList2Tag.SetCount (preview.fOpcodeList2Data->LogicalSize ()); directory.Add (&fOpcodeList2Tag); } if (preview.fImage->PixelType () == ttFloat) { for (uint32 j = 0; j < kMaxColorPlanes; j++) { fWhiteLevelData [j] = 32768; } directory.Add (&fWhiteLevelTag); } } /*****************************************************************************/ dng_raw_preview_tag_set::~dng_raw_preview_tag_set () { } /*****************************************************************************/ dng_raw_preview::dng_raw_preview () : fImage () , fOpcodeList2Data () , fCompressionQuality (-1) , fIFD () { } /*****************************************************************************/ dng_raw_preview::~dng_raw_preview () { } /*****************************************************************************/ dng_basic_tag_set * dng_raw_preview::AddTagSet (dng_tiff_directory &directory) const { fIFD.fNewSubFileType = sfPreviewImage; fIFD.fImageWidth = fImage->Width (); fIFD.fImageLength = fImage->Height (); fIFD.fSamplesPerPixel = fImage->Planes (); fIFD.fPhotometricInterpretation = piLinearRaw; if (fImage->PixelType () == ttFloat) { fIFD.fCompression = ccDeflate; fIFD.fCompressionQuality = fCompressionQuality; fIFD.fPredictor = cpFloatingPoint; for (uint32 j = 0; j < fIFD.fSamplesPerPixel; j++) { fIFD.fBitsPerSample [j] = 16; fIFD.fSampleFormat [j] = sfFloatingPoint; } fIFD.FindTileSize (512 * 1024); } else { fIFD.fCompression = ccLossyJPEG; fIFD.fCompressionQuality = fCompressionQuality; fIFD.fBitsPerSample [0] = TagTypeSize (fImage->PixelType ()) * 8; for (uint32 j = 1; j < fIFD.fSamplesPerPixel; j++) { fIFD.fBitsPerSample [j] = fIFD.fBitsPerSample [0]; } fIFD.FindTileSize (512 * 512 * fIFD.fSamplesPerPixel); } return new dng_raw_preview_tag_set (directory, *this, fIFD); } /*****************************************************************************/ void dng_raw_preview::WriteData (dng_host &host, dng_image_writer &writer, dng_basic_tag_set &basic, dng_stream &stream) const { writer.WriteImage (host, fIFD, basic, stream, *fImage.Get ()); } /*****************************************************************************/ dng_mask_preview::dng_mask_preview () : fImage () , fCompressionQuality (-1) , fIFD () { } /*****************************************************************************/ dng_mask_preview::~dng_mask_preview () { } /*****************************************************************************/ dng_basic_tag_set * dng_mask_preview::AddTagSet (dng_tiff_directory &directory) const { fIFD.fNewSubFileType = sfPreviewMask; fIFD.fImageWidth = fImage->Width (); fIFD.fImageLength = fImage->Height (); fIFD.fSamplesPerPixel = 1; fIFD.fPhotometricInterpretation = piTransparencyMask; fIFD.fCompression = ccDeflate; fIFD.fPredictor = cpHorizontalDifference; fIFD.fCompressionQuality = fCompressionQuality; fIFD.fBitsPerSample [0] = TagTypeSize (fImage->PixelType ()) * 8; fIFD.FindTileSize (512 * 512 * fIFD.fSamplesPerPixel); return new dng_basic_tag_set (directory, fIFD); } /*****************************************************************************/ void dng_mask_preview::WriteData (dng_host &host, dng_image_writer &writer, dng_basic_tag_set &basic, dng_stream &stream) const { writer.WriteImage (host, fIFD, basic, stream, *fImage.Get ()); } /*****************************************************************************/ dng_preview_list::dng_preview_list () : fCount (0) { } /*****************************************************************************/ dng_preview_list::~dng_preview_list () { } /*****************************************************************************/ void dng_preview_list::Append (AutoPtr<dng_preview> &preview) { if (preview.Get ()) { DNG_ASSERT (fCount < kMaxDNGPreviews, "DNG preview list overflow"); if (fCount < kMaxDNGPreviews) { fPreview [fCount++] . Reset (preview.Release ()); } } } /*****************************************************************************/