| /*****************************************************************************/ |
| // Copyright 2008 Adobe Systems Incorporated |
| // All Rights Reserved. |
| // |
| // NOTICE: Adobe permits you to use, modify, and distribute this file in |
| // accordance with the terms of the Adobe license agreement accompanying it. |
| /*****************************************************************************/ |
| |
| /* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_bad_pixels.cpp#1 $ */ |
| /* $DateTime: 2012/05/30 13:28:51 $ */ |
| /* $Change: 832332 $ */ |
| /* $Author: tknoll $ */ |
| |
| /*****************************************************************************/ |
| |
| #include "dng_bad_pixels.h" |
| |
| #include "dng_filter_task.h" |
| #include "dng_globals.h" |
| #include "dng_host.h" |
| #include "dng_image.h" |
| #include "dng_negative.h" |
| #include "dng_safe_arithmetic.h" |
| |
| #include <algorithm> |
| |
| /*****************************************************************************/ |
| |
| dng_opcode_FixBadPixelsConstant::dng_opcode_FixBadPixelsConstant |
| (uint32 constant, |
| uint32 bayerPhase) |
| |
| : dng_filter_opcode (dngOpcode_FixBadPixelsConstant, |
| dngVersion_1_3_0_0, |
| 0) |
| |
| , fConstant (constant) |
| , fBayerPhase (bayerPhase) |
| |
| { |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_opcode_FixBadPixelsConstant::dng_opcode_FixBadPixelsConstant |
| (dng_stream &stream) |
| |
| : dng_filter_opcode (dngOpcode_FixBadPixelsConstant, |
| stream, |
| "FixBadPixelsConstant") |
| |
| , fConstant (0) |
| , fBayerPhase (0) |
| |
| { |
| |
| if (stream.Get_uint32 () != 8) |
| { |
| ThrowBadFormat (); |
| } |
| |
| fConstant = stream.Get_uint32 (); |
| fBayerPhase = stream.Get_uint32 (); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("Constant: %u\n", (unsigned) fConstant); |
| |
| printf ("Bayer Phase: %u\n", (unsigned) fBayerPhase); |
| |
| } |
| |
| #endif |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_opcode_FixBadPixelsConstant::PutData (dng_stream &stream) const |
| { |
| |
| stream.Put_uint32 (8); |
| |
| stream.Put_uint32 (fConstant ); |
| stream.Put_uint32 (fBayerPhase); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_point dng_opcode_FixBadPixelsConstant::SrcRepeat () |
| { |
| |
| return dng_point (2, 2); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_rect dng_opcode_FixBadPixelsConstant::SrcArea (const dng_rect &dstArea, |
| const dng_rect & /* imageBounds */) |
| { |
| |
| dng_rect srcArea = dstArea; |
| |
| srcArea.t -= 2; |
| srcArea.l -= 2; |
| |
| srcArea.b += 2; |
| srcArea.r += 2; |
| |
| return srcArea; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_opcode_FixBadPixelsConstant::Prepare (dng_negative & /* negative */, |
| uint32 /* threadCount */, |
| const dng_point & /* tileSize */, |
| const dng_rect & /* imageBounds */, |
| uint32 imagePlanes, |
| uint32 bufferPixelType, |
| dng_memory_allocator & /* allocator */) |
| { |
| |
| // This opcode is restricted to single channel images. |
| |
| if (imagePlanes != 1) |
| { |
| |
| ThrowBadFormat (); |
| |
| } |
| |
| // This opcode is restricted to 16-bit images. |
| |
| if (bufferPixelType != ttShort) |
| { |
| |
| ThrowBadFormat (); |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_opcode_FixBadPixelsConstant::ProcessArea (dng_negative & /* negative */, |
| uint32 /* threadIndex */, |
| dng_pixel_buffer &srcBuffer, |
| dng_pixel_buffer &dstBuffer, |
| const dng_rect &dstArea, |
| const dng_rect & /* imageBounds */) |
| { |
| |
| dstBuffer.CopyArea (srcBuffer, |
| dstArea, |
| 0, |
| dstBuffer.fPlanes); |
| |
| uint16 badPixel = (uint16) fConstant; |
| |
| for (int32 dstRow = dstArea.t; dstRow < dstArea.b; dstRow++) |
| { |
| |
| const uint16 *sPtr = srcBuffer.ConstPixel_uint16 (dstRow, dstArea.l, 0); |
| uint16 *dPtr = dstBuffer.DirtyPixel_uint16 (dstRow, dstArea.l, 0); |
| |
| for (int32 dstCol = dstArea.l; dstCol < dstArea.r; dstCol++) |
| { |
| |
| if (*sPtr == badPixel) |
| { |
| |
| uint32 count = 0; |
| uint32 total = 0; |
| |
| uint16 value; |
| |
| if (IsGreen (dstRow, dstCol)) // Green pixel |
| { |
| |
| value = sPtr [-srcBuffer.fRowStep - 1]; |
| |
| if (value != badPixel) |
| { |
| count += 1; |
| total += value; |
| } |
| |
| value = sPtr [-srcBuffer.fRowStep + 1]; |
| |
| if (value != badPixel) |
| { |
| count += 1; |
| total += value; |
| } |
| |
| value = sPtr [srcBuffer.fRowStep - 1]; |
| |
| if (value != badPixel) |
| { |
| count += 1; |
| total += value; |
| } |
| |
| value = sPtr [srcBuffer.fRowStep + 1]; |
| |
| if (value != badPixel) |
| { |
| count += 1; |
| total += value; |
| } |
| |
| } |
| |
| else // Red/blue pixel. |
| { |
| |
| value = sPtr [-srcBuffer.fRowStep * 2]; |
| |
| if (value != badPixel) |
| { |
| count += 1; |
| total += value; |
| } |
| |
| value = sPtr [srcBuffer.fRowStep * 2]; |
| |
| if (value != badPixel) |
| { |
| count += 1; |
| total += value; |
| } |
| |
| value = sPtr [-2]; |
| |
| if (value != badPixel) |
| { |
| count += 1; |
| total += value; |
| } |
| |
| value = sPtr [2]; |
| |
| if (value != badPixel) |
| { |
| count += 1; |
| total += value; |
| } |
| |
| } |
| |
| if (count == 4) // Most common case. |
| { |
| |
| *dPtr = (uint16) ((total + 2) >> 2); |
| |
| } |
| |
| else if (count > 0) |
| { |
| |
| *dPtr = (uint16) ((total + (count >> 1)) / count); |
| |
| } |
| |
| } |
| |
| sPtr++; |
| dPtr++; |
| |
| } |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_bad_pixel_list::dng_bad_pixel_list () |
| |
| : fBadPoints () |
| , fBadRects () |
| |
| { |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_bad_pixel_list::AddPoint (const dng_point &pt) |
| { |
| |
| fBadPoints.push_back (pt); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_bad_pixel_list::AddRect (const dng_rect &r) |
| { |
| |
| fBadRects.push_back (r); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| static bool SortBadPoints (const dng_point &a, |
| const dng_point &b) |
| { |
| |
| if (a.v < b.v) |
| return true; |
| |
| if (a.v > b.v) |
| return false; |
| |
| return a.h < b.h; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| static bool SortBadRects (const dng_rect &a, |
| const dng_rect &b) |
| { |
| |
| if (a.t < b.t) |
| return true; |
| |
| if (a.t > b.t) |
| return false; |
| |
| if (a.l < b.l) |
| return true; |
| |
| if (a.l > b.l) |
| return false; |
| |
| if (a.b < b.b) |
| return true; |
| |
| if (a.b > b.b) |
| return false; |
| |
| return a.r < b.r; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_bad_pixel_list::Sort () |
| { |
| |
| if (PointCount () > 1) |
| { |
| |
| std::sort (fBadPoints.begin (), |
| fBadPoints.end (), |
| SortBadPoints); |
| |
| } |
| |
| if (RectCount () > 1) |
| { |
| |
| std::sort (fBadRects.begin (), |
| fBadRects.end (), |
| SortBadRects); |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| bool dng_bad_pixel_list::IsPointIsolated (uint32 index, |
| uint32 radius) const |
| { |
| |
| dng_point pt = Point (index); |
| |
| // Search backward through bad point list. |
| |
| for (int32 j = index - 1; j >= 0; j--) |
| { |
| |
| const dng_point &pt2 = Point (j); |
| |
| if (pt2.v < pt.v - (int32) radius) |
| { |
| break; |
| } |
| |
| if (Abs_int32 (pt2.h - pt.h) <= radius) |
| { |
| return false; |
| } |
| |
| } |
| |
| // Search forward through bad point list. |
| |
| for (uint32 k = index + 1; k < PointCount (); k++) |
| { |
| |
| const dng_point &pt2 = Point (k); |
| |
| if (pt2.v > pt.v + (int32) radius) |
| { |
| break; |
| } |
| |
| if (Abs_int32 (pt2.h - pt.h) <= radius) |
| { |
| return false; |
| } |
| |
| } |
| |
| // Search through bad rectangle list. |
| |
| dng_rect testRect (pt.v - radius, |
| pt.h - radius, |
| pt.v + radius + 1, |
| pt.h + radius + 1); |
| |
| for (uint32 n = 0; n < RectCount (); n++) |
| { |
| |
| if ((testRect & Rect (n)).NotEmpty ()) |
| { |
| return false; |
| } |
| |
| } |
| |
| // Did not find point anywhere, so bad pixel is isolated. |
| |
| return true; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| bool dng_bad_pixel_list::IsRectIsolated (uint32 index, |
| uint32 radius) const |
| { |
| |
| dng_rect testRect = Rect (index); |
| |
| testRect.t -= radius; |
| testRect.l -= radius; |
| testRect.b += radius; |
| testRect.r += radius; |
| |
| for (uint32 n = 0; n < RectCount (); n++) |
| { |
| |
| if (n != index) |
| { |
| |
| if ((testRect & Rect (n)).NotEmpty ()) |
| { |
| return false; |
| } |
| |
| } |
| |
| } |
| |
| return true; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| bool dng_bad_pixel_list::IsPointValid (const dng_point &pt, |
| const dng_rect &imageBounds, |
| uint32 index) const |
| { |
| |
| // The point must be in the image bounds to be valid. |
| |
| if (pt.v < imageBounds.t || |
| pt.h < imageBounds.l || |
| pt.v >= imageBounds.b || |
| pt.h >= imageBounds.r) |
| { |
| return false; |
| } |
| |
| // Only search the bad point list if we have a starting search index. |
| |
| if (index != kNoIndex) |
| { |
| |
| // Search backward through bad point list. |
| |
| for (int32 j = index - 1; j >= 0; j--) |
| { |
| |
| const dng_point &pt2 = Point (j); |
| |
| if (pt2.v < pt.v) |
| { |
| break; |
| } |
| |
| if (pt2 == pt) |
| { |
| return false; |
| } |
| |
| } |
| |
| // Search forward through bad point list. |
| |
| for (uint32 k = index + 1; k < PointCount (); k++) |
| { |
| |
| const dng_point &pt2 = Point (k); |
| |
| if (pt2.v > pt.v) |
| { |
| break; |
| } |
| |
| if (pt2 == pt) |
| { |
| return false; |
| } |
| |
| } |
| |
| } |
| |
| // Search through bad rectangle list. |
| |
| for (uint32 n = 0; n < RectCount (); n++) |
| { |
| |
| const dng_rect &r = Rect (n); |
| |
| if (pt.v >= r.t && |
| pt.h >= r.l && |
| pt.v < r.b && |
| pt.h < r.r) |
| { |
| return false; |
| } |
| |
| } |
| |
| // Did not find point anywhere, so pixel is valid. |
| |
| return true; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_opcode_FixBadPixelsList::dng_opcode_FixBadPixelsList |
| (AutoPtr<dng_bad_pixel_list> &list, |
| uint32 bayerPhase) |
| |
| |
| : dng_filter_opcode (dngOpcode_FixBadPixelsList, |
| dngVersion_1_3_0_0, |
| 0) |
| |
| , fList () |
| |
| , fBayerPhase (bayerPhase) |
| |
| { |
| |
| fList.Reset (list.Release ()); |
| |
| fList->Sort (); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_opcode_FixBadPixelsList::dng_opcode_FixBadPixelsList (dng_stream &stream) |
| |
| : dng_filter_opcode (dngOpcode_FixBadPixelsList, |
| stream, |
| "FixBadPixelsList") |
| |
| , fList () |
| |
| , fBayerPhase (0) |
| |
| { |
| |
| uint32 size = stream.Get_uint32 (); |
| |
| fBayerPhase = stream.Get_uint32 (); |
| |
| uint32 pCount = stream.Get_uint32 (); |
| uint32 rCount = stream.Get_uint32 (); |
| uint32 expectedSize = |
| SafeUint32Add(12, SafeUint32Add(SafeUint32Mult(pCount, 8), SafeUint32Mult(rCount, 16))); |
| if (size != expectedSize) |
| { |
| ThrowBadFormat (); |
| } |
| |
| fList.Reset (new dng_bad_pixel_list); |
| |
| uint32 index; |
| |
| for (index = 0; index < pCount; index++) |
| { |
| |
| dng_point pt; |
| |
| pt.v = stream.Get_int32 (); |
| pt.h = stream.Get_int32 (); |
| |
| fList->AddPoint (pt); |
| |
| } |
| |
| for (index = 0; index < rCount; index++) |
| { |
| |
| dng_rect r; |
| |
| r.t = stream.Get_int32 (); |
| r.l = stream.Get_int32 (); |
| r.b = stream.Get_int32 (); |
| r.r = stream.Get_int32 (); |
| |
| fList->AddRect (r); |
| |
| } |
| |
| fList->Sort (); |
| |
| #if qDNGValidate |
| |
| if (gVerbose) |
| { |
| |
| printf ("Bayer Phase: %u\n", (unsigned) fBayerPhase); |
| |
| printf ("Bad Pixels: %u\n", (unsigned) pCount); |
| |
| for (index = 0; index < pCount && index < gDumpLineLimit; index++) |
| { |
| printf (" Pixel [%u]: v=%d, h=%d\n", |
| (unsigned) index, |
| (int) fList->Point (index).v, |
| (int) fList->Point (index).h); |
| } |
| |
| if (pCount > gDumpLineLimit) |
| { |
| printf (" ... %u bad pixels skipped\n", (unsigned) (pCount - gDumpLineLimit)); |
| } |
| |
| printf ("Bad Rects: %u\n", (unsigned) rCount); |
| |
| for (index = 0; index < rCount && index < gDumpLineLimit; index++) |
| { |
| printf (" Rect [%u]: t=%d, l=%d, b=%d, r=%d\n", |
| (unsigned) index, |
| (int) fList->Rect (index).t, |
| (int) fList->Rect (index).l, |
| (int) fList->Rect (index).b, |
| (int) fList->Rect (index).r); |
| } |
| |
| if (rCount > gDumpLineLimit) |
| { |
| printf (" ... %u bad rects skipped\n", (unsigned) (rCount - gDumpLineLimit)); |
| } |
| |
| } |
| |
| #endif |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_opcode_FixBadPixelsList::PutData (dng_stream &stream) const |
| { |
| |
| uint32 pCount = fList->PointCount (); |
| uint32 rCount = fList->RectCount (); |
| |
| stream.Put_uint32 (12 + pCount * 8 + rCount * 16); |
| |
| stream.Put_uint32 (fBayerPhase); |
| |
| stream.Put_uint32 (pCount); |
| stream.Put_uint32 (rCount); |
| |
| uint32 index; |
| |
| for (index = 0; index < pCount; index++) |
| { |
| |
| const dng_point &pt (fList->Point (index)); |
| |
| stream.Put_int32 (pt.v); |
| stream.Put_int32 (pt.h); |
| |
| } |
| |
| for (index = 0; index < rCount; index++) |
| { |
| |
| const dng_rect &r (fList->Rect (index)); |
| |
| stream.Put_int32 (r.t); |
| stream.Put_int32 (r.l); |
| stream.Put_int32 (r.b); |
| stream.Put_int32 (r.r); |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_rect dng_opcode_FixBadPixelsList::SrcArea (const dng_rect &dstArea, |
| const dng_rect & /* imageBounds */) |
| { |
| |
| int32 padding = 0; |
| |
| if (fList->PointCount ()) |
| { |
| padding += kBadPointPadding; |
| } |
| |
| if (fList->RectCount ()) |
| { |
| padding += kBadRectPadding; |
| } |
| |
| dng_rect srcArea = dstArea; |
| |
| srcArea.t -= padding; |
| srcArea.l -= padding; |
| |
| srcArea.b += padding; |
| srcArea.r += padding; |
| |
| return srcArea; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| dng_point dng_opcode_FixBadPixelsList::SrcRepeat () |
| { |
| |
| return dng_point (2, 2); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_opcode_FixBadPixelsList::Prepare (dng_negative & /* negative */, |
| uint32 /* threadCount */, |
| const dng_point & /* tileSize */, |
| const dng_rect & /* imageBounds */, |
| uint32 imagePlanes, |
| uint32 bufferPixelType, |
| dng_memory_allocator & /* allocator */) |
| { |
| |
| // This opcode is restricted to single channel images. |
| |
| if (imagePlanes != 1) |
| { |
| |
| ThrowBadFormat (); |
| |
| } |
| |
| // This opcode is restricted to 16-bit images. |
| |
| if (bufferPixelType != ttShort) |
| { |
| |
| ThrowBadFormat (); |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_opcode_FixBadPixelsList::FixIsolatedPixel (dng_pixel_buffer &buffer, |
| dng_point &badPoint) |
| { |
| |
| uint16 *p0 = buffer.DirtyPixel_uint16 (badPoint.v - 2, badPoint.h - 2, 0); |
| uint16 *p1 = buffer.DirtyPixel_uint16 (badPoint.v - 1, badPoint.h - 2, 0); |
| uint16 *p2 = buffer.DirtyPixel_uint16 (badPoint.v , badPoint.h - 2, 0); |
| uint16 *p3 = buffer.DirtyPixel_uint16 (badPoint.v + 1, badPoint.h - 2, 0); |
| uint16 *p4 = buffer.DirtyPixel_uint16 (badPoint.v + 2, badPoint.h - 2, 0); |
| |
| uint32 est0; |
| uint32 est1; |
| uint32 est2; |
| uint32 est3; |
| |
| uint32 grad0; |
| uint32 grad1; |
| uint32 grad2; |
| uint32 grad3; |
| |
| if (IsGreen (badPoint.v, badPoint.h)) // Green pixel |
| { |
| |
| // g00 b01 g02 b03 g04 |
| // r10 g11 r12 g13 r14 |
| // g20 b21 g22 b23 g24 |
| // r30 g31 r32 g33 r34 |
| // g40 b41 g42 b43 g44 |
| |
| int32 b01 = p0 [1]; |
| int32 g02 = p0 [2]; |
| int32 b03 = p0 [3]; |
| |
| int32 r10 = p1 [0]; |
| int32 g11 = p1 [1]; |
| int32 r12 = p1 [2]; |
| int32 g13 = p1 [3]; |
| int32 r14 = p1 [4]; |
| |
| int32 g20 = p2 [0]; |
| int32 b21 = p2 [1]; |
| int32 b23 = p2 [3]; |
| int32 g24 = p2 [4]; |
| |
| int32 r30 = p3 [0]; |
| int32 g31 = p3 [1]; |
| int32 r32 = p3 [2]; |
| int32 g33 = p3 [3]; |
| int32 r34 = p3 [4]; |
| |
| int32 b41 = p4 [1]; |
| int32 g42 = p4 [2]; |
| int32 b43 = p4 [3]; |
| |
| est0 = g02 + g42; |
| |
| grad0 = Abs_int32 (g02 - g42) + |
| Abs_int32 (g11 - g31) + |
| Abs_int32 (g13 - g33) + |
| Abs_int32 (b01 - b21) + |
| Abs_int32 (b03 - b23) + |
| Abs_int32 (b21 - b41) + |
| Abs_int32 (b23 - b43); |
| |
| est1 = g11 + g33; |
| |
| grad1 = Abs_int32 (g11 - g33) + |
| Abs_int32 (g02 - g24) + |
| Abs_int32 (g20 - g42) + |
| Abs_int32 (b01 - b23) + |
| Abs_int32 (r10 - r32) + |
| Abs_int32 (r12 - r34) + |
| Abs_int32 (b21 - b43); |
| |
| est2 = g20 + g24; |
| |
| grad2 = Abs_int32 (g20 - g24) + |
| Abs_int32 (g11 - g13) + |
| Abs_int32 (g31 - g33) + |
| Abs_int32 (r10 - r12) + |
| Abs_int32 (r30 - r32) + |
| Abs_int32 (r12 - r14) + |
| Abs_int32 (r32 - r34); |
| |
| est3 = g13 + g31; |
| |
| grad3 = Abs_int32 (g13 - g31) + |
| Abs_int32 (g02 - g20) + |
| Abs_int32 (g24 - g42) + |
| Abs_int32 (b03 - b21) + |
| Abs_int32 (r14 - r32) + |
| Abs_int32 (r12 - r30) + |
| Abs_int32 (b23 - b41); |
| |
| } |
| |
| else // Red/blue pixel |
| { |
| |
| // b00 g01 b02 g03 b04 |
| // g10 r11 g12 r13 g14 |
| // b20 g21 b22 g23 b24 |
| // g30 r31 g32 r33 g34 |
| // b40 g41 b42 g43 b44 |
| |
| int32 b00 = p0 [0]; |
| int32 g01 = p0 [1]; |
| int32 b02 = p0 [2]; |
| int32 g03 = p0 [3]; |
| int32 b04 = p0 [4]; |
| |
| int32 g10 = p1 [0]; |
| int32 r11 = p1 [1]; |
| int32 g12 = p1 [2]; |
| int32 r13 = p1 [3]; |
| int32 g14 = p1 [4]; |
| |
| int32 b20 = p2 [0]; |
| int32 g21 = p2 [1]; |
| int32 g23 = p2 [3]; |
| int32 b24 = p2 [4]; |
| |
| int32 g30 = p3 [0]; |
| int32 r31 = p3 [1]; |
| int32 g32 = p3 [2]; |
| int32 r33 = p3 [3]; |
| int32 g34 = p3 [4]; |
| |
| int32 b40 = p4 [0]; |
| int32 g41 = p4 [1]; |
| int32 b42 = p4 [2]; |
| int32 g43 = p4 [3]; |
| int32 b44 = p4 [4]; |
| |
| est0 = b02 + b42; |
| |
| grad0 = Abs_int32 (b02 - b42) + |
| Abs_int32 (g12 - g32) + |
| Abs_int32 (g01 - g21) + |
| Abs_int32 (g21 - g41) + |
| Abs_int32 (g03 - g23) + |
| Abs_int32 (g23 - g43) + |
| Abs_int32 (r11 - r31) + |
| Abs_int32 (r13 - r33); |
| |
| est1 = b00 + b44; |
| |
| grad1 = Abs_int32 (b00 - b44) + |
| Abs_int32 (r11 - r33) + |
| Abs_int32 (g01 - g23) + |
| Abs_int32 (g10 - g32) + |
| Abs_int32 (g12 - g34) + |
| Abs_int32 (g21 - g43) + |
| Abs_int32 (b02 - b24) + |
| Abs_int32 (b20 - b42); |
| |
| est2 = b20 + b24; |
| |
| grad2 = Abs_int32 (b20 - b24) + |
| Abs_int32 (g21 - g23) + |
| Abs_int32 (g10 - g12) + |
| Abs_int32 (g12 - g14) + |
| Abs_int32 (g30 - g32) + |
| Abs_int32 (g32 - g34) + |
| Abs_int32 (r11 - r13) + |
| Abs_int32 (r31 - r33); |
| |
| est3 = b04 + b40; |
| |
| grad3 = Abs_int32 (b04 - b40) + |
| Abs_int32 (r13 - r31) + |
| Abs_int32 (g03 - g21) + |
| Abs_int32 (g14 - g32) + |
| Abs_int32 (g12 - g30) + |
| Abs_int32 (g23 - g41) + |
| Abs_int32 (b02 - b20) + |
| Abs_int32 (b24 - b42); |
| |
| } |
| |
| uint32 minGrad = Min_uint32 (grad0, grad1); |
| |
| minGrad = Min_uint32 (minGrad, grad2); |
| minGrad = Min_uint32 (minGrad, grad3); |
| |
| uint32 limit = (minGrad * 3) >> 1; |
| |
| uint32 total = 0; |
| uint32 count = 0; |
| |
| if (grad0 <= limit) |
| { |
| total += est0; |
| count += 2; |
| } |
| |
| if (grad1 <= limit) |
| { |
| total += est1; |
| count += 2; |
| } |
| |
| if (grad2 <= limit) |
| { |
| total += est2; |
| count += 2; |
| } |
| |
| if (grad3 <= limit) |
| { |
| total += est3; |
| count += 2; |
| } |
| |
| uint32 estimate = (total + (count >> 1)) / count; |
| |
| p2 [2] = (uint16) estimate; |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_opcode_FixBadPixelsList::FixClusteredPixel (dng_pixel_buffer &buffer, |
| uint32 pointIndex, |
| const dng_rect &imageBounds) |
| { |
| |
| const uint32 kNumSets = 3; |
| const uint32 kSetSize = 4; |
| |
| static const int32 kOffset [kNumSets] [kSetSize] [2] = |
| { |
| { |
| { -1, 1 }, |
| { -1, -1 }, |
| { 1, -1 }, |
| { 1, 1 } |
| }, |
| { |
| { -2, 0 }, |
| { 2, 0 }, |
| { 0, -2 }, |
| { 0, 2 } |
| }, |
| { |
| { -2, -2 }, |
| { -2, 2 }, |
| { 2, -2 }, |
| { 2, 2 } |
| } |
| }; |
| |
| dng_point badPoint = fList->Point (pointIndex); |
| |
| bool isGreen = IsGreen (badPoint.v, badPoint.h); |
| |
| uint16 *p = buffer.DirtyPixel_uint16 (badPoint.v, badPoint.h, 0); |
| |
| for (uint32 set = 0; set < kNumSets; set++) |
| { |
| |
| if (!isGreen && (kOffset [set] [0] [0] & 1) == 1) |
| { |
| continue; |
| } |
| |
| uint32 total = 0; |
| uint32 count = 0; |
| |
| for (uint32 entry = 0; entry < kSetSize; entry++) |
| { |
| |
| dng_point offset (kOffset [set] [entry] [0], |
| kOffset [set] [entry] [1]); |
| |
| if (fList->IsPointValid (badPoint + offset, |
| imageBounds, |
| pointIndex)) |
| { |
| |
| total += p [offset.v * buffer.fRowStep + |
| offset.h * buffer.fColStep]; |
| |
| count++; |
| |
| } |
| |
| } |
| |
| if (count) |
| { |
| |
| uint32 estimate = (total + (count >> 1)) / count; |
| |
| p [0] = (uint16) estimate; |
| |
| return; |
| |
| } |
| |
| } |
| |
| // Unable to patch bad pixel. Leave pixel as is. |
| |
| #if qDNGValidate |
| |
| char s [256]; |
| |
| sprintf (s, "Unable to repair bad pixel, row %d, column %d", |
| (int) badPoint.v, |
| (int) badPoint.h); |
| |
| ReportWarning (s); |
| |
| #endif |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_opcode_FixBadPixelsList::FixSingleColumn (dng_pixel_buffer &buffer, |
| const dng_rect &badRect) |
| { |
| |
| int32 cs = buffer.fColStep; |
| |
| for (int32 row = badRect.t; row < badRect.b; row++) |
| { |
| |
| uint16 *p0 = buffer.DirtyPixel_uint16 (row - 4, badRect.l - 4, 0); |
| uint16 *p1 = buffer.DirtyPixel_uint16 (row - 3, badRect.l - 4, 0); |
| uint16 *p2 = buffer.DirtyPixel_uint16 (row - 2, badRect.l - 4, 0); |
| uint16 *p3 = buffer.DirtyPixel_uint16 (row - 1, badRect.l - 4, 0); |
| uint16 *p4 = buffer.DirtyPixel_uint16 (row , badRect.l - 4, 0); |
| uint16 *p5 = buffer.DirtyPixel_uint16 (row + 1, badRect.l - 4, 0); |
| uint16 *p6 = buffer.DirtyPixel_uint16 (row + 2, badRect.l - 4, 0); |
| uint16 *p7 = buffer.DirtyPixel_uint16 (row + 3, badRect.l - 4, 0); |
| uint16 *p8 = buffer.DirtyPixel_uint16 (row + 4, badRect.l - 4, 0); |
| |
| uint32 est0; |
| uint32 est1; |
| uint32 est2; |
| uint32 est3; |
| uint32 est4; |
| uint32 est5; |
| uint32 est6; |
| |
| uint32 grad0; |
| uint32 grad1; |
| uint32 grad2; |
| uint32 grad3; |
| uint32 grad4; |
| uint32 grad5; |
| uint32 grad6; |
| |
| uint32 lower = 0; |
| uint32 upper = 0x0FFFF; |
| |
| if (IsGreen (row, badRect.l)) // Green pixel |
| { |
| |
| // g00 b01 g02 b03 g04 b05 g06 b07 g08 |
| // r10 g11 r12 g13 r14 g15 r16 g17 r18 |
| // g20 b21 g22 b23 g24 b25 g26 b27 g28 |
| // r30 g31 r32 g33 r34 g35 r36 g37 r38 |
| // g40 b41 g42 b43 g44 b45 g46 b47 g48 |
| // r50 g51 r52 g53 r54 g55 r56 g57 r58 |
| // g60 b61 g62 b63 g64 b65 g66 b67 g68 |
| // r70 g71 r72 g73 r74 g75 r76 g77 r78 |
| // g80 b81 g82 b83 g84 b85 g86 b87 g88 |
| |
| int32 b03 = p0 [3 * cs]; |
| int32 b05 = p0 [5 * cs]; |
| |
| int32 g11 = p1 [1 * cs]; |
| int32 g13 = p1 [3 * cs]; |
| int32 g15 = p1 [5 * cs]; |
| int32 g17 = p1 [7 * cs]; |
| |
| int32 g22 = p2 [2 * cs]; |
| int32 b23 = p2 [3 * cs]; |
| int32 b25 = p2 [5 * cs]; |
| int32 g26 = p2 [6 * cs]; |
| |
| int32 r30 = p3 [0 * cs]; |
| int32 g31 = p3 [1 * cs]; |
| int32 r32 = p3 [2 * cs]; |
| int32 g33 = p3 [3 * cs]; |
| int32 g35 = p3 [5 * cs]; |
| int32 r36 = p3 [6 * cs]; |
| int32 g37 = p3 [7 * cs]; |
| int32 r38 = p3 [8 * cs]; |
| |
| int32 g40 = p4 [0 * cs]; |
| int32 g42 = p4 [2 * cs]; |
| int32 b43 = p4 [3 * cs]; |
| int32 b45 = p4 [5 * cs]; |
| int32 g46 = p4 [6 * cs]; |
| int32 g48 = p4 [8 * cs]; |
| |
| int32 r50 = p5 [0 * cs]; |
| int32 g51 = p5 [1 * cs]; |
| int32 r52 = p5 [2 * cs]; |
| int32 g53 = p5 [3 * cs]; |
| int32 g55 = p5 [5 * cs]; |
| int32 r56 = p5 [6 * cs]; |
| int32 g57 = p5 [7 * cs]; |
| int32 r58 = p5 [8 * cs]; |
| |
| int32 g62 = p6 [2 * cs]; |
| int32 b63 = p6 [3 * cs]; |
| int32 b65 = p6 [5 * cs]; |
| int32 g66 = p6 [6 * cs]; |
| |
| int32 g71 = p7 [1 * cs]; |
| int32 g73 = p7 [3 * cs]; |
| int32 g75 = p7 [5 * cs]; |
| int32 g77 = p7 [7 * cs]; |
| |
| int32 b83 = p8 [3 * cs]; |
| int32 b85 = p8 [5 * cs]; |
| |
| // In case there is some green split, make an estimate of |
| // of the local difference between the greens, and adjust |
| // the estimated green values for the difference |
| // between the two types of green pixels when estimating |
| // across green types. |
| |
| int32 split = ((g22 + g62 + g26 + g66) * 4 + |
| (g42 + g46 ) * 8 - |
| (g11 + g13 + g15 + g17) - |
| (g31 + g33 + g35 + g37) * 3 - |
| (g51 + g53 + g55 + g57) * 3 - |
| (g71 + g73 + g75 + g77) + 16) >> 5; |
| |
| est0 = g13 + g75 + split * 2; |
| |
| grad0 = Abs_int32 (g13 - g75) + |
| Abs_int32 (g15 - g46) + |
| Abs_int32 (g22 - g53) + |
| Abs_int32 (g35 - g66) + |
| Abs_int32 (g42 - g73) + |
| Abs_int32 (b03 - b65) + |
| Abs_int32 (b23 - b85); |
| |
| est1 = g33 + g55 + split * 2; |
| |
| grad1 = Abs_int32 (g33 - g55) + |
| Abs_int32 (g22 - g55) + |
| Abs_int32 (g33 - g66) + |
| Abs_int32 (g13 - g35) + |
| Abs_int32 (g53 - g75) + |
| Abs_int32 (b23 - b45) + |
| Abs_int32 (b43 - b65); |
| |
| est2 = g31 + g57 + split * 2; |
| |
| grad2 = Abs_int32 (g31 - g57) + |
| Abs_int32 (g33 - g46) + |
| Abs_int32 (g35 - g48) + |
| Abs_int32 (g40 - g53) + |
| Abs_int32 (g42 - g55) + |
| Abs_int32 (r30 - r56) + |
| Abs_int32 (r32 - r58); |
| |
| est3 = g42 + g46; |
| |
| grad3 = Abs_int32 (g42 - g46) * 2 + |
| Abs_int32 (g33 - g35) + |
| Abs_int32 (g53 - g55) + |
| Abs_int32 (b23 - b25) + |
| Abs_int32 (b43 - b45) + |
| Abs_int32 (b63 - b65); |
| |
| est4 = g37 + g51 + split * 2; |
| |
| grad4 = Abs_int32 (g37 - g51) + |
| Abs_int32 (g35 - g42) + |
| Abs_int32 (g33 - g40) + |
| Abs_int32 (g48 - g55) + |
| Abs_int32 (g46 - g53) + |
| Abs_int32 (r38 - r52) + |
| Abs_int32 (r36 - r50); |
| |
| est5 = g35 + g53 + split * 2; |
| |
| grad5 = Abs_int32 (g35 - g53) + |
| Abs_int32 (g26 - g53) + |
| Abs_int32 (g35 - g62) + |
| Abs_int32 (g15 - g33) + |
| Abs_int32 (g55 - g73) + |
| Abs_int32 (b25 - b43) + |
| Abs_int32 (b45 - b63); |
| |
| est6 = g15 + g73 + split * 2; |
| |
| grad6 = Abs_int32 (g15 - g73) + |
| Abs_int32 (g13 - g42) + |
| Abs_int32 (g26 - g55) + |
| Abs_int32 (g33 - g62) + |
| Abs_int32 (g46 - g75) + |
| Abs_int32 (b05 - b63) + |
| Abs_int32 (b25 - b83); |
| |
| lower = Min_uint32 (Min_uint32 (g33, g35), |
| Min_uint32 (g53, g55)); |
| |
| upper = Max_uint32 (Max_uint32 (g33, g35), |
| Max_uint32 (g53, g55)); |
| |
| lower = Pin_int32 (0, lower + split, 65535); |
| upper = Pin_int32 (0, upper + split, 65535); |
| |
| } |
| |
| else // Red/blue pixel |
| { |
| |
| // b00 g01 b02 g03 b04 g05 b06 g07 b08 |
| // g10 r11 g12 r13 g14 r15 g16 r17 g18 |
| // b20 g21 b22 g23 b24 g25 b26 g27 b28 |
| // g30 r31 g32 r33 g34 r35 g36 r37 g38 |
| // b40 g41 b42 g43 b44 g45 b46 g47 b48 |
| // g50 r51 g52 r53 g54 r55 g56 r57 g58 |
| // b60 g61 b62 g63 b64 g65 b66 g67 b68 |
| // g70 r71 g72 r73 g74 r75 g76 r77 g78 |
| // b80 g81 b82 g83 b84 g85 b86 g87 b88 |
| |
| int32 b02 = p0 [2 * cs]; |
| int32 g03 = p0 [3 * cs]; |
| int32 g05 = p0 [5 * cs]; |
| int32 b06 = p0 [6 * cs]; |
| |
| int32 r13 = p1 [3 * cs]; |
| int32 r15 = p1 [5 * cs]; |
| |
| int32 b20 = p2 [0 * cs]; |
| int32 b22 = p2 [2 * cs]; |
| int32 g23 = p2 [3 * cs]; |
| int32 g25 = p2 [5 * cs]; |
| int32 b26 = p2 [6 * cs]; |
| int32 b28 = p2 [8 * cs]; |
| |
| int32 r31 = p3 [1 * cs]; |
| int32 g32 = p3 [2 * cs]; |
| int32 r33 = p3 [3 * cs]; |
| int32 r35 = p3 [5 * cs]; |
| int32 g36 = p3 [6 * cs]; |
| int32 r37 = p3 [7 * cs]; |
| |
| int32 g41 = p4 [1 * cs]; |
| int32 b42 = p4 [2 * cs]; |
| int32 g43 = p4 [3 * cs]; |
| int32 g45 = p4 [5 * cs]; |
| int32 b46 = p4 [6 * cs]; |
| int32 g47 = p4 [7 * cs]; |
| |
| int32 r51 = p5 [1 * cs]; |
| int32 g52 = p5 [2 * cs]; |
| int32 r53 = p5 [3 * cs]; |
| int32 r55 = p5 [5 * cs]; |
| int32 g56 = p5 [6 * cs]; |
| int32 r57 = p5 [7 * cs]; |
| |
| int32 b60 = p6 [0 * cs]; |
| int32 b62 = p6 [2 * cs]; |
| int32 g63 = p6 [3 * cs]; |
| int32 g65 = p6 [5 * cs]; |
| int32 b66 = p6 [6 * cs]; |
| int32 b68 = p6 [8 * cs]; |
| |
| int32 r73 = p7 [3 * cs]; |
| int32 r75 = p7 [5 * cs]; |
| |
| int32 b82 = p8 [2 * cs]; |
| int32 g83 = p8 [3 * cs]; |
| int32 g85 = p8 [5 * cs]; |
| int32 b86 = p8 [6 * cs]; |
| |
| est0 = b02 + b86; |
| |
| grad0 = Abs_int32 (b02 - b86) + |
| Abs_int32 (r13 - r55) + |
| Abs_int32 (r33 - r75) + |
| Abs_int32 (g03 - g45) + |
| Abs_int32 (g23 - g65) + |
| Abs_int32 (g43 - g85); |
| |
| est1 = b22 + b66; |
| |
| grad1 = Abs_int32 (b22 - b66) + |
| Abs_int32 (r13 - r35) + |
| Abs_int32 (r33 - r55) + |
| Abs_int32 (r53 - r75) + |
| Abs_int32 (g23 - g45) + |
| Abs_int32 (g43 - g65); |
| |
| est2 = b20 + b68; |
| |
| grad2 = Abs_int32 (b20 - b68) + |
| Abs_int32 (r31 - r55) + |
| Abs_int32 (r33 - r57) + |
| Abs_int32 (g23 - g47) + |
| Abs_int32 (g32 - g56) + |
| Abs_int32 (g41 - g65); |
| |
| est3 = b42 + b46; |
| |
| grad3 = Abs_int32 (b42 - b46) + |
| Abs_int32 (r33 - r35) + |
| Abs_int32 (r53 - r55) + |
| Abs_int32 (g32 - g36) + |
| Abs_int32 (g43 - g43) + |
| Abs_int32 (g52 - g56); |
| |
| est4 = b28 + b60; |
| |
| grad4 = Abs_int32 (b28 - b60) + |
| Abs_int32 (r37 - r53) + |
| Abs_int32 (r35 - r51) + |
| Abs_int32 (g25 - g41) + |
| Abs_int32 (g36 - g52) + |
| Abs_int32 (g47 - g63); |
| |
| est5 = b26 + b62; |
| |
| grad5 = Abs_int32 (b26 - b62) + |
| Abs_int32 (r15 - r33) + |
| Abs_int32 (r35 - r53) + |
| Abs_int32 (r55 - r73) + |
| Abs_int32 (g25 - g43) + |
| Abs_int32 (g45 - g63); |
| |
| est6 = b06 + b82; |
| |
| grad6 = Abs_int32 (b06 - b82) + |
| Abs_int32 (r15 - r53) + |
| Abs_int32 (r35 - r73) + |
| Abs_int32 (g05 - g43) + |
| Abs_int32 (g25 - g63) + |
| Abs_int32 (g45 - g83); |
| |
| lower = Min_uint32 (b42, b46); |
| upper = Max_uint32 (b42, b46); |
| |
| } |
| |
| uint32 minGrad = Min_uint32 (grad0, grad1); |
| |
| minGrad = Min_uint32 (minGrad, grad2); |
| minGrad = Min_uint32 (minGrad, grad3); |
| minGrad = Min_uint32 (minGrad, grad4); |
| minGrad = Min_uint32 (minGrad, grad5); |
| minGrad = Min_uint32 (minGrad, grad6); |
| |
| uint32 limit = (minGrad * 3) >> 1; |
| |
| uint32 total = 0; |
| uint32 count = 0; |
| |
| if (grad0 <= limit) |
| { |
| total += est0; |
| count += 2; |
| } |
| |
| if (grad1 <= limit) |
| { |
| total += est1; |
| count += 2; |
| } |
| |
| if (grad2 <= limit) |
| { |
| total += est2; |
| count += 2; |
| } |
| |
| if (grad3 <= limit) |
| { |
| total += est3; |
| count += 2; |
| } |
| |
| if (grad4 <= limit) |
| { |
| total += est4; |
| count += 2; |
| } |
| |
| if (grad5 <= limit) |
| { |
| total += est5; |
| count += 2; |
| } |
| |
| if (grad6 <= limit) |
| { |
| total += est6; |
| count += 2; |
| } |
| |
| uint32 estimate = (total + (count >> 1)) / count; |
| |
| p4 [4] = (uint16) Pin_uint32 (lower, estimate, upper); |
| |
| } |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_opcode_FixBadPixelsList::FixSingleRow (dng_pixel_buffer &buffer, |
| const dng_rect &badRect) |
| { |
| |
| dng_pixel_buffer tBuffer = buffer; |
| |
| tBuffer.fArea = Transpose (buffer.fArea); |
| |
| tBuffer.fRowStep = buffer.fColStep; |
| tBuffer.fColStep = buffer.fRowStep; |
| |
| dng_rect tBadRect = Transpose (badRect); |
| |
| FixSingleColumn (tBuffer, tBadRect); |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_opcode_FixBadPixelsList::FixClusteredRect (dng_pixel_buffer &buffer, |
| const dng_rect &badRect, |
| const dng_rect &imageBounds) |
| { |
| |
| const uint32 kNumSets = 8; |
| const uint32 kSetSize = 8; |
| |
| static const int32 kOffset [kNumSets] [kSetSize] [2] = |
| { |
| { |
| { -1, 1 }, |
| { -1, -1 }, |
| { 1, -1 }, |
| { 1, 1 }, |
| { 0, 0 }, |
| { 0, 0 }, |
| { 0, 0 }, |
| { 0, 0 } |
| }, |
| { |
| { -2, 0 }, |
| { 2, 0 }, |
| { 0, -2 }, |
| { 0, 2 }, |
| { 0, 0 }, |
| { 0, 0 }, |
| { 0, 0 }, |
| { 0, 0 } |
| }, |
| { |
| { -2, -2 }, |
| { -2, 2 }, |
| { 2, -2 }, |
| { 2, 2 }, |
| { 0, 0 }, |
| { 0, 0 }, |
| { 0, 0 }, |
| { 0, 0 } |
| }, |
| { |
| { -1, -3 }, |
| { -3, -1 }, |
| { 1, -3 }, |
| { 3, -1 }, |
| { -1, 3 }, |
| { -3, 1 }, |
| { 1, 3 }, |
| { 3, 1 } |
| }, |
| { |
| { -4, 0 }, |
| { 4, 0 }, |
| { 0, -4 }, |
| { 0, 4 }, |
| { 0, 0 }, |
| { 0, 0 }, |
| { 0, 0 }, |
| { 0, 0 } |
| }, |
| { |
| { -3, -3 }, |
| { -3, 3 }, |
| { 3, -3 }, |
| { 3, 3 }, |
| { 0, 0 }, |
| { 0, 0 }, |
| { 0, 0 }, |
| { 0, 0 } |
| }, |
| { |
| { -2, -4 }, |
| { -4, -2 }, |
| { 2, -4 }, |
| { 4, -2 }, |
| { -2, 4 }, |
| { -4, 2 }, |
| { 2, 4 }, |
| { 4, 2 } |
| }, |
| { |
| { -4, -4 }, |
| { -4, 4 }, |
| { 4, -4 }, |
| { 4, 4 }, |
| { 0, 0 }, |
| { 0, 0 }, |
| { 0, 0 }, |
| { 0, 0 } |
| } |
| }; |
| |
| bool didFail = false; |
| |
| for (int32 row = badRect.t; row < badRect.b; row++) |
| { |
| |
| for (int32 col = badRect.l; col < badRect.r; col++) |
| { |
| |
| uint16 *p = buffer.DirtyPixel_uint16 (row, col, 0); |
| |
| bool isGreen = IsGreen (row, col); |
| |
| bool didFixPixel = false; |
| |
| for (uint32 set = 0; set < kNumSets && !didFixPixel; set++) |
| { |
| |
| if (!isGreen && (kOffset [set] [0] [0] & 1) == 1) |
| { |
| continue; |
| } |
| |
| uint32 total = 0; |
| uint32 count = 0; |
| |
| for (uint32 entry = 0; entry < kSetSize; entry++) |
| { |
| |
| dng_point offset (kOffset [set] [entry] [0], |
| kOffset [set] [entry] [1]); |
| |
| if (offset.v == 0 && |
| offset.h == 0) |
| { |
| break; |
| } |
| |
| if (fList->IsPointValid (dng_point (row, col) + offset, |
| imageBounds)) |
| { |
| |
| total += p [offset.v * buffer.fRowStep + |
| offset.h * buffer.fColStep]; |
| |
| count++; |
| |
| } |
| |
| } |
| |
| if (count) |
| { |
| |
| uint32 estimate = (total + (count >> 1)) / count; |
| |
| p [0] = (uint16) estimate; |
| |
| didFixPixel = true; |
| |
| } |
| |
| } |
| |
| if (!didFixPixel) |
| { |
| |
| didFail = true; |
| |
| } |
| |
| } |
| |
| } |
| |
| #if qDNGValidate |
| |
| if (didFail) |
| { |
| |
| ReportWarning ("Unable to repair bad rectangle"); |
| |
| } |
| |
| #endif |
| |
| } |
| |
| /*****************************************************************************/ |
| |
| void dng_opcode_FixBadPixelsList::ProcessArea (dng_negative & /* negative */, |
| uint32 /* threadIndex */, |
| dng_pixel_buffer &srcBuffer, |
| dng_pixel_buffer &dstBuffer, |
| const dng_rect &dstArea, |
| const dng_rect &imageBounds) |
| { |
| |
| uint32 pointCount = fList->PointCount (); |
| uint32 rectCount = fList->RectCount (); |
| |
| dng_rect fixArea = dstArea; |
| |
| if (rectCount) |
| { |
| fixArea.t -= kBadRectPadding; |
| fixArea.l -= kBadRectPadding; |
| fixArea.b += kBadRectPadding; |
| fixArea.r += kBadRectPadding; |
| } |
| |
| bool didFixPoint = false; |
| |
| if (pointCount) |
| { |
| |
| for (uint32 pointIndex = 0; pointIndex < pointCount; pointIndex++) |
| { |
| |
| dng_point badPoint = fList->Point (pointIndex); |
| |
| if (badPoint.v >= fixArea.t && |
| badPoint.h >= fixArea.l && |
| badPoint.v < fixArea.b && |
| badPoint.h < fixArea.r) |
| { |
| |
| bool isIsolated = fList->IsPointIsolated (pointIndex, |
| kBadPointPadding); |
| |
| if (isIsolated && |
| badPoint.v >= imageBounds.t + kBadPointPadding && |
| badPoint.h >= imageBounds.l + kBadPointPadding && |
| badPoint.v < imageBounds.b - kBadPointPadding && |
| badPoint.h < imageBounds.r - kBadPointPadding) |
| { |
| |
| FixIsolatedPixel (srcBuffer, |
| badPoint); |
| |
| } |
| |
| else |
| { |
| |
| FixClusteredPixel (srcBuffer, |
| pointIndex, |
| imageBounds); |
| |
| } |
| |
| didFixPoint = true; |
| |
| } |
| |
| } |
| |
| } |
| |
| if (rectCount) |
| { |
| |
| if (didFixPoint) |
| { |
| |
| srcBuffer.RepeatSubArea (imageBounds, |
| SrcRepeat ().v, |
| SrcRepeat ().h); |
| |
| } |
| |
| for (uint32 rectIndex = 0; rectIndex < rectCount; rectIndex++) |
| { |
| |
| dng_rect badRect = fList->Rect (rectIndex); |
| |
| dng_rect overlap = dstArea & badRect; |
| |
| if (overlap.NotEmpty ()) |
| { |
| |
| bool isIsolated = fList->IsRectIsolated (rectIndex, |
| kBadRectPadding); |
| |
| if (isIsolated && |
| badRect.r == badRect.l + 1 && |
| badRect.l >= imageBounds.l + SrcRepeat ().h && |
| badRect.r <= imageBounds.r - SrcRepeat ().v) |
| { |
| |
| FixSingleColumn (srcBuffer, |
| overlap); |
| |
| } |
| |
| else if (isIsolated && |
| badRect.b == badRect.t + 1 && |
| badRect.t >= imageBounds.t + SrcRepeat ().h && |
| badRect.b <= imageBounds.b - SrcRepeat ().v) |
| { |
| |
| FixSingleRow (srcBuffer, |
| overlap); |
| |
| } |
| |
| else |
| { |
| |
| FixClusteredRect (srcBuffer, |
| overlap, |
| imageBounds); |
| |
| } |
| |
| } |
| |
| } |
| |
| } |
| |
| dstBuffer.CopyArea (srcBuffer, |
| dstArea, |
| 0, |
| dstBuffer.fPlanes); |
| |
| } |
| |
| /*****************************************************************************/ |