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