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