Coverage Report

Created: 2021-08-22 09:07

/src/skia/third_party/externals/dng_sdk/source/dng_lens_correction.cpp
Line
Count
Source (jump to first uncovered line)
1
/*****************************************************************************/
2
// Copyright 2008 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_lens_correction.cpp#1 $ */ 
10
/* $DateTime: 2012/05/30 13:28:51 $ */
11
/* $Change: 832332 $ */
12
/* $Author: tknoll $ */
13
14
/*****************************************************************************/
15
16
#include <cfloat>
17
#include <limits.h>
18
19
#include "dng_1d_table.h"
20
#include "dng_assertions.h"
21
#include "dng_bottlenecks.h"
22
#include "dng_exceptions.h"
23
#include "dng_filter_task.h"
24
#include "dng_globals.h"
25
#include "dng_host.h"
26
#include "dng_image.h"
27
#include "dng_lens_correction.h"
28
#include "dng_negative.h"
29
#include "dng_safe_arithmetic.h"
30
#include "dng_sdk_limits.h"
31
#include "dng_tag_values.h"
32
#include "dng_utils.h"
33
34
/*****************************************************************************/
35
36
dng_warp_params::dng_warp_params ()
37
38
  : fPlanes (1)
39
  , fCenter (0.5, 0.5)
40
41
0
  {
42
43
0
  }
44
45
/*****************************************************************************/
46
47
dng_warp_params::dng_warp_params (uint32 planes,
48
                  const dng_point_real64 &center)
49
50
  : fPlanes (planes)
51
  , fCenter (center)
52
53
0
  {
54
  
55
0
  DNG_ASSERT (planes >= 1,         "Too few planes." );
56
0
  DNG_ASSERT (planes <= kMaxColorPlanes, "Too many planes.");
57
58
0
  DNG_ASSERT (fCenter.h >= 0.0 && fCenter.h <= 1.0, 
59
0
        "Center (horizontal) out of range.");
60
61
0
  DNG_ASSERT (fCenter.v >= 0.0 && fCenter.v <= 1.0, 
62
0
        "Center (vertical) out of range.");
63
64
0
  }
65
66
/*****************************************************************************/
67
68
dng_warp_params::~dng_warp_params ()
69
0
  {
70
  
71
0
  }
72
73
/*****************************************************************************/
74
75
bool dng_warp_params::IsNOPAll () const
76
0
  {
77
78
0
  return IsRadNOPAll () && 
79
0
       IsTanNOPAll ();
80
  
81
0
  }
82
83
/*****************************************************************************/
84
85
bool dng_warp_params::IsNOP (uint32 plane) const
86
0
  {
87
88
0
  return IsRadNOP (plane) &&
89
0
       IsTanNOP (plane);
90
91
0
  }
92
93
/*****************************************************************************/
94
95
bool dng_warp_params::IsRadNOPAll () const
96
0
  {
97
  
98
0
  for (uint32 plane = 0; plane < fPlanes; plane++)
99
0
    {
100
    
101
0
    if (!IsRadNOP (plane))
102
0
      {
103
0
      return false;
104
0
      }
105
    
106
0
    }
107
108
0
  return true;
109
  
110
0
  }
111
112
/*****************************************************************************/
113
114
bool dng_warp_params::IsRadNOP (uint32 /* plane */) const
115
0
  {
116
117
0
  return false;
118
119
0
  }
120
121
/*****************************************************************************/
122
123
bool dng_warp_params::IsTanNOPAll () const
124
0
  {
125
  
126
0
  for (uint32 plane = 0; plane < fPlanes; plane++)
127
0
    {
128
    
129
0
    if (!IsTanNOP (plane))
130
0
      {
131
0
      return false;
132
0
      }
133
    
134
0
    }
135
136
0
  return true;
137
  
138
0
  }
139
140
/*****************************************************************************/
141
142
bool dng_warp_params::IsTanNOP (uint32 /* plane */) const
143
0
  {
144
145
0
  return false;
146
147
0
  }
148
149
/*****************************************************************************/
150
151
bool dng_warp_params::IsValid () const
152
0
  {
153
154
0
  if (fPlanes < 1 || fPlanes > kMaxColorPlanes)
155
0
    {
156
157
0
    return false;
158
159
0
    }
160
161
0
  if (fCenter.h < 0.0 || 
162
0
    fCenter.h > 1.0 ||
163
0
    fCenter.v < 0.0 ||
164
0
    fCenter.v > 1.0)
165
0
    {
166
167
0
    return false;
168
169
0
    }
170
171
0
  return true;
172
173
0
  }
174
175
/*****************************************************************************/
176
177
bool dng_warp_params::IsValidForNegative (const dng_negative &negative) const
178
0
  {
179
180
0
  if (!IsValid ())
181
0
    {
182
0
    return false;
183
0
    }
184
  
185
0
  if ((fPlanes != 1) &&
186
0
    (fPlanes != negative.ColorChannels ()))
187
0
    {
188
0
    return false;
189
0
    }
190
191
0
  return true;
192
193
0
  }
194
195
/*****************************************************************************/
196
197
real64 dng_warp_params::EvaluateInverse (uint32 plane,
198
                     real64 y) const
199
0
  {
200
  
201
0
  const uint32 kMaxIterations = 30;
202
0
  const real64 kNearZero    = 1.0e-10;
203
  
204
0
  real64 x0 = 0.0;
205
0
  real64 y0 = Evaluate (plane,
206
0
              x0);
207
  
208
0
  real64 x1 = 1.0;
209
0
  real64 y1 = Evaluate (plane,
210
0
              x1);
211
  
212
0
  for (uint32 iteration = 0; iteration < kMaxIterations; iteration++)   
213
0
    {
214
    
215
0
    if (Abs_real64 (y1 - y0) < kNearZero)
216
0
      {
217
0
      break;
218
0
      }
219
    
220
0
    const real64 x2 = Pin_real64 (0.0, 
221
0
                    x1 + (y - y1) * (x1 - x0) / (y1 - y0),
222
0
                    1.0);
223
    
224
0
    const real64 y2 = Evaluate (plane,
225
0
                  x2);
226
    
227
0
    x0 = x1;
228
0
    y0 = y1;
229
    
230
0
    x1 = x2;
231
0
    y1 = y2;
232
    
233
0
    }
234
  
235
0
  return x1;
236
  
237
0
  }
238
239
/*****************************************************************************/
240
241
dng_point_real64 dng_warp_params::EvaluateTangential2 (uint32 plane,
242
                             const dng_point_real64 &diff) const
243
0
  {
244
  
245
0
  const real64 dvdv = diff.v * diff.v;
246
0
  const real64 dhdh = diff.h * diff.h;
247
248
0
  const real64 rr = dvdv + dhdh;
249
250
0
  dng_point_real64 diffSqr (dvdv,
251
0
                dhdh);
252
253
0
  return EvaluateTangential (plane,
254
0
                 rr,
255
0
                 diff,
256
0
                 diffSqr);
257
  
258
0
  }
259
260
/*****************************************************************************/
261
    
262
dng_point_real64 dng_warp_params::EvaluateTangential3 (uint32 plane,
263
                             real64 r2,
264
                             const dng_point_real64 &diff) const
265
0
  {
266
  
267
0
  dng_point_real64 diffSqr (diff.v * diff.v,
268
0
                diff.h * diff.h);
269
270
0
  return EvaluateTangential (plane,
271
0
                 r2,
272
0
                 diff,
273
0
                 diffSqr);
274
  
275
0
  }
276
277
/*****************************************************************************/
278
279
void dng_warp_params::Dump () const
280
0
  {
281
282
  #if qDNGValidate
283
284
  printf ("Planes: %u\n", (unsigned) fPlanes);
285
286
  printf ("  Optical center:\n"
287
      "    h = %.6lf\n"
288
      "    v = %.6lf\n",
289
      fCenter.h,
290
      fCenter.v);
291
292
  #endif
293
  
294
0
  }
295
296
/*****************************************************************************/
297
298
dng_warp_params_rectilinear::dng_warp_params_rectilinear ()
299
300
  : dng_warp_params ()
301
302
0
  {
303
304
0
  for (uint32 plane = 0; plane < kMaxColorPlanes; plane++)
305
0
    {
306
307
0
    fRadParams [plane] = dng_vector (4);
308
0
    fTanParams [plane] = dng_vector (2);
309
310
0
    fRadParams [plane][0] = 1.0;
311
312
0
    }
313
  
314
0
  }
315
316
/*****************************************************************************/
317
318
dng_warp_params_rectilinear::dng_warp_params_rectilinear (uint32 planes,
319
                              const dng_vector radParams [],
320
                              const dng_vector tanParams [],
321
                              const dng_point_real64 &center)
322
323
  : dng_warp_params (planes, 
324
             center)
325
326
0
  {
327
  
328
0
  for (uint32 i = 0; i < fPlanes; i++)
329
0
    {
330
0
    fRadParams [i] = radParams [i];
331
0
    fTanParams [i] = tanParams [i];
332
0
    }
333
  
334
0
  }
335
336
/*****************************************************************************/
337
338
dng_warp_params_rectilinear::~dng_warp_params_rectilinear ()
339
0
  {
340
  
341
0
  }
342
343
/*****************************************************************************/
344
345
bool dng_warp_params_rectilinear::IsRadNOP (uint32 plane) const
346
0
  {
347
  
348
0
  DNG_ASSERT (plane < fPlanes, "plane out of range.");
349
350
0
  const dng_vector &r = fRadParams [plane];
351
352
0
  return (r [0] == 1.0 &&
353
0
      r [1] == 0.0 &&
354
0
      r [2] == 0.0 &&
355
0
      r [3] == 0.0);
356
  
357
0
  }
358
359
/*****************************************************************************/
360
361
bool dng_warp_params_rectilinear::IsTanNOP (uint32 plane) const
362
0
  {
363
  
364
0
  DNG_ASSERT (plane < fPlanes, "plane out of range.");
365
366
0
  const dng_vector &t = fTanParams [plane];
367
368
0
  return (t [0] == 0.0 &&
369
0
      t [1] == 0.0);
370
  
371
0
  }
372
373
/*****************************************************************************/
374
375
bool dng_warp_params_rectilinear::IsValid () const
376
0
  {
377
378
0
  for (uint32 plane = 0; plane < fPlanes; plane++)
379
0
    {
380
    
381
0
    if (fRadParams [plane].Count () != 4)
382
0
      {
383
0
      return false;
384
0
      }
385
    
386
0
    if (fTanParams [plane].Count () < 2)
387
0
      {
388
0
      return false;
389
0
      }
390
    
391
0
    }
392
393
0
  return dng_warp_params::IsValid ();
394
  
395
0
  }
396
397
/*****************************************************************************/
398
399
void dng_warp_params_rectilinear::PropagateToAllPlanes (uint32 totalPlanes)
400
0
  {
401
  
402
0
  for (uint32 plane = fPlanes; plane < totalPlanes; plane++)
403
0
    {
404
405
0
    fRadParams [plane] = fRadParams [0];
406
0
    fTanParams [plane] = fTanParams [0];
407
408
0
    }
409
410
0
  }
411
412
/*****************************************************************************/
413
414
real64 dng_warp_params_rectilinear::Evaluate (uint32 plane,
415
                        real64 x) const
416
0
  {
417
418
0
  const dng_vector &K = fRadParams [plane]; // Coefficients.
419
420
0
  const real64 x2 = x * x;
421
  
422
0
  return x * (K [0] + x2 * (K [1] + x2 * (K [2] + x2 * K [3])));
423
  
424
0
  }
425
426
/*****************************************************************************/
427
428
real64 dng_warp_params_rectilinear::EvaluateRatio (uint32 plane,
429
                           real64 r2) const
430
0
  {
431
  
432
0
  const dng_vector &K = fRadParams [plane]; // Coefficients.
433
434
0
  return K [0] + r2 * (K [1] + r2 * (K [2] + r2 * K [3]));
435
  
436
0
  }
437
    
438
/*****************************************************************************/
439
440
dng_point_real64 dng_warp_params_rectilinear::EvaluateTangential (uint32 plane,
441
                                  real64 r2,
442
                                  const dng_point_real64 &diff,
443
                                  const dng_point_real64 &diff2) const
444
0
  {
445
  
446
0
  const real64 kt0 = fTanParams [plane][0];
447
0
  const real64 kt1 = fTanParams [plane][1];
448
449
0
  const real64 dh = diff.h;
450
0
  const real64 dv = diff.v;
451
452
0
  const real64 dhdh = diff2.h;
453
0
  const real64 dvdv = diff2.v;
454
  
455
0
  return dng_point_real64 (kt0 * (r2 + 2.0 * dvdv) + (2.0 * kt1 * dh * dv),  // v
456
0
               kt1 * (r2 + 2.0 * dhdh) + (2.0 * kt0 * dh * dv)); // h
457
  
458
0
  }
459
460
/*****************************************************************************/
461
462
real64 dng_warp_params_rectilinear::MaxSrcRadiusGap (real64 maxDstGap) const
463
0
  {
464
  
465
0
  real64 maxSrcGap = 0.0;
466
467
0
  for (uint32 plane = 0; plane < fPlanes; plane++)
468
0
    {
469
470
0
    const dng_vector &coefs = fRadParams [plane];
471
    
472
0
    const real64 k3 = coefs [1];
473
0
    const real64 k5 = coefs [2];
474
0
    const real64 k7 = coefs [3];
475
476
    //
477
    //  Let f (r) be the radius warp function. Consider the function
478
    //
479
    //    gap (r) = f (r + maxDstGap) - f (r)
480
    //
481
    //  We wish to maximize gap (r) over the domain [0, 1 - maxDstGap]. This will
482
    //  give us a reasonable upper bound on the src tile size, independent of
483
    //  dstBounds.
484
    //
485
    //  As usual, we maximize gap (r) by examining its critical points, i.e., by
486
    //  considering the roots of its derivative which lie in the domain [0, 1 -
487
    //  maxDstGap]. gap' (r) is a 5th-order polynomial. One of its roots is
488
    //  -maxDstGap / 2, which is negative and hence lies outside the domain of
489
    //  interest. This leaves 4 other possible roots. We solve for these
490
    //  analytically below.
491
    //
492
493
0
    real64 roots [4];
494
0
    uint32 numRoots = 0;
495
496
0
    if (k7 == 0.0)
497
0
      {
498
      
499
0
      if (k5 == 0.0)
500
0
        {
501
        
502
        // No roots in [0,1].
503
        
504
0
        }
505
506
0
      else
507
0
        {
508
        
509
        // k7 is zero, but k5 is non-zero. At most two real roots. 
510
511
0
        const real64 discrim = 25.0 * (-6.0 * k3 * k5 - 5.0 * k5 * maxDstGap * maxDstGap);
512
513
0
        if (discrim >= 0.0)
514
0
          {
515
          
516
          // Two real roots.
517
518
0
          const real64 scale    =  0.1 * k5;
519
0
          const real64 offset   = -5.0 * maxDstGap * k5;
520
0
          const real64 sDiscrim =  sqrt (discrim);
521
522
0
          roots [numRoots++] = scale * (offset + sDiscrim);
523
0
          roots [numRoots++] = scale * (offset - sDiscrim);
524
          
525
0
          }
526
        
527
0
        }
528
      
529
0
      }
530
531
0
    else
532
0
      {
533
      
534
      // k7 is non-zero. Up to 4 real roots.
535
536
0
      const real64 d  = maxDstGap;
537
0
      const real64 d2 = d  * d;
538
0
      const real64 d4 = d2 * d2;
539
540
0
      const real64 discrim = 25.0 * k5 * k5 
541
0
                 - 63.0 * k3 * k7 
542
0
                 + 35.0 * d2 * k5 * k7 
543
0
                 + 49.0 * d4 * k7 * k7;
544
      
545
0
      if (discrim >= 0.0)
546
0
        {
547
        
548
0
        const real64 sDiscrim = 4.0 * k7 * sqrt (discrim);
549
550
0
        const real64 offset = -20.0 * k5 * k7 - 35.0 * d2 * k7 * k7;
551
552
0
        const real64 discrim1 = offset - sDiscrim;
553
0
        const real64 discrim2 = offset + sDiscrim;
554
        
555
0
        const real64 scale = sqrt (21.0) / (42.0 * k7);
556
557
0
        if (discrim1 >= 0.0)
558
0
          {
559
          
560
0
          const real64 offset1 = -d * 0.5;
561
0
          const real64 sDiscrim1 = scale * sqrt (discrim1);
562
563
0
          roots [numRoots++] = offset1 + sDiscrim1;
564
0
          roots [numRoots++] = offset1 - sDiscrim1;
565
          
566
0
          }
567
        
568
0
        if (discrim2 >= 0.0)
569
0
          {
570
          
571
0
          const real64 offset2 = -d * 0.5;
572
0
          const real64 sDiscrim2 = scale * sqrt (discrim2);
573
574
0
          roots [numRoots++] = offset2 + sDiscrim2;
575
0
          roots [numRoots++] = offset2 - sDiscrim2;
576
          
577
0
          }
578
        
579
0
        }
580
581
0
      }
582
583
0
    real64 planeMaxSrcGap = 0.0;
584
585
    // Examine the endpoints.
586
587
0
      {
588
589
      // Check left endpoint: f (maxDstGap) - f (0). Remember that f (0) == 0.
590
      
591
0
      const real64 gap1 = Evaluate (plane, maxDstGap);
592
      
593
0
      planeMaxSrcGap = Max_real64 (planeMaxSrcGap, gap1);
594
595
      // Check right endpoint: f (1) - f (1 - maxDstGap).
596
      
597
0
      const real64 gap2 = Evaluate (plane, 1.0)
598
0
                - Evaluate (plane, 1.0 - maxDstGap);
599
      
600
0
      planeMaxSrcGap = Max_real64 (planeMaxSrcGap, gap2);
601
602
0
      }
603
604
    // Examine the roots we found, if any.
605
606
0
    for (uint32 i = 0; i < numRoots; i++)
607
0
      {
608
        
609
0
      const real64 r = roots [i];
610
611
0
      if (r > 0.0 && r < 1.0 - maxDstGap)
612
0
        {
613
        
614
0
        const real64 gap = Evaluate (plane, r + maxDstGap)
615
0
                 - Evaluate (plane, r);
616
        
617
0
        planeMaxSrcGap = Max_real64 (planeMaxSrcGap, gap);
618
619
0
        }
620
        
621
0
      }
622
    
623
0
    maxSrcGap = Max_real64 (maxSrcGap,
624
0
                planeMaxSrcGap);
625
626
0
    }
627
628
0
  return maxSrcGap;
629
  
630
0
  }
631
632
/*****************************************************************************/
633
634
dng_point_real64 dng_warp_params_rectilinear::MaxSrcTanGap (dng_point_real64 minDst,
635
                              dng_point_real64 maxDst) const
636
0
  {
637
  
638
0
  const real64 v [] = { minDst.v, maxDst.v, 0.0 };
639
0
  const real64 h [] = { minDst.h, maxDst.h, 0.0 };
640
641
0
  dng_point_real64 maxGap;
642
643
0
  for (uint32 plane = 0; plane < fPlanes; plane++)
644
0
    {
645
646
0
    real64 hMin = +FLT_MAX;
647
0
    real64 hMax = -FLT_MAX;
648
649
0
    real64 vMin = +FLT_MAX;
650
0
    real64 vMax = -FLT_MAX;
651
652
0
    for (uint32 i = 0; i < 3; i++)
653
0
      {
654
    
655
0
      for (uint32 j = 0; j < 3; j++)
656
0
        {
657
      
658
0
        dng_point_real64 dstDiff (v [i], 
659
0
                      h [j]);
660
661
0
        dng_point_real64 srcDiff = EvaluateTangential2 (plane,
662
0
                                dstDiff);
663
664
0
        hMin = Min_real64 (hMin, srcDiff.h);
665
0
        hMax = Max_real64 (hMax, srcDiff.h);
666
      
667
0
        vMin = Min_real64 (vMin, srcDiff.v);
668
0
        vMax = Max_real64 (vMax, srcDiff.v);
669
      
670
0
        }
671
    
672
0
      }
673
674
0
    const real64 hGap = hMax - hMin;
675
0
    const real64 vGap = vMax - vMin;
676
677
0
    maxGap.h = Max_real64 (maxGap.h, hGap);
678
0
    maxGap.v = Max_real64 (maxGap.v, vGap);
679
680
0
    }
681
682
0
  return maxGap;
683
  
684
0
  }
685
    
686
/*****************************************************************************/
687
688
void dng_warp_params_rectilinear::Dump () const
689
0
  {
690
  
691
  #if qDNGValidate
692
693
  dng_warp_params::Dump ();
694
695
  for (uint32 plane = 0; plane < fPlanes; plane++)
696
    {
697
698
    printf ("  Plane %u:\n", (unsigned) plane);
699
700
    printf ("    Radial params:     %.6lf, %.6lf, %.6lf, %.6lf\n",
701
        fRadParams [plane][0],
702
        fRadParams [plane][1],
703
        fRadParams [plane][2],
704
        fRadParams [plane][3]);
705
706
    printf ("    Tangential params: %.6lf, %.6lf\n",
707
        fTanParams [plane][0],
708
        fTanParams [plane][1]);
709
710
    }   
711
712
  #endif
713
  
714
0
  }
715
716
/*****************************************************************************/
717
718
dng_warp_params_fisheye::dng_warp_params_fisheye ()
719
720
  : dng_warp_params ()
721
722
0
  {
723
724
0
  for (uint32 plane = 0; plane < kMaxColorPlanes; plane++)
725
0
    {
726
727
0
    fRadParams [plane] = dng_vector (4);
728
729
0
    }
730
  
731
0
  }
732
733
/*****************************************************************************/
734
735
dng_warp_params_fisheye::dng_warp_params_fisheye (uint32 planes,
736
                          const dng_vector radParams [],
737
                          const dng_point_real64 &center)
738
739
  : dng_warp_params (planes, center)
740
741
0
  {
742
  
743
0
  for (uint32 i = 0; i < fPlanes; i++)
744
0
    {
745
746
0
    fRadParams [i] = radParams [i];
747
748
0
    }
749
  
750
0
  }
751
752
/*****************************************************************************/
753
754
dng_warp_params_fisheye::~dng_warp_params_fisheye ()
755
0
  {
756
  
757
0
  }
758
759
/*****************************************************************************/
760
761
bool dng_warp_params_fisheye::IsRadNOP (uint32 /* plane */) const
762
0
  {
763
  
764
0
  return false;
765
  
766
0
  }
767
768
/*****************************************************************************/
769
770
bool dng_warp_params_fisheye::IsTanNOP (uint32 /* plane */) const
771
0
  {
772
  
773
0
  return true;
774
  
775
0
  }
776
777
/*****************************************************************************/
778
779
bool dng_warp_params_fisheye::IsValid () const
780
0
  {
781
782
0
  for (uint32 plane = 0; plane < fPlanes; plane++)
783
0
    {
784
    
785
0
    if (fRadParams [plane].Count () != 4)
786
0
      {
787
0
      return false;
788
0
      }
789
    
790
0
    }
791
792
0
  return dng_warp_params::IsValid ();
793
  
794
0
  }
795
796
/*****************************************************************************/
797
798
void dng_warp_params_fisheye::PropagateToAllPlanes (uint32 totalPlanes)
799
0
  {
800
  
801
0
  for (uint32 plane = fPlanes; plane < totalPlanes; plane++)
802
0
    {
803
804
0
    fRadParams [plane] = fRadParams [0];
805
806
0
    }
807
808
0
  }
809
810
/*****************************************************************************/
811
812
real64 dng_warp_params_fisheye::Evaluate (uint32 plane,
813
                      real64 r) const
814
0
  {
815
816
0
  const real64 t = atan (r);
817
818
0
  const dng_vector &K = fRadParams [plane];
819
820
0
  const real64 t2 = t * t;
821
  
822
0
  return t * (K [0] + t2 * (K [1] + t2 * (K [2] + t2 * K [3])));
823
  
824
0
  }
825
826
/*****************************************************************************/
827
828
real64 dng_warp_params_fisheye::EvaluateRatio (uint32 plane,
829
                         real64 rSqr) const
830
0
  {
831
832
0
  const real64 eps = 1.0e-12;
833
834
0
  if (rSqr < eps)
835
0
    {
836
    
837
    // r is very close to zero.
838
839
0
    return 1.0;
840
    
841
0
    }
842
843
0
  const real64 r = sqrt (rSqr);
844
845
0
  return Evaluate (plane, r) / r;
846
  
847
0
  }
848
849
/*****************************************************************************/
850
851
dng_point_real64 dng_warp_params_fisheye::EvaluateTangential (uint32 /* plane */,
852
                                real64 /* r2 */,
853
                                const dng_point_real64 & /* diff */,
854
                                const dng_point_real64 & /* diff2 */) const
855
0
  {
856
  
857
  // This fisheye model does not support tangential warping.
858
859
0
  ThrowProgramError ();
860
861
0
  return dng_point_real64 (0.0, 0.0);
862
  
863
0
  }
864
865
/*****************************************************************************/
866
867
real64 dng_warp_params_fisheye::MaxSrcRadiusGap (real64 maxDstGap) const
868
0
  {
869
  
870
  //
871
  //  Let f (r) be the radius warp function. Consider the function
872
  //
873
  //    gap (r) = f (r + maxDstGap) - f (r)
874
  //
875
  //  We wish to maximize gap (r) over the domain [0, 1 - maxDstGap]. This will
876
  //  give us a reasonable upper bound on the src tile size, independent of
877
  //  dstBounds.
878
  //
879
  //  Ideally, we'd like to maximize gap (r) by examining its critical points,
880
  //  i.e., by considering the roots of its derivative which lie in the domain [0,
881
  //  1 - maxDstGap]. However, gap' (r) is too complex to find its roots
882
  //  analytically.
883
  //
884
885
0
  real64 maxSrcGap = 0.0;
886
887
0
  DNG_REQUIRE (maxDstGap > 0.0, "maxDstGap must be positive.");
888
889
0
  const real64 kMaxValue = 1.0 - maxDstGap;
890
891
0
  const uint32 kSteps = 128;
892
    
893
0
  const real64 kNorm = kMaxValue / real64 (kSteps - 1);
894
895
0
  for (uint32 plane = 0; plane < fPlanes; plane++)
896
0
    {
897
898
0
    for (uint32 i = 0; i < kSteps; i++)
899
0
      {
900
      
901
0
      const real64 tt = i * kNorm;
902
903
0
      const real64 gap = Evaluate (plane, tt + maxDstGap)
904
0
               - Evaluate (plane, tt);
905
906
0
      maxSrcGap = Max_real64 (maxSrcGap,
907
0
                  gap);
908
      
909
0
      }
910
911
0
    }
912
913
0
  return maxSrcGap;
914
  
915
0
  }
916
917
/*****************************************************************************/
918
919
dng_point_real64 dng_warp_params_fisheye::MaxSrcTanGap (dng_point_real64 /* minDst */,
920
                            dng_point_real64 /* maxDst */) const
921
0
  {
922
923
  // This fisheye model does not support tangential distortion.
924
925
0
  return dng_point_real64 (0.0, 0.0);
926
927
0
  }
928
  
929
/*****************************************************************************/
930
931
void dng_warp_params_fisheye::Dump () const
932
0
  {
933
  
934
  #if qDNGValidate
935
936
  dng_warp_params::Dump ();
937
938
  for (uint32 plane = 0; plane < fPlanes; plane++)
939
    {
940
941
    printf ("  Plane %u:\n", (unsigned) plane);
942
943
    printf ("    Radial params:     %.6lf, %.6lf, %.6lf, %.6lf\n",
944
        fRadParams [plane][0],
945
        fRadParams [plane][1],
946
        fRadParams [plane][2],
947
        fRadParams [plane][3]);
948
949
    }   
950
    
951
  #endif
952
  
953
0
  }
954
955
/*****************************************************************************/
956
957
class dng_filter_warp: public dng_filter_task
958
  {
959
  
960
  protected:
961
962
    AutoPtr<dng_warp_params> fParams;
963
964
    dng_point_real64 fCenter;
965
  
966
    dng_resample_weights_2d fWeights;
967
968
    real64 fNormRadius;
969
    real64 fInvNormRadius;
970
971
    bool fIsRadNOP;
972
    bool fIsTanNOP;
973
974
    const real64 fPixelScaleV;
975
    const real64 fPixelScaleVInv;
976
977
  public:
978
  
979
    dng_filter_warp (const dng_image &srcImage,
980
             dng_image &dstImage,
981
             const dng_negative &negative,
982
             AutoPtr<dng_warp_params> &params);
983
984
    virtual void Initialize (dng_host &host);
985
986
    virtual dng_rect SrcArea (const dng_rect &dstArea);
987
988
    virtual dng_point SrcTileSize (const dng_point &dstTileSize);
989
990
    virtual void ProcessArea (uint32 threadIndex,
991
                  dng_pixel_buffer &srcBuffer,
992
                  dng_pixel_buffer &dstBuffer);
993
994
    virtual dng_point_real64 GetSrcPixelPosition (const dng_point_real64 &dst,
995
                            uint32 plane);
996
997
  };
998
999
/*****************************************************************************/
1000
1001
dng_filter_warp::dng_filter_warp (const dng_image &srcImage,
1002
                  dng_image &dstImage,
1003
                  const dng_negative &negative,
1004
                  AutoPtr<dng_warp_params> &params)
1005
1006
  : dng_filter_task (srcImage,
1007
             dstImage)
1008
1009
  , fParams     (params.Release ())
1010
1011
  , fCenter     ()
1012
1013
  , fWeights    ()
1014
1015
  , fNormRadius   (1.0)
1016
  , fInvNormRadius  (1.0)
1017
1018
  , fIsRadNOP   (false)
1019
  , fIsTanNOP   (false)
1020
1021
  , fPixelScaleV  (1.0 / negative.PixelAspectRatio ())
1022
  , fPixelScaleVInv (1.0 / fPixelScaleV)
1023
1024
0
  {
1025
1026
  // Force float processing.
1027
1028
0
  fSrcPixelType = ttFloat;
1029
0
  fDstPixelType = ttFloat;
1030
1031
0
  fIsRadNOP = fParams->IsRadNOPAll ();
1032
0
  fIsTanNOP = fParams->IsTanNOPAll ();
1033
1034
0
  const uint32 negPlanes = negative.ColorChannels ();
1035
1036
0
  DNG_ASSERT (negPlanes >= 1,         "Too few planes." );
1037
0
  DNG_ASSERT (negPlanes <= kMaxColorPlanes, "Too many planes.");
1038
1039
0
  (void) negPlanes;
1040
  
1041
  // At least one set of params must do something interesting.
1042
1043
0
  if (fIsRadNOP && fIsTanNOP)
1044
0
    {
1045
0
    ThrowProgramError ();
1046
0
    }
1047
1048
  // Make sure the warp params are valid for this negative.
1049
1050
0
  if (!fParams->IsValidForNegative (negative))
1051
0
    {
1052
0
    ThrowBadFormat ();
1053
0
    }
1054
1055
  // Compute center.
1056
1057
0
  const dng_rect bounds = srcImage.Bounds ();
1058
1059
0
  fCenter.h = Lerp_real64 ((real64) bounds.l,
1060
0
               (real64) bounds.r,
1061
0
               fParams->fCenter.h);
1062
1063
0
  fCenter.v = Lerp_real64 ((real64) bounds.t,
1064
0
               (real64) bounds.b,
1065
0
               fParams->fCenter.v);
1066
1067
  // Compute max pixel radius and derive various normalized radius values. Note
1068
  // that when computing the max pixel radius, we must take into account the pixel
1069
  // aspect ratio.
1070
1071
0
    {
1072
1073
0
    dng_rect squareBounds (bounds);
1074
1075
0
    squareBounds.b = squareBounds.t + 
1076
0
             Round_int32 (fPixelScaleV * (real64) squareBounds.H ());
1077
1078
0
    const dng_point_real64 squareCenter (Lerp_real64 ((real64) squareBounds.t,
1079
0
                              (real64) squareBounds.b,
1080
0
                              fParams->fCenter.v),
1081
1082
0
                       Lerp_real64 ((real64) squareBounds.l,
1083
0
                              (real64) squareBounds.r,
1084
0
                              fParams->fCenter.h));
1085
1086
0
    fNormRadius = MaxDistancePointToRect (squareCenter,
1087
0
                        squareBounds);
1088
1089
0
    fInvNormRadius = 1.0 / fNormRadius;
1090
1091
0
    }
1092
1093
  // Propagate warp params to other planes.
1094
1095
0
  fParams->PropagateToAllPlanes (fDstPlanes);
1096
1097
0
  }
1098
1099
/*****************************************************************************/
1100
1101
void dng_filter_warp::Initialize (dng_host &host)
1102
0
  {
1103
1104
  // Make resample weights.
1105
1106
0
  const dng_resample_function &kernel = dng_resample_bicubic::Get ();
1107
  
1108
0
  fWeights.Initialize (kernel,
1109
0
             host.Allocator ());
1110
  
1111
0
  }
1112
1113
/*****************************************************************************/
1114
  
1115
dng_rect dng_filter_warp::SrcArea (const dng_rect &dstArea)
1116
0
  {
1117
  
1118
  // Walk each pixel of the boundary of dstArea, map it to the uncorrected src
1119
  // pixel position, and return the rectangle that contains all such src pixels.
1120
1121
0
  int32 xMin = INT_MAX;
1122
0
  int32 xMax = INT_MIN;
1123
0
  int32 yMin = INT_MAX;
1124
0
  int32 yMax = INT_MIN;
1125
1126
0
  for (uint32 plane = 0; plane < fDstPlanes; plane++)
1127
0
    {
1128
1129
    // Top and bottom edges.
1130
    
1131
0
    for (int32 c = dstArea.l; c < dstArea.r; c++)
1132
0
      {
1133
      
1134
      // Top edge.
1135
1136
0
        {
1137
        
1138
0
        const dng_point_real64 dst (dstArea.t, c);
1139
1140
0
        const dng_point_real64 src = GetSrcPixelPosition (dst, plane);
1141
1142
0
        const int32 y = ConvertDoubleToInt32 (floor (src.v));
1143
        
1144
0
        yMin = Min_int32 (yMin, y);
1145
1146
0
        }
1147
1148
      // Bottom edge.
1149
1150
0
        {
1151
        
1152
0
        const dng_point_real64 dst (dstArea.b - 1, c);
1153
1154
0
        const dng_point_real64 src = GetSrcPixelPosition (dst, plane);
1155
1156
0
        const int32 y = ConvertDoubleToInt32 (ceil (src.v));
1157
        
1158
0
        yMax = Max_int32 (yMax, y);
1159
        
1160
0
        }
1161
        
1162
0
      }   
1163
    
1164
    // Left and right edges.
1165
    
1166
0
    for (int32 r = dstArea.t; r < dstArea.b; r++)
1167
0
      {
1168
1169
      // Left edge.
1170
1171
0
        {
1172
        
1173
0
        const dng_point_real64 dst (r, dstArea.l);
1174
1175
0
        const dng_point_real64 src = GetSrcPixelPosition (dst, plane);
1176
1177
0
        const int32 x = ConvertDoubleToInt32 (floor (src.h));
1178
        
1179
0
        xMin = Min_int32 (xMin, x);
1180
1181
0
        }
1182
        
1183
      // Right edge.
1184
1185
0
        {
1186
        
1187
0
        const dng_point_real64 dst (r, dstArea.r - 1);
1188
1189
0
        const dng_point_real64 src = GetSrcPixelPosition (dst, plane);
1190
1191
0
        const int32 x = ConvertDoubleToInt32 (ceil (src.h));
1192
        
1193
0
        xMax = Max_int32 (xMax, x);
1194
1195
0
        }
1196
        
1197
0
      }   
1198
    
1199
0
    }
1200
1201
  // Pad each side by filter radius.
1202
1203
0
  const int32 pad = ConvertUint32ToInt32(fWeights.Radius());
1204
1205
0
  xMin = SafeInt32Sub(xMin, pad);
1206
0
  yMin = SafeInt32Sub(yMin, pad);
1207
0
  xMax = SafeInt32Add(xMax, pad);
1208
0
  yMax = SafeInt32Add(yMax, pad);
1209
1210
0
  xMax = SafeInt32Add(xMax, 1);
1211
0
  yMax = SafeInt32Add(yMax, 1);
1212
1213
0
  const dng_rect srcArea (yMin,
1214
0
              xMin,
1215
0
              yMax,
1216
0
              xMax);
1217
1218
0
  return srcArea;
1219
  
1220
0
  }
1221
1222
/*****************************************************************************/
1223
1224
dng_point dng_filter_warp::SrcTileSize (const dng_point &dstTileSize)
1225
0
  {
1226
1227
  // Obtain an upper bound on the source tile size. We'll do this by considering
1228
  // upper bounds on the radial and tangential warp components separately, then add
1229
  // them together. This is not a tight bound but is good enough because the
1230
  // tangential terms are usually quite small.
1231
1232
  // Get upper bound on src tile size from radial warp.
1233
1234
0
  DNG_REQUIRE (dstTileSize.v > 0, "Invalid tile height.");
1235
0
  DNG_REQUIRE (dstTileSize.h > 0, "Invalid tile width.");
1236
1237
0
  const real64 maxDstGap = fInvNormRadius * hypot ((real64) dstTileSize.h,
1238
0
                           (real64) dstTileSize.v);
1239
1240
0
  dng_point srcTileSize;
1241
1242
0
  if (maxDstGap >= 1.0)
1243
0
    {
1244
1245
    // The proposed tile size is unusually large, i.e., its hypotenuse is larger
1246
    // than the maximum radius. Bite the bullet and just return a tile size big
1247
    // enough to process the whole image.
1248
1249
0
    srcTileSize = SrcArea (fDstImage.Bounds ()).Size ();
1250
    
1251
0
    }
1252
1253
0
  else
1254
0
    {
1255
1256
    // maxDstGap < 1.0.
1257
1258
0
    const real64 maxSrcGap = fParams->MaxSrcRadiusGap (maxDstGap);
1259
1260
0
    const int32 dim = ConvertDoubleToInt32 (ceil (maxSrcGap * fNormRadius));
1261
1262
0
    srcTileSize = dng_point (dim, dim);
1263
1264
0
    }
1265
1266
0
  srcTileSize.h += ConvertUint32ToInt32(fWeights.Width());
1267
0
  srcTileSize.v += ConvertUint32ToInt32(fWeights.Width());
1268
1269
  // Get upper bound on src tile size from tangential warp.
1270
1271
0
  const dng_rect_real64 bounds (fSrcImage.Bounds ());
1272
1273
0
  const dng_point_real64 minDst ((bounds.t - fCenter.v) * fInvNormRadius,
1274
0
                   (bounds.l - fCenter.h) * fInvNormRadius);
1275
  
1276
0
  const dng_point_real64 maxDst ((bounds.b - 1.0 - fCenter.v) * fInvNormRadius,
1277
0
                   (bounds.r - 1.0 - fCenter.h) * fInvNormRadius);
1278
  
1279
0
  const dng_point_real64 srcTanGap = fParams->MaxSrcTanGap (minDst,
1280
0
                                maxDst);
1281
1282
  // Add the two bounds together.
1283
1284
0
  srcTileSize.v += ConvertDoubleToInt32 (ceil (srcTanGap.v * fNormRadius));
1285
0
  srcTileSize.h += ConvertDoubleToInt32 (ceil (srcTanGap.h * fNormRadius));
1286
  
1287
0
  return srcTileSize;
1288
1289
0
  }
1290
1291
/*****************************************************************************/
1292
    
1293
void dng_filter_warp::ProcessArea (uint32 /* threadIndex */,
1294
                   dng_pixel_buffer &srcBuffer,
1295
                   dng_pixel_buffer &dstBuffer)
1296
0
  {
1297
1298
  // Prepare resample constants.
1299
1300
0
  const int32 wCount = fWeights.Width ();
1301
1302
0
  const dng_point srcOffset (fWeights.Offset (),
1303
0
                 fWeights.Offset ());
1304
1305
0
  const real64 numSubsamples = (real64) kResampleSubsampleCount2D;
1306
1307
  // Prepare area and step constants.
1308
1309
0
  const dng_rect srcArea = srcBuffer.fArea;
1310
0
  const dng_rect dstArea = dstBuffer.fArea;
1311
1312
0
  const int32 srcRowStep = (int32) srcBuffer.RowStep ();
1313
1314
0
  const int32 hMin = srcArea.l;
1315
0
  const int32 hMax = SafeInt32Sub (SafeInt32Sub (srcArea.r, wCount), 1);
1316
1317
0
  const int32 vMin = srcArea.t;
1318
0
  const int32 vMax = SafeInt32Sub (SafeInt32Sub (srcArea.b, wCount), 1);
1319
1320
0
  if (hMax < hMin || vMax < vMin)
1321
0
    {
1322
    
1323
0
    ThrowBadFormat ("Empty source area in dng_filter_warp.");
1324
    
1325
0
    }
1326
1327
  // Warp each plane.
1328
1329
0
  for (uint32 plane = 0; plane < dstBuffer.fPlanes; plane++)
1330
0
    {
1331
  
1332
0
    real32 *dPtr = dstBuffer.DirtyPixel_real32 (dstArea.t, 
1333
0
                          dstArea.l, 
1334
0
                          plane);
1335
1336
0
    for (int32 dstRow = dstArea.t; dstRow < dstArea.b; dstRow++)
1337
0
      {
1338
1339
0
      uint32 dstIndex = 0;
1340
      
1341
0
      for (int32 dstCol = dstArea.l; dstCol < dstArea.r; dstCol++, dstIndex++)
1342
0
        {
1343
1344
        // Get destination (corrected) pixel position.
1345
1346
0
        const dng_point_real64 dPos ((real64) dstRow,
1347
0
                       (real64) dstCol);
1348
1349
        // Warp to source (uncorrected) pixel position.
1350
1351
0
        const dng_point_real64 sPos = GetSrcPixelPosition (dPos,
1352
0
                                   plane);
1353
1354
        // Decompose into integer and fractional parts.
1355
1356
0
        dng_point sInt (ConvertDoubleToInt32 (floor (sPos.v)),
1357
0
                ConvertDoubleToInt32 (floor (sPos.h)));
1358
1359
0
        dng_point sFct (ConvertDoubleToInt32 ((sPos.v - (real64) sInt.v) * numSubsamples),
1360
0
                ConvertDoubleToInt32 ((sPos.h - (real64) sInt.h) * numSubsamples));
1361
1362
        // Add resample offset.
1363
1364
0
        sInt = sInt + srcOffset;
1365
1366
        // Clip.
1367
        
1368
0
        if (sInt.h < hMin)
1369
0
          {
1370
0
          sInt.h = hMin;
1371
0
          sFct.h = 0;
1372
0
          }
1373
1374
0
        else if (sInt.h > hMax)
1375
0
          {
1376
0
          sInt.h = hMax;
1377
0
          sFct.h = 0;
1378
0
          }
1379
1380
0
        if (sInt.v < vMin)
1381
0
          {
1382
0
          sInt.v = vMin;
1383
0
          sFct.v = 0;
1384
0
          }
1385
1386
0
        else if (sInt.v > vMax)
1387
0
          {
1388
0
          sInt.v = vMax;
1389
0
          sFct.v = 0;
1390
0
          }
1391
1392
        // Perform 2D resample.
1393
1394
0
        const real32 *w = fWeights.Weights32 (sFct);
1395
1396
0
        const real32 *s = srcBuffer.ConstPixel_real32 (sInt.v,
1397
0
                                 sInt.h,
1398
0
                                 plane);
1399
1400
0
        real32 total = 0.0f;
1401
1402
0
        for (int32 i = 0; i < wCount; i++)
1403
0
          {
1404
            
1405
0
          for (int32 j = 0; j < wCount; j++)
1406
0
            {
1407
              
1408
0
            total += w [j] * s [j];
1409
              
1410
0
            }
1411
1412
0
          w += wCount;
1413
0
          s += srcRowStep;
1414
            
1415
0
          }
1416
1417
        // Store final pixel value.
1418
1419
0
        dPtr [dstIndex] = Pin_real32 (total);
1420
        
1421
0
        }
1422
1423
      // Advance to next row.
1424
1425
0
      dPtr += dstBuffer.RowStep ();
1426
1427
0
      }
1428
1429
0
    } 
1430
1431
0
  }
1432
1433
/*****************************************************************************/
1434
1435
dng_point_real64 dng_filter_warp::GetSrcPixelPosition (const dng_point_real64 &dst,
1436
                             uint32 plane)
1437
0
  {
1438
1439
0
  const dng_point_real64 diff = dst - fCenter;
1440
1441
0
  const dng_point_real64 diffNorm (diff.v * fInvNormRadius,
1442
0
                   diff.h * fInvNormRadius);
1443
1444
0
  const dng_point_real64 diffNormScaled (diffNorm.v * fPixelScaleV,
1445
0
                       diffNorm.h);
1446
1447
0
  const dng_point_real64 diffNormSqr (diffNormScaled.v * diffNormScaled.v,
1448
0
                    diffNormScaled.h * diffNormScaled.h);
1449
1450
0
  const real64 rr = Min_real64 (diffNormSqr.v + diffNormSqr.h,
1451
0
                  1.0);
1452
1453
0
  dng_point_real64 dSrc;
1454
1455
0
  if (fIsTanNOP)
1456
0
    {
1457
1458
    // Radial only.
1459
    
1460
0
    const real64 ratio = fParams->EvaluateRatio (plane,
1461
0
                           rr);
1462
1463
0
    dSrc.h = diff.h * ratio;
1464
0
    dSrc.v = diff.v * ratio;
1465
    
1466
0
    }
1467
1468
0
  else if (fIsRadNOP)
1469
0
    {
1470
1471
    // Tangential only.
1472
1473
0
    const dng_point_real64 tan = fParams->EvaluateTangential (plane,
1474
0
                                  rr,
1475
0
                                  diffNormScaled,
1476
0
                                  diffNormSqr);
1477
1478
0
    dSrc.h = diff.h + (fNormRadius * tan.h);
1479
0
    dSrc.v = diff.v + (fNormRadius * tan.v * fPixelScaleVInv);
1480
1481
0
    }
1482
1483
0
  else
1484
0
    {
1485
    
1486
    // Radial and tangential.
1487
1488
0
    const real64 ratio = fParams->EvaluateRatio (plane,
1489
0
                           rr);
1490
1491
0
    const dng_point_real64 tan = fParams->EvaluateTangential (plane,
1492
0
                                  rr,
1493
0
                                  diffNormScaled,
1494
0
                                  diffNormSqr);
1495
1496
0
    dSrc.h = fNormRadius * (diffNorm.h * ratio + tan.h);
1497
0
    dSrc.v = fNormRadius * (diffNorm.v * ratio + tan.v * fPixelScaleVInv);
1498
1499
0
    }
1500
1501
0
  return fCenter + dSrc;
1502
  
1503
0
  }
1504
1505
/*****************************************************************************/
1506
1507
dng_opcode_WarpRectilinear::dng_opcode_WarpRectilinear (const dng_warp_params_rectilinear &params,
1508
                            uint32 flags)
1509
1510
  : dng_opcode (dngOpcode_WarpRectilinear,
1511
          dngVersion_1_3_0_0,
1512
          flags)
1513
1514
  , fWarpParams (params)
1515
1516
0
  {
1517
1518
0
  if (!params.IsValid ())
1519
0
    {
1520
0
    ThrowBadFormat ();
1521
0
    }
1522
1523
0
  }
1524
1525
/*****************************************************************************/
1526
    
1527
dng_opcode_WarpRectilinear::dng_opcode_WarpRectilinear (dng_stream &stream)
1528
1529
  : dng_opcode (dngOpcode_WarpRectilinear,
1530
          stream,
1531
          "WarpRectilinear")
1532
1533
  , fWarpParams ()
1534
1535
0
  {
1536
1537
  // Grab the size in bytes.
1538
1539
0
  const uint32 bytes = stream.Get_uint32 ();
1540
1541
  // Grab the number of planes to warp.
1542
1543
0
  fWarpParams.fPlanes = stream.Get_uint32 ();
1544
1545
  // Verify number of planes.
1546
1547
0
  if (fWarpParams.fPlanes == 0 ||
1548
0
    fWarpParams.fPlanes > kMaxColorPlanes)
1549
0
    {
1550
0
    ThrowBadFormat ();
1551
0
    }
1552
1553
  // Verify the size.
1554
1555
0
  if (bytes != ParamBytes (fWarpParams.fPlanes))
1556
0
    {
1557
0
    ThrowBadFormat ();
1558
0
    }
1559
1560
  // Read warp parameters for each plane.
1561
1562
0
  for (uint32 plane = 0; plane < fWarpParams.fPlanes; plane++)
1563
0
    {
1564
1565
0
    fWarpParams.fRadParams [plane][0] = stream.Get_real64 ();
1566
0
    fWarpParams.fRadParams [plane][1] = stream.Get_real64 ();
1567
0
    fWarpParams.fRadParams [plane][2] = stream.Get_real64 ();
1568
0
    fWarpParams.fRadParams [plane][3] = stream.Get_real64 ();
1569
    
1570
0
    fWarpParams.fTanParams [plane][0] = stream.Get_real64 ();
1571
0
    fWarpParams.fTanParams [plane][1] = stream.Get_real64 ();
1572
1573
0
    }
1574
1575
  // Read the image center.
1576
1577
0
  fWarpParams.fCenter.h = stream.Get_real64 ();
1578
0
  fWarpParams.fCenter.v = stream.Get_real64 ();
1579
  
1580
  #if qDNGValidate
1581
  
1582
  if (gVerbose)
1583
    {
1584
1585
    fWarpParams.Dump ();
1586
1587
    }
1588
    
1589
  #endif
1590
1591
0
  if (!fWarpParams.IsValid ())
1592
0
    {
1593
0
    ThrowBadFormat ();
1594
0
    }
1595
  
1596
0
  }
1597
  
1598
/*****************************************************************************/
1599
1600
bool dng_opcode_WarpRectilinear::IsNOP () const
1601
0
  {
1602
1603
0
  return fWarpParams.IsNOPAll ();
1604
  
1605
0
  }
1606
1607
/*****************************************************************************/
1608
1609
bool dng_opcode_WarpRectilinear::IsValidForNegative (const dng_negative &negative) const
1610
0
  {
1611
1612
0
  return fWarpParams.IsValidForNegative (negative);
1613
  
1614
0
  }
1615
1616
/*****************************************************************************/
1617
1618
void dng_opcode_WarpRectilinear::PutData (dng_stream &stream) const
1619
0
  {
1620
1621
0
  const uint32 bytes = ParamBytes (fWarpParams.fPlanes);
1622
  
1623
0
  stream.Put_uint32 (bytes);
1624
1625
0
  stream.Put_uint32 (fWarpParams.fPlanes);
1626
1627
0
  for (uint32 plane = 0; plane < fWarpParams.fPlanes; plane++)
1628
0
    {
1629
1630
0
    stream.Put_real64 (fWarpParams.fRadParams [plane][0]);
1631
0
    stream.Put_real64 (fWarpParams.fRadParams [plane][1]);
1632
0
    stream.Put_real64 (fWarpParams.fRadParams [plane][2]);
1633
0
    stream.Put_real64 (fWarpParams.fRadParams [plane][3]);
1634
    
1635
0
    stream.Put_real64 (fWarpParams.fTanParams [plane][0]);
1636
0
    stream.Put_real64 (fWarpParams.fTanParams [plane][1]);
1637
1638
0
    }
1639
1640
0
  stream.Put_real64 (fWarpParams.fCenter.h);
1641
0
  stream.Put_real64 (fWarpParams.fCenter.v);
1642
  
1643
0
  }
1644
1645
/*****************************************************************************/
1646
1647
void dng_opcode_WarpRectilinear::Apply (dng_host &host,
1648
                    dng_negative &negative,
1649
                    AutoPtr<dng_image> &image)
1650
0
  {
1651
1652
  #if qDNGValidate
1653
1654
  dng_timer timer ("WarpRectilinear time");
1655
1656
  #endif
1657
1658
  // Allocate destination image.
1659
  
1660
0
  AutoPtr<dng_image> dstImage (host.Make_dng_image (image->Bounds    (),
1661
0
                            image->Planes    (),
1662
0
                            image->PixelType ()));
1663
                            
1664
  // Warp the image.
1665
1666
0
  AutoPtr<dng_warp_params> params (new dng_warp_params_rectilinear (fWarpParams));
1667
  
1668
0
  dng_filter_warp filter (*image,
1669
0
              *dstImage,
1670
0
              negative,
1671
0
              params);
1672
1673
0
  filter.Initialize (host);
1674
                      
1675
0
  host.PerformAreaTask (filter,
1676
0
              image->Bounds ());
1677
            
1678
  // Return the new image.
1679
  
1680
0
  image.Reset (dstImage.Release ());
1681
  
1682
0
  }
1683
1684
/*****************************************************************************/
1685
1686
uint32 dng_opcode_WarpRectilinear::ParamBytes (uint32 planes)
1687
0
  {
1688
  
1689
0
  return (1 * (uint32) sizeof (uint32)     ) +  // Number of planes.
1690
0
       (6 * (uint32) sizeof (real64) * planes) +  // Warp coefficients.
1691
0
       (2 * (uint32) sizeof (real64)     );   // Optical center.
1692
  
1693
0
  }
1694
1695
/*****************************************************************************/
1696
1697
dng_opcode_WarpFisheye::dng_opcode_WarpFisheye (const dng_warp_params_fisheye &params,
1698
                        uint32 flags)
1699
1700
  : dng_opcode (dngOpcode_WarpFisheye,
1701
          dngVersion_1_3_0_0,
1702
          flags)
1703
1704
  , fWarpParams (params)
1705
1706
0
  {
1707
1708
0
  if (!params.IsValid ())
1709
0
    {
1710
0
    ThrowBadFormat ();
1711
0
    }
1712
1713
0
  }
1714
1715
/*****************************************************************************/
1716
    
1717
dng_opcode_WarpFisheye::dng_opcode_WarpFisheye (dng_stream &stream)
1718
1719
  : dng_opcode (dngOpcode_WarpFisheye,
1720
          stream,
1721
          "WarpFisheye")
1722
1723
  , fWarpParams ()
1724
1725
0
  {
1726
1727
  // Grab the size in bytes.
1728
1729
0
  const uint32 bytes = stream.Get_uint32 ();
1730
1731
  // Grab the number of planes to warp.
1732
1733
0
  fWarpParams.fPlanes = stream.Get_uint32 ();
1734
1735
  // Verify number of planes.
1736
1737
0
  if (fWarpParams.fPlanes == 0 ||
1738
0
    fWarpParams.fPlanes > kMaxColorPlanes)
1739
0
    {
1740
0
    ThrowBadFormat ();
1741
0
    }
1742
1743
  // Verify the size.
1744
1745
0
  if (bytes != ParamBytes (fWarpParams.fPlanes))
1746
0
    {
1747
0
    ThrowBadFormat ();
1748
0
    }
1749
1750
  // Read warp parameters for each plane.
1751
1752
0
  for (uint32 plane = 0; plane < fWarpParams.fPlanes; plane++)
1753
0
    {
1754
1755
0
    fWarpParams.fRadParams [plane][0] = stream.Get_real64 ();
1756
0
    fWarpParams.fRadParams [plane][1] = stream.Get_real64 ();
1757
0
    fWarpParams.fRadParams [plane][2] = stream.Get_real64 ();
1758
0
    fWarpParams.fRadParams [plane][3] = stream.Get_real64 ();
1759
1760
0
    }
1761
1762
  // Read the image center.
1763
1764
0
  fWarpParams.fCenter.h = stream.Get_real64 ();
1765
0
  fWarpParams.fCenter.v = stream.Get_real64 ();
1766
  
1767
  #if qDNGValidate
1768
  
1769
  if (gVerbose)
1770
    {
1771
1772
    fWarpParams.Dump ();
1773
1774
    }
1775
    
1776
  #endif
1777
1778
0
  if (!fWarpParams.IsValid ())
1779
0
    {
1780
0
    ThrowBadFormat ();
1781
0
    }
1782
  
1783
0
  }
1784
  
1785
/*****************************************************************************/
1786
1787
bool dng_opcode_WarpFisheye::IsNOP () const
1788
0
  {
1789
1790
0
  return fWarpParams.IsNOPAll ();
1791
  
1792
0
  }
1793
1794
/*****************************************************************************/
1795
1796
bool dng_opcode_WarpFisheye::IsValidForNegative (const dng_negative &negative) const
1797
0
  {
1798
1799
0
  return fWarpParams.IsValidForNegative (negative);
1800
  
1801
0
  }
1802
1803
/*****************************************************************************/
1804
1805
void dng_opcode_WarpFisheye::PutData (dng_stream &stream) const
1806
0
  {
1807
1808
0
  const uint32 bytes = ParamBytes (fWarpParams.fPlanes);
1809
  
1810
0
  stream.Put_uint32 (bytes);
1811
1812
  // Write the number of planes.
1813
1814
0
  stream.Put_uint32 (fWarpParams.fPlanes);
1815
1816
  // Write the warp coefficients.
1817
1818
0
  for (uint32 plane = 0; plane < fWarpParams.fPlanes; plane++)
1819
0
    {
1820
1821
0
    stream.Put_real64 (fWarpParams.fRadParams [plane][0]);
1822
0
    stream.Put_real64 (fWarpParams.fRadParams [plane][1]);
1823
0
    stream.Put_real64 (fWarpParams.fRadParams [plane][2]);
1824
0
    stream.Put_real64 (fWarpParams.fRadParams [plane][3]);
1825
1826
0
    }
1827
1828
  // Write the optical center.
1829
1830
0
  stream.Put_real64 (fWarpParams.fCenter.h);
1831
0
  stream.Put_real64 (fWarpParams.fCenter.v);
1832
  
1833
0
  }
1834
1835
/*****************************************************************************/
1836
1837
void dng_opcode_WarpFisheye::Apply (dng_host &host,
1838
                  dng_negative &negative,
1839
                  AutoPtr<dng_image> &image)
1840
0
  {
1841
1842
  #if qDNGValidate
1843
1844
  dng_timer timer ("WarpFisheye time");
1845
1846
  #endif
1847
1848
  // Allocate destination image.
1849
  
1850
0
  AutoPtr<dng_image> dstImage (host.Make_dng_image (image->Bounds    (),
1851
0
                            image->Planes    (),
1852
0
                            image->PixelType ()));
1853
                            
1854
  // Warp the image.
1855
  
1856
0
  AutoPtr<dng_warp_params> params (new dng_warp_params_fisheye (fWarpParams));
1857
  
1858
0
  dng_filter_warp filter (*image,
1859
0
              *dstImage,
1860
0
              negative,
1861
0
              params);
1862
1863
0
  filter.Initialize (host);
1864
                      
1865
0
  host.PerformAreaTask (filter,
1866
0
              image->Bounds ());
1867
            
1868
  // Return the new image.
1869
  
1870
0
  image.Reset (dstImage.Release ());
1871
  
1872
0
  }
1873
1874
/*****************************************************************************/
1875
1876
uint32 dng_opcode_WarpFisheye::ParamBytes (uint32 planes)
1877
0
  {
1878
  
1879
0
  return (1 * (uint32) sizeof (uint32)     ) +  // Number of planes.
1880
0
       (4 * (uint32) sizeof (real64) * planes) +  // Warp coefficients.
1881
0
       (2 * (uint32) sizeof (real64)     );   // Optical center.
1882
  
1883
0
  }
1884
1885
/*****************************************************************************/
1886
1887
dng_vignette_radial_params::dng_vignette_radial_params ()
1888
1889
  : fParams (kNumTerms)
1890
  , fCenter (0.5, 0.5)
1891
1892
0
  {
1893
  
1894
0
  }
1895
1896
/*****************************************************************************/
1897
1898
dng_vignette_radial_params::dng_vignette_radial_params (const dng_std_vector<real64> &params,
1899
                            const dng_point_real64 &center)
1900
1901
  : fParams (params)
1902
  , fCenter (center)
1903
1904
0
  {
1905
  
1906
0
  }
1907
1908
/*****************************************************************************/
1909
1910
bool dng_vignette_radial_params::IsNOP () const
1911
0
  {
1912
1913
0
  for (uint32 i = 0; i < fParams.size (); i++)
1914
0
    {
1915
    
1916
0
    if (fParams [i] != 0.0)
1917
0
      {
1918
0
      return false;
1919
0
      }
1920
    
1921
0
    }
1922
1923
0
  return true;
1924
1925
0
  }
1926
1927
/*****************************************************************************/
1928
1929
bool dng_vignette_radial_params::IsValid () const
1930
0
  {
1931
1932
0
  if (fParams.size () != kNumTerms)
1933
0
    {
1934
0
    return false;
1935
0
    }
1936
1937
0
  if (fCenter.h < 0.0 || 
1938
0
    fCenter.h > 1.0 ||
1939
0
    fCenter.v < 0.0 ||
1940
0
    fCenter.v > 1.0)
1941
0
    {
1942
0
    return false;
1943
0
    }
1944
1945
0
  return true;
1946
  
1947
0
  }
1948
1949
/*****************************************************************************/
1950
1951
void dng_vignette_radial_params::Dump () const
1952
0
  {
1953
  
1954
  #if qDNGValidate
1955
1956
  printf ("  Radial vignette params: ");
1957
1958
  for (uint32 i = 0; i < fParams.size (); i++)
1959
    {
1960
1961
    printf ("%s%.6lf",
1962
        (i == 0) ? "" : ", ",
1963
        fParams [i]);
1964
1965
    }
1966
1967
  printf ("\n");
1968
1969
  printf ("  Optical center:\n"
1970
      "  h = %.6lf\n"
1971
      "  v = %.6lf\n",
1972
      fCenter.h,
1973
      fCenter.v);
1974
1975
  #endif
1976
  
1977
0
  }
1978
1979
/*****************************************************************************/
1980
1981
class dng_vignette_radial_function: public dng_1d_function
1982
  {
1983
    
1984
  protected:
1985
1986
    const dng_vignette_radial_params fParams;
1987
1988
  public:
1989
1990
    explicit dng_vignette_radial_function (const dng_vignette_radial_params &params)
1991
1992
      : fParams (params)
1993
1994
0
      {
1995
1996
0
      }
1997
1998
    // x represents r^2, where r is the normalized Euclidean distance from the
1999
    // optical center to a pixel. r lies in [0,1], so r^2 (and hence x) also lies
2000
    // in [0,1].
2001
2002
    virtual real64 Evaluate (real64 x) const
2003
0
      {
2004
2005
0
      DNG_REQUIRE (fParams.fParams.size () == dng_vignette_radial_params::kNumTerms,
2006
0
             "Bad number of vignette opcode coefficients.");
2007
2008
0
      real64 sum = 0.0;
2009
2010
0
      const dng_std_vector<real64> &v = fParams.fParams;
2011
2012
0
      for (dng_std_vector<real64>::const_reverse_iterator i = v.rbegin (); i != v.rend (); i++)
2013
0
        {
2014
0
        sum = x * ((*i) + sum);
2015
0
        }
2016
2017
0
      sum += 1.0;
2018
2019
0
      return sum;
2020
2021
0
      }
2022
    
2023
  };
2024
2025
/*****************************************************************************/
2026
2027
dng_opcode_FixVignetteRadial::dng_opcode_FixVignetteRadial (const dng_vignette_radial_params &params,
2028
                              uint32 flags)
2029
2030
  :   dng_inplace_opcode (dngOpcode_FixVignetteRadial,
2031
              dngVersion_1_3_0_0,
2032
              flags)
2033
2034
  , fParams (params)
2035
2036
  , fImagePlanes (1)
2037
2038
  , fSrcOriginH (0)
2039
  , fSrcOriginV (0)
2040
  
2041
  , fSrcStepH (0)
2042
  , fSrcStepV (0)
2043
  
2044
  , fTableInputBits  (0)
2045
  , fTableOutputBits (0)
2046
  
2047
  , fGainTable ()
2048
2049
0
  {
2050
  
2051
0
  if (!params.IsValid ())
2052
0
    {
2053
0
    ThrowBadFormat ();
2054
0
    }
2055
  
2056
0
  }
2057
    
2058
/*****************************************************************************/
2059
2060
dng_opcode_FixVignetteRadial::dng_opcode_FixVignetteRadial (dng_stream &stream)
2061
2062
  : dng_inplace_opcode (dngOpcode_FixVignetteRadial,
2063
              stream,
2064
              "FixVignetteRadial")
2065
2066
  , fParams ()
2067
2068
  , fImagePlanes (1)
2069
2070
  , fSrcOriginH (0)
2071
  , fSrcOriginV (0)
2072
  
2073
  , fSrcStepH (0)
2074
  , fSrcStepV (0)
2075
  
2076
  , fTableInputBits  (0)
2077
  , fTableOutputBits (0)
2078
2079
  , fGainTable ()
2080
  
2081
0
  {
2082
  
2083
  // Grab the size in bytes.
2084
2085
0
  const uint32 bytes = stream.Get_uint32 ();
2086
2087
  // Verify the size.
2088
2089
0
  if (bytes != ParamBytes ())
2090
0
    {
2091
0
    ThrowBadFormat ();
2092
0
    }
2093
2094
  // Read vignette coefficients.
2095
2096
0
  fParams.fParams = dng_std_vector<real64> (dng_vignette_radial_params::kNumTerms);
2097
2098
0
  for (uint32 i = 0; i < dng_vignette_radial_params::kNumTerms; i++)
2099
0
    {
2100
0
    fParams.fParams [i] = stream.Get_real64 ();
2101
0
    }
2102
2103
  // Read the image center.
2104
2105
0
  fParams.fCenter.h = stream.Get_real64 ();
2106
0
  fParams.fCenter.v = stream.Get_real64 ();
2107
2108
  // Debug.
2109
  
2110
  #if qDNGValidate
2111
  
2112
  if (gVerbose)
2113
    {
2114
2115
    fParams.Dump ();
2116
2117
    }
2118
    
2119
  #endif
2120
2121
0
  if (!fParams.IsValid ())
2122
0
    {
2123
0
    ThrowBadFormat ();
2124
0
    }
2125
  
2126
0
  }
2127
  
2128
/*****************************************************************************/
2129
2130
bool dng_opcode_FixVignetteRadial::IsNOP () const
2131
0
  {
2132
  
2133
0
  return fParams.IsNOP ();
2134
  
2135
0
  }
2136
    
2137
/*****************************************************************************/
2138
2139
bool dng_opcode_FixVignetteRadial::IsValidForNegative (const dng_negative & /* negative */) const
2140
0
  {
2141
  
2142
0
  return fParams.IsValid ();
2143
  
2144
0
  }
2145
  
2146
/*****************************************************************************/
2147
2148
void dng_opcode_FixVignetteRadial::PutData (dng_stream &stream) const
2149
0
  {
2150
  
2151
0
  const uint32 bytes = ParamBytes ();
2152
  
2153
0
  stream.Put_uint32 (bytes);
2154
2155
0
  DNG_REQUIRE (fParams.fParams.size () == dng_vignette_radial_params::kNumTerms,
2156
0
         "Bad number of vignette opcode coefficients.");
2157
2158
0
  for (uint32 i = 0; i < dng_vignette_radial_params::kNumTerms; i++)
2159
0
    {
2160
0
    stream.Put_real64 (fParams.fParams [i]);
2161
0
    }
2162
2163
0
  stream.Put_real64 (fParams.fCenter.h);
2164
0
  stream.Put_real64 (fParams.fCenter.v);
2165
  
2166
0
  }
2167
2168
/*****************************************************************************/
2169
2170
void dng_opcode_FixVignetteRadial::Prepare (dng_negative &negative,
2171
                      uint32 threadCount,
2172
                      const dng_point &tileSize,
2173
                      const dng_rect &imageBounds,
2174
                      uint32 imagePlanes,
2175
                      uint32 bufferPixelType,
2176
                      dng_memory_allocator &allocator)
2177
0
  {
2178
2179
  // This opcode is restricted to 32-bit images.
2180
  
2181
0
  if (bufferPixelType != ttFloat)
2182
0
    {
2183
0
    ThrowBadFormat ();
2184
0
    }
2185
2186
  // Sanity check number of planes.
2187
2188
0
  DNG_ASSERT (imagePlanes >= 1 && imagePlanes <= kMaxColorPlanes, 
2189
0
        "Bad number of planes.");
2190
2191
0
  if (imagePlanes < 1 || imagePlanes > kMaxColorPlanes)
2192
0
    {
2193
0
    ThrowProgramError ();
2194
0
    }
2195
  
2196
0
  fImagePlanes = imagePlanes;
2197
2198
  // Set the vignette correction curve.
2199
2200
0
  const dng_vignette_radial_function curve (fParams);
2201
2202
  // Grab the destination image area.
2203
2204
0
  const dng_rect_real64 bounds (imageBounds);
2205
2206
  // Determine the optical center and maximum radius in pixel coordinates.
2207
2208
0
  const dng_point_real64 centerPixel (Lerp_real64 (bounds.t,
2209
0
                           bounds.b,
2210
0
                           fParams.fCenter.v),
2211
2212
0
                    Lerp_real64 (bounds.l,
2213
0
                           bounds.r,
2214
0
                           fParams.fCenter.h));
2215
2216
0
  const real64 pixelScaleV = 1.0 / negative.PixelAspectRatio ();
2217
2218
0
  const real64 maxRadius = hypot (Max_real64 (Abs_real64 (centerPixel.v - bounds.t),
2219
0
                        Abs_real64 (centerPixel.v - bounds.b)) * pixelScaleV,
2220
2221
0
                  Max_real64 (Abs_real64 (centerPixel.h - bounds.l),
2222
0
                        Abs_real64 (centerPixel.h - bounds.r)));
2223
2224
0
  const dng_point_real64 radius (maxRadius,
2225
0
                   maxRadius);
2226
2227
  // Find origin and scale.
2228
2229
0
  const real64 pixelScaleH = 1.0;
2230
  
2231
0
  fSrcOriginH = Real64ToFixed64 (-centerPixel.h * pixelScaleH / radius.h);
2232
0
  fSrcOriginV = Real64ToFixed64 (-centerPixel.v * pixelScaleV / radius.v);
2233
  
2234
0
  fSrcStepH = Real64ToFixed64 (pixelScaleH / radius.h);
2235
0
  fSrcStepV = Real64ToFixed64 (pixelScaleV / radius.v);
2236
  
2237
  // Adjust for pixel centers.
2238
  
2239
0
  fSrcOriginH += fSrcStepH >> 1;
2240
0
  fSrcOriginV += fSrcStepV >> 1;
2241
  
2242
  // Evaluate 32-bit vignette correction table.
2243
  
2244
0
  dng_1d_table table32;
2245
  
2246
0
  table32.Initialize (allocator,
2247
0
            curve,
2248
0
            false);
2249
  
2250
  // Find maximum scale factor.
2251
  
2252
0
  const real64 maxScale = Max_real32 (table32.Interpolate (0.0f),
2253
0
                    table32.Interpolate (1.0f));
2254
                  
2255
  // Find table input bits.
2256
  
2257
0
  fTableInputBits = 16;
2258
                  
2259
  // Find table output bits.
2260
  
2261
0
  fTableOutputBits = 15;
2262
  
2263
0
  while ((1 << fTableOutputBits) * maxScale > 65535.0)
2264
0
    {
2265
0
    fTableOutputBits--;
2266
0
    }
2267
  
2268
  // Allocate 16-bit scale table.
2269
  
2270
0
  const uint32 tableEntries = (1 << fTableInputBits) + 1;
2271
  
2272
0
  fGainTable.Reset (allocator.Allocate (tableEntries * (uint32) sizeof (uint16)));
2273
  
2274
0
  uint16 *table16 = fGainTable->Buffer_uint16 ();
2275
  
2276
  // Interpolate 32-bit table into 16-bit table.
2277
  
2278
0
  const real32 scale0 = 1.0f / (1 << fTableInputBits );
2279
0
  const real32 scale1 = 1.0f * (1 << fTableOutputBits);
2280
  
2281
0
  for (uint32 index = 0; index < tableEntries; index++)
2282
0
    {
2283
    
2284
0
    real32 x = index * scale0;
2285
    
2286
0
    real32 y = table32.Interpolate (x) * scale1;
2287
    
2288
0
    table16 [index] = (uint16) Round_uint32 (y);
2289
    
2290
0
    }
2291
2292
  // Prepare vignette mask buffers.
2293
2294
0
    {
2295
2296
0
    const uint32 pixelType = ttShort;
2297
0
    const uint32 bufferSize = ComputeBufferSize(pixelType, tileSize,
2298
0
                          imagePlanes, pad16Bytes);
2299
                   
2300
0
    for (uint32 threadIndex = 0; threadIndex < threadCount; threadIndex++)
2301
0
      {
2302
        
2303
0
      fMaskBuffers [threadIndex] . Reset (allocator.Allocate (bufferSize));
2304
        
2305
0
      }
2306
2307
0
    }
2308
        
2309
0
  }
2310
2311
/*****************************************************************************/
2312
2313
void dng_opcode_FixVignetteRadial::ProcessArea (dng_negative & /* negative */,
2314
                        uint32 threadIndex,
2315
                        dng_pixel_buffer &buffer,
2316
                        const dng_rect &dstArea,
2317
                        const dng_rect & /* imageBounds */)
2318
0
  {
2319
2320
  // Setup mask pixel buffer.
2321
      
2322
0
  dng_pixel_buffer maskPixelBuffer(dstArea, 0, fImagePlanes, ttShort,
2323
0
                   pcRowInterleavedAlign16,
2324
0
                   fMaskBuffers [threadIndex]->Buffer ());
2325
2326
  // Compute mask.
2327
2328
0
  DoVignetteMask16 (maskPixelBuffer.DirtyPixel_uint16 (dstArea.t, dstArea.l),
2329
0
            dstArea.H (),
2330
0
            dstArea.W (),
2331
0
            maskPixelBuffer.RowStep (),
2332
0
            fSrcOriginH + fSrcStepH * dstArea.l,
2333
0
            fSrcOriginV + fSrcStepV * dstArea.t,
2334
0
            fSrcStepH,
2335
0
            fSrcStepV,
2336
0
            fTableInputBits,
2337
0
            fGainTable->Buffer_uint16 ());
2338
2339
  // Apply mask.
2340
2341
0
  DoVignette32 (buffer.DirtyPixel_real32 (dstArea.t, dstArea.l),
2342
0
          maskPixelBuffer.ConstPixel_uint16 (dstArea.t, dstArea.l),
2343
0
          dstArea.H (),
2344
0
          dstArea.W (),
2345
0
          fImagePlanes,
2346
0
          buffer.RowStep (),
2347
0
          buffer.PlaneStep (),
2348
0
          maskPixelBuffer.RowStep (),
2349
0
          fTableOutputBits);
2350
2351
0
  }
2352
2353
/*****************************************************************************/
2354
2355
uint32 dng_opcode_FixVignetteRadial::ParamBytes ()
2356
0
  {
2357
2358
0
  const uint32 N = dng_vignette_radial_params::kNumTerms;
2359
  
2360
0
  return ((N * sizeof (real64)) +  // Vignette coefficients.
2361
0
      (2 * sizeof (real64)));  // Optical center.
2362
  
2363
0
  }
2364
2365
/*****************************************************************************/