File indexing completed on 2025-01-19 03:55:11
0001 /*****************************************************************************/ 0002 // Copyright 2007-2019 Adobe Systems Incorporated 0003 // All Rights Reserved. 0004 // 0005 // NOTICE: Adobe permits you to use, modify, and distribute this file in 0006 // accordance with the terms of the Adobe license agreement accompanying it. 0007 /*****************************************************************************/ 0008 0009 #include "dng_preview.h" 0010 0011 #include "dng_assertions.h" 0012 #include "dng_image.h" 0013 #include "dng_image_writer.h" 0014 #include "dng_memory.h" 0015 #include "dng_stream.h" 0016 #include "dng_tag_codes.h" 0017 #include "dng_tag_values.h" 0018 0019 /*****************************************************************************/ 0020 0021 class dng_preview_tag_set: public dng_basic_tag_set 0022 { 0023 0024 private: 0025 0026 tag_string fApplicationNameTag; 0027 0028 tag_string fApplicationVersionTag; 0029 0030 tag_string fSettingsNameTag; 0031 0032 dng_fingerprint fSettingsDigest; 0033 0034 tag_uint8_ptr fSettingsDigestTag; 0035 0036 tag_uint32 fColorSpaceTag; 0037 0038 tag_string fDateTimeTag; 0039 0040 tag_real64 fRawToPreviewGainTag; 0041 0042 tag_uint32 fCacheVersionTag; 0043 0044 public: 0045 0046 dng_preview_tag_set (dng_tiff_directory &directory, 0047 const dng_preview &preview, 0048 const dng_ifd &ifd); 0049 0050 virtual ~dng_preview_tag_set (); 0051 0052 }; 0053 0054 /*****************************************************************************/ 0055 0056 dng_preview_tag_set::dng_preview_tag_set (dng_tiff_directory &directory, 0057 const dng_preview &preview, 0058 const dng_ifd &ifd) 0059 0060 : dng_basic_tag_set (directory, ifd) 0061 0062 , fApplicationNameTag (tcPreviewApplicationName, 0063 preview.fInfo.fApplicationName, 0064 false) 0065 0066 , fApplicationVersionTag (tcPreviewApplicationVersion, 0067 preview.fInfo.fApplicationVersion, 0068 false) 0069 0070 , fSettingsNameTag (tcPreviewSettingsName, 0071 preview.fInfo.fSettingsName, 0072 false) 0073 0074 , fSettingsDigest (preview.fInfo.fSettingsDigest) 0075 0076 , fSettingsDigestTag (tcPreviewSettingsDigest, 0077 fSettingsDigest.data, 0078 16) 0079 0080 , fColorSpaceTag (tcPreviewColorSpace, 0081 preview.fInfo.fColorSpace) 0082 0083 , fDateTimeTag (tcPreviewDateTime, 0084 preview.fInfo.fDateTime, 0085 true) 0086 0087 , fRawToPreviewGainTag (tcRawToPreviewGain, 0088 preview.fInfo.fRawToPreviewGain) 0089 0090 , fCacheVersionTag (tcCacheVersion, 0091 preview.fInfo.fCacheVersion) 0092 0093 { 0094 0095 if (preview.fInfo.fApplicationName.NotEmpty ()) 0096 { 0097 0098 directory.Add (&fApplicationNameTag); 0099 0100 } 0101 0102 if (preview.fInfo.fApplicationVersion.NotEmpty ()) 0103 { 0104 0105 directory.Add (&fApplicationVersionTag); 0106 0107 } 0108 0109 if (preview.fInfo.fSettingsName.NotEmpty ()) 0110 { 0111 0112 directory.Add (&fSettingsNameTag); 0113 0114 } 0115 0116 if (preview.fInfo.fSettingsDigest.IsValid ()) 0117 { 0118 0119 directory.Add (&fSettingsDigestTag); 0120 0121 } 0122 0123 if (preview.fInfo.fColorSpace != previewColorSpace_MaxEnum) 0124 { 0125 0126 directory.Add (&fColorSpaceTag); 0127 0128 } 0129 0130 if (preview.fInfo.fDateTime.NotEmpty ()) 0131 { 0132 0133 directory.Add (&fDateTimeTag); 0134 0135 } 0136 0137 if (preview.fInfo.fRawToPreviewGain != 1.0) 0138 { 0139 0140 directory.Add (&fRawToPreviewGainTag); 0141 0142 } 0143 0144 if (preview.fInfo.fCacheVersion != 0) 0145 { 0146 0147 directory.Add (&fCacheVersionTag); 0148 0149 } 0150 0151 } 0152 0153 /*****************************************************************************/ 0154 0155 dng_preview_tag_set::~dng_preview_tag_set () 0156 { 0157 0158 } 0159 0160 /*****************************************************************************/ 0161 0162 dng_preview::dng_preview () 0163 0164 : fInfo () 0165 0166 { 0167 0168 } 0169 0170 /*****************************************************************************/ 0171 0172 dng_preview::~dng_preview () 0173 { 0174 0175 } 0176 0177 /*****************************************************************************/ 0178 0179 dng_image_preview::dng_image_preview () 0180 0181 : fImage () 0182 , fIFD () 0183 0184 { 0185 0186 } 0187 0188 /*****************************************************************************/ 0189 0190 dng_image_preview::~dng_image_preview () 0191 { 0192 0193 } 0194 0195 /*****************************************************************************/ 0196 0197 dng_basic_tag_set * dng_image_preview::AddTagSet (dng_tiff_directory &directory) const 0198 { 0199 0200 fIFD.fNewSubFileType = fInfo.fIsPrimary ? sfPreviewImage 0201 : sfAltPreviewImage; 0202 0203 fIFD.fImageWidth = fImage->Width (); 0204 fIFD.fImageLength = fImage->Height (); 0205 0206 fIFD.fSamplesPerPixel = fImage->Planes (); 0207 0208 fIFD.fPhotometricInterpretation = fIFD.fSamplesPerPixel == 1 ? piBlackIsZero 0209 : piRGB; 0210 0211 fIFD.fBitsPerSample [0] = TagTypeSize (fImage->PixelType ()) * 8; 0212 0213 for (uint32 j = 1; j < fIFD.fSamplesPerPixel; j++) 0214 { 0215 fIFD.fBitsPerSample [j] = fIFD.fBitsPerSample [0]; 0216 } 0217 0218 fIFD.SetSingleStrip (); 0219 0220 return new dng_preview_tag_set (directory, *this, fIFD); 0221 0222 } 0223 0224 /*****************************************************************************/ 0225 0226 void dng_image_preview::WriteData (dng_host &host, 0227 dng_image_writer &writer, 0228 dng_basic_tag_set &basic, 0229 dng_stream &stream) const 0230 { 0231 0232 writer.WriteImage (host, 0233 fIFD, 0234 basic, 0235 stream, 0236 *fImage.Get ()); 0237 0238 } 0239 0240 /*****************************************************************************/ 0241 0242 class dng_jpeg_preview_tag_set: public dng_preview_tag_set 0243 { 0244 0245 private: 0246 0247 dng_urational fCoefficientsData [3]; 0248 0249 tag_urational_ptr fCoefficientsTag; 0250 0251 uint16 fSubSamplingData [2]; 0252 0253 tag_uint16_ptr fSubSamplingTag; 0254 0255 tag_uint16 fPositioningTag; 0256 0257 dng_urational fReferenceData [6]; 0258 0259 tag_urational_ptr fReferenceTag; 0260 0261 public: 0262 0263 dng_jpeg_preview_tag_set (dng_tiff_directory &directory, 0264 const dng_jpeg_preview &preview, 0265 const dng_ifd &ifd); 0266 0267 virtual ~dng_jpeg_preview_tag_set (); 0268 0269 }; 0270 0271 /******************************************************************************/ 0272 0273 dng_jpeg_preview_tag_set::dng_jpeg_preview_tag_set (dng_tiff_directory &directory, 0274 const dng_jpeg_preview &preview, 0275 const dng_ifd &ifd) 0276 0277 : dng_preview_tag_set (directory, preview, ifd) 0278 0279 , fCoefficientsTag (tcYCbCrCoefficients, fCoefficientsData, 3) 0280 0281 , fSubSamplingTag (tcYCbCrSubSampling, fSubSamplingData, 2) 0282 0283 , fPositioningTag (tcYCbCrPositioning, preview.fYCbCrPositioning) 0284 0285 , fReferenceTag (tcReferenceBlackWhite, fReferenceData, 6) 0286 0287 { 0288 0289 if (preview.fPhotometricInterpretation == piYCbCr) 0290 { 0291 0292 fCoefficientsData [0] = dng_urational (299, 1000); 0293 fCoefficientsData [1] = dng_urational (587, 1000); 0294 fCoefficientsData [2] = dng_urational (114, 1000); 0295 0296 directory.Add (&fCoefficientsTag); 0297 0298 fSubSamplingData [0] = (uint16) preview.fYCbCrSubSampling.h; 0299 fSubSamplingData [1] = (uint16) preview.fYCbCrSubSampling.v; 0300 0301 directory.Add (&fSubSamplingTag); 0302 0303 directory.Add (&fPositioningTag); 0304 0305 fReferenceData [0] = dng_urational ( 0, 1); 0306 fReferenceData [1] = dng_urational (255, 1); 0307 fReferenceData [2] = dng_urational (128, 1); 0308 fReferenceData [3] = dng_urational (255, 1); 0309 fReferenceData [4] = dng_urational (128, 1); 0310 fReferenceData [5] = dng_urational (255, 1); 0311 0312 directory.Add (&fReferenceTag); 0313 0314 } 0315 0316 } 0317 0318 /*****************************************************************************/ 0319 0320 dng_jpeg_preview_tag_set::~dng_jpeg_preview_tag_set () 0321 { 0322 0323 } 0324 0325 /*****************************************************************************/ 0326 0327 dng_jpeg_preview::dng_jpeg_preview () 0328 0329 : fPreviewSize () 0330 , fPhotometricInterpretation (piYCbCr) 0331 , fYCbCrSubSampling (1, 1) 0332 , fYCbCrPositioning (2) 0333 , fCompressedData () 0334 0335 { 0336 0337 } 0338 0339 /*****************************************************************************/ 0340 0341 dng_jpeg_preview::~dng_jpeg_preview () 0342 { 0343 0344 } 0345 0346 /*****************************************************************************/ 0347 0348 dng_basic_tag_set * dng_jpeg_preview::AddTagSet (dng_tiff_directory &directory) const 0349 { 0350 0351 dng_ifd ifd; 0352 0353 ifd.fNewSubFileType = fInfo.fIsPrimary ? sfPreviewImage 0354 : sfAltPreviewImage; 0355 0356 ifd.fImageWidth = fPreviewSize.h; 0357 ifd.fImageLength = fPreviewSize.v; 0358 0359 ifd.fPhotometricInterpretation = fPhotometricInterpretation; 0360 0361 ifd.fBitsPerSample [0] = 8; 0362 ifd.fBitsPerSample [1] = 8; 0363 ifd.fBitsPerSample [2] = 8; 0364 0365 ifd.fSamplesPerPixel = (fPhotometricInterpretation == piBlackIsZero ? 1 : 3); 0366 0367 ifd.fCompression = ccJPEG; 0368 ifd.fPredictor = cpNullPredictor; 0369 0370 ifd.SetSingleStrip (); 0371 0372 return new dng_jpeg_preview_tag_set (directory, *this, ifd); 0373 0374 } 0375 0376 /*****************************************************************************/ 0377 0378 void dng_jpeg_preview::WriteData (dng_host & /* host */, 0379 dng_image_writer & /* writer */, 0380 dng_basic_tag_set &basic, 0381 dng_stream &stream) const 0382 { 0383 0384 basic.SetTileOffset (0, (uint32) stream.Position ()); 0385 0386 basic.SetTileByteCount (0, fCompressedData->LogicalSize ()); 0387 0388 stream.Put (fCompressedData->Buffer (), 0389 fCompressedData->LogicalSize ()); 0390 0391 if (fCompressedData->LogicalSize () & 1) 0392 { 0393 stream.Put_uint8 (0); 0394 } 0395 0396 } 0397 0398 /*****************************************************************************/ 0399 0400 void dng_jpeg_preview::SpoolAdobeThumbnail (dng_stream &stream) const 0401 { 0402 0403 DNG_ASSERT (fCompressedData.Get (), 0404 "SpoolAdobeThumbnail: no data"); 0405 0406 DNG_ASSERT (fPhotometricInterpretation == piYCbCr, 0407 "SpoolAdobeThumbnail: Non-YCbCr"); 0408 0409 uint32 compressedSize = fCompressedData->LogicalSize (); 0410 0411 stream.Put_uint32 (DNG_CHAR4 ('8','B','I','M')); 0412 stream.Put_uint16 (1036); 0413 stream.Put_uint16 (0); 0414 0415 stream.Put_uint32 (compressedSize + 28); 0416 0417 uint32 widthBytes = (fPreviewSize.h * 24 + 31) / 32 * 4; 0418 0419 stream.Put_uint32 (1); 0420 stream.Put_uint32 (fPreviewSize.h); 0421 stream.Put_uint32 (fPreviewSize.v); 0422 stream.Put_uint32 (widthBytes); 0423 stream.Put_uint32 (widthBytes * fPreviewSize.v); 0424 stream.Put_uint32 (compressedSize); 0425 stream.Put_uint16 (24); 0426 stream.Put_uint16 (1); 0427 0428 stream.Put (fCompressedData->Buffer (), 0429 compressedSize); 0430 0431 if (compressedSize & 1) 0432 { 0433 stream.Put_uint8 (0); 0434 } 0435 0436 } 0437 0438 /*****************************************************************************/ 0439 0440 class dng_raw_preview_tag_set: public dng_preview_tag_set 0441 { 0442 0443 private: 0444 0445 tag_data_ptr fOpcodeList2Tag; 0446 0447 tag_uint32_ptr fWhiteLevelTag; 0448 0449 uint32 fWhiteLevelData [kMaxColorPlanes]; 0450 0451 tag_urational_ptr fBlackLevelTag; 0452 0453 dng_urational fBlackLevelData [kMaxColorPlanes]; 0454 0455 public: 0456 0457 dng_raw_preview_tag_set (dng_tiff_directory &directory, 0458 const dng_raw_preview &preview, 0459 const dng_ifd &ifd); 0460 0461 virtual ~dng_raw_preview_tag_set (); 0462 0463 }; 0464 0465 /*****************************************************************************/ 0466 0467 dng_raw_preview_tag_set::dng_raw_preview_tag_set (dng_tiff_directory &directory, 0468 const dng_raw_preview &preview, 0469 const dng_ifd &ifd) 0470 0471 : dng_preview_tag_set (directory, preview, ifd) 0472 0473 , fOpcodeList2Tag (tcOpcodeList2, 0474 ttUndefined, 0475 0, 0476 NULL) 0477 0478 , fWhiteLevelTag (tcWhiteLevel, 0479 fWhiteLevelData, 0480 preview.fImage->Planes ()) 0481 0482 , fBlackLevelTag (tcBlackLevel, 0483 fBlackLevelData, 0484 preview.fImage->Planes ()) 0485 0486 { 0487 0488 if (preview.fOpcodeList2Data.Get ()) 0489 { 0490 0491 fOpcodeList2Tag.SetData (preview.fOpcodeList2Data->Buffer ()); 0492 fOpcodeList2Tag.SetCount (preview.fOpcodeList2Data->LogicalSize ()); 0493 0494 directory.Add (&fOpcodeList2Tag); 0495 0496 } 0497 0498 if (preview.fImage->PixelType () == ttFloat) 0499 { 0500 0501 for (uint32 j = 0; j < kMaxColorPlanes; j++) 0502 { 0503 fWhiteLevelData [j] = 32768; 0504 } 0505 0506 directory.Add (&fWhiteLevelTag); 0507 0508 } 0509 0510 else 0511 { 0512 0513 bool nonZeroBlack = false; 0514 0515 for (uint32 j = 0; j < preview.fImage->Planes (); j++) 0516 { 0517 0518 fBlackLevelData [j].Set_real64 (preview.fBlackLevel [j], 1); 0519 0520 nonZeroBlack = nonZeroBlack || (preview.fBlackLevel [j] != 0.0); 0521 0522 } 0523 0524 if (nonZeroBlack) 0525 { 0526 0527 directory.Add (&fBlackLevelTag); 0528 0529 } 0530 0531 } 0532 0533 } 0534 0535 /*****************************************************************************/ 0536 0537 dng_raw_preview_tag_set::~dng_raw_preview_tag_set () 0538 { 0539 0540 } 0541 0542 /*****************************************************************************/ 0543 0544 dng_raw_preview::dng_raw_preview () 0545 0546 : fImage () 0547 , fOpcodeList2Data () 0548 , fCompressionQuality (-1) 0549 , fIFD () 0550 0551 { 0552 0553 for (uint32 n = 0; n < kMaxSamplesPerPixel; n++) 0554 { 0555 fBlackLevel [n] = 0.0; 0556 } 0557 0558 } 0559 0560 /*****************************************************************************/ 0561 0562 dng_raw_preview::~dng_raw_preview () 0563 { 0564 0565 } 0566 0567 /*****************************************************************************/ 0568 0569 dng_basic_tag_set * dng_raw_preview::AddTagSet (dng_tiff_directory &directory) const 0570 { 0571 0572 fIFD.fNewSubFileType = sfPreviewImage; 0573 0574 fIFD.fImageWidth = fImage->Width (); 0575 fIFD.fImageLength = fImage->Height (); 0576 0577 fIFD.fSamplesPerPixel = fImage->Planes (); 0578 0579 fIFD.fPhotometricInterpretation = piLinearRaw; 0580 0581 if (fImage->PixelType () == ttFloat) 0582 { 0583 0584 fIFD.fCompression = ccDeflate; 0585 0586 fIFD.fCompressionQuality = fCompressionQuality; 0587 0588 fIFD.fPredictor = cpFloatingPoint; 0589 0590 for (uint32 j = 0; j < fIFD.fSamplesPerPixel; j++) 0591 { 0592 fIFD.fBitsPerSample [j] = 16; 0593 fIFD.fSampleFormat [j] = sfFloatingPoint; 0594 } 0595 0596 fIFD.FindTileSize (512 * 1024); 0597 0598 } 0599 0600 else 0601 { 0602 0603 fIFD.fCompression = ccLossyJPEG; 0604 0605 fIFD.fCompressionQuality = fCompressionQuality; 0606 0607 fIFD.fBitsPerSample [0] = TagTypeSize (fImage->PixelType ()) * 8; 0608 0609 for (uint32 j = 1; j < fIFD.fSamplesPerPixel; j++) 0610 { 0611 fIFD.fBitsPerSample [j] = fIFD.fBitsPerSample [0]; 0612 } 0613 0614 fIFD.FindTileSize (512 * 512 * fIFD.fSamplesPerPixel); 0615 0616 } 0617 0618 return new dng_raw_preview_tag_set (directory, *this, fIFD); 0619 0620 } 0621 0622 /*****************************************************************************/ 0623 0624 void dng_raw_preview::WriteData (dng_host &host, 0625 dng_image_writer &writer, 0626 dng_basic_tag_set &basic, 0627 dng_stream &stream) const 0628 { 0629 0630 writer.WriteImage (host, 0631 fIFD, 0632 basic, 0633 stream, 0634 *fImage.Get ()); 0635 0636 } 0637 0638 /*****************************************************************************/ 0639 0640 dng_mask_preview::dng_mask_preview () 0641 0642 : fImage () 0643 , fCompressionQuality (-1) 0644 , fIFD () 0645 0646 { 0647 0648 } 0649 0650 /*****************************************************************************/ 0651 0652 dng_mask_preview::~dng_mask_preview () 0653 { 0654 0655 } 0656 0657 /*****************************************************************************/ 0658 0659 dng_basic_tag_set * dng_mask_preview::AddTagSet (dng_tiff_directory &directory) const 0660 { 0661 0662 fIFD.fNewSubFileType = sfPreviewMask; 0663 0664 fIFD.fImageWidth = fImage->Width (); 0665 fIFD.fImageLength = fImage->Height (); 0666 0667 fIFD.fSamplesPerPixel = 1; 0668 0669 fIFD.fPhotometricInterpretation = piTransparencyMask; 0670 0671 fIFD.fCompression = ccDeflate; 0672 fIFD.fPredictor = cpHorizontalDifference; 0673 0674 fIFD.fCompressionQuality = fCompressionQuality; 0675 0676 fIFD.fBitsPerSample [0] = TagTypeSize (fImage->PixelType ()) * 8; 0677 0678 fIFD.FindTileSize (512 * 512 * fIFD.fSamplesPerPixel); 0679 0680 return new dng_basic_tag_set (directory, fIFD); 0681 0682 } 0683 0684 /*****************************************************************************/ 0685 0686 void dng_mask_preview::WriteData (dng_host &host, 0687 dng_image_writer &writer, 0688 dng_basic_tag_set &basic, 0689 dng_stream &stream) const 0690 { 0691 0692 writer.WriteImage (host, 0693 fIFD, 0694 basic, 0695 stream, 0696 *fImage.Get ()); 0697 0698 } 0699 0700 /*****************************************************************************/ 0701 0702 dng_depth_preview::dng_depth_preview () 0703 0704 : fImage () 0705 , fCompressionQuality (-1) 0706 , fFullResolution (false) 0707 , fIFD () 0708 0709 { 0710 0711 } 0712 0713 /*****************************************************************************/ 0714 0715 dng_depth_preview::~dng_depth_preview () 0716 { 0717 0718 } 0719 0720 /*****************************************************************************/ 0721 0722 dng_basic_tag_set * dng_depth_preview::AddTagSet (dng_tiff_directory &directory) const 0723 { 0724 0725 fIFD.fNewSubFileType = fFullResolution ? sfDepthMap 0726 : sfPreviewDepthMap; 0727 0728 fIFD.fImageWidth = fImage->Width (); 0729 fIFD.fImageLength = fImage->Height (); 0730 0731 fIFD.fSamplesPerPixel = 1; 0732 0733 fIFD.fPhotometricInterpretation = piDepth; 0734 0735 fIFD.fCompression = ccDeflate; 0736 fIFD.fPredictor = cpHorizontalDifference; 0737 0738 fIFD.fCompressionQuality = fCompressionQuality; 0739 0740 fIFD.fBitsPerSample [0] = TagTypeSize (fImage->PixelType ()) * 8; 0741 0742 fIFD.FindTileSize (512 * 512 * fIFD.fSamplesPerPixel); 0743 0744 return new dng_basic_tag_set (directory, fIFD); 0745 0746 } 0747 0748 /*****************************************************************************/ 0749 0750 void dng_depth_preview::WriteData (dng_host &host, 0751 dng_image_writer &writer, 0752 dng_basic_tag_set &basic, 0753 dng_stream &stream) const 0754 { 0755 0756 writer.WriteImage (host, 0757 fIFD, 0758 basic, 0759 stream, 0760 *fImage.Get ()); 0761 0762 } 0763 0764 /*****************************************************************************/ 0765 0766 dng_preview_list::dng_preview_list () 0767 0768 : fCount (0) 0769 0770 { 0771 0772 } 0773 0774 /*****************************************************************************/ 0775 0776 dng_preview_list::~dng_preview_list () 0777 { 0778 0779 } 0780 0781 /*****************************************************************************/ 0782 0783 void dng_preview_list::Append (AutoPtr<dng_preview> &preview) 0784 { 0785 0786 if (preview.Get ()) 0787 { 0788 0789 DNG_ASSERT (fCount < kMaxDNGPreviews, "DNG preview list overflow"); 0790 0791 if (fCount < kMaxDNGPreviews) 0792 { 0793 0794 fPreview [fCount++] . Reset (preview.Release ()); 0795 0796 } 0797 0798 } 0799 0800 } 0801 0802 /*****************************************************************************/