Home | History | Annotate | Download | only in source
      1 /*****************************************************************************/
      2 // Copyright 2008 Adobe Systems Incorporated
      3 // All Rights Reserved.
      4 //
      5 // NOTICE:  Adobe permits you to use, modify, and distribute this file in
      6 // accordance with the terms of the Adobe license agreement accompanying it.
      7 /*****************************************************************************/
      8 
      9 /* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_bad_pixels.cpp#1 $ */
     10 /* $DateTime: 2012/05/30 13:28:51 $ */
     11 /* $Change: 832332 $ */
     12 /* $Author: tknoll $ */
     13 
     14 /*****************************************************************************/
     15 
     16 #include "dng_bad_pixels.h"
     17 
     18 #include "dng_filter_task.h"
     19 #include "dng_globals.h"
     20 #include "dng_host.h"
     21 #include "dng_image.h"
     22 #include "dng_negative.h"
     23 #include "dng_safe_arithmetic.h"
     24 
     25 #include <algorithm>
     26 
     27 /*****************************************************************************/
     28 
     29 dng_opcode_FixBadPixelsConstant::dng_opcode_FixBadPixelsConstant
     30 								 (uint32 constant,
     31 								  uint32 bayerPhase)
     32 
     33 	:	dng_filter_opcode (dngOpcode_FixBadPixelsConstant,
     34 						   dngVersion_1_3_0_0,
     35 						   0)
     36 
     37 	,	fConstant   (constant)
     38 	,	fBayerPhase (bayerPhase)
     39 
     40 	{
     41 
     42 	}
     43 
     44 /*****************************************************************************/
     45 
     46 dng_opcode_FixBadPixelsConstant::dng_opcode_FixBadPixelsConstant
     47 								 (dng_stream &stream)
     48 
     49 	:	dng_filter_opcode (dngOpcode_FixBadPixelsConstant,
     50 						   stream,
     51 						   "FixBadPixelsConstant")
     52 
     53 	,	fConstant   (0)
     54 	,	fBayerPhase (0)
     55 
     56 	{
     57 
     58 	if (stream.Get_uint32 () != 8)
     59 		{
     60 		ThrowBadFormat ();
     61 		}
     62 
     63 	fConstant   = stream.Get_uint32 ();
     64 	fBayerPhase = stream.Get_uint32 ();
     65 
     66 	#if qDNGValidate
     67 
     68 	if (gVerbose)
     69 		{
     70 
     71 		printf ("Constant: %u\n", (unsigned) fConstant);
     72 
     73 		printf ("Bayer Phase: %u\n", (unsigned) fBayerPhase);
     74 
     75 		}
     76 
     77 	#endif
     78 
     79 	}
     80 
     81 /*****************************************************************************/
     82 
     83 void dng_opcode_FixBadPixelsConstant::PutData (dng_stream &stream) const
     84 	{
     85 
     86 	stream.Put_uint32 (8);
     87 
     88 	stream.Put_uint32 (fConstant  );
     89 	stream.Put_uint32 (fBayerPhase);
     90 
     91 	}
     92 
     93 /*****************************************************************************/
     94 
     95 dng_point dng_opcode_FixBadPixelsConstant::SrcRepeat ()
     96 	{
     97 
     98 	return dng_point (2, 2);
     99 
    100 	}
    101 
    102 /*****************************************************************************/
    103 
    104 dng_rect dng_opcode_FixBadPixelsConstant::SrcArea (const dng_rect &dstArea,
    105 												   const dng_rect & /* imageBounds */)
    106 	{
    107 
    108 	dng_rect srcArea = dstArea;
    109 
    110 	srcArea.t -= 2;
    111 	srcArea.l -= 2;
    112 
    113 	srcArea.b += 2;
    114 	srcArea.r += 2;
    115 
    116 	return srcArea;
    117 
    118 	}
    119 
    120 /*****************************************************************************/
    121 
    122 void dng_opcode_FixBadPixelsConstant::Prepare (dng_negative & /* negative */,
    123 											   uint32 /* threadCount */,
    124 											   const dng_point & /* tileSize */,
    125 											   const dng_rect & /* imageBounds */,
    126 											   uint32 imagePlanes,
    127 											   uint32 bufferPixelType,
    128 											   dng_memory_allocator & /* allocator */)
    129 	{
    130 
    131 	// This opcode is restricted to single channel images.
    132 
    133 	if (imagePlanes != 1)
    134 		{
    135 
    136 		ThrowBadFormat ();
    137 
    138 		}
    139 
    140 	// This opcode is restricted to 16-bit images.
    141 
    142 	if (bufferPixelType != ttShort)
    143 		{
    144 
    145 		ThrowBadFormat ();
    146 
    147 		}
    148 
    149 	}
    150 
    151 /*****************************************************************************/
    152 
    153 void dng_opcode_FixBadPixelsConstant::ProcessArea (dng_negative & /* negative */,
    154 												   uint32 /* threadIndex */,
    155 												   dng_pixel_buffer &srcBuffer,
    156 												   dng_pixel_buffer &dstBuffer,
    157 												   const dng_rect &dstArea,
    158 												   const dng_rect & /* imageBounds */)
    159 	{
    160 
    161 	dstBuffer.CopyArea (srcBuffer,
    162 						dstArea,
    163 						0,
    164 						dstBuffer.fPlanes);
    165 
    166 	uint16 badPixel = (uint16) fConstant;
    167 
    168 	for (int32 dstRow = dstArea.t; dstRow < dstArea.b; dstRow++)
    169 		{
    170 
    171 		const uint16 *sPtr = srcBuffer.ConstPixel_uint16 (dstRow, dstArea.l, 0);
    172 			  uint16 *dPtr = dstBuffer.DirtyPixel_uint16 (dstRow, dstArea.l, 0);
    173 
    174 		for (int32 dstCol = dstArea.l; dstCol < dstArea.r; dstCol++)
    175 			{
    176 
    177 			if (*sPtr == badPixel)
    178 				{
    179 
    180 				uint32 count = 0;
    181 				uint32 total = 0;
    182 
    183 				uint16 value;
    184 
    185 				if (IsGreen (dstRow, dstCol))	// Green pixel
    186 					{
    187 
    188 					value = sPtr [-srcBuffer.fRowStep - 1];
    189 
    190 					if (value != badPixel)
    191 						{
    192 						count += 1;
    193 						total += value;
    194 						}
    195 
    196 					value = sPtr [-srcBuffer.fRowStep + 1];
    197 
    198 					if (value != badPixel)
    199 						{
    200 						count += 1;
    201 						total += value;
    202 						}
    203 
    204 					value = sPtr [srcBuffer.fRowStep - 1];
    205 
    206 					if (value != badPixel)
    207 						{
    208 						count += 1;
    209 						total += value;
    210 						}
    211 
    212 					value = sPtr [srcBuffer.fRowStep + 1];
    213 
    214 					if (value != badPixel)
    215 						{
    216 						count += 1;
    217 						total += value;
    218 						}
    219 
    220 					}
    221 
    222 				else	// Red/blue pixel.
    223 					{
    224 
    225 					value = sPtr [-srcBuffer.fRowStep * 2];
    226 
    227 					if (value != badPixel)
    228 						{
    229 						count += 1;
    230 						total += value;
    231 						}
    232 
    233 					value = sPtr [srcBuffer.fRowStep * 2];
    234 
    235 					if (value != badPixel)
    236 						{
    237 						count += 1;
    238 						total += value;
    239 						}
    240 
    241 					value = sPtr [-2];
    242 
    243 					if (value != badPixel)
    244 						{
    245 						count += 1;
    246 						total += value;
    247 						}
    248 
    249 					value = sPtr [2];
    250 
    251 					if (value != badPixel)
    252 						{
    253 						count += 1;
    254 						total += value;
    255 						}
    256 
    257 					}
    258 
    259 				if (count == 4)		// Most common case.
    260 					{
    261 
    262 					*dPtr = (uint16) ((total + 2) >> 2);
    263 
    264 					}
    265 
    266 				else if (count > 0)
    267 					{
    268 
    269 					*dPtr = (uint16) ((total + (count >> 1)) / count);
    270 
    271 					}
    272 
    273 				}
    274 
    275 			sPtr++;
    276 			dPtr++;
    277 
    278 			}
    279 
    280 		}
    281 
    282 	}
    283 
    284 /*****************************************************************************/
    285 
    286 dng_bad_pixel_list::dng_bad_pixel_list ()
    287 
    288 	:	fBadPoints ()
    289 	,	fBadRects  ()
    290 
    291 	{
    292 
    293 	}
    294 
    295 /*****************************************************************************/
    296 
    297 void dng_bad_pixel_list::AddPoint (const dng_point &pt)
    298 	{
    299 
    300 	fBadPoints.push_back (pt);
    301 
    302 	}
    303 
    304 /*****************************************************************************/
    305 
    306 void dng_bad_pixel_list::AddRect (const dng_rect &r)
    307 	{
    308 
    309 	fBadRects.push_back (r);
    310 
    311 	}
    312 
    313 /*****************************************************************************/
    314 
    315 static bool SortBadPoints (const dng_point &a,
    316 						   const dng_point &b)
    317 	{
    318 
    319 	if (a.v < b.v)
    320 		return true;
    321 
    322 	if (a.v > b.v)
    323 		return false;
    324 
    325 	return a.h < b.h;
    326 
    327 	}
    328 
    329 /*****************************************************************************/
    330 
    331 static bool SortBadRects (const dng_rect &a,
    332 						  const dng_rect &b)
    333 	{
    334 
    335 	if (a.t < b.t)
    336 		return true;
    337 
    338 	if (a.t > b.t)
    339 		return false;
    340 
    341 	if (a.l < b.l)
    342 		return true;
    343 
    344 	if (a.l > b.l)
    345 		return false;
    346 
    347 	if (a.b < b.b)
    348 		return true;
    349 
    350 	if (a.b > b.b)
    351 		return false;
    352 
    353 	return a.r < b.r;
    354 
    355 	}
    356 
    357 /*****************************************************************************/
    358 
    359 void dng_bad_pixel_list::Sort ()
    360 	{
    361 
    362 	if (PointCount () > 1)
    363 		{
    364 
    365 		std::sort (fBadPoints.begin (),
    366 				   fBadPoints.end   (),
    367 				   SortBadPoints);
    368 
    369 		}
    370 
    371 	if (RectCount () > 1)
    372 		{
    373 
    374 		std::sort (fBadRects.begin (),
    375 				   fBadRects.end   (),
    376 				   SortBadRects);
    377 
    378 		}
    379 
    380 	}
    381 
    382 /*****************************************************************************/
    383 
    384 bool dng_bad_pixel_list::IsPointIsolated (uint32 index,
    385 										  uint32 radius) const
    386 	{
    387 
    388 	dng_point pt = Point (index);
    389 
    390 	// Search backward through bad point list.
    391 
    392 	for (int32 j = index - 1; j >= 0; j--)
    393 		{
    394 
    395 		const dng_point &pt2 = Point (j);
    396 
    397 		if (pt2.v < pt.v - (int32) radius)
    398 			{
    399 			break;
    400 			}
    401 
    402 		if (Abs_int32 (pt2.h - pt.h) <= radius)
    403 			{
    404 			return false;
    405 			}
    406 
    407 		}
    408 
    409 	// Search forward through bad point list.
    410 
    411 	for (uint32 k = index + 1; k < PointCount (); k++)
    412 		{
    413 
    414 		const dng_point &pt2 = Point (k);
    415 
    416 		if (pt2.v > pt.v + (int32) radius)
    417 			{
    418 			break;
    419 			}
    420 
    421 		if (Abs_int32 (pt2.h - pt.h) <= radius)
    422 			{
    423 			return false;
    424 			}
    425 
    426 		}
    427 
    428 	// Search through bad rectangle list.
    429 
    430 	dng_rect testRect (pt.v - radius,
    431 					   pt.h - radius,
    432 					   pt.v + radius + 1,
    433 					   pt.h + radius + 1);
    434 
    435 	for (uint32 n = 0; n < RectCount (); n++)
    436 		{
    437 
    438 		if ((testRect & Rect (n)).NotEmpty ())
    439 			{
    440 			return false;
    441 			}
    442 
    443 		}
    444 
    445 	// Did not find point anywhere, so bad pixel is isolated.
    446 
    447 	return true;
    448 
    449 	}
    450 
    451 /*****************************************************************************/
    452 
    453 bool dng_bad_pixel_list::IsRectIsolated (uint32 index,
    454 										 uint32 radius) const
    455 	{
    456 
    457 	dng_rect testRect = Rect (index);
    458 
    459 	testRect.t -= radius;
    460 	testRect.l -= radius;
    461 	testRect.b += radius;
    462 	testRect.r += radius;
    463 
    464 	for (uint32 n = 0; n < RectCount (); n++)
    465 		{
    466 
    467 		if (n != index)
    468 			{
    469 
    470 			if ((testRect & Rect (n)).NotEmpty ())
    471 				{
    472 				return false;
    473 				}
    474 
    475 			}
    476 
    477 		}
    478 
    479 	return true;
    480 
    481 	}
    482 
    483 /*****************************************************************************/
    484 
    485 bool dng_bad_pixel_list::IsPointValid (const dng_point &pt,
    486 									   const dng_rect &imageBounds,
    487 									   uint32 index) const
    488 	{
    489 
    490 	// The point must be in the image bounds to be valid.
    491 
    492 	if (pt.v <  imageBounds.t ||
    493 		pt.h <  imageBounds.l ||
    494 		pt.v >= imageBounds.b ||
    495 		pt.h >= imageBounds.r)
    496 		{
    497 		return false;
    498 		}
    499 
    500 	// Only search the bad point list if we have a starting search index.
    501 
    502 	if (index != kNoIndex)
    503 		{
    504 
    505 		// Search backward through bad point list.
    506 
    507 		for (int32 j = index - 1; j >= 0; j--)
    508 			{
    509 
    510 			const dng_point &pt2 = Point (j);
    511 
    512 			if (pt2.v < pt.v)
    513 				{
    514 				break;
    515 				}
    516 
    517 			if (pt2 == pt)
    518 				{
    519 				return false;
    520 				}
    521 
    522 			}
    523 
    524 		// Search forward through bad point list.
    525 
    526 		for (uint32 k = index + 1; k < PointCount (); k++)
    527 			{
    528 
    529 			const dng_point &pt2 = Point (k);
    530 
    531 			if (pt2.v > pt.v)
    532 				{
    533 				break;
    534 				}
    535 
    536 			if (pt2 == pt)
    537 				{
    538 				return false;
    539 				}
    540 
    541 			}
    542 
    543 		}
    544 
    545 	// Search through bad rectangle list.
    546 
    547 	for (uint32 n = 0; n < RectCount (); n++)
    548 		{
    549 
    550 		const dng_rect &r = Rect (n);
    551 
    552 		if (pt.v >= r.t &&
    553 			pt.h >= r.l &&
    554 			pt.v <  r.b &&
    555 			pt.h <  r.r)
    556 			{
    557 			return false;
    558 			}
    559 
    560 		}
    561 
    562 	// Did not find point anywhere, so pixel is valid.
    563 
    564 	return true;
    565 
    566 	}
    567 
    568 /*****************************************************************************/
    569 
    570 dng_opcode_FixBadPixelsList::dng_opcode_FixBadPixelsList
    571 							 (AutoPtr<dng_bad_pixel_list> &list,
    572 							  uint32 bayerPhase)
    573 
    574 
    575 	:	dng_filter_opcode (dngOpcode_FixBadPixelsList,
    576 						   dngVersion_1_3_0_0,
    577 						   0)
    578 
    579 	,	fList ()
    580 
    581 	,	fBayerPhase (bayerPhase)
    582 
    583 	{
    584 
    585 	fList.Reset (list.Release ());
    586 
    587 	fList->Sort ();
    588 
    589 	}
    590 
    591 /*****************************************************************************/
    592 
    593 dng_opcode_FixBadPixelsList::dng_opcode_FixBadPixelsList (dng_stream &stream)
    594 
    595 	:	dng_filter_opcode (dngOpcode_FixBadPixelsList,
    596 						   stream,
    597 						   "FixBadPixelsList")
    598 
    599 	,	fList ()
    600 
    601 	,	fBayerPhase (0)
    602 
    603 	{
    604 
    605 	uint32 size = stream.Get_uint32 ();
    606 
    607 	fBayerPhase = stream.Get_uint32 ();
    608 
    609 	uint32 pCount = stream.Get_uint32 ();
    610 	uint32 rCount = stream.Get_uint32 ();
    611 	uint32 expectedSize =
    612 	SafeUint32Add(12, SafeUint32Add(SafeUint32Mult(pCount, 8), SafeUint32Mult(rCount, 16)));
    613 	if (size != expectedSize)
    614 		{
    615 		ThrowBadFormat ();
    616 		}
    617 
    618 	fList.Reset (new dng_bad_pixel_list);
    619 
    620 	uint32 index;
    621 
    622 	for (index = 0; index < pCount; index++)
    623 		{
    624 
    625 		dng_point pt;
    626 
    627 		pt.v = stream.Get_int32 ();
    628 		pt.h = stream.Get_int32 ();
    629 
    630 		fList->AddPoint (pt);
    631 
    632 		}
    633 
    634 	for (index = 0; index < rCount; index++)
    635 		{
    636 
    637 		dng_rect r;
    638 
    639 		r.t = stream.Get_int32 ();
    640 		r.l = stream.Get_int32 ();
    641 		r.b = stream.Get_int32 ();
    642 		r.r = stream.Get_int32 ();
    643 
    644 		fList->AddRect (r);
    645 
    646 		}
    647 
    648 	fList->Sort ();
    649 
    650 	#if qDNGValidate
    651 
    652 	if (gVerbose)
    653 		{
    654 
    655 		printf ("Bayer Phase: %u\n", (unsigned) fBayerPhase);
    656 
    657 		printf ("Bad Pixels: %u\n", (unsigned) pCount);
    658 
    659 		for (index = 0; index < pCount && index < gDumpLineLimit; index++)
    660 			{
    661 			printf ("    Pixel [%u]: v=%d, h=%d\n",
    662 					(unsigned) index,
    663 					(int) fList->Point (index).v,
    664 					(int) fList->Point (index).h);
    665 			}
    666 
    667 		if (pCount > gDumpLineLimit)
    668 			{
    669 			printf ("    ... %u bad pixels skipped\n", (unsigned) (pCount - gDumpLineLimit));
    670 			}
    671 
    672 		printf ("Bad Rects: %u\n", (unsigned) rCount);
    673 
    674 		for (index = 0; index < rCount && index < gDumpLineLimit; index++)
    675 			{
    676 			printf ("    Rect [%u]: t=%d, l=%d, b=%d, r=%d\n",
    677 					(unsigned) index,
    678 					(int) fList->Rect (index).t,
    679 					(int) fList->Rect (index).l,
    680 					(int) fList->Rect (index).b,
    681 					(int) fList->Rect (index).r);
    682 			}
    683 
    684 		if (rCount > gDumpLineLimit)
    685 			{
    686 			printf ("    ... %u bad rects skipped\n", (unsigned) (rCount - gDumpLineLimit));
    687 			}
    688 
    689 		}
    690 
    691 	#endif
    692 
    693 	}
    694 
    695 /*****************************************************************************/
    696 
    697 void dng_opcode_FixBadPixelsList::PutData (dng_stream &stream) const
    698 	{
    699 
    700 	uint32 pCount = fList->PointCount ();
    701 	uint32 rCount = fList->RectCount  ();
    702 
    703 	stream.Put_uint32 (12 + pCount * 8 + rCount * 16);
    704 
    705 	stream.Put_uint32 (fBayerPhase);
    706 
    707 	stream.Put_uint32 (pCount);
    708 	stream.Put_uint32 (rCount);
    709 
    710 	uint32 index;
    711 
    712 	for (index = 0; index < pCount; index++)
    713 		{
    714 
    715 		const dng_point &pt (fList->Point (index));
    716 
    717 		stream.Put_int32 (pt.v);
    718 		stream.Put_int32 (pt.h);
    719 
    720 		}
    721 
    722 	for (index = 0; index < rCount; index++)
    723 		{
    724 
    725 		const dng_rect &r (fList->Rect (index));
    726 
    727 		stream.Put_int32 (r.t);
    728 		stream.Put_int32 (r.l);
    729 		stream.Put_int32 (r.b);
    730 		stream.Put_int32 (r.r);
    731 
    732 		}
    733 
    734 	}
    735 
    736 /*****************************************************************************/
    737 
    738 dng_rect dng_opcode_FixBadPixelsList::SrcArea (const dng_rect &dstArea,
    739 											   const dng_rect & /* imageBounds */)
    740 	{
    741 
    742 	int32 padding = 0;
    743 
    744 	if (fList->PointCount ())
    745 		{
    746 		padding += kBadPointPadding;
    747 		}
    748 
    749 	if (fList->RectCount ())
    750 		{
    751 		padding += kBadRectPadding;
    752 		}
    753 
    754 	dng_rect srcArea = dstArea;
    755 
    756 	srcArea.t -= padding;
    757 	srcArea.l -= padding;
    758 
    759 	srcArea.b += padding;
    760 	srcArea.r += padding;
    761 
    762 	return srcArea;
    763 
    764 	}
    765 
    766 /*****************************************************************************/
    767 
    768 dng_point dng_opcode_FixBadPixelsList::SrcRepeat ()
    769 	{
    770 
    771 	return dng_point (2, 2);
    772 
    773 	}
    774 
    775 /*****************************************************************************/
    776 
    777 void dng_opcode_FixBadPixelsList::Prepare (dng_negative & /* negative */,
    778 										   uint32 /* threadCount */,
    779 										   const dng_point & /* tileSize */,
    780 										   const dng_rect & /* imageBounds */,
    781 										   uint32 imagePlanes,
    782 										   uint32 bufferPixelType,
    783 										   dng_memory_allocator & /* allocator */)
    784 	{
    785 
    786 	// This opcode is restricted to single channel images.
    787 
    788 	if (imagePlanes != 1)
    789 		{
    790 
    791 		ThrowBadFormat ();
    792 
    793 		}
    794 
    795 	// This opcode is restricted to 16-bit images.
    796 
    797 	if (bufferPixelType != ttShort)
    798 		{
    799 
    800 		ThrowBadFormat ();
    801 
    802 		}
    803 
    804 	}
    805 
    806 /*****************************************************************************/
    807 
    808 void dng_opcode_FixBadPixelsList::FixIsolatedPixel (dng_pixel_buffer &buffer,
    809 													dng_point &badPoint)
    810 	{
    811 
    812 	uint16 *p0 = buffer.DirtyPixel_uint16 (badPoint.v - 2, badPoint.h - 2, 0);
    813 	uint16 *p1 = buffer.DirtyPixel_uint16 (badPoint.v - 1, badPoint.h - 2, 0);
    814 	uint16 *p2 = buffer.DirtyPixel_uint16 (badPoint.v    , badPoint.h - 2, 0);
    815 	uint16 *p3 = buffer.DirtyPixel_uint16 (badPoint.v + 1, badPoint.h - 2, 0);
    816 	uint16 *p4 = buffer.DirtyPixel_uint16 (badPoint.v + 2, badPoint.h - 2, 0);
    817 
    818 	uint32 est0;
    819 	uint32 est1;
    820 	uint32 est2;
    821 	uint32 est3;
    822 
    823 	uint32 grad0;
    824 	uint32 grad1;
    825 	uint32 grad2;
    826 	uint32 grad3;
    827 
    828 	if (IsGreen (badPoint.v, badPoint.h))		// Green pixel
    829 		{
    830 
    831 		// g00 b01 g02 b03 g04
    832 		// r10 g11 r12 g13 r14
    833 		// g20 b21 g22 b23 g24
    834 		// r30 g31 r32 g33 r34
    835 		// g40 b41 g42 b43 g44
    836 
    837 		int32 b01 = p0 [1];
    838 		int32 g02 = p0 [2];
    839 		int32 b03 = p0 [3];
    840 
    841 		int32 r10 = p1 [0];
    842 		int32 g11 = p1 [1];
    843 		int32 r12 = p1 [2];
    844 		int32 g13 = p1 [3];
    845 		int32 r14 = p1 [4];
    846 
    847 		int32 g20 = p2 [0];
    848 		int32 b21 = p2 [1];
    849 		int32 b23 = p2 [3];
    850 		int32 g24 = p2 [4];
    851 
    852 		int32 r30 = p3 [0];
    853 		int32 g31 = p3 [1];
    854 		int32 r32 = p3 [2];
    855 		int32 g33 = p3 [3];
    856 		int32 r34 = p3 [4];
    857 
    858 		int32 b41 = p4 [1];
    859 		int32 g42 = p4 [2];
    860 		int32 b43 = p4 [3];
    861 
    862 		est0 = g02 + g42;
    863 
    864 		grad0 = Abs_int32 (g02 - g42) +
    865 				Abs_int32 (g11 - g31) +
    866 				Abs_int32 (g13 - g33) +
    867 				Abs_int32 (b01 - b21) +
    868 				Abs_int32 (b03 - b23) +
    869 				Abs_int32 (b21 - b41) +
    870 				Abs_int32 (b23 - b43);
    871 
    872 		est1 = g11 + g33;
    873 
    874 		grad1 = Abs_int32 (g11 - g33) +
    875 				Abs_int32 (g02 - g24) +
    876 				Abs_int32 (g20 - g42) +
    877 				Abs_int32 (b01 - b23) +
    878 				Abs_int32 (r10 - r32) +
    879 				Abs_int32 (r12 - r34) +
    880 				Abs_int32 (b21 - b43);
    881 
    882 		est2 = g20 + g24;
    883 
    884 		grad2 = Abs_int32 (g20 - g24) +
    885 				Abs_int32 (g11 - g13) +
    886 				Abs_int32 (g31 - g33) +
    887 				Abs_int32 (r10 - r12) +
    888 				Abs_int32 (r30 - r32) +
    889 				Abs_int32 (r12 - r14) +
    890 				Abs_int32 (r32 - r34);
    891 
    892 		est3 = g13 + g31;
    893 
    894 		grad3 = Abs_int32 (g13 - g31) +
    895 				Abs_int32 (g02 - g20) +
    896 				Abs_int32 (g24 - g42) +
    897 				Abs_int32 (b03 - b21) +
    898 				Abs_int32 (r14 - r32) +
    899 				Abs_int32 (r12 - r30) +
    900 				Abs_int32 (b23 - b41);
    901 
    902 		}
    903 
    904 	else		// Red/blue pixel
    905 		{
    906 
    907 		// b00 g01 b02 g03 b04
    908 		// g10 r11 g12 r13 g14
    909 		// b20 g21 b22 g23 b24
    910 		// g30 r31 g32 r33 g34
    911 		// b40 g41 b42 g43 b44
    912 
    913 		int32 b00 = p0 [0];
    914 		int32 g01 = p0 [1];
    915 		int32 b02 = p0 [2];
    916 		int32 g03 = p0 [3];
    917 		int32 b04 = p0 [4];
    918 
    919 		int32 g10 = p1 [0];
    920 		int32 r11 = p1 [1];
    921 		int32 g12 = p1 [2];
    922 		int32 r13 = p1 [3];
    923 		int32 g14 = p1 [4];
    924 
    925 		int32 b20 = p2 [0];
    926 		int32 g21 = p2 [1];
    927 		int32 g23 = p2 [3];
    928 		int32 b24 = p2 [4];
    929 
    930 		int32 g30 = p3 [0];
    931 		int32 r31 = p3 [1];
    932 		int32 g32 = p3 [2];
    933 		int32 r33 = p3 [3];
    934 		int32 g34 = p3 [4];
    935 
    936 		int32 b40 = p4 [0];
    937 		int32 g41 = p4 [1];
    938 		int32 b42 = p4 [2];
    939 		int32 g43 = p4 [3];
    940 		int32 b44 = p4 [4];
    941 
    942 		est0 = b02 + b42;
    943 
    944 		grad0 = Abs_int32 (b02 - b42) +
    945 				Abs_int32 (g12 - g32) +
    946 				Abs_int32 (g01 - g21) +
    947 				Abs_int32 (g21 - g41) +
    948 				Abs_int32 (g03 - g23) +
    949 				Abs_int32 (g23 - g43) +
    950 				Abs_int32 (r11 - r31) +
    951 				Abs_int32 (r13 - r33);
    952 
    953 		est1 = b00 + b44;
    954 
    955 		grad1 = Abs_int32 (b00 - b44) +
    956 				Abs_int32 (r11 - r33) +
    957 				Abs_int32 (g01 - g23) +
    958 				Abs_int32 (g10 - g32) +
    959 				Abs_int32 (g12 - g34) +
    960 				Abs_int32 (g21 - g43) +
    961 				Abs_int32 (b02 - b24) +
    962 				Abs_int32 (b20 - b42);
    963 
    964 		est2 = b20 + b24;
    965 
    966 		grad2 = Abs_int32 (b20 - b24) +
    967 				Abs_int32 (g21 - g23) +
    968 				Abs_int32 (g10 - g12) +
    969 				Abs_int32 (g12 - g14) +
    970 				Abs_int32 (g30 - g32) +
    971 				Abs_int32 (g32 - g34) +
    972 				Abs_int32 (r11 - r13) +
    973 				Abs_int32 (r31 - r33);
    974 
    975 		est3 = b04 + b40;
    976 
    977 		grad3 = Abs_int32 (b04 - b40) +
    978 				Abs_int32 (r13 - r31) +
    979 				Abs_int32 (g03 - g21) +
    980 				Abs_int32 (g14 - g32) +
    981 				Abs_int32 (g12 - g30) +
    982 				Abs_int32 (g23 - g41) +
    983 				Abs_int32 (b02 - b20) +
    984 				Abs_int32 (b24 - b42);
    985 
    986 		}
    987 
    988 	uint32 minGrad = Min_uint32 (grad0, grad1);
    989 
    990 	minGrad = Min_uint32 (minGrad, grad2);
    991 	minGrad = Min_uint32 (minGrad, grad3);
    992 
    993 	uint32 limit = (minGrad * 3) >> 1;
    994 
    995 	uint32 total = 0;
    996 	uint32 count = 0;
    997 
    998 	if (grad0 <= limit)
    999 		{
   1000 		total += est0;
   1001 		count += 2;
   1002 		}
   1003 
   1004 	if (grad1 <= limit)
   1005 		{
   1006 		total += est1;
   1007 		count += 2;
   1008 		}
   1009 
   1010 	if (grad2 <= limit)
   1011 		{
   1012 		total += est2;
   1013 		count += 2;
   1014 		}
   1015 
   1016 	if (grad3 <= limit)
   1017 		{
   1018 		total += est3;
   1019 		count += 2;
   1020 		}
   1021 
   1022 	uint32 estimate = (total + (count >> 1)) / count;
   1023 
   1024 	p2 [2] = (uint16) estimate;
   1025 
   1026 	}
   1027 
   1028 /*****************************************************************************/
   1029 
   1030 void dng_opcode_FixBadPixelsList::FixClusteredPixel (dng_pixel_buffer &buffer,
   1031 													 uint32 pointIndex,
   1032 													 const dng_rect &imageBounds)
   1033 	{
   1034 
   1035 	const uint32 kNumSets = 3;
   1036 	const uint32 kSetSize = 4;
   1037 
   1038 	static const int32 kOffset [kNumSets] [kSetSize] [2] =
   1039 		{
   1040 			{
   1041 				{ -1,  1 },
   1042 				{ -1, -1 },
   1043 				{  1, -1 },
   1044 				{  1,  1 }
   1045 			},
   1046 			{
   1047 				{ -2,  0 },
   1048 				{  2,  0 },
   1049 				{  0, -2 },
   1050 				{  0,  2 }
   1051 			},
   1052 			{
   1053 				{ -2, -2 },
   1054 				{ -2,  2 },
   1055 				{  2, -2 },
   1056 				{  2,  2 }
   1057 			}
   1058 		};
   1059 
   1060 	dng_point badPoint = fList->Point (pointIndex);
   1061 
   1062 	bool isGreen = IsGreen (badPoint.v, badPoint.h);
   1063 
   1064 	uint16 *p = buffer.DirtyPixel_uint16 (badPoint.v, badPoint.h, 0);
   1065 
   1066 	for (uint32 set = 0; set < kNumSets; set++)
   1067 		{
   1068 
   1069 		if (!isGreen && (kOffset [set] [0] [0] & 1) == 1)
   1070 			{
   1071 			continue;
   1072 			}
   1073 
   1074 		uint32 total = 0;
   1075 		uint32 count = 0;
   1076 
   1077 		for (uint32 entry = 0; entry < kSetSize; entry++)
   1078 			{
   1079 
   1080 			dng_point offset (kOffset [set] [entry] [0],
   1081 							  kOffset [set] [entry] [1]);
   1082 
   1083 			if (fList->IsPointValid (badPoint + offset,
   1084 									 imageBounds,
   1085 									 pointIndex))
   1086 				{
   1087 
   1088 				total += p [offset.v * buffer.fRowStep +
   1089 							offset.h * buffer.fColStep];
   1090 
   1091 				count++;
   1092 
   1093 				}
   1094 
   1095 			}
   1096 
   1097 		if (count)
   1098 			{
   1099 
   1100 			uint32 estimate = (total + (count >> 1)) / count;
   1101 
   1102 			p [0] = (uint16) estimate;
   1103 
   1104 			return;
   1105 
   1106 			}
   1107 
   1108 		}
   1109 
   1110 	// Unable to patch bad pixel.  Leave pixel as is.
   1111 
   1112 	#if qDNGValidate
   1113 
   1114 	char s [256];
   1115 
   1116 	sprintf (s, "Unable to repair bad pixel, row %d, column %d",
   1117 			 (int) badPoint.v,
   1118 			 (int) badPoint.h);
   1119 
   1120 	ReportWarning (s);
   1121 
   1122 	#endif
   1123 
   1124 	}
   1125 
   1126 /*****************************************************************************/
   1127 
   1128 void dng_opcode_FixBadPixelsList::FixSingleColumn (dng_pixel_buffer &buffer,
   1129 												   const dng_rect &badRect)
   1130 	{
   1131 
   1132 	int32 cs = buffer.fColStep;
   1133 
   1134 	for (int32 row = badRect.t; row < badRect.b; row++)
   1135 		{
   1136 
   1137 		uint16 *p0 = buffer.DirtyPixel_uint16 (row - 4, badRect.l - 4, 0);
   1138 		uint16 *p1 = buffer.DirtyPixel_uint16 (row - 3, badRect.l - 4, 0);
   1139 		uint16 *p2 = buffer.DirtyPixel_uint16 (row - 2, badRect.l - 4, 0);
   1140 		uint16 *p3 = buffer.DirtyPixel_uint16 (row - 1, badRect.l - 4, 0);
   1141 		uint16 *p4 = buffer.DirtyPixel_uint16 (row    , badRect.l - 4, 0);
   1142 		uint16 *p5 = buffer.DirtyPixel_uint16 (row + 1, badRect.l - 4, 0);
   1143 		uint16 *p6 = buffer.DirtyPixel_uint16 (row + 2, badRect.l - 4, 0);
   1144 		uint16 *p7 = buffer.DirtyPixel_uint16 (row + 3, badRect.l - 4, 0);
   1145 		uint16 *p8 = buffer.DirtyPixel_uint16 (row + 4, badRect.l - 4, 0);
   1146 
   1147 		uint32 est0;
   1148 		uint32 est1;
   1149 		uint32 est2;
   1150 		uint32 est3;
   1151 		uint32 est4;
   1152 		uint32 est5;
   1153 		uint32 est6;
   1154 
   1155 		uint32 grad0;
   1156 		uint32 grad1;
   1157 		uint32 grad2;
   1158 		uint32 grad3;
   1159 		uint32 grad4;
   1160 		uint32 grad5;
   1161 		uint32 grad6;
   1162 
   1163 		uint32 lower = 0;
   1164 		uint32 upper = 0x0FFFF;
   1165 
   1166 		if (IsGreen (row, badRect.l))		// Green pixel
   1167 			{
   1168 
   1169 			// g00 b01 g02 b03 g04 b05 g06 b07 g08
   1170 			// r10 g11 r12 g13 r14 g15 r16 g17 r18
   1171 			// g20 b21 g22 b23 g24 b25 g26 b27 g28
   1172 			// r30 g31 r32 g33 r34 g35 r36 g37 r38
   1173 			// g40 b41 g42 b43 g44 b45 g46 b47 g48
   1174 			// r50 g51 r52 g53 r54 g55 r56 g57 r58
   1175 			// g60 b61 g62 b63 g64 b65 g66 b67 g68
   1176 			// r70 g71 r72 g73 r74 g75 r76 g77 r78
   1177 			// g80 b81 g82 b83 g84 b85 g86 b87 g88
   1178 
   1179 			int32 b03 = p0 [3 * cs];
   1180 			int32 b05 = p0 [5 * cs];
   1181 
   1182 			int32 g11 = p1 [1 * cs];
   1183 			int32 g13 = p1 [3 * cs];
   1184 			int32 g15 = p1 [5 * cs];
   1185 			int32 g17 = p1 [7 * cs];
   1186 
   1187 			int32 g22 = p2 [2 * cs];
   1188 			int32 b23 = p2 [3 * cs];
   1189 			int32 b25 = p2 [5 * cs];
   1190 			int32 g26 = p2 [6 * cs];
   1191 
   1192 			int32 r30 = p3 [0 * cs];
   1193 			int32 g31 = p3 [1 * cs];
   1194 			int32 r32 = p3 [2 * cs];
   1195 			int32 g33 = p3 [3 * cs];
   1196 			int32 g35 = p3 [5 * cs];
   1197 			int32 r36 = p3 [6 * cs];
   1198 			int32 g37 = p3 [7 * cs];
   1199 			int32 r38 = p3 [8 * cs];
   1200 
   1201 			int32 g40 = p4 [0 * cs];
   1202 			int32 g42 = p4 [2 * cs];
   1203 			int32 b43 = p4 [3 * cs];
   1204 			int32 b45 = p4 [5 * cs];
   1205 			int32 g46 = p4 [6 * cs];
   1206 			int32 g48 = p4 [8 * cs];
   1207 
   1208 			int32 r50 = p5 [0 * cs];
   1209 			int32 g51 = p5 [1 * cs];
   1210 			int32 r52 = p5 [2 * cs];
   1211 			int32 g53 = p5 [3 * cs];
   1212 			int32 g55 = p5 [5 * cs];
   1213 			int32 r56 = p5 [6 * cs];
   1214 			int32 g57 = p5 [7 * cs];
   1215 			int32 r58 = p5 [8 * cs];
   1216 
   1217 			int32 g62 = p6 [2 * cs];
   1218 			int32 b63 = p6 [3 * cs];
   1219 			int32 b65 = p6 [5 * cs];
   1220 			int32 g66 = p6 [6 * cs];
   1221 
   1222 			int32 g71 = p7 [1 * cs];
   1223 			int32 g73 = p7 [3 * cs];
   1224 			int32 g75 = p7 [5 * cs];
   1225 			int32 g77 = p7 [7 * cs];
   1226 
   1227 			int32 b83 = p8 [3 * cs];
   1228 			int32 b85 = p8 [5 * cs];
   1229 
   1230 			// In case there is some green split, make an estimate of
   1231 			// of the local difference between the greens, and adjust
   1232 			// the estimated green values for the difference
   1233 			// between the two types of green pixels when estimating
   1234 			// across green types.
   1235 
   1236 			int32 split = ((g22 + g62 + g26 + g66) * 4 +
   1237 						   (g42 + g46            ) * 8 -
   1238 						   (g11 + g13 + g15 + g17)     -
   1239 						   (g31 + g33 + g35 + g37) * 3 -
   1240 						   (g51 + g53 + g55 + g57) * 3 -
   1241 						   (g71 + g73 + g75 + g77) + 16) >> 5;
   1242 
   1243 			est0 = g13 + g75 + split * 2;
   1244 
   1245 			grad0 = Abs_int32 (g13 - g75) +
   1246 					Abs_int32 (g15 - g46) +
   1247 					Abs_int32 (g22 - g53) +
   1248 					Abs_int32 (g35 - g66) +
   1249 					Abs_int32 (g42 - g73) +
   1250 					Abs_int32 (b03 - b65) +
   1251 					Abs_int32 (b23 - b85);
   1252 
   1253 			est1 = g33 + g55 + split * 2;
   1254 
   1255 			grad1 = Abs_int32 (g33 - g55) +
   1256 					Abs_int32 (g22 - g55) +
   1257 					Abs_int32 (g33 - g66) +
   1258 					Abs_int32 (g13 - g35) +
   1259 					Abs_int32 (g53 - g75) +
   1260 					Abs_int32 (b23 - b45) +
   1261 					Abs_int32 (b43 - b65);
   1262 
   1263 			est2 = g31 + g57 + split * 2;
   1264 
   1265 			grad2 = Abs_int32 (g31 - g57) +
   1266 					Abs_int32 (g33 - g46) +
   1267 					Abs_int32 (g35 - g48) +
   1268 					Abs_int32 (g40 - g53) +
   1269 					Abs_int32 (g42 - g55) +
   1270 					Abs_int32 (r30 - r56) +
   1271 					Abs_int32 (r32 - r58);
   1272 
   1273 			est3 = g42 + g46;
   1274 
   1275 			grad3 = Abs_int32 (g42 - g46) * 2 +
   1276 					Abs_int32 (g33 - g35) +
   1277 					Abs_int32 (g53 - g55) +
   1278 					Abs_int32 (b23 - b25) +
   1279 					Abs_int32 (b43 - b45) +
   1280 					Abs_int32 (b63 - b65);
   1281 
   1282 			est4 = g37 + g51 + split * 2;
   1283 
   1284 			grad4 = Abs_int32 (g37 - g51) +
   1285 					Abs_int32 (g35 - g42) +
   1286 					Abs_int32 (g33 - g40) +
   1287 					Abs_int32 (g48 - g55) +
   1288 					Abs_int32 (g46 - g53) +
   1289 					Abs_int32 (r38 - r52) +
   1290 					Abs_int32 (r36 - r50);
   1291 
   1292 			est5 = g35 + g53 + split * 2;
   1293 
   1294 			grad5 = Abs_int32 (g35 - g53) +
   1295 					Abs_int32 (g26 - g53) +
   1296 					Abs_int32 (g35 - g62) +
   1297 					Abs_int32 (g15 - g33) +
   1298 					Abs_int32 (g55 - g73) +
   1299 					Abs_int32 (b25 - b43) +
   1300 					Abs_int32 (b45 - b63);
   1301 
   1302 			est6 = g15 + g73 + split * 2;
   1303 
   1304 			grad6 = Abs_int32 (g15 - g73) +
   1305 					Abs_int32 (g13 - g42) +
   1306 					Abs_int32 (g26 - g55) +
   1307 					Abs_int32 (g33 - g62) +
   1308 					Abs_int32 (g46 - g75) +
   1309 					Abs_int32 (b05 - b63) +
   1310 					Abs_int32 (b25 - b83);
   1311 
   1312 			lower = Min_uint32 (Min_uint32 (g33, g35),
   1313 								Min_uint32 (g53, g55));
   1314 
   1315 			upper = Max_uint32 (Max_uint32 (g33, g35),
   1316 								Max_uint32 (g53, g55));
   1317 
   1318 			lower = Pin_int32 (0, lower + split, 65535);
   1319 			upper = Pin_int32 (0, upper + split, 65535);
   1320 
   1321 			}
   1322 
   1323 		else		// Red/blue pixel
   1324 			{
   1325 
   1326 			// b00 g01 b02 g03 b04 g05 b06 g07 b08
   1327 			// g10 r11 g12 r13 g14 r15 g16 r17 g18
   1328 			// b20 g21 b22 g23 b24 g25 b26 g27 b28
   1329 			// g30 r31 g32 r33 g34 r35 g36 r37 g38
   1330 			// b40 g41 b42 g43 b44 g45 b46 g47 b48
   1331 			// g50 r51 g52 r53 g54 r55 g56 r57 g58
   1332 			// b60 g61 b62 g63 b64 g65 b66 g67 b68
   1333 			// g70 r71 g72 r73 g74 r75 g76 r77 g78
   1334 			// b80 g81 b82 g83 b84 g85 b86 g87 b88
   1335 
   1336 			int32 b02 = p0 [2 * cs];
   1337 			int32 g03 = p0 [3 * cs];
   1338 			int32 g05 = p0 [5 * cs];
   1339 			int32 b06 = p0 [6 * cs];
   1340 
   1341 			int32 r13 = p1 [3 * cs];
   1342 			int32 r15 = p1 [5 * cs];
   1343 
   1344 			int32 b20 = p2 [0 * cs];
   1345 			int32 b22 = p2 [2 * cs];
   1346 			int32 g23 = p2 [3 * cs];
   1347 			int32 g25 = p2 [5 * cs];
   1348 			int32 b26 = p2 [6 * cs];
   1349 			int32 b28 = p2 [8 * cs];
   1350 
   1351 			int32 r31 = p3 [1 * cs];
   1352 			int32 g32 = p3 [2 * cs];
   1353 			int32 r33 = p3 [3 * cs];
   1354 			int32 r35 = p3 [5 * cs];
   1355 			int32 g36 = p3 [6 * cs];
   1356 			int32 r37 = p3 [7 * cs];
   1357 
   1358 			int32 g41 = p4 [1 * cs];
   1359 			int32 b42 = p4 [2 * cs];
   1360 			int32 g43 = p4 [3 * cs];
   1361 			int32 g45 = p4 [5 * cs];
   1362 			int32 b46 = p4 [6 * cs];
   1363 			int32 g47 = p4 [7 * cs];
   1364 
   1365 			int32 r51 = p5 [1 * cs];
   1366 			int32 g52 = p5 [2 * cs];
   1367 			int32 r53 = p5 [3 * cs];
   1368 			int32 r55 = p5 [5 * cs];
   1369 			int32 g56 = p5 [6 * cs];
   1370 			int32 r57 = p5 [7 * cs];
   1371 
   1372 			int32 b60 = p6 [0 * cs];
   1373 			int32 b62 = p6 [2 * cs];
   1374 			int32 g63 = p6 [3 * cs];
   1375 			int32 g65 = p6 [5 * cs];
   1376 			int32 b66 = p6 [6 * cs];
   1377 			int32 b68 = p6 [8 * cs];
   1378 
   1379 			int32 r73 = p7 [3 * cs];
   1380 			int32 r75 = p7 [5 * cs];
   1381 
   1382 			int32 b82 = p8 [2 * cs];
   1383 			int32 g83 = p8 [3 * cs];
   1384 			int32 g85 = p8 [5 * cs];
   1385 			int32 b86 = p8 [6 * cs];
   1386 
   1387 			est0 = b02 + b86;
   1388 
   1389 			grad0 = Abs_int32 (b02 - b86) +
   1390 					Abs_int32 (r13 - r55) +
   1391 					Abs_int32 (r33 - r75) +
   1392 					Abs_int32 (g03 - g45) +
   1393 					Abs_int32 (g23 - g65) +
   1394 					Abs_int32 (g43 - g85);
   1395 
   1396 			est1 = b22 + b66;
   1397 
   1398 			grad1 = Abs_int32 (b22 - b66) +
   1399 					Abs_int32 (r13 - r35) +
   1400 					Abs_int32 (r33 - r55) +
   1401 					Abs_int32 (r53 - r75) +
   1402 					Abs_int32 (g23 - g45) +
   1403 					Abs_int32 (g43 - g65);
   1404 
   1405 			est2 = b20 + b68;
   1406 
   1407 			grad2 = Abs_int32 (b20 - b68) +
   1408 					Abs_int32 (r31 - r55) +
   1409 					Abs_int32 (r33 - r57) +
   1410 					Abs_int32 (g23 - g47) +
   1411 					Abs_int32 (g32 - g56) +
   1412 					Abs_int32 (g41 - g65);
   1413 
   1414 			est3 = b42 + b46;
   1415 
   1416 			grad3 = Abs_int32 (b42 - b46) +
   1417 					Abs_int32 (r33 - r35) +
   1418 					Abs_int32 (r53 - r55) +
   1419 					Abs_int32 (g32 - g36) +
   1420 					Abs_int32 (g43 - g43) +
   1421 					Abs_int32 (g52 - g56);
   1422 
   1423 			est4 = b28 + b60;
   1424 
   1425 			grad4 = Abs_int32 (b28 - b60) +
   1426 					Abs_int32 (r37 - r53) +
   1427 					Abs_int32 (r35 - r51) +
   1428 					Abs_int32 (g25 - g41) +
   1429 					Abs_int32 (g36 - g52) +
   1430 					Abs_int32 (g47 - g63);
   1431 
   1432 			est5 = b26 + b62;
   1433 
   1434 			grad5 = Abs_int32 (b26 - b62) +
   1435 					Abs_int32 (r15 - r33) +
   1436 					Abs_int32 (r35 - r53) +
   1437 					Abs_int32 (r55 - r73) +
   1438 					Abs_int32 (g25 - g43) +
   1439 					Abs_int32 (g45 - g63);
   1440 
   1441 			est6 = b06 + b82;
   1442 
   1443 			grad6 = Abs_int32 (b06 - b82) +
   1444 					Abs_int32 (r15 - r53) +
   1445 					Abs_int32 (r35 - r73) +
   1446 					Abs_int32 (g05 - g43) +
   1447 					Abs_int32 (g25 - g63) +
   1448 					Abs_int32 (g45 - g83);
   1449 
   1450 			lower = Min_uint32 (b42, b46);
   1451 			upper = Max_uint32 (b42, b46);
   1452 
   1453 			}
   1454 
   1455 		uint32 minGrad = Min_uint32 (grad0, grad1);
   1456 
   1457 		minGrad = Min_uint32 (minGrad, grad2);
   1458 		minGrad = Min_uint32 (minGrad, grad3);
   1459 		minGrad = Min_uint32 (minGrad, grad4);
   1460 		minGrad = Min_uint32 (minGrad, grad5);
   1461 		minGrad = Min_uint32 (minGrad, grad6);
   1462 
   1463 		uint32 limit = (minGrad * 3) >> 1;
   1464 
   1465 		uint32 total = 0;
   1466 		uint32 count = 0;
   1467 
   1468 		if (grad0 <= limit)
   1469 			{
   1470 			total += est0;
   1471 			count += 2;
   1472 			}
   1473 
   1474 		if (grad1 <= limit)
   1475 			{
   1476 			total += est1;
   1477 			count += 2;
   1478 			}
   1479 
   1480 		if (grad2 <= limit)
   1481 			{
   1482 			total += est2;
   1483 			count += 2;
   1484 			}
   1485 
   1486 		if (grad3 <= limit)
   1487 			{
   1488 			total += est3;
   1489 			count += 2;
   1490 			}
   1491 
   1492 		if (grad4 <= limit)
   1493 			{
   1494 			total += est4;
   1495 			count += 2;
   1496 			}
   1497 
   1498 		if (grad5 <= limit)
   1499 			{
   1500 			total += est5;
   1501 			count += 2;
   1502 			}
   1503 
   1504 		if (grad6 <= limit)
   1505 			{
   1506 			total += est6;
   1507 			count += 2;
   1508 			}
   1509 
   1510 		uint32 estimate = (total + (count >> 1)) / count;
   1511 
   1512 		p4 [4] = (uint16) Pin_uint32 (lower, estimate, upper);
   1513 
   1514 		}
   1515 
   1516 	}
   1517 
   1518 /*****************************************************************************/
   1519 
   1520 void dng_opcode_FixBadPixelsList::FixSingleRow (dng_pixel_buffer &buffer,
   1521 												const dng_rect &badRect)
   1522 	{
   1523 
   1524 	dng_pixel_buffer tBuffer = buffer;
   1525 
   1526 	tBuffer.fArea = Transpose (buffer.fArea);
   1527 
   1528 	tBuffer.fRowStep = buffer.fColStep;
   1529 	tBuffer.fColStep = buffer.fRowStep;
   1530 
   1531 	dng_rect tBadRect = Transpose (badRect);
   1532 
   1533 	FixSingleColumn (tBuffer, tBadRect);
   1534 
   1535 	}
   1536 
   1537 /*****************************************************************************/
   1538 
   1539 void dng_opcode_FixBadPixelsList::FixClusteredRect (dng_pixel_buffer &buffer,
   1540 												    const dng_rect &badRect,
   1541 													const dng_rect &imageBounds)
   1542 	{
   1543 
   1544 	const uint32 kNumSets = 8;
   1545 	const uint32 kSetSize = 8;
   1546 
   1547 	static const int32 kOffset [kNumSets] [kSetSize] [2] =
   1548 		{
   1549 			{
   1550 				{ -1,  1 },
   1551 				{ -1, -1 },
   1552 				{  1, -1 },
   1553 				{  1,  1 },
   1554 				{  0,  0 },
   1555 				{  0,  0 },
   1556 				{  0,  0 },
   1557 				{  0,  0 }
   1558 			},
   1559 			{
   1560 				{ -2,  0 },
   1561 				{  2,  0 },
   1562 				{  0, -2 },
   1563 				{  0,  2 },
   1564 				{  0,  0 },
   1565 				{  0,  0 },
   1566 				{  0,  0 },
   1567 				{  0,  0 }
   1568 			},
   1569 			{
   1570 				{ -2, -2 },
   1571 				{ -2,  2 },
   1572 				{  2, -2 },
   1573 				{  2,  2 },
   1574 				{  0,  0 },
   1575 				{  0,  0 },
   1576 				{  0,  0 },
   1577 				{  0,  0 }
   1578 			},
   1579 			{
   1580 				{ -1, -3 },
   1581 				{ -3, -1 },
   1582 				{  1, -3 },
   1583 				{  3, -1 },
   1584 				{ -1,  3 },
   1585 				{ -3,  1 },
   1586 				{  1,  3 },
   1587 				{  3,  1 }
   1588 			},
   1589 			{
   1590 				{ -4,  0 },
   1591 				{  4,  0 },
   1592 				{  0, -4 },
   1593 				{  0,  4 },
   1594 				{  0,  0 },
   1595 				{  0,  0 },
   1596 				{  0,  0 },
   1597 				{  0,  0 }
   1598 			},
   1599 			{
   1600 				{ -3, -3 },
   1601 				{ -3,  3 },
   1602 				{  3, -3 },
   1603 				{  3,  3 },
   1604 				{  0,  0 },
   1605 				{  0,  0 },
   1606 				{  0,  0 },
   1607 				{  0,  0 }
   1608 			},
   1609 			{
   1610 				{ -2, -4 },
   1611 				{ -4, -2 },
   1612 				{  2, -4 },
   1613 				{  4, -2 },
   1614 				{ -2,  4 },
   1615 				{ -4,  2 },
   1616 				{  2,  4 },
   1617 				{  4,  2 }
   1618 			},
   1619 			{
   1620 				{ -4, -4 },
   1621 				{ -4,  4 },
   1622 				{  4, -4 },
   1623 				{  4,  4 },
   1624 				{  0,  0 },
   1625 				{  0,  0 },
   1626 				{  0,  0 },
   1627 				{  0,  0 }
   1628 			}
   1629 		};
   1630 
   1631 	bool didFail = false;
   1632 
   1633 	for (int32 row = badRect.t; row < badRect.b; row++)
   1634 		{
   1635 
   1636 		for (int32 col = badRect.l; col < badRect.r; col++)
   1637 			{
   1638 
   1639 			uint16 *p = buffer.DirtyPixel_uint16 (row, col, 0);
   1640 
   1641 			bool isGreen = IsGreen (row, col);
   1642 
   1643 			bool didFixPixel = false;
   1644 
   1645 			for (uint32 set = 0; set < kNumSets && !didFixPixel; set++)
   1646 				{
   1647 
   1648 				if (!isGreen && (kOffset [set] [0] [0] & 1) == 1)
   1649 					{
   1650 					continue;
   1651 					}
   1652 
   1653 				uint32 total = 0;
   1654 				uint32 count = 0;
   1655 
   1656 				for (uint32 entry = 0; entry < kSetSize; entry++)
   1657 					{
   1658 
   1659 					dng_point offset (kOffset [set] [entry] [0],
   1660 									  kOffset [set] [entry] [1]);
   1661 
   1662 					if (offset.v == 0 &&
   1663 						offset.h == 0)
   1664 						{
   1665 						break;
   1666 						}
   1667 
   1668 					if (fList->IsPointValid (dng_point (row, col) + offset,
   1669 											 imageBounds))
   1670 						{
   1671 
   1672 						total += p [offset.v * buffer.fRowStep +
   1673 									offset.h * buffer.fColStep];
   1674 
   1675 						count++;
   1676 
   1677 						}
   1678 
   1679 					}
   1680 
   1681 				if (count)
   1682 					{
   1683 
   1684 					uint32 estimate = (total + (count >> 1)) / count;
   1685 
   1686 					p [0] = (uint16) estimate;
   1687 
   1688 					didFixPixel = true;
   1689 
   1690 					}
   1691 
   1692 				}
   1693 
   1694 			if (!didFixPixel)
   1695 				{
   1696 
   1697 				didFail = true;
   1698 
   1699 				}
   1700 
   1701 			}
   1702 
   1703 		}
   1704 
   1705 	#if qDNGValidate
   1706 
   1707 	if (didFail)
   1708 		{
   1709 
   1710 		ReportWarning ("Unable to repair bad rectangle");
   1711 
   1712 		}
   1713 
   1714 	#endif
   1715 
   1716 	}
   1717 
   1718 /*****************************************************************************/
   1719 
   1720 void dng_opcode_FixBadPixelsList::ProcessArea (dng_negative & /* negative */,
   1721 											   uint32 /* threadIndex */,
   1722 											   dng_pixel_buffer &srcBuffer,
   1723 											   dng_pixel_buffer &dstBuffer,
   1724 											   const dng_rect &dstArea,
   1725 											   const dng_rect &imageBounds)
   1726 	{
   1727 
   1728 	uint32 pointCount = fList->PointCount ();
   1729 	uint32 rectCount  = fList->RectCount  ();
   1730 
   1731 	dng_rect fixArea = dstArea;
   1732 
   1733 	if (rectCount)
   1734 		{
   1735 		fixArea.t -= kBadRectPadding;
   1736 		fixArea.l -= kBadRectPadding;
   1737 		fixArea.b += kBadRectPadding;
   1738 		fixArea.r += kBadRectPadding;
   1739 		}
   1740 
   1741 	bool didFixPoint = false;
   1742 
   1743 	if (pointCount)
   1744 		{
   1745 
   1746 		for (uint32 pointIndex = 0; pointIndex < pointCount; pointIndex++)
   1747 			{
   1748 
   1749 			dng_point badPoint = fList->Point (pointIndex);
   1750 
   1751 			if (badPoint.v >= fixArea.t &&
   1752 				badPoint.h >= fixArea.l &&
   1753 				badPoint.v <  fixArea.b &&
   1754 				badPoint.h <  fixArea.r)
   1755 				{
   1756 
   1757 				bool isIsolated = fList->IsPointIsolated (pointIndex,
   1758 														  kBadPointPadding);
   1759 
   1760 				if (isIsolated &&
   1761 					badPoint.v >= imageBounds.t + kBadPointPadding &&
   1762 					badPoint.h >= imageBounds.l + kBadPointPadding &&
   1763 					badPoint.v <  imageBounds.b - kBadPointPadding &&
   1764 					badPoint.h <  imageBounds.r - kBadPointPadding)
   1765 					{
   1766 
   1767 					FixIsolatedPixel (srcBuffer,
   1768 									  badPoint);
   1769 
   1770 					}
   1771 
   1772 				else
   1773 					{
   1774 
   1775 					FixClusteredPixel (srcBuffer,
   1776 									   pointIndex,
   1777 									   imageBounds);
   1778 
   1779 					}
   1780 
   1781 				didFixPoint = true;
   1782 
   1783 				}
   1784 
   1785 			}
   1786 
   1787 		}
   1788 
   1789 	if (rectCount)
   1790 		{
   1791 
   1792 		if (didFixPoint)
   1793 			{
   1794 
   1795 			srcBuffer.RepeatSubArea (imageBounds,
   1796 									 SrcRepeat ().v,
   1797 									 SrcRepeat ().h);
   1798 
   1799 			}
   1800 
   1801 		for (uint32 rectIndex = 0; rectIndex < rectCount; rectIndex++)
   1802 			{
   1803 
   1804 			dng_rect badRect = fList->Rect (rectIndex);
   1805 
   1806 			dng_rect overlap = dstArea & badRect;
   1807 
   1808 			if (overlap.NotEmpty ())
   1809 				{
   1810 
   1811 				bool isIsolated = fList->IsRectIsolated (rectIndex,
   1812 														 kBadRectPadding);
   1813 
   1814 				if (isIsolated &&
   1815 					badRect.r == badRect.l + 1 &&
   1816 					badRect.l >= imageBounds.l + SrcRepeat ().h &&
   1817 					badRect.r <= imageBounds.r - SrcRepeat ().v)
   1818 					{
   1819 
   1820 					FixSingleColumn (srcBuffer,
   1821 									 overlap);
   1822 
   1823 					}
   1824 
   1825 				else if (isIsolated &&
   1826 						 badRect.b == badRect.t + 1 &&
   1827 						 badRect.t >= imageBounds.t + SrcRepeat ().h &&
   1828 						 badRect.b <= imageBounds.b - SrcRepeat ().v)
   1829 					{
   1830 
   1831 					FixSingleRow (srcBuffer,
   1832 								  overlap);
   1833 
   1834 					}
   1835 
   1836 				else
   1837 					{
   1838 
   1839 					FixClusteredRect (srcBuffer,
   1840 									  overlap,
   1841 									  imageBounds);
   1842 
   1843 					}
   1844 
   1845 				}
   1846 
   1847 			}
   1848 
   1849 		}
   1850 
   1851 	dstBuffer.CopyArea (srcBuffer,
   1852 						dstArea,
   1853 						0,
   1854 						dstBuffer.fPlanes);
   1855 
   1856 	}
   1857 
   1858 /*****************************************************************************/
   1859