Example #1
0
void dng_hue_sat_map::GetDelta (uint32 hueDiv,
								uint32 satDiv,
								uint32 valDiv,
								HSBModify &modify) const
	{

	if (hueDiv >= fHueDivisions ||
		satDiv >= fSatDivisions ||
		valDiv >= fValDivisions ||
		fDeltas.Buffer () == NULL)
		{
		
		DNG_REPORT ("Bad parameters to dng_hue_sat_map::GetDelta");
		
		ThrowProgramError ();
		
		}

	int32 offset = valDiv * fValStep +
				   hueDiv * fHueStep +
				   satDiv;

	const HSBModify *deltas = GetDeltas ();

	modify.fHueShift = deltas [offset].fHueShift;
	modify.fSatScale = deltas [offset].fSatScale;
	modify.fValScale = deltas [offset].fValScale;

	}
Example #2
0
dng_matrix::dng_matrix (uint32 rows,
						uint32 cols)
						
	:	fRows (0)
	,	fCols (0)
	
	{
	
	if (rows < 1 || rows > kMaxColorPlanes ||
		cols < 1 || cols > kMaxColorPlanes)
		{
		
		ThrowProgramError ();
		
		}
	
	fRows = rows;
	fCols = cols;
	
	for (uint32 row = 0; row < fRows; row++)
		for (uint32 col = 0; col < fCols; col++)
			{
			
			fData [row] [col] = 0.0;
			
			}
	
	}
Example #3
0
dng_memory_block * dng_stream::AsMemoryBlock (dng_memory_allocator &allocator)
	{
	Flush ();
	
	uint64 len64 = Length ();
	
	if (len64 > 0xFFFFFFFF)
		{
		ThrowProgramError ();
		}
	
	uint32 len = (uint32) len64;
	
	AutoPtr<dng_memory_block> block (allocator.Allocate (len));
	
	if (len)
		{
	
		SetReadPosition (0);
		
		Get (block->Buffer (), len);
		
		}

	return block.Release ();
	
	}
Example #4
0
dng_opcode_MapTable::dng_opcode_MapTable (dng_host &host,
										  const dng_area_spec &areaSpec,
										  const uint16 *table,
										  uint32 count)

	:	dng_inplace_opcode (dngOpcode_MapTable,
							dngVersion_1_3_0_0,
							kFlag_None)

	,	fAreaSpec (areaSpec)
	,	fTable    ()
	,	fCount    (count)

	{

	if (count == 0 || count > 0x10000)
		{
		ThrowProgramError ();
		}

	fTable.Reset (host.Allocate (0x10000 * sizeof (uint16)));

	DoCopyBytes (table,
				 fTable->Buffer (),
				 count * sizeof (uint16));

	ReplicateLastEntry ();

	}
Example #5
0
void dng_stream::DoWrite (const void * /* data */,
						  uint32 /* count */,
						  uint64 /* offset */)
	{
	
	ThrowProgramError ();

	}
Example #6
0
uint64 dng_stream::DoGetLength ()
	{
	
	ThrowProgramError ();

	return 0;
	
	}
Example #7
0
void dng_stream::DoRead (void * /* data */,
						 uint32 /* count */,
						 uint64 /* offset */)
	{
	
	ThrowProgramError ();

	}
dng_image * dng_image::Clone () const
	{
	
	ThrowProgramError ("Clone is not supported by this dng_image subclass");

	return NULL;
	
	}
void dng_image::AcquireTileBuffer (dng_tile_buffer & /* buffer */,
								   const dng_rect & /* area */,
								   bool /* dirty */) const
	{
	
	ThrowProgramError ();
	
	}
Example #10
0
dng_date_time_format dng_date_time_storage_info::Format () const
	{
	
	if (!IsValid ())
		ThrowProgramError ();
		
	return fFormat;
	
	}
Example #11
0
uint64 dng_date_time_storage_info::Offset () const
	{
	
	if (!IsValid ())
		ThrowProgramError ();
		
	return fOffset;
	
	}
Example #12
0
static void InitInnermostMutex ()
	{
	
	int result = pthread_key_create (&gInnermostMutexKey, NULL);

	DNG_ASSERT (result == 0, "pthread_key_create failed.");

	if (result != 0)
		ThrowProgramError ();

	}
void dng_image::Rotate (const dng_orientation &orientation)
	{
	
	if (orientation != dng_orientation::Normal ())
		{
		
		ThrowProgramError ("Rotate is not support by this dng_image subclass");
		
		}
	
	}
void dng_image::Trim (const dng_rect &r)
	{
	
	if (r != Bounds ())
		{
		
		ThrowProgramError ("Trim is not support by this dng_image subclass");
		
		}
	
	}
Example #15
0
static void SetInnermostMutex (dng_mutex *mutex)
	{

	int result;

	result = pthread_setspecific (gInnermostMutexKey, (void *)mutex);

	DNG_ASSERT (result == 0, "pthread_setspecific failed.");

	if (result != 0)
		ThrowProgramError ();

	}
void dng_image::SetPixelType (uint32 pixelType)
	{
	
	if (TagTypeSize (pixelType) != PixelSize ())
		{
		
		ThrowProgramError ("Cannot change pixel size for existing image");
		
		}
	
	fPixelType = pixelType;
	
	}
Example #17
0
void dng_condition::Broadcast ()
	{

	int result;

	result = pthread_cond_broadcast (&fPthreadCondition);

	DNG_ASSERT (result == 0, "pthread_cond_broadcast failed.");

	if (result != 0)
		ThrowProgramError ();

	}
Example #18
0
void dng_condition::Signal ()
	{

	int result;

	result = pthread_cond_signal (&fPthreadCondition);

	DNG_ASSERT (result == 0, "pthread_cond_signal failed.");

	if (result != 0)
		ThrowProgramError ();

	}
Example #19
0
void dng_camera_profile::SetFourColorBayer ()
	{
	
	uint32 j;
	
	if (!IsValid (3))
		{
		ThrowProgramError ();
		}
		
	if (fColorMatrix1.NotEmpty ())
		{
		
		dng_matrix m (4, 3);
		
		for (j = 0; j < 3; j++)
			{
			m [0] [j] = fColorMatrix1 [0] [j];
			m [1] [j] = fColorMatrix1 [1] [j];
			m [2] [j] = fColorMatrix1 [2] [j];
			m [3] [j] = fColorMatrix1 [1] [j];
			}
			
		fColorMatrix1 = m;
		
		}
	
	if (fColorMatrix2.NotEmpty ())
		{
		
		dng_matrix m (4, 3);
		
		for (j = 0; j < 3; j++)
			{
			m [0] [j] = fColorMatrix2 [0] [j];
			m [1] [j] = fColorMatrix2 [1] [j];
			m [2] [j] = fColorMatrix2 [2] [j];
			m [3] [j] = fColorMatrix2 [1] [j];
			}
			
		fColorMatrix2 = m;
		
		}
			
	fReductionMatrix1.Clear ();
	fReductionMatrix2.Clear ();
	
	fForwardMatrix1.Clear ();
	fForwardMatrix2.Clear ();
	
	}
Example #20
0
dng_condition::dng_condition ()

	:	fPthreadCondition ()

	{

	int result;

	result = pthread_cond_init (&fPthreadCondition, NULL);

	DNG_ASSERT (result == 0, "pthread_cond_init failed.");

	if (result != 0)
		{
		ThrowProgramError ();
		}

	}
Example #21
0
dng_vector::dng_vector (uint32 count)

	:	fCount (0)
	
	{
	
	if (count < 1 || count > kMaxColorPlanes)
		{
		
		ThrowProgramError ();
		
		}
	
	fCount = count;
	
	for (uint32 index = 0; index < fCount; index++)
		{
		
		fData [index] = 0.0;
		
		}
	
	}
real64 TickCountInSeconds ()
	{
	
	#if qWinOS
	
	return GetTickCount () * (1.0 / 1000.0);
	
	#elif qMacOS
	
	#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
	// TODO: Needs implementation.
	ThrowProgramError ("TickCountInSeconds() not implemented on iOS");
	return 0;
	#else	
	return TickCount () * (1.0 / 60.0);
	#endif  // TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
	
	#else
	
	return TickTimeInSeconds ();
	
	#endif
	
	}
void dng_image::GetEdge (dng_pixel_buffer &buffer,
					     edge_option edgeOption,
				         const dng_rect &srcArea,
				         const dng_rect &dstArea) const
	{
	
	switch (edgeOption)
		{
		
		case edge_zero:
			{
			
			buffer.SetZero (dstArea,
							buffer.fPlane,
							buffer.fPlanes);
							
			break;
			
			}
			
		case edge_repeat:
			{
			
			GetRepeat (buffer,
					   srcArea,
					   dstArea);
					   
			break;
						
			}
			
		case edge_repeat_zero_last:
			{
			
			if (buffer.fPlanes > 1)
				{
			
				dng_pixel_buffer buffer1 (buffer);
				
				buffer1.fPlanes--;
				
				GetEdge (buffer1,
						 edge_repeat,
						 srcArea,
						 dstArea);
						 
				}
				
			dng_pixel_buffer buffer2 (buffer);
			
			buffer2.fPlane  = buffer.fPlanes - 1;
			buffer2.fPlanes = 1;
			
			buffer2.fData = buffer.DirtyPixel (buffer2.fArea.t,
										  	   buffer2.fArea.l,
										  	   buffer2.fPlane);
										  
			GetEdge (buffer2,
					 edge_zero,
					 srcArea,
					 dstArea);
					 
			break;
			
			}
			
		default:
			{
			
			ThrowProgramError ();
			
			}
			
		}
	
	}
Example #24
0
dng_color_spec::dng_color_spec (const dng_negative &negative,
							    const dng_camera_profile *profile)
								
	:	fChannels (negative.ColorChannels ())
	
	,	fTemperature1 (0.0)
	,	fTemperature2 (0.0)
	
	,	fColorMatrix1 ()
	,	fColorMatrix2 ()
	
	,	fForwardMatrix1 ()
	,	fForwardMatrix2 ()
	
	,	fReductionMatrix1 ()
	,	fReductionMatrix2 ()
	
	,	fCameraCalibration1 ()
	,	fCameraCalibration2 ()
	
	,	fAnalogBalance ()
	
	,	fWhiteXY ()
	
	,	fCameraWhite ()
	,	fCameraToPCS ()
	
	,	fPCStoCamera ()
	
	{
	
	if (fChannels > 1)
		{
	
		if (!profile || !profile->IsValid (fChannels))
			{
			ThrowBadFormat ();
			}
			
		if (profile->WasStubbed ())
			{
			ThrowProgramError ("Using stubbed profile");
			}
		
		fTemperature1 = profile->CalibrationTemperature1 ();
		fTemperature2 = profile->CalibrationTemperature2 ();
		
		fColorMatrix1 = profile->ColorMatrix1 ();
		fColorMatrix2 = profile->ColorMatrix2 ();
				
		fForwardMatrix1 = profile->ForwardMatrix1 ();
		fForwardMatrix2 = profile->ForwardMatrix2 ();
				
		fReductionMatrix1 = profile->ReductionMatrix1 ();
		fReductionMatrix2 = profile->ReductionMatrix2 ();
		
		fCameraCalibration1.SetIdentity (fChannels);
		fCameraCalibration2.SetIdentity (fChannels);

		if (negative. CameraCalibrationSignature () ==
			profile->ProfileCalibrationSignature ())
			{
			
			if (negative.CameraCalibration1 ().Rows () == fChannels &&
				negative.CameraCalibration1 ().Cols () == fChannels)
				{
				
				fCameraCalibration1 = negative.CameraCalibration1 ();
				
				}
				
			if (negative.CameraCalibration2 ().Rows () == fChannels &&
				negative.CameraCalibration2 ().Cols () == fChannels)
				{
				
				fCameraCalibration2 = negative.CameraCalibration2 ();
				
				}
							
			}

		fAnalogBalance = dng_matrix (fChannels, fChannels);
		
		for (uint32 j = 0; j < fChannels; j++)
			{
			
			fAnalogBalance [j] [j] = negative.AnalogBalance (j);
			
			}

		dng_camera_profile::NormalizeForwardMatrix (fForwardMatrix1);
		
		fColorMatrix1 = fAnalogBalance * fCameraCalibration1 * fColorMatrix1;
								
		if (!profile->HasColorMatrix2 () ||
				fTemperature1 <= 0.0 ||
				fTemperature2 <= 0.0 ||
				fTemperature1 == fTemperature2)
			{
			
			fTemperature1 = 5000.0;
			fTemperature2 = 5000.0;
			
			fColorMatrix2       = fColorMatrix1;
			fForwardMatrix2     = fForwardMatrix1;
			fReductionMatrix2   = fReductionMatrix1;
			fCameraCalibration2 = fCameraCalibration1;
			
			}
			
		else
			{
			
			dng_camera_profile::NormalizeForwardMatrix (fForwardMatrix2);
			
			fColorMatrix2 = fAnalogBalance * fCameraCalibration2 * fColorMatrix2;
			
			// Swap values if temperatures are out of order.
											
			if (fTemperature1 > fTemperature2)
				{
				
				real64 temp   = fTemperature1;
				fTemperature1 = fTemperature2;
				fTemperature2 = temp;
				
				dng_matrix T  = fColorMatrix1;
				fColorMatrix1 = fColorMatrix2;
				fColorMatrix2 = T;
				
				T               = fForwardMatrix1;
				fForwardMatrix1 = fForwardMatrix2;
				fForwardMatrix2 = T;
				
				T                 = fReductionMatrix1;
				fReductionMatrix1 = fReductionMatrix2;
				fReductionMatrix2 = T;
				
				T                   = fCameraCalibration1;
				fCameraCalibration1 = fCameraCalibration2;
				fCameraCalibration2 = T;
				
				}
				
			}
			
		}
		
	}
Example #25
0
void dng_hue_sat_map::SetDelta (uint32 hueDiv,
								uint32 satDiv,
								uint32 valDiv,
								const HSBModify &modify)
	{

	if (hueDiv >= fHueDivisions ||
		satDiv >= fSatDivisions ||
		valDiv >= fValDivisions ||
		fDeltas.Buffer () == NULL)
		{
		
		DNG_REPORT ("Bad parameters to dng_hue_sat_map::SetDelta");
		
		ThrowProgramError ();
		
		}
		
	// Set this entry.
		
	int32 offset = valDiv * fValStep +
				   hueDiv * fHueStep +
				   satDiv;

	GetDeltas () [offset] = modify;
	
	// The zero saturation entry is required to have a value scale
	// of 1.0f.
	
	if (satDiv == 0)
		{
		
		if (modify.fValScale != 1.0f)
			{
			
			#if qDNGValidate
		
			ReportWarning ("Value scale for zero saturation entries must be 1.0");
						 
			#endif
			
			GetDeltas () [offset] . fValScale = 1.0f;
		
			}
		
		}
		
	// If we are settings the first saturation entry and we have not
	// set the zero saturation entry yet, fill in the zero saturation entry
	// by extrapolating first saturation entry.
	
	if (satDiv == 1)
		{
		
		HSBModify zeroSatModify;
		
		GetDelta (hueDiv, 0, valDiv, zeroSatModify);
		
		if (zeroSatModify.fValScale != 1.0f)
			{
			
			zeroSatModify.fHueShift = modify.fHueShift;
			zeroSatModify.fSatScale = modify.fSatScale;
			zeroSatModify.fValScale = 1.0f;
			
			SetDelta (hueDiv, 0, valDiv, zeroSatModify);
			
			}
		
		}

	}
Example #26
0
void dng_stream::DoSetLength (uint64 /* length */)
	{
	
	ThrowProgramError ();

	}
Example #27
0
dng_linearize_plane::dng_linearize_plane (dng_host &host,
										  dng_linearization_info &info,
										  const dng_image &srcImage,
										  dng_image &dstImage,
										  uint32 plane)

	:	fSrcImage (srcImage)
	,	fDstImage (dstImage)
	,	fPlane (plane)
	,	fActiveArea (info.fActiveArea)
	,	fSrcPixelType (srcImage.PixelType ())
	,	fDstPixelType (dstImage.PixelType ())
	,	fReal32 (false)
	,	fScale (0.0f)
	,	fScale_buffer ()
	,	fBlack_2D_rows (0)
	,	fBlack_2D_cols (0)
	,	fBlack_2D_buffer ()
	,	fBlack_1D_rows (0)
	,	fBlack_1D_buffer ()

	{

	uint32 j;
	uint32 k;

	// Make sure the source pixel type is supported.

	if (fSrcPixelType != ttByte  &&
		fSrcPixelType != ttShort &&
		fSrcPixelType != ttLong)
		{

		DNG_REPORT ("Unsupported source pixel type");

		ThrowProgramError ();

		}

	if (fDstPixelType != ttShort &&
		fDstPixelType != ttFloat)
		{

		DNG_REPORT ("Unsupported destination pixel type");

		ThrowProgramError ();

		}

	// Are we using floating point math?

	fReal32 = (fSrcPixelType == ttLong ||
			   fDstPixelType == ttFloat);

	// Find the scale for this plane.

	real64 maxBlack = info.MaxBlackLevel (plane);

	real64 minRange = info.fWhiteLevel [plane] - maxBlack;

	if (minRange <= 0.0)
		{
		ThrowBadFormat ();
		}

	real64 scale = 1.0 / minRange;

	fScale = (real32) scale;

	// Calculate two-dimensional black pattern, if any.

	if (info.fBlackDeltaH.Get ())
		{

		fBlack_2D_rows = info.fBlackLevelRepeatRows;
		fBlack_2D_cols = info.fActiveArea.W ();

		}

	else if (info.fBlackLevelRepeatCols > 1)
		{

		fBlack_2D_rows = info.fBlackLevelRepeatRows;
		fBlack_2D_cols = info.fBlackLevelRepeatCols;

		}

	if (fBlack_2D_rows)
		{

		fBlack_2D_buffer.Reset (host.Allocate (fBlack_2D_rows * fBlack_2D_cols * 4));

		for (j = 0; j < fBlack_2D_rows; j++)
			{

			for (k = 0;  k < fBlack_2D_cols; k++)
				{

				real64 x = info.fBlackLevel [j]
											[k % info.fBlackLevelRepeatCols]
											[plane];

				if (info.fBlackDeltaH.Get ())
					{

					x += info.fBlackDeltaH->Buffer_real64 () [k];

					}

				x *= scale;

				uint32 index = j * fBlack_2D_cols + k;

				if (fReal32)
					{

					fBlack_2D_buffer->Buffer_real32 () [index] = (real32) x;

					}

				else
					{

					x *= 0x0FFFF * 256.0;

					int32 y = Round_int32 (x);

					fBlack_2D_buffer->Buffer_int32 () [index] = y;

					}

				}

			}

		}

	// Calculate one-dimensional (per row) black pattern, if any.

	if (info.fBlackDeltaV.Get ())
		{

		fBlack_1D_rows = info.fActiveArea.H ();

		}

	else if (fBlack_2D_rows == 0 &&
			 (info.fBlackLevelRepeatRows > 1 || fSrcPixelType != ttShort))
		{

		fBlack_1D_rows = info.fBlackLevelRepeatRows;

		}

	if (fBlack_1D_rows)
		{

		fBlack_1D_buffer.Reset (host.Allocate (fBlack_1D_rows * 4));

		for (j = 0; j < fBlack_1D_rows; j++)
			{

			real64 x = 0.0;

			if (fBlack_2D_rows == 0)
				{

				x = info.fBlackLevel [j % info.fBlackLevelRepeatRows]
									 [0]
									 [plane];

				}

			if (info.fBlackDeltaV.Get ())
				{

				x += info.fBlackDeltaV->Buffer_real64 () [j];

				}

			x *= scale;

			if (fReal32)
				{

				fBlack_1D_buffer->Buffer_real32 () [j] = (real32) x;

				}

			else
				{

				x *= 0x0FFFF * 256.0;

				int32 y = Round_int32 (x);

				fBlack_1D_buffer->Buffer_int32 () [j] = y;

				}

			}

		}

	// Calculate scale table, if any.

	if (fSrcPixelType != ttLong)
		{

		// Find linearization table, if any.

		uint16 *lut = NULL;

		uint32 lutEntries = 0;

		if (info.fLinearizationTable.Get ())
			{

			lut = info.fLinearizationTable->Buffer_uint16 ();

			lutEntries = info.fLinearizationTable->LogicalSize () >> 1;

			}
Example #28
0
dng_hue_sat_map * dng_hue_sat_map::Interpolate (const dng_hue_sat_map &map1,
											    const dng_hue_sat_map &map2,
											    real64 weight1)
	{
	
	if (weight1 >= 1.0)
		{
		
		if (!map1.IsValid ())
			{
			
			DNG_REPORT ("map1 is not valid");
			
			ThrowProgramError ();
			
			}
			
		return new dng_hue_sat_map (map1);
		
		}
		
	if (weight1 <= 0.0)
		{
		
		if (!map2.IsValid ())
			{
			
			DNG_REPORT ("map2 is not valid");
			
			ThrowProgramError ();
			
			}
			
		return new dng_hue_sat_map (map2);
		
		}
		
	// Both maps must be valid if we are using both.
	
	if (!map1.IsValid () || !map2.IsValid ())
		{
			
		DNG_REPORT ("map1 or map2 is not valid");
		
		ThrowProgramError ();
		
		}
		
	// Must have the same dimensions.
	
	if (map1.fHueDivisions != map2.fHueDivisions ||
		map1.fSatDivisions != map2.fSatDivisions ||
		map1.fValDivisions != map2.fValDivisions)
		{
		
		DNG_REPORT ("map1 and map2 have different sizes");
		
		ThrowProgramError ();
		
		}
		
	// Make table to hold interpolated results.
	
	AutoPtr<dng_hue_sat_map> result (new dng_hue_sat_map);
	
	result->SetDivisions (map1.fHueDivisions,
						  map1.fSatDivisions,
						  map1.fValDivisions);
						  
	// Interpolate between the tables.
	
	real32 w1 = (real32) weight1;
	real32 w2 = 1.0f - w1;
	
	const HSBModify *data1 = map1.GetDeltas ();
	const HSBModify *data2 = map2.GetDeltas ();
	
	HSBModify *data3 = result->GetDeltas ();
	
	uint32 count = map1.DeltasCount ();
	
	for (uint32 index = 0; index < count; index++)
		{
		
		data3->fHueShift = w1 * data1->fHueShift +
						   w2 * data2->fHueShift;
						   
		data3->fSatScale = w1 * data1->fSatScale +
						   w2 * data2->fSatScale;
						   
		data3->fValScale = w1 * data1->fValScale +
						   w2 * data2->fValScale;
						   
		data1++;
		data2++;
		data3++;
		
		}
		
	// Return interpolated tables.
	
	return result.Release ();
		
	}
Example #29
0
void dng_xmp_sdk::InitializeSDK (dng_xmp_namespace * extraNamespaces)
	{
	
	if (!gInitializedXMP)
		{
		
		try
			{
			
			if (!SXMPMeta::Initialize ())
				{
				ThrowProgramError ();
				}
				
			// Register Lightroom beta settings namespace.
			// We no longer read this but I don't want to cut it out this close
			// to a release. [bruzenak]
			
				{
		
				TXMP_STRING_TYPE ss;
				
				SXMPMeta::RegisterNamespace (XMP_NS_CRX,
											 "crx",
											 &ss);
											 
				}
			
			// Register CRSS snapshots namespace
			
				{
				
				TXMP_STRING_TYPE ss;
				
				SXMPMeta::RegisterNamespace (XMP_NS_CRSS,
											 "crss",
											 &ss);
				
				}
			
			// Register extra namespaces.
			
			if (extraNamespaces != NULL)
				{
				
				for (; extraNamespaces->fullName != NULL; ++extraNamespaces)
					{
					
					TXMP_STRING_TYPE ss;
					
					SXMPMeta::RegisterNamespace (extraNamespaces->fullName,
												 extraNamespaces->shortName,
												 &ss);
					
					}
				
				}
			
			}
			
		CATCH_XMP ("Initialization", true)
		
	    gInitializedXMP = true;
		
		}
		
	}
Example #30
0
void dng_filter_task::Process (uint32 threadIndex,
							   const dng_rect &area,
							   dng_abort_sniffer * /* sniffer */)
	{
	
	// Find source area for this destination area.
	
	dng_rect srcArea = SrcArea (area);
					  
	// Setup srcBuffer.
	
	dng_pixel_buffer srcBuffer;
	
	srcBuffer.fArea = srcArea;
								
	srcBuffer.fPlane  = fSrcPlane;
	srcBuffer.fPlanes = fSrcPlanes;
	
	srcBuffer.fPixelType  = fSrcPixelType;
	srcBuffer.fPixelSize  = TagTypeSize (fSrcPixelType);
	
	srcBuffer.fPlaneStep = RoundUpForPixelSize (srcArea.W (),
											    srcBuffer.fPixelSize);
	
	srcBuffer.fRowStep = srcBuffer.fPlaneStep *
						 srcBuffer.fPlanes;
	
	if (fSrcPixelType == fSrcImage.PixelType ())
		{
		
		srcBuffer.fPixelRange = fSrcImage.PixelRange ();
		
		}
		
	else switch (fSrcPixelType)
		{
		
		case ttByte:
		case ttSByte:
			{
			srcBuffer.fPixelRange = 0x0FF;
			break;
			}
		
		case ttShort:
		case ttSShort:
			{
			srcBuffer.fPixelRange = 0x0FFFF;
			break;
			}
		
		case ttLong:
		case ttSLong:
			{
			srcBuffer.fPixelRange = 0xFFFFFFFF;
			break;
			}
			
		case ttFloat:
			break;
			
		default:
			ThrowProgramError ();
		
		}
		
	srcBuffer.fData = fSrcBuffer [threadIndex]->Buffer ();
	
	// Setup dstBuffer.
	
	dng_pixel_buffer dstBuffer;
	
	dstBuffer.fArea = area;
	
	dstBuffer.fPlane  = fDstPlane;
	dstBuffer.fPlanes = fDstPlanes;
	
	dstBuffer.fPixelType  = fDstPixelType;
	dstBuffer.fPixelSize  = TagTypeSize (fDstPixelType);
	
	dstBuffer.fPlaneStep = RoundUpForPixelSize (area.W (),
												dstBuffer.fPixelSize);
	
	dstBuffer.fRowStep = dstBuffer.fPlaneStep *
						 dstBuffer.fPlanes;
	
	if (fDstPixelType == fDstImage.PixelType ())
		{
		
		dstBuffer.fPixelRange = fDstImage.PixelRange ();
		
		}
		
	else switch (fDstPixelType)
		{
		
		case ttByte:
		case ttSByte:
			{
			dstBuffer.fPixelRange = 0x0FF;
			break;
			}
		
		case ttShort:
		case ttSShort:
			{
			dstBuffer.fPixelRange = 0x0FFFF;
			break;
			}
		
		case ttLong:
		case ttSLong:
			{
			dstBuffer.fPixelRange = 0xFFFFFFFF;
			break;
			}
			
		case ttFloat:
			break;
			
		default:
			ThrowProgramError ();
		
		}
		
	dstBuffer.fData = fDstBuffer [threadIndex]->Buffer ();
	
	// Get source pixels.
	
	fSrcImage.Get (srcBuffer,
				   dng_image::edge_repeat,
				   fSrcRepeat.v,
				   fSrcRepeat.h);
				   
	// Process area.
	
	ProcessArea (threadIndex,
				 srcBuffer,
				 dstBuffer);

	// Save result pixels.
	
	fDstImage.Put (dstBuffer);
	
	}