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 
38 class 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 
dng_bilinear_kernel()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 
Add(const dng_point & delta,real32 weight)77 void 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 
Finalize(const dng_point & scale,uint32 patRow,uint32 patCol,int32 rowStep,int32 colStep)118 void 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 
246 class 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 
dng_bilinear_pattern()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
DeltaRow(uint32 row,int32 delta)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
DeltaCol(uint32 col,int32 delta)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 
LinearWeight1(int32 d1,int32 d2)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 
LinearWeight2(int32 d1,int32 d2)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 
Calculate(const dng_mosaic_info & info,uint32 dstPlane,int32 rowStep,int32 colStep)340 void 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 
990 class 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 
dng_bilinear_interpolator(const dng_mosaic_info & info,int32 rowStep,int32 colStep)1010 dng_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 
Interpolate(dng_pixel_buffer & srcBuffer,dng_pixel_buffer & dstBuffer)1029 void 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 
1107 class 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 
dng_fast_interpolator(const dng_mosaic_info & info,const dng_image & srcImage,dng_image & dstImage,const dng_point & downScale,uint32 srcPlane)1136 dng_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 
SrcArea(const dng_rect & dstArea)1202 dng_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 
ProcessArea(uint32,dng_pixel_buffer & srcBuffer,dng_pixel_buffer & dstBuffer)1214 void 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 
dng_mosaic_info()1332 dng_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 
~dng_mosaic_info()1348 dng_mosaic_info::~dng_mosaic_info ()
1349 	{
1350 
1351 	}
1352 
1353 /*****************************************************************************/
1354 
Parse(dng_host &,dng_stream &,dng_info & info)1355 void 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 
PostParse(dng_host &,dng_negative & negative)1405 void 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 
SetFourColorBayer()1427 bool 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 
FullScale() const1501 dng_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 
IsSafeDownScale(const dng_point & downScale) const1534 bool 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 
SizeForDownScale(const dng_point & downScale) const1615 uint32 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 
ValidSizeDownScale(const dng_point & downScale,uint32 minSize) const1627 bool 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 
DownScale(uint32 minSize,uint32 prefSize,real64 cropFactor) const1647 dng_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 
DstSize(const dng_point & downScale) const1769 dng_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 
InterpolateGeneric(dng_host & host,dng_negative &,const dng_image & srcImage,dng_image & dstImage,uint32 srcPlane) const1803 void 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 
InterpolateFast(dng_host & host,dng_negative &,const dng_image & srcImage,dng_image & dstImage,const dng_point & downScale,uint32 srcPlane) const1930 void 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 
Interpolate(dng_host & host,dng_negative & negative,const dng_image & srcImage,dng_image & dstImage,const dng_point & downScale,uint32 srcPlane) const1959 void 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