Coverage Report

Created: 2025-08-26 06:51

/src/dng_sdk/source/dng_gain_map.cpp
Line
Count
Source (jump to first uncovered line)
1
/*****************************************************************************/
2
// Copyright 2008-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_gain_map.cpp#1 $ */ 
10
/* $DateTime: 2012/05/30 13:28:51 $ */
11
/* $Change: 832332 $ */
12
/* $Author: tknoll $ */
13
14
/*****************************************************************************/
15
16
#include "dng_gain_map.h"
17
18
#include "dng_exceptions.h"
19
#include "dng_globals.h"
20
#include "dng_host.h"
21
#include "dng_pixel_buffer.h"
22
#include "dng_safe_arithmetic.h"
23
#include "dng_stream.h"
24
#include "dng_tag_values.h"
25
26
/*****************************************************************************/
27
28
class dng_gain_map_interpolator
29
  {
30
  
31
  private:
32
  
33
    const dng_gain_map &fMap;
34
    
35
    dng_point_real64 fScale;
36
    dng_point_real64 fOffset;
37
    
38
    int32 fColumn;
39
    int32 fPlane;
40
    
41
    uint32 fRowIndex1;
42
    uint32 fRowIndex2;
43
    real32 fRowFract;
44
    
45
    int32 fResetColumn;
46
    
47
    real32 fValueBase;
48
    real32 fValueStep;
49
    real32 fValueIndex;
50
      
51
  public:
52
  
53
    dng_gain_map_interpolator (const dng_gain_map &map,
54
                   const dng_rect &mapBounds,
55
                   int32 row,
56
                   int32 column,
57
                   uint32 plane);
58
59
    real32 Interpolate () const
60
0
      {
61
      
62
0
      return fValueBase + fValueStep * fValueIndex;
63
      
64
0
      }
65
      
66
    void Increment ()
67
0
      {
68
      
69
0
      if (++fColumn >= fResetColumn)
70
0
        {
71
        
72
0
        ResetColumn ();
73
        
74
0
        }
75
        
76
0
      else
77
0
        {
78
        
79
0
        fValueIndex += 1.0f;
80
        
81
0
        }
82
            
83
0
      }
84
  
85
  private:
86
      
87
    real32 InterpolateEntry (uint32 colIndex);
88
      
89
    void ResetColumn ();
90
      
91
  };
92
      
93
/*****************************************************************************/
94
95
dng_gain_map_interpolator::dng_gain_map_interpolator (const dng_gain_map &map,
96
                            const dng_rect &mapBounds,
97
                            int32 row,
98
                            int32 column,
99
                            uint32 plane)
100
101
0
  : fMap (map)
102
  
103
0
  , fScale (1.0 / mapBounds.H (),
104
0
        1.0 / mapBounds.W ())
105
  
106
0
  , fOffset (0.5 - mapBounds.t,
107
0
         0.5 - mapBounds.l)
108
  
109
0
  , fColumn (column)
110
0
  , fPlane  (plane)
111
  
112
0
  , fRowIndex1 (0)
113
0
  , fRowIndex2 (0)
114
0
  , fRowFract  (0.0f)
115
  
116
0
  , fResetColumn (0)
117
  
118
0
  , fValueBase  (0.0f)
119
0
  , fValueStep  (0.0f)
120
0
  , fValueIndex (0.0f)
121
  
122
0
  {
123
  
124
0
  real64 rowIndexF = (fScale.v * (row + fOffset.v) -
125
0
            fMap.Origin ().v) / fMap.Spacing ().v;
126
  
127
0
  if (rowIndexF <= 0.0)
128
0
    {
129
    
130
0
    fRowIndex1 = 0;
131
0
    fRowIndex2 = 0;
132
    
133
0
    fRowFract = 0.0f;
134
135
0
    }
136
    
137
0
  else
138
0
    {
139
    
140
0
    if (fMap.Points ().v < 1)
141
0
      {
142
0
      ThrowProgramError ("Empty gain map");
143
0
      }
144
0
    uint32 lastRow = static_cast<uint32> (fMap.Points ().v - 1);
145
    
146
0
    if (rowIndexF >= static_cast<real64> (lastRow))
147
0
      {
148
      
149
0
      fRowIndex1 = lastRow;
150
0
      fRowIndex2 = fRowIndex1;
151
      
152
0
      fRowFract = 0.0f;
153
      
154
0
      }
155
      
156
0
    else
157
0
      {
158
      
159
      // If we got here, we know that rowIndexF can safely be converted to
160
      // a uint32 and that static_cast<uint32> (rowIndexF) < lastRow. This
161
      // implies fRowIndex2 <= lastRow below.
162
0
      fRowIndex1 = static_cast<uint32> (rowIndexF);
163
0
      fRowIndex2 = fRowIndex1 + 1;
164
      
165
0
      fRowFract = (real32) (rowIndexF - (real64) fRowIndex1);
166
      
167
0
      }
168
      
169
0
    }
170
  
171
0
  ResetColumn ();
172
    
173
0
  }
174
175
/*****************************************************************************/
176
177
real32 dng_gain_map_interpolator::InterpolateEntry (uint32 colIndex)
178
0
  {
179
  
180
0
  return fMap.Entry (fRowIndex1, colIndex, fPlane) * (1.0f - fRowFract) +
181
0
       fMap.Entry (fRowIndex2, colIndex, fPlane) * (       fRowFract);
182
  
183
0
  }
184
185
/*****************************************************************************/
186
187
void dng_gain_map_interpolator::ResetColumn ()
188
0
  {
189
  
190
0
  real64 colIndexF = ((fScale.h * (fColumn + fOffset.h)) - 
191
0
            fMap.Origin ().h) / fMap.Spacing ().h;
192
  
193
0
  if (colIndexF <= 0.0)
194
0
    {
195
    
196
0
    fValueBase = InterpolateEntry (0);
197
    
198
0
    fValueStep = 0.0f;
199
    
200
0
    fResetColumn = (int32) ceil (fMap.Origin ().h / fScale.h - fOffset.h);
201
202
0
    }
203
    
204
0
  else
205
0
    {
206
  
207
0
    if (fMap.Points ().h < 1)
208
0
      {
209
0
      ThrowProgramError ("Empty gain map");
210
0
      }
211
0
    uint32 lastCol = static_cast<uint32> (fMap.Points ().h - 1);
212
    
213
0
    if (colIndexF >= static_cast<real64> (lastCol))
214
0
      {
215
      
216
0
      fValueBase = InterpolateEntry (lastCol);
217
      
218
0
      fValueStep = 0.0f;
219
      
220
0
      fResetColumn = 0x7FFFFFFF;
221
      
222
0
      }
223
    
224
0
    else
225
0
      {
226
      
227
      // If we got here, we know that colIndexF can safely be converted to
228
      // a uint32 and that static_cast<uint32> (colIndexF) < lastCol. This
229
      // implies colIndex + 1 <= lastCol, i.e. the argument to
230
      // InterpolateEntry() below is valid.
231
0
      uint32 colIndex = static_cast<uint32> (colIndexF);
232
0
      real64 base  = InterpolateEntry (colIndex);
233
0
      real64 delta = InterpolateEntry (colIndex + 1) - base;
234
      
235
0
      fValueBase = (real32) (base + delta * (colIndexF - (real64) colIndex));
236
      
237
0
      fValueStep = (real32) ((delta * fScale.h) / fMap.Spacing ().h);
238
      
239
0
      fResetColumn = (int32) ceil (((colIndex + 1) * fMap.Spacing ().h +
240
0
                      fMap.Origin ().h) / fScale.h - fOffset.h);
241
      
242
0
      }
243
      
244
0
    }
245
  
246
0
  fValueIndex = 0.0f;
247
  
248
0
  }
249
250
/*****************************************************************************/
251
252
dng_gain_map::dng_gain_map (dng_memory_allocator &allocator,
253
              const dng_point &points,
254
              const dng_point_real64 &spacing,
255
              const dng_point_real64 &origin,
256
              uint32 planes)
257
          
258
406
  : fPoints  (points)
259
406
  , fSpacing (spacing)
260
406
  , fOrigin  (origin)
261
406
  , fPlanes  (planes)
262
  
263
406
  , fRowStep (SafeUint32Mult(planes, points.h))
264
  
265
406
  , fBuffer ()
266
  
267
406
  {
268
  
269
406
  fBuffer.Reset (allocator.Allocate (
270
406
    ComputeBufferSize (ttFloat, fPoints, fPlanes, pad16Bytes)));
271
  
272
406
  }
273
            
274
/*****************************************************************************/
275
276
real32 dng_gain_map::Interpolate (int32 row,
277
                  int32 col,
278
                  uint32 plane,
279
                  const dng_rect &bounds) const
280
0
  {
281
  
282
0
  dng_gain_map_interpolator interp (*this,
283
0
                    bounds,
284
0
                    row,
285
0
                    col,
286
0
                    plane);
287
                    
288
0
  return interp.Interpolate ();
289
  
290
0
  }
291
            
292
/*****************************************************************************/
293
294
uint32 dng_gain_map::PutStreamSize () const
295
0
  {
296
  
297
0
  return 44 + fPoints.v * fPoints.h * fPlanes * 4;
298
  
299
0
  }
300
            
301
/*****************************************************************************/
302
303
void dng_gain_map::PutStream (dng_stream &stream) const
304
0
  {
305
  
306
0
  stream.Put_uint32 (fPoints.v);
307
0
  stream.Put_uint32 (fPoints.h);
308
  
309
0
  stream.Put_real64 (fSpacing.v);
310
0
  stream.Put_real64 (fSpacing.h);
311
  
312
0
  stream.Put_real64 (fOrigin.v);
313
0
  stream.Put_real64 (fOrigin.h);
314
  
315
0
  stream.Put_uint32 (fPlanes);
316
  
317
0
  for (int32 rowIndex = 0; rowIndex < fPoints.v; rowIndex++)
318
0
    {
319
    
320
0
    for (int32 colIndex = 0; colIndex < fPoints.h; colIndex++)
321
0
      {
322
      
323
0
      for (uint32 plane = 0; plane < fPlanes; plane++)
324
0
        {
325
        
326
0
        stream.Put_real32 (Entry (rowIndex,
327
0
                      colIndex,
328
0
                      plane));
329
                      
330
0
        }
331
        
332
0
      }
333
      
334
0
    }
335
  
336
0
  }
337
338
/*****************************************************************************/
339
340
dng_gain_map * dng_gain_map::GetStream (dng_host &host,
341
                    dng_stream &stream)
342
699
  {
343
  
344
699
  dng_point mapPoints;
345
  
346
699
  mapPoints.v = stream.Get_uint32 ();
347
699
  mapPoints.h = stream.Get_uint32 ();
348
  
349
699
  dng_point_real64 mapSpacing;
350
  
351
699
  mapSpacing.v = stream.Get_real64 ();
352
699
  mapSpacing.h = stream.Get_real64 ();
353
  
354
699
  dng_point_real64 mapOrigin;
355
  
356
699
  mapOrigin.v = stream.Get_real64 ();
357
699
  mapOrigin.h = stream.Get_real64 ();
358
  
359
699
  uint32 mapPlanes = stream.Get_uint32 ();
360
  
361
  #if qDNGValidate
362
  
363
  if (gVerbose)
364
    {
365
    
366
    printf ("Points: v=%d, h=%d\n", 
367
        (int) mapPoints.v,
368
        (int) mapPoints.h);
369
    
370
    printf ("Spacing: v=%.6f, h=%.6f\n", 
371
        mapSpacing.v,
372
        mapSpacing.h);
373
    
374
    printf ("Origin: v=%.6f, h=%.6f\n", 
375
        mapOrigin.v,
376
        mapOrigin.h);
377
    
378
    printf ("Planes: %u\n", 
379
        (unsigned) mapPlanes);
380
    
381
    }
382
    
383
  #endif
384
  
385
699
  if (mapPoints.v == 1)
386
47
    {
387
47
    mapSpacing.v = 1.0;
388
47
    mapOrigin.v  = 0.0;
389
47
    }
390
  
391
699
  if (mapPoints.h == 1)
392
77
    {
393
77
    mapSpacing.h = 1.0;
394
77
    mapOrigin.h  = 0.0;
395
77
    }
396
    
397
699
  if (mapPoints.v < 1 ||
398
699
    mapPoints.h < 1 ||
399
699
    mapSpacing.v <= 0.0 ||
400
699
    mapSpacing.h <= 0.0 ||
401
699
    mapPlanes < 1)
402
263
    {
403
263
    ThrowBadFormat ();
404
263
    }
405
  
406
699
  AutoPtr<dng_gain_map> map (new dng_gain_map (host.Allocator (),
407
699
                         mapPoints,
408
699
                         mapSpacing,
409
699
                         mapOrigin,
410
699
                         mapPlanes));
411
                         
412
  #if qDNGValidate
413
  
414
  uint32 linesPrinted = 0;
415
  uint32 linesSkipped = 0;
416
  
417
  #endif
418
  
419
4.48k
  for (int32 rowIndex = 0; rowIndex < mapPoints.v; rowIndex++)
420
3.78k
    {
421
    
422
9.98k
    for (int32 colIndex = 0; colIndex < mapPoints.h; colIndex++)
423
6.20k
      {
424
      
425
19.6k
      for (uint32 plane = 0; plane < mapPlanes; plane++)
426
13.4k
        {
427
        
428
13.4k
        real32 x = stream.Get_real32 ();
429
        
430
13.4k
        map->Entry (rowIndex, colIndex, plane) = x;
431
        
432
        #if qDNGValidate
433
        
434
        if (gVerbose)
435
          {
436
          
437
          if (linesPrinted < gDumpLineLimit)
438
            {
439
            
440
            printf ("    Map [%3u] [%3u] [%u] = %.4f\n",
441
                (unsigned) rowIndex,
442
                (unsigned) colIndex,
443
                (unsigned) plane,
444
                x);
445
            
446
            linesPrinted++;
447
            
448
            }
449
            
450
          else
451
            linesSkipped++;
452
            
453
          }
454
          
455
        #endif
456
457
13.4k
        }
458
        
459
6.20k
      }
460
      
461
3.78k
    }
462
                         
463
  #if qDNGValidate
464
  
465
  if (linesSkipped)
466
    {
467
    
468
    printf ("    ... %u map entries skipped\n", (unsigned) linesSkipped);
469
    
470
    }
471
  
472
  #endif
473
        
474
699
  return map.Release ();
475
  
476
699
  }
477
478
/*****************************************************************************/
479
480
dng_opcode_GainMap::dng_opcode_GainMap (const dng_area_spec &areaSpec,
481
                    AutoPtr<dng_gain_map> &gainMap)
482
  
483
0
  : dng_inplace_opcode (dngOpcode_GainMap,
484
0
                dngVersion_1_3_0_0,
485
0
                kFlag_None)
486
              
487
0
  , fAreaSpec (areaSpec)
488
          
489
0
  , fGainMap ()
490
  
491
0
  {
492
  
493
0
  fGainMap.Reset (gainMap.Release ());
494
  
495
0
  }
496
    
497
/*****************************************************************************/
498
499
dng_opcode_GainMap::dng_opcode_GainMap (dng_host &host,
500
                    dng_stream &stream)
501
                        
502
1.14k
  : dng_inplace_opcode (dngOpcode_GainMap,
503
1.14k
              stream,
504
1.14k
              "GainMap")
505
              
506
1.14k
  , fAreaSpec ()
507
              
508
1.14k
  , fGainMap ()
509
              
510
1.14k
  {
511
  
512
1.14k
  uint32 byteCount = stream.Get_uint32 ();
513
  
514
1.14k
  uint64 startPosition = stream.Position ();
515
  
516
1.14k
  fAreaSpec.GetData (stream);
517
  
518
1.14k
  fGainMap.Reset (dng_gain_map::GetStream (host, stream));
519
  
520
1.14k
  if (stream.Position () != startPosition + byteCount)
521
29
    {
522
29
    ThrowBadFormat ();
523
29
    }
524
    
525
1.14k
  }
526
    
527
/*****************************************************************************/
528
529
void dng_opcode_GainMap::PutData (dng_stream &stream) const
530
0
  {
531
  
532
0
  stream.Put_uint32 (dng_area_spec::kDataSize +
533
0
             fGainMap->PutStreamSize ());
534
             
535
0
  fAreaSpec.PutData (stream);
536
  
537
0
  fGainMap->PutStream (stream);
538
  
539
0
  }
540
    
541
/*****************************************************************************/
542
543
void dng_opcode_GainMap::ProcessArea (dng_negative & /* negative */,
544
                    uint32 /* threadIndex */,
545
                    dng_pixel_buffer &buffer,
546
                    const dng_rect &dstArea,
547
                    const dng_rect &imageBounds)
548
0
  {
549
  
550
0
  dng_rect overlap = fAreaSpec.Overlap (dstArea);
551
  
552
0
  if (overlap.NotEmpty ())
553
0
    {
554
    
555
0
    uint32 cols = overlap.W ();
556
    
557
0
    uint32 colPitch = fAreaSpec.ColPitch ();
558
    
559
0
    for (uint32 plane = fAreaSpec.Plane ();
560
0
       plane < fAreaSpec.Plane () + fAreaSpec.Planes () &&
561
0
       plane < buffer.Planes ();
562
0
       plane++)
563
0
      {
564
      
565
0
      uint32 mapPlane = Min_uint32 (plane, fGainMap->Planes () - 1);
566
      
567
0
      for (int32 row = overlap.t; row < overlap.b; row += fAreaSpec.RowPitch ())
568
0
        {
569
        
570
0
        real32 *dPtr = buffer.DirtyPixel_real32 (row, overlap.l, plane);
571
        
572
0
        dng_gain_map_interpolator interp (*fGainMap,
573
0
                          imageBounds,
574
0
                          row,
575
0
                          overlap.l,
576
0
                          mapPlane);
577
                       
578
0
        for (uint32 col = 0; col < cols; col += colPitch)
579
0
          {
580
          
581
0
          real32 gain = interp.Interpolate ();
582
          
583
0
          dPtr [col] = Min_real32 (dPtr [col] * gain, 1.0f);
584
          
585
0
          for (uint32 j = 0; j < colPitch; j++)
586
0
            {
587
0
            interp.Increment ();
588
0
            }
589
          
590
0
          }
591
        
592
0
        }
593
      
594
0
      }
595
    
596
0
    }
597
598
0
  }
599
  
600
/*****************************************************************************/