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