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