Coverage Report

Created: 2026-09-04 07:10

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