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.

1599 lines
32 KiB

/*****************************************************************************/
// Copyright 2008-2009 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_misc_opcodes.cpp#1 $ */
/* $DateTime: 2012/05/30 13:28:51 $ */
/* $Change: 832332 $ */
/* $Author: tknoll $ */
/*****************************************************************************/
#include "dng_misc_opcodes.h"
#include "dng_bottlenecks.h"
#include "dng_exceptions.h"
#include "dng_globals.h"
#include "dng_host.h"
#include "dng_image.h"
#include "dng_rect.h"
#include "dng_safe_arithmetic.h"
#include "dng_stream.h"
#include "dng_tag_values.h"
/*****************************************************************************/
dng_opcode_TrimBounds::dng_opcode_TrimBounds (const dng_rect &bounds)
: dng_opcode (dngOpcode_TrimBounds,
dngVersion_1_3_0_0,
kFlag_None)
, fBounds (bounds)
{
}
/*****************************************************************************/
dng_opcode_TrimBounds::dng_opcode_TrimBounds (dng_stream &stream)
: dng_opcode (dngOpcode_TrimBounds,
stream,
"TrimBounds")
, fBounds ()
{
if (stream.Get_uint32 () != 16)
{
ThrowBadFormat ();
}
fBounds.t = stream.Get_int32 ();
fBounds.l = stream.Get_int32 ();
fBounds.b = stream.Get_int32 ();
fBounds.r = stream.Get_int32 ();
if (fBounds.IsEmpty ())
{
ThrowBadFormat ();
}
#if qDNGValidate
if (gVerbose)
{
printf ("Bounds: t=%d, l=%d, b=%d, r=%d\n",
(int) fBounds.t,
(int) fBounds.l,
(int) fBounds.b,
(int) fBounds.r);
}
#endif
}
/*****************************************************************************/
void dng_opcode_TrimBounds::PutData (dng_stream &stream) const
{
stream.Put_uint32 (16);
stream.Put_int32 (fBounds.t);
stream.Put_int32 (fBounds.l);
stream.Put_int32 (fBounds.b);
stream.Put_int32 (fBounds.r);
}
/*****************************************************************************/
void dng_opcode_TrimBounds::Apply (dng_host & /* host */,
dng_negative & /* negative */,
AutoPtr<dng_image> &image)
{
if (fBounds.IsEmpty () || (fBounds & image->Bounds ()) != fBounds)
{
ThrowBadFormat ();
}
image->Trim (fBounds);
}
/*****************************************************************************/
void dng_area_spec::GetData (dng_stream &stream)
{
fArea.t = stream.Get_int32 ();
fArea.l = stream.Get_int32 ();
fArea.b = stream.Get_int32 ();
fArea.r = stream.Get_int32 ();
fPlane = stream.Get_uint32 ();
fPlanes = stream.Get_uint32 ();
fRowPitch = stream.Get_uint32 ();
fColPitch = stream.Get_uint32 ();
if (fPlanes < 1)
{
ThrowBadFormat ();
}
if (fRowPitch < 1 || fColPitch < 1)
{
ThrowBadFormat ();
}
if (fArea.IsEmpty ())
{
if (fRowPitch != 1 || fColPitch != 1)
{
ThrowBadFormat ();
}
}
else
{
int32 width = 0;
int32 height = 0;
if (!SafeInt32Sub (fArea.b, fArea.t, &height) ||
!SafeInt32Sub (fArea.r, fArea.l, &width) ||
fRowPitch > static_cast<uint32>(height) ||
fColPitch > static_cast<uint32>(width))
{
ThrowBadFormat();
}
}
#if qDNGValidate
if (gVerbose)
{
printf ("AreaSpec: t=%d, l=%d, b=%d, r=%d, p=%u:%u, rp=%u, cp=%u\n",
(int) fArea.t,
(int) fArea.l,
(int) fArea.b,
(int) fArea.r,
(unsigned) fPlane,
(unsigned) fPlanes,
(unsigned) fRowPitch,
(unsigned) fColPitch);
}
#endif
}
/*****************************************************************************/
void dng_area_spec::PutData (dng_stream &stream) const
{
stream.Put_int32 (fArea.t);
stream.Put_int32 (fArea.l);
stream.Put_int32 (fArea.b);
stream.Put_int32 (fArea.r);
stream.Put_uint32 (fPlane);
stream.Put_uint32 (fPlanes);
stream.Put_uint32 (fRowPitch);
stream.Put_uint32 (fColPitch);
}
/*****************************************************************************/
dng_rect dng_area_spec::Overlap (const dng_rect &tile) const
{
// Special case - if the fArea is empty, then dng_area_spec covers
// the entire image, no matter how large it is.
if (fArea.IsEmpty ())
{
return tile;
}
dng_rect overlap = fArea & tile;
if (overlap.NotEmpty ())
{
overlap.t = fArea.t + ConvertUint32ToInt32(
RoundUpUint32ToMultiple(static_cast<uint32>(overlap.t - fArea.t),
fRowPitch));
overlap.l = fArea.l + ConvertUint32ToInt32(
RoundUpUint32ToMultiple(static_cast<uint32>(overlap.l - fArea.l),
fColPitch));
if (overlap.NotEmpty ())
{
overlap.b = overlap.t + ((overlap.H () - 1) / fRowPitch) * fRowPitch + 1;
overlap.r = overlap.l + ((overlap.W () - 1) / fColPitch) * fColPitch + 1;
return overlap;
}
}
return dng_rect ();
}
/*****************************************************************************/
dng_opcode_MapTable::dng_opcode_MapTable (dng_host &host,
const dng_area_spec &areaSpec,
const uint16 *table,
uint32 count)
: dng_inplace_opcode (dngOpcode_MapTable,
dngVersion_1_3_0_0,
kFlag_None)
, fAreaSpec (areaSpec)
, fTable ()
, fCount (count)
{
if (count == 0 || count > 0x10000)
{
ThrowProgramError ();
}
fTable.Reset (host.Allocate (0x10000 * sizeof (uint16)));
DoCopyBytes (table,
fTable->Buffer (),
count * (uint32) sizeof (uint16));
ReplicateLastEntry ();
}
/*****************************************************************************/
dng_opcode_MapTable::dng_opcode_MapTable (dng_host &host,
dng_stream &stream)
: dng_inplace_opcode (dngOpcode_MapTable,
stream,
"MapTable")
, fAreaSpec ()
, fTable ()
, fCount (0)
{
uint32 dataSize = stream.Get_uint32 ();
fAreaSpec.GetData (stream);
fCount = stream.Get_uint32 ();
uint32 requiredSize = SafeUint32Mult(fCount, 2);
requiredSize = SafeUint32Add(requiredSize, dng_area_spec::kDataSize);
requiredSize = SafeUint32Add(requiredSize, 4);
if (dataSize != requiredSize)
{
ThrowBadFormat ();
}
if (fCount == 0 || fCount > 0x10000)
{
ThrowBadFormat ();
}
fTable.Reset (host.Allocate (0x10000 * sizeof (uint16)));
uint16 *table = fTable->Buffer_uint16 ();
for (uint32 index = 0; index < fCount; index++)
{
table [index] = stream.Get_uint16 ();
}
ReplicateLastEntry ();
#if qDNGValidate
if (gVerbose)
{
printf ("Count: %u\n", (unsigned) fCount);
for (uint32 j = 0; j < fCount && j < gDumpLineLimit; j++)
{
printf (" Table [%5u] = %5u\n", (unsigned) j, (unsigned) table [j]);
}
if (fCount > gDumpLineLimit)
{
printf (" ... %u table entries skipped\n", (unsigned) (fCount - gDumpLineLimit));
}
}
#endif
}
/*****************************************************************************/
void dng_opcode_MapTable::ReplicateLastEntry ()
{
uint16 *table = fTable->Buffer_uint16 ();
uint16 lastEntry = table [fCount];
for (uint32 index = fCount; index < 0x10000; index++)
{
table [index] = lastEntry;
}
}
/*****************************************************************************/
void dng_opcode_MapTable::PutData (dng_stream &stream) const
{
stream.Put_uint32 (dng_area_spec::kDataSize + 4 + fCount * 2);
fAreaSpec.PutData (stream);
stream.Put_uint32 (fCount);
uint16 *table = fTable->Buffer_uint16 ();
for (uint32 index = 0; index < fCount; index++)
{
stream.Put_uint16 (table [index]);
}
}
/*****************************************************************************/
uint32 dng_opcode_MapTable::BufferPixelType (uint32 /* imagePixelType */)
{
return ttShort;
}
/*****************************************************************************/
dng_rect dng_opcode_MapTable::ModifiedBounds (const dng_rect &imageBounds)
{
return fAreaSpec.Overlap (imageBounds);
}
/*****************************************************************************/
void dng_opcode_MapTable::ProcessArea (dng_negative & /* negative */,
uint32 /* threadIndex */,
dng_pixel_buffer &buffer,
const dng_rect &dstArea,
const dng_rect & /* imageBounds */)
{
dng_rect overlap = fAreaSpec.Overlap (dstArea);
if (overlap.NotEmpty ())
{
for (uint32 plane = fAreaSpec.Plane ();
plane < fAreaSpec.Plane () + fAreaSpec.Planes () &&
plane < buffer.Planes ();
plane++)
{
DoMapArea16 (buffer.DirtyPixel_uint16 (overlap.t, overlap.l, plane),
1,
(overlap.H () + fAreaSpec.RowPitch () - 1) / fAreaSpec.RowPitch (),
(overlap.W () + fAreaSpec.ColPitch () - 1) / fAreaSpec.ColPitch (),
0,
fAreaSpec.RowPitch () * buffer.RowStep (),
fAreaSpec.ColPitch (),
fTable->Buffer_uint16 ());
}
}
}
/*****************************************************************************/
dng_opcode_MapPolynomial::dng_opcode_MapPolynomial (const dng_area_spec &areaSpec,
uint32 degree,
const real64 *coefficient)
: dng_inplace_opcode (dngOpcode_MapPolynomial,
dngVersion_1_3_0_0,
kFlag_None)
, fAreaSpec (areaSpec)
, fDegree (degree)
{
for (uint32 j = 0; j <= kMaxDegree; j++)
{
if (j <= fDegree)
{
fCoefficient [j] = coefficient [j];
}
else
{
fCoefficient [j] = 0.0;
}
}
// Reduce degree if possible.
while (fDegree > 0 && fCoefficient [fDegree] == 0.0)
{
fDegree--;
}
}
/*****************************************************************************/
dng_opcode_MapPolynomial::dng_opcode_MapPolynomial (dng_stream &stream)
: dng_inplace_opcode (dngOpcode_MapPolynomial,
stream,
"MapPolynomial")
, fAreaSpec ()
, fDegree (0)
{
uint32 dataSize = stream.Get_uint32 ();
fAreaSpec.GetData (stream);
fDegree = stream.Get_uint32 ();
if (fDegree > kMaxDegree)
{
ThrowBadFormat ();
}
if (dataSize != dng_area_spec::kDataSize + 4 + (fDegree + 1) * 8)
{
ThrowBadFormat ();
}
for (uint32 j = 0; j <= kMaxDegree; j++)
{
if (j <= fDegree)
{
fCoefficient [j] = stream.Get_real64 ();
}
else
{
fCoefficient [j] = 0.0;
}
}
#if qDNGValidate
if (gVerbose)
{
for (uint32 k = 0; k <= fDegree; k++)
{
printf (" Coefficient [%u] = %f\n", (unsigned) k, fCoefficient [k]);
}
}
#endif
}
/*****************************************************************************/
void dng_opcode_MapPolynomial::PutData (dng_stream &stream) const
{
stream.Put_uint32 (dng_area_spec::kDataSize + 4 + (fDegree + 1) * 8);
fAreaSpec.PutData (stream);
stream.Put_uint32 (fDegree);
for (uint32 j = 0; j <= fDegree; j++)
{
stream.Put_real64 (fCoefficient [j]);
}
}
/*****************************************************************************/
uint32 dng_opcode_MapPolynomial::BufferPixelType (uint32 imagePixelType)
{
// If we are operating on the stage 1 image, then we need
// to adjust the coefficients to convert from the image
// values to the 32-bit floating point values that this
// opcode operates on.
// If we are operating on the stage 2 or 3 image, the logical
// range of the image is already 0.0 to 1.0, so we don't
// need to adjust the values.
real64 scale32 = 1.0;
if (Stage () == 1)
{
switch (imagePixelType)
{
case ttFloat:
break;
case ttShort:
{
scale32 = (real64) 0xFFFF;
break;
}
case ttLong:
{
scale32 = (real64) 0xFFFFFFFF;
break;
}
default:
ThrowBadFormat ();
}
}
real64 factor32 = 1.0 / scale32;
for (uint32 j = 0; j <= kMaxDegree; j++)
{
fCoefficient32 [j] = ConvertDoubleToFloat(fCoefficient [j] * factor32);
factor32 *= scale32;
}
return ttFloat;
}
/*****************************************************************************/
dng_rect dng_opcode_MapPolynomial::ModifiedBounds (const dng_rect &imageBounds)
{
return fAreaSpec.Overlap (imageBounds);
}
/*****************************************************************************/
void dng_opcode_MapPolynomial::ProcessArea (dng_negative & /* negative */,
uint32 /* threadIndex */,
dng_pixel_buffer &buffer,
const dng_rect &dstArea,
const dng_rect & /* imageBounds */)
{
dng_rect overlap = fAreaSpec.Overlap (dstArea);
if (overlap.NotEmpty ())
{
uint32 cols = overlap.W ();
uint32 colPitch = fAreaSpec.ColPitch ();
for (uint32 plane = fAreaSpec.Plane ();
plane < fAreaSpec.Plane () + fAreaSpec.Planes () &&
plane < buffer.Planes ();
plane++)
{
for (int32 row = overlap.t; row < overlap.b; row += fAreaSpec.RowPitch ())
{
real32 *dPtr = buffer.DirtyPixel_real32 (row, overlap.l, plane);
switch (fDegree)
{
case 0:
{
real32 y = Pin_real32 (0.0f,
fCoefficient32 [0],
1.0f);
for (uint32 col = 0; col < cols; col += colPitch)
{
dPtr [col] = y;
}
break;
}
case 1:
{
real32 c0 = fCoefficient32 [0];
real32 c1 = fCoefficient32 [1];
if (c0 == 0.0f)
{
if (c1 > 0.0f)
{
for (uint32 col = 0; col < cols; col += colPitch)
{
real32 x = dPtr [col];
real32 y = c1 * x;
dPtr [col] = Min_real32 (y, 1.0f);
}
}
else
{
for (uint32 col = 0; col < cols; col += colPitch)
{
dPtr [col] = 0.0f;
}
}
}
else
{
for (uint32 col = 0; col < cols; col += colPitch)
{
real32 x = dPtr [col];
real32 y = c0 +
c1 * x;
dPtr [col] = Pin_real32 (0.0f, y, 1.0f);
}
}
break;
}
case 2:
{
for (uint32 col = 0; col < cols; col += colPitch)
{
real32 x = dPtr [col];
real32 y = fCoefficient32 [0] + x *
(fCoefficient32 [1] + x *
(fCoefficient32 [2]));
dPtr [col] = Pin_real32 (0.0f, y, 1.0f);
}
break;
}
case 3:
{
for (uint32 col = 0; col < cols; col += colPitch)
{
real32 x = dPtr [col];
real32 y = fCoefficient32 [0] + x *
(fCoefficient32 [1] + x *
(fCoefficient32 [2] + x *
(fCoefficient32 [3])));
dPtr [col] = Pin_real32 (0.0f, y, 1.0f);
}
break;
}
case 4:
{
for (uint32 col = 0; col < cols; col += colPitch)
{
real32 x = dPtr [col];
real32 y = fCoefficient32 [0] + x *
(fCoefficient32 [1] + x *
(fCoefficient32 [2] + x *
(fCoefficient32 [3] + x *
(fCoefficient32 [4]))));
dPtr [col] = Pin_real32 (0.0f, y, 1.0f);
}
break;
}
default:
{
for (uint32 col = 0; col < cols; col += colPitch)
{
real32 x = dPtr [col];
real32 y = fCoefficient32 [0];
real32 xx = x;
for (uint32 j = 1; j <= fDegree; j++)
{
y += fCoefficient32 [j] * xx;
xx *= x;
}
dPtr [col] = Pin_real32 (0.0f, y, 1.0f);
}
}
}
}
}
}
}
/*****************************************************************************/
dng_opcode_DeltaPerRow::dng_opcode_DeltaPerRow (const dng_area_spec &areaSpec,
AutoPtr<dng_memory_block> &table)
: dng_inplace_opcode (dngOpcode_DeltaPerRow,
dngVersion_1_3_0_0,
kFlag_None)
, fAreaSpec (areaSpec)
, fTable ()
, fScale (1.0f)
{
fTable.Reset (table.Release ());
}
/*****************************************************************************/
dng_opcode_DeltaPerRow::dng_opcode_DeltaPerRow (dng_host &host,
dng_stream &stream)
: dng_inplace_opcode (dngOpcode_DeltaPerRow,
stream,
"DeltaPerRow")
, fAreaSpec ()
, fTable ()
, fScale (1.0f)
{
uint32 dataSize = stream.Get_uint32 ();
fAreaSpec.GetData (stream);
uint32 deltas = SafeUint32DivideUp (fAreaSpec.Area ().H (),
fAreaSpec.RowPitch ());
if (deltas != stream.Get_uint32 ())
{
ThrowBadFormat ();
}
if (dataSize != dng_area_spec::kDataSize + 4 + deltas * 4)
{
ThrowBadFormat ();
}
fTable.Reset (host.Allocate (SafeUint32Mult (deltas,
static_cast<uint32> (sizeof (real32)))));
real32 *table = fTable->Buffer_real32 ();
for (uint32 j = 0; j < deltas; j++)
{
table [j] = stream.Get_real32 ();
}
#if qDNGValidate
if (gVerbose)
{
printf ("Count: %u\n", (unsigned) deltas);
for (uint32 k = 0; k < deltas && k < gDumpLineLimit; k++)
{
printf (" Delta [%u] = %f\n", (unsigned) k, table [k]);
}
if (deltas > gDumpLineLimit)
{
printf (" ... %u deltas skipped\n", (unsigned) (deltas - gDumpLineLimit));
}
}
#endif
}
/*****************************************************************************/
void dng_opcode_DeltaPerRow::PutData (dng_stream &stream) const
{
uint32 deltas = SafeUint32DivideUp (fAreaSpec.Area ().H (),
fAreaSpec.RowPitch ());
stream.Put_uint32 (dng_area_spec::kDataSize + 4 + deltas * 4);
fAreaSpec.PutData (stream);
stream.Put_uint32 (deltas);
real32 *table = fTable->Buffer_real32 ();
for (uint32 j = 0; j < deltas; j++)
{
stream.Put_real32 (table [j]);
}
}
/*****************************************************************************/
uint32 dng_opcode_DeltaPerRow::BufferPixelType (uint32 imagePixelType)
{
real64 scale32 = 1.0;
switch (imagePixelType)
{
case ttFloat:
break;
case ttShort:
{
scale32 = (real64) 0xFFFF;
break;
}
case ttLong:
{
scale32 = (real64) 0xFFFFFFFF;
break;
}
default:
ThrowBadFormat ();
}
fScale = (real32) (1.0 / scale32);
return ttFloat;
}
/*****************************************************************************/
dng_rect dng_opcode_DeltaPerRow::ModifiedBounds (const dng_rect &imageBounds)
{
return fAreaSpec.Overlap (imageBounds);
}
/*****************************************************************************/
void dng_opcode_DeltaPerRow::ProcessArea (dng_negative & /* negative */,
uint32 /* threadIndex */,
dng_pixel_buffer &buffer,
const dng_rect &dstArea,
const dng_rect & /* imageBounds */)
{
dng_rect overlap = fAreaSpec.Overlap (dstArea);
if (overlap.NotEmpty ())
{
uint32 cols = overlap.W ();
uint32 colPitch = fAreaSpec.ColPitch ();
for (uint32 plane = fAreaSpec.Plane ();
plane < fAreaSpec.Plane () + fAreaSpec.Planes () &&
plane < buffer.Planes ();
plane++)
{
const real32 *table = fTable->Buffer_real32 () +
((overlap.t - fAreaSpec.Area ().t) /
fAreaSpec.RowPitch ());
for (int32 row = overlap.t; row < overlap.b; row += fAreaSpec.RowPitch ())
{
real32 rowDelta = *(table++) * fScale;
real32 *dPtr = buffer.DirtyPixel_real32 (row, overlap.l, plane);
for (uint32 col = 0; col < cols; col += colPitch)
{
real32 x = dPtr [col];
real32 y = x + rowDelta;
dPtr [col] = Pin_real32 (0.0f, y, 1.0f);
}
}
}
}
}
/*****************************************************************************/
dng_opcode_DeltaPerColumn::dng_opcode_DeltaPerColumn (const dng_area_spec &areaSpec,
AutoPtr<dng_memory_block> &table)
: dng_inplace_opcode (dngOpcode_DeltaPerColumn,
dngVersion_1_3_0_0,
kFlag_None)
, fAreaSpec (areaSpec)
, fTable ()
, fScale (1.0f)
{
fTable.Reset (table.Release ());
}
/*****************************************************************************/
dng_opcode_DeltaPerColumn::dng_opcode_DeltaPerColumn (dng_host &host,
dng_stream &stream)
: dng_inplace_opcode (dngOpcode_DeltaPerColumn,
stream,
"DeltaPerColumn")
, fAreaSpec ()
, fTable ()
, fScale (1.0f)
{
uint32 dataSize = stream.Get_uint32 ();
fAreaSpec.GetData (stream);
uint32 deltas = SafeUint32DivideUp (fAreaSpec.Area ().W (),
fAreaSpec.ColPitch ());
if (deltas != stream.Get_uint32 ())
{
ThrowBadFormat ();
}
if (dataSize != dng_area_spec::kDataSize + 4 + deltas * 4)
{
ThrowBadFormat ();
}
fTable.Reset (host.Allocate (SafeUint32Mult (deltas,
static_cast<uint32> (sizeof (real32)))));
real32 *table = fTable->Buffer_real32 ();
for (uint32 j = 0; j < deltas; j++)
{
table [j] = stream.Get_real32 ();
}
#if qDNGValidate
if (gVerbose)
{
printf ("Count: %u\n", (unsigned) deltas);
for (uint32 k = 0; k < deltas && k < gDumpLineLimit; k++)
{
printf (" Delta [%u] = %f\n", (unsigned) k, table [k]);
}
if (deltas > gDumpLineLimit)
{
printf (" ... %u deltas skipped\n", (unsigned) (deltas - gDumpLineLimit));
}
}
#endif
}
/*****************************************************************************/
void dng_opcode_DeltaPerColumn::PutData (dng_stream &stream) const
{
uint32 deltas = SafeUint32DivideUp (fAreaSpec.Area ().W (),
fAreaSpec.ColPitch ());
stream.Put_uint32 (dng_area_spec::kDataSize + 4 + deltas * 4);
fAreaSpec.PutData (stream);
stream.Put_uint32 (deltas);
real32 *table = fTable->Buffer_real32 ();
for (uint32 j = 0; j < deltas; j++)
{
stream.Put_real32 (table [j]);
}
}
/*****************************************************************************/
uint32 dng_opcode_DeltaPerColumn::BufferPixelType (uint32 imagePixelType)
{
real64 scale32 = 1.0;
switch (imagePixelType)
{
case ttFloat:
break;
case ttShort:
{
scale32 = (real64) 0xFFFF;
break;
}
case ttLong:
{
scale32 = (real64) 0xFFFFFFFF;
break;
}
default:
ThrowBadFormat ();
}
fScale = (real32) (1.0 / scale32);
return ttFloat;
}
/*****************************************************************************/
dng_rect dng_opcode_DeltaPerColumn::ModifiedBounds (const dng_rect &imageBounds)
{
return fAreaSpec.Overlap (imageBounds);
}
/*****************************************************************************/
void dng_opcode_DeltaPerColumn::ProcessArea (dng_negative & /* negative */,
uint32 /* threadIndex */,
dng_pixel_buffer &buffer,
const dng_rect &dstArea,
const dng_rect & /* imageBounds */)
{
dng_rect overlap = fAreaSpec.Overlap (dstArea);
if (overlap.NotEmpty ())
{
uint32 rows = (overlap.H () + fAreaSpec.RowPitch () - 1) /
fAreaSpec.RowPitch ();
int32 rowStep = buffer.RowStep () * fAreaSpec.RowPitch ();
for (uint32 plane = fAreaSpec.Plane ();
plane < fAreaSpec.Plane () + fAreaSpec.Planes () &&
plane < buffer.Planes ();
plane++)
{
const real32 *table = fTable->Buffer_real32 () +
((overlap.l - fAreaSpec.Area ().l) /
fAreaSpec.ColPitch ());
for (int32 col = overlap.l; col < overlap.r; col += fAreaSpec.ColPitch ())
{
real32 colDelta = *(table++) * fScale;
real32 *dPtr = buffer.DirtyPixel_real32 (overlap.t, col, plane);
for (uint32 row = 0; row < rows; row++)
{
real32 x = dPtr [0];
real32 y = x + colDelta;
dPtr [0] = Pin_real32 (0.0f, y, 1.0f);
dPtr += rowStep;
}
}
}
}
}
/*****************************************************************************/
dng_opcode_ScalePerRow::dng_opcode_ScalePerRow (const dng_area_spec &areaSpec,
AutoPtr<dng_memory_block> &table)
: dng_inplace_opcode (dngOpcode_ScalePerRow,
dngVersion_1_3_0_0,
kFlag_None)
, fAreaSpec (areaSpec)
, fTable ()
{
fTable.Reset (table.Release ());
}
/*****************************************************************************/
dng_opcode_ScalePerRow::dng_opcode_ScalePerRow (dng_host &host,
dng_stream &stream)
: dng_inplace_opcode (dngOpcode_ScalePerRow,
stream,
"ScalePerRow")
, fAreaSpec ()
, fTable ()
{
uint32 dataSize = stream.Get_uint32 ();
fAreaSpec.GetData (stream);
uint32 scales = SafeUint32DivideUp (fAreaSpec.Area ().H (),
fAreaSpec.RowPitch ());
if (scales != stream.Get_uint32 ())
{
ThrowBadFormat ();
}
if (dataSize != dng_area_spec::kDataSize + 4 + scales * 4)
{
ThrowBadFormat ();
}
fTable.Reset (host.Allocate (SafeUint32Mult (scales,
static_cast<uint32> (sizeof (real32)))));
real32 *table = fTable->Buffer_real32 ();
for (uint32 j = 0; j < scales; j++)
{
table [j] = stream.Get_real32 ();
}
#if qDNGValidate
if (gVerbose)
{
printf ("Count: %u\n", (unsigned) scales);
for (uint32 k = 0; k < scales && k < gDumpLineLimit; k++)
{
printf (" Scale [%u] = %f\n", (unsigned) k, table [k]);
}
if (scales > gDumpLineLimit)
{
printf (" ... %u scales skipped\n", (unsigned) (scales - gDumpLineLimit));
}
}
#endif
}
/*****************************************************************************/
void dng_opcode_ScalePerRow::PutData (dng_stream &stream) const
{
uint32 scales = SafeUint32DivideUp (fAreaSpec.Area ().H (),
fAreaSpec.RowPitch ());
stream.Put_uint32 (dng_area_spec::kDataSize + 4 + scales * 4);
fAreaSpec.PutData (stream);
stream.Put_uint32 (scales);
real32 *table = fTable->Buffer_real32 ();
for (uint32 j = 0; j < scales; j++)
{
stream.Put_real32 (table [j]);
}
}
/*****************************************************************************/
uint32 dng_opcode_ScalePerRow::BufferPixelType (uint32 /* imagePixelType */)
{
return ttFloat;
}
/*****************************************************************************/
dng_rect dng_opcode_ScalePerRow::ModifiedBounds (const dng_rect &imageBounds)
{
return fAreaSpec.Overlap (imageBounds);
}
/*****************************************************************************/
void dng_opcode_ScalePerRow::ProcessArea (dng_negative & /* negative */,
uint32 /* threadIndex */,
dng_pixel_buffer &buffer,
const dng_rect &dstArea,
const dng_rect & /* imageBounds */)
{
dng_rect overlap = fAreaSpec.Overlap (dstArea);
if (overlap.NotEmpty ())
{
uint32 cols = overlap.W ();
uint32 colPitch = fAreaSpec.ColPitch ();
for (uint32 plane = fAreaSpec.Plane ();
plane < fAreaSpec.Plane () + fAreaSpec.Planes () &&
plane < buffer.Planes ();
plane++)
{
const real32 *table = fTable->Buffer_real32 () +
((overlap.t - fAreaSpec.Area ().t) /
fAreaSpec.RowPitch ());
for (int32 row = overlap.t; row < overlap.b; row += fAreaSpec.RowPitch ())
{
real32 rowScale = *(table++);
real32 *dPtr = buffer.DirtyPixel_real32 (row, overlap.l, plane);
for (uint32 col = 0; col < cols; col += colPitch)
{
real32 x = dPtr [col];
real32 y = x * rowScale;
dPtr [col] = Min_real32 (y, 1.0f);
}
}
}
}
}
/*****************************************************************************/
dng_opcode_ScalePerColumn::dng_opcode_ScalePerColumn (const dng_area_spec &areaSpec,
AutoPtr<dng_memory_block> &table)
: dng_inplace_opcode (dngOpcode_ScalePerColumn,
dngVersion_1_3_0_0,
kFlag_None)
, fAreaSpec (areaSpec)
, fTable ()
{
fTable.Reset (table.Release ());
}
/*****************************************************************************/
dng_opcode_ScalePerColumn::dng_opcode_ScalePerColumn (dng_host &host,
dng_stream &stream)
: dng_inplace_opcode (dngOpcode_ScalePerColumn,
stream,
"ScalePerColumn")
, fAreaSpec ()
, fTable ()
{
uint32 dataSize = stream.Get_uint32 ();
fAreaSpec.GetData (stream);
uint32 scales = SafeUint32DivideUp (fAreaSpec.Area ().W (),
fAreaSpec.ColPitch());
if (scales != stream.Get_uint32 ())
{
ThrowBadFormat ();
}
if (dataSize != dng_area_spec::kDataSize + 4 + scales * 4)
{
ThrowBadFormat ();
}
fTable.Reset (host.Allocate (SafeUint32Mult (scales,
static_cast<uint32> (sizeof (real32)))));
real32 *table = fTable->Buffer_real32 ();
for (uint32 j = 0; j < scales; j++)
{
table [j] = stream.Get_real32 ();
}
#if qDNGValidate
if (gVerbose)
{
printf ("Count: %u\n", (unsigned) scales);
for (uint32 k = 0; k < scales && k < gDumpLineLimit; k++)
{
printf (" Scale [%u] = %f\n", (unsigned) k, table [k]);
}
if (scales > gDumpLineLimit)
{
printf (" ... %u deltas skipped\n", (unsigned) (scales - gDumpLineLimit));
}
}
#endif
}
/*****************************************************************************/
void dng_opcode_ScalePerColumn::PutData (dng_stream &stream) const
{
uint32 scales = SafeUint32DivideUp (fAreaSpec.Area ().W (),
fAreaSpec.ColPitch ());
stream.Put_uint32 (dng_area_spec::kDataSize + 4 + scales * 4);
fAreaSpec.PutData (stream);
stream.Put_uint32 (scales);
real32 *table = fTable->Buffer_real32 ();
for (uint32 j = 0; j < scales; j++)
{
stream.Put_real32 (table [j]);
}
}
/*****************************************************************************/
uint32 dng_opcode_ScalePerColumn::BufferPixelType (uint32 /* imagePixelType */)
{
return ttFloat;
}
/*****************************************************************************/
dng_rect dng_opcode_ScalePerColumn::ModifiedBounds (const dng_rect &imageBounds)
{
return fAreaSpec.Overlap (imageBounds);
}
/*****************************************************************************/
void dng_opcode_ScalePerColumn::ProcessArea (dng_negative & /* negative */,
uint32 /* threadIndex */,
dng_pixel_buffer &buffer,
const dng_rect &dstArea,
const dng_rect & /* imageBounds */)
{
dng_rect overlap = fAreaSpec.Overlap (dstArea);
if (overlap.NotEmpty ())
{
uint32 rows = (overlap.H () + fAreaSpec.RowPitch () - 1) /
fAreaSpec.RowPitch ();
int32 rowStep = buffer.RowStep () * fAreaSpec.RowPitch ();
for (uint32 plane = fAreaSpec.Plane ();
plane < fAreaSpec.Plane () + fAreaSpec.Planes () &&
plane < buffer.Planes ();
plane++)
{
const real32 *table = fTable->Buffer_real32 () +
((overlap.l - fAreaSpec.Area ().l) /
fAreaSpec.ColPitch ());
for (int32 col = overlap.l; col < overlap.r; col += fAreaSpec.ColPitch ())
{
real32 colScale = *(table++);
real32 *dPtr = buffer.DirtyPixel_real32 (overlap.t, col, plane);
for (uint32 row = 0; row < rows; row++)
{
real32 x = dPtr [0];
real32 y = x * colScale;
dPtr [0] = Min_real32 (y, 1.0f);
dPtr += rowStep;
}
}
}
}
}
/*****************************************************************************/