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