Coverage Report

Created: 2025-12-14 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dng_sdk/source/dng_negative.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_negative.cpp#3 $ */ 
10
/* $DateTime: 2012/06/14 20:24:41 $ */
11
/* $Change: 835078 $ */
12
/* $Author: tknoll $ */
13
14
/*****************************************************************************/
15
16
#include "dng_negative.h"
17
18
#include "dng_1d_table.h"
19
#include "dng_abort_sniffer.h"
20
#include "dng_area_task.h"
21
#include "dng_assertions.h"
22
#include "dng_bottlenecks.h"
23
#include "dng_camera_profile.h"
24
#include "dng_color_space.h"
25
#include "dng_color_spec.h"
26
#include "dng_exceptions.h"
27
#include "dng_globals.h"
28
#include "dng_host.h"
29
#include "dng_image.h"
30
#include "dng_image_writer.h"
31
#include "dng_info.h"
32
#include "dng_jpeg_image.h"
33
#include "dng_linearization_info.h"
34
#include "dng_memory.h"
35
#include "dng_memory_stream.h"
36
#include "dng_misc_opcodes.h"
37
#include "dng_mosaic_info.h"
38
#include "dng_preview.h"
39
#include "dng_resample.h"
40
#include "dng_safe_arithmetic.h"
41
#include "dng_simple_image.h"
42
#include "dng_tag_codes.h"
43
#include "dng_tag_values.h"
44
#include "dng_tile_iterator.h"
45
#include "dng_utils.h"
46
47
#if qDNGUseXMP
48
#include "dng_xmp.h"
49
#endif
50
51
/*****************************************************************************/
52
53
dng_noise_profile::dng_noise_profile ()
54
55
88.1k
  : fNoiseFunctions ()
56
57
88.1k
  {
58
  
59
88.1k
  }
60
61
/*****************************************************************************/
62
63
dng_noise_profile::dng_noise_profile (const dng_std_vector<dng_noise_function> &functions)
64
65
1.67k
  : fNoiseFunctions (functions)
66
67
1.67k
  {
68
69
1.67k
  }
70
71
/*****************************************************************************/
72
73
bool dng_noise_profile::IsValid () const
74
39.9k
  {
75
76
39.9k
  if (NumFunctions () == 0 || NumFunctions () > kMaxColorPlanes)
77
39.6k
    {
78
39.6k
    return false;
79
39.6k
    }
80
  
81
784
  for (uint32 plane = 0; plane < NumFunctions (); plane++)
82
578
    {
83
    
84
578
    if (!NoiseFunction (plane).IsValid ())
85
28
      {
86
28
      return false;
87
28
      }
88
    
89
578
    }
90
91
206
  return true;
92
  
93
234
  }
94
95
/*****************************************************************************/
96
97
bool dng_noise_profile::IsValidForNegative (const dng_negative &negative) const
98
10.8k
  {
99
  
100
10.8k
  if (!(NumFunctions () == 1 || NumFunctions () == negative.ColorChannels ()))
101
10.8k
    {
102
10.8k
    return false;
103
10.8k
    }
104
105
51
  return IsValid ();
106
107
10.8k
  }
108
109
/*****************************************************************************/
110
111
const dng_noise_function & dng_noise_profile::NoiseFunction (uint32 plane) const
112
906
  {
113
  
114
906
  if (NumFunctions () == 1)
115
168
    {
116
168
    return fNoiseFunctions.front ();
117
168
    }
118
119
738
  DNG_REQUIRE (plane < NumFunctions (), 
120
738
         "Bad plane index argument for NoiseFunction ().");
121
122
738
  return fNoiseFunctions [plane];
123
  
124
906
  }
125
126
/*****************************************************************************/
127
128
uint32 dng_noise_profile::NumFunctions () const
129
136k
  {
130
136k
  return (uint32) fNoiseFunctions.size ();
131
136k
  }
132
133
/*****************************************************************************/
134
135
dng_metadata::dng_metadata (dng_host &host)
136
137
34.8k
  : fHasBaseOrientation     (false)
138
34.8k
  , fBaseOrientation        ()
139
34.8k
  , fIsMakerNoteSafe      (false)
140
34.8k
  , fMakerNote          ()
141
34.8k
  , fExif             (host.Make_dng_exif ())
142
34.8k
  , fOriginalExif       ()
143
34.8k
  , fIPTCBlock              ()
144
34.8k
  , fIPTCOffset         (kDNGStreamInvalidOffset)
145
  
146
  #if qDNGUseXMP
147
  
148
  , fXMP              (host.Make_dng_xmp ())
149
  
150
  #endif
151
  
152
34.8k
  , fEmbeddedXMPDigest        ()
153
34.8k
  , fXMPinSidecar         (false)
154
34.8k
  , fXMPisNewer           (false)
155
34.8k
  , fSourceMIMI         ()
156
157
34.8k
  {
158
34.8k
  }
159
160
/*****************************************************************************/
161
162
dng_metadata::~dng_metadata ()
163
49.3k
  {
164
49.3k
  }
165
  
166
/******************************************************************************/
167
168
template< class T >
169
T * CloneAutoPtr (const AutoPtr< T > &ptr)
170
29.1k
  {
171
  
172
29.1k
  return ptr.Get () ? ptr->Clone () : NULL;
173
  
174
29.1k
  }
175
176
/******************************************************************************/
177
178
template< class T, typename U >
179
T * CloneAutoPtr (const AutoPtr< T > &ptr, U &u)
180
29.1k
  {
181
  
182
29.1k
  return ptr.Get () ? ptr->Clone (u) : NULL;
183
  
184
29.1k
  }
185
186
/******************************************************************************/
187
188
dng_metadata::dng_metadata (const dng_metadata &rhs,
189
              dng_memory_allocator &allocator)
190
191
14.5k
  : fHasBaseOrientation     (rhs.fHasBaseOrientation)
192
14.5k
  , fBaseOrientation        (rhs.fBaseOrientation)
193
14.5k
  , fIsMakerNoteSafe      (rhs.fIsMakerNoteSafe)
194
14.5k
  , fMakerNote          (CloneAutoPtr (rhs.fMakerNote, allocator))
195
14.5k
  , fExif             (CloneAutoPtr (rhs.fExif))
196
14.5k
  , fOriginalExif       (CloneAutoPtr (rhs.fOriginalExif))
197
14.5k
  , fIPTCBlock              (CloneAutoPtr (rhs.fIPTCBlock, allocator))
198
14.5k
  , fIPTCOffset         (rhs.fIPTCOffset)
199
  
200
  #if qDNGUseXMP
201
  
202
  , fXMP              (CloneAutoPtr (rhs.fXMP))
203
  
204
  #endif
205
  
206
14.5k
  , fEmbeddedXMPDigest        (rhs.fEmbeddedXMPDigest)
207
14.5k
  , fXMPinSidecar         (rhs.fXMPinSidecar)
208
14.5k
  , fXMPisNewer           (rhs.fXMPisNewer)
209
14.5k
  , fSourceMIMI         (rhs.fSourceMIMI)
210
211
14.5k
  {
212
213
14.5k
  }
214
215
/******************************************************************************/
216
217
dng_metadata * dng_metadata::Clone (dng_memory_allocator &allocator) const
218
14.5k
  {
219
  
220
14.5k
  return new dng_metadata (*this, allocator);
221
  
222
14.5k
  }
223
224
/******************************************************************************/
225
226
void dng_metadata::SetBaseOrientation (const dng_orientation &orientation)
227
3.09k
  {
228
  
229
3.09k
  fHasBaseOrientation = true;
230
  
231
3.09k
  fBaseOrientation = orientation;
232
  
233
3.09k
  }
234
    
235
/******************************************************************************/
236
237
void dng_metadata::ApplyOrientation (const dng_orientation &orientation)
238
0
  {
239
  
240
0
  fBaseOrientation += orientation;
241
242
  #if qDNGUseXMP
243
  
244
  fXMP->SetOrientation (fBaseOrientation);
245
  
246
  #endif
247
248
0
  }
249
          
250
/*****************************************************************************/
251
252
void dng_metadata::ResetExif (dng_exif * newExif)
253
28.1k
  {
254
255
28.1k
  fExif.Reset (newExif);
256
257
28.1k
  }
258
259
/******************************************************************************/
260
261
dng_memory_block * dng_metadata::BuildExifBlock (dng_memory_allocator &allocator,
262
                         const dng_resolution *resolution,
263
                         bool includeIPTC,
264
                         const dng_jpeg_preview *thumbnail) const
265
0
  {
266
  
267
0
  dng_memory_stream stream (allocator);
268
  
269
0
    {
270
  
271
    // Create the main IFD
272
                       
273
0
    dng_tiff_directory mainIFD;
274
    
275
    // Optionally include the resolution tags.
276
    
277
0
    dng_resolution res;
278
    
279
0
    if (resolution)
280
0
      {
281
0
      res = *resolution;
282
0
      }
283
  
284
0
    tag_urational tagXResolution (tcXResolution, res.fXResolution);
285
0
    tag_urational tagYResolution (tcYResolution, res.fYResolution);
286
    
287
0
    tag_uint16 tagResolutionUnit (tcResolutionUnit, res.fResolutionUnit);
288
    
289
0
    if (resolution)
290
0
      {
291
0
      mainIFD.Add (&tagXResolution   );
292
0
      mainIFD.Add (&tagYResolution   );
293
0
      mainIFD.Add (&tagResolutionUnit);
294
0
      }
295
296
    // Optionally include IPTC block.
297
    
298
0
    tag_iptc tagIPTC (IPTCData   (),
299
0
              IPTCLength ());
300
      
301
0
    if (includeIPTC && tagIPTC.Count ())
302
0
      {
303
0
      mainIFD.Add (&tagIPTC);
304
0
      }
305
              
306
    // Exif tags.
307
    
308
0
    exif_tag_set exifSet (mainIFD,
309
0
                *GetExif (),
310
0
                IsMakerNoteSafe (),
311
0
                MakerNoteData   (),
312
0
                MakerNoteLength (),
313
0
                false);
314
                
315
    // Figure out the Exif IFD offset.
316
    
317
0
    uint32 exifOffset = 8 + mainIFD.Size ();
318
    
319
0
    exifSet.Locate (exifOffset);
320
    
321
    // Thumbnail IFD (if any).
322
    
323
0
    dng_tiff_directory thumbIFD;
324
    
325
0
    tag_uint16 thumbCompression (tcCompression, ccOldJPEG);
326
    
327
0
    tag_urational thumbXResolution (tcXResolution, dng_urational (72, 1));
328
0
    tag_urational thumbYResolution (tcYResolution, dng_urational (72, 1));
329
    
330
0
    tag_uint16 thumbResolutionUnit (tcResolutionUnit, ruInch);
331
    
332
0
    tag_uint32 thumbDataOffset (tcJPEGInterchangeFormat      , 0);
333
0
    tag_uint32 thumbDataLength (tcJPEGInterchangeFormatLength, 0);
334
    
335
0
    if (thumbnail)
336
0
      {
337
      
338
0
      thumbIFD.Add (&thumbCompression);
339
      
340
0
      thumbIFD.Add (&thumbXResolution);
341
0
      thumbIFD.Add (&thumbYResolution);
342
0
      thumbIFD.Add (&thumbResolutionUnit);
343
      
344
0
      thumbIFD.Add (&thumbDataOffset);
345
0
      thumbIFD.Add (&thumbDataLength);
346
      
347
0
      thumbDataLength.Set (thumbnail->fCompressedData->LogicalSize ());
348
      
349
0
      uint32 thumbOffset = exifOffset + exifSet.Size ();
350
      
351
0
      mainIFD.SetChained (thumbOffset);
352
      
353
0
      thumbDataOffset.Set (thumbOffset + thumbIFD.Size ());
354
      
355
0
      }
356
      
357
    // Don't write anything unless the main IFD has some tags.
358
    
359
0
    if (mainIFD.Size () != 0)
360
0
      {
361
          
362
      // Write TIFF Header.
363
      
364
0
      stream.SetWritePosition (0);
365
      
366
0
      stream.Put_uint16 (stream.BigEndian () ? byteOrderMM : byteOrderII);
367
      
368
0
      stream.Put_uint16 (42);
369
      
370
0
      stream.Put_uint32 (8);
371
      
372
      // Write the IFDs.
373
      
374
0
      mainIFD.Put (stream);
375
      
376
0
      exifSet.Put (stream);
377
      
378
0
      if (thumbnail)
379
0
        {
380
        
381
0
        thumbIFD.Put (stream);
382
        
383
0
        stream.Put (thumbnail->fCompressedData->Buffer      (),
384
0
              thumbnail->fCompressedData->LogicalSize ());
385
        
386
0
        }
387
        
388
      // Trim the file to this length.
389
      
390
0
      stream.Flush ();
391
      
392
0
      stream.SetLength (stream.Position ());
393
      
394
0
      }
395
    
396
0
    }
397
    
398
0
  return stream.AsMemoryBlock (allocator);
399
    
400
0
  }
401
      
402
/******************************************************************************/
403
404
void dng_metadata::SetIPTC (AutoPtr<dng_memory_block> &block, uint64 offset)
405
39
  {
406
  
407
39
  fIPTCBlock.Reset (block.Release ());
408
  
409
39
  fIPTCOffset = offset;
410
  
411
39
  }
412
            
413
/******************************************************************************/
414
415
void dng_metadata::SetIPTC (AutoPtr<dng_memory_block> &block)
416
0
  {
417
  
418
0
  SetIPTC (block, kDNGStreamInvalidOffset);
419
  
420
0
  }
421
            
422
/******************************************************************************/
423
424
void dng_metadata::ClearIPTC ()
425
0
  {
426
  
427
0
  fIPTCBlock.Reset ();
428
  
429
0
  fIPTCOffset = kDNGStreamInvalidOffset;
430
  
431
0
  }
432
            
433
/*****************************************************************************/
434
435
const void * dng_metadata::IPTCData () const
436
3.63k
  {
437
  
438
3.63k
  if (fIPTCBlock.Get ())
439
68
    {
440
    
441
68
    return fIPTCBlock->Buffer ();
442
    
443
68
    }
444
    
445
3.56k
  return NULL;
446
  
447
3.63k
  }
448
449
/*****************************************************************************/
450
451
uint32 dng_metadata::IPTCLength () const
452
7.27k
  {
453
  
454
7.27k
  if (fIPTCBlock.Get ())
455
136
    {
456
    
457
136
    return fIPTCBlock->LogicalSize ();
458
    
459
136
    }
460
    
461
7.13k
  return 0;
462
  
463
7.27k
  }
464
    
465
/*****************************************************************************/
466
467
uint64 dng_metadata::IPTCOffset () const
468
0
  {
469
  
470
0
  if (fIPTCBlock.Get ())
471
0
    {
472
    
473
0
    return fIPTCOffset;
474
    
475
0
    }
476
    
477
0
  return kDNGStreamInvalidOffset;
478
  
479
0
  }
480
    
481
/*****************************************************************************/
482
483
dng_fingerprint dng_metadata::IPTCDigest (bool includePadding) const
484
34
  {
485
  
486
34
  if (IPTCLength ())
487
34
    {
488
    
489
34
    dng_md5_printer printer;
490
    
491
34
    const uint8 *data = (const uint8 *) IPTCData ();
492
    
493
34
    uint32 count = IPTCLength ();
494
    
495
    // Because of some stupid ways of storing the IPTC data, the IPTC
496
    // data might be padded with up to three zeros.  The official Adobe
497
    // logic is to include these zeros in the digest.  However, older
498
    // versions of the Camera Raw code did not include the padding zeros
499
    // in the digest, so we support both methods and allow either to
500
    // match.
501
    
502
34
    if (!includePadding)
503
0
      {
504
    
505
0
      uint32 removed = 0;
506
      
507
0
      while ((removed < 3) && (count > 0) && (data [count - 1] == 0))
508
0
        {
509
0
        removed++;
510
0
        count--;
511
0
        }
512
        
513
0
      }
514
    
515
34
    printer.Process (data, count);
516
             
517
34
    return printer.Result ();
518
      
519
34
    }
520
  
521
0
  return dng_fingerprint ();
522
  
523
34
  }
524
    
525
/******************************************************************************/
526
527
#if qDNGUseXMP
528
529
void dng_metadata::RebuildIPTC (dng_memory_allocator &allocator,
530
                bool padForTIFF)
531
  {
532
  
533
  ClearIPTC ();
534
  
535
  fXMP->RebuildIPTC (*this, allocator, padForTIFF);
536
  
537
  dng_fingerprint digest = IPTCDigest ();
538
  
539
  fXMP->SetIPTCDigest (digest);
540
  
541
  }
542
        
543
/*****************************************************************************/
544
545
void dng_metadata::ResetXMP (dng_xmp * newXMP)
546
  {
547
  
548
  fXMP.Reset (newXMP);
549
  
550
  }
551
552
/*****************************************************************************/
553
554
void dng_metadata::ResetXMPSidecarNewer (dng_xmp * newXMP,
555
                     bool inSidecar,
556
                     bool isNewer )
557
  {
558
559
  fXMP.Reset (newXMP);
560
561
  fXMPinSidecar = inSidecar;
562
563
  fXMPisNewer = isNewer;
564
565
  }
566
567
/*****************************************************************************/
568
569
bool dng_metadata::SetXMP (dng_host &host,
570
               const void *buffer,
571
               uint32 count,
572
               bool xmpInSidecar,
573
               bool xmpIsNewer)
574
  {
575
  
576
  bool result = false;
577
  
578
  try
579
    {
580
    
581
    AutoPtr<dng_xmp> tempXMP (host.Make_dng_xmp ());
582
    
583
    tempXMP->Parse (host, buffer, count);
584
    
585
    ResetXMPSidecarNewer (tempXMP.Release (), xmpInSidecar, xmpIsNewer);
586
    
587
    result = true;
588
    
589
    }
590
    
591
  catch (dng_exception &except)
592
    {
593
    
594
    // Don't ignore transient errors.
595
    
596
    if (host.IsTransientError (except.ErrorCode ()))
597
      {
598
      
599
      throw;
600
      
601
      }
602
      
603
    // Eat other parsing errors.
604
    
605
    }
606
    
607
  catch (...)
608
    {
609
    
610
    // Eat unknown parsing exceptions.
611
    
612
    }
613
  
614
  return result;
615
  
616
  }
617
618
/*****************************************************************************/
619
620
void dng_metadata::SetEmbeddedXMP (dng_host &host,
621
                   const void *buffer,
622
                   uint32 count)
623
  {
624
  
625
  if (SetXMP (host, buffer, count))
626
    {
627
    
628
    dng_md5_printer printer;
629
    
630
    printer.Process (buffer, count);
631
    
632
    fEmbeddedXMPDigest = printer.Result ();
633
    
634
    // Remove any sidecar specific tags from embedded XMP.
635
    
636
    if (fXMP.Get ())
637
      {
638
    
639
      fXMP->Remove (XMP_NS_PHOTOSHOP, "SidecarForExtension");
640
      fXMP->Remove (XMP_NS_PHOTOSHOP, "EmbeddedXMPDigest");
641
      
642
      }
643
    
644
    }
645
    
646
  else
647
    {
648
    
649
    fEmbeddedXMPDigest.Clear ();
650
    
651
    }
652
653
  }
654
655
#endif
656
657
/*****************************************************************************/
658
659
void dng_metadata::SynchronizeMetadata ()
660
14.2k
  {
661
  
662
14.2k
  if (!fOriginalExif.Get ())
663
14.2k
    {
664
    
665
14.2k
    fOriginalExif.Reset (fExif->Clone ());
666
    
667
14.2k
    }
668
    
669
  #if qDNGUseXMP
670
  
671
  fXMP->ValidateMetadata ();
672
  
673
  fXMP->IngestIPTC (*this, fXMPisNewer);
674
  
675
  fXMP->SyncExif (*fExif.Get ());
676
  
677
  fXMP->SyncOrientation (*this, fXMPinSidecar);
678
  
679
  #endif
680
  
681
14.2k
  }
682
          
683
/*****************************************************************************/
684
685
void dng_metadata::UpdateDateTime (const dng_date_time_info &dt)
686
0
  {
687
  
688
0
  fExif->UpdateDateTime (dt);
689
  
690
#if qDNGUseXMP
691
  fXMP->UpdateDateTime (dt);
692
#endif
693
  
694
0
  }
695
          
696
/*****************************************************************************/
697
698
void dng_metadata::UpdateDateTimeToNow ()
699
0
  {
700
  
701
0
  dng_date_time_info dt;
702
  
703
0
  CurrentDateTimeAndZone (dt);
704
  
705
0
  UpdateDateTime (dt);
706
  
707
  #if qDNGUseXMP
708
  
709
  fXMP->UpdateMetadataDate (dt);
710
  
711
  #endif
712
  
713
0
  }
714
          
715
/*****************************************************************************/
716
717
void dng_metadata::UpdateMetadataDateTimeToNow ()
718
0
  {
719
  
720
0
  dng_date_time_info dt;
721
  
722
0
  CurrentDateTimeAndZone (dt);
723
  
724
#if qDNGUseXMP
725
  fXMP->UpdateMetadataDate (dt);
726
#endif
727
  
728
0
  }
729
          
730
/*****************************************************************************/
731
732
dng_negative::dng_negative (dng_host &host)
733
734
34.8k
  : fAllocator            (host.Allocator ())
735
  
736
34.8k
  , fModelName            ()
737
34.8k
  , fLocalName            ()
738
34.8k
  , fDefaultCropSizeH       ()
739
34.8k
  , fDefaultCropSizeV       ()
740
34.8k
  , fDefaultCropOriginH       (0, 1)
741
34.8k
  , fDefaultCropOriginV       (0, 1)
742
34.8k
  , fDefaultUserCropT       (0, 1)
743
34.8k
  , fDefaultUserCropL       (0, 1)
744
34.8k
  , fDefaultUserCropB       (1, 1)
745
34.8k
  , fDefaultUserCropR       (1, 1)
746
34.8k
  , fDefaultScaleH          (1, 1)
747
34.8k
  , fDefaultScaleV          (1, 1)
748
34.8k
  , fBestQualityScale       (1, 1)
749
34.8k
  , fOriginalDefaultFinalSize   ()
750
34.8k
  , fOriginalBestQualityFinalSize ()
751
34.8k
  , fOriginalDefaultCropSizeH     ()
752
34.8k
  , fOriginalDefaultCropSizeV     ()
753
34.8k
  , fRawToFullScaleH        (1.0)
754
34.8k
  , fRawToFullScaleV        (1.0)
755
34.8k
  , fBaselineNoise          (100, 100)
756
34.8k
  , fNoiseReductionApplied      (0, 0)
757
34.8k
  , fNoiseProfile         ()
758
34.8k
  , fBaselineExposure       (  0, 100)
759
34.8k
  , fBaselineSharpness        (100, 100)
760
34.8k
  , fChromaBlurRadius       ()
761
34.8k
  , fAntiAliasStrength        (100, 100)
762
34.8k
  , fLinearResponseLimit      (100, 100)
763
34.8k
  , fShadowScale          (1, 1)
764
34.8k
  , fColorimetricReference      (crSceneReferred)
765
34.8k
  , fColorChannels          (0)
766
34.8k
  , fAnalogBalance          ()
767
34.8k
  , fCameraNeutral          ()
768
34.8k
  , fCameraWhiteXY          ()
769
34.8k
  , fCameraCalibration1       ()
770
34.8k
  , fCameraCalibration2       ()
771
34.8k
  , fCameraCalibrationSignature   ()
772
34.8k
  , fCameraProfile          ()
773
34.8k
  , fAsShotProfileName        ()
774
34.8k
  , fRawImageDigest         ()
775
34.8k
  , fNewRawImageDigest        ()
776
34.8k
  , fRawDataUniqueID        ()
777
34.8k
  , fOriginalRawFileName      ()
778
34.8k
  , fHasOriginalRawFileData     (false)
779
34.8k
  , fOriginalRawFileData      ()
780
34.8k
  , fOriginalRawFileDigest      ()
781
34.8k
  , fDNGPrivateData         ()
782
34.8k
  , fMetadata           (host)
783
34.8k
  , fLinearizationInfo        ()
784
34.8k
  , fMosaicInfo           ()
785
34.8k
  , fOpcodeList1          (1)
786
34.8k
  , fOpcodeList2          (2)
787
34.8k
  , fOpcodeList3          (3)
788
34.8k
  , fStage1Image          ()
789
34.8k
  , fStage2Image          ()
790
34.8k
  , fStage3Image          ()
791
34.8k
  , fStage3Gain           (1.0)
792
34.8k
  , fIsPreview            (false)
793
34.8k
  , fIsDamaged            (false)
794
34.8k
  , fRawImageStage          (rawImageStageNone)
795
34.8k
  , fRawImage           ()
796
34.8k
  , fRawFloatBitDepth       (0)
797
34.8k
  , fRawJPEGImage         ()
798
34.8k
  , fRawJPEGImageDigest       ()
799
34.8k
  , fTransparencyMask       ()
800
34.8k
  , fRawTransparencyMask      ()
801
34.8k
  , fRawTransparencyMaskBitDepth  (0)
802
34.8k
  , fUnflattenedStage3Image     ()
803
804
34.8k
  {
805
806
34.8k
  }
807
808
/*****************************************************************************/
809
810
dng_negative::~dng_negative ()
811
34.8k
  {
812
  
813
  // Delete any camera profiles owned by this negative.
814
  
815
34.8k
  ClearProfiles ();
816
    
817
34.8k
  }
818
819
/******************************************************************************/
820
821
void dng_negative::Initialize ()
822
34.8k
  {
823
  
824
34.8k
  }
825
826
/******************************************************************************/
827
828
dng_negative * dng_negative::Make (dng_host &host)
829
34.8k
  {
830
  
831
34.8k
  AutoPtr<dng_negative> result (new dng_negative (host));
832
  
833
34.8k
  if (!result.Get ())
834
0
    {
835
0
    ThrowMemoryFull ();
836
0
    }
837
  
838
34.8k
  result->Initialize ();
839
  
840
34.8k
  return result.Release ();
841
  
842
34.8k
  }
843
844
/******************************************************************************/
845
846
dng_metadata * dng_negative::CloneInternalMetadata () const
847
0
  {
848
  
849
0
  return InternalMetadata ().Clone (Allocator ());
850
  
851
0
  }
852
853
/******************************************************************************/
854
855
dng_orientation dng_negative::ComputeOrientation (const dng_metadata &metadata) const
856
14.4k
  {
857
  
858
14.4k
  return metadata.BaseOrientation ();
859
  
860
14.4k
  }
861
    
862
/******************************************************************************/
863
864
void dng_negative::SetAnalogBalance (const dng_vector &b)
865
8.12k
  {
866
  
867
8.12k
  real64 minEntry = b.MinEntry ();
868
  
869
8.12k
  if (b.NotEmpty () && minEntry > 0.0)
870
4.81k
    {
871
    
872
4.81k
    fAnalogBalance = b;
873
  
874
4.81k
    fAnalogBalance.Scale (1.0 / minEntry);
875
    
876
4.81k
    fAnalogBalance.Round (1000000.0);
877
    
878
4.81k
    }
879
    
880
3.31k
  else
881
3.31k
    {
882
    
883
3.31k
    fAnalogBalance.Clear ();
884
    
885
3.31k
    }
886
    
887
8.12k
  }
888
            
889
/*****************************************************************************/
890
891
real64 dng_negative::AnalogBalance (uint32 channel) const
892
31.2k
  {
893
  
894
31.2k
  DNG_ASSERT (channel < ColorChannels (), "Channel out of bounds");
895
  
896
31.2k
  if (channel < fAnalogBalance.Count ())
897
5.36k
    {
898
    
899
5.36k
    return fAnalogBalance [channel];
900
    
901
5.36k
    }
902
    
903
25.9k
  return 1.0;
904
  
905
31.2k
  }
906
    
907
/*****************************************************************************/
908
909
dng_urational dng_negative::AnalogBalanceR (uint32 channel) const
910
23.9k
  {
911
  
912
23.9k
  dng_urational result;
913
  
914
23.9k
  result.Set_real64 (AnalogBalance (channel), 1000000);
915
  
916
23.9k
  return result;
917
  
918
23.9k
  }
919
920
/******************************************************************************/
921
922
void dng_negative::SetCameraNeutral (const dng_vector &n)
923
393
  {
924
  
925
393
  real64 maxEntry = n.MaxEntry ();
926
    
927
393
  if (n.NotEmpty () && maxEntry > 0.0)
928
368
    {
929
    
930
368
    fCameraNeutral = n;
931
  
932
368
    fCameraNeutral.Scale (1.0 / maxEntry);
933
    
934
368
    fCameraNeutral.Round (1000000.0);
935
    
936
368
    }
937
    
938
25
  else
939
25
    {
940
    
941
25
    fCameraNeutral.Clear ();
942
    
943
25
    }
944
945
393
  }
946
    
947
/*****************************************************************************/
948
949
dng_urational dng_negative::CameraNeutralR (uint32 channel) const
950
594
  {
951
  
952
594
  dng_urational result;
953
  
954
594
  result.Set_real64 (CameraNeutral () [channel], 1000000);
955
  
956
594
  return result;
957
  
958
594
  }
959
960
/******************************************************************************/
961
962
void dng_negative::SetCameraWhiteXY (const dng_xy_coord &coord)
963
3.97k
  {
964
  
965
3.97k
  if (coord.IsValid ())
966
3.97k
    {
967
    
968
3.97k
    fCameraWhiteXY.x = Round_int32 (coord.x * 1000000.0) / 1000000.0;
969
3.97k
    fCameraWhiteXY.y = Round_int32 (coord.y * 1000000.0) / 1000000.0;
970
    
971
3.97k
    }
972
    
973
0
  else
974
0
    {
975
    
976
0
    fCameraWhiteXY.Clear ();
977
    
978
0
    }
979
  
980
3.97k
  }
981
    
982
/*****************************************************************************/
983
984
const dng_xy_coord & dng_negative::CameraWhiteXY () const
985
618
  {
986
  
987
618
  DNG_ASSERT (HasCameraWhiteXY (), "Using undefined CameraWhiteXY");
988
989
618
  return fCameraWhiteXY;
990
  
991
618
  }
992
                 
993
/*****************************************************************************/
994
995
void dng_negative::GetCameraWhiteXY (dng_urational &x,
996
                     dng_urational &y) const
997
421
  {
998
  
999
421
  dng_xy_coord coord = CameraWhiteXY ();
1000
  
1001
421
  x.Set_real64 (coord.x, 1000000);
1002
421
  y.Set_real64 (coord.y, 1000000);
1003
  
1004
421
  }
1005
    
1006
/*****************************************************************************/
1007
1008
void dng_negative::SetCameraCalibration1 (const dng_matrix &m)
1009
257
  {
1010
  
1011
257
  fCameraCalibration1 = m;
1012
  
1013
257
  fCameraCalibration1.Round (10000);
1014
  
1015
257
  }
1016
1017
/******************************************************************************/
1018
1019
void dng_negative::SetCameraCalibration2 (const dng_matrix &m)
1020
173
  {
1021
  
1022
173
  fCameraCalibration2 = m;
1023
  
1024
173
  fCameraCalibration2.Round (10000);
1025
    
1026
173
  }
1027
1028
/******************************************************************************/
1029
1030
void dng_negative::AddProfile (AutoPtr<dng_camera_profile> &profile)
1031
153k
  {
1032
  
1033
  // Make sure we have a profile to add.
1034
  
1035
153k
  if (!profile.Get ())
1036
0
    {
1037
    
1038
0
    return;
1039
    
1040
0
    }
1041
  
1042
  // We must have some profile name.  Use "embedded" if nothing else.
1043
  
1044
153k
  if (profile->Name ().IsEmpty ())
1045
122k
    {
1046
    
1047
122k
    profile->SetName (kProfileName_Embedded);
1048
    
1049
122k
    }
1050
    
1051
  // Special case support for reading older DNG files which did not store
1052
  // the profile name in the main IFD profile.
1053
  
1054
153k
  if (fCameraProfile.size ())
1055
130k
    {
1056
    
1057
    // See the first profile has a default "embedded" name, and has
1058
    // the same data as the profile we are adding.
1059
    
1060
130k
    if (fCameraProfile [0]->NameIsEmbedded () &&
1061
24.4k
      fCameraProfile [0]->EqualData (*profile.Get ()))
1062
631
      {
1063
      
1064
      // If the profile we are deleting was read from DNG
1065
      // then the new profile should be marked as such also.
1066
      
1067
631
      if (fCameraProfile [0]->WasReadFromDNG ())
1068
631
        {
1069
        
1070
631
        profile->SetWasReadFromDNG ();
1071
        
1072
631
        }
1073
        
1074
      // If the profile we are deleting wasn't read from disk then the new
1075
      // profile should be marked as such also.
1076
      
1077
631
      if (!fCameraProfile [0]->WasReadFromDisk ())
1078
631
        {
1079
        
1080
631
        profile->SetWasReadFromDisk (false);
1081
        
1082
631
        }
1083
        
1084
      // Delete the profile with default name.
1085
      
1086
631
      delete fCameraProfile [0];
1087
      
1088
631
      fCameraProfile [0] = NULL;
1089
      
1090
631
      fCameraProfile.erase (fCameraProfile.begin ());
1091
      
1092
631
      }
1093
    
1094
130k
    }
1095
    
1096
  // Duplicate detection logic.  We give a preference to last added profile
1097
  // so the profiles end up in a more consistent order no matter what profiles
1098
  // happen to be embedded in the DNG.
1099
  
1100
6.40M
  for (uint32 index = 0; index < (uint32) fCameraProfile.size (); index++)
1101
6.27M
    {
1102
1103
    // Instead of checking for matching fingerprints, we check that the two
1104
    // profiles have the same color and have the same name. This allows two
1105
    // profiles that are identical except for copyright string and embed policy
1106
    // to be considered duplicates.
1107
1108
6.27M
    const bool equalColorAndSameName = (fCameraProfile [index]->EqualData (*profile.Get ()) &&
1109
24.4k
                      fCameraProfile [index]->Name () == profile->Name ());
1110
1111
6.27M
    if (equalColorAndSameName)
1112
22.9k
      {
1113
      
1114
      // If the profile we are deleting was read from DNG
1115
      // then the new profile should be marked as such also.
1116
      
1117
22.9k
      if (fCameraProfile [index]->WasReadFromDNG ())
1118
22.9k
        {
1119
        
1120
22.9k
        profile->SetWasReadFromDNG ();
1121
        
1122
22.9k
        }
1123
        
1124
      // If the profile we are deleting wasn't read from disk then the new
1125
      // profile should be marked as such also.
1126
      
1127
22.9k
      if (!fCameraProfile [index]->WasReadFromDisk ())
1128
22.9k
        {
1129
        
1130
22.9k
        profile->SetWasReadFromDisk (false);
1131
        
1132
22.9k
        }
1133
        
1134
      // Delete the duplicate profile.
1135
      
1136
22.9k
      delete fCameraProfile [index];
1137
      
1138
22.9k
      fCameraProfile [index] = NULL;
1139
      
1140
22.9k
      fCameraProfile.erase (fCameraProfile.begin () + index);
1141
      
1142
22.9k
      break;
1143
      
1144
22.9k
      }
1145
      
1146
6.27M
    }
1147
    
1148
  // Now add to profile list.
1149
  
1150
153k
  fCameraProfile.push_back (NULL);
1151
  
1152
153k
  fCameraProfile [fCameraProfile.size () - 1] = profile.Release ();
1153
  
1154
153k
  }
1155
      
1156
/******************************************************************************/
1157
1158
void dng_negative::ClearProfiles ()
1159
34.8k
  {
1160
  
1161
  // Delete any camera profiles owned by this negative.
1162
  
1163
165k
  for (uint32 index = 0; index < (uint32) fCameraProfile.size (); index++)
1164
130k
    {
1165
    
1166
130k
    if (fCameraProfile [index])
1167
130k
      {
1168
      
1169
130k
      delete fCameraProfile [index];
1170
      
1171
130k
      fCameraProfile [index] = NULL;
1172
      
1173
130k
      }
1174
    
1175
130k
    }
1176
    
1177
  // Now empty list.
1178
  
1179
34.8k
  fCameraProfile.clear ();
1180
  
1181
34.8k
  }
1182
1183
/*****************************************************************************/
1184
1185
void dng_negative::ClearProfiles (bool clearBuiltinMatrixProfiles,
1186
                  bool clearReadFromDisk)
1187
0
  {
1188
1189
  // If neither flag is set, then there's nothing to do.
1190
1191
0
  if (!clearBuiltinMatrixProfiles &&
1192
0
    !clearReadFromDisk)
1193
0
    {
1194
0
    return;
1195
0
    }
1196
  
1197
  // Delete any camera profiles in this negative that match the specified criteria.
1198
1199
0
  dng_std_vector<dng_camera_profile *>::iterator iter = fCameraProfile.begin ();
1200
0
  dng_std_vector<dng_camera_profile *>::iterator next;
1201
  
1202
0
  for (; iter != fCameraProfile.end (); iter = next)
1203
0
    {
1204
1205
0
    dng_camera_profile *profile = *iter;
1206
1207
    // If the profile is invalid (i.e., NULL pointer), or meets one of the
1208
    // specified criteria, then axe it.
1209
1210
0
    if (!profile ||
1211
0
      (clearBuiltinMatrixProfiles && profile->WasBuiltinMatrix ()) ||
1212
0
      (clearReadFromDisk      && profile->WasReadFromDisk   ()))
1213
0
      {
1214
      
1215
0
      delete profile;
1216
1217
0
      next = fCameraProfile.erase (iter);
1218
1219
0
      }
1220
1221
    // Otherwise, just advance to the next element.
1222
1223
0
    else
1224
0
      {
1225
      
1226
0
      next = iter + 1;
1227
      
1228
0
      }
1229
1230
0
    }
1231
  
1232
0
  }
1233
1234
/******************************************************************************/
1235
1236
uint32 dng_negative::ProfileCount () const
1237
41.9k
  {
1238
  
1239
41.9k
  return (uint32) fCameraProfile.size ();
1240
  
1241
41.9k
  }
1242
    
1243
/******************************************************************************/
1244
1245
const dng_camera_profile & dng_negative::ProfileByIndex (uint32 index) const
1246
268k
  {
1247
  
1248
268k
  DNG_ASSERT (index < ProfileCount (),
1249
268k
        "Invalid index for ProfileByIndex");
1250
        
1251
268k
  return *fCameraProfile [index];
1252
    
1253
268k
  }
1254
    
1255
/*****************************************************************************/
1256
1257
const dng_camera_profile * dng_negative::ProfileByID (const dng_camera_profile_id &id,
1258
                            bool useDefaultIfNoMatch) const
1259
27.5k
  {
1260
  
1261
27.5k
  uint32 index;
1262
  
1263
  // If this negative does not have any profiles, we are not going to
1264
  // find a match.
1265
  
1266
27.5k
  uint32 profileCount = ProfileCount ();
1267
  
1268
27.5k
  if (profileCount == 0)
1269
16.2k
    {
1270
16.2k
    return NULL;
1271
16.2k
    }
1272
    
1273
  // If we have both a profile name and fingerprint, try matching both.
1274
  
1275
11.3k
  if (id.Name ().NotEmpty () && id.Fingerprint ().IsValid ())
1276
2.20k
    {
1277
    
1278
23.3k
    for (index = 0; index < profileCount; index++)
1279
21.1k
      {
1280
      
1281
21.1k
      const dng_camera_profile &profile = ProfileByIndex (index);
1282
      
1283
21.1k
      if (id.Name        () == profile.Name        () &&
1284
0
        id.Fingerprint () == profile.Fingerprint ())
1285
0
        {
1286
        
1287
0
        return &profile;
1288
        
1289
0
        }
1290
      
1291
21.1k
      }
1292
1293
2.20k
    }
1294
    
1295
  // If we have a name, try matching that.
1296
  
1297
11.3k
  if (id.Name ().NotEmpty ())
1298
2.20k
    {
1299
    
1300
23.3k
    for (index = 0; index < profileCount; index++)
1301
21.1k
      {
1302
      
1303
21.1k
      const dng_camera_profile &profile = ProfileByIndex (index);
1304
      
1305
21.1k
      if (id.Name () == profile.Name ())
1306
0
        {
1307
        
1308
0
        return &profile;
1309
        
1310
0
        }
1311
      
1312
21.1k
      }
1313
1314
2.20k
    }
1315
    
1316
  // If we have a valid fingerprint, try matching that.
1317
    
1318
11.3k
  if (id.Fingerprint ().IsValid ())
1319
2.20k
    {
1320
    
1321
23.3k
    for (index = 0; index < profileCount; index++)
1322
21.1k
      {
1323
      
1324
21.1k
      const dng_camera_profile &profile = ProfileByIndex (index);
1325
      
1326
21.1k
      if (id.Fingerprint () == profile.Fingerprint ())
1327
0
        {
1328
        
1329
0
        return &profile;
1330
        
1331
0
        }
1332
      
1333
21.1k
      }
1334
1335
2.20k
    }
1336
    
1337
  // Try "upgrading" profile name versions.
1338
  
1339
11.3k
  if (id.Name ().NotEmpty ())
1340
2.20k
    {
1341
    
1342
2.20k
    dng_string baseName;
1343
2.20k
    int32      version;
1344
    
1345
2.20k
    SplitCameraProfileName (id.Name (),
1346
2.20k
                baseName,
1347
2.20k
                version);
1348
    
1349
2.20k
    int32 bestIndex   = -1;
1350
2.20k
    int32 bestVersion = 0;
1351
    
1352
23.3k
    for (index = 0; index < profileCount; index++)
1353
21.1k
      {
1354
      
1355
21.1k
      const dng_camera_profile &profile = ProfileByIndex (index);
1356
      
1357
21.1k
      if (profile.Name ().StartsWith (baseName.Get ()))
1358
26
        {
1359
        
1360
26
        dng_string testBaseName;
1361
26
        int32      testVersion;
1362
        
1363
26
        SplitCameraProfileName (profile.Name (),
1364
26
                    testBaseName,
1365
26
                    testVersion);
1366
                    
1367
26
        if (bestIndex == -1 || testVersion > bestVersion)
1368
26
          {
1369
          
1370
26
          bestIndex   = index;
1371
26
          bestVersion = testVersion;
1372
          
1373
26
          }
1374
          
1375
26
        }
1376
        
1377
21.1k
      }
1378
      
1379
2.20k
    if (bestIndex != -1)
1380
26
      {
1381
      
1382
26
      return &ProfileByIndex (bestIndex);
1383
      
1384
26
      }
1385
    
1386
2.20k
    }
1387
    
1388
  // Did not find a match any way.  See if we should return a default value.
1389
  
1390
11.2k
  if (useDefaultIfNoMatch)
1391
11.2k
    {
1392
    
1393
11.2k
    return &ProfileByIndex (0);
1394
    
1395
11.2k
    }
1396
    
1397
  // Found nothing.
1398
  
1399
0
  return NULL;
1400
    
1401
11.2k
  }
1402
1403
/*****************************************************************************/
1404
1405
const dng_camera_profile * dng_negative::ComputeCameraProfileToEmbed
1406
                    (const dng_metadata & /* metadata */) const
1407
7.21k
  {
1408
  
1409
7.21k
  uint32 index;
1410
  
1411
7.21k
  uint32 count = ProfileCount ();
1412
  
1413
7.21k
  if (count == 0)
1414
0
    {
1415
    
1416
0
    return NULL;
1417
    
1418
0
    }
1419
    
1420
  // First try to look for the first profile that was already in the DNG
1421
  // when we read it.
1422
  
1423
13.4k
  for (index = 0; index < count; index++)
1424
9.70k
    {
1425
    
1426
9.70k
    const dng_camera_profile &profile (ProfileByIndex (index));
1427
    
1428
9.70k
    if (profile.WasReadFromDNG ())
1429
3.47k
      {
1430
      
1431
3.47k
      return &profile;
1432
      
1433
3.47k
      }
1434
    
1435
9.70k
    }
1436
    
1437
  // Next we look for the first profile that is legal to embed.
1438
  
1439
3.74k
  for (index = 0; index < count; index++)
1440
3.74k
    {
1441
    
1442
3.74k
    const dng_camera_profile &profile (ProfileByIndex (index));
1443
    
1444
3.74k
    if (profile.IsLegalToEmbed ())
1445
3.74k
      {
1446
      
1447
3.74k
      return &profile;
1448
      
1449
3.74k
      }
1450
    
1451
3.74k
    }
1452
    
1453
  // Else just return the first profile.
1454
  
1455
0
  return fCameraProfile [0];
1456
  
1457
3.74k
  }
1458
                 
1459
/*****************************************************************************/
1460
1461
dng_color_spec * dng_negative::MakeColorSpec (const dng_camera_profile_id &id) const
1462
2.29k
  {
1463
1464
2.29k
  dng_color_spec *spec = new dng_color_spec (*this, ProfileByID (id));
1465
                         
1466
2.29k
  if (!spec)
1467
0
    {
1468
0
    ThrowMemoryFull ();
1469
0
    }
1470
    
1471
2.29k
  return spec;
1472
  
1473
2.29k
  }
1474
                 
1475
/*****************************************************************************/
1476
1477
dng_fingerprint dng_negative::FindImageDigest (dng_host &host,
1478
                         const dng_image &image) const
1479
4.35k
  {
1480
  
1481
4.35k
  dng_md5_printer printer;
1482
  
1483
4.35k
  dng_pixel_buffer buffer (image.Bounds (), 0, image.Planes (),
1484
4.35k
     image.PixelType (), pcInterleaved, NULL);
1485
  
1486
  // Sometimes we expand 8-bit data to 16-bit data while reading or
1487
  // writing, so always compute the digest of 8-bit data as 16-bits.
1488
  
1489
4.35k
  if (buffer.fPixelType == ttByte)
1490
137
    {
1491
137
    buffer.fPixelType = ttShort;
1492
137
    buffer.fPixelSize = 2;
1493
137
    }
1494
  
1495
4.35k
  const uint32 kBufferRows = 16;
1496
  
1497
4.35k
  uint32 bufferBytes = 0;
1498
  
1499
4.35k
  if (!SafeUint32Mult (kBufferRows, buffer.fRowStep, &bufferBytes) ||
1500
4.35k
     !SafeUint32Mult (bufferBytes, buffer.fPixelSize, &bufferBytes))
1501
0
    {
1502
    
1503
0
    ThrowMemoryFull("Arithmetic overflow computing buffer size.");
1504
    
1505
0
    }
1506
  
1507
4.35k
  AutoPtr<dng_memory_block> bufferData (host.Allocate (bufferBytes));
1508
  
1509
4.35k
  buffer.fData = bufferData->Buffer ();
1510
  
1511
4.35k
  dng_rect area;
1512
  
1513
4.35k
  dng_tile_iterator iter (dng_point (kBufferRows,
1514
4.35k
                     image.Width ()),
1515
4.35k
              image.Bounds ());
1516
              
1517
296k
  while (iter.GetOneTile (area))
1518
291k
    {
1519
    
1520
291k
    host.SniffForAbort ();
1521
    
1522
291k
    buffer.fArea = area;
1523
    
1524
291k
    image.Get (buffer);
1525
    
1526
291k
    uint32 count = buffer.fArea.H () *
1527
291k
             buffer.fRowStep *
1528
291k
             buffer.fPixelSize;
1529
             
1530
    #if qDNGBigEndian
1531
    
1532
    // We need to use the same byte order to compute
1533
    // the digest, no matter the native order.  Little-endian
1534
    // is more common now, so use that.
1535
    
1536
    switch (buffer.fPixelSize)
1537
      {
1538
      
1539
      case 1:
1540
        break;
1541
      
1542
      case 2:
1543
        {
1544
        DoSwapBytes16 ((uint16 *) buffer.fData, count >> 1);
1545
        break;
1546
        }
1547
      
1548
      case 4:
1549
        {
1550
        DoSwapBytes32 ((uint32 *) buffer.fData, count >> 2);
1551
        break;
1552
        }
1553
        
1554
      default:
1555
        {
1556
        DNG_REPORT ("Unexpected pixel size");
1557
        break;
1558
        }
1559
      
1560
      }
1561
    
1562
    #endif
1563
1564
291k
    printer.Process (buffer.fData,
1565
291k
             count);
1566
    
1567
291k
    }
1568
      
1569
4.35k
  return printer.Result ();
1570
  
1571
4.35k
  }
1572
                 
1573
/*****************************************************************************/
1574
1575
void dng_negative::FindRawImageDigest (dng_host &host) const
1576
4.55k
  {
1577
  
1578
4.55k
  if (fRawImageDigest.IsNull ())
1579
4.55k
    {
1580
    
1581
    // Since we are adding the floating point and transparency support 
1582
    // in DNG 1.4, and there are no legacy floating point or transparent
1583
    // DNGs, switch to using the more MP friendly algorithm to compute
1584
    // the digest for these images.
1585
    
1586
4.55k
    if (RawImage ().PixelType () == ttFloat || RawTransparencyMask ())
1587
195
      {
1588
      
1589
195
      FindNewRawImageDigest (host);
1590
      
1591
195
      fRawImageDigest = fNewRawImageDigest;
1592
      
1593
195
      }
1594
      
1595
4.35k
    else
1596
4.35k
      {
1597
      
1598
      #if qDNGValidate
1599
      
1600
      dng_timer timeScope ("FindRawImageDigest time");
1601
1602
      #endif
1603
    
1604
4.35k
      fRawImageDigest = FindImageDigest (host, RawImage ());
1605
      
1606
4.35k
      }
1607
  
1608
4.55k
    }
1609
  
1610
4.55k
  }
1611
                 
1612
/*****************************************************************************/
1613
1614
class dng_find_new_raw_image_digest_task : public dng_area_task
1615
  {
1616
  
1617
  private:
1618
  
1619
    enum
1620
      {
1621
      kTileSize = 256
1622
      };
1623
      
1624
    const dng_image &fImage;
1625
    
1626
    uint32 fPixelType;
1627
    uint32 fPixelSize;
1628
    
1629
    uint32 fTilesAcross;
1630
    uint32 fTilesDown;
1631
    
1632
    uint32 fTileCount;
1633
    
1634
    AutoArray<dng_fingerprint> fTileHash;
1635
    
1636
    AutoPtr<dng_memory_block> fBufferData [kMaxMPThreads];
1637
  
1638
  public:
1639
  
1640
    dng_find_new_raw_image_digest_task (const dng_image &image,
1641
                      uint32 pixelType)
1642
    
1643
8.89k
      : fImage       (image)
1644
8.89k
      , fPixelType   (pixelType)
1645
8.89k
      , fPixelSize   (TagTypeSize (pixelType))
1646
8.89k
      , fTilesAcross (0)
1647
8.89k
      , fTilesDown   (0)
1648
8.89k
      , fTileCount   (0)
1649
8.89k
      , fTileHash    ()
1650
      
1651
8.89k
      {
1652
      
1653
8.89k
      fMinTaskArea = 1;
1654
                  
1655
8.89k
      fUnitCell = dng_point (Min_int32 (kTileSize, fImage.Bounds ().H ()),
1656
8.89k
                   Min_int32 (kTileSize, fImage.Bounds ().W ()));
1657
                   
1658
8.89k
      fMaxTileSize = fUnitCell;
1659
            
1660
8.89k
      }
1661
  
1662
    virtual void Start (uint32 threadCount,
1663
              const dng_point &tileSize,
1664
              dng_memory_allocator *allocator,
1665
              dng_abort_sniffer * /* sniffer */)
1666
8.89k
      {
1667
      
1668
8.89k
      if (tileSize != fUnitCell)
1669
0
        {
1670
0
        ThrowProgramError ();
1671
0
        }
1672
        
1673
8.89k
      fTilesAcross = (fImage.Bounds ().W () + fUnitCell.h - 1) / fUnitCell.h;
1674
8.89k
      fTilesDown   = (fImage.Bounds ().H () + fUnitCell.v - 1) / fUnitCell.v;
1675
      
1676
8.89k
      fTileCount = fTilesAcross * fTilesDown;
1677
             
1678
8.89k
      fTileHash.Reset (fTileCount);
1679
      
1680
8.89k
      const uint32 bufferSize =
1681
8.89k
        ComputeBufferSize(fPixelType, tileSize, fImage.Planes(),
1682
8.89k
                  padNone);
1683
      
1684
17.7k
      for (uint32 index = 0; index < threadCount; index++)
1685
8.89k
        {
1686
        
1687
8.89k
        fBufferData [index].Reset (allocator->Allocate (bufferSize));
1688
        
1689
8.89k
        }
1690
      
1691
8.89k
      }
1692
1693
    virtual void Process (uint32 threadIndex,
1694
                const dng_rect &tile,
1695
                dng_abort_sniffer * /* sniffer */)
1696
132k
      {
1697
      
1698
132k
      int32 colIndex = (tile.l - fImage.Bounds ().l) / fUnitCell.h;
1699
132k
      int32 rowIndex = (tile.t - fImage.Bounds ().t) / fUnitCell.v;
1700
      
1701
132k
      DNG_ASSERT (tile.l == fImage.Bounds ().l + colIndex * fUnitCell.h &&
1702
132k
            tile.t == fImage.Bounds ().t + rowIndex * fUnitCell.v,
1703
132k
            "Bad tile origin");
1704
      
1705
132k
      uint32 tileIndex = rowIndex * fTilesAcross + colIndex;
1706
      
1707
132k
      dng_pixel_buffer buffer (tile, 0, fImage.Planes (),
1708
132k
         fPixelType, pcPlanar,
1709
132k
         fBufferData [threadIndex]->Buffer ());
1710
      
1711
132k
      fImage.Get (buffer);
1712
      
1713
132k
      uint32 count = buffer.fPlaneStep *
1714
132k
               buffer.fPlanes *
1715
132k
               buffer.fPixelSize;
1716
      
1717
      #if qDNGBigEndian
1718
      
1719
      // We need to use the same byte order to compute
1720
      // the digest, no matter the native order.  Little-endian
1721
      // is more common now, so use that.
1722
      
1723
      switch (buffer.fPixelSize)
1724
        {
1725
        
1726
        case 1:
1727
          break;
1728
        
1729
        case 2:
1730
          {
1731
          DoSwapBytes16 ((uint16 *) buffer.fData, count >> 1);
1732
          break;
1733
          }
1734
        
1735
        case 4:
1736
          {
1737
          DoSwapBytes32 ((uint32 *) buffer.fData, count >> 2);
1738
          break;
1739
          }
1740
          
1741
        default:
1742
          {
1743
          DNG_REPORT ("Unexpected pixel size");
1744
          break;
1745
          }
1746
        
1747
        }
1748
1749
      #endif
1750
      
1751
132k
      dng_md5_printer printer;
1752
      
1753
132k
      printer.Process (buffer.fData, count);
1754
               
1755
132k
      fTileHash [tileIndex] = printer.Result ();
1756
      
1757
132k
      }
1758
      
1759
    dng_fingerprint Result ()
1760
8.89k
      {
1761
      
1762
8.89k
      dng_md5_printer printer;
1763
      
1764
141k
      for (uint32 tileIndex = 0; tileIndex < fTileCount; tileIndex++)
1765
132k
        {
1766
        
1767
132k
        printer.Process (fTileHash [tileIndex] . data, 16);
1768
        
1769
132k
        }
1770
        
1771
8.89k
      return printer.Result ();
1772
      
1773
8.89k
      }
1774
    
1775
  };
1776
1777
/*****************************************************************************/
1778
1779
void dng_negative::FindNewRawImageDigest (dng_host &host) const
1780
12.3k
  {
1781
  
1782
12.3k
  if (fNewRawImageDigest.IsNull ())
1783
8.89k
    {
1784
    
1785
    #if qDNGValidate
1786
    
1787
    dng_timer timeScope ("FindNewRawImageDigest time");
1788
1789
    #endif
1790
    
1791
    // Find fast digest of the raw image.
1792
    
1793
8.89k
      {
1794
    
1795
8.89k
      const dng_image &rawImage = RawImage ();
1796
      
1797
      // Find pixel type that will be saved in the file.  When saving DNGs, we convert
1798
      // some 16-bit data to 8-bit data, so we need to do the matching logic here.
1799
      
1800
8.89k
      uint32 rawPixelType = rawImage.PixelType ();
1801
      
1802
8.89k
      if (rawPixelType == ttShort)
1803
5.13k
        {
1804
      
1805
        // See if we are using a linearization table with <= 256 entries, in which
1806
        // case the useful data will all fit within 8-bits.
1807
        
1808
5.13k
        const dng_linearization_info *rangeInfo = GetLinearizationInfo ();
1809
      
1810
5.13k
        if (rangeInfo)
1811
449
          {
1812
1813
449
          if (rangeInfo->fLinearizationTable.Get ())
1814
12
            {
1815
            
1816
12
            uint32 entries = rangeInfo->fLinearizationTable->LogicalSize () >> 1;
1817
            
1818
12
            if (entries <= 256)
1819
10
              {
1820
              
1821
10
              rawPixelType = ttByte;
1822
              
1823
10
              }
1824
                            
1825
12
            }
1826
            
1827
449
          }
1828
1829
5.13k
        }
1830
      
1831
      // Find the fast digest on the raw image.
1832
        
1833
8.89k
      dng_find_new_raw_image_digest_task task (rawImage, rawPixelType);
1834
      
1835
8.89k
      host.PerformAreaTask (task, rawImage.Bounds ());
1836
      
1837
8.89k
      fNewRawImageDigest = task.Result ();
1838
        
1839
8.89k
      }
1840
      
1841
    // If there is a transparancy mask, we need to include that in the
1842
    // digest also.
1843
    
1844
8.89k
    if (RawTransparencyMask () != NULL)
1845
0
      {
1846
      
1847
      // Find the fast digest on the raw mask.
1848
      
1849
0
      dng_fingerprint maskDigest;
1850
      
1851
0
        {
1852
        
1853
0
        dng_find_new_raw_image_digest_task task (*RawTransparencyMask (),
1854
0
                             RawTransparencyMask ()->PixelType ());
1855
        
1856
0
        host.PerformAreaTask (task, RawTransparencyMask ()->Bounds ());
1857
        
1858
0
        maskDigest = task.Result ();
1859
        
1860
0
        }
1861
        
1862
      // Combine the two digests into a single digest.
1863
      
1864
0
      dng_md5_printer printer;
1865
      
1866
0
      printer.Process (fNewRawImageDigest.data, 16);
1867
      
1868
0
      printer.Process (maskDigest.data, 16);
1869
      
1870
0
      fNewRawImageDigest = printer.Result ();
1871
      
1872
0
      }
1873
    
1874
8.89k
    }
1875
  
1876
12.3k
  }
1877
                 
1878
/*****************************************************************************/
1879
1880
void dng_negative::ValidateRawImageDigest (dng_host &host)
1881
6.03k
  {
1882
  
1883
6.03k
  if (Stage1Image () && !IsPreview () && (fRawImageDigest   .IsValid () ||
1884
5.79k
                        fNewRawImageDigest.IsValid ()))
1885
303
    {
1886
    
1887
303
    bool isNewDigest = fNewRawImageDigest.IsValid ();
1888
    
1889
303
    dng_fingerprint &rawDigest = isNewDigest ? fNewRawImageDigest
1890
303
                         : fRawImageDigest;
1891
    
1892
    // For lossy compressed JPEG images, we need to compare the stored
1893
    // digest to the digest computed from the compressed data, since
1894
    // decompressing lossy JPEG data is itself a lossy process.
1895
    
1896
303
    if (RawJPEGImageDigest ().IsValid () || RawJPEGImage ())
1897
0
      {
1898
      
1899
      // Compute the raw JPEG image digest if we have not done so
1900
      // already.
1901
      
1902
0
      FindRawJPEGImageDigest (host);
1903
      
1904
0
      if (rawDigest != RawJPEGImageDigest ())
1905
0
        {
1906
        
1907
        #if qDNGValidate
1908
        
1909
        ReportError ("RawImageDigest does not match raw jpeg image");
1910
        
1911
        #else
1912
        
1913
0
        SetIsDamaged (true);
1914
        
1915
0
        #endif
1916
        
1917
0
        }
1918
      
1919
0
      }
1920
      
1921
    // Else we can compare the stored digest to the image in memory.
1922
      
1923
303
    else
1924
303
      {
1925
    
1926
303
      dng_fingerprint oldDigest = rawDigest;
1927
      
1928
303
      try
1929
303
        {
1930
        
1931
303
        rawDigest.Clear ();
1932
        
1933
303
        if (isNewDigest)
1934
63
          {
1935
          
1936
63
          FindNewRawImageDigest (host);
1937
          
1938
63
          }
1939
          
1940
240
        else
1941
240
          {
1942
          
1943
240
          FindRawImageDigest (host);
1944
          
1945
240
          }
1946
        
1947
303
        }
1948
        
1949
303
      catch (...)
1950
303
        {
1951
        
1952
0
        rawDigest = oldDigest;
1953
        
1954
0
        throw;
1955
        
1956
0
        }
1957
      
1958
303
      if (oldDigest != rawDigest)
1959
302
        {
1960
        
1961
        #if qDNGValidate
1962
        
1963
        if (isNewDigest)
1964
          {
1965
          ReportError ("NewRawImageDigest does not match raw image");
1966
          }
1967
        else
1968
          {
1969
          ReportError ("RawImageDigest does not match raw image");
1970
          }
1971
        
1972
        SetIsDamaged (true);
1973
        
1974
        #else
1975
        
1976
302
        if (!isNewDigest)
1977
239
          {
1978
        
1979
          // Note that Lightroom 1.4 Windows had a bug that corrupts the
1980
          // first four bytes of the RawImageDigest tag.  So if the last
1981
          // twelve bytes match, this is very likely the result of the
1982
          // bug, and not an actual corrupt file.  So don't report this
1983
          // to the user--just fix it.
1984
          
1985
239
            {
1986
          
1987
239
            bool matchLast12 = true;
1988
            
1989
3.10k
            for (uint32 j = 4; j < 16; j++)
1990
2.86k
              {
1991
2.86k
              matchLast12 = matchLast12 && (oldDigest.data [j] == fRawImageDigest.data [j]);
1992
2.86k
              }
1993
              
1994
239
            if (matchLast12)
1995
0
              {
1996
0
              return;
1997
0
              }
1998
              
1999
239
            }
2000
            
2001
          // Sometimes Lightroom 1.4 would corrupt more than the first four
2002
          // bytes, but for all those files that I have seen so far the
2003
          // resulting first four bytes are 0x08 0x00 0x00 0x00.
2004
          
2005
239
          if (oldDigest.data [0] == 0x08 &&
2006
28
            oldDigest.data [1] == 0x00 &&
2007
24
            oldDigest.data [2] == 0x00 &&
2008
15
            oldDigest.data [3] == 0x00)
2009
12
            {
2010
12
            return;
2011
12
            }
2012
            
2013
239
          }
2014
          
2015
290
        SetIsDamaged (true);
2016
        
2017
290
        #endif
2018
        
2019
290
        }
2020
        
2021
303
      }
2022
      
2023
303
    }
2024
  
2025
6.03k
  }
2026
2027
/*****************************************************************************/
2028
2029
// If the raw data unique ID is missing, compute one based on a MD5 hash of
2030
// the raw image hash and the model name, plus other commonly changed
2031
// data that can affect rendering.
2032
2033
void dng_negative::FindRawDataUniqueID (dng_host &host) const
2034
17.2k
  {
2035
  
2036
17.2k
  if (fRawDataUniqueID.IsNull ())
2037
11.9k
    {
2038
    
2039
11.9k
    dng_md5_printer_stream printer;
2040
    
2041
    // If we have a raw jpeg image, it is much faster to
2042
    // use its digest as part of the unique ID since
2043
    // the data size is much smaller.  We cannot use it
2044
    // if there a transparency mask, since that is not
2045
    // included in the RawJPEGImageDigest.
2046
    
2047
11.9k
    if (RawJPEGImage () && !RawTransparencyMask ())
2048
3.25k
      {
2049
      
2050
3.25k
      FindRawJPEGImageDigest (host);
2051
      
2052
3.25k
      printer.Put (fRawJPEGImageDigest.data, 16);
2053
      
2054
3.25k
      }
2055
    
2056
    // Include the new raw image digest in the unique ID.
2057
    
2058
8.72k
    else
2059
8.72k
      {
2060
    
2061
8.72k
      FindNewRawImageDigest (host);
2062
          
2063
8.72k
      printer.Put (fNewRawImageDigest.data, 16);
2064
      
2065
8.72k
      }
2066
    
2067
    // Include model name.
2068
          
2069
11.9k
    printer.Put (ModelName ().Get    (),
2070
11.9k
           ModelName ().Length ());
2071
           
2072
    // Include default crop area, since DNG Recover Edges can modify
2073
    // these values and they affect rendering.
2074
           
2075
11.9k
    printer.Put_uint32 (fDefaultCropSizeH.n);
2076
11.9k
    printer.Put_uint32 (fDefaultCropSizeH.d);
2077
    
2078
11.9k
    printer.Put_uint32 (fDefaultCropSizeV.n);
2079
11.9k
    printer.Put_uint32 (fDefaultCropSizeV.d);
2080
    
2081
11.9k
    printer.Put_uint32 (fDefaultCropOriginH.n);
2082
11.9k
    printer.Put_uint32 (fDefaultCropOriginH.d);
2083
    
2084
11.9k
    printer.Put_uint32 (fDefaultCropOriginV.n);
2085
11.9k
    printer.Put_uint32 (fDefaultCropOriginV.d);
2086
2087
    // Include default user crop.
2088
2089
11.9k
    printer.Put_uint32 (fDefaultUserCropT.n);
2090
11.9k
    printer.Put_uint32 (fDefaultUserCropT.d);
2091
    
2092
11.9k
    printer.Put_uint32 (fDefaultUserCropL.n);
2093
11.9k
    printer.Put_uint32 (fDefaultUserCropL.d);
2094
    
2095
11.9k
    printer.Put_uint32 (fDefaultUserCropB.n);
2096
11.9k
    printer.Put_uint32 (fDefaultUserCropB.d);
2097
    
2098
11.9k
    printer.Put_uint32 (fDefaultUserCropR.n);
2099
11.9k
    printer.Put_uint32 (fDefaultUserCropR.d);
2100
    
2101
    // Include opcode lists, since lens correction utilities can modify
2102
    // these values and they affect rendering.
2103
    
2104
11.9k
    fOpcodeList1.FingerprintToStream (printer);
2105
11.9k
    fOpcodeList2.FingerprintToStream (printer);
2106
11.9k
    fOpcodeList3.FingerprintToStream (printer);
2107
    
2108
11.9k
    fRawDataUniqueID = printer.Result ();
2109
  
2110
11.9k
    }
2111
  
2112
17.2k
  }
2113
    
2114
/******************************************************************************/
2115
2116
// Forces recomputation of RawDataUniqueID, useful to call
2117
// after modifying the opcode lists, etc.
2118
2119
void dng_negative::RecomputeRawDataUniqueID (dng_host &host)
2120
6.35k
  {
2121
  
2122
6.35k
  fRawDataUniqueID.Clear ();
2123
  
2124
6.35k
  FindRawDataUniqueID (host);
2125
  
2126
6.35k
  }
2127
    
2128
/******************************************************************************/
2129
2130
void dng_negative::FindOriginalRawFileDigest () const
2131
10.9k
  {
2132
2133
10.9k
  if (fOriginalRawFileDigest.IsNull () && fOriginalRawFileData.Get ())
2134
185
    {
2135
    
2136
185
    dng_md5_printer printer;
2137
    
2138
185
    printer.Process (fOriginalRawFileData->Buffer      (),
2139
185
             fOriginalRawFileData->LogicalSize ());
2140
          
2141
185
    fOriginalRawFileDigest = printer.Result ();
2142
  
2143
185
    }
2144
2145
10.9k
  }
2146
    
2147
/*****************************************************************************/
2148
2149
void dng_negative::ValidateOriginalRawFileDigest ()
2150
280
  {
2151
  
2152
280
  if (fOriginalRawFileDigest.IsValid () && fOriginalRawFileData.Get ())
2153
60
    {
2154
    
2155
60
    dng_fingerprint oldDigest = fOriginalRawFileDigest;
2156
    
2157
60
    try
2158
60
      {
2159
      
2160
60
      fOriginalRawFileDigest.Clear ();
2161
      
2162
60
      FindOriginalRawFileDigest ();
2163
      
2164
60
      }
2165
      
2166
60
    catch (...)
2167
60
      {
2168
      
2169
0
      fOriginalRawFileDigest = oldDigest;
2170
      
2171
0
      throw;
2172
      
2173
0
      }
2174
    
2175
60
    if (oldDigest != fOriginalRawFileDigest)
2176
60
      {
2177
      
2178
      #if qDNGValidate
2179
      
2180
      ReportError ("OriginalRawFileDigest does not match OriginalRawFileData");
2181
      
2182
      #else
2183
      
2184
60
      SetIsDamaged (true);
2185
      
2186
60
      #endif
2187
      
2188
      // Don't "repair" the original image data digest.  Once it is
2189
      // bad, it stays bad.  The user cannot tell by looking at the image
2190
      // whether the damage is acceptable and can be ignored in the
2191
      // future.
2192
      
2193
60
      fOriginalRawFileDigest = oldDigest;
2194
      
2195
60
      }
2196
      
2197
60
    }
2198
    
2199
280
  }
2200
                 
2201
/******************************************************************************/
2202
2203
dng_rect dng_negative::DefaultCropArea () const
2204
18.8k
  {
2205
  
2206
  // First compute the area using simple rounding.
2207
    
2208
18.8k
  dng_rect result;
2209
  
2210
18.8k
  result.l = Round_int32 (fDefaultCropOriginH.As_real64 () * fRawToFullScaleH);
2211
18.8k
  result.t = Round_int32 (fDefaultCropOriginV.As_real64 () * fRawToFullScaleV);
2212
  
2213
18.8k
  result.r = result.l + Round_int32 (fDefaultCropSizeH.As_real64 () * fRawToFullScaleH);
2214
18.8k
  result.b = result.t + Round_int32 (fDefaultCropSizeV.As_real64 () * fRawToFullScaleV);
2215
  
2216
  // Sometimes the simple rounding causes the resulting default crop
2217
  // area to slide off the scaled image area.  So we force this not
2218
  // to happen.  We only do this if the image is not stubbed.
2219
    
2220
18.8k
  const dng_image *image = Stage3Image ();
2221
  
2222
18.8k
  if (image)
2223
18.8k
    {
2224
  
2225
18.8k
    dng_point imageSize = image->Size ();
2226
    
2227
18.8k
    if (result.r > imageSize.h)
2228
0
      {
2229
0
      result.l -= result.r - imageSize.h;
2230
0
      result.r  = imageSize.h;
2231
0
      }
2232
      
2233
18.8k
    if (result.b > imageSize.v)
2234
0
      {
2235
0
      result.t -= result.b - imageSize.v;
2236
0
      result.b  = imageSize.v;
2237
0
      }
2238
      
2239
18.8k
    }
2240
    
2241
18.8k
  return result;
2242
  
2243
18.8k
  }
2244
2245
/*****************************************************************************/
2246
2247
real64 dng_negative::TotalBaselineExposure (const dng_camera_profile_id &profileID) const
2248
10.1k
  {
2249
  
2250
10.1k
  real64 total = BaselineExposure ();
2251
2252
10.1k
  const dng_camera_profile *profile = ProfileByID (profileID);
2253
  
2254
10.1k
  if (profile)
2255
2.25k
    {
2256
2257
2.25k
    real64 offset = profile->BaselineExposureOffset ().As_real64 ();
2258
2259
2.25k
    total += offset;
2260
    
2261
2.25k
    }
2262
2263
10.1k
  return total;
2264
  
2265
10.1k
  }
2266
2267
/******************************************************************************/
2268
2269
void dng_negative::SetShadowScale (const dng_urational &scale)
2270
33.7k
  {
2271
  
2272
33.7k
  if (scale.d > 0)
2273
33.7k
    {
2274
    
2275
33.7k
    real64 s = scale.As_real64 ();
2276
    
2277
33.7k
    if (s > 0.0 && s <= 1.0)
2278
33.1k
      {
2279
  
2280
33.1k
      fShadowScale = scale;
2281
      
2282
33.1k
      }
2283
    
2284
33.7k
    }
2285
  
2286
33.7k
  }
2287
      
2288
/******************************************************************************/
2289
2290
void dng_negative::SetActiveArea (const dng_rect &area)
2291
0
  {
2292
  
2293
0
  NeedLinearizationInfo ();
2294
  
2295
0
  dng_linearization_info &info = *fLinearizationInfo.Get ();
2296
                    
2297
0
  info.fActiveArea = area;
2298
  
2299
0
  }
2300
2301
/******************************************************************************/
2302
2303
void dng_negative::SetMaskedAreas (uint32 count,
2304
                   const dng_rect *area)
2305
0
  {
2306
  
2307
0
  DNG_ASSERT (count <= kMaxMaskedAreas, "Too many masked areas");
2308
  
2309
0
  NeedLinearizationInfo ();
2310
  
2311
0
  dng_linearization_info &info = *fLinearizationInfo.Get ();
2312
                    
2313
0
  info.fMaskedAreaCount = Min_uint32 (count, kMaxMaskedAreas);
2314
  
2315
0
  for (uint32 index = 0; index < info.fMaskedAreaCount; index++)
2316
0
    {
2317
    
2318
0
    info.fMaskedArea [index] = area [index];
2319
    
2320
0
    }
2321
    
2322
0
  }
2323
    
2324
/*****************************************************************************/
2325
2326
void dng_negative::SetLinearization (AutoPtr<dng_memory_block> &curve)
2327
0
  {
2328
  
2329
0
  NeedLinearizationInfo ();
2330
  
2331
0
  dng_linearization_info &info = *fLinearizationInfo.Get ();
2332
                    
2333
0
  info.fLinearizationTable.Reset (curve.Release ());
2334
  
2335
0
  }
2336
    
2337
/*****************************************************************************/
2338
2339
void dng_negative::SetBlackLevel (real64 black,
2340
                  int32 plane)
2341
0
  {
2342
2343
0
  NeedLinearizationInfo ();
2344
  
2345
0
  dng_linearization_info &info = *fLinearizationInfo.Get ();
2346
                    
2347
0
  info.fBlackLevelRepeatRows = 1;
2348
0
  info.fBlackLevelRepeatCols = 1;
2349
  
2350
0
  if (plane < 0)
2351
0
    {
2352
    
2353
0
    for (uint32 j = 0; j < kMaxSamplesPerPixel; j++)
2354
0
      {
2355
      
2356
0
      info.fBlackLevel [0] [0] [j] = black;
2357
      
2358
0
      }
2359
    
2360
0
    }
2361
    
2362
0
  else
2363
0
    {
2364
    
2365
0
    info.fBlackLevel [0] [0] [plane] = black;
2366
      
2367
0
    }
2368
  
2369
0
  info.RoundBlacks ();
2370
    
2371
0
  }
2372
    
2373
/*****************************************************************************/
2374
2375
void dng_negative::SetQuadBlacks (real64 black0,
2376
                    real64 black1,
2377
                    real64 black2,
2378
                    real64 black3,
2379
                  int32 plane)
2380
0
  {
2381
  
2382
0
  NeedLinearizationInfo ();
2383
  
2384
0
  dng_linearization_info &info = *fLinearizationInfo.Get ();
2385
                    
2386
0
  info.fBlackLevelRepeatRows = 2;
2387
0
  info.fBlackLevelRepeatCols = 2;
2388
2389
0
  if (plane < 0)
2390
0
    {
2391
  
2392
0
    for (uint32 j = 0; j < kMaxSamplesPerPixel; j++)
2393
0
      {
2394
2395
0
      info.fBlackLevel [0] [0] [j] = black0;
2396
0
      info.fBlackLevel [0] [1] [j] = black1;
2397
0
      info.fBlackLevel [1] [0] [j] = black2;
2398
0
      info.fBlackLevel [1] [1] [j] = black3;
2399
2400
0
      }
2401
2402
0
    }
2403
2404
0
  else
2405
0
    {
2406
    
2407
0
    info.fBlackLevel [0] [0] [plane] = black0;
2408
0
    info.fBlackLevel [0] [1] [plane] = black1;
2409
0
    info.fBlackLevel [1] [0] [plane] = black2;
2410
0
    info.fBlackLevel [1] [1] [plane] = black3;
2411
    
2412
0
    }
2413
    
2414
0
  info.RoundBlacks ();
2415
    
2416
0
  }
2417
2418
/*****************************************************************************/
2419
2420
void dng_negative::SetRowBlacks (const real64 *blacks,
2421
                     uint32 count)
2422
0
  {
2423
  
2424
0
  if (count)
2425
0
    {
2426
  
2427
0
    NeedLinearizationInfo ();
2428
    
2429
0
    dng_linearization_info &info = *fLinearizationInfo.Get ();
2430
    
2431
0
    uint32 byteCount = 0;
2432
    
2433
0
    if (!SafeUint32Mult (count, (uint32) sizeof (real64), &byteCount))
2434
0
      {
2435
      
2436
0
      ThrowMemoryFull("Arithmetic overflow computing byte count.");
2437
      
2438
0
      }
2439
                      
2440
0
    info.fBlackDeltaV.Reset (Allocator ().Allocate (byteCount));
2441
    
2442
0
    DoCopyBytes (blacks,
2443
0
           info.fBlackDeltaV->Buffer (),
2444
0
           byteCount);
2445
    
2446
0
    info.RoundBlacks ();
2447
    
2448
0
    }
2449
    
2450
0
  else if (fLinearizationInfo.Get ())
2451
0
    {
2452
    
2453
0
    dng_linearization_info &info = *fLinearizationInfo.Get ();
2454
    
2455
0
    info.fBlackDeltaV.Reset ();
2456
  
2457
0
    }
2458
                    
2459
0
  }
2460
              
2461
/*****************************************************************************/
2462
2463
void dng_negative::SetColumnBlacks (const real64 *blacks,
2464
                        uint32 count)
2465
0
  {
2466
  
2467
0
  if (count)
2468
0
    {
2469
  
2470
0
    NeedLinearizationInfo ();
2471
    
2472
0
    dng_linearization_info &info = *fLinearizationInfo.Get ();
2473
    
2474
0
    uint32 byteCount = 0;
2475
    
2476
0
    if (!SafeUint32Mult (count, (uint32) sizeof (real64), &byteCount))
2477
0
      {
2478
      
2479
0
      ThrowMemoryFull("Arithmetic overflow computing byte count.");
2480
      
2481
0
      }
2482
                      
2483
0
    info.fBlackDeltaH.Reset (Allocator ().Allocate (byteCount));
2484
    
2485
0
    DoCopyBytes (blacks,
2486
0
           info.fBlackDeltaH->Buffer (),
2487
0
           byteCount);
2488
    
2489
0
    info.RoundBlacks ();
2490
    
2491
0
    }
2492
    
2493
0
  else if (fLinearizationInfo.Get ())
2494
0
    {
2495
    
2496
0
    dng_linearization_info &info = *fLinearizationInfo.Get ();
2497
                      
2498
0
    info.fBlackDeltaH.Reset ();
2499
  
2500
0
    }
2501
                    
2502
0
  }
2503
              
2504
/*****************************************************************************/
2505
2506
uint32 dng_negative::WhiteLevel (uint32 plane) const
2507
17.3k
  {
2508
  
2509
17.3k
  if (fLinearizationInfo.Get ())
2510
7.73k
    {
2511
    
2512
7.73k
    const dng_linearization_info &info = *fLinearizationInfo.Get ();
2513
                      
2514
7.73k
    return Round_uint32 (info.fWhiteLevel [plane]);
2515
                      
2516
7.73k
    }
2517
    
2518
9.59k
  if (RawImage ().PixelType () == ttFloat)
2519
389
    {
2520
    
2521
389
    return 1;
2522
    
2523
389
    }
2524
    
2525
9.21k
  return 0x0FFFF;
2526
  
2527
9.59k
  }
2528
              
2529
/*****************************************************************************/
2530
2531
void dng_negative::SetWhiteLevel (uint32 white,
2532
                    int32 plane)
2533
6.36k
  {
2534
2535
6.36k
  NeedLinearizationInfo ();
2536
  
2537
6.36k
  dng_linearization_info &info = *fLinearizationInfo.Get ();
2538
                    
2539
6.36k
  if (plane < 0)
2540
6.36k
    {
2541
    
2542
31.8k
    for (uint32 j = 0; j < kMaxSamplesPerPixel; j++)
2543
25.4k
      {
2544
      
2545
25.4k
      info.fWhiteLevel [j] = (real64) white;
2546
      
2547
25.4k
      }
2548
    
2549
6.36k
    }
2550
    
2551
0
  else
2552
0
    {
2553
    
2554
0
    info.fWhiteLevel [plane] = (real64) white;
2555
      
2556
0
    }
2557
  
2558
6.36k
  }
2559
2560
/******************************************************************************/
2561
2562
void dng_negative::SetColorKeys (ColorKeyCode color0,
2563
                   ColorKeyCode color1,
2564
                   ColorKeyCode color2,
2565
                   ColorKeyCode color3)
2566
7.06k
  {
2567
  
2568
7.06k
  NeedMosaicInfo ();
2569
  
2570
7.06k
  dng_mosaic_info &info = *fMosaicInfo.Get ();
2571
               
2572
7.06k
  info.fCFAPlaneColor [0] = color0;
2573
7.06k
  info.fCFAPlaneColor [1] = color1;
2574
7.06k
  info.fCFAPlaneColor [2] = color2;
2575
7.06k
  info.fCFAPlaneColor [3] = color3;
2576
  
2577
7.06k
  }
2578
2579
/******************************************************************************/
2580
2581
void dng_negative::SetBayerMosaic (uint32 phase)
2582
0
  {
2583
  
2584
0
  NeedMosaicInfo ();
2585
  
2586
0
  dng_mosaic_info &info = *fMosaicInfo.Get ();
2587
  
2588
0
  ColorKeyCode color0 = (ColorKeyCode) info.fCFAPlaneColor [0];
2589
0
  ColorKeyCode color1 = (ColorKeyCode) info.fCFAPlaneColor [1];
2590
0
  ColorKeyCode color2 = (ColorKeyCode) info.fCFAPlaneColor [2];
2591
  
2592
0
  info.fCFAPatternSize = dng_point (2, 2);
2593
  
2594
0
  switch (phase)
2595
0
    {
2596
    
2597
0
    case 0:
2598
0
      {
2599
0
      info.fCFAPattern [0] [0] = color1;
2600
0
      info.fCFAPattern [0] [1] = color0;
2601
0
      info.fCFAPattern [1] [0] = color2;
2602
0
      info.fCFAPattern [1] [1] = color1;
2603
0
      break;
2604
0
      }
2605
      
2606
0
    case 1:
2607
0
      {
2608
0
      info.fCFAPattern [0] [0] = color0;
2609
0
      info.fCFAPattern [0] [1] = color1;
2610
0
      info.fCFAPattern [1] [0] = color1;
2611
0
      info.fCFAPattern [1] [1] = color2;
2612
0
      break;
2613
0
      }
2614
      
2615
0
    case 2:
2616
0
      {
2617
0
      info.fCFAPattern [0] [0] = color2;
2618
0
      info.fCFAPattern [0] [1] = color1;
2619
0
      info.fCFAPattern [1] [0] = color1;
2620
0
      info.fCFAPattern [1] [1] = color0;
2621
0
      break;
2622
0
      }
2623
      
2624
0
    case 3:
2625
0
      {
2626
0
      info.fCFAPattern [0] [0] = color1;
2627
0
      info.fCFAPattern [0] [1] = color2;
2628
0
      info.fCFAPattern [1] [0] = color0;
2629
0
      info.fCFAPattern [1] [1] = color1;
2630
0
      break;
2631
0
      }
2632
      
2633
0
    }
2634
    
2635
0
  info.fColorPlanes = 3;
2636
  
2637
0
  info.fCFALayout = 1;
2638
  
2639
0
  }
2640
2641
/******************************************************************************/
2642
2643
void dng_negative::SetFujiMosaic (uint32 phase)
2644
0
  {
2645
  
2646
0
  NeedMosaicInfo ();
2647
  
2648
0
  dng_mosaic_info &info = *fMosaicInfo.Get ();
2649
  
2650
0
  ColorKeyCode color0 = (ColorKeyCode) info.fCFAPlaneColor [0];
2651
0
  ColorKeyCode color1 = (ColorKeyCode) info.fCFAPlaneColor [1];
2652
0
  ColorKeyCode color2 = (ColorKeyCode) info.fCFAPlaneColor [2];
2653
  
2654
0
  info.fCFAPatternSize = dng_point (2, 4);
2655
  
2656
0
  switch (phase)
2657
0
    {
2658
    
2659
0
    case 0:
2660
0
      {
2661
0
      info.fCFAPattern [0] [0] = color0;
2662
0
      info.fCFAPattern [0] [1] = color1;
2663
0
      info.fCFAPattern [0] [2] = color2;
2664
0
      info.fCFAPattern [0] [3] = color1;
2665
0
      info.fCFAPattern [1] [0] = color2;
2666
0
      info.fCFAPattern [1] [1] = color1;
2667
0
      info.fCFAPattern [1] [2] = color0;
2668
0
      info.fCFAPattern [1] [3] = color1;
2669
0
      break;
2670
0
      }
2671
      
2672
0
    case 1:
2673
0
      {
2674
0
      info.fCFAPattern [0] [0] = color2;
2675
0
      info.fCFAPattern [0] [1] = color1;
2676
0
      info.fCFAPattern [0] [2] = color0;
2677
0
      info.fCFAPattern [0] [3] = color1;
2678
0
      info.fCFAPattern [1] [0] = color0;
2679
0
      info.fCFAPattern [1] [1] = color1;
2680
0
      info.fCFAPattern [1] [2] = color2;
2681
0
      info.fCFAPattern [1] [3] = color1;
2682
0
      break;
2683
0
      }
2684
      
2685
0
    }
2686
    
2687
0
  info.fColorPlanes = 3;
2688
  
2689
0
  info.fCFALayout = 2;
2690
      
2691
0
  }
2692
2693
/*****************************************************************************/
2694
2695
void dng_negative::SetFujiMosaic6x6 (uint32 phase)
2696
0
  {
2697
  
2698
0
  NeedMosaicInfo ();
2699
  
2700
0
  dng_mosaic_info &info = *fMosaicInfo.Get ();
2701
  
2702
0
  ColorKeyCode color0 = (ColorKeyCode) info.fCFAPlaneColor [0];
2703
0
  ColorKeyCode color1 = (ColorKeyCode) info.fCFAPlaneColor [1];
2704
0
  ColorKeyCode color2 = (ColorKeyCode) info.fCFAPlaneColor [2];
2705
2706
0
  const uint32 patSize = 6;
2707
  
2708
0
  info.fCFAPatternSize = dng_point (patSize, patSize);
2709
2710
0
  info.fCFAPattern [0] [0] = color1;
2711
0
  info.fCFAPattern [0] [1] = color2;
2712
0
  info.fCFAPattern [0] [2] = color1;
2713
0
  info.fCFAPattern [0] [3] = color1;
2714
0
  info.fCFAPattern [0] [4] = color0;
2715
0
  info.fCFAPattern [0] [5] = color1;
2716
2717
0
  info.fCFAPattern [1] [0] = color0;
2718
0
  info.fCFAPattern [1] [1] = color1;
2719
0
  info.fCFAPattern [1] [2] = color0;
2720
0
  info.fCFAPattern [1] [3] = color2;
2721
0
  info.fCFAPattern [1] [4] = color1;
2722
0
  info.fCFAPattern [1] [5] = color2;
2723
2724
0
  info.fCFAPattern [2] [0] = color1;
2725
0
  info.fCFAPattern [2] [1] = color2;
2726
0
  info.fCFAPattern [2] [2] = color1;
2727
0
  info.fCFAPattern [2] [3] = color1;
2728
0
  info.fCFAPattern [2] [4] = color0;
2729
0
  info.fCFAPattern [2] [5] = color1;
2730
2731
0
  info.fCFAPattern [3] [0] = color1;
2732
0
  info.fCFAPattern [3] [1] = color0;
2733
0
  info.fCFAPattern [3] [2] = color1;
2734
0
  info.fCFAPattern [3] [3] = color1;
2735
0
  info.fCFAPattern [3] [4] = color2;
2736
0
  info.fCFAPattern [3] [5] = color1;
2737
2738
0
  info.fCFAPattern [4] [0] = color2;
2739
0
  info.fCFAPattern [4] [1] = color1;
2740
0
  info.fCFAPattern [4] [2] = color2;
2741
0
  info.fCFAPattern [4] [3] = color0;
2742
0
  info.fCFAPattern [4] [4] = color1;
2743
0
  info.fCFAPattern [4] [5] = color0;
2744
2745
0
  info.fCFAPattern [5] [0] = color1;
2746
0
  info.fCFAPattern [5] [1] = color0;
2747
0
  info.fCFAPattern [5] [2] = color1;
2748
0
  info.fCFAPattern [5] [3] = color1;
2749
0
  info.fCFAPattern [5] [4] = color2;
2750
0
  info.fCFAPattern [5] [5] = color1;
2751
2752
0
  DNG_REQUIRE (phase >= 0 && phase < patSize * patSize,
2753
0
         "Bad phase in SetFujiMosaic6x6.");
2754
2755
0
  if (phase > 0)
2756
0
    {
2757
    
2758
0
    dng_mosaic_info temp = info;
2759
2760
0
    uint32 phaseRow = phase / patSize;
2761
2762
0
    uint32 phaseCol = phase - (phaseRow * patSize);
2763
2764
0
    for (uint32 dstRow = 0; dstRow < patSize; dstRow++)
2765
0
      {
2766
      
2767
0
      uint32 srcRow = (dstRow + phaseRow) % patSize;
2768
      
2769
0
      for (uint32 dstCol = 0; dstCol < patSize; dstCol++)
2770
0
        {
2771
2772
0
        uint32 srcCol = (dstCol + phaseCol) % patSize;
2773
      
2774
0
        temp.fCFAPattern [dstRow] [dstCol] = info.fCFAPattern [srcRow] [srcCol];
2775
2776
0
        }
2777
      
2778
0
      }
2779
2780
0
    info = temp;
2781
    
2782
0
    }
2783
    
2784
0
  info.fColorPlanes = 3;
2785
  
2786
0
  info.fCFALayout = 1;
2787
      
2788
0
  }
2789
2790
/******************************************************************************/
2791
2792
void dng_negative::SetQuadMosaic (uint32 pattern)
2793
0
  {
2794
  
2795
  // The pattern of the four colors is assumed to be repeat at least every two
2796
  // columns and eight rows.  The pattern is encoded as a 32-bit integer,
2797
  // with every two bits encoding a color, in scan order for two columns and
2798
  // eight rows (lsb is first).  The usual color coding is:
2799
  //
2800
  // 0 = Green
2801
  // 1 = Magenta
2802
  // 2 = Cyan
2803
  // 3 = Yellow
2804
  //
2805
  // Examples:
2806
  //
2807
  //  PowerShot 600 uses 0xe1e4e1e4:
2808
  //
2809
  //    0 1 2 3 4 5
2810
  //  0 G M G M G M
2811
  //  1 C Y C Y C Y
2812
  //  2 M G M G M G
2813
  //  3 C Y C Y C Y
2814
  //
2815
  //  PowerShot A5 uses 0x1e4e1e4e:
2816
  //
2817
  //    0 1 2 3 4 5
2818
  //  0 C Y C Y C Y
2819
  //  1 G M G M G M
2820
  //  2 C Y C Y C Y
2821
  //  3 M G M G M G
2822
  //
2823
  //  PowerShot A50 uses 0x1b4e4b1e:
2824
  //
2825
  //    0 1 2 3 4 5
2826
  //  0 C Y C Y C Y
2827
  //  1 M G M G M G
2828
  //  2 Y C Y C Y C
2829
  //  3 G M G M G M
2830
  //  4 C Y C Y C Y
2831
  //  5 G M G M G M
2832
  //  6 Y C Y C Y C
2833
  //  7 M G M G M G
2834
  //
2835
  //  PowerShot Pro70 uses 0x1e4b4e1b:
2836
  //
2837
  //    0 1 2 3 4 5
2838
  //  0 Y C Y C Y C
2839
  //  1 M G M G M G
2840
  //  2 C Y C Y C Y
2841
  //  3 G M G M G M
2842
  //  4 Y C Y C Y C
2843
  //  5 G M G M G M
2844
  //  6 C Y C Y C Y
2845
  //  7 M G M G M G
2846
  //
2847
  //  PowerShots Pro90 and G1 use 0xb4b4b4b4:
2848
  //
2849
  //    0 1 2 3 4 5
2850
  //  0 G M G M G M
2851
  //  1 Y C Y C Y C
2852
2853
0
  NeedMosaicInfo ();
2854
  
2855
0
  dng_mosaic_info &info = *fMosaicInfo.Get ();
2856
               
2857
0
  if (((pattern >> 16) & 0x0FFFF) != (pattern & 0x0FFFF))
2858
0
    {
2859
0
    info.fCFAPatternSize = dng_point (8, 2);
2860
0
    }
2861
    
2862
0
  else if (((pattern >> 8) & 0x0FF) != (pattern & 0x0FF))
2863
0
    {
2864
0
    info.fCFAPatternSize = dng_point (4, 2);
2865
0
    }
2866
    
2867
0
  else
2868
0
    {
2869
0
    info.fCFAPatternSize = dng_point (2, 2);
2870
0
    }
2871
    
2872
0
  for (int32 row = 0; row < info.fCFAPatternSize.v; row++)
2873
0
    {
2874
    
2875
0
    for (int32 col = 0; col < info.fCFAPatternSize.h; col++)
2876
0
      {
2877
      
2878
0
      uint32 index = (pattern >> ((((row << 1) & 14) + (col & 1)) << 1)) & 3;
2879
      
2880
0
      info.fCFAPattern [row] [col] = info.fCFAPlaneColor [index];
2881
      
2882
0
      }
2883
      
2884
0
    }
2885
2886
0
  info.fColorPlanes = 4;
2887
  
2888
0
  info.fCFALayout = 1;
2889
      
2890
0
  }
2891
  
2892
/******************************************************************************/
2893
2894
void dng_negative::SetGreenSplit (uint32 split)
2895
0
  {
2896
  
2897
0
  NeedMosaicInfo ();
2898
  
2899
0
  dng_mosaic_info &info = *fMosaicInfo.Get ();
2900
  
2901
0
  info.fBayerGreenSplit = split;
2902
  
2903
0
  }
2904
2905
/*****************************************************************************/
2906
2907
void dng_negative::Parse (dng_host &host,
2908
              dng_stream &stream,
2909
              dng_info &info)
2910
33.7k
  {
2911
  
2912
  // Shared info.
2913
  
2914
33.7k
  dng_shared &shared = *(info.fShared.Get ());
2915
  
2916
  // Find IFD holding the main raw information.
2917
  
2918
33.7k
  dng_ifd &rawIFD = *info.fIFD [info.fMainIndex].Get ();
2919
  
2920
  // Model name.
2921
  
2922
33.7k
  SetModelName (shared.fUniqueCameraModel.Get ());
2923
  
2924
  // Localized model name.
2925
  
2926
33.7k
  SetLocalName (shared.fLocalizedCameraModel.Get ());
2927
  
2928
  // Base orientation.
2929
  
2930
33.7k
    {
2931
  
2932
33.7k
    uint32 orientation = info.fIFD [0]->fOrientation;
2933
    
2934
33.7k
    if (orientation >= 1 && orientation <= 8)
2935
3.09k
      {
2936
      
2937
3.09k
      SetBaseOrientation (dng_orientation::TIFFtoDNG (orientation));
2938
            
2939
3.09k
      }
2940
      
2941
33.7k
    }
2942
    
2943
  // Default crop rectangle.
2944
  
2945
33.7k
  SetDefaultCropSize (rawIFD.fDefaultCropSizeH,
2946
33.7k
              rawIFD.fDefaultCropSizeV);
2947
2948
33.7k
  SetDefaultCropOrigin (rawIFD.fDefaultCropOriginH,
2949
33.7k
              rawIFD.fDefaultCropOriginV);
2950
2951
  // Default user crop rectangle.
2952
2953
33.7k
  SetDefaultUserCrop (rawIFD.fDefaultUserCropT,
2954
33.7k
            rawIFD.fDefaultUserCropL,
2955
33.7k
            rawIFD.fDefaultUserCropB,
2956
33.7k
            rawIFD.fDefaultUserCropR);
2957
                    
2958
  // Default scale.
2959
    
2960
33.7k
  SetDefaultScale (rawIFD.fDefaultScaleH,
2961
33.7k
           rawIFD.fDefaultScaleV);
2962
  
2963
  // Best quality scale.
2964
  
2965
33.7k
  SetBestQualityScale (rawIFD.fBestQualityScale);
2966
  
2967
  // Baseline noise.
2968
2969
33.7k
  SetBaselineNoise (shared.fBaselineNoise.As_real64 ());
2970
  
2971
  // NoiseReductionApplied.
2972
  
2973
33.7k
  SetNoiseReductionApplied (shared.fNoiseReductionApplied);
2974
2975
  // NoiseProfile.
2976
2977
33.7k
  SetNoiseProfile (shared.fNoiseProfile);
2978
  
2979
  // Baseline exposure.
2980
  
2981
33.7k
  SetBaselineExposure (shared.fBaselineExposure.As_real64 ());
2982
2983
  // Baseline sharpness.
2984
  
2985
33.7k
  SetBaselineSharpness (shared.fBaselineSharpness.As_real64 ());
2986
2987
  // Chroma blur radius.
2988
  
2989
33.7k
  SetChromaBlurRadius (rawIFD.fChromaBlurRadius);
2990
2991
  // Anti-alias filter strength.
2992
  
2993
33.7k
  SetAntiAliasStrength (rawIFD.fAntiAliasStrength);
2994
    
2995
  // Linear response limit.
2996
  
2997
33.7k
  SetLinearResponseLimit (shared.fLinearResponseLimit.As_real64 ());
2998
  
2999
  // Shadow scale.
3000
  
3001
33.7k
  SetShadowScale (shared.fShadowScale);
3002
  
3003
  // Colorimetric reference.
3004
  
3005
33.7k
  SetColorimetricReference (shared.fColorimetricReference);
3006
  
3007
  // Color channels.
3008
    
3009
33.7k
  SetColorChannels (shared.fCameraProfile.fColorPlanes);
3010
  
3011
  // Analog balance.
3012
  
3013
33.7k
  if (shared.fAnalogBalance.NotEmpty ())
3014
8.12k
    {
3015
    
3016
8.12k
    SetAnalogBalance (shared.fAnalogBalance);
3017
    
3018
8.12k
    }
3019
3020
  // Camera calibration matrices
3021
3022
33.7k
  if (shared.fCameraCalibration1.NotEmpty ())
3023
257
    {
3024
    
3025
257
    SetCameraCalibration1 (shared.fCameraCalibration1);
3026
    
3027
257
    }
3028
    
3029
33.7k
  if (shared.fCameraCalibration2.NotEmpty ())
3030
173
    {
3031
    
3032
173
    SetCameraCalibration2 (shared.fCameraCalibration2);
3033
    
3034
173
    }
3035
    
3036
33.7k
  if (shared.fCameraCalibration1.NotEmpty () ||
3037
33.4k
    shared.fCameraCalibration2.NotEmpty ())
3038
286
    {
3039
    
3040
286
    SetCameraCalibrationSignature (shared.fCameraCalibrationSignature.Get ());
3041
    
3042
286
    }
3043
3044
  // Embedded camera profiles.
3045
  
3046
33.7k
  if (shared.fCameraProfile.fColorPlanes > 1)
3047
16.2k
    {
3048
  
3049
16.2k
    if (qDNGValidate || host.NeedsMeta () || host.NeedsImage ())
3050
16.2k
      {
3051
      
3052
      // Add profile from main IFD.
3053
      
3054
16.2k
        {
3055
      
3056
16.2k
        AutoPtr<dng_camera_profile> profile (new dng_camera_profile ());
3057
        
3058
16.2k
        dng_camera_profile_info &profileInfo = shared.fCameraProfile;
3059
        
3060
16.2k
        profile->Parse (stream, profileInfo);
3061
        
3062
        // The main embedded profile must be valid.
3063
        
3064
16.2k
        if (!profile->IsValid (shared.fCameraProfile.fColorPlanes))
3065
135
          {
3066
          
3067
135
          ThrowBadFormat ();
3068
          
3069
135
          }
3070
        
3071
16.2k
        profile->SetWasReadFromDNG ();
3072
        
3073
16.2k
        AddProfile (profile);
3074
        
3075
16.2k
        }
3076
        
3077
      // Extra profiles.
3078
3079
168k
      for (uint32 index = 0; index < (uint32) shared.fExtraCameraProfiles.size (); index++)
3080
152k
        {
3081
        
3082
152k
        try
3083
152k
          {
3084
3085
152k
          AutoPtr<dng_camera_profile> profile (new dng_camera_profile ());
3086
          
3087
152k
          dng_camera_profile_info &profileInfo = shared.fExtraCameraProfiles [index];
3088
          
3089
152k
          profile->Parse (stream, profileInfo);
3090
          
3091
152k
          if (!profile->IsValid (shared.fCameraProfile.fColorPlanes))
3092
12.4k
            {
3093
            
3094
12.4k
            ThrowBadFormat ();
3095
            
3096
12.4k
            }
3097
          
3098
152k
          profile->SetWasReadFromDNG ();
3099
          
3100
152k
          AddProfile (profile);
3101
3102
152k
          }
3103
          
3104
152k
        catch (dng_exception &except)
3105
152k
          {
3106
          
3107
          // Don't ignore transient errors.
3108
          
3109
32.9k
          if (host.IsTransientError (except.ErrorCode ()))
3110
17
            {
3111
            
3112
17
            throw;
3113
            
3114
17
            }
3115
        
3116
          // Eat other parsing errors.
3117
      
3118
          #if qDNGValidate
3119
          
3120
          ReportWarning ("Unable to parse extra profile");
3121
          
3122
          #endif
3123
          
3124
32.9k
          }
3125
      
3126
152k
        }
3127
      
3128
16.2k
      }
3129
      
3130
    // As shot profile name.
3131
    
3132
16.2k
    if (shared.fAsShotProfileName.NotEmpty ())
3133
361
      {
3134
      
3135
361
      SetAsShotProfileName (shared.fAsShotProfileName.Get ());
3136
      
3137
361
      }
3138
      
3139
16.2k
    }
3140
    
3141
  // Raw image data digest.
3142
  
3143
33.7k
  if (shared.fRawImageDigest.IsValid ())
3144
4.54k
    {
3145
    
3146
4.54k
    SetRawImageDigest (shared.fRawImageDigest);
3147
    
3148
4.54k
    }
3149
      
3150
  // New raw image data digest.
3151
  
3152
33.7k
  if (shared.fNewRawImageDigest.IsValid ())
3153
101
    {
3154
    
3155
101
    SetNewRawImageDigest (shared.fNewRawImageDigest);
3156
    
3157
101
    }
3158
      
3159
  // Raw data unique ID.
3160
  
3161
33.7k
  if (shared.fRawDataUniqueID.IsValid ())
3162
3.45k
    {
3163
    
3164
3.45k
    SetRawDataUniqueID (shared.fRawDataUniqueID);
3165
    
3166
3.45k
    }
3167
      
3168
  // Original raw file name.
3169
  
3170
33.7k
  if (shared.fOriginalRawFileName.NotEmpty ())
3171
206
    {
3172
    
3173
206
    SetOriginalRawFileName (shared.fOriginalRawFileName.Get ());
3174
    
3175
206
    }
3176
    
3177
  // Original raw file data.
3178
  
3179
33.7k
  if (shared.fOriginalRawFileDataCount)
3180
320
    {
3181
    
3182
320
    SetHasOriginalRawFileData (true);
3183
          
3184
320
    if (host.KeepOriginalFile ())
3185
288
      {
3186
      
3187
288
      uint32 count = shared.fOriginalRawFileDataCount;
3188
      
3189
288
      AutoPtr<dng_memory_block> block (host.Allocate (count));
3190
      
3191
288
      stream.SetReadPosition (shared.fOriginalRawFileDataOffset);
3192
    
3193
288
      stream.Get (block->Buffer (), count);
3194
            
3195
288
      SetOriginalRawFileData (block);
3196
      
3197
288
      SetOriginalRawFileDigest (shared.fOriginalRawFileDigest);
3198
      
3199
288
      ValidateOriginalRawFileDigest ();
3200
      
3201
288
      }
3202
      
3203
320
    }
3204
      
3205
  // DNG private data.
3206
  
3207
33.7k
  if (shared.fDNGPrivateDataCount && (host.SaveDNGVersion () != dngVersion_None))
3208
6.01k
    {
3209
    
3210
6.01k
    uint32 length = shared.fDNGPrivateDataCount;
3211
    
3212
6.01k
    AutoPtr<dng_memory_block> block (host.Allocate (length));
3213
    
3214
6.01k
    stream.SetReadPosition (shared.fDNGPrivateDataOffset);
3215
      
3216
6.01k
    stream.Get (block->Buffer (), length);
3217
              
3218
6.01k
    SetPrivateData (block);
3219
      
3220
6.01k
    }
3221
    
3222
  // Hand off EXIF metadata to negative.
3223
  
3224
33.7k
  ResetExif (info.fExif.Release ());
3225
  
3226
  // Parse linearization info.
3227
  
3228
33.7k
  NeedLinearizationInfo ();
3229
  
3230
33.7k
  fLinearizationInfo.Get ()->Parse (host,
3231
33.7k
                      stream,
3232
33.7k
                      info);
3233
                      
3234
  // Parse mosaic info.
3235
  
3236
33.7k
  if (rawIFD.fPhotometricInterpretation == piCFA)
3237
1.81k
    {
3238
  
3239
1.81k
    NeedMosaicInfo ();
3240
    
3241
1.81k
    fMosaicInfo.Get ()->Parse (host,
3242
1.81k
                     stream,
3243
1.81k
                     info);
3244
                
3245
1.81k
    }
3246
              
3247
  // Fill in original sizes.
3248
  
3249
33.7k
  if (shared.fOriginalDefaultFinalSize.h > 0 &&
3250
362
    shared.fOriginalDefaultFinalSize.v > 0)
3251
218
    {
3252
    
3253
218
    SetOriginalDefaultFinalSize (shared.fOriginalDefaultFinalSize);
3254
    
3255
218
    SetOriginalBestQualityFinalSize (shared.fOriginalDefaultFinalSize);
3256
    
3257
218
    SetOriginalDefaultCropSize (dng_urational (shared.fOriginalDefaultFinalSize.h, 1),
3258
218
                  dng_urational (shared.fOriginalDefaultFinalSize.v, 1));
3259
    
3260
218
    }
3261
    
3262
33.7k
  if (shared.fOriginalBestQualityFinalSize.h > 0 &&
3263
230
    shared.fOriginalBestQualityFinalSize.v > 0)
3264
179
    {
3265
    
3266
179
    SetOriginalBestQualityFinalSize (shared.fOriginalBestQualityFinalSize);
3267
    
3268
179
    }
3269
    
3270
33.7k
  if (shared.fOriginalDefaultCropSizeH.As_real64 () >= 1.0 &&
3271
916
    shared.fOriginalDefaultCropSizeV.As_real64 () >= 1.0)
3272
163
    {
3273
    
3274
163
    SetOriginalDefaultCropSize (shared.fOriginalDefaultCropSizeH,
3275
163
                  shared.fOriginalDefaultCropSizeV);
3276
    
3277
163
    }
3278
    
3279
33.7k
  }
3280
3281
/*****************************************************************************/
3282
3283
void dng_negative::SetDefaultOriginalSizes ()
3284
28.0k
  {
3285
  
3286
  // Fill in original sizes if we don't have them already.
3287
  
3288
28.0k
  if (OriginalDefaultFinalSize () == dng_point ())
3289
27.7k
    {
3290
    
3291
27.7k
    SetOriginalDefaultFinalSize (dng_point (DefaultFinalHeight (),
3292
27.7k
                        DefaultFinalWidth  ()));
3293
    
3294
27.7k
    }
3295
    
3296
28.0k
  if (OriginalBestQualityFinalSize () == dng_point ())
3297
27.5k
    {
3298
    
3299
27.5k
    SetOriginalBestQualityFinalSize (dng_point (BestQualityFinalHeight (),
3300
27.5k
                          BestQualityFinalWidth  ()));
3301
    
3302
27.5k
    }
3303
    
3304
28.0k
  if (OriginalDefaultCropSizeH ().NotValid () ||
3305
363
    OriginalDefaultCropSizeV ().NotValid ())
3306
27.4k
    {
3307
    
3308
27.4k
    SetOriginalDefaultCropSize (DefaultCropSizeH (),
3309
27.4k
                  DefaultCropSizeV ());
3310
    
3311
27.4k
    }
3312
3313
28.0k
  }
3314
3315
/*****************************************************************************/
3316
3317
void dng_negative::PostParse (dng_host &host,
3318
                  dng_stream &stream,
3319
                  dng_info &info)
3320
28.0k
  {
3321
  
3322
  // Shared info.
3323
  
3324
28.0k
  dng_shared &shared = *(info.fShared.Get ());
3325
  
3326
28.0k
  if (host.NeedsMeta ())
3327
28.0k
    {
3328
    
3329
    // Fill in original sizes if we don't have them already.
3330
    
3331
28.0k
    SetDefaultOriginalSizes ();
3332
        
3333
    // MakerNote.
3334
    
3335
28.0k
    if (shared.fMakerNoteCount)
3336
477
      {
3337
      
3338
      // See if we know if the MakerNote is safe or not.
3339
      
3340
477
      SetMakerNoteSafety (shared.fMakerNoteSafety == 1);
3341
      
3342
      // If the MakerNote is safe, preserve it as a MakerNote.
3343
      
3344
477
      if (IsMakerNoteSafe ())
3345
84
        {
3346
3347
84
        AutoPtr<dng_memory_block> block (host.Allocate (shared.fMakerNoteCount));
3348
        
3349
84
        stream.SetReadPosition (shared.fMakerNoteOffset);
3350
          
3351
84
        stream.Get (block->Buffer (), shared.fMakerNoteCount);
3352
                  
3353
84
        SetMakerNote (block);
3354
              
3355
84
        }
3356
      
3357
477
      }
3358
    
3359
    // IPTC metadata.
3360
    
3361
28.0k
    if (shared.fIPTC_NAA_Count)
3362
57
      {
3363
      
3364
57
      AutoPtr<dng_memory_block> block (host.Allocate (shared.fIPTC_NAA_Count));
3365
      
3366
57
      stream.SetReadPosition (shared.fIPTC_NAA_Offset);
3367
      
3368
57
      uint64 iptcOffset = stream.PositionInOriginalFile();
3369
      
3370
57
      stream.Get (block->Buffer      (), 
3371
57
            block->LogicalSize ());
3372
      
3373
57
      SetIPTC (block, iptcOffset);
3374
              
3375
57
      }
3376
    
3377
    // XMP metadata.
3378
    
3379
    #if qDNGUseXMP
3380
    
3381
    if (shared.fXMPCount)
3382
      {
3383
      
3384
      AutoPtr<dng_memory_block> block (host.Allocate (shared.fXMPCount));
3385
      
3386
      stream.SetReadPosition (shared.fXMPOffset);
3387
      
3388
      stream.Get (block->Buffer      (),
3389
            block->LogicalSize ());
3390
            
3391
      Metadata ().SetEmbeddedXMP (host,
3392
                      block->Buffer      (),
3393
                      block->LogicalSize ());
3394
                    
3395
      #if qDNGValidate
3396
      
3397
      if (!Metadata ().HaveValidEmbeddedXMP ())
3398
        {
3399
        ReportError ("The embedded XMP is invalid");
3400
        }
3401
      
3402
      #endif
3403
      
3404
      }
3405
        
3406
    #endif
3407
    
3408
    // Color info.
3409
    
3410
28.0k
    if (!IsMonochrome ())
3411
11.4k
      {
3412
      
3413
      // If the ColorimetricReference is the ICC profile PCS,
3414
      // then the data must be already be white balanced to the
3415
      // ICC profile PCS white point.
3416
      
3417
11.4k
      if (ColorimetricReference () == crICCProfilePCS)
3418
2.89k
        {
3419
        
3420
2.89k
        ClearCameraNeutral ();
3421
        
3422
2.89k
        SetCameraWhiteXY (PCStoXY ());
3423
        
3424
2.89k
        }
3425
        
3426
8.56k
      else
3427
8.56k
        {
3428
                  
3429
        // AsShotNeutral.
3430
        
3431
8.56k
        if (shared.fAsShotNeutral.Count () == ColorChannels ())
3432
393
          {
3433
          
3434
393
          SetCameraNeutral (shared.fAsShotNeutral);
3435
                    
3436
393
          }
3437
          
3438
        // AsShotWhiteXY.
3439
        
3440
8.56k
        if (shared.fAsShotWhiteXY.IsValid () && !HasCameraNeutral ())
3441
1.08k
          {
3442
          
3443
1.08k
          SetCameraWhiteXY (shared.fAsShotWhiteXY);
3444
          
3445
1.08k
          }
3446
          
3447
8.56k
        }
3448
        
3449
11.4k
      }
3450
          
3451
28.0k
    }
3452
    
3453
28.0k
  }
3454
              
3455
/*****************************************************************************/
3456
3457
bool dng_negative::SetFourColorBayer ()
3458
12.1k
  {
3459
  
3460
12.1k
  if (ColorChannels () != 3)
3461
8.27k
    {
3462
8.27k
    return false;
3463
8.27k
    }
3464
    
3465
3.90k
  if (!fMosaicInfo.Get ())
3466
3.38k
    {
3467
3.38k
    return false;
3468
3.38k
    }
3469
    
3470
518
  if (!fMosaicInfo.Get ()->SetFourColorBayer ())
3471
113
    {
3472
113
    return false;
3473
113
    }
3474
    
3475
405
  SetColorChannels (4);
3476
  
3477
405
  if (fCameraNeutral.Count () == 3)
3478
26
    {
3479
    
3480
26
    dng_vector n (4);
3481
    
3482
26
    n [0] = fCameraNeutral [0];
3483
26
    n [1] = fCameraNeutral [1];
3484
26
    n [2] = fCameraNeutral [2];
3485
26
    n [3] = fCameraNeutral [1];
3486
    
3487
26
    fCameraNeutral = n;
3488
    
3489
26
    }
3490
3491
405
  fCameraCalibration1.Clear ();
3492
405
  fCameraCalibration2.Clear ();
3493
  
3494
405
  fCameraCalibrationSignature.Clear ();
3495
  
3496
7.96k
  for (uint32 index = 0; index < (uint32) fCameraProfile.size (); index++)
3497
7.56k
    {
3498
    
3499
7.56k
    fCameraProfile [index]->SetFourColorBayer ();
3500
    
3501
7.56k
    }
3502
      
3503
405
  return true;
3504
  
3505
518
  }
3506
          
3507
/*****************************************************************************/
3508
3509
const dng_image & dng_negative::RawImage () const
3510
70.9k
  {
3511
  
3512
70.9k
  if (fRawImage.Get ())
3513
59.3k
    {
3514
59.3k
    return *fRawImage.Get ();
3515
59.3k
    }
3516
    
3517
11.5k
  if (fStage1Image.Get ())
3518
543
    {
3519
543
    return *fStage1Image.Get ();
3520
543
    }
3521
    
3522
11.0k
  if (fUnflattenedStage3Image.Get ())
3523
0
    {
3524
0
    return *fUnflattenedStage3Image.Get ();
3525
0
    }
3526
    
3527
11.0k
  DNG_ASSERT (fStage3Image.Get (),
3528
11.0k
        "dng_negative::RawImage with no raw image");
3529
        
3530
11.0k
  return *fStage3Image.Get ();
3531
  
3532
11.0k
  }
3533
3534
/*****************************************************************************/
3535
3536
const dng_jpeg_image * dng_negative::RawJPEGImage () const
3537
37.1k
  {
3538
3539
37.1k
  return fRawJPEGImage.Get ();
3540
3541
37.1k
  }
3542
3543
/*****************************************************************************/
3544
3545
void dng_negative::SetRawJPEGImage (AutoPtr<dng_jpeg_image> &jpegImage)
3546
3.56k
  {
3547
3548
3.56k
  fRawJPEGImage.Reset (jpegImage.Release ());
3549
3550
3.56k
  }
3551
3552
/*****************************************************************************/
3553
3554
void dng_negative::ClearRawJPEGImage ()
3555
14.7k
  {
3556
  
3557
14.7k
  fRawJPEGImage.Reset ();
3558
3559
14.7k
  }
3560
3561
/*****************************************************************************/
3562
3563
void dng_negative::FindRawJPEGImageDigest (dng_host &host) const
3564
6.48k
  {
3565
  
3566
6.48k
  if (fRawJPEGImageDigest.IsNull ())
3567
3.25k
    {
3568
    
3569
3.25k
    if (fRawJPEGImage.Get ())
3570
3.25k
      {
3571
      
3572
      #if qDNGValidate
3573
      
3574
      dng_timer timer ("FindRawJPEGImageDigest time");
3575
       
3576
      #endif
3577
      
3578
3.25k
      fRawJPEGImageDigest = fRawJPEGImage->FindDigest (host);
3579
      
3580
3.25k
      }
3581
      
3582
0
    else
3583
0
      {
3584
      
3585
0
      ThrowProgramError ("No raw JPEG image");
3586
      
3587
0
      }
3588
    
3589
3.25k
    }
3590
  
3591
6.48k
  }
3592
    
3593
/*****************************************************************************/
3594
3595
void dng_negative::ReadStage1Image (dng_host &host,
3596
                  dng_stream &stream,
3597
                  dng_info &info)
3598
27.6k
  {
3599
  
3600
  // Allocate image we are reading.
3601
  
3602
27.6k
  dng_ifd &rawIFD = *info.fIFD [info.fMainIndex].Get ();
3603
  
3604
27.6k
  fStage1Image.Reset (host.Make_dng_image (rawIFD.Bounds (),
3605
27.6k
                       rawIFD.fSamplesPerPixel,
3606
27.6k
                       rawIFD.PixelType ()));
3607
          
3608
  // See if we should grab the compressed JPEG data.
3609
  
3610
27.6k
  AutoPtr<dng_jpeg_image> jpegImage;
3611
  
3612
27.6k
  if (host.SaveDNGVersion () >= dngVersion_1_4_0_0 &&
3613
11.8k
    !host.PreferredSize () &&
3614
11.8k
    !host.ForPreview () &&
3615
10.0k
    rawIFD.fCompression == ccLossyJPEG)
3616
370
    {
3617
    
3618
370
    jpegImage.Reset (new dng_jpeg_image);
3619
    
3620
370
    }
3621
    
3622
  // See if we need to compute the digest of the compressed JPEG data
3623
  // while reading.
3624
  
3625
27.6k
  bool needJPEGDigest = (RawImageDigest    ().IsValid () ||
3626
23.3k
               NewRawImageDigest ().IsValid ()) &&
3627
4.36k
              rawIFD.fCompression == ccLossyJPEG &&
3628
443
              jpegImage.Get () == NULL;
3629
  
3630
27.6k
  dng_fingerprint jpegDigest;
3631
  
3632
  // Read the image.
3633
  
3634
27.6k
  rawIFD.ReadImage (host,
3635
27.6k
            stream,
3636
27.6k
            *fStage1Image.Get (),
3637
27.6k
            jpegImage.Get (),
3638
27.6k
            needJPEGDigest ? &jpegDigest : NULL);
3639
            
3640
  // Remember the raw floating point bit depth, if reading from
3641
  // a floating point image.
3642
  
3643
27.6k
  if (fStage1Image->PixelType () == ttFloat)
3644
702
    {
3645
    
3646
702
    SetRawFloatBitDepth (rawIFD.fBitsPerSample [0]);
3647
    
3648
702
    }
3649
            
3650
  // Remember the compressed JPEG data if we read it.
3651
  
3652
27.6k
  if (jpegImage.Get ())
3653
311
    {
3654
        
3655
311
    SetRawJPEGImage (jpegImage);
3656
        
3657
311
    }
3658
    
3659
  // Remember the compressed JPEG digest if we computed it.
3660
  
3661
27.6k
  if (jpegDigest.IsValid ())
3662
262
    {
3663
    
3664
262
    SetRawJPEGImageDigest (jpegDigest);
3665
    
3666
262
    }
3667
            
3668
  // We are are reading the main image, we should read the opcode lists
3669
  // also.
3670
  
3671
27.6k
  if (rawIFD.fOpcodeList1Count)
3672
332
    {
3673
    
3674
    #if qDNGValidate
3675
    
3676
    if (gVerbose)
3677
      {
3678
      printf ("\nParsing OpcodeList1: ");
3679
      }
3680
      
3681
    #endif
3682
    
3683
332
    fOpcodeList1.Parse (host,
3684
332
              stream,
3685
332
              rawIFD.fOpcodeList1Count,
3686
332
              rawIFD.fOpcodeList1Offset);
3687
    
3688
332
    }
3689
    
3690
27.6k
  if (rawIFD.fOpcodeList2Count)
3691
2.20k
    {
3692
    
3693
    #if qDNGValidate
3694
    
3695
    if (gVerbose)
3696
      {
3697
      printf ("\nParsing OpcodeList2: ");
3698
      }
3699
      
3700
    #endif
3701
    
3702
2.20k
    fOpcodeList2.Parse (host,
3703
2.20k
              stream,
3704
2.20k
              rawIFD.fOpcodeList2Count,
3705
2.20k
              rawIFD.fOpcodeList2Offset);
3706
    
3707
2.20k
    }
3708
3709
27.6k
  if (rawIFD.fOpcodeList3Count)
3710
2.87k
    {
3711
    
3712
    #if qDNGValidate
3713
    
3714
    if (gVerbose)
3715
      {
3716
      printf ("\nParsing OpcodeList3: ");
3717
      }
3718
      
3719
    #endif
3720
    
3721
2.87k
    fOpcodeList3.Parse (host,
3722
2.87k
              stream,
3723
2.87k
              rawIFD.fOpcodeList3Count,
3724
2.87k
              rawIFD.fOpcodeList3Offset);
3725
    
3726
2.87k
    }
3727
3728
27.6k
  }
3729
          
3730
/*****************************************************************************/
3731
3732
void dng_negative::SetStage1Image (AutoPtr<dng_image> &image)
3733
0
  {
3734
  
3735
0
  fStage1Image.Reset (image.Release ());
3736
  
3737
0
  }
3738
3739
/*****************************************************************************/
3740
3741
void dng_negative::SetStage2Image (AutoPtr<dng_image> &image)
3742
0
  {
3743
  
3744
0
  fStage2Image.Reset (image.Release ());
3745
  
3746
0
  }
3747
3748
/*****************************************************************************/
3749
3750
void dng_negative::SetStage3Image (AutoPtr<dng_image> &image)
3751
0
  {
3752
  
3753
0
  fStage3Image.Reset (image.Release ());
3754
  
3755
0
  }
3756
3757
/*****************************************************************************/
3758
3759
void dng_negative::DoBuildStage2 (dng_host &host)
3760
14.1k
  {
3761
  
3762
14.1k
  dng_image &stage1 = *fStage1Image.Get ();
3763
    
3764
14.1k
  dng_linearization_info &info = *fLinearizationInfo.Get ();
3765
  
3766
14.1k
  uint32 pixelType = ttShort;
3767
  
3768
14.1k
  if (stage1.PixelType () == ttLong ||
3769
11.1k
    stage1.PixelType () == ttFloat)
3770
3.70k
    {
3771
    
3772
3.70k
    pixelType = ttFloat;
3773
    
3774
3.70k
    }
3775
  
3776
14.1k
  fStage2Image.Reset (host.Make_dng_image (info.fActiveArea.Size (),
3777
14.1k
                       stage1.Planes (),
3778
14.1k
                       pixelType));
3779
                   
3780
14.1k
  info.Linearize (host,
3781
14.1k
          stage1,
3782
14.1k
          *fStage2Image.Get ());
3783
               
3784
14.1k
  }
3785
    
3786
/*****************************************************************************/
3787
3788
void dng_negative::DoPostOpcodeList2 (dng_host & /* host */)
3789
13.7k
  {
3790
  
3791
  // Nothing by default.
3792
  
3793
13.7k
  }
3794
3795
/*****************************************************************************/
3796
3797
bool dng_negative::NeedDefloatStage2 (dng_host &host)
3798
13.7k
  {
3799
  
3800
13.7k
  if (fStage2Image->PixelType () == ttFloat)
3801
3.69k
    {
3802
    
3803
3.69k
    if (fRawImageStage >= rawImageStagePostOpcode2 &&
3804
1.63k
      host.SaveDNGVersion () != dngVersion_None  &&
3805
671
      host.SaveDNGVersion () <  dngVersion_1_4_0_0)
3806
516
      {
3807
      
3808
516
      return true;
3809
      
3810
516
      }
3811
    
3812
3.69k
    }
3813
  
3814
13.2k
  return false;
3815
  
3816
13.7k
  }
3817
    
3818
/*****************************************************************************/
3819
3820
void dng_negative::DefloatStage2 (dng_host & /* host */)
3821
516
  {
3822
  
3823
516
  ThrowNotYetImplemented ("dng_negative::DefloatStage2");
3824
  
3825
516
  }
3826
    
3827
/*****************************************************************************/
3828
3829
void dng_negative::BuildStage2Image (dng_host &host)
3830
14.2k
  {
3831
  
3832
  // If reading the negative to save in DNG format, figure out
3833
  // when to grab a copy of the raw data.
3834
  
3835
14.2k
  if (host.SaveDNGVersion () != dngVersion_None)
3836
11.4k
    {
3837
    
3838
    // Transparency masks are only supported in DNG version 1.4 and
3839
    // later.  In this case, the flattening of the transparency mask happens
3840
    // on the the stage3 image.  
3841
    
3842
11.4k
    if (TransparencyMask () && host.SaveDNGVersion () < dngVersion_1_4_0_0)
3843
0
      {
3844
0
      fRawImageStage = rawImageStagePostOpcode3;
3845
0
      }
3846
    
3847
11.4k
    else if (fOpcodeList3.MinVersion (false) > host.SaveDNGVersion () ||
3848
11.2k
           fOpcodeList3.AlwaysApply ())
3849
183
      {
3850
183
      fRawImageStage = rawImageStagePostOpcode3;
3851
183
      }
3852
      
3853
11.2k
    else if (host.SaveLinearDNG (*this))
3854
4.87k
      {
3855
      
3856
      // If the opcode list 3 has optional tags that are beyond the
3857
      // the minimum version, and we are saving a linear DNG anyway,
3858
      // then go ahead and apply them.
3859
      
3860
4.87k
      if (fOpcodeList3.MinVersion (true) > host.SaveDNGVersion ())
3861
26
        {
3862
26
        fRawImageStage = rawImageStagePostOpcode3;
3863
26
        }
3864
        
3865
4.84k
      else
3866
4.84k
        {
3867
4.84k
        fRawImageStage = rawImageStagePreOpcode3;
3868
4.84k
        }
3869
      
3870
4.87k
      }
3871
      
3872
6.35k
    else if (fOpcodeList2.MinVersion (false) > host.SaveDNGVersion () ||
3873
6.33k
         fOpcodeList2.AlwaysApply ())
3874
54
      {
3875
54
      fRawImageStage = rawImageStagePostOpcode2;
3876
54
      }
3877
      
3878
6.30k
    else if (fOpcodeList1.MinVersion (false) > host.SaveDNGVersion () ||
3879
6.29k
         fOpcodeList1.AlwaysApply ())
3880
18
      {
3881
18
      fRawImageStage = rawImageStagePostOpcode1;
3882
18
      }
3883
      
3884
6.28k
    else
3885
6.28k
      {
3886
6.28k
      fRawImageStage = rawImageStagePreOpcode1;
3887
6.28k
      }
3888
      
3889
    // We should not save floating point stage1 images unless the target
3890
    // DNG version is high enough to understand floating point images. 
3891
    // We handle this by converting from floating point to integer if 
3892
    // required after building stage2 image.
3893
    
3894
11.4k
    if (fStage1Image->PixelType () == ttFloat)
3895
539
      {
3896
      
3897
539
      if (fRawImageStage < rawImageStagePostOpcode2)
3898
466
        {
3899
        
3900
466
        if (host.SaveDNGVersion () < dngVersion_1_4_0_0)
3901
0
          {
3902
          
3903
0
          fRawImageStage = rawImageStagePostOpcode2;
3904
          
3905
0
          }
3906
          
3907
466
        }
3908
        
3909
539
      }
3910
      
3911
11.4k
    }
3912
    
3913
  // Grab clone of raw image if required.
3914
  
3915
14.2k
  if (fRawImageStage == rawImageStagePreOpcode1)
3916
6.28k
    {
3917
    
3918
6.28k
    fRawImage.Reset (fStage1Image->Clone ());
3919
    
3920
6.28k
    if (fTransparencyMask.Get ())
3921
0
      {
3922
0
      fRawTransparencyMask.Reset (fTransparencyMask->Clone ());
3923
0
      }
3924
    
3925
6.28k
    }
3926
3927
7.92k
  else
3928
7.92k
    {
3929
    
3930
    // If we are not keeping the most raw image, we need
3931
    // to recompute the raw image digest.
3932
    
3933
7.92k
    ClearRawImageDigest ();
3934
    
3935
    // If we don't grab the unprocessed stage 1 image, then
3936
    // the raw JPEG image is no longer valid.
3937
    
3938
7.92k
    ClearRawJPEGImage ();
3939
    
3940
    // Nor is the digest of the raw JPEG data.
3941
    
3942
7.92k
    ClearRawJPEGImageDigest ();
3943
    
3944
    // We also don't know the raw floating point bit depth.
3945
    
3946
7.92k
    SetRawFloatBitDepth (0);
3947
    
3948
7.92k
    }
3949
    
3950
  // Process opcode list 1.
3951
  
3952
14.2k
  host.ApplyOpcodeList (fOpcodeList1, *this, fStage1Image);
3953
  
3954
  // See if we are done with the opcode list 1.
3955
  
3956
14.2k
  if (fRawImageStage > rawImageStagePreOpcode1)
3957
7.85k
    {
3958
    
3959
7.85k
    fOpcodeList1.Clear ();
3960
    
3961
7.85k
    }
3962
  
3963
  // Grab clone of raw image if required.
3964
  
3965
14.2k
  if (fRawImageStage == rawImageStagePostOpcode1)
3966
4
    {
3967
    
3968
4
    fRawImage.Reset (fStage1Image->Clone ());
3969
    
3970
4
    if (fTransparencyMask.Get ())
3971
0
      {
3972
0
      fRawTransparencyMask.Reset (fTransparencyMask->Clone ());
3973
0
      }
3974
    
3975
4
    }
3976
3977
  // Finalize linearization info.
3978
  
3979
14.2k
    {
3980
  
3981
14.2k
    NeedLinearizationInfo ();
3982
  
3983
14.2k
    dng_linearization_info &info = *fLinearizationInfo.Get ();
3984
    
3985
14.2k
    info.PostParse (host, *this);
3986
    
3987
14.2k
    }
3988
    
3989
  // Perform the linearization.
3990
  
3991
14.2k
  DoBuildStage2 (host);
3992
    
3993
  // Delete the stage1 image now that we have computed the stage 2 image.
3994
  
3995
14.2k
  fStage1Image.Reset ();
3996
  
3997
  // Are we done with the linearization info.
3998
  
3999
14.2k
  if (fRawImageStage > rawImageStagePostOpcode1)
4000
7.67k
    {
4001
    
4002
7.67k
    ClearLinearizationInfo ();
4003
    
4004
7.67k
    }
4005
  
4006
  // Process opcode list 2.
4007
  
4008
14.2k
  host.ApplyOpcodeList (fOpcodeList2, *this, fStage2Image);
4009
  
4010
  // See if we are done with the opcode list 2.
4011
  
4012
14.2k
  if (fRawImageStage > rawImageStagePostOpcode1)
4013
7.59k
    {
4014
    
4015
7.59k
    fOpcodeList2.Clear ();
4016
    
4017
7.59k
    }
4018
    
4019
  // Hook for any required processing just after opcode list 2.
4020
  
4021
14.2k
  DoPostOpcodeList2 (host);
4022
    
4023
  // Convert from floating point to integer if required.
4024
  
4025
14.2k
  if (NeedDefloatStage2 (host))
4026
516
    {
4027
    
4028
516
    DefloatStage2 (host);
4029
    
4030
516
    }
4031
    
4032
  // Grab clone of raw image if required.
4033
  
4034
14.2k
  if (fRawImageStage == rawImageStagePostOpcode2)
4035
15
    {
4036
    
4037
15
    fRawImage.Reset (fStage2Image->Clone ());
4038
    
4039
15
    if (fTransparencyMask.Get ())
4040
0
      {
4041
0
      fRawTransparencyMask.Reset (fTransparencyMask->Clone ());
4042
0
      }
4043
    
4044
15
    }
4045
  
4046
14.2k
  }
4047
                    
4048
/*****************************************************************************/
4049
4050
void dng_negative::DoInterpolateStage3 (dng_host &host,
4051
                        int32 srcPlane)
4052
1.47k
  {
4053
  
4054
1.47k
  dng_image &stage2 = *fStage2Image.Get ();
4055
    
4056
1.47k
  dng_mosaic_info &info = *fMosaicInfo.Get ();
4057
  
4058
1.47k
  dng_point downScale = info.DownScale (host.MinimumSize   (),
4059
1.47k
                      host.PreferredSize (),
4060
1.47k
                      host.CropFactor    ());
4061
  
4062
1.47k
  if (downScale != dng_point (1, 1))
4063
137
    {
4064
137
    SetIsPreview (true);
4065
137
    }
4066
  
4067
1.47k
  dng_point dstSize = info.DstSize (downScale);
4068
      
4069
1.47k
  fStage3Image.Reset (host.Make_dng_image (dng_rect (dstSize),
4070
1.47k
                       info.fColorPlanes,
4071
1.47k
                       stage2.PixelType ()));
4072
4073
1.47k
  if (srcPlane < 0 || srcPlane >= (int32) stage2.Planes ())
4074
1.46k
    {
4075
1.46k
    srcPlane = 0;
4076
1.46k
    }
4077
        
4078
1.47k
  info.Interpolate (host,
4079
1.47k
            *this,
4080
1.47k
            stage2,
4081
1.47k
            *fStage3Image.Get (),
4082
1.47k
            downScale,
4083
1.47k
            srcPlane);
4084
4085
1.47k
  }
4086
                     
4087
/*****************************************************************************/
4088
4089
// Interpolate and merge a multi-channel CFA image.
4090
4091
void dng_negative::DoMergeStage3 (dng_host &host)
4092
0
  {
4093
  
4094
  // The DNG SDK does not provide multi-channel CFA image merging code.
4095
  // It just grabs the first channel and uses that.
4096
  
4097
0
  DoInterpolateStage3 (host, 0);
4098
           
4099
  // Just grabbing the first channel would often result in the very
4100
  // bright image using the baseline exposure value.
4101
  
4102
0
  fStage3Gain = pow (2.0, BaselineExposure ());
4103
  
4104
0
  }
4105
                     
4106
/*****************************************************************************/
4107
4108
void dng_negative::DoBuildStage3 (dng_host &host,
4109
                  int32 srcPlane)
4110
13.2k
  {
4111
  
4112
  // If we don't have a mosaic pattern, then just move the stage 2
4113
  // image on to stage 3.
4114
  
4115
13.2k
  dng_mosaic_info *info = fMosaicInfo.Get ();
4116
4117
13.2k
  if (!info || !info->IsColorFilterArray ())
4118
11.8k
    {
4119
    
4120
11.8k
    fStage3Image.Reset (fStage2Image.Release ());
4121
    
4122
11.8k
    }
4123
    
4124
1.47k
  else
4125
1.47k
    {
4126
    
4127
    // Remember the size of the stage 2 image.
4128
    
4129
1.47k
    dng_point stage2_size = fStage2Image->Size ();
4130
    
4131
    // Special case multi-channel CFA interpolation.
4132
    
4133
1.47k
    if ((fStage2Image->Planes () > 1) && (srcPlane < 0))
4134
0
      {
4135
      
4136
0
      DoMergeStage3 (host);
4137
      
4138
0
      }
4139
      
4140
    // Else do a single channel interpolation.
4141
    
4142
1.47k
    else
4143
1.47k
      {
4144
        
4145
1.47k
      DoInterpolateStage3 (host, srcPlane);
4146
               
4147
1.47k
      }
4148
    
4149
    // Calculate the ratio of the stage 3 image size to stage 2 image size.
4150
    
4151
1.47k
    dng_point stage3_size = fStage3Image->Size ();
4152
    
4153
1.47k
    fRawToFullScaleH = (real64) stage3_size.h / (real64) stage2_size.h;
4154
1.47k
    fRawToFullScaleV = (real64) stage3_size.v / (real64) stage2_size.v;
4155
    
4156
1.47k
    }
4157
4158
13.2k
  }
4159
                     
4160
/*****************************************************************************/
4161
4162
void dng_negative::BuildStage3Image (dng_host &host,
4163
                   int32 srcPlane)
4164
13.2k
  {
4165
  
4166
  // Finalize the mosaic information.
4167
  
4168
13.2k
  dng_mosaic_info *info = fMosaicInfo.Get ();
4169
  
4170
13.2k
  if (info)
4171
7.76k
    {
4172
    
4173
7.76k
    info->PostParse (host, *this);
4174
    
4175
7.76k
    }
4176
    
4177
  // Do the interpolation as required.
4178
  
4179
13.2k
  DoBuildStage3 (host, srcPlane);
4180
  
4181
  // Delete the stage2 image now that we have computed the stage 3 image.
4182
  
4183
13.2k
  fStage2Image.Reset ();
4184
  
4185
  // Are we done with the mosaic info?
4186
  
4187
13.2k
  if (fRawImageStage >= rawImageStagePreOpcode3)
4188
7.06k
    {
4189
    
4190
7.06k
    ClearMosaicInfo ();
4191
    
4192
    // To support saving linear DNG files, to need to account for
4193
    // and upscaling during interpolation.
4194
4195
7.06k
    if (fRawToFullScaleH > 1.0)
4196
16
      {
4197
      
4198
16
      uint32 adjust = Round_uint32 (fRawToFullScaleH);
4199
      
4200
16
      fDefaultCropSizeH  .n =
4201
16
        SafeUint32Mult (fDefaultCropSizeH.n, adjust);
4202
16
      fDefaultCropOriginH.n =
4203
16
        SafeUint32Mult (fDefaultCropOriginH.n, adjust);
4204
16
      fDefaultScaleH     .d = SafeUint32Mult (fDefaultScaleH.d, adjust);
4205
      
4206
16
      fRawToFullScaleH /= (real64) adjust;
4207
      
4208
16
      }
4209
    
4210
7.06k
    if (fRawToFullScaleV > 1.0)
4211
15
      {
4212
      
4213
15
      uint32 adjust = Round_uint32 (fRawToFullScaleV);
4214
      
4215
15
      fDefaultCropSizeV  .n =
4216
15
        SafeUint32Mult (fDefaultCropSizeV.n, adjust);
4217
15
      fDefaultCropOriginV.n =
4218
15
        SafeUint32Mult (fDefaultCropOriginV.n, adjust);
4219
15
      fDefaultScaleV     .d =
4220
15
        SafeUint32Mult (fDefaultScaleV.d, adjust);
4221
      
4222
15
      fRawToFullScaleV /= (real64) adjust;
4223
      
4224
15
      }
4225
4226
7.06k
    }
4227
    
4228
  // Resample the transparency mask if required.
4229
  
4230
13.2k
  ResizeTransparencyToMatchStage3 (host);
4231
      
4232
  // Grab clone of raw image if required.
4233
  
4234
13.2k
  if (fRawImageStage == rawImageStagePreOpcode3)
4235
4.14k
    {
4236
    
4237
4.14k
    fRawImage.Reset (fStage3Image->Clone ());
4238
    
4239
4.14k
    if (fTransparencyMask.Get ())
4240
0
      {
4241
0
      fRawTransparencyMask.Reset (fTransparencyMask->Clone ());
4242
0
      }
4243
4244
4.14k
    }
4245
    
4246
  // Process opcode list 3.
4247
  
4248
13.2k
  host.ApplyOpcodeList (fOpcodeList3, *this, fStage3Image);
4249
  
4250
  // See if we are done with the opcode list 3.
4251
  
4252
13.2k
  if (fRawImageStage > rawImageStagePreOpcode3)
4253
2.85k
    {
4254
    
4255
2.85k
    fOpcodeList3.Clear ();
4256
    
4257
2.85k
    }
4258
    
4259
  // Just in case the opcode list 3 changed the image size, resample the
4260
  // transparency mask again if required.  This is nearly always going
4261
  // to be a fast NOP operation.
4262
  
4263
13.2k
  ResizeTransparencyToMatchStage3 (host);
4264
 
4265
  // Don't need to grab a copy of raw data at this stage since
4266
  // it is kept around as the stage 3 image.
4267
  
4268
13.2k
  }
4269
    
4270
/******************************************************************************/
4271
4272
class dng_gamma_encode_proxy : public dng_1d_function
4273
  {
4274
  
4275
  private:
4276
  
4277
    real64 fBlack;
4278
    real64 fWhite;
4279
    
4280
    bool fIsSceneReferred;
4281
    
4282
    real64 scale;
4283
    real64 t1;
4284
    
4285
  public:
4286
    
4287
    dng_gamma_encode_proxy (real64 black,
4288
                  real64 white,
4289
                  bool isSceneReferred)
4290
                 
4291
6.34k
      : fBlack (black)
4292
6.34k
      , fWhite (white)
4293
6.34k
      , fIsSceneReferred (isSceneReferred)
4294
      
4295
6.34k
      , scale (1.0 / (fWhite - fBlack))
4296
6.34k
      , t1 (1.0 / (27.0 * pow (5.0, 3.0 / 2.0)))
4297
      
4298
6.34k
      {
4299
6.34k
      }
4300
      
4301
    virtual real64 Evaluate (real64 x) const
4302
26.0M
      {
4303
      
4304
26.0M
      x = Pin_real64 (0.0, (x - fBlack) * scale, 1.0);
4305
      
4306
26.0M
      real64 y;
4307
      
4308
26.0M
      if (fIsSceneReferred)
4309
20.8M
        {
4310
      
4311
20.8M
        real64 t = pow (sqrt (25920.0 * x * x + 1.0) * t1 + x * (8.0 / 15.0), 1.0 / 3.0);
4312
        
4313
20.8M
        y = t - 1.0 / (45.0 * t);
4314
        
4315
20.8M
        DNG_ASSERT (Abs_real64 (x - (y / 16.0 + y * y * y * 15.0 / 16.0)) < 0.0000001,
4316
20.8M
              "Round trip error");
4317
              
4318
20.8M
        }
4319
        
4320
5.12M
      else
4321
5.12M
        {
4322
        
4323
5.12M
        y = (sqrt (960.0 * x + 1.0) - 1.0) / 30.0;
4324
        
4325
5.12M
        DNG_ASSERT (Abs_real64 (x - (y / 16.0 + y * y * (15.0 / 16.0))) < 0.0000001,
4326
5.12M
              "Round trip error");
4327
              
4328
5.12M
        }
4329
        
4330
26.0M
      return y;
4331
      
4332
26.0M
      }
4333
  
4334
  };
4335
4336
/*****************************************************************************/
4337
4338
class dng_encode_proxy_task: public dng_area_task
4339
  {
4340
  
4341
  private:
4342
  
4343
    const dng_image &fSrcImage;
4344
    
4345
    dng_image &fDstImage;
4346
    
4347
    AutoPtr<dng_memory_block> fTable16 [kMaxColorPlanes];
4348
      
4349
  public:
4350
  
4351
    dng_encode_proxy_task (dng_host &host,
4352
                 const dng_image &srcImage,
4353
                 dng_image &dstImage,
4354
                 const real64 *black,
4355
                 const real64 *white,
4356
                 bool isSceneReferred);
4357
               
4358
    virtual dng_rect RepeatingTile1 () const
4359
7.87k
      {
4360
7.87k
      return fSrcImage.RepeatingTile ();
4361
7.87k
      }
4362
      
4363
    virtual dng_rect RepeatingTile2 () const
4364
7.87k
      {
4365
7.87k
      return fDstImage.RepeatingTile ();
4366
7.87k
      }
4367
      
4368
    virtual void Process (uint32 threadIndex,
4369
                const dng_rect &tile,
4370
                dng_abort_sniffer *sniffer);
4371
                  
4372
  private:
4373
  
4374
    // Hidden copy constructor and assignment operator.
4375
  
4376
    dng_encode_proxy_task (const dng_encode_proxy_task &task);
4377
    
4378
    dng_encode_proxy_task & operator= (const dng_encode_proxy_task &task);
4379
  
4380
  };
4381
4382
/*****************************************************************************/
4383
4384
dng_encode_proxy_task::dng_encode_proxy_task (dng_host &host,
4385
                        const dng_image &srcImage,
4386
                          dng_image &dstImage,
4387
                          const real64 *black,
4388
                          const real64 *white,
4389
                          bool isSceneReferred)
4390
                    
4391
3.93k
  : fSrcImage (srcImage)
4392
3.93k
  , fDstImage (dstImage)
4393
  
4394
3.93k
  {
4395
  
4396
10.2k
  for (uint32 plane = 0; plane < fSrcImage.Planes (); plane++)
4397
6.34k
    {
4398
    
4399
6.34k
    dng_gamma_encode_proxy gamma (black [plane],
4400
6.34k
                    white [plane],
4401
6.34k
                    isSceneReferred);
4402
                    
4403
6.34k
    dng_1d_table table32;
4404
    
4405
6.34k
    table32.Initialize (host.Allocator (), gamma);
4406
    
4407
6.34k
    fTable16 [plane] . Reset (host.Allocate (0x10000 * sizeof (uint16)));
4408
    
4409
6.34k
    table32.Expand16 (fTable16 [plane]->Buffer_uint16 ());
4410
                     
4411
6.34k
    }
4412
    
4413
3.93k
  }
4414
4415
/*****************************************************************************/
4416
4417
void dng_encode_proxy_task::Process (uint32 /* threadIndex */,
4418
                     const dng_rect &tile,
4419
                       dng_abort_sniffer * /* sniffer */)
4420
48.6k
  {
4421
  
4422
48.6k
  dng_const_tile_buffer srcBuffer (fSrcImage, tile);
4423
48.6k
  dng_dirty_tile_buffer dstBuffer (fDstImage, tile);
4424
  
4425
48.6k
  int32 sColStep = srcBuffer.fColStep;
4426
48.6k
  int32 dColStep = dstBuffer.fColStep;
4427
  
4428
48.6k
  const uint16 *noise = dng_dither::Get ().NoiseBuffer16 ();
4429
  
4430
130k
  for (uint32 plane = 0; plane < fSrcImage.Planes (); plane++)
4431
82.2k
    {
4432
    
4433
82.2k
    const uint16 *map = fTable16 [plane]->Buffer_uint16 ();
4434
    
4435
8.41M
    for (int32 row = tile.t; row < tile.b; row++)
4436
8.33M
      {
4437
      
4438
8.33M
      const uint16 *sPtr = srcBuffer.ConstPixel_uint16 (row, tile.l, plane);
4439
      
4440
8.33M
      uint8 *dPtr = dstBuffer.DirtyPixel_uint8 (row, tile.l, plane);
4441
      
4442
8.33M
      const uint16 *rPtr = &noise [(row & dng_dither::kRNGMask) * dng_dither::kRNGSize];
4443
4444
1.17G
      for (int32 col = tile.l; col < tile.r; col++)
4445
1.16G
        {
4446
        
4447
1.16G
        uint32 x = *sPtr;
4448
        
4449
1.16G
        uint32 r = rPtr [col & dng_dither::kRNGMask];
4450
        
4451
1.16G
        x = map [x];
4452
        
4453
1.16G
        x = (((x << 8) - x) + r) >> 16;
4454
        
4455
1.16G
        *dPtr = (uint8) x;
4456
        
4457
1.16G
        sPtr += sColStep;
4458
1.16G
        dPtr += dColStep;
4459
        
4460
1.16G
        }
4461
      
4462
8.33M
      }
4463
      
4464
82.2k
    }
4465
    
4466
48.6k
  }
4467
                  
4468
/******************************************************************************/
4469
4470
dng_image * dng_negative::EncodeRawProxy (dng_host &host,
4471
                      const dng_image &srcImage,
4472
                      dng_opcode_list &opcodeList) const
4473
4.26k
  {
4474
  
4475
4.26k
  if (srcImage.PixelType () != ttShort)
4476
0
    {
4477
0
    return NULL;
4478
0
    }
4479
    
4480
4.26k
  real64 black [kMaxColorPlanes];
4481
4.26k
  real64 white [kMaxColorPlanes];
4482
  
4483
4.26k
  bool isSceneReferred = (ColorimetricReference () == crSceneReferred);
4484
  
4485
4.26k
    {
4486
    
4487
4.26k
    const real64 kClipFraction = 0.00001;
4488
  
4489
4.26k
    uint64 pixels = (uint64) srcImage.Bounds ().H () *
4490
4.26k
            (uint64) srcImage.Bounds ().W ();
4491
            
4492
4.26k
    uint32 limit = Round_int32 ((real64) pixels * kClipFraction);
4493
    
4494
4.26k
    AutoPtr<dng_memory_block> histData (host.Allocate (65536 * sizeof (uint32)));
4495
    
4496
4.26k
    uint32 *hist = histData->Buffer_uint32 ();
4497
      
4498
11.5k
    for (uint32 plane = 0; plane < srcImage.Planes (); plane++)
4499
7.32k
      {
4500
      
4501
7.32k
      HistogramArea (host,
4502
7.32k
               srcImage,
4503
7.32k
               srcImage.Bounds (),
4504
7.32k
               hist,
4505
7.32k
               65535,
4506
7.32k
               plane);
4507
               
4508
7.32k
      uint32 total = 0;
4509
4510
7.32k
      uint32 upper = 65535;
4511
4512
187M
      while (total + hist [upper] <= limit && upper > 255)
4513
187M
        {
4514
        
4515
187M
        total += hist [upper];
4516
        
4517
187M
        upper--;
4518
        
4519
187M
        }
4520
  
4521
7.32k
      total = 0;
4522
      
4523
7.32k
      uint32 lower = 0;
4524
      
4525
45.9M
      while (total + hist [lower] <= limit && lower < upper - 255)
4526
45.9M
        {
4527
        
4528
45.9M
        total += hist [lower];
4529
        
4530
45.9M
        lower++;
4531
        
4532
45.9M
        }
4533
      
4534
7.32k
      black [plane] = lower / 65535.0;
4535
7.32k
      white [plane] = upper / 65535.0;
4536
    
4537
7.32k
      }
4538
      
4539
4.26k
    }
4540
    
4541
  // Apply the gamma encoding, using dither when downsampling to 8-bit.
4542
  
4543
4.26k
  AutoPtr<dng_image> dstImage (host.Make_dng_image (srcImage.Bounds (),
4544
4.26k
                            srcImage.Planes (),
4545
4.26k
                            ttByte));
4546
4547
4.26k
    {
4548
    
4549
4.26k
    dng_encode_proxy_task task (host,
4550
4.26k
                      srcImage,
4551
4.26k
                  *dstImage,
4552
4.26k
                  black,
4553
4.26k
                  white,
4554
4.26k
                  isSceneReferred);
4555
    
4556
4.26k
    host.PerformAreaTask (task,
4557
4.26k
                srcImage.Bounds ());
4558
  
4559
4.26k
    }
4560
          
4561
  // Add opcodes to undo the gamma encoding.
4562
  
4563
4.26k
    {
4564
  
4565
10.6k
    for (uint32 plane = 0; plane < srcImage.Planes (); plane++)
4566
6.34k
      {
4567
      
4568
6.34k
      dng_area_spec areaSpec (srcImage.Bounds (),
4569
6.34k
                  plane);
4570
      
4571
6.34k
      real64 coefficient [4];
4572
      
4573
6.34k
      coefficient [0] = 0.0;
4574
6.34k
      coefficient [1] = 1.0 / 16.0;
4575
      
4576
6.34k
      if (isSceneReferred)
4577
5.09k
        {
4578
5.09k
        coefficient [2] = 0.0;
4579
5.09k
        coefficient [3] = 15.0 / 16.0;
4580
5.09k
        }
4581
1.25k
      else
4582
1.25k
        {
4583
1.25k
        coefficient [2] = 15.0 / 16.0;
4584
1.25k
        coefficient [3] = 0.0;
4585
1.25k
        }
4586
      
4587
6.34k
      coefficient [0] *= white [plane] - black [plane];
4588
6.34k
      coefficient [1] *= white [plane] - black [plane];
4589
6.34k
      coefficient [2] *= white [plane] - black [plane];
4590
6.34k
      coefficient [3] *= white [plane] - black [plane];
4591
      
4592
6.34k
      coefficient [0] += black [plane];
4593
      
4594
6.34k
      AutoPtr<dng_opcode> opcode (new dng_opcode_MapPolynomial (areaSpec,
4595
6.34k
                                    isSceneReferred ? 3 : 2,
4596
6.34k
                                    coefficient));
4597
                                    
4598
6.34k
      opcodeList.Append (opcode);
4599
      
4600
6.34k
      }
4601
      
4602
4.26k
    }
4603
    
4604
4.26k
  return dstImage.Release ();
4605
  
4606
4.26k
  }
4607
                    
4608
/******************************************************************************/
4609
4610
void dng_negative::AdjustProfileForStage3 ()
4611
6.85k
  {
4612
4613
  // For dng_sdk, the stage3 image's color space is always the same as the
4614
  // raw image's color space.
4615
  
4616
6.85k
  }
4617
                    
4618
/******************************************************************************/
4619
4620
void dng_negative::ConvertToProxy (dng_host &host,
4621
                   dng_image_writer &writer,
4622
                   uint32 proxySize,
4623
                   uint64 proxyCount)
4624
6.99k
  {
4625
  
4626
6.99k
  if (!proxySize)
4627
0
    {
4628
0
    proxySize = kMaxImageSide;
4629
0
    }
4630
  
4631
6.99k
  if (!proxyCount)
4632
6.99k
    {
4633
6.99k
    proxyCount = (uint64) proxySize * proxySize;
4634
6.99k
    }
4635
  
4636
  // Don't need to private data around in non-full size proxies.
4637
  
4638
6.99k
  if (proxySize  < kMaxImageSide ||
4639
1.96k
    proxyCount < kMaxImageSide * kMaxImageSide)
4640
5.02k
    {
4641
  
4642
5.02k
    ClearMakerNote ();
4643
    
4644
5.02k
    ClearPrivateData ();
4645
    
4646
5.02k
    }
4647
  
4648
  // See if we already have an acceptable proxy image.
4649
  
4650
6.99k
  if (fRawImage.Get () &&
4651
5.53k
    fRawImage->PixelType () == ttByte &&
4652
1.33k
    fRawImage->Bounds () == DefaultCropArea () &&
4653
830
    fRawImage->Bounds ().H () <= proxySize &&
4654
537
    fRawImage->Bounds ().W () <= proxySize &&
4655
421
    (uint64) fRawImage->Bounds ().H () *
4656
421
    (uint64) fRawImage->Bounds ().W () <= proxyCount &&
4657
421
    (!GetMosaicInfo () || !GetMosaicInfo ()->IsColorFilterArray ()) &&
4658
400
    fRawJPEGImage.Get () &&
4659
1
    (!RawTransparencyMask () || RawTransparencyMask ()->PixelType () == ttByte))
4660
1
    {
4661
    
4662
1
    return;
4663
    
4664
1
    }
4665
    
4666
6.99k
  if (fRawImage.Get () &&
4667
5.53k
    fRawImage->PixelType () == ttFloat &&
4668
409
    fRawImage->Bounds ().H () <= proxySize &&
4669
349
    fRawImage->Bounds ().W () <= proxySize &&
4670
323
    (uint64) fRawImage->Bounds ().H () *
4671
323
    (uint64) fRawImage->Bounds ().W () <= proxyCount &&
4672
323
    RawFloatBitDepth () == 16 &&
4673
136
    (!RawTransparencyMask () || RawTransparencyMask ()->PixelType () == ttByte))
4674
136
    {
4675
    
4676
136
    return;
4677
    
4678
136
    }
4679
  
4680
  // Clear any grabbed raw image, since we are going to start
4681
  // building the proxy with the stage3 image.
4682
4683
6.85k
  fRawImage.Reset ();
4684
  
4685
6.85k
  ClearRawJPEGImage ();
4686
  
4687
6.85k
  SetRawFloatBitDepth (0);
4688
  
4689
6.85k
  ClearLinearizationInfo ();
4690
  
4691
6.85k
  ClearMosaicInfo ();
4692
  
4693
6.85k
  fOpcodeList1.Clear ();
4694
6.85k
  fOpcodeList2.Clear ();
4695
6.85k
  fOpcodeList3.Clear ();
4696
  
4697
  // Adjust the profile to match the stage 3 image, if required.
4698
  
4699
6.85k
  AdjustProfileForStage3 ();
4700
  
4701
  // Not saving the raw-most image, do the old raw digest is no
4702
  // longer valid.
4703
    
4704
6.85k
  ClearRawImageDigest ();
4705
  
4706
6.85k
  ClearRawJPEGImageDigest ();
4707
  
4708
  // Trim off extra pixels outside the default crop area.
4709
  
4710
6.85k
  dng_rect defaultCropArea = DefaultCropArea ();
4711
  
4712
6.85k
  if (Stage3Image ()->Bounds () != defaultCropArea)
4713
512
    {
4714
    
4715
512
    fStage3Image->Trim (defaultCropArea);
4716
    
4717
512
    if (fTransparencyMask.Get ())
4718
0
      {
4719
0
      fTransparencyMask->Trim (defaultCropArea);
4720
0
      }
4721
    
4722
512
    fDefaultCropOriginH = dng_urational (0, 1);
4723
512
    fDefaultCropOriginV = dng_urational (0, 1);
4724
    
4725
512
    }
4726
    
4727
  // Figure out the requested proxy pixel size.
4728
  
4729
6.85k
  real64 aspectRatio = AspectRatio ();
4730
  
4731
6.85k
  dng_point newSize (proxySize, proxySize);
4732
  
4733
6.85k
  if (aspectRatio >= 1.0)
4734
2.88k
    {
4735
2.88k
    newSize.v = Max_int32 (1, Round_int32 (proxySize / aspectRatio));
4736
2.88k
    }
4737
3.97k
  else
4738
3.97k
    {
4739
3.97k
    newSize.h = Max_int32 (1, Round_int32 (proxySize * aspectRatio));
4740
3.97k
    }
4741
    
4742
6.85k
  newSize.v = Min_int32 (newSize.v, DefaultFinalHeight ());
4743
6.85k
  newSize.h = Min_int32 (newSize.h, DefaultFinalWidth  ());
4744
  
4745
6.85k
  if ((uint64) newSize.v *
4746
6.85k
      (uint64) newSize.h > proxyCount)
4747
1.32k
    {
4748
4749
1.32k
    if (aspectRatio >= 1.0)
4750
709
      {
4751
      
4752
709
      newSize.h = (uint32) sqrt (proxyCount * aspectRatio);
4753
      
4754
709
      newSize.v = Max_int32 (1, Round_int32 (newSize.h / aspectRatio));
4755
      
4756
709
      }
4757
      
4758
617
    else
4759
617
      {
4760
      
4761
617
      newSize.v = (uint32) sqrt (proxyCount / aspectRatio);
4762
      
4763
617
      newSize.h = Max_int32 (1, Round_int32 (newSize.v * aspectRatio));
4764
                           
4765
617
      }
4766
                                 
4767
1.32k
    }
4768
    
4769
  // If this is fewer pixels, downsample the stage 3 image to that size.
4770
  
4771
6.85k
  dng_point oldSize = defaultCropArea.Size ();
4772
  
4773
6.85k
  if ((uint64) newSize.v * (uint64) newSize.h <
4774
6.85k
    (uint64) oldSize.v * (uint64) oldSize.h)
4775
1.91k
    {
4776
    
4777
1.91k
    const dng_image &srcImage (*Stage3Image ());
4778
    
4779
1.91k
    AutoPtr<dng_image> dstImage (host.Make_dng_image (newSize,
4780
1.91k
                              srcImage.Planes (),
4781
1.91k
                              srcImage.PixelType ()));
4782
                              
4783
1.91k
    host.ResampleImage (srcImage,
4784
1.91k
              *dstImage);
4785
                             
4786
1.91k
    fStage3Image.Reset (dstImage.Release ());
4787
    
4788
1.91k
    fDefaultCropSizeH = dng_urational (newSize.h, 1);
4789
1.91k
    fDefaultCropSizeV = dng_urational (newSize.v, 1);
4790
    
4791
1.91k
    fDefaultScaleH = dng_urational (1, 1);
4792
1.91k
    fDefaultScaleV = dng_urational (1, 1);
4793
    
4794
1.91k
    fBestQualityScale = dng_urational (1, 1);
4795
    
4796
1.91k
    fRawToFullScaleH = 1.0;
4797
1.91k
    fRawToFullScaleV = 1.0;
4798
    
4799
1.91k
    }
4800
    
4801
  // Convert 32-bit floating point images to 16-bit floating point to
4802
  // save space.
4803
  
4804
6.85k
  if (Stage3Image ()->PixelType () == ttFloat)
4805
2.49k
    {
4806
    
4807
2.49k
    fRawImage.Reset (host.Make_dng_image (Stage3Image ()->Bounds (),
4808
2.49k
                        Stage3Image ()->Planes (),
4809
2.49k
                        ttFloat));
4810
    
4811
2.49k
    LimitFloatBitDepth (host,
4812
2.49k
              *Stage3Image (),
4813
2.49k
              *fRawImage,
4814
2.49k
              16,
4815
2.49k
              32768.0f);
4816
    
4817
2.49k
    SetRawFloatBitDepth (16);
4818
    
4819
2.49k
    SetWhiteLevel (32768);
4820
    
4821
2.49k
    }
4822
    
4823
4.36k
  else
4824
4.36k
    {
4825
    
4826
    // Convert 16-bit deep images to 8-bit deep image for saving.
4827
    
4828
4.36k
    fRawImage.Reset (EncodeRawProxy (host,
4829
4.36k
                     *Stage3Image (),
4830
4.36k
                     fOpcodeList2));
4831
                     
4832
4.36k
    if (fRawImage.Get ())
4833
3.93k
      {
4834
      
4835
3.93k
      SetWhiteLevel (255);
4836
      
4837
      // Compute JPEG compressed version.
4838
      
4839
3.93k
      if (fRawImage->PixelType () == ttByte &&
4840
3.93k
        host.SaveDNGVersion () >= dngVersion_1_4_0_0)
4841
3.25k
        {
4842
      
4843
3.25k
        AutoPtr<dng_jpeg_image> jpegImage (new dng_jpeg_image);
4844
        
4845
3.25k
        jpegImage->Encode (host,
4846
3.25k
                   *this,
4847
3.25k
                   writer,
4848
3.25k
                   *fRawImage);
4849
                   
4850
3.25k
        SetRawJPEGImage (jpegImage);
4851
                   
4852
3.25k
        }
4853
      
4854
3.93k
      }
4855
      
4856
4.36k
    }
4857
    
4858
  // Deal with transparency mask.
4859
  
4860
6.85k
  if (TransparencyMask ())
4861
0
    {
4862
    
4863
0
    const bool convertTo8Bit = true;
4864
    
4865
0
    ResizeTransparencyToMatchStage3 (host, convertTo8Bit);
4866
    
4867
0
    fRawTransparencyMask.Reset (fTransparencyMask->Clone ());
4868
    
4869
0
    }
4870
    
4871
  // Recompute the raw data unique ID, since we changed the image data.
4872
  
4873
6.85k
  RecomputeRawDataUniqueID (host);
4874
      
4875
6.85k
  }
4876
4877
/*****************************************************************************/
4878
4879
dng_linearization_info * dng_negative::MakeLinearizationInfo ()
4880
34.5k
  {
4881
  
4882
34.5k
  dng_linearization_info *info = new dng_linearization_info ();
4883
  
4884
34.5k
  if (!info)
4885
0
    {
4886
0
    ThrowMemoryFull ();
4887
0
    }
4888
    
4889
34.5k
  return info;
4890
  
4891
34.5k
  }
4892
4893
/*****************************************************************************/
4894
4895
void dng_negative::NeedLinearizationInfo ()
4896
48.6k
  {
4897
  
4898
48.6k
  if (!fLinearizationInfo.Get ())
4899
34.5k
    {
4900
  
4901
34.5k
    fLinearizationInfo.Reset (MakeLinearizationInfo ());
4902
    
4903
34.5k
    }
4904
  
4905
48.6k
  }
4906
4907
/*****************************************************************************/
4908
4909
dng_mosaic_info * dng_negative::MakeMosaicInfo ()
4910
8.73k
  {
4911
  
4912
8.73k
  dng_mosaic_info *info = new dng_mosaic_info ();
4913
  
4914
8.73k
  if (!info)
4915
0
    {
4916
0
    ThrowMemoryFull ();
4917
0
    }
4918
    
4919
8.73k
  return info;
4920
  
4921
8.73k
  }
4922
4923
/*****************************************************************************/
4924
4925
void dng_negative::NeedMosaicInfo ()
4926
8.87k
  {
4927
  
4928
8.87k
  if (!fMosaicInfo.Get ())
4929
8.73k
    {
4930
  
4931
8.73k
    fMosaicInfo.Reset (MakeMosaicInfo ());
4932
    
4933
8.73k
    }
4934
  
4935
8.87k
  }
4936
4937
/*****************************************************************************/
4938
4939
void dng_negative::SetTransparencyMask (AutoPtr<dng_image> &image,
4940
                    uint32 bitDepth)
4941
0
  {
4942
  
4943
0
  fTransparencyMask.Reset (image.Release ());
4944
  
4945
0
  fRawTransparencyMaskBitDepth = bitDepth;
4946
  
4947
0
  }
4948
4949
/*****************************************************************************/
4950
4951
const dng_image * dng_negative::TransparencyMask () const
4952
84.4k
  {
4953
  
4954
84.4k
  return fTransparencyMask.Get ();
4955
  
4956
84.4k
  }
4957
4958
/*****************************************************************************/
4959
4960
const dng_image * dng_negative::RawTransparencyMask () const
4961
27.5k
  {
4962
  
4963
27.5k
  if (fRawTransparencyMask.Get ())
4964
0
    {
4965
    
4966
0
    return fRawTransparencyMask.Get ();
4967
    
4968
0
    }
4969
    
4970
27.5k
  return TransparencyMask ();
4971
  
4972
27.5k
  }
4973
4974
/*****************************************************************************/
4975
4976
uint32 dng_negative::RawTransparencyMaskBitDepth () const
4977
0
  {
4978
  
4979
0
  if (fRawTransparencyMaskBitDepth)
4980
0
    {
4981
  
4982
0
    return fRawTransparencyMaskBitDepth;
4983
    
4984
0
    }
4985
    
4986
0
  const dng_image *mask = RawTransparencyMask ();
4987
  
4988
0
  if (mask)
4989
0
    {
4990
    
4991
0
    switch (mask->PixelType ())
4992
0
      {
4993
      
4994
0
      case ttByte:
4995
0
        return 8;
4996
        
4997
0
      case ttShort:
4998
0
        return 16;
4999
        
5000
0
      case ttFloat:
5001
0
        return 32;
5002
        
5003
0
      default:
5004
0
        ThrowProgramError ();
5005
        
5006
0
      }
5007
    
5008
0
    }
5009
    
5010
0
  return 0;
5011
  
5012
0
  }
5013
                    
5014
/*****************************************************************************/
5015
5016
void dng_negative::ReadTransparencyMask (dng_host &host,
5017
                       dng_stream &stream,
5018
                       dng_info &info)
5019
0
  {
5020
  
5021
0
  if (info.fMaskIndex != -1)
5022
0
    {
5023
  
5024
    // Allocate image we are reading.
5025
    
5026
0
    dng_ifd &maskIFD = *info.fIFD [info.fMaskIndex].Get ();
5027
    
5028
0
    fTransparencyMask.Reset (host.Make_dng_image (maskIFD.Bounds (),
5029
0
                            1,
5030
0
                            maskIFD.PixelType ()));
5031
            
5032
    // Read the image.
5033
    
5034
0
    maskIFD.ReadImage (host,
5035
0
               stream,
5036
0
               *fTransparencyMask.Get ());
5037
               
5038
    // Remember the pixel depth.
5039
    
5040
0
    fRawTransparencyMaskBitDepth = maskIFD.fBitsPerSample [0];
5041
               
5042
0
    }
5043
5044
0
  }
5045
5046
/*****************************************************************************/
5047
5048
void dng_negative::ResizeTransparencyToMatchStage3 (dng_host &host,
5049
                          bool convertTo8Bit)
5050
26.4k
  {
5051
  
5052
26.4k
  if (TransparencyMask ())
5053
0
    {
5054
    
5055
0
    if ((TransparencyMask ()->Bounds () != fStage3Image->Bounds ()) ||
5056
0
      (TransparencyMask ()->PixelType () != ttByte && convertTo8Bit))
5057
0
      {
5058
      
5059
0
      AutoPtr<dng_image> newMask (host.Make_dng_image (fStage3Image->Bounds (),
5060
0
                               1,
5061
0
                               convertTo8Bit ?
5062
0
                               ttByte :
5063
0
                               TransparencyMask ()->PixelType ()));
5064
                  
5065
0
      host.ResampleImage (*TransparencyMask (),
5066
0
                *newMask);
5067
               
5068
0
      fTransparencyMask.Reset (newMask.Release ());
5069
      
5070
0
      if (!fRawTransparencyMask.Get ())
5071
0
        {
5072
0
        fRawTransparencyMaskBitDepth = 0;
5073
0
        }
5074
      
5075
0
      }
5076
      
5077
0
    }
5078
    
5079
26.4k
  }
5080
5081
/*****************************************************************************/
5082
5083
bool dng_negative::NeedFlattenTransparency (dng_host & /* host */)
5084
12.6k
  {
5085
  
5086
12.6k
  if (TransparencyMask ())
5087
0
    {
5088
    
5089
0
    return true;
5090
  
5091
0
    }
5092
  
5093
12.6k
  return false;
5094
    
5095
12.6k
  }
5096
                    
5097
/*****************************************************************************/
5098
5099
void dng_negative::FlattenTransparency (dng_host & /* host */)
5100
0
  {
5101
  
5102
0
  ThrowNotYetImplemented ();
5103
  
5104
0
  }
5105
                    
5106
/*****************************************************************************/
5107
5108
const dng_image * dng_negative::UnflattenedStage3Image () const
5109
0
  {
5110
  
5111
0
  if (fUnflattenedStage3Image.Get ())
5112
0
    {
5113
    
5114
0
    return fUnflattenedStage3Image.Get ();
5115
    
5116
0
    }
5117
    
5118
0
  return fStage3Image.Get ();
5119
    
5120
0
  }
5121
5122
/*****************************************************************************/