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