/*****************************************************************************/
// Copyright 2007-2022 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.
/*****************************************************************************/

#include "dng_preview.h"

#include "dng_assertions.h"
#include "dng_host.h"
#include "dng_image.h"
#include "dng_image_writer.h"
#include "dng_jxl.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 ()
	{
	
	}
		
/*****************************************************************************/

void dng_preview::SetIFDInfo (dng_host & /* host */,
							  const dng_image &image)
	{
	
	fIFD.fNewSubFileType = fInfo.fIsPrimary ? sfPreviewImage
											: sfAltPreviewImage;
	
	fIFD.fImageWidth  = image.Width	 ();
	fIFD.fImageLength = image.Height ();
	
	fIFD.fSamplesPerPixel = image.Planes ();

	fIFD.fPhotometricInterpretation = fIFD.fSamplesPerPixel == 1 ? piBlackIsZero
																 : piRGB;
																 
	fIFD.fBitsPerSample [0] = TagTypeSize (image.PixelType ()) * 8;
	
	fIFD.fSampleFormat [0] = image.PixelType () == ttFloat
							 ? sfFloatingPoint
							 : sfUnsignedInteger;
		
	for (uint32 j = 1; j < fIFD.fSamplesPerPixel; j++)
		{
		fIFD.fBitsPerSample [j] = fIFD.fBitsPerSample [0];
		fIFD.fSampleFormat  [j] = fIFD.fSampleFormat  [0];
		}
		
	fIFD.SetSingleStrip ();
	
	}
		
/*****************************************************************************/

dng_basic_tag_set * dng_preview::AddTagSet (dng_host & /* host */,
											dng_tiff_directory &directory) const
	{
	
	return new dng_preview_tag_set (directory, *this, fIFD);
	
	}

/*****************************************************************************/

void dng_preview::WriteData (dng_host &host,
							 dng_image_writer &writer,
							 dng_basic_tag_set &basic,
							 dng_stream &stream) const
	{
	
	if (fCompressedImage.get ())
		{
		
		fCompressedImage->WriteData (stream,
									 basic);
		
		}
		
	else
		{
	
		writer.WriteImage (host,
						   fIFD,
						   basic,
						   stream,
						   *fImage);
						   
		}
					
	}

/*****************************************************************************/

uint64 dng_preview::MaxImageDataByteCount () const
	{
	
	if (fCompressedImage.get ())
		{
		
		return fCompressedImage->NonHeaderSize ();
		
		}
		
	else
		{
		
		return fIFD.MaxImageDataByteCount ();
		
		}
	
	}
		
/*****************************************************************************/

void dng_preview::Compress (dng_host &host,
							dng_image_writer &writer)
	{
	
	if (fIFD.fCompression == ccJXL ||
		fIFD.fCompression == ccLossyJPEG ||
		fIFD.fCompression == ccDeflate)
		{
		
		AutoPtr<dng_compressed_image_tiles> compressedImage
											(new dng_compressed_image_tiles);
		
		compressedImage->EncodeTiles (host,
									  writer,
									  *fImage,
									  fIFD);
							
		fCompressedImage.reset (compressedImage.Release ());
		
		fImage.reset ();

		}
	
	}
		
/*****************************************************************************/

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);
		
	};

/******************************************************************************/

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, ifd.fYCbCrPositioning)
	
	,	fReferenceTag (tcReferenceBlackWhite, fReferenceData, 6)
	
	{
	
	if (ifd.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) ifd.fYCbCrSubSampleH;
		fSubSamplingData [1] = (uint16) ifd.fYCbCrSubSampleV;

		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);
		
		}
	
	}
		
/*****************************************************************************/

void dng_jpeg_preview::SetIFDInfo (dng_host &host,
								   const dng_image &image)
	{
	
	dng_preview::SetIFDInfo (host, image);
	
	fIFD.fCompression = ccJPEG;		// Lossy version
	
	if (image.Planes () == 1)
		{
		fIFD.fPhotometricInterpretation = piBlackIsZero;
		}
		
	else
		{
		SetYCbCr (1, 1);
		}
	
	}
		
/*****************************************************************************/

void dng_jpeg_preview::SetCompressedData (AutoPtr<dng_memory_block> &compressedData)
	{
	
	fImage.reset ();
	
	AutoPtr<dng_compressed_image_tiles> compressedTiles (new dng_compressed_image_tiles);
	
	compressedTiles->fData.resize (1);
	
	compressedTiles->fData [0].reset (compressedData.Release ());
	
	fCompressedImage.reset (compressedTiles.Release ());
	
	}
		
/*****************************************************************************/

const dng_memory_block & dng_jpeg_preview::CompressedData () const
	{
	
	DNG_REQUIRE (fCompressedImage.get () &&
				 fCompressedImage->fData.size () == 1,
				 "No compressed data");
	
	return *(fCompressedImage->fData [0]);
	
	}
		
/*****************************************************************************/

dng_basic_tag_set * dng_jpeg_preview::AddTagSet (dng_host & /* host */,
												 dng_tiff_directory &directory) const
	{
	
	return new dng_jpeg_preview_tag_set (directory, *this, fIFD);
	
	}
		
/*****************************************************************************/

void dng_jpeg_preview::WriteData (dng_host &host,
								  dng_image_writer &writer,
								  dng_basic_tag_set &basic,
								  dng_stream &stream) const
	{
	
	// Force the data to be written using lossy JPEG.
	
	fIFD.fCompression = ccLossyJPEG;
	
	dng_preview::WriteData (host,
							writer,
							basic,
							stream);
								  
	// But we still want to use the normal jpeg compression code in the IFD.
	
	fIFD.fCompression = ccJPEG;
			
	}
		
/*****************************************************************************/

uint64 dng_jpeg_preview::MaxImageDataByteCount () const
	{
	
	fIFD.fCompression = ccLossyJPEG;
	
	uint64 result = dng_preview::MaxImageDataByteCount ();
	
	fIFD.fCompression = ccJPEG;
	
	return result;
	
	}
		
/*****************************************************************************/

void dng_jpeg_preview::Compress (dng_host &host,
								 dng_image_writer &writer)
	{
	
	fIFD.fCompression = ccLossyJPEG;
	
	dng_preview::Compress (host, writer);
	
	fIFD.fCompression = ccJPEG;
	
	}
		
/*****************************************************************************/

void dng_jpeg_preview::SpoolAdobeThumbnail (dng_stream &stream) const
	{
	
	DNG_ASSERT (fIFD.fPhotometricInterpretation == piYCbCr,
				"SpoolAdobeThumbnail: Non-YCbCr");
				
	uint32 compressedSize = CompressedData ().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 = (fIFD.fImageWidth * 24 + 31) / 32 * 4;
	
	stream.Put_uint32 (1);
	stream.Put_uint32 (fIFD.fImageWidth);
	stream.Put_uint32 (fIFD.fImageLength);
	stream.Put_uint32 (widthBytes);
	stream.Put_uint32 (widthBytes * fIFD.fImageLength);
	stream.Put_uint32 (compressedSize);
	stream.Put_uint16 (24);
	stream.Put_uint16 (1);
	
	stream.Put (CompressedData ().Buffer (),
				compressedSize);
				
	if (compressedSize & 1)
		{
		stream.Put_uint8 (0);
		}
	
	}
		
//*****************************************************************************/

void dng_jxl_preview::SetIFDInfo (dng_host &host,
								  const dng_image &image)
	{
	
	dng_preview::SetIFDInfo (host, image);
	
	// Store a copy of the preview info so that the writer can get information
	// about the color space.

	fIFD.fPreviewInfo = this->fInfo;

	fIFD.fCompression = ccJXL;
	fIFD.fPredictor	  = cpNullPredictor;

	AutoPtr<dng_jxl_encode_settings> settings (host.MakeJXLEncodeSettings (dng_host::use_case_RenderedPreview,
																		   image));

	fIFD.fJXLEncodeSettings.reset (settings.Release ());
	
	fIFD.fJXLDistance    = fIFD.fJXLEncodeSettings->Distance    ();
	fIFD.fJXLEffort      = fIFD.fJXLEncodeSettings->Effort      ();
	fIFD.fJXLDecodeSpeed = fIFD.fJXLEncodeSettings->DecodeSpeed ();

	}
		
/*****************************************************************************/

class dng_raw_preview_tag_set: public dng_preview_tag_set
	{
	
	private:
	
		tag_data_ptr fOpcodeList2Tag;
		
		tag_uint32_ptr fWhiteLevelTag;
		
		uint32 fWhiteLevelData [kMaxColorPlanes];
  
		tag_urational_ptr fBlackLevelTag;
		
		dng_urational fBlackLevelData [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.SamplesPerPixel ())

	,	fBlackLevelTag (tcBlackLevel,
						fBlackLevelData,
						preview.SamplesPerPixel ())
						
	{
									 
	if (preview.fOpcodeList2Data.Get ())
		{
		
		fOpcodeList2Tag.SetData	 (preview.fOpcodeList2Data->Buffer		());
		fOpcodeList2Tag.SetCount (preview.fOpcodeList2Data->LogicalSize ());
		
		directory.Add (&fOpcodeList2Tag);
		
		}
		
	if (preview.SampleFormat () == sfFloatingPoint)
		{
		
		for (uint32 j = 0; j < kMaxColorPlanes; j++)
			{
			fWhiteLevelData [j] = 32768;
			}
			
		directory.Add (&fWhiteLevelTag);
		
		}
  
	else
		{
		
		bool nonZeroBlack = false;
		
		for (uint32 j = 0; j < preview.SamplesPerPixel (); j++)
			{
			
			fBlackLevelData [j].Set_real64 (preview.fBlackLevel [j], 1);
			
			nonZeroBlack = nonZeroBlack || (preview.fBlackLevel [j] != 0.0);
			
			}
			
		if (nonZeroBlack)
			{
			
			directory.Add (&fBlackLevelTag);

			}
		
		}
		
	}

/*****************************************************************************/

dng_raw_preview_tag_set::~dng_raw_preview_tag_set ()
	{
	
	}

/*****************************************************************************/

dng_raw_preview::dng_raw_preview ()
	{
 
	for (uint32 n = 0; n < kMaxColorPlanes; n++)
		{
		fBlackLevel [n] = 0.0;
		}
	
	}
		
/*****************************************************************************/

void dng_raw_preview::SetIFDInfo (dng_host &host,
								  const dng_image &image)
	{
	
	dng_preview::SetIFDInfo (host, image);
	
	fIFD.fNewSubFileType = sfPreviewImage;
	
	fIFD.fPhotometricInterpretation = piLinearRaw;
	
	if (image.PixelType () == ttFloat)
		{

		if (fPreferJXL && SupportsJXL (*fImage))
			{
			fIFD.fCompression = ccJXL;
			fIFD.fPredictor	  = cpNullPredictor;
			}
	
		else
			{
			fIFD.fCompression		 = ccDeflate;
			fIFD.fCompressionQuality = fCompressionQuality;
			fIFD.fPredictor			 = cpFloatingPoint;
			}
		
		for (uint32 j = 0; j < fIFD.fSamplesPerPixel; j++)
			{
			fIFD.fBitsPerSample [j] = 16;
			}
			
		fIFD.FindTileSize (512 * 1024);
		
		}
		
	else
		{
	
		if (fPreferJXL && SupportsJXL (*fImage))
			{
			fIFD.fCompression = ccJXL;
			fIFD.fPredictor	  = cpNullPredictor;
			}
		
		else
			{
			fIFD.fCompression		 = ccLossyJPEG;
			fIFD.fCompressionQuality = fCompressionQuality;
			}
																	 
		fIFD.FindTileSize (512 * 512 * fIFD.fSamplesPerPixel);
		
		}
		
	if (fIFD.fCompression == ccJXL)
		{
		
		// Use default host for the raw preview compression settings so any customizations
		// targeted for the actual main image are not used.
		
		dng_host defaultHost;
		
		// Use same compression quality as if encoding a non-full size proxy image.
		
		AutoPtr<dng_jxl_encode_settings> settings (defaultHost.MakeJXLEncodeSettings (dng_host::use_case_ProxyImage,
																					  image));

		if (fForNegativeCache)
			{
			settings->SetEffort (1);
			}
		
		fIFD.fJXLEncodeSettings.reset (settings.Release ());
		
		fIFD.fJXLDistance    = fIFD.fJXLEncodeSettings->Distance    ();
		fIFD.fJXLEffort      = fIFD.fJXLEncodeSettings->Effort      ();
		fIFD.fJXLDecodeSpeed = fIFD.fJXLEncodeSettings->DecodeSpeed ();
		
		if (image.PixelType () == ttShort)
			{
		
			AutoPtr<JxlColorEncoding> encoding (new JxlColorEncoding);

			memset (encoding.Get (), 0, sizeof (JxlColorEncoding));
			
			// EncodeImageForCompression leaves the image far from linear gamma,
			// so let's pretend it is sRGB gamma.

			encoding->color_space	    = image.Planes () == 1 ? JXL_COLOR_SPACE_GRAY
															   : JXL_COLOR_SPACE_RGB;
			encoding->white_point	    = JXL_WHITE_POINT_D65;
			encoding->primaries		    = JXL_PRIMARIES_2100;
			encoding->transfer_function = JXL_TRANSFER_FUNCTION_SRGB;
			
			fIFD.fJXLColorEncoding.reset (encoding.Release ());
			
			}
		
		}

	}
		
/*****************************************************************************/

dng_basic_tag_set * dng_raw_preview::AddTagSet (dng_host & /* host */,
												dng_tiff_directory &directory) const
	{
	
	return new dng_raw_preview_tag_set (directory, *this, fIFD);
	
	}
		
/*****************************************************************************/

void dng_mask_preview::SetIFDInfo (dng_host &host,
								   const dng_image &image)
	{
	
	dng_preview::SetIFDInfo (host, image);
	
	fIFD.fNewSubFileType = sfPreviewMask;
	
	fIFD.fPhotometricInterpretation = piTransparencyMask;
	
	fIFD.FindTileSize (512 * 512 * fIFD.fSamplesPerPixel);
	
	if (fPreferJXL && SupportsJXL (*fImage))
		{
		fIFD.fCompression = ccJXL;
		fIFD.fPredictor	  = cpNullPredictor;
		}
	
	else
		{
		
		fIFD.fCompression = ccDeflate;
		fIFD.fPredictor	  = cpHorizontalDifference;

		fIFD.fCompressionQuality = fCompressionQuality;

		}
	
	if (fIFD.fCompression == ccJXL)
		{
		
		AutoPtr<dng_jxl_encode_settings> settings (host.MakeJXLEncodeSettings (dng_host::use_case_Transparency,
																			   image));

		if (fForNegativeCache)
			{
			settings->SetEffort (1);
			}
		
		fIFD.fJXLEncodeSettings.reset (settings.Release ());
		
		fIFD.fJXLDistance    = fIFD.fJXLEncodeSettings->Distance    ();
		fIFD.fJXLEffort      = fIFD.fJXLEncodeSettings->Effort      ();
		fIFD.fJXLDecodeSpeed = fIFD.fJXLEncodeSettings->DecodeSpeed ();
		
		}

	}
		
/*****************************************************************************/

dng_basic_tag_set * dng_mask_preview::AddTagSet (dng_host & /* host */,
												 dng_tiff_directory &directory) const
	{
	
	return new dng_basic_tag_set (directory, fIFD);
	
	}
		
/*****************************************************************************/

void dng_semantic_mask_preview::SetIFDInfo (dng_host &host,
											const dng_image &image)
	{
	
	dng_preview::SetIFDInfo (host, image);
	
	fIFD.fNewSubFileType = fOriginalSize ? sfSemanticMask
										 : sfPreviewSemanticMask;
	
	fIFD.fPhotometricInterpretation = piPhotometricMask;

	fIFD.FindTileSize (512 * 512 * fIFD.fSamplesPerPixel);

	if (fPreferJXL && SupportsJXL (*fImage))
		{
		fIFD.fCompression = ccJXL;
		fIFD.fPredictor	  = cpNullPredictor;
		}
	
	else
		{
	
		fIFD.fCompression = ccDeflate;
		fIFD.fPredictor	  = cpHorizontalDifference;

		fIFD.fCompressionQuality = fCompressionQuality;

		}
	
	if (fIFD.fCompression == ccJXL)
		{
		
		AutoPtr<dng_jxl_encode_settings> settings (host.MakeJXLEncodeSettings (dng_host::use_case_SemanticMask,
																			   image));

		if (fForNegativeCache)
			{
			settings->SetEffort (1);
			}
		
		fIFD.fJXLEncodeSettings.reset (settings.Release ());
		
		fIFD.fJXLDistance    = fIFD.fJXLEncodeSettings->Distance    ();
		fIFD.fJXLEffort      = fIFD.fJXLEncodeSettings->Effort      ();
		fIFD.fJXLDecodeSpeed = fIFD.fJXLEncodeSettings->DecodeSpeed ();
		
		}
	
	}
		
/*****************************************************************************/

dng_basic_tag_set * dng_semantic_mask_preview::AddTagSet (dng_host & /* host */,
														  dng_tiff_directory &directory) const
	{

	// Need to write the name and instance ID to the directory, too. Otherwise
	// we won't have corresponding labels when reading the image back in.

	fTagName.reset (new tag_string (tcSemanticName,
									fName,
									false));

	fTagInstanceID.reset (new tag_string (tcSemanticInstanceID,
										  fInstanceID,
										  false));

	directory.Add (fTagName.get ());

	directory.Add (fTagInstanceID.get ());

	// Also need to add the MaskSubArea info.

	fTagMaskSubArea.reset (new tag_uint32_ptr (tcMaskSubArea,
											   & fMaskSubArea [0],
											   4));
	
	directory.Add (fTagMaskSubArea.get ());

	return new dng_basic_tag_set (directory, fIFD);
	
	}
		
/*****************************************************************************/

void dng_depth_preview::SetIFDInfo (dng_host &host,
									const dng_image &image)
	{
	
	dng_preview::SetIFDInfo (host, image);
	
	fIFD.fNewSubFileType = fFullResolution ? sfDepthMap
										   : sfPreviewDepthMap;

	fIFD.fPhotometricInterpretation = piDepth;
	
	fIFD.FindTileSize (512 * 512 * fIFD.fSamplesPerPixel);
	
	if (fPreferJXL && SupportsJXL (*fImage))
		{
		fIFD.fCompression = ccJXL;
		fIFD.fPredictor	  = cpNullPredictor;
		}
	
	else
		{
		
		fIFD.fCompression = ccDeflate;
		fIFD.fPredictor	  = cpHorizontalDifference;

		fIFD.fCompressionQuality = fCompressionQuality;

		}
	
	if (fIFD.fCompression == ccJXL)
		{
		
		AutoPtr<dng_jxl_encode_settings> settings (host.MakeJXLEncodeSettings (dng_host::use_case_Depth,
																			   image));

		if (fForNegativeCache)
			{
			settings->SetEffort (1);
			}
		
		fIFD.fJXLEncodeSettings.reset (settings.Release ());
		
		fIFD.fJXLDistance    = fIFD.fJXLEncodeSettings->Distance    ();
		fIFD.fJXLEffort      = fIFD.fJXLEncodeSettings->Effort      ();
		fIFD.fJXLDecodeSpeed = fIFD.fJXLEncodeSettings->DecodeSpeed ();
		
		}
	
	}
		
/*****************************************************************************/

dng_basic_tag_set * dng_depth_preview::AddTagSet (dng_host & /* host */,
												  dng_tiff_directory &directory) const
	{
	
	return new dng_basic_tag_set (directory, fIFD);
	
	}

/*****************************************************************************/

void dng_preview_list::Append (AutoPtr<dng_preview> &preview)
	{
	
	if (preview.Get ())
		{
		
		std::shared_ptr<const dng_preview> entry (preview.Release ());
		
		fPreview.push_back (entry);
		
		}
	
	}
		
/*****************************************************************************/
