Home | History | Annotate | Download | only in source
      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 
     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 
     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 
    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 
    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 
    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 
   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 
   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 
   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 
   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 
   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 
   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 
   1348 dng_mosaic_info::~dng_mosaic_info ()
   1349 	{
   1350 
   1351 	}
   1352 
   1353 /*****************************************************************************/
   1354 
   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 
   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 
   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 
   1501 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 
   1534 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 
   1615 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 
   1627 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 
   1647 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 
   1769 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 
   1803 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 
   1930 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 
   1959 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