blob: c1380ebe5488bfb9922c9f79a27ca4b2c56b32e2 [file] [log] [blame]
/*****************************************************************************/
// Copyright 2006-2008 Adobe Systems Incorporated
// All Rights Reserved.
//
// NOTICE: Adobe permits you to use, modify, and distribute this file in
// accordance with the terms of the Adobe license agreement accompanying it.
/*****************************************************************************/
/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_pixel_buffer.cpp#1 $ */
/* $DateTime: 2012/05/30 13:28:51 $ */
/* $Change: 832332 $ */
/* $Author: tknoll $ */
/*****************************************************************************/
#include "dng_pixel_buffer.h"
#include "dng_bottlenecks.h"
#include "dng_exceptions.h"
#include "dng_flags.h"
#include "dng_safe_arithmetic.h"
#include "dng_tag_types.h"
#include "dng_tag_values.h"
#include "dng_utils.h"
/*****************************************************************************/
namespace {
bool SafeUint32ToInt32Mult(uint32 arg1, uint32 arg2, int32 *result) {
uint32 uint32_result;
return SafeUint32Mult(arg1, arg2, &uint32_result) &&
ConvertUint32ToInt32(uint32_result, result);
}
} // namespace
/*****************************************************************************/
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)
{
uint32 step0;
uint32 step1;
uint32 step2;
// Optimize the order for the data that is most spread out.
uint32 sRange = Abs_int32 (sStep0) * (count0 - 1) +
Abs_int32 (sStep1) * (count1 - 1) +
Abs_int32 (sStep2) * (count2 - 1);
uint32 dRange = Abs_int32 (dStep0) * (count0 - 1) +
Abs_int32 (dStep1) * (count1 - 1) +
Abs_int32 (dStep2) * (count2 - 1);
if (dRange >= sRange)
{
if (dStep0 < 0)
{
sPtr = (const void *)
(((const uint8 *) sPtr) + (int32)(count0 - 1) * sStep0 * (int32)sPixelSize);
dPtr = (void *)
(((uint8 *) dPtr) + (int32)(count0 - 1) * dStep0 * (int32)dPixelSize);
sStep0 = -sStep0;
dStep0 = -dStep0;
}
if (dStep1 < 0)
{
sPtr = (const void *)
(((const uint8 *) sPtr) + (int32)(count1 - 1) * sStep1 * (int32)sPixelSize);
dPtr = (void *)
(((uint8 *) dPtr) + (int32)(count1 - 1) * dStep1 * (int32)dPixelSize);
sStep1 = -sStep1;
dStep1 = -dStep1;
}
if (dStep2 < 0)
{
sPtr = (const void *)
(((const uint8 *) sPtr) + (int32)(count2 - 1) * sStep2 * (int32)sPixelSize);
dPtr = (void *)
(((uint8 *) dPtr) + (int32)(count2 - 1) * dStep2 * (int32)dPixelSize);
sStep2 = -sStep2;
dStep2 = -dStep2;
}
step0 = (uint32) dStep0;
step1 = (uint32) dStep1;
step2 = (uint32) dStep2;
}
else
{
if (sStep0 < 0)
{
sPtr = (const void *)
(((const uint8 *) sPtr) + (int32)(count0 - 1) * sStep0 * (int32)sPixelSize);
dPtr = (void *)
(((uint8 *) dPtr) + (int32)(count0 - 1) * dStep0 * (int32)dPixelSize);
sStep0 = -sStep0;
dStep0 = -dStep0;
}
if (sStep1 < 0)
{
sPtr = (const void *)
(((const uint8 *) sPtr) + (int32)(count1 - 1) * sStep1 * (int32)sPixelSize);
dPtr = (void *)
(((uint8 *) dPtr) + (int32)(count1 - 1) * dStep1 * (int32)dPixelSize);
sStep1 = -sStep1;
dStep1 = -dStep1;
}
if (sStep2 < 0)
{
sPtr = (const void *)
(((const uint8 *) sPtr) + (int32)(count2 - 1) * sStep2 * (int32)sPixelSize);
dPtr = (void *)
(((uint8 *) dPtr) + (int32)(count2 - 1) * dStep2 * (int32)dPixelSize);
sStep2 = -sStep2;
dStep2 = -dStep2;
}
step0 = (uint32) sStep0;
step1 = (uint32) sStep1;
step2 = (uint32) sStep2;
}
if (count0 == 1) step0 = 0xFFFFFFFF;
if (count1 == 1) step1 = 0xFFFFFFFF;
if (count2 == 1) step2 = 0xFFFFFFFF;
uint32 index0;
uint32 index1;
uint32 index2;
if (step0 >= step1)
{
if (step1 >= step2)
{
index0 = 0;
index1 = 1;
index2 = 2;
}
else if (step2 >= step0)
{
index0 = 2;
index1 = 0;
index2 = 1;
}
else
{
index0 = 0;
index1 = 2;
index2 = 1;
}
}
else
{
if (step0 >= step2)
{
index0 = 1;
index1 = 0;
index2 = 2;
}
else if (step2 >= step1)
{
index0 = 2;
index1 = 1;
index2 = 0;
}
else
{
index0 = 1;
index1 = 2;
index2 = 0;
}
}
uint32 count [3];
count [0] = count0;
count [1] = count1;
count [2] = count2;
count0 = count [index0];
count1 = count [index1];
count2 = count [index2];
int32 step [3];
step [0] = sStep0;
step [1] = sStep1;
step [2] = sStep2;
sStep0 = step [index0];
sStep1 = step [index1];
sStep2 = step [index2];
step [0] = dStep0;
step [1] = dStep1;
step [2] = dStep2;
dStep0 = step [index0];
dStep1 = step [index1];
dStep2 = step [index2];
if (sStep0 == ((int32) count1) * sStep1 &&
dStep0 == ((int32) count1) * dStep1)
{
count1 *= count0;
count0 = 1;
}
if (sStep1 == ((int32) count2) * sStep2 &&
dStep1 == ((int32) count2) * dStep2)
{
count2 *= count1;
count1 = 1;
}
}
/*****************************************************************************/
void OptimizeOrder (const void *&sPtr,
uint32 sPixelSize,
uint32 &count0,
uint32 &count1,
uint32 &count2,
int32 &sStep0,
int32 &sStep1,
int32 &sStep2)
{
void *dPtr = NULL;
int32 dStep0 = sStep0;
int32 dStep1 = sStep1;
int32 dStep2 = sStep2;
OptimizeOrder (sPtr,
dPtr,
sPixelSize,
sPixelSize,
count0,
count1,
count2,
sStep0,
sStep1,
sStep2,
dStep0,
dStep1,
dStep2);
}
/*****************************************************************************/
void OptimizeOrder (void *&dPtr,
uint32 dPixelSize,
uint32 &count0,
uint32 &count1,
uint32 &count2,
int32 &dStep0,
int32 &dStep1,
int32 &dStep2)
{
const void *sPtr = NULL;
int32 sStep0 = dStep0;
int32 sStep1 = dStep1;
int32 sStep2 = dStep2;
OptimizeOrder (sPtr,
dPtr,
dPixelSize,
dPixelSize,
count0,
count1,
count2,
sStep0,
sStep1,
sStep2,
dStep0,
dStep1,
dStep2);
}
/*****************************************************************************/
dng_pixel_buffer::dng_pixel_buffer ()
: fArea ()
, fPlane (0)
, fPlanes (1)
, fRowStep (1)
, fColStep (1)
, fPlaneStep (1)
, fPixelType (ttUndefined)
, fPixelSize (0)
, fData (NULL)
, fDirty (true)
{
}
/*****************************************************************************/
dng_pixel_buffer::dng_pixel_buffer (const dng_rect &area,
uint32 plane,
uint32 planes,
uint32 pixelType,
uint32 planarConfiguration,
void *data)
: fArea (area)
, fPlane (plane)
, fPlanes (planes)
, fRowStep (0)
, fColStep (0)
, fPlaneStep (0)
, fPixelType (pixelType)
, fPixelSize (TagTypeSize(pixelType))
, fData (data)
, fDirty (true)
{
const char *overflowMessage = "Arithmetic overflow in pixel buffer setup";
// Initialize fRowStep, fColStep and fPlaneStep according to the desired
// pixel layout.
switch (planarConfiguration)
{
case pcInterleaved:
fPlaneStep = 1;
if (!ConvertUint32ToInt32 (fPlanes, &fColStep) ||
!SafeUint32ToInt32Mult (fArea.W(), fPlanes, &fRowStep))
{
ThrowMemoryFull (overflowMessage);
}
break;
case pcPlanar:
fColStep = 1;
// Even though we've hardened dng_rect::W() to guarantee that it
// will never return a result that's out of range for an int32,
// we still protect the conversion for defense in depth.
if (!ConvertUint32ToInt32 (fArea.W(), &fRowStep) ||
!SafeUint32ToInt32Mult (fArea.H(), fArea.W(), &fPlaneStep))
{
ThrowMemoryFull (overflowMessage);
}
break;
case pcRowInterleaved:
case pcRowInterleavedAlign16:
{
fColStep = 1;
uint32 planeStepUint32;
if (planarConfiguration == pcRowInterleaved)
{
planeStepUint32 = fArea.W();
}
else
{
if (!RoundUpForPixelSize (fArea.W(), fPixelSize,
&planeStepUint32))
{
ThrowMemoryFull (overflowMessage);
}
}
if (!ConvertUint32ToInt32 (planeStepUint32, &fPlaneStep) ||
!SafeUint32ToInt32Mult (planeStepUint32, fPlanes, &fRowStep))
{
ThrowMemoryFull (overflowMessage);
}
break;
}
default:
ThrowProgramError ("Invalid value for 'planarConfiguration'");
break;
}
}
/*****************************************************************************/
dng_pixel_buffer::dng_pixel_buffer (const dng_pixel_buffer &buffer)
: fArea (buffer.fArea)
, fPlane (buffer.fPlane)
, fPlanes (buffer.fPlanes)
, fRowStep (buffer.fRowStep)
, fColStep (buffer.fColStep)
, fPlaneStep (buffer.fPlaneStep)
, fPixelType (buffer.fPixelType)
, fPixelSize (buffer.fPixelSize)
, fData (buffer.fData)
, fDirty (buffer.fDirty)
{
}
/*****************************************************************************/
dng_pixel_buffer & dng_pixel_buffer::operator= (const dng_pixel_buffer &buffer)
{
fArea = buffer.fArea;
fPlane = buffer.fPlane;
fPlanes = buffer.fPlanes;
fRowStep = buffer.fRowStep;
fColStep = buffer.fColStep;
fPlaneStep = buffer.fPlaneStep;
fPixelType = buffer.fPixelType;
fPixelSize = buffer.fPixelSize;
fPixelType = buffer.fPixelType;
fData = buffer.fData;
fDirty = buffer.fDirty;
return *this;
}
/*****************************************************************************/
dng_pixel_buffer::~dng_pixel_buffer ()
{
}
/*****************************************************************************/
#if qDebugPixelType
void dng_pixel_buffer::CheckPixelType (uint32 pixelType) const
{
if (fPixelType != pixelType)
{
DNG_REPORT ("Pixel type access mismatch");
}
}
#endif
/*****************************************************************************/
uint32 dng_pixel_buffer::PixelRange () const
{
switch (fPixelType)
{
case ttByte:
case ttSByte:
{
return 0x0FF;
}
case ttShort:
case ttSShort:
{
return 0x0FFFF;
}
case ttLong:
case ttSLong:
{
return 0xFFFFFFFF;
}
default:
break;
}
return 0;
}
/*****************************************************************************/
void dng_pixel_buffer::SetConstant (const dng_rect &area,
uint32 plane,
uint32 planes,
uint32 value)
{
uint32 rows = area.H ();
uint32 cols = area.W ();
void *dPtr = DirtyPixel (area.t,
area.l,
plane);
int32 dRowStep = fRowStep;
int32 dColStep = fColStep;
int32 dPlaneStep = fPlaneStep;
OptimizeOrder (dPtr,
fPixelSize,
rows,
cols,
planes,
dRowStep,
dColStep,
dPlaneStep);
switch (fPixelSize)
{
case 1:
{
if (rows == 1 && cols == 1 && dPlaneStep == 1 && value == 0)
{
DoZeroBytes (dPtr, planes);
}
else
{
DoSetArea8 ((uint8 *) dPtr,
(uint8) value,
rows,
cols,
planes,
dRowStep,
dColStep,
dPlaneStep);
}
break;
}
case 2:
{
if (rows == 1 && cols == 1 && dPlaneStep == 1 && value == 0)
{
DoZeroBytes (dPtr, planes << 1);
}
else
{
DoSetArea16 ((uint16 *) dPtr,
(uint16) value,
rows,
cols,
planes,
dRowStep,
dColStep,
dPlaneStep);
}
break;
}
case 4:
{
if (rows == 1 && cols == 1 && dPlaneStep == 1 && value == 0)
{
DoZeroBytes (dPtr, planes << 2);
}
else
{
DoSetArea32 ((uint32 *) dPtr,
value,
rows,
cols,
planes,
dRowStep,
dColStep,
dPlaneStep);
}
break;
}
default:
{
ThrowNotYetImplemented ();
}
}
}
/*****************************************************************************/
void dng_pixel_buffer::SetZero (const dng_rect &area,
uint32 plane,
uint32 planes)
{
uint32 value = 0;
switch (fPixelType)
{
case ttByte:
case ttShort:
case ttLong:
case ttFloat:
{
break;
}
case ttSShort:
{
value = 0x8000;
break;
}
default:
{
ThrowNotYetImplemented ();
}
}
SetConstant (area,
plane,
planes,
value);
}
/*****************************************************************************/
void dng_pixel_buffer::CopyArea (const dng_pixel_buffer &src,
const dng_rect &area,
uint32 srcPlane,
uint32 dstPlane,
uint32 planes)
{
uint32 rows = area.H ();
uint32 cols = area.W ();
const void *sPtr = src.ConstPixel (area.t,
area.l,
srcPlane);
void *dPtr = DirtyPixel (area.t,
area.l,
dstPlane);
int32 sRowStep = src.fRowStep;
int32 sColStep = src.fColStep;
int32 sPlaneStep = src.fPlaneStep;
int32 dRowStep = fRowStep;
int32 dColStep = fColStep;
int32 dPlaneStep = fPlaneStep;
OptimizeOrder (sPtr,
dPtr,
src.fPixelSize,
fPixelSize,
rows,
cols,
planes,
sRowStep,
sColStep,
sPlaneStep,
dRowStep,
dColStep,
dPlaneStep);
if (fPixelType == src.fPixelType)
{
if (rows == 1 && cols == 1 && sPlaneStep == 1 && dPlaneStep == 1)
{
DoCopyBytes (sPtr,
dPtr,
planes * fPixelSize);
}
else switch (fPixelSize)
{
case 1:
{
DoCopyArea8 ((const uint8 *) sPtr,
(uint8 *) dPtr,
rows,
cols,
planes,
sRowStep,
sColStep,
sPlaneStep,
dRowStep,
dColStep,
dPlaneStep);
break;
}
case 2:
{
DoCopyArea16 ((const uint16 *) sPtr,
(uint16 *) dPtr,
rows,
cols,
planes,
sRowStep,
sColStep,
sPlaneStep,
dRowStep,
dColStep,
dPlaneStep);
break;
}
case 4:
{
DoCopyArea32 ((const uint32 *) sPtr,
(uint32 *) dPtr,
rows,
cols,
planes,
sRowStep,
sColStep,
sPlaneStep,
dRowStep,
dColStep,
dPlaneStep);
break;
}
default:
{
ThrowNotYetImplemented ();
}
}
}
else if (src.fPixelType == ttByte)
{
switch (fPixelType)
{
case ttShort:
{
DoCopyArea8_16 ((const uint8 *) sPtr,
(uint16 *) dPtr,
rows,
cols,
planes,
sRowStep,
sColStep,
sPlaneStep,
dRowStep,
dColStep,
dPlaneStep);
break;
}
case ttSShort:
{
DoCopyArea8_S16 ((const uint8 *) sPtr,
(int16 *) dPtr,
rows,
cols,
planes,
sRowStep,
sColStep,
sPlaneStep,
dRowStep,
dColStep,
dPlaneStep);
break;
}
case ttLong:
{
DoCopyArea8_32 ((const uint8 *) sPtr,
(uint32 *) dPtr,
rows,
cols,
planes,
sRowStep,
sColStep,
sPlaneStep,
dRowStep,
dColStep,
dPlaneStep);
break;
}
case ttFloat:
{
DoCopyArea8_R32 ((const uint8 *) sPtr,
(real32 *) dPtr,
rows,
cols,
planes,
sRowStep,
sColStep,
sPlaneStep,
dRowStep,
dColStep,
dPlaneStep,
src.PixelRange ());
break;
}
default:
{
ThrowNotYetImplemented ();
}
}
}
else if (src.fPixelType == ttShort)
{
switch (fPixelType)
{
case ttByte:
{
DoCopyArea8 (((const uint8 *) sPtr) + (qDNGBigEndian ? 1 : 0),
(uint8 *) dPtr,
rows,
cols,
planes,
sRowStep << 1,
sColStep << 1,
sPlaneStep << 1,
dRowStep,
dColStep,
dPlaneStep);
break;
}
case ttSShort:
{
DoCopyArea16_S16 ((const uint16 *) sPtr,
(int16 *) dPtr,
rows,
cols,
planes,
sRowStep,
sColStep,
sPlaneStep,
dRowStep,
dColStep,
dPlaneStep);
break;
}
case ttLong:
{
DoCopyArea16_32 ((const uint16 *) sPtr,
(uint32 *) dPtr,
rows,
cols,
planes,
sRowStep,
sColStep,
sPlaneStep,
dRowStep,
dColStep,
dPlaneStep);
break;
}
case ttFloat:
{
DoCopyArea16_R32 ((const uint16 *) sPtr,
(real32 *) dPtr,
rows,
cols,
planes,
sRowStep,
sColStep,
sPlaneStep,
dRowStep,
dColStep,
dPlaneStep,
src.PixelRange ());
break;
}
default:
{
ThrowNotYetImplemented ();
}
}
}
else if (src.fPixelType == ttSShort)
{
switch (fPixelType)
{
case ttByte:
{
DoCopyArea8 (((const uint8 *) sPtr) + (qDNGBigEndian ? 1 : 0),
(uint8 *) dPtr,
rows,
cols,
planes,
sRowStep << 1,
sColStep << 1,
sPlaneStep << 1,
dRowStep,
dColStep,
dPlaneStep);
break;
}
case ttShort:
{
// Moving between signed 16 bit values and unsigned 16
// bit values just requires toggling the sign bit. So
// we can use the "backwards" bottleneck.
DoCopyArea16_S16 ((const uint16 *) sPtr,
(int16 *) dPtr,
rows,
cols,
planes,
sRowStep,
sColStep,
sPlaneStep,
dRowStep,
dColStep,
dPlaneStep);
break;
}
case ttFloat:
{
DoCopyAreaS16_R32 ((const int16 *) sPtr,
(real32 *) dPtr,
rows,
cols,
planes,
sRowStep,
sColStep,
sPlaneStep,
dRowStep,
dColStep,
dPlaneStep,
src.PixelRange ());
break;
}
default:
{
ThrowNotYetImplemented ();
}
}
}
else if (src.fPixelType == ttLong)
{
switch (fPixelType)
{
case ttByte:
{
DoCopyArea8 (((const uint8 *) sPtr) + (qDNGBigEndian ? 3 : 0),
(uint8 *) dPtr,
rows,
cols,
planes,
sRowStep << 2,
sColStep << 2,
sPlaneStep << 2,
dRowStep,
dColStep,
dPlaneStep);
break;
}
case ttShort:
{
DoCopyArea16 (((const uint16 *) sPtr) + (qDNGBigEndian ? 1 : 0),
(uint16 *) dPtr,
rows,
cols,
planes,
sRowStep << 1,
sColStep << 1,
sPlaneStep << 1,
dRowStep,
dColStep,
dPlaneStep);
break;
}
default:
{
ThrowNotYetImplemented ();
}
}
}
else if (src.fPixelType == ttFloat)
{
switch (fPixelType)
{
case ttByte:
{
DoCopyAreaR32_8 ((const real32 *) sPtr,
(uint8 *) dPtr,
rows,
cols,
planes,
sRowStep,
sColStep,
sPlaneStep,
dRowStep,
dColStep,
dPlaneStep,
PixelRange ());
break;
}
case ttShort:
{
DoCopyAreaR32_16 ((const real32 *) sPtr,
(uint16 *) dPtr,
rows,
cols,
planes,
sRowStep,
sColStep,
sPlaneStep,
dRowStep,
dColStep,
dPlaneStep,
PixelRange ());
break;
}
case ttSShort:
{
DoCopyAreaR32_S16 ((const real32 *) sPtr,
(int16 *) dPtr,
rows,
cols,
planes,
sRowStep,
sColStep,
sPlaneStep,
dRowStep,
dColStep,
dPlaneStep,
PixelRange ());
break;
}
default:
{
ThrowNotYetImplemented ();
}
}
}
else
{
ThrowNotYetImplemented ();
}
}
/*****************************************************************************/
dng_point dng_pixel_buffer::RepeatPhase (const dng_rect &srcArea,
const dng_rect &dstArea)
{
int32 repeatV = srcArea.H ();
int32 repeatH = srcArea.W ();
int32 phaseV;
int32 phaseH;
if (srcArea.t >= dstArea.t)
{
phaseV = (repeatV - ((srcArea.t - dstArea.t) % repeatV)) % repeatV;
}
else
{
phaseV = (dstArea.t - srcArea.t) % repeatV;
}
if (srcArea.l >= dstArea.l)
{
phaseH = (repeatH - ((srcArea.l - dstArea.l) % repeatH)) % repeatH;
}
else
{
phaseH = (dstArea.l - srcArea.l) % repeatH;
}
return dng_point (phaseV, phaseH);
}
/*****************************************************************************/
void dng_pixel_buffer::RepeatArea (const dng_rect &srcArea,
const dng_rect &dstArea)
{
dng_point repeat = srcArea.Size ();
dng_point phase = RepeatPhase (srcArea,
dstArea);
const void *sPtr = ConstPixel (srcArea.t,
srcArea.l,
fPlane);
void *dPtr = DirtyPixel (dstArea.t,
dstArea.l,
fPlane);
uint32 rows = dstArea.H ();
uint32 cols = dstArea.W ();
switch (fPixelSize)
{
case 1:
{
DoRepeatArea8 ((const uint8 *) sPtr,
(uint8 *) dPtr,
rows,
cols,
fPlanes,
fRowStep,
fColStep,
fPlaneStep,
repeat.v,
repeat.h,
phase.v,
phase.h);
break;
}
case 2:
{
DoRepeatArea16 ((const uint16 *) sPtr,
(uint16 *) dPtr,
rows,
cols,
fPlanes,
fRowStep,
fColStep,
fPlaneStep,
repeat.v,
repeat.h,
phase.v,
phase.h);
break;
}
case 4:
{
DoRepeatArea32 ((const uint32 *) sPtr,
(uint32 *) dPtr,
rows,
cols,
fPlanes,
fRowStep,
fColStep,
fPlaneStep,
repeat.v,
repeat.h,
phase.v,
phase.h);
break;
}
default:
{
ThrowNotYetImplemented ();
}
}
}
/*****************************************************************************/
void dng_pixel_buffer::RepeatSubArea (const dng_rect subArea,
uint32 repeatV,
uint32 repeatH)
{
if (fArea.t < subArea.t)
{
RepeatArea (dng_rect (subArea.t , fArea.l,
subArea.t + repeatV, fArea.r),
dng_rect (fArea.t , fArea.l,
subArea.t , fArea.r));
}
if (fArea.b > subArea.b)
{
RepeatArea (dng_rect (subArea.b - repeatV, fArea.l,
subArea.b , fArea.r),
dng_rect (subArea.b , fArea.l,
fArea.b , fArea.r));
}
if (fArea.l < subArea.l)
{
RepeatArea (dng_rect (fArea.t, subArea.l ,
fArea.b, subArea.l + repeatH),
dng_rect (fArea.t, fArea.l ,
fArea.b, subArea.l ));
}
if (fArea.r > subArea.r)
{
RepeatArea (dng_rect (fArea.t, subArea.r - repeatH,
fArea.b, subArea.r ),
dng_rect (fArea.t, subArea.r ,
fArea.b, fArea.r ));
}
}
/*****************************************************************************/
void dng_pixel_buffer::ShiftRight (uint32 shift)
{
if (fPixelType != ttShort)
{
ThrowNotYetImplemented ();
}
uint32 rows = fArea.H ();
uint32 cols = fArea.W ();
uint32 planes = fPlanes;
void *dPtr = DirtyPixel (fArea.t,
fArea.l,
fPlane);
const void *sPtr = dPtr;
int32 sRowStep = fRowStep;
int32 sColStep = fColStep;
int32 sPlaneStep = fPlaneStep;
int32 dRowStep = fRowStep;
int32 dColStep = fColStep;
int32 dPlaneStep = fPlaneStep;
OptimizeOrder (sPtr,
dPtr,
fPixelSize,
fPixelSize,
rows,
cols,
planes,
sRowStep,
sColStep,
sPlaneStep,
dRowStep,
dColStep,
dPlaneStep);
DoShiftRight16 ((uint16 *) dPtr,
rows,
cols,
planes,
dRowStep,
dColStep,
dPlaneStep,
shift);
}
/*****************************************************************************/
void dng_pixel_buffer::FlipH ()
{
fData = InternalPixel (fArea.t, fArea.r - 1);
fColStep = -fColStep;
}
/*****************************************************************************/
void dng_pixel_buffer::FlipV ()
{
fData = InternalPixel (fArea.b - 1, fArea.l);
fRowStep = -fRowStep;
}
/*****************************************************************************/
void dng_pixel_buffer::FlipZ ()
{
fData = InternalPixel (fArea.t, fArea.l, fPlanes - 1);
fPlaneStep = -fPlaneStep;
}
/*****************************************************************************/
bool dng_pixel_buffer::EqualArea (const dng_pixel_buffer &src,
const dng_rect &area,
uint32 plane,
uint32 planes) const
{
uint32 rows = area.H ();
uint32 cols = area.W ();
const void *sPtr = src.ConstPixel (area.t,
area.l,
plane);
const void *dPtr = ConstPixel (area.t,
area.l,
plane);
int32 sRowStep = src.fRowStep;
int32 sColStep = src.fColStep;
int32 sPlaneStep = src.fPlaneStep;
int32 dRowStep = fRowStep;
int32 dColStep = fColStep;
int32 dPlaneStep = fPlaneStep;
if (fPixelType == src.fPixelType)
{
if (rows == 1 && cols == 1 && sPlaneStep == 1 && dPlaneStep == 1)
{
return DoEqualBytes (sPtr,
dPtr,
planes * fPixelSize);
}
else switch (fPixelSize)
{
case 1:
{
return DoEqualArea8 ((const uint8 *) sPtr,
(const uint8 *) dPtr,
rows,
cols,
planes,
sRowStep,
sColStep,
sPlaneStep,
dRowStep,
dColStep,
dPlaneStep);
break;
}
case 2:
{
return DoEqualArea16 ((const uint16 *) sPtr,
(const uint16 *) dPtr,
rows,
cols,
planes,
sRowStep,
sColStep,
sPlaneStep,
dRowStep,
dColStep,
dPlaneStep);
break;
}
case 4:
{
return DoEqualArea32 ((const uint32 *) sPtr,
(const uint32 *) dPtr,
rows,
cols,
planes,
sRowStep,
sColStep,
sPlaneStep,
dRowStep,
dColStep,
dPlaneStep);
break;
}
default:
{
ThrowNotYetImplemented ();
return false;
}
}
}
else
return false;
}
/*****************************************************************************/
namespace
{
template <typename T>
real64 MaxDiff (const T *src1,
int32 s1RowStep,
int32 s1PlaneStep,
const T *src2,
int32 s2RowStep,
int32 s2PlaneStep,
uint32 rows,
uint32 cols,
uint32 planes)
{
real64 result = 0.0;
for (uint32 plane = 0; plane < planes; plane++)
{
const T *src1Save = src1;
const T *src2Save = src2;
for (uint32 row = 0; row < rows; row++)
{
for (uint32 col = 0; col < cols; col++)
{
real64 diff = fabs ((real64)src1 [col] - src2 [col]);
if (diff > result)
result = diff;
}
src1 += s1RowStep;
src2 += s2RowStep;
}
src1 = src1Save + s1PlaneStep;
src2 = src2Save + s2PlaneStep;
}
return result;
}
template <typename T>
real64 MaxDiff (const T *src1,
int32 s1ColStep,
int32 s1RowStep,
int32 s1PlaneStep,
const T *src2,
int32 s2ColStep,
int32 s2RowStep,
int32 s2PlaneStep,
uint32 rows,
uint32 cols,
uint32 planes)
{
if (s1ColStep == s2ColStep &&
s1ColStep == 1)
return MaxDiff (src1,
s1RowStep,
s1PlaneStep,
src2,
s2RowStep,
s2PlaneStep,
rows,
cols,
planes);
real64 result = 0.0;
for (uint32 plane = 0; plane < planes; plane++)
{
const T *src1Save = src1;
const T *src2Save = src2;
for (uint32 row = 0; row < rows; row++)
{
for (uint32 col = 0; col < cols; col++)
{
real64 diff = fabs ((real64)src1 [col * s1ColStep] - src2 [col * s2ColStep]);
if (diff > result)
result = diff;
}
src1 += s1RowStep;
src2 += s2RowStep;
}
src1 = src1Save + s1PlaneStep;
src2 = src2Save + s2PlaneStep;
}
return result;
}
}
real64 dng_pixel_buffer::MaximumDifference (const dng_pixel_buffer &rhs,
const dng_rect &area,
uint32 plane,
uint32 planes) const
{
uint32 rows = area.H ();
uint32 cols = area.W ();
const void *s1Ptr = rhs.ConstPixel (area.t,
area.l,
plane);
const void *s2Ptr = ConstPixel (area.t,
area.l,
plane);
int32 s1RowStep = rhs.fRowStep;
int32 s1ColStep = rhs.fColStep;
int32 s1PlaneStep = rhs.fPlaneStep;
int32 s2RowStep = fRowStep;
int32 s2ColStep = fColStep;
int32 s2PlaneStep = fPlaneStep;
if (fPixelType == rhs.fPixelType)
{
switch (fPixelType)
{
case ttByte:
return MaxDiff ((const uint8 *)s1Ptr,
s1ColStep,
s1RowStep,
s1PlaneStep,
(const uint8 *)s2Ptr,
s2ColStep,
s2RowStep,
s2PlaneStep,
rows,
cols,
planes);
break;
case ttShort:
return MaxDiff ((const uint16 *)s1Ptr,
s1ColStep,
s1RowStep,
s1PlaneStep,
(const uint16 *)s2Ptr,
s2ColStep,
s2RowStep,
s2PlaneStep,
rows,
cols,
planes);
break;
case ttLong:
return MaxDiff ((const uint32 *)s1Ptr,
s1ColStep,
s1RowStep,
s1PlaneStep,
(const uint32 *)s2Ptr,
s2ColStep,
s2RowStep,
s2PlaneStep,
rows,
cols,
planes);
break;
case ttSByte:
return MaxDiff ((const int8 *)s1Ptr,
s1ColStep,
s1RowStep,
s1PlaneStep,
(const int8 *)s2Ptr,
s2ColStep,
s2RowStep,
s2PlaneStep,
rows,
cols,
planes);
break;
case ttSShort:
return MaxDiff ((const int16 *)s1Ptr,
s1ColStep,
s1RowStep,
s1PlaneStep,
(const int16 *)s2Ptr,
s2ColStep,
s2RowStep,
s2PlaneStep,
rows,
cols,
planes);
break;
case ttSLong:
return MaxDiff ((const int32 *)s1Ptr,
s1ColStep,
s1RowStep,
s1PlaneStep,
(const int32 *)s2Ptr,
s2ColStep,
s2RowStep,
s2PlaneStep,
rows,
cols,
planes);
break;
case ttFloat:
return MaxDiff ((const real32 *)s1Ptr,
s1ColStep,
s1RowStep,
s1PlaneStep,
(const real32 *)s2Ptr,
s2ColStep,
s2RowStep,
s2PlaneStep,
rows,
cols,
planes);
break;
case ttDouble:
return MaxDiff ((const real64 *)s1Ptr,
s1ColStep,
s1RowStep,
s1PlaneStep,
(const real64 *)s2Ptr,
s2ColStep,
s2RowStep,
s2PlaneStep,
rows,
cols,
planes);
break;
default:
{
ThrowNotYetImplemented ();
return 0.0;
}
}
}
else
ThrowProgramError ("attempt to difference pixel buffers of different formats.");
return 0.0;
}
/*****************************************************************************/