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 
dng_opcode_FixBadPixelsConstant(uint32 constant,uint32 bayerPhase)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 
dng_opcode_FixBadPixelsConstant(dng_stream & stream)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 
PutData(dng_stream & stream) const83 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 
SrcRepeat()95 dng_point dng_opcode_FixBadPixelsConstant::SrcRepeat ()
96 	{
97 
98 	return dng_point (2, 2);
99 
100 	}
101 
102 /*****************************************************************************/
103 
SrcArea(const dng_rect & dstArea,const dng_rect &)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 
Prepare(dng_negative &,uint32,const dng_point &,const dng_rect &,uint32 imagePlanes,uint32 bufferPixelType,dng_memory_allocator &)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 
ProcessArea(dng_negative &,uint32,dng_pixel_buffer & srcBuffer,dng_pixel_buffer & dstBuffer,const dng_rect & dstArea,const dng_rect &)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 
dng_bad_pixel_list()286 dng_bad_pixel_list::dng_bad_pixel_list ()
287 
288 	:	fBadPoints ()
289 	,	fBadRects  ()
290 
291 	{
292 
293 	}
294 
295 /*****************************************************************************/
296 
AddPoint(const dng_point & pt)297 void dng_bad_pixel_list::AddPoint (const dng_point &pt)
298 	{
299 
300 	fBadPoints.push_back (pt);
301 
302 	}
303 
304 /*****************************************************************************/
305 
AddRect(const dng_rect & r)306 void dng_bad_pixel_list::AddRect (const dng_rect &r)
307 	{
308 
309 	fBadRects.push_back (r);
310 
311 	}
312 
313 /*****************************************************************************/
314 
SortBadPoints(const dng_point & a,const dng_point & b)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 
SortBadRects(const dng_rect & a,const dng_rect & b)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 
Sort()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 
IsPointIsolated(uint32 index,uint32 radius) const384 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 
IsRectIsolated(uint32 index,uint32 radius) const453 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 
IsPointValid(const dng_point & pt,const dng_rect & imageBounds,uint32 index) const485 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 
dng_opcode_FixBadPixelsList(AutoPtr<dng_bad_pixel_list> & list,uint32 bayerPhase)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 
dng_opcode_FixBadPixelsList(dng_stream & stream)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 
PutData(dng_stream & stream) const697 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 
SrcArea(const dng_rect & dstArea,const dng_rect &)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 
SrcRepeat()768 dng_point dng_opcode_FixBadPixelsList::SrcRepeat ()
769 	{
770 
771 	return dng_point (2, 2);
772 
773 	}
774 
775 /*****************************************************************************/
776 
Prepare(dng_negative &,uint32,const dng_point &,const dng_rect &,uint32 imagePlanes,uint32 bufferPixelType,dng_memory_allocator &)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 
FixIsolatedPixel(dng_pixel_buffer & buffer,dng_point & badPoint)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 
FixClusteredPixel(dng_pixel_buffer & buffer,uint32 pointIndex,const dng_rect & imageBounds)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 
FixSingleColumn(dng_pixel_buffer & buffer,const dng_rect & badRect)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 
FixSingleRow(dng_pixel_buffer & buffer,const dng_rect & badRect)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 
FixClusteredRect(dng_pixel_buffer & buffer,const dng_rect & badRect,const dng_rect & imageBounds)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 
ProcessArea(dng_negative &,uint32,dng_pixel_buffer & srcBuffer,dng_pixel_buffer & dstBuffer,const dng_rect & dstArea,const dng_rect & imageBounds)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