Coverage Report

Created: 2025-11-24 06:57

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
204k
{
174
  
175
  // Convert tile size to uint32.
176
204k
  if (tileSize.h < 0 || tileSize.v < 0)
177
0
    {
178
0
    ThrowMemoryFull("Negative tile size");
179
0
    }
180
204k
  const uint32 tileSizeH = static_cast<uint32>(tileSize.h);
181
204k
  const uint32 tileSizeV = static_cast<uint32>(tileSize.v);
182
  
183
204k
  const uint32 pixelSize = TagTypeSize(pixelType);
184
  
185
  // Add padding to width if necessary.
186
204k
  uint32 paddedWidth = tileSizeH;
187
204k
  if (paddingType == pad16Bytes)
188
178k
    {
189
178k
    if (!RoundUpForPixelSize(paddedWidth, pixelSize, &paddedWidth))
190
0
      {
191
0
        ThrowMemoryFull("Arithmetic overflow computing buffer size");
192
0
      }
193
178k
    }
194
  
195
  // Compute buffer size.
196
204k
  uint32 bufferSize;
197
204k
  if (!SafeUint32Mult(paddedWidth, tileSizeV, &bufferSize) ||
198
203k
    !SafeUint32Mult(bufferSize, pixelSize, &bufferSize) ||
199
203k
    !SafeUint32Mult(bufferSize, numPlanes, &bufferSize))
200
410
    {
201
410
    ThrowMemoryFull("Arithmetic overflow computing buffer size");
202
410
    }
203
  
204
204k
  return bufferSize;
205
204k
}
206
207
/*****************************************************************************/
208
209
real64 TickTimeInSeconds ()
210
112k
  {
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
112k
    struct timespec now;
283
112k
  clock_gettime(CLOCK_MONOTONIC, &now);
284
112k
  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
112k
  }
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
56.2k
  : fMessage   (message             )
316
56.2k
  , fStartTime (TickTimeInSeconds ())
317
  
318
56.2k
  {
319
320
56.2k
  }
321
322
/*****************************************************************************/
323
324
dng_timer::~dng_timer ()
325
56.2k
  {
326
  
327
56.2k
  if (!gDNGShowTimers)
328
0
    return;
329
330
56.2k
  real64 totalTime = TickTimeInSeconds () - fStartTime;
331
  
332
56.2k
  fprintf (stderr, "%s: %0.3f sec\n", fMessage, totalTime);
333
334
56.2k
  }
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
66.7k
  {
403
  
404
66.7k
  static dng_dither dither;
405
  
406
66.7k
  return dither;
407
  
408
66.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
10.4k
  {
419
  
420
10.4k
  DNG_ASSERT (image.PixelType () == ttShort, "Unsupported pixel type");
421
  
422
10.4k
  DoZeroBytes (hist, (maxValue + 1) * (uint32) sizeof (uint32));
423
  
424
10.4k
  dng_rect tile;
425
  
426
10.4k
  dng_tile_iterator iter (image, area);
427
  
428
20.0k
  while (iter.GetOneTile (tile))
429
9.63k
    {
430
    
431
9.63k
    dng_const_tile_buffer buffer (image, tile);
432
    
433
9.63k
    const void *sPtr = buffer.ConstPixel (tile.t,
434
9.63k
                        tile.l,
435
9.63k
                        plane);
436
    
437
9.63k
    uint32 count0 = 1;
438
9.63k
    uint32 count1 = tile.H ();
439
9.63k
    uint32 count2 = tile.W ();
440
    
441
9.63k
    int32 step0 = 0;
442
9.63k
    int32 step1 = buffer.fRowStep;
443
9.63k
    int32 step2 = buffer.fColStep;
444
    
445
9.63k
    OptimizeOrder (sPtr,
446
9.63k
             buffer.fPixelSize,
447
9.63k
             count0,
448
9.63k
             count1,
449
9.63k
             count2,
450
9.63k
             step0,
451
9.63k
             step1,
452
9.63k
             step2);
453
             
454
9.63k
    DNG_ASSERT (count0 == 1, "OptimizeOrder logic error");
455
    
456
9.63k
    const uint16 *s1 = (const uint16 *) sPtr;
457
        
458
121k
    for (uint32 row = 0; row < count1; row++)
459
112k
      {
460
      
461
112k
      if (maxValue == 0x0FFFF && step2 == 1)
462
106k
        {
463
        
464
1.75G
        for (uint32 col = 0; col < count2; col++)
465
1.75G
          {
466
          
467
1.75G
          uint32 x = s1 [col];
468
          
469
1.75G
          hist [x] ++;
470
          
471
1.75G
          }
472
          
473
106k
        }
474
        
475
5.93k
      else
476
5.93k
        {
477
      
478
5.93k
        const uint16 *s2 = s1;
479
      
480
216M
        for (uint32 col = 0; col < count2; col++)
481
216M
          {
482
          
483
216M
          uint32 x = s2 [0];
484
          
485
216M
          if (x <= maxValue)
486
216M
            {
487
          
488
216M
            hist [x] ++;
489
            
490
216M
            }
491
          
492
216M
          s2 += step2;
493
          
494
216M
          }
495
          
496
5.93k
        }
497
        
498
112k
      s1 += step1;
499
      
500
112k
      }
501
    
502
9.63k
    }
503
    
504
10.4k
  }
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
7.76k
      {
530
7.76k
      return fSrcImage.RepeatingTile ();
531
7.76k
      }
532
      
533
    virtual dng_rect RepeatingTile2 () const
534
7.76k
      {
535
7.76k
      return fDstImage.RepeatingTile ();
536
7.76k
      }
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
3.88k
  : fSrcImage (srcImage)
552
3.88k
  , fDstImage (dstImage)
553
3.88k
  , fBitDepth (bitDepth)
554
3.88k
  , fScale    (scale)
555
  
556
3.88k
  {
557
  
558
3.88k
  }
559
560
/*****************************************************************************/
561
562
void dng_limit_float_depth_task::Process (uint32 /* threadIndex */,
563
                      const dng_rect &tile,
564
                      dng_abort_sniffer * /* sniffer */)
565
26.4k
  {
566
  
567
26.4k
  dng_const_tile_buffer srcBuffer (fSrcImage, tile);
568
26.4k
  dng_dirty_tile_buffer dstBuffer (fDstImage, tile);
569
  
570
26.4k
  uint32 count0 = tile.H ();
571
26.4k
  uint32 count1 = tile.W ();
572
26.4k
  uint32 count2 = fDstImage.Planes ();
573
  
574
26.4k
  int32 sStep0 = srcBuffer.fRowStep;
575
26.4k
  int32 sStep1 = srcBuffer.fColStep;
576
26.4k
  int32 sStep2 = srcBuffer.fPlaneStep;
577
  
578
26.4k
  int32 dStep0 = dstBuffer.fRowStep;
579
26.4k
  int32 dStep1 = dstBuffer.fColStep;
580
26.4k
  int32 dStep2 = dstBuffer.fPlaneStep;
581
582
26.4k
  const void *sPtr = srcBuffer.ConstPixel (tile.t,
583
26.4k
                       tile.l,
584
26.4k
                       0);
585
                       
586
26.4k
      void *dPtr = dstBuffer.DirtyPixel (tile.t,
587
26.4k
                       tile.l,
588
26.4k
                       0);
589
590
26.4k
  OptimizeOrder (sPtr,
591
26.4k
             dPtr,
592
26.4k
           srcBuffer.fPixelSize,
593
26.4k
           dstBuffer.fPixelSize,
594
26.4k
           count0,
595
26.4k
           count1,
596
26.4k
           count2,
597
26.4k
           sStep0,
598
26.4k
           sStep1,
599
26.4k
           sStep2,
600
26.4k
           dStep0,
601
26.4k
           dStep1,
602
26.4k
           dStep2);
603
           
604
26.4k
  const real32 *sPtr0 = (const real32 *) sPtr;
605
26.4k
      real32 *dPtr0 = (      real32 *) dPtr;
606
      
607
26.4k
  real32 scale = fScale;
608
      
609
26.4k
  bool limit16 = (fBitDepth == 16);
610
26.4k
  bool limit24 = (fBitDepth == 24);
611
           
612
166k
  for (uint32 index0 = 0; index0 < count0; index0++)
613
140k
    {
614
    
615
140k
    const real32 *sPtr1 = sPtr0;
616
140k
        real32 *dPtr1 = dPtr0;
617
        
618
1.85M
    for (uint32 index1 = 0; index1 < count1; index1++)
619
1.71M
      {
620
      
621
      // If the scale is a NOP, and the data is packed solid, we can just do memory
622
      // copy.
623
      
624
1.71M
      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
1.71M
      else
637
1.71M
        {
638
      
639
1.71M
        const real32 *sPtr2 = sPtr1;
640
1.71M
            real32 *dPtr2 = dPtr1;
641
            
642
614M
        for (uint32 index2 = 0; index2 < count2; index2++)
643
612M
          {
644
          
645
612M
          real32 x = sPtr2 [0];
646
          
647
612M
          x *= scale;
648
          
649
612M
          dPtr2 [0] = x;
650
          
651
612M
          sPtr2 += sStep2;
652
612M
          dPtr2 += dStep2;
653
          
654
612M
          }
655
          
656
1.71M
        }
657
        
658
      // The data is now in the destination buffer.
659
        
660
1.71M
      if (limit16)
661
1.71M
        {
662
      
663
1.71M
        uint32 *dPtr2 = (uint32 *) dPtr1;
664
            
665
614M
        for (uint32 index2 = 0; index2 < count2; index2++)
666
612M
          {
667
          
668
612M
          uint32 x = dPtr2 [0];
669
          
670
612M
          uint16 y = DNG_FloatToHalf (x);
671
          
672
612M
          x = DNG_HalfToFloat (y);
673
                      
674
612M
          dPtr2 [0] = x;
675
          
676
612M
          dPtr2 += dStep2;
677
          
678
612M
          }
679
          
680
1.71M
        }
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
1.71M
      sPtr1 += sStep1;
707
1.71M
      dPtr1 += dStep1;
708
      
709
1.71M
      }
710
           
711
140k
    sPtr0 += sStep0;
712
140k
    dPtr0 += dStep0;
713
    
714
140k
    }
715
            
716
26.4k
  }
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
3.88k
  {
726
  
727
3.88k
  DNG_ASSERT (srcImage.PixelType () == ttFloat, "Floating point image expected");
728
3.88k
  DNG_ASSERT (dstImage.PixelType () == ttFloat, "Floating point image expected");
729
  
730
3.88k
  dng_limit_float_depth_task task (srcImage,
731
3.88k
                   dstImage,
732
3.88k
                   bitDepth,
733
3.88k
                   scale);
734
                   
735
3.88k
  host.PerformAreaTask (task, dstImage.Bounds ());
736
  
737
3.88k
  }
738
739
/*****************************************************************************/