Coverage Report

Created: 2026-02-26 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dng_sdk/source/dng_utils.cpp
Line
Count
Source
1
/*****************************************************************************/
2
// Copyright 2006-2012 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_utils.cpp#3 $ */ 
10
/* $DateTime: 2012/08/12 15:38:38 $ */
11
/* $Change: 842799 $ */
12
/* $Author: tknoll $ */
13
14
/*****************************************************************************/
15
16
#include "dng_utils.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_host.h"
23
#include "dng_image.h"
24
#include "dng_flags.h"
25
#include "dng_point.h"
26
#include "dng_rect.h"
27
#include "dng_safe_arithmetic.h"
28
#include "dng_tag_types.h"
29
#include "dng_tile_iterator.h"
30
31
#if qMacOS
32
#include <TargetConditionals.h>
33
#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
34
#include <MobileCoreServices/MobileCoreServices.h>
35
#else
36
#include <CoreServices/CoreServices.h>
37
#endif  // TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
38
#endif  // qMacOS
39
40
#if qiPhone || qMacOS
41
// these provide timers
42
#include <mach/mach.h>
43
#include <mach/mach_time.h>
44
#endif
45
46
#if qWinOS
47
#include <windows.h>
48
#else
49
#include <sys/time.h>
50
#include <stdarg.h> // for va_start/va_end
51
#endif
52
53
/*****************************************************************************/
54
55
#if qDNGDebug
56
57
/*****************************************************************************/
58
59
#if qMacOS
60
  #define DNG_DEBUG_BREAK __asm__ volatile ("int3")
61
#elif qWinOS
62
  #if qDNG64Bit
63
    // no inline assembly on Win 64-bit, so use DebugBreak
64
    #define DNG_DEBUG_BREAK DebugBreak()
65
  #else
66
    #define DNG_DEBUG_BREAK __asm__ volatile ("int3")
67
  #endif
68
#elif qiPhone
69
  // simulator is running on Intel
70
  #if qiPhoneSimulator
71
    #define DNG_DEBUG_BREAK __asm__ volatile ("int3")
72
  #else
73
    // The debugger doesn't restore program counter after this is called.
74
    //   Caller must move program counter past line to continue.
75
    // As of iOS5/xCode 4.2, recovery may not be possible.
76
    #define DNG_DEBUG_BREAK __asm__ volatile ("bkpt 1")
77
  #endif
78
#elif qAndroid
79
  #define DNG_DEBUG_BREAK __asm__ volatile ("bkpt 1") 
80
#elif qLinux
81
  #define DNG_DEBUG_BREAK __asm__ volatile ("int3")
82
#else
83
  #define DNG_DEBUG_BREAK
84
#endif
85
86
/*****************************************************************************/
87
88
bool gPrintAsserts   = true;
89
bool gBreakOnAsserts = true;
90
91
/*****************************************************************************/
92
93
void dng_show_message (const char *s)
94
  {
95
  
96
  #if qDNGPrintMessages
97
  
98
  // display the message
99
  if (gPrintAsserts)
100
    fprintf (stderr, "%s\n", s);
101
    
102
  #elif qiPhone || qAndroid || qLinux
103
  
104
  if (gPrintAsserts)
105
    fprintf (stderr, "%s\n", s);
106
  
107
  // iOS doesn't print a message to the console like DebugStr and MessageBox do, so we have to do both
108
  // You'll have to advance the program counter manually past this statement
109
  if (gBreakOnAsserts)
110
    DNG_DEBUG_BREAK;
111
  
112
  #elif qMacOS
113
  
114
  if (gBreakOnAsserts)
115
    {
116
    // truncate the to 255 chars
117
    char ss [256];
118
  
119
    uint32 len = strlen (s);
120
    if (len > 255)
121
      len = 255;
122
    strncpy (&(ss [1]), s, len );
123
    ss [0] = (unsigned char) len;
124
  
125
    DebugStr ((unsigned char *) ss);
126
    }
127
   else if (gPrintAsserts)
128
    {
129
    fprintf (stderr, "%s\n", s);
130
    }
131
  
132
  #elif qWinOS
133
  
134
  // display a dialog
135
  // This is not thread safe.  Multiple message boxes can be launched.
136
  // Should also be launched in its own thread so main msg queue isn't thrown off.
137
  if (gBreakOnAsserts)
138
    MessageBoxA (NULL, (LPSTR) s, NULL, MB_OK);
139
  else if (gPrintAsserts)
140
    fprintf (stderr, "%s\n", s);
141
    
142
  #endif
143
144
  }
145
146
/*****************************************************************************/
147
148
void dng_show_message_f (const char *fmt, ... )
149
  {
150
  
151
  char buffer [1024];
152
  
153
  va_list ap;
154
  va_start (ap, fmt);
155
156
  vsnprintf (buffer, sizeof (buffer), fmt, ap);
157
  
158
  va_end (ap);
159
  
160
  dng_show_message (buffer);
161
  
162
  }
163
164
/*****************************************************************************/
165
166
#endif
167
168
/*****************************************************************************/
169
170
uint32 ComputeBufferSize(uint32 pixelType, const dng_point &tileSize,
171
             uint32 numPlanes, PaddingType paddingType)
172
173
49.2k
{
174
  
175
  // Convert tile size to uint32.
176
49.2k
  if (tileSize.h < 0 || tileSize.v < 0)
177
0
    {
178
0
    ThrowMemoryFull("Negative tile size");
179
0
    }
180
49.2k
  const uint32 tileSizeH = static_cast<uint32>(tileSize.h);
181
49.2k
  const uint32 tileSizeV = static_cast<uint32>(tileSize.v);
182
  
183
49.2k
  const uint32 pixelSize = TagTypeSize(pixelType);
184
  
185
  // Add padding to width if necessary.
186
49.2k
  uint32 paddedWidth = tileSizeH;
187
49.2k
  if (paddingType == pad16Bytes)
188
45.3k
    {
189
45.3k
    if (!RoundUpForPixelSize(paddedWidth, pixelSize, &paddedWidth))
190
0
      {
191
0
        ThrowMemoryFull("Arithmetic overflow computing buffer size");
192
0
      }
193
45.3k
    }
194
  
195
  // Compute buffer size.
196
49.2k
  uint32 bufferSize;
197
49.2k
  if (!SafeUint32Mult(paddedWidth, tileSizeV, &bufferSize) ||
198
49.0k
    !SafeUint32Mult(bufferSize, pixelSize, &bufferSize) ||
199
49.0k
    !SafeUint32Mult(bufferSize, numPlanes, &bufferSize))
200
179
    {
201
179
    ThrowMemoryFull("Arithmetic overflow computing buffer size");
202
179
    }
203
  
204
49.2k
  return bufferSize;
205
49.2k
}
206
207
/*****************************************************************************/
208
209
real64 TickTimeInSeconds ()
210
43.6k
  {
211
  
212
  #if qWinOS
213
  
214
  // One might think it prudent to cache the frequency here, however
215
  // low-power CPU modes can, and do, change the value returned.
216
  // Thus the frequencey needs to be retrieved each time.
217
  
218
  // Note that the frequency changing can cause the return
219
  // result to jump backwards, which is why the TickCountInSeconds
220
  // (below) also exists.
221
222
  // Just plug in laptop when doing timings to minimize this.
223
  //  QPC/QPH is a slow call compared to rtdsc.
224
    
225
  #if qImagecore
226
227
  // You should be plugged-in when measuring.
228
229
  static real64 freqMultiplier = 0.0;
230
231
  if (freqMultiplier == 0.0)
232
    {
233
234
    LARGE_INTEGER freq;
235
236
    QueryPerformanceFrequency (&freq);
237
238
    freqMultiplier = 1.0 / (real64) freq.QuadPart;
239
240
    }
241
242
  #else
243
244
  LARGE_INTEGER freq;
245
246
  QueryPerformanceFrequency (&freq);
247
248
  real64 freqMultiplier = 1.0 / (real64) freq.QuadPart;
249
    
250
  #endif  // qImagecore
251
    
252
  LARGE_INTEGER cycles;
253
254
  QueryPerformanceCounter (&cycles);
255
256
  return (real64) cycles.QuadPart * freqMultiplier;
257
258
  #elif qiPhone || qMacOS
259
  
260
  //  this is switching Mac to high performance timer
261
  //  and this is also the timer for iPhone
262
  
263
  // assume frequency is unchanging, requesting frequency every time call
264
  //   is too slow.  multiple cores, different frequency ?
265
  
266
  static real64 freqMultiplier = 0.0;
267
  if (freqMultiplier == 0.0)
268
    {
269
    mach_timebase_info_data_t freq; 
270
    mach_timebase_info(&freq);
271
    
272
    // converts from nanos to micros
273
    //  numer = 125, denom = 3 * 1000
274
    freqMultiplier = ((real64)freq.numer / (real64)freq.denom) * 1.0e-9;
275
    }
276
  
277
  return mach_absolute_time() * freqMultiplier;
278
    
279
  #elif qAndroid || qLinux
280
281
  //this is a fast timer to nanos
282
43.6k
    struct timespec now;
283
43.6k
  clock_gettime(CLOCK_MONOTONIC, &now);
284
43.6k
  return now.tv_sec + (real64)now.tv_nsec * 1.0e-9;
285
286
  #else
287
288
  // Perhaps a better call exists. (e.g. avoid adjtime effects)
289
290
  struct timeval tv;
291
  
292
  gettimeofday (&tv, NULL);
293
294
  return tv.tv_sec + (real64)tv.tv_usec * 1.0e-6;
295
  
296
  #endif
297
298
43.6k
  }
299
300
/*****************************************************************************/
301
302
real64 TickCountInSeconds ()
303
0
  {
304
  
305
0
  return TickTimeInSeconds ();
306
  
307
0
  }
308
309
/*****************************************************************************/
310
311
bool gDNGShowTimers = true;
312
313
dng_timer::dng_timer (const char *message)
314
315
21.8k
  : fMessage   (message             )
316
21.8k
  , fStartTime (TickTimeInSeconds ())
317
  
318
21.8k
  {
319
320
21.8k
  }
321
322
/*****************************************************************************/
323
324
dng_timer::~dng_timer ()
325
21.8k
  {
326
  
327
21.8k
  if (!gDNGShowTimers)
328
0
    return;
329
330
21.8k
  real64 totalTime = TickTimeInSeconds () - fStartTime;
331
  
332
21.8k
  fprintf (stderr, "%s: %0.3f sec\n", fMessage, totalTime);
333
334
21.8k
  }
335
336
/*****************************************************************************/
337
338
real64 MaxSquaredDistancePointToRect (const dng_point_real64 &point,
339
                    const dng_rect_real64 &rect)
340
0
  {
341
  
342
0
  real64 distSqr = DistanceSquared (point, 
343
0
                    rect.TL ());
344
345
0
  distSqr = Max_real64 (distSqr,
346
0
              DistanceSquared (point, 
347
0
                       rect.BL ()));
348
349
0
  distSqr = Max_real64 (distSqr,
350
0
              DistanceSquared (point, 
351
0
                       rect.BR ()));
352
353
0
  distSqr = Max_real64 (distSqr,
354
0
              DistanceSquared (point, 
355
0
                       rect.TR ()));
356
357
0
  return distSqr;
358
  
359
0
  }
360
361
/*****************************************************************************/
362
363
real64 MaxDistancePointToRect (const dng_point_real64 &point,
364
                 const dng_rect_real64 &rect)
365
0
  {
366
367
0
  return sqrt (MaxSquaredDistancePointToRect (point, 
368
0
                        rect));
369
370
0
  }
371
372
/*****************************************************************************/
373
374
dng_dither::dng_dither ()
375
376
3
  : fNoiseBuffer ()
377
378
3
  {
379
  
380
3
  const uint32 kSeed = 1;
381
382
3
  fNoiseBuffer.Allocate (kRNGSize2D * sizeof (uint16));
383
384
3
  uint16 *buffer = fNoiseBuffer.Buffer_uint16 ();
385
    
386
3
  uint32 seed = kSeed;
387
388
49.1k
  for (uint32 i = 0; i < kRNGSize2D; i++)
389
49.1k
    {
390
391
49.1k
    seed = DNG_Random (seed);
392
393
49.1k
    buffer [i] = (uint16) (seed);
394
395
49.1k
    }
396
  
397
3
  }
398
399
/******************************************************************************/
400
401
const dng_dither & dng_dither::Get ()
402
18.7k
  {
403
  
404
18.7k
  static dng_dither dither;
405
  
406
18.7k
  return dither;
407
  
408
18.7k
  }
409
410
/*****************************************************************************/
411
412
void HistogramArea (dng_host & /* host */,
413
          const dng_image &image,
414
          const dng_rect &area,
415
          uint32 *hist,
416
          uint32 maxValue,
417
          uint32 plane)
418
2.60k
  {
419
  
420
2.60k
  DNG_ASSERT (image.PixelType () == ttShort, "Unsupported pixel type");
421
  
422
2.60k
  DoZeroBytes (hist, (maxValue + 1) * (uint32) sizeof (uint32));
423
  
424
2.60k
  dng_rect tile;
425
  
426
2.60k
  dng_tile_iterator iter (image, area);
427
  
428
4.79k
  while (iter.GetOneTile (tile))
429
2.19k
    {
430
    
431
2.19k
    dng_const_tile_buffer buffer (image, tile);
432
    
433
2.19k
    const void *sPtr = buffer.ConstPixel (tile.t,
434
2.19k
                        tile.l,
435
2.19k
                        plane);
436
    
437
2.19k
    uint32 count0 = 1;
438
2.19k
    uint32 count1 = tile.H ();
439
2.19k
    uint32 count2 = tile.W ();
440
    
441
2.19k
    int32 step0 = 0;
442
2.19k
    int32 step1 = buffer.fRowStep;
443
2.19k
    int32 step2 = buffer.fColStep;
444
    
445
2.19k
    OptimizeOrder (sPtr,
446
2.19k
             buffer.fPixelSize,
447
2.19k
             count0,
448
2.19k
             count1,
449
2.19k
             count2,
450
2.19k
             step0,
451
2.19k
             step1,
452
2.19k
             step2);
453
             
454
2.19k
    DNG_ASSERT (count0 == 1, "OptimizeOrder logic error");
455
    
456
2.19k
    const uint16 *s1 = (const uint16 *) sPtr;
457
        
458
4.99k
    for (uint32 row = 0; row < count1; row++)
459
2.80k
      {
460
      
461
2.80k
      if (maxValue == 0x0FFFF && step2 == 1)
462
1.46k
        {
463
        
464
9.29M
        for (uint32 col = 0; col < count2; col++)
465
9.28M
          {
466
          
467
9.28M
          uint32 x = s1 [col];
468
          
469
9.28M
          hist [x] ++;
470
          
471
9.28M
          }
472
          
473
1.46k
        }
474
        
475
1.33k
      else
476
1.33k
        {
477
      
478
1.33k
        const uint16 *s2 = s1;
479
      
480
34.1M
        for (uint32 col = 0; col < count2; col++)
481
34.1M
          {
482
          
483
34.1M
          uint32 x = s2 [0];
484
          
485
34.1M
          if (x <= maxValue)
486
34.1M
            {
487
          
488
34.1M
            hist [x] ++;
489
            
490
34.1M
            }
491
          
492
34.1M
          s2 += step2;
493
          
494
34.1M
          }
495
          
496
1.33k
        }
497
        
498
2.80k
      s1 += step1;
499
      
500
2.80k
      }
501
    
502
2.19k
    }
503
    
504
2.60k
  }
505
    
506
/*****************************************************************************/
507
508
class dng_limit_float_depth_task: public dng_area_task
509
  {
510
  
511
  private:
512
  
513
    const dng_image &fSrcImage;
514
    
515
    dng_image &fDstImage;
516
    
517
    uint32 fBitDepth;
518
    
519
    real32 fScale;
520
      
521
  public:
522
  
523
    dng_limit_float_depth_task (const dng_image &srcImage,
524
                  dng_image &dstImage,
525
                  uint32 bitDepth,
526
                  real32 scale);
527
               
528
    virtual dng_rect RepeatingTile1 () const
529
1.87k
      {
530
1.87k
      return fSrcImage.RepeatingTile ();
531
1.87k
      }
532
      
533
    virtual dng_rect RepeatingTile2 () const
534
1.87k
      {
535
1.87k
      return fDstImage.RepeatingTile ();
536
1.87k
      }
537
               
538
    virtual void Process (uint32 threadIndex,
539
                const dng_rect &tile,
540
                dng_abort_sniffer *sniffer);
541
                  
542
  };
543
544
/*****************************************************************************/
545
546
dng_limit_float_depth_task::dng_limit_float_depth_task (const dng_image &srcImage,
547
                            dng_image &dstImage,
548
                            uint32 bitDepth,
549
                            real32 scale)
550
                    
551
936
  : fSrcImage (srcImage)
552
936
  , fDstImage (dstImage)
553
936
  , fBitDepth (bitDepth)
554
936
  , fScale    (scale)
555
  
556
936
  {
557
  
558
936
  }
559
560
/*****************************************************************************/
561
562
void dng_limit_float_depth_task::Process (uint32 /* threadIndex */,
563
                      const dng_rect &tile,
564
                      dng_abort_sniffer * /* sniffer */)
565
4.47k
  {
566
  
567
4.47k
  dng_const_tile_buffer srcBuffer (fSrcImage, tile);
568
4.47k
  dng_dirty_tile_buffer dstBuffer (fDstImage, tile);
569
  
570
4.47k
  uint32 count0 = tile.H ();
571
4.47k
  uint32 count1 = tile.W ();
572
4.47k
  uint32 count2 = fDstImage.Planes ();
573
  
574
4.47k
  int32 sStep0 = srcBuffer.fRowStep;
575
4.47k
  int32 sStep1 = srcBuffer.fColStep;
576
4.47k
  int32 sStep2 = srcBuffer.fPlaneStep;
577
  
578
4.47k
  int32 dStep0 = dstBuffer.fRowStep;
579
4.47k
  int32 dStep1 = dstBuffer.fColStep;
580
4.47k
  int32 dStep2 = dstBuffer.fPlaneStep;
581
582
4.47k
  const void *sPtr = srcBuffer.ConstPixel (tile.t,
583
4.47k
                       tile.l,
584
4.47k
                       0);
585
                       
586
4.47k
      void *dPtr = dstBuffer.DirtyPixel (tile.t,
587
4.47k
                       tile.l,
588
4.47k
                       0);
589
590
4.47k
  OptimizeOrder (sPtr,
591
4.47k
             dPtr,
592
4.47k
           srcBuffer.fPixelSize,
593
4.47k
           dstBuffer.fPixelSize,
594
4.47k
           count0,
595
4.47k
           count1,
596
4.47k
           count2,
597
4.47k
           sStep0,
598
4.47k
           sStep1,
599
4.47k
           sStep2,
600
4.47k
           dStep0,
601
4.47k
           dStep1,
602
4.47k
           dStep2);
603
           
604
4.47k
  const real32 *sPtr0 = (const real32 *) sPtr;
605
4.47k
      real32 *dPtr0 = (      real32 *) dPtr;
606
      
607
4.47k
  real32 scale = fScale;
608
      
609
4.47k
  bool limit16 = (fBitDepth == 16);
610
4.47k
  bool limit24 = (fBitDepth == 24);
611
           
612
25.0k
  for (uint32 index0 = 0; index0 < count0; index0++)
613
20.6k
    {
614
    
615
20.6k
    const real32 *sPtr1 = sPtr0;
616
20.6k
        real32 *dPtr1 = dPtr0;
617
        
618
60.4k
    for (uint32 index1 = 0; index1 < count1; index1++)
619
39.8k
      {
620
      
621
      // If the scale is a NOP, and the data is packed solid, we can just do memory
622
      // copy.
623
      
624
39.8k
      if (scale == 1.0f && sStep2 == 1 && dStep2 == 1)
625
0
        {
626
        
627
0
        if (dPtr1 != sPtr1)     // srcImage != dstImage
628
0
          {
629
        
630
0
          memcpy (dPtr1, sPtr1, count2 * (uint32) sizeof (real32));
631
          
632
0
          }
633
        
634
0
        }
635
        
636
39.8k
      else
637
39.8k
        {
638
      
639
39.8k
        const real32 *sPtr2 = sPtr1;
640
39.8k
            real32 *dPtr2 = dPtr1;
641
            
642
18.3M
        for (uint32 index2 = 0; index2 < count2; index2++)
643
18.3M
          {
644
          
645
18.3M
          real32 x = sPtr2 [0];
646
          
647
18.3M
          x *= scale;
648
          
649
18.3M
          dPtr2 [0] = x;
650
          
651
18.3M
          sPtr2 += sStep2;
652
18.3M
          dPtr2 += dStep2;
653
          
654
18.3M
          }
655
          
656
39.8k
        }
657
        
658
      // The data is now in the destination buffer.
659
        
660
39.8k
      if (limit16)
661
39.8k
        {
662
      
663
39.8k
        uint32 *dPtr2 = (uint32 *) dPtr1;
664
            
665
18.3M
        for (uint32 index2 = 0; index2 < count2; index2++)
666
18.3M
          {
667
          
668
18.3M
          uint32 x = dPtr2 [0];
669
          
670
18.3M
          uint16 y = DNG_FloatToHalf (x);
671
          
672
18.3M
          x = DNG_HalfToFloat (y);
673
                      
674
18.3M
          dPtr2 [0] = x;
675
          
676
18.3M
          dPtr2 += dStep2;
677
          
678
18.3M
          }
679
          
680
39.8k
        }
681
        
682
0
      else if (limit24)
683
0
        {
684
      
685
0
        uint32 *dPtr2 = (uint32 *) dPtr1;
686
            
687
0
        for (uint32 index2 = 0; index2 < count2; index2++)
688
0
          {
689
          
690
0
          uint32 x = dPtr2 [0];
691
                      
692
0
          uint8 temp [3];
693
          
694
0
          DNG_FloatToFP24 (x, temp);
695
          
696
0
          x = DNG_FP24ToFloat (temp);
697
          
698
0
          dPtr2 [0] = x;
699
          
700
0
          dPtr2 += dStep2;
701
          
702
0
          }
703
          
704
0
        }
705
        
706
39.8k
      sPtr1 += sStep1;
707
39.8k
      dPtr1 += dStep1;
708
      
709
39.8k
      }
710
           
711
20.6k
    sPtr0 += sStep0;
712
20.6k
    dPtr0 += dStep0;
713
    
714
20.6k
    }
715
            
716
4.47k
  }
717
                  
718
/******************************************************************************/
719
720
void LimitFloatBitDepth (dng_host &host,
721
             const dng_image &srcImage,
722
             dng_image &dstImage,
723
             uint32 bitDepth,
724
             real32 scale)
725
936
  {
726
  
727
936
  DNG_ASSERT (srcImage.PixelType () == ttFloat, "Floating point image expected");
728
936
  DNG_ASSERT (dstImage.PixelType () == ttFloat, "Floating point image expected");
729
  
730
936
  dng_limit_float_depth_task task (srcImage,
731
936
                   dstImage,
732
936
                   bitDepth,
733
936
                   scale);
734
                   
735
936
  host.PerformAreaTask (task, dstImage.Bounds ());
736
  
737
936
  }
738
739
/*****************************************************************************/