Coverage Report

Created: 2026-10-27 07:06

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