/*****************************************************************************/
// Copyright 2006-2019 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.
/*****************************************************************************/

/** \file
 * Support for holding buffers of sample data.
 */

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

#ifndef __dng_pixel_buffer__
#define __dng_pixel_buffer__

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

#include "dng_assertions.h"
#include "dng_rect.h"
#include "dng_safe_arithmetic.h"
#include "dng_tag_types.h"

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

/// Compute best set of step values for a given source and destination area and stride.

void OptimizeOrder (const void *&sPtr,
					void *&dPtr,
					uint32 sPixelSize,
					uint32 dPixelSize,
					uint32 &count0,
					uint32 &count1,
					uint32 &count2,
					int32 &sStep0,
					int32 &sStep1,
					int32 &sStep2,
					int32 &dStep0,
					int32 &dStep1,
					int32 &dStep2);

void OptimizeOrder (const void *&sPtr,
					uint32 sPixelSize,
					uint32 &count0,
					uint32 &count1,
					uint32 &count2,
					int32 &sStep0,
					int32 &sStep1,
					int32 &sStep2);

void OptimizeOrder (void *&dPtr,
					uint32 dPixelSize,
					uint32 &count0,
					uint32 &count1,
					uint32 &count2,
					int32 &dStep0,
					int32 &dStep1,
					int32 &dStep2);

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

#define qDebugPixelType 0

#if qDebugPixelType

#define ASSERT_PIXEL_TYPE(typeVal) CheckPixelType (typeVal)

#else

#define ASSERT_PIXEL_TYPE(typeVal) DNG_ASSERT (fPixelType == typeVal, "Pixel type access mismatch")

#endif

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

/// \brief Holds a buffer of pixel data with "pixel geometry" metadata.
///
/// The pixel geometry describes the layout in terms of how many planes, rows and columns
/// plus the steps (in bytes) between each column, row and plane.

class dng_pixel_buffer
	{
	
	public:
	
		// Area this buffer holds.
	
		dng_rect fArea;
		
		// Range of planes this buffer holds.
		
		uint32 fPlane;
		uint32 fPlanes;
		
		// Steps between pixels.
		
		int32 fRowStep;
		int32 fColStep;
		int32 fPlaneStep;
		
		// Basic pixel type (TIFF tag type code).
	
		uint32 fPixelType;
		
		// Size of pixel type in bytes.
		
		uint32 fPixelSize;
		
		// Pointer to buffer's data.
		
		void *fData;
		
		// Do we have write-access to this data?
		
		bool fDirty;
		
	private:
	
		void * InternalPixel (int32 row,
							  int32 col,
							  uint32 plane = 0) const
			{

			// TO DO: review this. do we set up buffers sometimes with "col" parameter
			// equal to 0, which would then cause this exception to throw?!

			#if 0

			// Ensure pixel to be accessed lies inside valid area.
			if (row < fArea.t || row >= fArea.b ||
				col < fArea.l || col >= fArea.r ||
				plane < fPlane || (plane - fPlane) >= fPlanes)
				{
				ThrowProgramError ("Out-of-range pixel access");
				}
			
			// Compute offset of pixel.
			const int64 rowOffset = SafeInt64Mult(fRowStep,
				static_cast<int64> (row) - static_cast<int64> (fArea.t));
			const int64 colOffset = SafeInt64Mult(fColStep,
				static_cast<int64> (col) - static_cast<int64> (fArea.l));
			const int64 planeOffset = SafeInt64Mult(fPlaneStep,
				static_cast<int64> (plane - fPlane));
			const int64 offset = SafeInt64Mult(static_cast<int64>(fPixelSize),
				SafeInt64Add(SafeInt64Add(rowOffset, colOffset), planeOffset));
			
			// Add offset to buffer base address.
			return static_cast<void *> (static_cast<uint8 *> (fData) + offset);

			#else

			#if qDNG64Bit
			
			return (void *)
				   (((uint8 *) fData) + (int64) fPixelSize *
					(fRowStep	* (int64) (row	 - fArea.t) +
					 fColStep	* (int64) (col	 - fArea.l) +
					 fPlaneStep * (int64) (plane - fPlane )));
			
			#else

			return (void *)
				   (((uint8 *) fData) + (int32) fPixelSize *
					(fRowStep	* (int32) (row	 - fArea.t) +
					 fColStep	* (int32) (col	 - fArea.l) +
					 fPlaneStep * (int32) (plane - fPlane )));

			#endif

			#endif

			}
			
		#if qDebugPixelType
			
		void CheckPixelType (uint32 pixelType) const;
		
		#endif
		
	public:
	
		dng_pixel_buffer ();
		
		/// Note: This constructor is for internal use only and should not be
		/// considered part of the DNG SDK API.
		///
		/// Initialize the pixel buffer according to the given parameters (see
		/// below). May throw an error if arithmetic overflow occurs when
		/// computing the row, column or plane step, or if an invalid value
		/// was passed for planarConfiguration.
		///
		/// \param area Area covered by the pixel buffer
		/// \param plane Index of the first plane
		/// \param planes Number of planes
		/// \param pixelType Pixel data type (one of the values defined in
		///		   dng_tag_types.h)
		/// \param planarConfiguration Layout of the pixel planes in memory: One
		///		   of pcInterleaved, pcPlanar, or pcRowInterleaved (defined in
		///		   dng_tag_values.h)
		/// \param data Pointer to the pixel data

		dng_pixel_buffer (const dng_rect &area, 
						  uint32 plane, 
						  uint32 planes,
						  uint32 pixelType, 
						  uint32 planarConfiguration,
						  void *data);
		
		dng_pixel_buffer (const dng_pixel_buffer &buffer);
		
		dng_pixel_buffer & operator= (const dng_pixel_buffer &buffer);

		virtual ~dng_pixel_buffer ();
		
		/// Get the range of pixel values.
		/// \retval Range of value a pixel can take. (Meaning [0, max] for unsigned case. Signed case is biased so [-32768, max - 32768].)

		uint32 PixelRange () const;

		/// Get extent of pixels in buffer
		/// \retval Rectangle giving valid extent of buffer.

		const dng_rect & Area () const
			{
			return fArea;
			}

		/// Number of planes of image data.
		/// \retval Number of planes held in buffer.

		uint32 Planes () const
			{
			return fPlanes;
			}

		/// Step, in pixels not bytes, between rows of data in buffer.
		/// \retval row step in pixels. May be negative.

		int32 RowStep () const
			{
			return fRowStep;
			}
			
		/// Step, in pixels not bytes, between planes of data in buffer.
		/// \retval plane step in pixels. May be negative.

		int32 PlaneStep () const
			{
			return fPlaneStep;
			}

		/// Get read-only untyped (void *) pointer to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as void *.

		const void * ConstPixel (int32 row,
								 int32 col,
								 uint32 plane = 0) const
			{
			
			return InternalPixel (row, col, plane);
					 
			}
			
		/// Get a writable untyped (void *) pointer to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as void *.

		void * DirtyPixel (int32 row,
						   int32 col,
						   uint32 plane = 0)
			{
			
			DNG_ASSERT (fDirty, "Dirty access to const pixel buffer");
			
			return InternalPixel (row, col, plane);
			
			}

		/// Get read-only uint8 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as uint8 *.
			
		const uint8 * ConstPixel_uint8 (int32 row,
										int32 col,
										uint32 plane = 0) const
			{
			
			ASSERT_PIXEL_TYPE (ttByte);

			return (const uint8 *) ConstPixel (row, col, plane);
			
			}

		const uint8 * ConstPixel_uint8_overrideType (int32 row,
										int32 col,
										uint32 plane = 0) const
			{
			
			// No type check

			return (const uint8 *) ConstPixel (row, col, plane);
			
			}
			
		/// Get a writable uint8 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as uint8 *.

		uint8 * DirtyPixel_uint8 (int32 row,
								  int32 col,
								  uint32 plane = 0)
			{
			
			ASSERT_PIXEL_TYPE (ttByte);

			return (uint8 *) DirtyPixel (row, col, plane);
			
			}

		uint8 * DirtyPixel_uint8_overrideType (int32 row,
								  int32 col,
								  uint32 plane = 0)
			{
			
			// No type check

			return (uint8 *) DirtyPixel (row, col, plane);
			
			}
			
		/// Get read-only int8 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as int8 *.

		const int8 * ConstPixel_int8 (int32 row,
									  int32 col,
									  uint32 plane = 0) const
			{
			
			ASSERT_PIXEL_TYPE (ttSByte);

			return (const int8 *) ConstPixel (row, col, plane);
			
			}
			
		/// Get a writable int8 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as int8 *.

		int8 * DirtyPixel_int8 (int32 row,
								int32 col,
								uint32 plane = 0)
			{
			
			ASSERT_PIXEL_TYPE (ttSByte);

			return (int8 *) DirtyPixel (row, col, plane);
			
			}
			
		/// Get read-only uint16 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as uint16 *.

		const uint16 * ConstPixel_uint16 (int32 row,
										  int32 col,
										  uint32 plane = 0) const
			{
			
			ASSERT_PIXEL_TYPE (ttShort);

			return (const uint16 *) ConstPixel (row, col, plane);
			
			}
			
		/// Get a writable uint16 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as uint16 *.

		uint16 * DirtyPixel_uint16 (int32 row,
									int32 col,
									uint32 plane = 0)
			{
			
			ASSERT_PIXEL_TYPE (ttShort);

			return (uint16 *) DirtyPixel (row, col, plane);
			
			}
			
		/// Get read-only int16 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as int16 *.

		const int16 * ConstPixel_int16 (int32 row,
										int32 col,
										uint32 plane = 0) const
			{
			
			ASSERT_PIXEL_TYPE (ttSShort);

			return (const int16 *) ConstPixel (row, col, plane);
			
			}
			
		/// Get a writable int16 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as int16 *.

		int16 * DirtyPixel_int16 (int32 row,
								  int32 col,
								  uint32 plane = 0)
			{
			
			ASSERT_PIXEL_TYPE (ttSShort);

			return (int16 *) DirtyPixel (row, col, plane);
			
			}

		/// Get read-only uint32 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as uint32 *.

		const uint32 * ConstPixel_uint32 (int32 row,
										  int32 col,
										  uint32 plane = 0) const
			{
			
			ASSERT_PIXEL_TYPE (ttLong);

			return (const uint32 *) ConstPixel (row, col, plane);
			
			}
			
		/// Get a writable uint32 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as uint32 *.

		uint32 * DirtyPixel_uint32 (int32 row,
									int32 col,
									uint32 plane = 0)
			{
			
			ASSERT_PIXEL_TYPE (ttLong);

			return (uint32 *) DirtyPixel (row, col, plane);
			
			}
			
		/// Get read-only int32 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as int32 *.

		const int32 * ConstPixel_int32 (int32 row,
										int32 col,
										uint32 plane = 0) const
			{
			
			ASSERT_PIXEL_TYPE (ttSLong);

			return (const int32 *) ConstPixel (row, col, plane);
			
			}
			
		/// Get a writable int32 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as int32 *.

		int32 * DirtyPixel_int32 (int32 row,
								  int32 col,
								  uint32 plane = 0)
			{
			
			ASSERT_PIXEL_TYPE (ttSLong);

			return (int32 *) DirtyPixel (row, col, plane);
			
			}

		/// Get read-only uint64 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as uint64 *.

		const uint64 * ConstPixel_uint64 (int32 row,
										  int32 col,
										  uint32 plane = 0) const
			{
			
			ASSERT_PIXEL_TYPE (ttLong8);

			return (const uint64 *) ConstPixel (row, col, plane);
			
			}
			
		/// Get a writable uint64 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as uint64 *.

		uint64 * DirtyPixel_uint64 (int32 row,
									int32 col,
									uint32 plane = 0)
			{
			
			ASSERT_PIXEL_TYPE (ttLong8);

			return (uint64 *) DirtyPixel (row, col, plane);
			
			}
			
		/// Get read-only int64 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as int64 *.

		const int64 * ConstPixel_int64 (int32 row,
										int32 col,
										uint32 plane = 0) const
			{
			
			ASSERT_PIXEL_TYPE (ttSLong8);

			return (const int64 *) ConstPixel (row, col, plane);
			
			}
			
		/// Get a writable int64 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as int64 *.

		int64 * DirtyPixel_int64 (int32 row,
								  int32 col,
								  uint32 plane = 0)
			{
			
			ASSERT_PIXEL_TYPE (ttSLong8);

			return (int64 *) DirtyPixel (row, col, plane);
			
			}

		/// Get read-only real32 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as real32 *.

		const real32 * ConstPixel_real32 (int32 row,
										  int32 col,
										  uint32 plane = 0) const
			{
			
			ASSERT_PIXEL_TYPE (ttFloat);

			return (const real32 *) ConstPixel (row, col, plane);
			
			}
			
		/// Get a writable real32 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as real32 *.

		real32 * DirtyPixel_real32 (int32 row,
									int32 col,
									uint32 plane = 0)
			{
			
			ASSERT_PIXEL_TYPE (ttFloat);

			return (real32 *) DirtyPixel (row, col, plane);
			
			}
		
		/// Get read-only real64 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as real64 *.

		const real64 * ConstPixel_real64 (int32 row,
										  int32 col,
										  uint32 plane = 0) const
			{

			ASSERT_PIXEL_TYPE (ttDouble);

			return (const real64 *) ConstPixel (row, col, plane);

			}

		/// Get a writable real64 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as real64 *.

		real64 * DirtyPixel_real64 (int32 row,
									int32 col,
									uint32 plane = 0)
			{

			ASSERT_PIXEL_TYPE (ttDouble);

			return (real64 *) DirtyPixel (row, col, plane);

			}

		/// Initialize a rectangular area of pixel buffer to a constant.
		/// \param area Rectangle of pixel buffer to set.
		/// \param plane Plane to start filling on.
		/// \param planes Number of planes to fill.
		/// \param value Constant value to set pixels to.

		void SetConstant (const dng_rect &area,
						  uint32 plane,
						  uint32 planes,
						  uint32 value);
		
		/// Initialize a rectangular area of pixel buffer to a constant unsigned 8-bit value.
		/// \param area Rectangle of pixel buffer to set.
		/// \param plane Plane to start filling on.
		/// \param planes Number of planes to fill.
		/// \param value Constant uint8 value to set pixels to.

		void SetConstant_uint8 (const dng_rect &area,
								uint32 plane,
								uint32 planes,
								uint8 value)
			{
			
			DNG_ASSERT (fPixelType == ttByte, "Mismatched pixel type");
			
			SetConstant (area, plane, planes, (uint32) value);
			
			}
		
		/// Initialize a rectangular area of pixel buffer to a constant unsigned 16-bit value.
		/// \param area Rectangle of pixel buffer to set.
		/// \param plane Plane to start filling on.
		/// \param planes Number of planes to fill.
		/// \param value Constant uint16 value to set pixels to.

		void SetConstant_uint16 (const dng_rect &area,
								 uint32 plane,
								 uint32 planes,
								 uint16 value)
			{
			
			DNG_ASSERT (fPixelType == ttShort, "Mismatched pixel type");
			
			SetConstant (area, plane, planes, (uint32) value);
			
			}
		
		/// Initialize a rectangular area of pixel buffer to a constant signed 16-bit value.
		/// \param area Rectangle of pixel buffer to set.
		/// \param plane Plane to start filling on.
		/// \param planes Number of planes to fill.
		/// \param value Constant int16 value to set pixels to.

		void SetConstant_int16 (const dng_rect &area,
								uint32 plane,
								uint32 planes,
								int16 value)
			{
			
			DNG_ASSERT (fPixelType == ttSShort, "Mismatched pixel type");
			
			SetConstant (area, plane, planes, (uint32) (uint16) value);
			
			}
		
		/// Initialize a rectangular area of pixel buffer to a constant unsigned 32-bit value.
		/// \param area Rectangle of pixel buffer to set.
		/// \param plane Plane to start filling on.
		/// \param planes Number of planes to fill.
		/// \param value Constant uint32 value to set pixels to.

		void SetConstant_uint32 (const dng_rect &area,
								 uint32 plane,
								 uint32 planes,
								 uint32 value)
			{
			
			DNG_ASSERT (fPixelType == ttLong, "Mismatched pixel type");
			
			SetConstant (area, plane, planes, value);
			
			}
		
		/// Initialize a rectangular area of pixel buffer to a constant real 32-bit value.
		/// \param area Rectangle of pixel buffer to set.
		/// \param plane Plane to start filling on.
		/// \param planes Number of planes to fill.
		/// \param value Constant real32 value to set pixels to.

		void SetConstant_real32 (const dng_rect &area,
								 uint32 plane,
								 uint32 planes,
								 real32 value)
			{
			
			DNG_ASSERT (fPixelType == ttFloat, "Mismatched pixel type");
			
			union
				{
				uint32 i;
				real32 f;
				} x;
				
			x.f = value;
			
			SetConstant (area, plane, planes, x.i);
			
			}

		/// Initialize a rectangular area of pixel buffer to zeros.
		/// \param area Rectangle of pixel buffer to zero.
		/// \param plane Plane to start filling on.
		/// \param planes Number of planes to fill.

		void SetZero (const dng_rect &area,
					  uint32 plane,
					  uint32 planes);
		
		/// Copy image data from an area of one pixel buffer to same area of another.
		/// \param src Buffer to copy from.
		/// \param area Rectangle of pixel buffer to copy.
		/// \param srcPlane Plane to start copy in src.
		/// \param dstPlane Plane to start copy in dst.
		/// \param planes Number of planes to copy.
		///
		/// Most pairings of the pixel types
		///		{ttByte, ttShort, ttSShort, ttLong, ttFloat}
		/// are currently supported, though not all pairings.
		///
		/// Copies between the identical pixel types preserve values.
		///
		/// Copies between an integer pixel type and ttFloat treat the
		/// integer pixel type as normalized values in [0,1].
		///
		/// Copies between ttShort and ttSShort toggle the sign bit and thus
		/// preserve the data as normalized values.
		///
		/// Copies supported between integer pixel types of different sizes
		/// generally perform a promotion or demotion; they do not scale
		/// the values (ttByte -> ttSShort is a special case, though it does
		/// not scale values either). Consequently, copies between integer
		/// pixel types of different sizes DO NOT PRESERVE NORMALIZED VALUES
		/// and thus in general do not preserve the appearance of image
		/// data represented by normalized values. This is by design, since
		/// dng_pixel_buffer objects are often used for non-normalized data.
		/// For example, a buffer may contain 10, 12 or 14-bit data.

		void CopyArea (const dng_pixel_buffer &src,
					   const dng_rect &area,
					   uint32 srcPlane,
					   uint32 dstPlane,
					   uint32 planes);
					   
		/// Copy image data from an area of one pixel buffer to same area of another.
		/// \param src Buffer to copy from.
		/// \param area Rectangle of pixel buffer to copy.
		/// \param plane Plane to start copy in src and this.
		/// \param planes Number of planes to copy.

		void CopyArea (const dng_pixel_buffer &src,
					   const dng_rect &area,
					   uint32 plane,
					   uint32 planes)
			{
			
			CopyArea (src, area, plane, plane, planes);
			
			}
					   
		/// Calculate the offset phase of destination rectangle relative to source rectangle.
		/// Phase is based on a 0,0 origin and the notion of repeating srcArea across dstArea.
		/// It is the number of pixels into srcArea to start repeating from when tiling dstArea.
		/// \retval dng_point containing horizontal and vertical phase.

		static dng_point RepeatPhase (const dng_rect &srcArea,
									  const dng_rect &dstArea);

		/// Repeat the image data in srcArea across dstArea.
		/// (Generally used for padding operations.)
		/// \param srcArea Area to repeat from.
		/// \param dstArea Area to fill with data from srcArea.

		void RepeatArea (const dng_rect &srcArea,
						 const dng_rect &dstArea);
						 
		/// Replicates a sub-area of a buffer to fill the entire buffer.
		
		void RepeatSubArea (const dng_rect subArea,
							uint32 repeatV = 1,
							uint32 repeatH = 1);

		/// Apply a right shift (C++ oerpator >>) to all pixel values. Only implemented for 16-bit (signed or unsigned) pixel buffers.
		/// \param shift Number of bits by which to right shift each pixel value.

		void ShiftRight (uint32 shift);
		
		/// Change metadata so pixels are iterated in opposite horizontal order.
		/// This operation does not require movement of actual pixel data.

		void FlipH ();
		
		/// Change metadata so pixels are iterated in opposite vertical order.
		/// This operation does not require movement of actual pixel data.

		void FlipV ();
		
		/// Change metadata so pixels are iterated in opposite plane order.
		/// This operation does not require movement of actual pixel data.

		void FlipZ ();	// Flip planes
		
		/// Return true if the contents of an area of the pixel buffer area are the same as those of another.
		/// \param rhs Buffer to compare against.
		/// \param area Rectangle of pixel buffer to test.
		/// \param plane Plane to start comparing.
		/// \param planes Number of planes to compare.
		/// \retval bool true if areas are equal, false otherwise.

		bool EqualArea (const dng_pixel_buffer &rhs,
						const dng_rect &area,
						uint32 plane,
						uint32 planes) const;

		/// Return the absolute value of the maximum difference between two pixel buffers. Used for comparison testing with tolerance
		/// \param rhs Buffer to compare against.
		/// \param area Rectangle of pixel buffer to test.
		/// \param plane Plane to start comparing.
		/// \param planes Number of planes to compare.
		/// \retval larges absolute value difference between the corresponding pixels each buffer across area.

		real64 MaximumDifference (const dng_pixel_buffer &rhs,
								  const dng_rect &area,
								  uint32 plane,
								  uint32 planes) const;

	};

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

// Template versions of the DirtyPixel_xxx and ConstPixel_xxx methods.
// Facilitates use of those methods in templated functions.

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

template <typename T>
inline T * DirtyPixel (dng_pixel_buffer & pixBuf,
					   const int32 row,
					   const int32 col,
					   const uint32 plane = 0) = delete;

#define DEFINE_DIRTY_PIXEL_SPECIALIZATION_FOR_TYPE(T)		 \
	template <>												 \
	inline T * DirtyPixel (dng_pixel_buffer &pixBuf,		 \
						   const int32 row,					 \
						   const int32 col,					 \
						   const uint32 plane)				 \
		{													 \
															 \
		return pixBuf.DirtyPixel_ ## T (row, col, plane);	 \
															 \
		}

DEFINE_DIRTY_PIXEL_SPECIALIZATION_FOR_TYPE (uint8 )
DEFINE_DIRTY_PIXEL_SPECIALIZATION_FOR_TYPE ( int8 )
DEFINE_DIRTY_PIXEL_SPECIALIZATION_FOR_TYPE (uint16)
DEFINE_DIRTY_PIXEL_SPECIALIZATION_FOR_TYPE ( int16)
DEFINE_DIRTY_PIXEL_SPECIALIZATION_FOR_TYPE (uint32)
DEFINE_DIRTY_PIXEL_SPECIALIZATION_FOR_TYPE ( int32)
DEFINE_DIRTY_PIXEL_SPECIALIZATION_FOR_TYPE (uint64)
DEFINE_DIRTY_PIXEL_SPECIALIZATION_FOR_TYPE ( int64)
DEFINE_DIRTY_PIXEL_SPECIALIZATION_FOR_TYPE (real32)
DEFINE_DIRTY_PIXEL_SPECIALIZATION_FOR_TYPE (real64)

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

template <typename T>
inline const T * ConstPixel (const dng_pixel_buffer &pixBuf,
							 const int32 row,
							 const int32 col,
							 const uint32 plane = 0) = delete;

#define DEFINE_CONST_PIXEL_SPECIALIZATION_FOR_TYPE(T)			 \
	template <>													 \
	inline const T * ConstPixel (const dng_pixel_buffer &pixBuf, \
						  const int32 row,						 \
						  const int32 col,						 \
						  const uint32 plane)					 \
		{														 \
																 \
		return pixBuf.ConstPixel_ ## T (row, col, plane);		 \
																 \
		}

DEFINE_CONST_PIXEL_SPECIALIZATION_FOR_TYPE (uint8 )
DEFINE_CONST_PIXEL_SPECIALIZATION_FOR_TYPE ( int8 )
DEFINE_CONST_PIXEL_SPECIALIZATION_FOR_TYPE (uint16)
DEFINE_CONST_PIXEL_SPECIALIZATION_FOR_TYPE ( int16)
DEFINE_CONST_PIXEL_SPECIALIZATION_FOR_TYPE (uint32)
DEFINE_CONST_PIXEL_SPECIALIZATION_FOR_TYPE ( int32)
DEFINE_CONST_PIXEL_SPECIALIZATION_FOR_TYPE (uint64)
DEFINE_CONST_PIXEL_SPECIALIZATION_FOR_TYPE ( int64)
DEFINE_CONST_PIXEL_SPECIALIZATION_FOR_TYPE (real32)
DEFINE_CONST_PIXEL_SPECIALIZATION_FOR_TYPE (real64)

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

template <typename T>
inline constexpr T SignBit () = delete;

template <> inline constexpr   uint8 SignBit () { return  (uint8)0x80;       }
template <> inline constexpr    int8 SignBit () { return   (int8)0x80;       }
template <> inline constexpr  uint16 SignBit () { return (uint16)0x8000;     }
template <> inline constexpr   int16 SignBit () { return  (int16)0x8000;     }
template <> inline constexpr  uint32 SignBit () { return (uint32)0x80000000; }
template <> inline constexpr   int32 SignBit () { return  (int32)0x80000000; }
template <> inline constexpr  uint64 SignBit () { return (uint64)0x8000000000000000ULL; }
template <> inline constexpr   int64 SignBit () { return  (int64)0x8000000000000000ULL; }

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

#endif
	
/*****************************************************************************/
