You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1524 lines
27 KiB
1524 lines
27 KiB
/*****************************************************************************/
|
|
// 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);
|
|
|
|
}
|
|
|
|
/*****************************************************************************/
|