1/*****************************************************************************/
2// Copyright 2006-2009 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_mosaic_info.cpp#1 $ */
10/* $DateTime: 2012/05/30 13:28:51 $ */
11/* $Change: 832332 $ */
12/* $Author: tknoll $ */
13
14/*****************************************************************************/
15
16#include "dng_mosaic_info.h"
17
18#include "dng_area_task.h"
19#include "dng_assertions.h"
20#include "dng_bottlenecks.h"
21#include "dng_exceptions.h"
22#include "dng_filter_task.h"
23#include "dng_host.h"
24#include "dng_ifd.h"
25#include "dng_image.h"
26#include "dng_info.h"
27#include "dng_negative.h"
28#include "dng_pixel_buffer.h"
29#include "dng_tag_types.h"
30#include "dng_tag_values.h"
31#include "dng_tile_iterator.h"
32#include "dng_utils.h"
33
34/*****************************************************************************/
35
36// A interpolation kernel for a single pixel of a single plane.
37
38class dng_bilinear_kernel
39 {
40
41 public:
42
43 enum
44 {
45 kMaxCount = 8
46 };
47
48 uint32 fCount;
49
50 dng_point fDelta [kMaxCount];
51
52 real32 fWeight32 [kMaxCount];
53 uint16 fWeight16 [kMaxCount];
54
55 int32 fOffset [kMaxCount];
56
57 public:
58
59 dng_bilinear_kernel ()
60 : fCount (0)
61 {
62 }
63
64 void Add (const dng_point &delta,
65 real32 weight);
66
67 void Finalize (const dng_point &scale,
68 uint32 patRow,
69 uint32 patCol,
70 int32 rowStep,
71 int32 colStep);
72
73 };
74
75/*****************************************************************************/
76
77void dng_bilinear_kernel::Add (const dng_point &delta,
78 real32 weight)
79 {
80
81 // Don't add zero weight elements.
82
83 if (weight <= 0.0f)
84 {
85 return;
86 }
87
88 // If the delta already matches an existing element, just combine the
89 // weights.
90
91 for (uint32 j = 0; j < fCount; j++)
92 {
93
94 if (fDelta [j] == delta)
95 {
96
97 fWeight32 [j] += weight;
98
99 return;
100
101 }
102
103 }
104
105 // Add element to list.
106
107 DNG_ASSERT (fCount < kMaxCount, "Too many kernel entries");
108
109 fDelta [fCount] = delta;
110 fWeight32 [fCount] = weight;
111
112 fCount++;
113
114 }
115
116/*****************************************************************************/
117
118void dng_bilinear_kernel::Finalize (const dng_point &scale,
119 uint32 patRow,
120 uint32 patCol,
121 int32 rowStep,
122 int32 colStep)
123 {
124
125 uint32 j;
126
127 // Adjust deltas to compensate for interpolation upscaling.
128
129 for (j = 0; j < fCount; j++)
130 {
131
132 dng_point &delta = fDelta [j];
133
134 if (scale.v == 2)
135 {
136
137 delta.v = (delta.v + (int32) (patRow & 1)) >> 1;
138
139 }
140
141 if (scale.h == 2)
142 {
143
144 delta.h = (delta.h + (int32) (patCol & 1)) >> 1;
145
146 }
147
148 }
149
150 // Sort entries into row-column scan order.
151
152 while (true)
153 {
154
155 bool didSwap = false;
156
157 for (j = 1; j < fCount; j++)
158 {
159
160 dng_point &delta0 = fDelta [j - 1];
161 dng_point &delta1 = fDelta [j ];
162
163 if (delta0.v > delta1.v ||
164 (delta0.v == delta1.v &&
165 delta0.h > delta1.h))
166 {
167
168 didSwap = true;
169
170 dng_point tempDelta = delta0;
171
172 delta0 = delta1;
173 delta1 = tempDelta;
174
175 real32 tempWeight = fWeight32 [j - 1];
176
177 fWeight32 [j - 1] = fWeight32 [j];
178 fWeight32 [j ] = tempWeight;
179
180 }
181
182 }
183
184 if (!didSwap)
185 {
186 break;
187 }
188
189 }
190
191 // Calculate offsets.
192
193 for (j = 0; j < fCount; j++)
194 {
195
196 fOffset [j] = rowStep * fDelta [j].v +
197 colStep * fDelta [j].h;
198
199 }
200
201 // Calculate 16-bit weights.
202
203 uint16 total = 0;
204 uint32 biggest = 0;
205
206 for (j = 0; j < fCount; j++)
207 {
208
209 // Round weights to 8 fractional bits.
210
211 fWeight16 [j] = (uint16) Round_uint32 (fWeight32 [j] * 256.0);
212
213 // Keep track of total of weights.
214
215 total += fWeight16 [j];
216
217 // Keep track of which weight is biggest.
218
219 if (fWeight16 [biggest] < fWeight16 [j])
220 {
221
222 biggest = j;
223
224 }
225
226 }
227
228 // Adjust largest entry so total of weights is exactly 256.
229
230 fWeight16 [biggest] += (256 - total);
231
232 // Recompute the floating point weights from the rounded integer weights
233 // so results match more closely.
234
235 for (j = 0; j < fCount; j++)
236 {
237
238 fWeight32 [j] = fWeight16 [j] * (1.0f / 256.0f);
239
240 }
241
242 }
243
244/*****************************************************************************/
245
246class dng_bilinear_pattern
247 {
248
249 public:
250
251 enum
252 {
253 kMaxPattern = kMaxCFAPattern * 2
254 };
255
256 dng_point fScale;
257
258 uint32 fPatRows;
259 uint32 fPatCols;
260
261 dng_bilinear_kernel fKernel [kMaxPattern]
262 [kMaxPattern];
263
264 uint32 fCounts [kMaxPattern]
265 [kMaxPattern];
266
267 int32 *fOffsets [kMaxPattern]
268 [kMaxPattern];
269
270 uint16 *fWeights16 [kMaxPattern]
271 [kMaxPattern];
272
273 real32 *fWeights32 [kMaxPattern]
274 [kMaxPattern];
275
276 public:
277
278 dng_bilinear_pattern ()
279
280 : fScale ()
281 , fPatRows (0)
282 , fPatCols (0)
283
284 {
285 }
286
287 private:
288
289#if defined(__clang__) && defined(__has_attribute)
290#if __has_attribute(no_sanitize)
291__attribute__((no_sanitize("unsigned-integer-overflow")))
292#endif
293#endif
294 uint32 DeltaRow (uint32 row, int32 delta)
295 {
296 // Potential overflow in the conversion from delta to a uint32 as
297 // well as in the subsequent addition is intentional.
298 return (SafeUint32Add(row, fPatRows) + (uint32) delta) % fPatRows;
299 }
300
301#if defined(__clang__) && defined(__has_attribute)
302#if __has_attribute(no_sanitize)
303__attribute__((no_sanitize("unsigned-integer-overflow")))
304#endif
305#endif
306 uint32 DeltaCol (uint32 col, int32 delta)
307 {
308 // Potential overflow in the conversion from delta to a uint32 as
309 // well as in the subsequent addition is intentional.
310 return (SafeUint32Add(col, fPatCols) + (uint32) delta) % fPatCols;
311 }
312
313 real32 LinearWeight1 (int32 d1, int32 d2)
314 {
315 if (d1 == d2)
316 return 1.0f;
317 else
318 return d2 / (real32) (d2 - d1);
319 }
320
321 real32 LinearWeight2 (int32 d1, int32 d2)
322 {
323 if (d1 == d2)
324 return 0.0f;
325 else
326 return -d1 / (real32) (d2 - d1);
327 }
328
329 public:
330
331 void Calculate (const dng_mosaic_info &info,
332 uint32 dstPlane,
333 int32 rowStep,
334 int32 colStep);
335
336 };
337
338/*****************************************************************************/
339
340void dng_bilinear_pattern::Calculate (const dng_mosaic_info &info,
341 uint32 dstPlane,
342 int32 rowStep,
343 int32 colStep)
344 {
345
346 uint32 j;
347 uint32 k;
348 uint32 patRow;
349 uint32 patCol;
350
351 // Find destination pattern size.
352
353 fScale = info.FullScale ();
354
355 fPatRows = info.fCFAPatternSize.v * fScale.v;
356 fPatCols = info.fCFAPatternSize.h * fScale.h;
357
358 // See if we need to scale up just while computing the kernels.
359
360 dng_point tempScale (1, 1);
361
362 if (info.fCFALayout >= 6)
363 {
364
365 tempScale = dng_point (2, 2);
366
367 fPatRows *= tempScale.v;
368 fPatCols *= tempScale.h;
369
370 }
371
372 // Find a boolean map for this plane color and layout.
373
374 bool map [kMaxPattern]
375 [kMaxPattern];
376
377 uint8 planeColor = info.fCFAPlaneColor [dstPlane];
378
379 switch (info.fCFALayout)
380 {
381
382 case 1: // Rectangular (or square) layout
383 {
384
385 for (j = 0; j < fPatRows; j++)
386 {
387
388 for (k = 0; k < fPatCols; k++)
389 {
390
391 map [j] [k] = (info.fCFAPattern [j] [k] == planeColor);
392
393 }
394
395 }
396
397 break;
398
399 }
400
401 // Note that when the descriptions of the staggered patterns refer to even rows or
402 // columns, this mean the second, fourth, etc. (i.e. using one-based numbering).
403 // This needs to be clarified in the DNG specification.
404
405 case 2: // Staggered layout A: even (1-based) columns are offset down by 1/2 row
406 {
407
408 for (j = 0; j < fPatRows; j++)
409 {
410
411 for (k = 0; k < fPatCols; k++)
412 {
413
414 if ((j & 1) != (k & 1))
415 {
416
417 map [j] [k] = false;
418
419 }
420
421 else
422 {
423
424 map [j] [k] = (info.fCFAPattern [j >> 1] [k] == planeColor);
425
426 }
427
428 }
429
430 }
431
432 break;
433
434 }
435
436 case 3: // Staggered layout B: even (1-based) columns are offset up by 1/2 row
437 {
438
439 for (j = 0; j < fPatRows; j++)
440 {
441
442 for (k = 0; k < fPatCols; k++)
443 {
444
445 if ((j & 1) == (k & 1))
446 {
447
448 map [j] [k] = false;
449
450 }
451
452 else
453 {
454
455 map [j] [k] = (info.fCFAPattern [j >> 1] [k] == planeColor);
456
457 }
458
459 }
460
461 }
462
463 break;
464
465 }
466
467 case 4: // Staggered layout C: even (1-based) rows are offset right by 1/2 column
468 {
469
470 for (j = 0; j < fPatRows; j++)
471 {
472
473 for (k = 0; k < fPatCols; k++)
474 {
475
476 if ((j & 1) != (k & 1))
477 {
478
479 map [j] [k] = false;
480
481 }
482
483 else
484 {
485
486 map [j] [k] = (info.fCFAPattern [j] [k >> 1] == planeColor);
487
488 }
489
490 }
491
492 }
493
494 break;
495
496 }
497
498 case 5: // Staggered layout D: even (1-based) rows are offset left by 1/2 column
499 {
500
501 for (j = 0; j < fPatRows; j++)
502 {
503
504 for (k = 0; k < fPatCols; k++)
505 {
506
507 if ((j & 1) == (k & 1))
508 {
509
510 map [j] [k] = false;
511
512 }
513
514 else
515 {
516
517 map [j] [k] = (info.fCFAPattern [j] [k >> 1] == planeColor);
518
519 }
520
521 }
522
523 }
524
525 break;
526
527 }
528
529 case 6: // Staggered layout E: even rows are offset up by 1/2 row, even columns are offset left by 1/2 column
530 case 7: // Staggered layout F: even rows are offset up by 1/2 row, even columns are offset right by 1/2 column
531 case 8: // Staggered layout G: even rows are offset down by 1/2 row, even columns are offset left by 1/2 column
532 case 9: // Staggered layout H: even rows are offset down by 1/2 row, even columns are offset right by 1/2 column
533 {
534
535 uint32 eRow = (info.fCFALayout == 6 ||
536 info.fCFALayout == 7) ? 1 : 3;
537
538 uint32 eCol = (info.fCFALayout == 6 ||
539 info.fCFALayout == 8) ? 1 : 3;
540
541 for (j = 0; j < fPatRows; j++)
542 {
543
544 for (k = 0; k < fPatCols; k++)
545 {
546
547 uint32 jj = j & 3;
548 uint32 kk = k & 3;
549
550 if ((jj != 0 && jj != eRow) ||
551 (kk != 0 && kk != eCol))
552 {
553
554 map [j] [k] = false;
555
556 }
557
558 else
559 {
560
561 map [j] [k] = (info.fCFAPattern [((j >> 1) & ~1) + Min_uint32 (jj, 1)]
562 [((k >> 1) & ~1) + Min_uint32 (kk, 1)] == planeColor);
563
564 }
565
566 }
567
568 }
569
570 break;
571
572 }
573
574 default:
575 ThrowProgramError ();
576
577 }
578
579 // Find projections of maps.
580
581 bool mapH [kMaxPattern];
582 bool mapV [kMaxPattern];
583
584 for (j = 0; j < kMaxPattern; j++)
585 {
586
587 mapH [j] = false;
588 mapV [j] = false;
589
590 }
591
592 for (j = 0; j < fPatRows; j++)
593 {
594
595 for (k = 0; k < fPatCols; k++)
596 {
597
598 if (map [j] [k])
599 {
600
601 mapV [j] = true;
602 mapH [k] = true;
603
604 }
605
606 }
607
608 }
609
610 // Find kernel for each patten entry.
611
612 for (patRow = 0; patRow < fPatRows; patRow += tempScale.v)
613 {
614
615 for (patCol = 0; patCol < fPatCols; patCol += tempScale.h)
616 {
617
618 dng_bilinear_kernel &kernel = fKernel [patRow] [patCol];
619
620 // Special case no interpolation case.
621
622 if (map [patRow] [patCol])
623 {
624
625 kernel.Add (dng_point (0, 0), 1.0f);
626
627 continue;
628
629 }
630
631 // Special case common patterns in 3 by 3 neighborhood.
632
633 uint32 n = DeltaRow (patRow, -1);
634 uint32 s = DeltaRow (patRow, 1);
635 uint32 w = DeltaCol (patCol, -1);
636 uint32 e = DeltaCol (patCol, 1);
637
638 bool mapNW = map [n] [w];
639 bool mapN = map [n] [patCol];
640 bool mapNE = map [n] [e];
641
642 bool mapW = map [patRow] [w];
643 bool mapE = map [patRow] [e];
644
645 bool mapSW = map [s] [w];
646 bool mapS = map [s] [patCol];
647 bool mapSE = map [s] [e];
648
649 // All sides.
650
651 if (mapN && mapS && mapW && mapW)
652 {
653
654 kernel.Add (dng_point (-1, 0), 0.25f);
655 kernel.Add (dng_point ( 0, -1), 0.25f);
656 kernel.Add (dng_point ( 0, 1), 0.25f);
657 kernel.Add (dng_point ( 1, 0), 0.25f);
658
659 continue;
660
661 }
662
663 // N & S.
664
665 if (mapN && mapS)
666 {
667
668 kernel.Add (dng_point (-1, 0), 0.5f);
669 kernel.Add (dng_point ( 1, 0), 0.5f);
670
671 continue;
672
673 }
674
675 // E & W.
676
677 if (mapW && mapE)
678 {
679
680 kernel.Add (dng_point ( 0, -1), 0.5f);
681 kernel.Add (dng_point ( 0, 1), 0.5f);
682
683 continue;
684
685 }
686
687 // N & SW & SE.
688
689 if (mapN && mapSW && mapSE)
690 {
691
692 kernel.Add (dng_point (-1, 0), 0.50f);
693 kernel.Add (dng_point ( 1, -1), 0.25f);
694 kernel.Add (dng_point ( 1, 1), 0.25f);
695
696 continue;
697
698 }
699
700 // S & NW & NE.
701
702 if (mapS && mapNW && mapNE)
703 {
704
705 kernel.Add (dng_point (-1, -1), 0.25f);
706 kernel.Add (dng_point (-1, 1), 0.25f);
707 kernel.Add (dng_point ( 1, 0), 0.50f);
708
709 continue;
710
711 }
712
713 // W & NE & SE.
714
715 if (mapW && mapNE && mapSE)
716 {
717
718 kernel.Add (dng_point (-1, 1), 0.25f);
719 kernel.Add (dng_point ( 0, -1), 0.50f);
720 kernel.Add (dng_point ( 1, 1), 0.25f);
721
722 continue;
723
724 }
725
726 // E & NW & SW.
727
728 if (mapE && mapNW && mapSW)
729 {
730
731 kernel.Add (dng_point (-1, -1), 0.25f);
732 kernel.Add (dng_point ( 0, 1), 0.50f);
733 kernel.Add (dng_point ( 1, -1), 0.25f);
734
735 continue;
736
737 }
738
739 // Four corners.
740
741 if (mapNW && mapNE && mapSE && mapSW)
742 {
743
744 kernel.Add (dng_point (-1, -1), 0.25f);
745 kernel.Add (dng_point (-1, 1), 0.25f);
746 kernel.Add (dng_point ( 1, -1), 0.25f);
747 kernel.Add (dng_point ( 1, 1), 0.25f);
748
749 continue;
750
751 }
752
753 // NW & SE
754
755 if (mapNW && mapSE)
756 {
757
758 kernel.Add (dng_point (-1, -1), 0.50f);
759 kernel.Add (dng_point ( 1, 1), 0.50f);
760
761 continue;
762
763 }
764
765 // NE & SW
766
767 if (mapNE && mapSW)
768 {
769
770 kernel.Add (dng_point (-1, 1), 0.50f);
771 kernel.Add (dng_point ( 1, -1), 0.50f);
772
773 continue;
774
775 }
776
777 // Else use double-bilinear kernel.
778
779 int32 dv1 = 0;
780 int32 dv2 = 0;
781
782 while (!mapV [DeltaRow (patRow, dv1)])
783 {
784 dv1--;
785 }
786
787 while (!mapV [DeltaRow (patRow, dv2)])
788 {
789 dv2++;
790 }
791
792 real32 w1 = LinearWeight1 (dv1, dv2) * 0.5f;
793 real32 w2 = LinearWeight2 (dv1, dv2) * 0.5f;
794
795 int32 v1 = DeltaRow (patRow, dv1);
796 int32 v2 = DeltaRow (patRow, dv2);
797
798 int32 dh1 = 0;
799 int32 dh2 = 0;
800
801 while (!map [v1] [DeltaCol (patCol, dh1)])
802 {
803 dh1--;
804 }
805
806 while (!map [v1] [DeltaCol (patCol, dh2)])
807 {
808 dh2++;
809 }
810
811 kernel.Add (dng_point (dv1, dh1),
812 LinearWeight1 (dh1, dh2) * w1);
813
814 kernel.Add (dng_point (dv1, dh2),
815 LinearWeight2 (dh1, dh2) * w1);
816
817 dh1 = 0;
818 dh2 = 0;
819
820 while (!map [v2] [DeltaCol (patCol, dh1)])
821 {
822 dh1--;
823 }
824
825 while (!map [v2] [DeltaCol (patCol, dh2)])
826 {
827 dh2++;
828 }
829
830 kernel.Add (dng_point (dv2, dh1),
831 LinearWeight1 (dh1, dh2) * w2);
832
833 kernel.Add (dng_point (dv2, dh2),
834 LinearWeight2 (dh1, dh2) * w2);
835
836 dh1 = 0;
837 dh2 = 0;
838
839 while (!mapH [DeltaCol (patCol, dh1)])
840 {
841 dh1--;
842 }
843
844 while (!mapH [DeltaCol (patCol, dh2)])
845 {
846 dh2++;
847 }
848
849 w1 = LinearWeight1 (dh1, dh2) * 0.5f;
850 w2 = LinearWeight2 (dh1, dh2) * 0.5f;
851
852 int32 h1 = DeltaCol (patCol, dh1);
853 int32 h2 = DeltaCol (patCol, dh2);
854
855 dv1 = 0;
856 dv2 = 0;
857
858 while (!map [DeltaRow (patRow, dv1)] [h1])
859 {
860 dv1--;
861 }
862
863 while (!map [DeltaRow (patRow, dv2)] [h1])
864 {
865 dv2++;
866 }
867
868 kernel.Add (dng_point (dv1, dh1),
869 LinearWeight1 (dv1, dv2) * w1);
870
871 kernel.Add (dng_point (dv2, dh1),
872 LinearWeight2 (dv1, dv2) * w1);
873
874 dv1 = 0;
875 dv2 = 0;
876
877 while (!map [DeltaRow (patRow, dv1)] [h2])
878 {
879 dv1--;
880 }
881
882 while (!map [DeltaRow (patRow, dv2)] [h2])
883 {
884 dv2++;
885 }
886
887 kernel.Add (dng_point (dv1, dh2),
888 LinearWeight1 (dv1, dv2) * w2);
889
890 kernel.Add (dng_point (dv2, dh2),
891 LinearWeight2 (dv1, dv2) * w2);
892
893 }
894
895 }
896
897 // Deal with temp scale case.
898
899 if (tempScale == dng_point (2, 2))
900 {
901
902 fPatRows /= tempScale.v;
903 fPatCols /= tempScale.h;
904
905 for (patRow = 0; patRow < fPatRows; patRow++)
906 {
907
908 for (patCol = 0; patCol < fPatCols; patCol++)
909 {
910
911 int32 patRow2 = patRow << 1;
912 int32 patCol2 = patCol << 1;
913
914 dng_bilinear_kernel &kernel = fKernel [patRow2] [patCol2];
915
916 for (j = 0; j < kernel.fCount; j++)
917 {
918
919 int32 x = patRow2 + kernel.fDelta [j].v;
920
921 if ((x & 3) != 0)
922 {
923 x = (x & ~3) + 2;
924 }
925
926 kernel.fDelta [j].v = ((x - patRow2) >> 1);
927
928 x = patCol2 + kernel.fDelta [j].h;
929
930 if ((x & 3) != 0)
931 {
932 x = (x & ~3) + 2;
933 }
934
935 kernel.fDelta [j].h = ((x - patCol2) >> 1);
936
937 }
938
939 kernel.Finalize (fScale,
940 patRow,
941 patCol,
942 rowStep,
943 colStep);
944
945 fCounts [patRow] [patCol] = kernel.fCount;
946 fOffsets [patRow] [patCol] = kernel.fOffset;
947 fWeights16 [patRow] [patCol] = kernel.fWeight16;
948 fWeights32 [patRow] [patCol] = kernel.fWeight32;
949
950 }
951
952 }
953
954 }
955
956 // Non-temp scale case.
957
958 else
959 {
960
961 for (patRow = 0; patRow < fPatRows; patRow++)
962 {
963
964 for (patCol = 0; patCol < fPatCols; patCol++)
965 {
966
967 dng_bilinear_kernel &kernel = fKernel [patRow] [patCol];
968
969 kernel.Finalize (fScale,
970 patRow,
971 patCol,
972 rowStep,
973 colStep);
974
975 fCounts [patRow] [patCol] = kernel.fCount;
976 fOffsets [patRow] [patCol] = kernel.fOffset;
977 fWeights16 [patRow] [patCol] = kernel.fWeight16;
978 fWeights32 [patRow] [patCol] = kernel.fWeight32;
979
980 }
981
982 }
983
984 }
985
986 }
987
988/*****************************************************************************/
989
990class dng_bilinear_interpolator
991 {
992
993 private:
994
995 dng_bilinear_pattern fPattern [kMaxColorPlanes];
996
997 public:
998
999 dng_bilinear_interpolator (const dng_mosaic_info &info,
1000 int32 rowStep,
1001 int32 colStep);
1002
1003 void Interpolate (dng_pixel_buffer &srcBuffer,
1004 dng_pixel_buffer &dstBuffer);
1005
1006 };
1007
1008/*****************************************************************************/
1009
1010dng_bilinear_interpolator::dng_bilinear_interpolator (const dng_mosaic_info &info,
1011 int32 rowStep,
1012 int32 colStep)
1013 {
1014
1015 for (uint32 dstPlane = 0; dstPlane < info.fColorPlanes; dstPlane++)
1016 {
1017
1018 fPattern [dstPlane] . Calculate (info,
1019 dstPlane,
1020 rowStep,
1021 colStep);
1022
1023 }
1024
1025 }
1026
1027/*****************************************************************************/
1028
1029void dng_bilinear_interpolator::Interpolate (dng_pixel_buffer &srcBuffer,
1030 dng_pixel_buffer &dstBuffer)
1031 {
1032
1033 uint32 patCols = fPattern [0] . fPatCols;
1034 uint32 patRows = fPattern [0] . fPatRows;
1035
1036 dng_point scale = fPattern [0] . fScale;
1037
1038 uint32 sRowShift = scale.v - 1;
1039 uint32 sColShift = scale.h - 1;
1040
1041 int32 dstCol = dstBuffer.fArea.l;
1042
1043 int32 srcCol = dstCol >> sColShift;
1044
1045 uint32 patPhase = dstCol % patCols;
1046
1047 for (int32 dstRow = dstBuffer.fArea.t;
1048 dstRow < dstBuffer.fArea.b;
1049 dstRow++)
1050 {
1051
1052 int32 srcRow = dstRow >> sRowShift;
1053
1054 uint32 patRow = dstRow % patRows;
1055
1056 for (uint32 dstPlane = 0;
1057 dstPlane < dstBuffer.fPlanes;
1058 dstPlane++)
1059 {
1060
1061 const void *sPtr = srcBuffer.ConstPixel (srcRow,
1062 srcCol,
1063 srcBuffer.fPlane);
1064
1065 void *dPtr = dstBuffer.DirtyPixel (dstRow,
1066 dstCol,
1067 dstPlane);
1068
1069 if (dstBuffer.fPixelType == ttShort)
1070 {
1071
1072 DoBilinearRow16 ((const uint16 *) sPtr,
1073 (uint16 *) dPtr,
1074 dstBuffer.fArea.W (),
1075 patPhase,
1076 patCols,
1077 fPattern [dstPlane].fCounts [patRow],
1078 fPattern [dstPlane].fOffsets [patRow],
1079 fPattern [dstPlane].fWeights16 [patRow],
1080 sColShift);
1081
1082 }
1083
1084 else
1085 {
1086
1087 DoBilinearRow32 ((const real32 *) sPtr,
1088 (real32 *) dPtr,
1089 dstBuffer.fArea.W (),
1090 patPhase,
1091 patCols,
1092 fPattern [dstPlane].fCounts [patRow],
1093 fPattern [dstPlane].fOffsets [patRow],
1094 fPattern [dstPlane].fWeights32 [patRow],
1095 sColShift);
1096
1097 }
1098
1099 }
1100
1101 }
1102
1103 }
1104
1105/*****************************************************************************/
1106
1107class dng_fast_interpolator: public dng_filter_task
1108 {
1109
1110 protected:
1111
1112 const dng_mosaic_info &fInfo;
1113
1114 dng_point fDownScale;
1115
1116 uint32 fFilterColor [kMaxCFAPattern] [kMaxCFAPattern];
1117
1118 public:
1119
1120 dng_fast_interpolator (const dng_mosaic_info &info,
1121 const dng_image &srcImage,
1122 dng_image &dstImage,
1123 const dng_point &downScale,
1124 uint32 srcPlane);
1125
1126 virtual dng_rect SrcArea (const dng_rect &dstArea);
1127
1128 virtual void ProcessArea (uint32 threadIndex,
1129 dng_pixel_buffer &srcBuffer,
1130 dng_pixel_buffer &dstBuffer);
1131
1132 };
1133
1134/*****************************************************************************/
1135
1136dng_fast_interpolator::dng_fast_interpolator (const dng_mosaic_info &info,
1137 const dng_image &srcImage,
1138 dng_image &dstImage,
1139 const dng_point &downScale,
1140 uint32 srcPlane)
1141
1142 : dng_filter_task (srcImage,
1143 dstImage)
1144
1145 , fInfo (info )
1146 , fDownScale (downScale)
1147
1148 {
1149
1150 fSrcPlane = srcPlane;
1151 fSrcPlanes = 1;
1152
1153 fSrcPixelType = ttShort;
1154 fDstPixelType = ttShort;
1155
1156 fSrcRepeat = fInfo.fCFAPatternSize;
1157
1158 fUnitCell = fInfo.fCFAPatternSize;
1159
1160 fMaxTileSize = dng_point (256 / fDownScale.v,
1161 256 / fDownScale.h);
1162
1163 fMaxTileSize.h = Max_int32 (fMaxTileSize.h, fUnitCell.h);
1164 fMaxTileSize.v = Max_int32 (fMaxTileSize.v, fUnitCell.v);
1165
1166 // Find color map.
1167
1168 {
1169
1170 for (int32 r = 0; r < fInfo.fCFAPatternSize.v; r++)
1171 {
1172
1173 for (int32 c = 0; c < fInfo.fCFAPatternSize.h; c++)
1174 {
1175
1176 uint8 key = fInfo.fCFAPattern [r] [c];
1177
1178 for (uint32 index = 0; index < fInfo.fColorPlanes; index++)
1179 {
1180
1181 if (key == fInfo.fCFAPlaneColor [index])
1182 {
1183
1184 fFilterColor [r] [c] = index;
1185
1186 break;
1187
1188 }
1189
1190 }
1191
1192 }
1193
1194 }
1195
1196 }
1197
1198 }
1199
1200/*****************************************************************************/
1201
1202dng_rect dng_fast_interpolator::SrcArea (const dng_rect &dstArea)
1203 {
1204
1205 return dng_rect (dstArea.t * fDownScale.v,
1206 dstArea.l * fDownScale.h,
1207 dstArea.b * fDownScale.v,
1208 dstArea.r * fDownScale.h);
1209
1210 }
1211
1212/*****************************************************************************/
1213
1214void dng_fast_interpolator::ProcessArea (uint32 /* threadIndex */,
1215 dng_pixel_buffer &srcBuffer,
1216 dng_pixel_buffer &dstBuffer)
1217 {
1218
1219 dng_rect srcArea = srcBuffer.fArea;
1220 dng_rect dstArea = dstBuffer.fArea;
1221
1222 // Downsample buffer.
1223
1224 int32 srcRow = srcArea.t;
1225
1226 uint32 srcRowPhase1 = 0;
1227 uint32 srcRowPhase2 = 0;
1228
1229 uint32 patRows = fInfo.fCFAPatternSize.v;
1230 uint32 patCols = fInfo.fCFAPatternSize.h;
1231
1232 uint32 cellRows = fDownScale.v;
1233 uint32 cellCols = fDownScale.h;
1234
1235 uint32 plane;
1236 uint32 planes = fInfo.fColorPlanes;
1237
1238 int32 dstPlaneStep = dstBuffer.fPlaneStep;
1239
1240 uint32 total [kMaxColorPlanes];
1241 uint32 count [kMaxColorPlanes];
1242
1243 for (plane = 0; plane < planes; plane++)
1244 {
1245 total [plane] = 0;
1246 count [plane] = 0;
1247 }
1248
1249 for (int32 dstRow = dstArea.t; dstRow < dstArea.b; dstRow++)
1250 {
1251
1252 const uint16 *sPtr = srcBuffer.ConstPixel_uint16 (srcRow,
1253 srcArea.l,
1254 fSrcPlane);
1255
1256 uint16 *dPtr = dstBuffer.DirtyPixel_uint16 (dstRow,
1257 dstArea.l,
1258 0);
1259
1260 uint32 srcColPhase1 = 0;
1261 uint32 srcColPhase2 = 0;
1262
1263 for (int32 dstCol = dstArea.l; dstCol < dstArea.r; dstCol++)
1264 {
1265
1266 const uint16 *ssPtr = sPtr;
1267
1268 srcRowPhase2 = srcRowPhase1;
1269
1270 for (uint32 cellRow = 0; cellRow < cellRows; cellRow++)
1271 {
1272
1273 const uint32 *filterRow = fFilterColor [srcRowPhase2];
1274
1275 if (++srcRowPhase2 == patRows)
1276 {
1277 srcRowPhase2 = 0;
1278 }
1279
1280 srcColPhase2 = srcColPhase1;
1281
1282 for (uint32 cellCol = 0; cellCol < cellCols; cellCol++)
1283 {
1284
1285 uint32 color = filterRow [srcColPhase2];
1286
1287 if (++srcColPhase2 == patCols)
1288 {
1289 srcColPhase2 = 0;
1290 }
1291
1292 total [color] += (uint32) ssPtr [cellCol];
1293 count [color] ++;
1294
1295 }
1296
1297 ssPtr += srcBuffer.fRowStep;
1298
1299 }
1300
1301 for (plane = 0; plane < planes; plane++)
1302 {
1303
1304 uint32 t = total [plane];
1305 uint32 c = count [plane];
1306
1307 dPtr [plane * dstPlaneStep] = (uint16) ((t + (c >> 1)) / c);
1308
1309 total [plane] = 0;
1310 count [plane] = 0;
1311
1312 }
1313
1314 srcColPhase1 = srcColPhase2;
1315
1316 sPtr += cellCols;
1317
1318 dPtr ++;
1319
1320 }
1321
1322 srcRowPhase1 = srcRowPhase2;
1323
1324 srcRow += cellRows;
1325
1326 }
1327
1328 }
1329
1330/*****************************************************************************/
1331
1332dng_mosaic_info::dng_mosaic_info ()
1333
1334 : fCFAPatternSize ()
1335 , fColorPlanes (0)
1336 , fCFALayout (1)
1337 , fBayerGreenSplit (0)
1338 , fSrcSize ()
1339 , fCroppedSize ()
1340 , fAspectRatio (1.0)
1341
1342 {
1343
1344 }
1345
1346/*****************************************************************************/
1347
1348dng_mosaic_info::~dng_mosaic_info ()
1349 {
1350
1351 }
1352
1353/*****************************************************************************/
1354
1355void dng_mosaic_info::Parse (dng_host & /* host */,
1356 dng_stream & /* stream */,
1357 dng_info &info)
1358 {
1359
1360 // Find main image IFD.
1361
1362 dng_ifd &rawIFD = *info.fIFD [info.fMainIndex].Get ();
1363
1364 // This information only applies to CFA images.
1365
1366 if (rawIFD.fPhotometricInterpretation != piCFA)
1367 {
1368 return;
1369 }
1370
1371 // Copy CFA pattern.
1372
1373 fCFAPatternSize.v = rawIFD.fCFARepeatPatternRows;
1374 fCFAPatternSize.h = rawIFD.fCFARepeatPatternCols;
1375
1376 for (int32 j = 0; j < fCFAPatternSize.v; j++)
1377 {
1378 for (int32 k = 0; k < fCFAPatternSize.h; k++)
1379 {
1380 fCFAPattern [j] [k] = rawIFD.fCFAPattern [j] [k];
1381 }
1382 }
1383
1384 // Copy CFA plane information.
1385
1386 fColorPlanes = info.fShared->fCameraProfile.fColorPlanes;
1387
1388 for (uint32 n = 0; n < fColorPlanes; n++)
1389 {
1390 fCFAPlaneColor [n] = rawIFD.fCFAPlaneColor [n];
1391 }
1392
1393 // Copy CFA layout information.
1394
1395 fCFALayout = rawIFD.fCFALayout;
1396
1397 // Green split value for Bayer patterns.
1398
1399 fBayerGreenSplit = rawIFD.fBayerGreenSplit;
1400
1401 }
1402
1403/*****************************************************************************/
1404
1405void dng_mosaic_info::PostParse (dng_host & /* host */,
1406 dng_negative &negative)
1407 {
1408
1409 // Keep track of source image size.
1410
1411 fSrcSize = negative.Stage2Image ()->Size ();
1412
1413 // Default cropped size.
1414
1415 fCroppedSize.v = Round_int32 (negative.DefaultCropSizeV ().As_real64 ());
1416 fCroppedSize.h = Round_int32 (negative.DefaultCropSizeH ().As_real64 ());
1417
1418 // Pixel aspect ratio.
1419
1420 fAspectRatio = negative.DefaultScaleH ().As_real64 () /
1421 negative.DefaultScaleV ().As_real64 ();
1422
1423 }
1424
1425/*****************************************************************************/
1426
1427bool dng_mosaic_info::SetFourColorBayer ()
1428 {
1429
1430 if (fCFAPatternSize != dng_point (2, 2))
1431 {
1432 return false;
1433 }
1434
1435 if (fColorPlanes != 3)
1436 {
1437 return false;
1438 }
1439
1440 uint8 color0 = fCFAPlaneColor [0];
1441 uint8 color1 = fCFAPlaneColor [1];
1442 uint8 color2 = fCFAPlaneColor [2];
1443
1444 // Look for color 1 repeated twice in a diagonal.
1445
1446 if ((fCFAPattern [0] [0] == color1 && fCFAPattern [1] [1] == color1) ||
1447 (fCFAPattern [0] [1] == color1 && fCFAPattern [1] [0] == color1))
1448 {
1449
1450 // OK, this looks like a Bayer pattern.
1451
1452 // Find unused color code.
1453
1454 uint8 color3 = 0;
1455
1456 while (color3 == color0 ||
1457 color3 == color1 ||
1458 color3 == color2)
1459 {
1460 color3++;
1461 }
1462
1463 // Switch the four color mosaic.
1464
1465 fColorPlanes = 4;
1466
1467 fCFAPlaneColor [3] = color3;
1468
1469 // Replace the "green" in the "blue" rows with the new color.
1470
1471 if (fCFAPattern [0] [0] == color0)
1472 {
1473 fCFAPattern [1] [0] = color3;
1474 }
1475
1476 else if (fCFAPattern [0] [1] == color0)
1477 {
1478 fCFAPattern [1] [1] = color3;
1479 }
1480
1481 else if (fCFAPattern [1] [0] == color0)
1482 {
1483 fCFAPattern [0] [0] = color3;
1484 }
1485
1486 else
1487 {
1488 fCFAPattern [0] [1] = color3;
1489 }
1490
1491 return true;
1492
1493 }
1494
1495 return false;
1496
1497 }
1498
1499/*****************************************************************************/
1500
1501dng_point dng_mosaic_info::FullScale () const
1502 {
1503
1504 switch (fCFALayout)
1505 {
1506
1507 // Staggered layouts with offset columns double the row count
1508 // during interpolation.
1509
1510 case 2:
1511 case 3:
1512 return dng_point (2, 1);
1513
1514 // Staggered layouts with offset rows double the column count
1515 // during interpolation.
1516
1517 case 4:
1518 case 5:
1519 return dng_point (1, 2);
1520
1521 // Otherwise there is no size change during interpolation.
1522
1523 default:
1524 break;
1525
1526 }
1527
1528 return dng_point (1, 1);
1529
1530 }
1531
1532/*****************************************************************************/
1533
1534bool dng_mosaic_info::IsSafeDownScale (const dng_point &downScale) const
1535 {
1536
1537 if (downScale.v >= fCFAPatternSize.v &&
1538 downScale.h >= fCFAPatternSize.h)
1539 {
1540
1541 return true;
1542
1543 }
1544
1545 dng_point test;
1546
1547 test.v = Min_int32 (downScale.v, fCFAPatternSize.v);
1548 test.h = Min_int32 (downScale.h, fCFAPatternSize.h);
1549
1550 for (int32 phaseV = 0; phaseV <= fCFAPatternSize.v - test.v; phaseV++)
1551 {
1552
1553 for (int32 phaseH = 0; phaseH <= fCFAPatternSize.h - test.h; phaseH++)
1554 {
1555
1556 uint32 plane;
1557
1558 bool contains [kMaxColorPlanes];
1559
1560 for (plane = 0; plane < fColorPlanes; plane++)
1561 {
1562
1563 contains [plane] = false;
1564
1565 }
1566
1567 for (int32 srcRow = 0; srcRow < test.v; srcRow++)
1568 {
1569
1570 for (int32 srcCol = 0; srcCol < test.h; srcCol++)
1571 {
1572
1573 uint8 srcKey = fCFAPattern [srcRow + phaseV]
1574 [srcCol + phaseH];
1575
1576 for (plane = 0; plane < fColorPlanes; plane++)
1577 {
1578
1579 if (srcKey == fCFAPlaneColor [plane])
1580 {
1581
1582 contains [plane] = true;
1583
1584 }
1585
1586 }
1587
1588
1589 }
1590
1591 }
1592
1593 for (plane = 0; plane < fColorPlanes; plane++)
1594 {
1595
1596 if (!contains [plane])
1597 {
1598
1599 return false;
1600
1601 }
1602
1603 }
1604
1605 }
1606
1607 }
1608
1609 return true;
1610
1611 }
1612
1613/*****************************************************************************/
1614
1615uint32 dng_mosaic_info::SizeForDownScale (const dng_point &downScale) const
1616 {
1617
1618 uint32 sizeV = Max_uint32 (1, (fCroppedSize.v + (downScale.v >> 1)) / downScale.v);
1619 uint32 sizeH = Max_uint32 (1, (fCroppedSize.h + (downScale.h >> 1)) / downScale.h);
1620
1621 return Max_int32 (sizeV, sizeH);
1622
1623 }
1624
1625/*****************************************************************************/
1626
1627bool dng_mosaic_info::ValidSizeDownScale (const dng_point &downScale,
1628 uint32 minSize) const
1629 {
1630
1631 const int32 kMaxDownScale = 64;
1632
1633 if (downScale.h > kMaxDownScale ||
1634 downScale.v > kMaxDownScale)
1635 {
1636
1637 return false;
1638
1639 }
1640
1641 return SizeForDownScale (downScale) >= minSize;
1642
1643 }
1644
1645/*****************************************************************************/
1646
1647dng_point dng_mosaic_info::DownScale (uint32 minSize,
1648 uint32 prefSize,
1649 real64 cropFactor) const
1650 {
1651
1652 dng_point bestScale (1, 1);
1653
1654 if (prefSize && IsColorFilterArray ())
1655 {
1656
1657 // Adjust sizes for crop factor.
1658
1659 minSize = Round_uint32 (minSize / cropFactor);
1660 prefSize = Round_uint32 (prefSize / cropFactor);
1661
1662 prefSize = Max_uint32 (prefSize, minSize);
1663
1664 // Start by assuming we need the full size image.
1665
1666 int32 bestSize = SizeForDownScale (bestScale);
1667
1668 // Find size of nearly square cell.
1669
1670 dng_point squareCell (1, 1);
1671
1672 if (fAspectRatio < 1.0 / 1.8)
1673 {
1674
1675 squareCell.h = Min_int32 (4, Round_int32 (1.0 / fAspectRatio));
1676
1677 }
1678
1679 if (fAspectRatio > 1.8)
1680 {
1681
1682 squareCell.v = Min_int32 (4, Round_int32 (fAspectRatio));
1683
1684 }
1685
1686 // Find minimum safe cell size.
1687
1688 dng_point testScale = squareCell;
1689
1690 while (!IsSafeDownScale (testScale))
1691 {
1692
1693 testScale.v += squareCell.v;
1694 testScale.h += squareCell.h;
1695
1696 }
1697
1698 // See if this scale is usable.
1699
1700 if (!ValidSizeDownScale (testScale, minSize))
1701 {
1702
1703 // We cannot downsample at all...
1704
1705 return bestScale;
1706
1707 }
1708
1709 // See if this is closer to the preferred size.
1710
1711 int32 testSize = SizeForDownScale (testScale);
1712
1713 if (Abs_int32 (testSize - (int32) prefSize) <=
1714 Abs_int32 (bestSize - (int32) prefSize))
1715 {
1716 bestScale = testScale;
1717 bestSize = testSize;
1718 }
1719
1720 else
1721 {
1722 return bestScale;
1723 }
1724
1725 // Now keep adding square cells as long as possible.
1726
1727 while (true)
1728 {
1729
1730 testScale.v += squareCell.v;
1731 testScale.h += squareCell.h;
1732
1733 if (IsSafeDownScale (testScale))
1734 {
1735
1736 if (!ValidSizeDownScale (testScale, minSize))
1737 {
1738 return bestScale;
1739 }
1740
1741 // See if this is closer to the preferred size.
1742
1743 testSize = SizeForDownScale (testScale);
1744
1745 if (Abs_int32 (testSize - (int32) prefSize) <=
1746 Abs_int32 (bestSize - (int32) prefSize))
1747 {
1748 bestScale = testScale;
1749 bestSize = testSize;
1750 }
1751
1752 else
1753 {
1754 return bestScale;
1755 }
1756
1757 }
1758
1759 }
1760
1761 }
1762
1763 return bestScale;
1764
1765 }
1766
1767/*****************************************************************************/
1768
1769dng_point dng_mosaic_info::DstSize (const dng_point &downScale) const
1770 {
1771
1772 if (downScale == dng_point (1, 1))
1773 {
1774
1775 dng_point scale = FullScale ();
1776
1777 return dng_point (fSrcSize.v * scale.v,
1778 fSrcSize.h * scale.h);
1779
1780 }
1781
1782 const int32 kMaxDownScale = 64;
1783
1784 if (downScale.h > kMaxDownScale ||
1785 downScale.v > kMaxDownScale)
1786 {
1787
1788 return dng_point (0, 0);
1789
1790 }
1791
1792 dng_point size;
1793
1794 size.v = Max_int32 (1, (fSrcSize.v + (downScale.v >> 1)) / downScale.v);
1795 size.h = Max_int32 (1, (fSrcSize.h + (downScale.h >> 1)) / downScale.h);
1796
1797 return size;
1798
1799 }
1800
1801/*****************************************************************************/
1802
1803void dng_mosaic_info::InterpolateGeneric (dng_host &host,
1804 dng_negative & /* negative */,
1805 const dng_image &srcImage,
1806 dng_image &dstImage,
1807 uint32 srcPlane) const
1808 {
1809
1810 // Find destination to source bit shifts.
1811
1812 dng_point scale = FullScale ();
1813
1814 uint32 srcShiftV = scale.v - 1;
1815 uint32 srcShiftH = scale.h - 1;
1816
1817 // Find tile sizes.
1818
1819 const uint32 kMaxDstTileRows = 128;
1820 const uint32 kMaxDstTileCols = 128;
1821
1822 dng_point dstTileSize = dstImage.RepeatingTile ().Size ();
1823
1824 dstTileSize.v = Min_int32 (dstTileSize.v, kMaxDstTileRows);
1825 dstTileSize.h = Min_int32 (dstTileSize.h, kMaxDstTileCols);
1826
1827 dng_point srcTileSize = dstTileSize;
1828
1829 srcTileSize.v >>= srcShiftV;
1830 srcTileSize.h >>= srcShiftH;
1831
1832 srcTileSize.v += fCFAPatternSize.v * 2;
1833 srcTileSize.h += fCFAPatternSize.h * 2;
1834
1835 // Allocate source buffer.
1836
1837 dng_pixel_buffer srcBuffer (dng_rect (srcTileSize), srcPlane, 1,
1838 srcImage.PixelType (), pcInterleaved, NULL);
1839
1840 uint32 srcBufferSize = ComputeBufferSize (srcBuffer.fPixelType,
1841 srcTileSize, srcBuffer.fPlanes,
1842 padNone);
1843
1844 AutoPtr<dng_memory_block> srcData (host.Allocate (srcBufferSize));
1845
1846 srcBuffer.fData = srcData->Buffer ();
1847
1848 // Allocate destination buffer.
1849
1850 dng_pixel_buffer dstBuffer (dng_rect (dstTileSize), 0, fColorPlanes,
1851 dstImage.PixelType (), pcRowInterleaved, NULL);
1852
1853 uint32 dstBufferSize = ComputeBufferSize (dstBuffer.fPixelType,
1854 dstTileSize, dstBuffer.fPlanes,
1855 padNone);
1856
1857 AutoPtr<dng_memory_block> dstData (host.Allocate (dstBufferSize));
1858
1859 dstBuffer.fData = dstData->Buffer ();
1860
1861 // Create interpolator.
1862
1863 AutoPtr<dng_bilinear_interpolator> interpolator (new dng_bilinear_interpolator (*this,
1864 srcBuffer.fRowStep,
1865 srcBuffer.fColStep));
1866
1867 // Iterate over destination tiles.
1868
1869 dng_rect dstArea;
1870
1871 dng_tile_iterator iter1 (dstImage, dstImage.Bounds ());
1872
1873 while (iter1.GetOneTile (dstArea))
1874 {
1875
1876 // Break into buffer sized tiles.
1877
1878 dng_rect dstTile;
1879
1880 dng_tile_iterator iter2 (dstTileSize, dstArea);
1881
1882 while (iter2.GetOneTile (dstTile))
1883 {
1884
1885 host.SniffForAbort ();
1886
1887 // Setup buffers for this tile.
1888
1889 dng_rect srcTile (dstTile);
1890
1891 srcTile.t >>= srcShiftV;
1892 srcTile.b >>= srcShiftV;
1893
1894 srcTile.l >>= srcShiftH;
1895 srcTile.r >>= srcShiftH;
1896
1897 srcTile.t -= fCFAPatternSize.v;
1898 srcTile.b += fCFAPatternSize.v;
1899
1900 srcTile.l -= fCFAPatternSize.h;
1901 srcTile.r += fCFAPatternSize.h;
1902
1903 srcBuffer.fArea = srcTile;
1904 dstBuffer.fArea = dstTile;
1905
1906 // Get source data.
1907
1908 srcImage.Get (srcBuffer,
1909 dng_image::edge_repeat,
1910 fCFAPatternSize.v,
1911 fCFAPatternSize.h);
1912
1913 // Process data.
1914
1915 interpolator->Interpolate (srcBuffer,
1916 dstBuffer);
1917
1918 // Save results.
1919
1920 dstImage.Put (dstBuffer);
1921
1922 }
1923
1924 }
1925
1926 }
1927
1928/*****************************************************************************/
1929
1930void dng_mosaic_info::InterpolateFast (dng_host &host,
1931 dng_negative & /* negative */,
1932 const dng_image &srcImage,
1933 dng_image &dstImage,
1934 const dng_point &downScale,
1935 uint32 srcPlane) const
1936 {
1937
1938 // Create fast interpolator task.
1939
1940 dng_fast_interpolator interpolator (*this,
1941 srcImage,
1942 dstImage,
1943 downScale,
1944 srcPlane);
1945
1946 // Find area to process.
1947
1948 dng_rect bounds = dstImage.Bounds ();
1949
1950 // Do the interpolation.
1951
1952 host.PerformAreaTask (interpolator,
1953 bounds);
1954
1955 }
1956
1957/*****************************************************************************/
1958
1959void dng_mosaic_info::Interpolate (dng_host &host,
1960 dng_negative &negative,
1961 const dng_image &srcImage,
1962 dng_image &dstImage,
1963 const dng_point &downScale,
1964 uint32 srcPlane) const
1965 {
1966
1967 if (downScale == dng_point (1, 1))
1968 {
1969
1970 InterpolateGeneric (host,
1971 negative,
1972 srcImage,
1973 dstImage,
1974 srcPlane);
1975
1976 }
1977
1978 else
1979 {
1980
1981 InterpolateFast (host,
1982 negative,
1983 srcImage,
1984 dstImage,
1985 downScale,
1986 srcPlane);
1987
1988 }
1989
1990 }
1991
1992/*****************************************************************************/
1993