/*****************************************************************************/
// Copyright 2006-2011 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_linearization_info.cpp#1 $ */
/* $DateTime: 2012/05/30 13:28:51 $ */
/* $Change: 832332 $ */
/* $Author: tknoll $ */
/*****************************************************************************/
#include "dng_linearization_info.h"
#include "dng_area_task.h"
#include "dng_exceptions.h"
#include "dng_host.h"
#include "dng_image.h"
#include "dng_info.h"
#include "dng_negative.h"
#include "dng_pixel_buffer.h"
#include "dng_safe_arithmetic.h"
#include "dng_tag_types.h"
#include "dng_tile_iterator.h"
#include "dng_utils.h"
/*****************************************************************************/
class dng_linearize_plane
{
private:
const dng_image & fSrcImage;
dng_image & fDstImage;
uint32 fPlane;
dng_rect fActiveArea;
uint32 fSrcPixelType;
uint32 fDstPixelType;
bool fReal32;
real32 fScale;
AutoPtr<dng_memory_block> fScale_buffer;
uint32 fBlack_2D_rows;
uint32 fBlack_2D_cols;
AutoPtr<dng_memory_block> fBlack_2D_buffer;
uint32 fBlack_1D_rows;
AutoPtr<dng_memory_block> fBlack_1D_buffer;
public:
dng_linearize_plane (dng_host &host,
dng_linearization_info &info,
const dng_image &srcImage,
dng_image &dstImage,
uint32 plane);
~dng_linearize_plane ();
void Process (const dng_rect &tile);
};
/*****************************************************************************/
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 &&
fSrcPixelType != ttFloat)
{
DNG_REPORT ("Unsupported source pixel type");
ThrowProgramError ();
}
if (fDstPixelType != ttShort &&
fDstPixelType != ttFloat)
{
DNG_REPORT ("Unsupported destination pixel type");
ThrowProgramError ();
}
if (fSrcPixelType == ttFloat &&
fDstPixelType != ttFloat)
{
DNG_REPORT ("Cannot convert floating point stage1 to non-floating stage2");
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 (
SafeUint32Mult (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 (
SafeUint32Mult(fBlack_1D_rows, 4)));
bool allZero = true;
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];
}
allZero = allZero && (x == 0.0);
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;
}
}
if (allZero)
{
fBlack_1D_rows = 0;
fBlack_1D_buffer.Reset ();
}
}
// Calculate scale table, if any.
if (fSrcPixelType != ttLong &&
fSrcPixelType != ttFloat)
{
// 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;
}
// If the black level does not vary from pixel to pixel, then
// the entire process can be a single LUT.
if (fBlack_1D_rows == 0 &&
fBlack_2D_rows == 0)
{
fScale_buffer.Reset (host.Allocate (0x10000 *
TagTypeSize (fDstPixelType)));
for (j = 0; j < 0x10000; j++)
{
uint32 x = j;
// Apply linearization table, if any.
if (lut)
{
x = Min_uint32 (x, lutEntries - 1);
x = lut [x];
}
// Subtract constant black level.
real64 y = x - info.fBlackLevel [0] [0] [plane];
// Apply scale.
y *= scale;
// We can burn in the clipping also.
y = Pin_real64 (0.0, y, 1.0);
// Store output value in table.
if (fDstPixelType == ttShort)
{
uint16 z = (uint16) Round_uint32 (y * 0x0FFFF);
fScale_buffer->Buffer_uint16 () [j] = z;
}
else
{
fScale_buffer->Buffer_real32 () [j] = (real32) y;
}
}
}
// Else we only do the scaling operation in the scale table.
else
{
fScale_buffer.Reset (host.Allocate (0x10000 * 4));
for (j = 0; j < 0x10000; j++)
{
uint32 x = j;
// Apply linearization table, if any.
if (lut)
{
x = Min_uint32 (x, lutEntries - 1);
x = lut [x];
}
// Apply scale.
real64 y = x * scale;
// Store output value in table.
if (fReal32)
{
fScale_buffer->Buffer_real32 () [j] = (real32) y;
}
else
{
int32 z = Round_int32 (y * 0x0FFFF * 256.0);
fScale_buffer->Buffer_int32 () [j] = z;
}
}
}
}
}
/*****************************************************************************/
dng_linearize_plane::~dng_linearize_plane ()
{
}
/*****************************************************************************/
void dng_linearize_plane::Process (const dng_rect &srcTile)
{
// Process tile.
dng_rect dstTile = srcTile - fActiveArea.TL ();
dng_const_tile_buffer srcBuffer (fSrcImage, srcTile);
dng_dirty_tile_buffer dstBuffer (fDstImage, dstTile);
int32 sStep = srcBuffer.fColStep;
int32 dStep = dstBuffer.fColStep;
uint32 count = srcTile.W ();
uint32 dstCol = dstTile.l;
uint32 rows = srcTile.H ();
for (uint32 row = 0; row < rows; row++)
{
uint32 dstRow = dstTile.t + row;
const void *sPtr = srcBuffer.ConstPixel (srcTile.t + row,
srcTile.l,
fPlane);
void *dPtr = dstBuffer.DirtyPixel (dstRow,
dstCol,
fPlane);
// Floating point source case.
if (fSrcPixelType == ttFloat)
{
real32 scale = fScale;
const real32 *srcPtr = (const real32 *) sPtr;
real32 *dstPtr = (real32 *) dPtr;
// Optimize scale only case, which is the most common.
if (fBlack_1D_rows == 0 &&
fBlack_2D_cols == 0)
{
for (uint32 j = 0; j < count; j++)
{
*dstPtr = (*srcPtr) * scale;
srcPtr += sStep;
dstPtr += dStep;
}
}
else
{
real32 b1 = 0.0f;
if (fBlack_1D_rows)
{
b1 = fBlack_1D_buffer->Buffer_real32 () [dstRow % fBlack_1D_rows];
}
const real32 *b2 = NULL;
uint32 b2_count = fBlack_2D_cols;
uint32 b2_phase = 0;
if (b2_count)
{
b2 = fBlack_2D_buffer->Buffer_real32 () +
b2_count * (dstRow % fBlack_2D_rows);
b2_phase = dstCol % b2_count;
}
for (uint32 j = 0; j < count; j++)
{
real32 x = (*srcPtr) * scale - b1;
if (b2_count)
{
x -= b2 [b2_phase];
if (++b2_phase == b2_count)
{
b2_phase = 0;
}
}
*dstPtr = x;
srcPtr += sStep;
dstPtr += dStep;
}
}
}
// Simple LUT case.
else if (fBlack_1D_rows == 0 &&
fBlack_2D_rows == 0 && fSrcPixelType != ttLong)
{
if (fDstPixelType == ttShort)
{
const uint16 *lut = fScale_buffer->Buffer_uint16 ();
uint16 *dstPtr = (uint16 *) dPtr;
if (fSrcPixelType == ttByte)
{
const uint8 *srcPtr = (const uint8 *) sPtr;
for (uint32 j = 0; j < count; j++)
{
*dstPtr = lut [*srcPtr];
srcPtr += sStep;
dstPtr += dStep;
}
}
else
{
const uint16 *srcPtr = (const uint16 *) sPtr;
for (uint32 j = 0; j < count; j++)
{
*dstPtr = lut [*srcPtr];
srcPtr += sStep;
dstPtr += dStep;
}
}
}
else
{
const real32 *lut = fScale_buffer->Buffer_real32 ();
real32 *dstPtr = (real32 *) dPtr;
if (fSrcPixelType == ttByte)
{
const uint8 *srcPtr = (const uint8 *) sPtr;
for (uint32 j = 0; j < count; j++)
{
*dstPtr = lut [*srcPtr];
srcPtr += sStep;
dstPtr += dStep;
}
}
else
{
const uint16 *srcPtr = (const uint16 *) sPtr;
for (uint32 j = 0; j < count; j++)
{
*dstPtr = lut [*srcPtr];
srcPtr += sStep;
dstPtr += dStep;
}
}
}
}
// Integer math case.
else if (!fReal32)
{
const int32 *lut = fScale_buffer->Buffer_int32 ();
int32 b1 = 0;
if (fBlack_1D_rows)
{
b1 = fBlack_1D_buffer->Buffer_int32 () [dstRow % fBlack_1D_rows];
}
const int32 *b2 = NULL;
uint32 b2_count = fBlack_2D_cols;
uint32 b2_phase = 0;
if (b2_count)
{
b2 = fBlack_2D_buffer->Buffer_int32 () +
b2_count * (dstRow % fBlack_2D_rows);
b2_phase = dstCol % b2_count;
}
uint16 *dstPtr = (uint16 *) dPtr;
b1 -= 128; // Rounding for 8 bit shift
if (fSrcPixelType == ttByte)
{
const uint8 *srcPtr = (const uint8 *) sPtr;
for (uint32 j = 0; j < count; j++)
{
int32 x = lut [*srcPtr] - b1;
if (b2_count)
{
x -= b2 [b2_phase];
if (++b2_phase == b2_count)
{
b2_phase = 0;
}
}
x >>= 8;
*dstPtr = Pin_uint16 (x);
srcPtr += sStep;
dstPtr += dStep;
}
}
else
{
const uint16 *srcPtr = (const uint16 *) sPtr;
for (uint32 j = 0; j < count; j++)
{
int32 x = lut [*srcPtr] - b1;
if (b2_count)
{
x -= b2 [b2_phase];
if (++b2_phase == b2_count)
{
b2_phase = 0;
}
}
x >>= 8;
*dstPtr = Pin_uint16 (x);
srcPtr += sStep;
dstPtr += dStep;
}
}
}
// Floating point math cases.
else
{
real32 b1 = 0.0f;
if (fBlack_1D_rows)
{
b1 = fBlack_1D_buffer->Buffer_real32 () [dstRow % fBlack_1D_rows];
}
const real32 *b2 = NULL;
uint32 b2_count = fBlack_2D_cols;
uint32 b2_phase = 0;
if (b2_count)
{
b2 = fBlack_2D_buffer->Buffer_real32 () +
b2_count * (dstRow % fBlack_2D_rows);
b2_phase = dstCol % b2_count;
}
// Case 1: uint8/uint16 -> real32
if (fSrcPixelType != ttLong)
{
const real32 *lut = fScale_buffer->Buffer_real32 ();
real32 *dstPtr = (real32 *) dPtr;
if (fSrcPixelType == ttByte)
{
const uint8 *srcPtr = (const uint8 *) sPtr;
for (uint32 j = 0; j < count; j++)
{
real32 x = lut [*srcPtr] - b1;
if (b2_count)
{
x -= b2 [b2_phase];
if (++b2_phase == b2_count)
{
b2_phase = 0;
}
}
x = Pin_real32 (0.0f, x, 1.0f);
*dstPtr = x;
srcPtr += sStep;
dstPtr += dStep;
}
}
else
{
const uint16 *srcPtr = (const uint16 *) sPtr;
for (uint32 j = 0; j < count; j++)
{
real32 x = lut [*srcPtr] - b1;
if (b2_count)
{
x -= b2 [b2_phase];
if (++b2_phase == b2_count)
{
b2_phase = 0;
}
}
x = Pin_real32 (0.0f, x, 1.0f);
*dstPtr = x;
srcPtr += sStep;
dstPtr += dStep;
}
}
}
// Otherwise source is uint32
else
{
real32 scale = fScale;
const uint32 *srcPtr = (const uint32 *) sPtr;
// Case 2: uint32 -> real32
if (fDstPixelType == ttFloat)
{
real32 *dstPtr = (real32 *) dPtr;
for (uint32 j = 0; j < count; j++)
{
real32 x = ((real32) *srcPtr) * scale - b1;
if (b2_count)
{
x -= b2 [b2_phase];
if (++b2_phase == b2_count)
{
b2_phase = 0;
}
}
x = Pin_real32 (0.0f, x, 1.0f);
*dstPtr = x;
srcPtr += sStep;
dstPtr += dStep;
}
}
// Case 3: uint32 -> uint16
else
{
uint16 *dstPtr = (uint16 *) dPtr;
real32 dstScale = (real32) 0x0FFFF;
for (uint32 j = 0; j < count; j++)
{
real32 x = ((real32) *srcPtr) * scale - b1;
if (b2_count)
{
x -= b2 [b2_phase];
if (++b2_phase == b2_count)
{
b2_phase = 0;
}
}
x = Pin_real32 (0.0f, x, 1.0f);
*dstPtr = (uint16) (x * dstScale + 0.5f);
srcPtr += sStep;
dstPtr += dStep;
}
}
}
}
}
}
/*****************************************************************************/
class dng_linearize_image: public dng_area_task
{
private:
const dng_image & fSrcImage;
dng_image & fDstImage;
dng_rect fActiveArea;
AutoPtr<dng_linearize_plane> fPlaneTask [kMaxColorPlanes];
public:
dng_linearize_image (dng_host &host,
dng_linearization_info &info,
const dng_image &srcImage,
dng_image &dstImage);
virtual ~dng_linearize_image ();
virtual dng_rect RepeatingTile1 () const;
virtual dng_rect RepeatingTile2 () const;
virtual void Process (uint32 threadIndex,
const dng_rect &tile,
dng_abort_sniffer *sniffer);
};
/*****************************************************************************/
dng_linearize_image::dng_linearize_image (dng_host &host,
dng_linearization_info &info,
const dng_image &srcImage,
dng_image &dstImage)
: fSrcImage (srcImage)
, fDstImage (dstImage)
, fActiveArea (info.fActiveArea)
{
// Build linearization table for each plane.
for (uint32 plane = 0; plane < srcImage.Planes (); plane++)
{
fPlaneTask [plane].Reset (new dng_linearize_plane (host,
info,
srcImage,
dstImage,
plane));
}
// Adjust maximum tile size.
fMaxTileSize = dng_point (1024, 1024);
}
/*****************************************************************************/
dng_linearize_image::~dng_linearize_image ()
{
}
/*****************************************************************************/
dng_rect dng_linearize_image::RepeatingTile1 () const
{
return fSrcImage.RepeatingTile ();
}
/*****************************************************************************/
dng_rect dng_linearize_image::RepeatingTile2 () const
{
return fDstImage.RepeatingTile () + fActiveArea.TL ();
}
/*****************************************************************************/
void dng_linearize_image::Process (uint32 /* threadIndex */,
const dng_rect &srcTile,
dng_abort_sniffer * /* sniffer */)
{
// Process each plane.
for (uint32 plane = 0; plane < fSrcImage.Planes (); plane++)
{
fPlaneTask [plane]->Process (srcTile);
}
}
/*****************************************************************************/
dng_linearization_info::dng_linearization_info ()
: fActiveArea ()
, fMaskedAreaCount (0)
, fLinearizationTable ()
, fBlackLevelRepeatRows (1)
, fBlackLevelRepeatCols (1)
, fBlackDeltaH ()
, fBlackDeltaV ()
, fBlackDenom (256)
{
uint32 j;
uint32 k;
uint32 n;
for (j = 0; j < kMaxBlackPattern; j++)
for (k = 0; k < kMaxBlackPattern; k++)
for (n = 0; n < kMaxSamplesPerPixel; n++)
{
fBlackLevel [j] [k] [n] = 0.0;
}
for (n = 0; n < kMaxSamplesPerPixel; n++)
{
fWhiteLevel [n] = 65535.0;
}
}
/*****************************************************************************/
dng_linearization_info::~dng_linearization_info ()
{
}
/*****************************************************************************/
void dng_linearization_info::RoundBlacks ()
{
uint32 j;
uint32 k;
uint32 n;
real64 maxAbs = 0.0;
for (j = 0; j < fBlackLevelRepeatRows; j++)
for (k = 0; k < fBlackLevelRepeatCols; k++)
for (n = 0; n < kMaxSamplesPerPixel; n++)
{
maxAbs = Max_real64 (maxAbs,
Abs_real64 (fBlackLevel [j] [k] [n]));
}
uint32 count = RowBlackCount ();
for (j = 0; j < count; j++)
{
maxAbs = Max_real64 (maxAbs,
Abs_real64 (fBlackDeltaV->Buffer_real64 () [j]));
}
count = ColumnBlackCount ();
for (j = 0; j < count; j++)
{
maxAbs = Max_real64 (maxAbs,
Abs_real64 (fBlackDeltaH->Buffer_real64 () [j]));
}
fBlackDenom = 256;
while (fBlackDenom > 1 && (maxAbs * fBlackDenom) >= 30000.0 * 65536.0)
{
fBlackDenom >>= 1;
}
for (j = 0; j < fBlackLevelRepeatRows; j++)
for (k = 0; k < fBlackLevelRepeatCols; k++)
for (n = 0; n < kMaxSamplesPerPixel; n++)
{
fBlackLevel [j] [k] [n] = BlackLevel (j, k, n).As_real64 ();
}
count = RowBlackCount ();
for (j = 0; j < count; j++)
{
fBlackDeltaV->Buffer_real64 () [j] = RowBlack (j).As_real64 ();
}
count = ColumnBlackCount ();
for (j = 0; j < count; j++)
{
fBlackDeltaH->Buffer_real64 () [j] = ColumnBlack (j).As_real64 ();
}
}
/*****************************************************************************/
void dng_linearization_info::Parse (dng_host &host,
dng_stream &stream,
dng_info &info)
{
uint32 j;
uint32 k;
uint32 n;
// Find main image IFD.
dng_ifd &rawIFD = *info.fIFD [info.fMainIndex].Get ();
// Copy active area.
fActiveArea = rawIFD.fActiveArea;
// Copy masked areas.
fMaskedAreaCount = rawIFD.fMaskedAreaCount;
for (j = 0; j < fMaskedAreaCount; j++)
{
fMaskedArea [j] = rawIFD.fMaskedArea [j];
}
// Read linearization LUT.
if (rawIFD.fLinearizationTableCount)
{
uint32 size = SafeUint32Mult (rawIFD.fLinearizationTableCount,
static_cast<uint32> (sizeof (uint16)));
fLinearizationTable.Reset (host.Allocate (size));
uint16 *table = fLinearizationTable->Buffer_uint16 ();
stream.SetReadPosition (rawIFD.fLinearizationTableOffset);
for (j = 0; j < rawIFD.fLinearizationTableCount; j++)
{
table [j] = stream.Get_uint16 ();
}
}
// Copy black level pattern.
fBlackLevelRepeatRows = rawIFD.fBlackLevelRepeatRows;
fBlackLevelRepeatCols = rawIFD.fBlackLevelRepeatCols;
for (j = 0; j < kMaxBlackPattern; j++)
for (k = 0; k < kMaxBlackPattern; k++)
for (n = 0; n < kMaxSamplesPerPixel; n++)
{
fBlackLevel [j] [k] [n] = rawIFD.fBlackLevel [j] [k] [n];
}
// Read BlackDeltaH.
if (rawIFD.fBlackLevelDeltaHCount)
{
uint32 size = SafeUint32Mult (rawIFD.fBlackLevelDeltaHCount,
static_cast<uint32> (sizeof (real64)));
fBlackDeltaH.Reset (host.Allocate (size));
real64 *blacks = fBlackDeltaH->Buffer_real64 ();
stream.SetReadPosition (rawIFD.fBlackLevelDeltaHOffset);
for (j = 0; j < rawIFD.fBlackLevelDeltaHCount; j++)
{
blacks [j] = stream.TagValue_real64 (rawIFD.fBlackLevelDeltaHType);
}
}
// Read BlackDeltaV.
if (rawIFD.fBlackLevelDeltaVCount)
{
uint32 size = SafeUint32Mult (rawIFD.fBlackLevelDeltaVCount,
static_cast<uint32> (sizeof (real64)));
fBlackDeltaV.Reset (host.Allocate (size));
real64 *blacks = fBlackDeltaV->Buffer_real64 ();
stream.SetReadPosition (rawIFD.fBlackLevelDeltaVOffset);
for (j = 0; j < rawIFD.fBlackLevelDeltaVCount; j++)
{
blacks [j] = stream.TagValue_real64 (rawIFD.fBlackLevelDeltaVType);
}
}
// Copy white level.
for (n = 0; n < kMaxSamplesPerPixel; n++)
{
fWhiteLevel [n] = rawIFD.fWhiteLevel [n];
}
// Round off black levels.
RoundBlacks ();
}
/*****************************************************************************/
void dng_linearization_info::PostParse (dng_host & /* host */,
dng_negative &negative)
{
if (fActiveArea.IsEmpty ())
{
fActiveArea = negative.Stage1Image ()->Bounds ();
}
}
/*****************************************************************************/
real64 dng_linearization_info::MaxBlackLevel (uint32 plane) const
{
uint32 j;
uint32 k;
// Find maximum value of fBlackDeltaH for each phase of black pattern.
real64 maxDeltaH [kMaxBlackPattern];
for (j = 0; j < fBlackLevelRepeatCols; j++)
{
maxDeltaH [j] = 0.0;
}
if (fBlackDeltaH.Get ())
{
real64 *table = fBlackDeltaH->Buffer_real64 ();
uint32 entries = fBlackDeltaH->LogicalSize () / (uint32) sizeof (table [0]);
for (j = 0; j < entries; j++)
{
real64 &entry = maxDeltaH [j % fBlackLevelRepeatCols];
if (j < fBlackLevelRepeatCols)
{
entry = table [j];
}
else
{
entry = Max_real64 (entry, table [j]);
}
}
}
// Find maximum value of fBlackDeltaV for each phase of black pattern.
real64 maxDeltaV [kMaxBlackPattern];
for (j = 0; j < fBlackLevelRepeatRows; j++)
{
maxDeltaV [j] = 0.0;
}
if (fBlackDeltaV.Get ())
{
real64 *table = fBlackDeltaV->Buffer_real64 ();
uint32 entries = fBlackDeltaV->LogicalSize () / (uint32) sizeof (table [0]);
for (j = 0; j < entries; j++)
{
real64 &entry = maxDeltaV [j % fBlackLevelRepeatRows];
if (j < fBlackLevelRepeatRows)
{
entry = table [j];
}
else
{
entry = Max_real64 (entry, table [j]);
}
}
}
// Now scan the pattern and find the maximum value after row and column
// deltas.
real64 maxBlack = 0.0;
for (j = 0; j < fBlackLevelRepeatRows; j++)
{
for (k = 0; k < fBlackLevelRepeatCols; k++)
{
real64 black = fBlackLevel [j] [k] [plane];
black += maxDeltaH [k];
black += maxDeltaV [j];
if (j == 0 && k == 0)
{
maxBlack = black;
}
else
{
maxBlack = Max_real64 (maxBlack, black);
}
}
}
return maxBlack;
}
/*****************************************************************************/
void dng_linearization_info::Linearize (dng_host &host,
const dng_image &srcImage,
dng_image &dstImage)
{
dng_linearize_image processor (host,
*this,
srcImage,
dstImage);
host.PerformAreaTask (processor,
fActiveArea);
}
/*****************************************************************************/
dng_urational dng_linearization_info::BlackLevel (uint32 row,
uint32 col,
uint32 plane) const
{
dng_urational r;
r.Set_real64 (fBlackLevel [row] [col] [plane], fBlackDenom);
return r;
}
/*****************************************************************************/
uint32 dng_linearization_info::RowBlackCount () const
{
if (fBlackDeltaV.Get ())
{
return fBlackDeltaV->LogicalSize () >> 3;
}
return 0;
}
/*****************************************************************************/
dng_srational dng_linearization_info::RowBlack (uint32 row) const
{
if (fBlackDeltaV.Get ())
{
dng_srational r;
r.Set_real64 (fBlackDeltaV->Buffer_real64 () [row], fBlackDenom);
return r;
}
return dng_srational (0, 1);
}
/*****************************************************************************/
uint32 dng_linearization_info::ColumnBlackCount () const
{
if (fBlackDeltaH.Get ())
{
return fBlackDeltaH->LogicalSize () >> 3;
}
return 0;
}
/*****************************************************************************/
dng_srational dng_linearization_info::ColumnBlack (uint32 col) const
{
if (fBlackDeltaH.Get ())
{
dng_srational r;
r.Set_real64 (fBlackDeltaH->Buffer_real64 () [col], fBlackDenom);
return r;
}
return dng_srational (0, 1);
}
/*****************************************************************************/