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_jpeg_image.cpp
Line
Count
Source
1
/*****************************************************************************/
2
// Copyright 2011 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_jpeg_image.cpp#1 $ */ 
10
/* $DateTime: 2012/05/30 13:28:51 $ */
11
/* $Change: 832332 $ */
12
/* $Author: tknoll $ */
13
14
/*****************************************************************************/
15
16
#include "dng_jpeg_image.h"
17
18
#include "dng_abort_sniffer.h"
19
#include "dng_area_task.h"
20
#include "dng_assertions.h"
21
#include "dng_host.h"
22
#include "dng_ifd.h"
23
#include "dng_image.h"
24
#include "dng_image_writer.h"
25
#include "dng_memory_stream.h"
26
#include "dng_mutex.h"
27
#include "dng_safe_arithmetic.h"
28
29
/*****************************************************************************/
30
31
dng_jpeg_image::dng_jpeg_image ()
32
33
6.27k
  : fImageSize  ()
34
6.27k
  , fTileSize   ()
35
6.27k
  , fUsesStrips (false)
36
6.27k
  , fJPEGTables ()
37
6.27k
  , fJPEGData   ()
38
  
39
6.27k
  {
40
  
41
6.27k
  }
42
43
/*****************************************************************************/
44
45
class dng_jpeg_image_encode_task : public dng_area_task
46
  {
47
  
48
  private:
49
  
50
    dng_host &fHost;
51
    
52
    dng_image_writer &fWriter;
53
    
54
    const dng_image &fImage;
55
  
56
    dng_jpeg_image &fJPEGImage;
57
    
58
    uint32 fTileCount;
59
    
60
    const dng_ifd &fIFD;
61
        
62
    dng_mutex fMutex;
63
    
64
    uint32 fNextTileIndex;
65
    
66
  public:
67
  
68
    dng_jpeg_image_encode_task (dng_host &host,
69
                  dng_image_writer &writer,
70
                  const dng_image &image,
71
                  dng_jpeg_image &jpegImage,
72
                  uint32 tileCount,
73
                  const dng_ifd &ifd)
74
    
75
5.85k
      : fHost       (host)
76
5.85k
      , fWriter       (writer)
77
5.85k
      , fImage        (image)
78
5.85k
      , fJPEGImage        (jpegImage)
79
5.85k
      , fTileCount      (tileCount)
80
5.85k
      , fIFD          (ifd)
81
5.85k
      , fMutex        ("dng_jpeg_image_encode_task")
82
5.85k
      , fNextTileIndex    (0)
83
      
84
5.85k
      {
85
      
86
5.85k
      fMinTaskArea = 16 * 16;
87
5.85k
      fUnitCell    = dng_point (16, 16);
88
5.85k
      fMaxTileSize = dng_point (16, 16);
89
      
90
5.85k
      }
91
  
92
    void Process (uint32 /* threadIndex */,
93
            const dng_rect & /* tile */,
94
            dng_abort_sniffer *sniffer)
95
5.85k
      {
96
      
97
5.85k
      AutoPtr<dng_memory_block> compressedBuffer;
98
5.85k
      AutoPtr<dng_memory_block> uncompressedBuffer;
99
5.85k
      AutoPtr<dng_memory_block> subTileBlockBuffer;
100
5.85k
      AutoPtr<dng_memory_block> tempBuffer;
101
      
102
5.85k
      uint32 uncompressedSize = SafeUint32Mult (
103
5.85k
        fIFD.fTileLength, fIFD.fTileWidth, fIFD.fSamplesPerPixel);
104
      
105
5.85k
      uncompressedBuffer.Reset (fHost.Allocate (uncompressedSize));
106
      
107
5.85k
      uint32 tilesAcross = fIFD.TilesAcross ();
108
  
109
23.0k
      while (true)
110
23.0k
        {
111
        
112
23.0k
        uint32 tileIndex;
113
        
114
23.0k
          {
115
          
116
23.0k
          dng_lock_mutex lock (&fMutex);
117
          
118
23.0k
          if (fNextTileIndex == fTileCount)
119
5.85k
            {
120
5.85k
            return;
121
5.85k
            }
122
            
123
17.1k
          tileIndex = fNextTileIndex++;
124
                    
125
17.1k
          }
126
          
127
0
        dng_abort_sniffer::SniffForAbort (sniffer);
128
        
129
17.1k
        uint32 rowIndex = tileIndex / tilesAcross;
130
17.1k
        uint32 colIndex = tileIndex % tilesAcross;
131
        
132
17.1k
        dng_rect tileArea = fIFD.TileArea (rowIndex, colIndex);
133
        
134
17.1k
        dng_memory_stream stream (fHost.Allocator ());
135
        
136
17.1k
        fWriter.WriteTile (fHost,
137
17.1k
                   fIFD,
138
17.1k
                   stream,
139
17.1k
                   fImage,
140
17.1k
                   tileArea,
141
17.1k
                   1,
142
17.1k
                   compressedBuffer,
143
17.1k
                   uncompressedBuffer,
144
17.1k
                   subTileBlockBuffer,
145
17.1k
                   tempBuffer);
146
                  
147
17.1k
        fJPEGImage.fJPEGData [tileIndex].Reset (stream.AsMemoryBlock (fHost.Allocator ()));
148
          
149
17.1k
        }
150
      
151
5.85k
      }
152
    
153
  private:
154
155
    // Hidden copy constructor and assignment operator.
156
157
    dng_jpeg_image_encode_task (const dng_jpeg_image_encode_task &);
158
159
    dng_jpeg_image_encode_task & operator= (const dng_jpeg_image_encode_task &);
160
    
161
  };
162
163
/*****************************************************************************/
164
165
void dng_jpeg_image::Encode (dng_host &host,
166
               const dng_negative &negative,
167
               dng_image_writer &writer,
168
               const dng_image &image)
169
5.85k
  {
170
  
171
  #if qDNGValidate
172
  dng_timer timer ("Encode JPEG Proxy time");
173
  #endif
174
  
175
5.85k
  DNG_ASSERT (image.PixelType () == ttByte, "Cannot JPEG encode non-byte image");
176
  
177
5.85k
  fImageSize = image.Bounds ().Size ();
178
  
179
5.85k
  dng_ifd ifd;
180
  
181
5.85k
  ifd.fImageWidth  = fImageSize.h;
182
5.85k
  ifd.fImageLength = fImageSize.v;
183
  
184
5.85k
  ifd.fSamplesPerPixel = image.Planes ();
185
  
186
5.85k
  ifd.fBitsPerSample [0] = 8;
187
5.85k
  ifd.fBitsPerSample [1] = 8;
188
5.85k
  ifd.fBitsPerSample [2] = 8;
189
5.85k
  ifd.fBitsPerSample [3] = 8;
190
  
191
5.85k
  ifd.fPhotometricInterpretation = piLinearRaw;
192
  
193
5.85k
  ifd.fCompression = ccLossyJPEG;
194
  
195
5.85k
  ifd.FindTileSize (512 * 512 * ifd.fSamplesPerPixel);
196
  
197
5.85k
  fTileSize.h = ifd.fTileWidth;
198
5.85k
  fTileSize.v = ifd.fTileLength;
199
  
200
  // Need a higher quality for raw proxies than non-raw proxies,
201
  // since users often perform much greater color changes.  Also, use
202
  // we are targeting a "large" size proxy (larger than 5MP pixels), or this
203
  // is a full size proxy, then use a higher quality.
204
  
205
5.85k
  bool useHigherQuality = (uint64) ifd.fImageWidth *
206
5.85k
              (uint64) ifd.fImageLength > 5000000 ||
207
5.84k
              image.Bounds ().Size () == negative.OriginalDefaultFinalSize ();
208
  
209
5.85k
  if (negative.ColorimetricReference () == crSceneReferred)
210
5.25k
    {
211
5.25k
    ifd.fCompressionQuality = useHigherQuality ? 11 : 10;
212
5.25k
    }
213
605
  else
214
605
    {
215
605
    ifd.fCompressionQuality = useHigherQuality ? 10 : 8;
216
605
    }
217
  
218
5.85k
  uint32 tilesAcross = ifd.TilesAcross ();
219
5.85k
  uint32 tilesDown   = ifd.TilesDown   ();
220
  
221
5.85k
  uint32 tileCount = tilesAcross * tilesDown;
222
  
223
5.85k
  fJPEGData.Reset (tileCount);
224
  
225
5.85k
  uint32 threadCount = Min_uint32 (tileCount,
226
5.85k
                   host.PerformAreaTaskThreads ());
227
                     
228
5.85k
  dng_jpeg_image_encode_task task (host,
229
5.85k
                   writer,
230
5.85k
                   image,
231
5.85k
                   *this,
232
5.85k
                   tileCount,
233
5.85k
                   ifd);
234
                    
235
5.85k
  host.PerformAreaTask (task,
236
5.85k
              dng_rect (0, 0, 16, 16 * threadCount));
237
    
238
5.85k
  }
239
      
240
/*****************************************************************************/
241
242
class dng_jpeg_image_find_digest_task : public dng_area_task
243
  {
244
  
245
  private:
246
  
247
    const dng_jpeg_image &fJPEGImage;
248
    
249
    uint32 fTileCount;
250
    
251
    dng_fingerprint *fDigests;
252
        
253
    dng_mutex fMutex;
254
    
255
    uint32 fNextTileIndex;
256
    
257
  public:
258
  
259
    dng_jpeg_image_find_digest_task (const dng_jpeg_image &jpegImage,
260
                     uint32 tileCount,
261
                     dng_fingerprint *digests)
262
    
263
5.85k
      : fJPEGImage        (jpegImage)
264
5.85k
      , fTileCount      (tileCount)
265
5.85k
      , fDigests      (digests)
266
5.85k
      , fMutex        ("dng_jpeg_image_find_digest_task")
267
5.85k
      , fNextTileIndex    (0)
268
      
269
5.85k
      {
270
      
271
5.85k
      fMinTaskArea = 16 * 16;
272
5.85k
      fUnitCell    = dng_point (16, 16);
273
5.85k
      fMaxTileSize = dng_point (16, 16);
274
      
275
5.85k
      }
276
  
277
    void Process (uint32 /* threadIndex */,
278
            const dng_rect & /* tile */,
279
            dng_abort_sniffer *sniffer)
280
5.85k
      {
281
      
282
23.0k
      while (true)
283
23.0k
        {
284
        
285
23.0k
        uint32 tileIndex;
286
        
287
23.0k
          {
288
          
289
23.0k
          dng_lock_mutex lock (&fMutex);
290
          
291
23.0k
          if (fNextTileIndex == fTileCount)
292
5.85k
            {
293
5.85k
            return;
294
5.85k
            }
295
            
296
17.1k
          tileIndex = fNextTileIndex++;
297
                    
298
17.1k
          }
299
          
300
0
        dng_abort_sniffer::SniffForAbort (sniffer);
301
        
302
17.1k
        dng_md5_printer printer;
303
        
304
17.1k
        printer.Process (fJPEGImage.fJPEGData [tileIndex]->Buffer      (),
305
17.1k
                 fJPEGImage.fJPEGData [tileIndex]->LogicalSize ());
306
                 
307
17.1k
        fDigests [tileIndex] = printer.Result ();
308
          
309
17.1k
        }
310
      
311
5.85k
      }
312
    
313
  private:
314
315
    // Hidden copy constructor and assignment operator.
316
317
    dng_jpeg_image_find_digest_task (const dng_jpeg_image_find_digest_task &);
318
319
    dng_jpeg_image_find_digest_task & operator= (const dng_jpeg_image_find_digest_task &);
320
    
321
  };
322
323
/*****************************************************************************/
324
325
dng_fingerprint dng_jpeg_image::FindDigest (dng_host &host) const
326
5.85k
  {
327
  
328
5.85k
  uint32 tileCount = TileCount ();
329
  
330
5.85k
  uint32 arrayCount = tileCount + (fJPEGTables.Get () ? 1 : 0);
331
  
332
5.85k
  AutoArray<dng_fingerprint> digests (arrayCount);
333
  
334
  // Compute digest of each compressed tile.
335
336
5.85k
    {
337
    
338
5.85k
    uint32 threadCount = Min_uint32 (tileCount,
339
5.85k
                     host.PerformAreaTaskThreads ());
340
                     
341
5.85k
    dng_jpeg_image_find_digest_task task (*this,
342
5.85k
                        tileCount,
343
5.85k
                        digests.Get ());
344
                      
345
5.85k
    host.PerformAreaTask (task,
346
5.85k
                dng_rect (0, 0, 16, 16 * threadCount));
347
    
348
5.85k
    }
349
  
350
  // Compute digest of JPEG tables, if any.
351
    
352
5.85k
  if (fJPEGTables.Get ())
353
0
    {
354
    
355
0
    dng_md5_printer printer;
356
    
357
0
    printer.Process (fJPEGTables->Buffer      (),
358
0
             fJPEGTables->LogicalSize ());
359
             
360
0
    digests [tileCount] = printer.Result ();
361
    
362
0
    }
363
    
364
  // Combine digests into a single digest.
365
  
366
5.85k
    {
367
    
368
5.85k
    dng_md5_printer printer;
369
    
370
23.0k
    for (uint32 k = 0; k < arrayCount; k++)
371
17.1k
      {
372
    
373
17.1k
      printer.Process (digests [k].data,
374
17.1k
               dng_fingerprint::kDNGFingerprintSize);
375
               
376
17.1k
      }
377
      
378
5.85k
    return printer.Result ();
379
    
380
5.85k
    }
381
  
382
5.85k
  }
383
      
384
/*****************************************************************************/
385