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
29dng_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
46dng_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
83void 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
95dng_point dng_opcode_FixBadPixelsConstant::SrcRepeat ()
96	{
97
98	return dng_point (2, 2);
99
100	}
101
102/*****************************************************************************/
103
104dng_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
122void 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
153void 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
286dng_bad_pixel_list::dng_bad_pixel_list ()
287
288	:	fBadPoints ()
289	,	fBadRects  ()
290
291	{
292
293	}
294
295/*****************************************************************************/
296
297void dng_bad_pixel_list::AddPoint (const dng_point &pt)
298	{
299
300	fBadPoints.push_back (pt);
301
302	}
303
304/*****************************************************************************/
305
306void dng_bad_pixel_list::AddRect (const dng_rect &r)
307	{
308
309	fBadRects.push_back (r);
310
311	}
312
313/*****************************************************************************/
314
315static 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
331static 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
359void 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
384bool 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
453bool 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
485bool 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
570dng_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
593dng_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
697void 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
738dng_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
768dng_point dng_opcode_FixBadPixelsList::SrcRepeat ()
769	{
770
771	return dng_point (2, 2);
772
773	}
774
775/*****************************************************************************/
776
777void 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
808void 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
1030void 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
1128void 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
1520void 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
1539void 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
1720void 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