Coverage Report

Created: 2025-01-23 06:29

/src/dng_sdk/source/dng_negative.cpp
Line
Count
Source (jump to first uncovered line)
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
19.9k
  : fNoiseFunctions ()
56
57
19.9k
  {
58
  
59
19.9k
  }
60
61
/*****************************************************************************/
62
63
dng_noise_profile::dng_noise_profile (const dng_std_vector<dng_noise_function> &functions)
64
65
465
  : fNoiseFunctions (functions)
66
67
465
  {
68
69
465
  }
70
71
/*****************************************************************************/
72
73
bool dng_noise_profile::IsValid () const
74
5.60k
  {
75
76
5.60k
  if (NumFunctions () == 0 || NumFunctions () > kMaxColorPlanes)
77
5.59k
    {
78
5.59k
    return false;
79
5.59k
    }
80
  
81
41
  for (uint32 plane = 0; plane < NumFunctions (); plane++)
82
34
    {
83
    
84
34
    if (!NoiseFunction (plane).IsValid ())
85
5
      {
86
5
      return false;
87
5
      }
88
    
89
34
    }
90
91
7
  return true;
92
  
93
12
  }
94
95
/*****************************************************************************/
96
97
bool dng_noise_profile::IsValidForNegative (const dng_negative &negative) const
98
2.07k
  {
99
  
100
2.07k
  if (!(NumFunctions () == 1 || NumFunctions () == negative.ColorChannels ()))
101
2.06k
    {
102
2.06k
    return false;
103
2.06k
    }
104
105
1
  return IsValid ();
106
107
2.07k
  }
108
109
/*****************************************************************************/
110
111
const dng_noise_function & dng_noise_profile::NoiseFunction (uint32 plane) const
112
54
  {
113
  
114
54
  if (NumFunctions () == 1)
115
0
    {
116
0
    return fNoiseFunctions.front ();
117
0
    }
118
119
54
  DNG_REQUIRE (plane < NumFunctions (), 
120
54
         "Bad plane index argument for NoiseFunction ().");
121
122
54
  return fNoiseFunctions [plane];
123
  
124
54
  }
125
126
/*****************************************************************************/
127
128
uint32 dng_noise_profile::NumFunctions () const
129
21.7k
  {
130
21.7k
  return (uint32) fNoiseFunctions.size ();
131
21.7k
  }
132
133
/*****************************************************************************/
134
135
dng_metadata::dng_metadata (dng_host &host)
136
137
3.65k
  : fHasBaseOrientation     (false)
138
3.65k
  , fBaseOrientation        ()
139
3.65k
  , fIsMakerNoteSafe      (false)
140
3.65k
  , fMakerNote          ()
141
3.65k
  , fExif             (host.Make_dng_exif ())
142
3.65k
  , fOriginalExif       ()
143
3.65k
  , fIPTCBlock              ()
144
3.65k
  , fIPTCOffset         (kDNGStreamInvalidOffset)
145
  
146
  #if qDNGUseXMP
147
  
148
  , fXMP              (host.Make_dng_xmp ())
149
  
150
  #endif
151
  
152
3.65k
  , fEmbeddedXMPDigest        ()
153
3.65k
  , fXMPinSidecar         (false)
154
3.65k
  , fXMPisNewer           (false)
155
3.65k
  , fSourceMIMI         ()
156
157
3.65k
  {
158
3.65k
  }
159
160
/*****************************************************************************/
161
162
dng_metadata::~dng_metadata ()
163
7.66k
  {
164
7.66k
  }
165
  
166
/******************************************************************************/
167
168
template< class T >
169
T * CloneAutoPtr (const AutoPtr< T > &ptr)
170
8.02k
  {
171
  
172
8.02k
  return ptr.Get () ? ptr->Clone () : NULL;
173
  
174
8.02k
  }
175
176
/******************************************************************************/
177
178
template< class T, typename U >
179
T * CloneAutoPtr (const AutoPtr< T > &ptr, U &u)
180
8.02k
  {
181
  
182
8.02k
  return ptr.Get () ? ptr->Clone (u) : NULL;
183
  
184
8.02k
  }
185
186
/******************************************************************************/
187
188
dng_metadata::dng_metadata (const dng_metadata &rhs,
189
              dng_memory_allocator &allocator)
190
191
4.01k
  : fHasBaseOrientation     (rhs.fHasBaseOrientation)
192
4.01k
  , fBaseOrientation        (rhs.fBaseOrientation)
193
4.01k
  , fIsMakerNoteSafe      (rhs.fIsMakerNoteSafe)
194
4.01k
  , fMakerNote          (CloneAutoPtr (rhs.fMakerNote, allocator))
195
4.01k
  , fExif             (CloneAutoPtr (rhs.fExif))
196
4.01k
  , fOriginalExif       (CloneAutoPtr (rhs.fOriginalExif))
197
4.01k
  , fIPTCBlock              (CloneAutoPtr (rhs.fIPTCBlock, allocator))
198
4.01k
  , fIPTCOffset         (rhs.fIPTCOffset)
199
  
200
  #if qDNGUseXMP
201
  
202
  , fXMP              (CloneAutoPtr (rhs.fXMP))
203
  
204
  #endif
205
  
206
4.01k
  , fEmbeddedXMPDigest        (rhs.fEmbeddedXMPDigest)
207
4.01k
  , fXMPinSidecar         (rhs.fXMPinSidecar)
208
4.01k
  , fXMPisNewer           (rhs.fXMPisNewer)
209
4.01k
  , fSourceMIMI         (rhs.fSourceMIMI)
210
211
4.01k
  {
212
213
4.01k
  }
214
215
/******************************************************************************/
216
217
dng_metadata * dng_metadata::Clone (dng_memory_allocator &allocator) const
218
4.01k
  {
219
  
220
4.01k
  return new dng_metadata (*this, allocator);
221
  
222
4.01k
  }
223
224
/******************************************************************************/
225
226
void dng_metadata::SetBaseOrientation (const dng_orientation &orientation)
227
1.23k
  {
228
  
229
1.23k
  fHasBaseOrientation = true;
230
  
231
1.23k
  fBaseOrientation = orientation;
232
  
233
1.23k
  }
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
3.62k
  {
254
255
3.62k
  fExif.Reset (newExif);
256
257
3.62k
  }
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
47
  {
406
  
407
47
  fIPTCBlock.Reset (block.Release ());
408
  
409
47
  fIPTCOffset = offset;
410
  
411
47
  }
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
1.98k
  {
437
  
438
1.98k
  if (fIPTCBlock.Get ())
439
82
    {
440
    
441
82
    return fIPTCBlock->Buffer ();
442
    
443
82
    }
444
    
445
1.90k
  return NULL;
446
  
447
1.98k
  }
448
449
/*****************************************************************************/
450
451
uint32 dng_metadata::IPTCLength () const
452
3.96k
  {
453
  
454
3.96k
  if (fIPTCBlock.Get ())
455
164
    {
456
    
457
164
    return fIPTCBlock->LogicalSize ();
458
    
459
164
    }
460
    
461
3.80k
  return 0;
462
  
463
3.96k
  }
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
41
  {
485
  
486
41
  if (IPTCLength ())
487
41
    {
488
    
489
41
    dng_md5_printer printer;
490
    
491
41
    const uint8 *data = (const uint8 *) IPTCData ();
492
    
493
41
    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
41
    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
41
    printer.Process (data, count);
516
             
517
41
    return printer.Result ();
518
      
519
41
    }
520
  
521
0
  return dng_fingerprint ();
522
  
523
41
  }
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
2.32k
  {
661
  
662
2.32k
  if (!fOriginalExif.Get ())
663
2.32k
    {
664
    
665
2.32k
    fOriginalExif.Reset (fExif->Clone ());
666
    
667
2.32k
    }
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
2.32k
  }
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
3.65k
  : fAllocator            (host.Allocator ())
735
  
736
3.65k
  , fModelName            ()
737
3.65k
  , fLocalName            ()
738
3.65k
  , fDefaultCropSizeH       ()
739
3.65k
  , fDefaultCropSizeV       ()
740
3.65k
  , fDefaultCropOriginH       (0, 1)
741
3.65k
  , fDefaultCropOriginV       (0, 1)
742
3.65k
  , fDefaultUserCropT       (0, 1)
743
3.65k
  , fDefaultUserCropL       (0, 1)
744
3.65k
  , fDefaultUserCropB       (1, 1)
745
3.65k
  , fDefaultUserCropR       (1, 1)
746
3.65k
  , fDefaultScaleH          (1, 1)
747
3.65k
  , fDefaultScaleV          (1, 1)
748
3.65k
  , fBestQualityScale       (1, 1)
749
3.65k
  , fOriginalDefaultFinalSize   ()
750
3.65k
  , fOriginalBestQualityFinalSize ()
751
3.65k
  , fOriginalDefaultCropSizeH     ()
752
3.65k
  , fOriginalDefaultCropSizeV     ()
753
3.65k
  , fRawToFullScaleH        (1.0)
754
3.65k
  , fRawToFullScaleV        (1.0)
755
3.65k
  , fBaselineNoise          (100, 100)
756
3.65k
  , fNoiseReductionApplied      (0, 0)
757
3.65k
  , fNoiseProfile         ()
758
3.65k
  , fBaselineExposure       (  0, 100)
759
3.65k
  , fBaselineSharpness        (100, 100)
760
3.65k
  , fChromaBlurRadius       ()
761
3.65k
  , fAntiAliasStrength        (100, 100)
762
3.65k
  , fLinearResponseLimit      (100, 100)
763
3.65k
  , fShadowScale          (1, 1)
764
3.65k
  , fColorimetricReference      (crSceneReferred)
765
3.65k
  , fColorChannels          (0)
766
3.65k
  , fAnalogBalance          ()
767
3.65k
  , fCameraNeutral          ()
768
3.65k
  , fCameraWhiteXY          ()
769
3.65k
  , fCameraCalibration1       ()
770
3.65k
  , fCameraCalibration2       ()
771
3.65k
  , fCameraCalibrationSignature   ()
772
3.65k
  , fCameraProfile          ()
773
3.65k
  , fAsShotProfileName        ()
774
3.65k
  , fRawImageDigest         ()
775
3.65k
  , fNewRawImageDigest        ()
776
3.65k
  , fRawDataUniqueID        ()
777
3.65k
  , fOriginalRawFileName      ()
778
3.65k
  , fHasOriginalRawFileData     (false)
779
3.65k
  , fOriginalRawFileData      ()
780
3.65k
  , fOriginalRawFileDigest      ()
781
3.65k
  , fDNGPrivateData         ()
782
3.65k
  , fMetadata           (host)
783
3.65k
  , fLinearizationInfo        ()
784
3.65k
  , fMosaicInfo           ()
785
3.65k
  , fOpcodeList1          (1)
786
3.65k
  , fOpcodeList2          (2)
787
3.65k
  , fOpcodeList3          (3)
788
3.65k
  , fStage1Image          ()
789
3.65k
  , fStage2Image          ()
790
3.65k
  , fStage3Image          ()
791
3.65k
  , fStage3Gain           (1.0)
792
3.65k
  , fIsPreview            (false)
793
3.65k
  , fIsDamaged            (false)
794
3.65k
  , fRawImageStage          (rawImageStageNone)
795
3.65k
  , fRawImage           ()
796
3.65k
  , fRawFloatBitDepth       (0)
797
3.65k
  , fRawJPEGImage         ()
798
3.65k
  , fRawJPEGImageDigest       ()
799
3.65k
  , fTransparencyMask       ()
800
3.65k
  , fRawTransparencyMask      ()
801
3.65k
  , fRawTransparencyMaskBitDepth  (0)
802
3.65k
  , fUnflattenedStage3Image     ()
803
804
3.65k
  {
805
806
3.65k
  }
807
808
/*****************************************************************************/
809
810
dng_negative::~dng_negative ()
811
3.65k
  {
812
  
813
  // Delete any camera profiles owned by this negative.
814
  
815
3.65k
  ClearProfiles ();
816
    
817
3.65k
  }
818
819
/******************************************************************************/
820
821
void dng_negative::Initialize ()
822
3.65k
  {
823
  
824
3.65k
  }
825
826
/******************************************************************************/
827
828
dng_negative * dng_negative::Make (dng_host &host)
829
3.65k
  {
830
  
831
3.65k
  AutoPtr<dng_negative> result (new dng_negative (host));
832
  
833
3.65k
  if (!result.Get ())
834
0
    {
835
0
    ThrowMemoryFull ();
836
0
    }
837
  
838
3.65k
  result->Initialize ();
839
  
840
3.65k
  return result.Release ();
841
  
842
3.65k
  }
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
4.01k
  {
857
  
858
4.01k
  return metadata.BaseOrientation ();
859
  
860
4.01k
  }
861
    
862
/******************************************************************************/
863
864
void dng_negative::SetAnalogBalance (const dng_vector &b)
865
611
  {
866
  
867
611
  real64 minEntry = b.MinEntry ();
868
  
869
611
  if (b.NotEmpty () && minEntry > 0.0)
870
609
    {
871
    
872
609
    fAnalogBalance = b;
873
  
874
609
    fAnalogBalance.Scale (1.0 / minEntry);
875
    
876
609
    fAnalogBalance.Round (1000000.0);
877
    
878
609
    }
879
    
880
2
  else
881
2
    {
882
    
883
2
    fAnalogBalance.Clear ();
884
    
885
2
    }
886
    
887
611
  }
888
            
889
/*****************************************************************************/
890
891
real64 dng_negative::AnalogBalance (uint32 channel) const
892
7.41k
  {
893
  
894
7.41k
  DNG_ASSERT (channel < ColorChannels (), "Channel out of bounds");
895
  
896
7.41k
  if (channel < fAnalogBalance.Count ())
897
549
    {
898
    
899
549
    return fAnalogBalance [channel];
900
    
901
549
    }
902
    
903
6.86k
  return 1.0;
904
  
905
7.41k
  }
906
    
907
/*****************************************************************************/
908
909
dng_urational dng_negative::AnalogBalanceR (uint32 channel) const
910
2.47k
  {
911
  
912
2.47k
  dng_urational result;
913
  
914
2.47k
  result.Set_real64 (AnalogBalance (channel), 1000000);
915
  
916
2.47k
  return result;
917
  
918
2.47k
  }
919
920
/******************************************************************************/
921
922
void dng_negative::SetCameraNeutral (const dng_vector &n)
923
52
  {
924
  
925
52
  real64 maxEntry = n.MaxEntry ();
926
    
927
52
  if (n.NotEmpty () && maxEntry > 0.0)
928
51
    {
929
    
930
51
    fCameraNeutral = n;
931
  
932
51
    fCameraNeutral.Scale (1.0 / maxEntry);
933
    
934
51
    fCameraNeutral.Round (1000000.0);
935
    
936
51
    }
937
    
938
1
  else
939
1
    {
940
    
941
1
    fCameraNeutral.Clear ();
942
    
943
1
    }
944
945
52
  }
946
    
947
/*****************************************************************************/
948
949
dng_urational dng_negative::CameraNeutralR (uint32 channel) const
950
138
  {
951
  
952
138
  dng_urational result;
953
  
954
138
  result.Set_real64 (CameraNeutral () [channel], 1000000);
955
  
956
138
  return result;
957
  
958
138
  }
959
960
/******************************************************************************/
961
962
void dng_negative::SetCameraWhiteXY (const dng_xy_coord &coord)
963
1.21k
  {
964
  
965
1.21k
  if (coord.IsValid ())
966
1.21k
    {
967
    
968
1.21k
    fCameraWhiteXY.x = Round_int32 (coord.x * 1000000.0) / 1000000.0;
969
1.21k
    fCameraWhiteXY.y = Round_int32 (coord.y * 1000000.0) / 1000000.0;
970
    
971
1.21k
    }
972
    
973
0
  else
974
0
    {
975
    
976
0
    fCameraWhiteXY.Clear ();
977
    
978
0
    }
979
  
980
1.21k
  }
981
    
982
/*****************************************************************************/
983
984
const dng_xy_coord & dng_negative::CameraWhiteXY () const
985
1.65k
  {
986
  
987
1.65k
  DNG_ASSERT (HasCameraWhiteXY (), "Using undefined CameraWhiteXY");
988
989
1.65k
  return fCameraWhiteXY;
990
  
991
1.65k
  }
992
                 
993
/*****************************************************************************/
994
995
void dng_negative::GetCameraWhiteXY (dng_urational &x,
996
                     dng_urational &y) const
997
568
  {
998
  
999
568
  dng_xy_coord coord = CameraWhiteXY ();
1000
  
1001
568
  x.Set_real64 (coord.x, 1000000);
1002
568
  y.Set_real64 (coord.y, 1000000);
1003
  
1004
568
  }
1005
    
1006
/*****************************************************************************/
1007
1008
void dng_negative::SetCameraCalibration1 (const dng_matrix &m)
1009
150
  {
1010
  
1011
150
  fCameraCalibration1 = m;
1012
  
1013
150
  fCameraCalibration1.Round (10000);
1014
  
1015
150
  }
1016
1017
/******************************************************************************/
1018
1019
void dng_negative::SetCameraCalibration2 (const dng_matrix &m)
1020
0
  {
1021
  
1022
0
  fCameraCalibration2 = m;
1023
  
1024
0
  fCameraCalibration2.Round (10000);
1025
    
1026
0
  }
1027
1028
/******************************************************************************/
1029
1030
void dng_negative::AddProfile (AutoPtr<dng_camera_profile> &profile)
1031
1.62k
  {
1032
  
1033
  // Make sure we have a profile to add.
1034
  
1035
1.62k
  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
1.62k
  if (profile->Name ().IsEmpty ())
1045
625
    {
1046
    
1047
625
    profile->SetName (kProfileName_Embedded);
1048
    
1049
625
    }
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
1.62k
  if (fCameraProfile.size ())
1055
0
    {
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
0
    if (fCameraProfile [0]->NameIsEmbedded () &&
1061
0
      fCameraProfile [0]->EqualData (*profile.Get ()))
1062
0
      {
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
0
      if (fCameraProfile [0]->WasReadFromDNG ())
1068
0
        {
1069
        
1070
0
        profile->SetWasReadFromDNG ();
1071
        
1072
0
        }
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
0
      if (!fCameraProfile [0]->WasReadFromDisk ())
1078
0
        {
1079
        
1080
0
        profile->SetWasReadFromDisk (false);
1081
        
1082
0
        }
1083
        
1084
      // Delete the profile with default name.
1085
      
1086
0
      delete fCameraProfile [0];
1087
      
1088
0
      fCameraProfile [0] = NULL;
1089
      
1090
0
      fCameraProfile.erase (fCameraProfile.begin ());
1091
      
1092
0
      }
1093
    
1094
0
    }
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
1.62k
  for (uint32 index = 0; index < (uint32) fCameraProfile.size (); index++)
1101
0
    {
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
0
    const bool equalColorAndSameName = (fCameraProfile [index]->EqualData (*profile.Get ()) &&
1109
0
                      fCameraProfile [index]->Name () == profile->Name ());
1110
1111
0
    if (equalColorAndSameName)
1112
0
      {
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
0
      if (fCameraProfile [index]->WasReadFromDNG ())
1118
0
        {
1119
        
1120
0
        profile->SetWasReadFromDNG ();
1121
        
1122
0
        }
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
0
      if (!fCameraProfile [index]->WasReadFromDisk ())
1128
0
        {
1129
        
1130
0
        profile->SetWasReadFromDisk (false);
1131
        
1132
0
        }
1133
        
1134
      // Delete the duplicate profile.
1135
      
1136
0
      delete fCameraProfile [index];
1137
      
1138
0
      fCameraProfile [index] = NULL;
1139
      
1140
0
      fCameraProfile.erase (fCameraProfile.begin () + index);
1141
      
1142
0
      break;
1143
      
1144
0
      }
1145
      
1146
0
    }
1147
    
1148
  // Now add to profile list.
1149
  
1150
1.62k
  fCameraProfile.push_back (NULL);
1151
  
1152
1.62k
  fCameraProfile [fCameraProfile.size () - 1] = profile.Release ();
1153
  
1154
1.62k
  }
1155
      
1156
/******************************************************************************/
1157
1158
void dng_negative::ClearProfiles ()
1159
3.65k
  {
1160
  
1161
  // Delete any camera profiles owned by this negative.
1162
  
1163
5.28k
  for (uint32 index = 0; index < (uint32) fCameraProfile.size (); index++)
1164
1.62k
    {
1165
    
1166
1.62k
    if (fCameraProfile [index])
1167
1.62k
      {
1168
      
1169
1.62k
      delete fCameraProfile [index];
1170
      
1171
1.62k
      fCameraProfile [index] = NULL;
1172
      
1173
1.62k
      }
1174
    
1175
1.62k
    }
1176
    
1177
  // Now empty list.
1178
  
1179
3.65k
  fCameraProfile.clear ();
1180
  
1181
3.65k
  }
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
14.4k
  {
1238
  
1239
14.4k
  return (uint32) fCameraProfile.size ();
1240
  
1241
14.4k
  }
1242
    
1243
/******************************************************************************/
1244
1245
const dng_camera_profile & dng_negative::ProfileByIndex (uint32 index) const
1246
8.33k
  {
1247
  
1248
8.33k
  DNG_ASSERT (index < ProfileCount (),
1249
8.33k
        "Invalid index for ProfileByIndex");
1250
        
1251
8.33k
  return *fCameraProfile [index];
1252
    
1253
8.33k
  }
1254
    
1255
/*****************************************************************************/
1256
1257
const dng_camera_profile * dng_negative::ProfileByID (const dng_camera_profile_id &id,
1258
                            bool useDefaultIfNoMatch) const
1259
12.7k
  {
1260
  
1261
12.7k
  uint32 index;
1262
  
1263
  // If this negative does not have any profiles, we are not going to
1264
  // find a match.
1265
  
1266
12.7k
  uint32 profileCount = ProfileCount ();
1267
  
1268
12.7k
  if (profileCount == 0)
1269
6.08k
    {
1270
6.08k
    return NULL;
1271
6.08k
    }
1272
    
1273
  // If we have both a profile name and fingerprint, try matching both.
1274
  
1275
6.67k
  if (id.Name ().NotEmpty () && id.Fingerprint ().IsValid ())
1276
0
    {
1277
    
1278
0
    for (index = 0; index < profileCount; index++)
1279
0
      {
1280
      
1281
0
      const dng_camera_profile &profile = ProfileByIndex (index);
1282
      
1283
0
      if (id.Name        () == profile.Name        () &&
1284
0
        id.Fingerprint () == profile.Fingerprint ())
1285
0
        {
1286
        
1287
0
        return &profile;
1288
        
1289
0
        }
1290
      
1291
0
      }
1292
1293
0
    }
1294
    
1295
  // If we have a name, try matching that.
1296
  
1297
6.67k
  if (id.Name ().NotEmpty ())
1298
0
    {
1299
    
1300
0
    for (index = 0; index < profileCount; index++)
1301
0
      {
1302
      
1303
0
      const dng_camera_profile &profile = ProfileByIndex (index);
1304
      
1305
0
      if (id.Name () == profile.Name ())
1306
0
        {
1307
        
1308
0
        return &profile;
1309
        
1310
0
        }
1311
      
1312
0
      }
1313
1314
0
    }
1315
    
1316
  // If we have a valid fingerprint, try matching that.
1317
    
1318
6.67k
  if (id.Fingerprint ().IsValid ())
1319
0
    {
1320
    
1321
0
    for (index = 0; index < profileCount; index++)
1322
0
      {
1323
      
1324
0
      const dng_camera_profile &profile = ProfileByIndex (index);
1325
      
1326
0
      if (id.Fingerprint () == profile.Fingerprint ())
1327
0
        {
1328
        
1329
0
        return &profile;
1330
        
1331
0
        }
1332
      
1333
0
      }
1334
1335
0
    }
1336
    
1337
  // Try "upgrading" profile name versions.
1338
  
1339
6.67k
  if (id.Name ().NotEmpty ())
1340
0
    {
1341
    
1342
0
    dng_string baseName;
1343
0
    int32      version;
1344
    
1345
0
    SplitCameraProfileName (id.Name (),
1346
0
                baseName,
1347
0
                version);
1348
    
1349
0
    int32 bestIndex   = -1;
1350
0
    int32 bestVersion = 0;
1351
    
1352
0
    for (index = 0; index < profileCount; index++)
1353
0
      {
1354
      
1355
0
      const dng_camera_profile &profile = ProfileByIndex (index);
1356
      
1357
0
      if (profile.Name ().StartsWith (baseName.Get ()))
1358
0
        {
1359
        
1360
0
        dng_string testBaseName;
1361
0
        int32      testVersion;
1362
        
1363
0
        SplitCameraProfileName (profile.Name (),
1364
0
                    testBaseName,
1365
0
                    testVersion);
1366
                    
1367
0
        if (bestIndex == -1 || testVersion > bestVersion)
1368
0
          {
1369
          
1370
0
          bestIndex   = index;
1371
0
          bestVersion = testVersion;
1372
          
1373
0
          }
1374
          
1375
0
        }
1376
        
1377
0
      }
1378
      
1379
0
    if (bestIndex != -1)
1380
0
      {
1381
      
1382
0
      return &ProfileByIndex (bestIndex);
1383
      
1384
0
      }
1385
    
1386
0
    }
1387
    
1388
  // Did not find a match any way.  See if we should return a default value.
1389
  
1390
6.67k
  if (useDefaultIfNoMatch)
1391
6.67k
    {
1392
    
1393
6.67k
    return &ProfileByIndex (0);
1394
    
1395
6.67k
    }
1396
    
1397
  // Found nothing.
1398
  
1399
0
  return NULL;
1400
    
1401
6.67k
  }
1402
1403
/*****************************************************************************/
1404
1405
const dng_camera_profile * dng_negative::ComputeCameraProfileToEmbed
1406
                    (const dng_metadata & /* metadata */) const
1407
826
  {
1408
  
1409
826
  uint32 index;
1410
  
1411
826
  uint32 count = ProfileCount ();
1412
  
1413
826
  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
826
  for (index = 0; index < count; index++)
1424
826
    {
1425
    
1426
826
    const dng_camera_profile &profile (ProfileByIndex (index));
1427
    
1428
826
    if (profile.WasReadFromDNG ())
1429
826
      {
1430
      
1431
826
      return &profile;
1432
      
1433
826
      }
1434
    
1435
826
    }
1436
    
1437
  // Next we look for the first profile that is legal to embed.
1438
  
1439
0
  for (index = 0; index < count; index++)
1440
0
    {
1441
    
1442
0
    const dng_camera_profile &profile (ProfileByIndex (index));
1443
    
1444
0
    if (profile.IsLegalToEmbed ())
1445
0
      {
1446
      
1447
0
      return &profile;
1448
      
1449
0
      }
1450
    
1451
0
    }
1452
    
1453
  // Else just return the first profile.
1454
  
1455
0
  return fCameraProfile [0];
1456
  
1457
0
  }
1458
                 
1459
/*****************************************************************************/
1460
1461
dng_color_spec * dng_negative::MakeColorSpec (const dng_camera_profile_id &id) const
1462
1.64k
  {
1463
1464
1.64k
  dng_color_spec *spec = new dng_color_spec (*this, ProfileByID (id));
1465
                         
1466
1.64k
  if (!spec)
1467
0
    {
1468
0
    ThrowMemoryFull ();
1469
0
    }
1470
    
1471
1.64k
  return spec;
1472
  
1473
1.64k
  }
1474
                 
1475
/*****************************************************************************/
1476
1477
dng_fingerprint dng_negative::FindImageDigest (dng_host &host,
1478
                         const dng_image &image) const
1479
436
  {
1480
  
1481
436
  dng_md5_printer printer;
1482
  
1483
436
  dng_pixel_buffer buffer (image.Bounds (), 0, image.Planes (),
1484
436
     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
436
  if (buffer.fPixelType == ttByte)
1490
383
    {
1491
383
    buffer.fPixelType = ttShort;
1492
383
    buffer.fPixelSize = 2;
1493
383
    }
1494
  
1495
436
  const uint32 kBufferRows = 16;
1496
  
1497
436
  uint32 bufferBytes = 0;
1498
  
1499
436
  if (!SafeUint32Mult (kBufferRows, buffer.fRowStep, &bufferBytes) ||
1500
436
     !SafeUint32Mult (bufferBytes, buffer.fPixelSize, &bufferBytes))
1501
0
    {
1502
    
1503
0
    ThrowMemoryFull("Arithmetic overflow computing buffer size.");
1504
    
1505
0
    }
1506
  
1507
436
  AutoPtr<dng_memory_block> bufferData (host.Allocate (bufferBytes));
1508
  
1509
436
  buffer.fData = bufferData->Buffer ();
1510
  
1511
436
  dng_rect area;
1512
  
1513
436
  dng_tile_iterator iter (dng_point (kBufferRows,
1514
436
                     image.Width ()),
1515
436
              image.Bounds ());
1516
              
1517
27.3k
  while (iter.GetOneTile (area))
1518
26.9k
    {
1519
    
1520
26.9k
    host.SniffForAbort ();
1521
    
1522
26.9k
    buffer.fArea = area;
1523
    
1524
26.9k
    image.Get (buffer);
1525
    
1526
26.9k
    uint32 count = buffer.fArea.H () *
1527
26.9k
             buffer.fRowStep *
1528
26.9k
             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
26.9k
    printer.Process (buffer.fData,
1565
26.9k
             count);
1566
    
1567
26.9k
    }
1568
      
1569
436
  return printer.Result ();
1570
  
1571
436
  }
1572
                 
1573
/*****************************************************************************/
1574
1575
void dng_negative::FindRawImageDigest (dng_host &host) const
1576
473
  {
1577
  
1578
473
  if (fRawImageDigest.IsNull ())
1579
473
    {
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
473
    if (RawImage ().PixelType () == ttFloat || RawTransparencyMask ())
1587
37
      {
1588
      
1589
37
      FindNewRawImageDigest (host);
1590
      
1591
37
      fRawImageDigest = fNewRawImageDigest;
1592
      
1593
37
      }
1594
      
1595
436
    else
1596
436
      {
1597
      
1598
      #if qDNGValidate
1599
      
1600
      dng_timer timeScope ("FindRawImageDigest time");
1601
1602
      #endif
1603
    
1604
436
      fRawImageDigest = FindImageDigest (host, RawImage ());
1605
      
1606
436
      }
1607
  
1608
473
    }
1609
  
1610
473
  }
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
597
      : fImage       (image)
1644
597
      , fPixelType   (pixelType)
1645
597
      , fPixelSize   (TagTypeSize (pixelType))
1646
597
      , fTilesAcross (0)
1647
597
      , fTilesDown   (0)
1648
597
      , fTileCount   (0)
1649
597
      , fTileHash    ()
1650
      
1651
597
      {
1652
      
1653
597
      fMinTaskArea = 1;
1654
                  
1655
597
      fUnitCell = dng_point (Min_int32 (kTileSize, fImage.Bounds ().H ()),
1656
597
                   Min_int32 (kTileSize, fImage.Bounds ().W ()));
1657
                   
1658
597
      fMaxTileSize = fUnitCell;
1659
            
1660
597
      }
1661
  
1662
    virtual void Start (uint32 threadCount,
1663
              const dng_point &tileSize,
1664
              dng_memory_allocator *allocator,
1665
              dng_abort_sniffer * /* sniffer */)
1666
597
      {
1667
      
1668
597
      if (tileSize != fUnitCell)
1669
0
        {
1670
0
        ThrowProgramError ();
1671
0
        }
1672
        
1673
597
      fTilesAcross = (fImage.Bounds ().W () + fUnitCell.h - 1) / fUnitCell.h;
1674
597
      fTilesDown   = (fImage.Bounds ().H () + fUnitCell.v - 1) / fUnitCell.v;
1675
      
1676
597
      fTileCount = fTilesAcross * fTilesDown;
1677
             
1678
597
      fTileHash.Reset (fTileCount);
1679
      
1680
597
      const uint32 bufferSize =
1681
597
        ComputeBufferSize(fPixelType, tileSize, fImage.Planes(),
1682
597
                  padNone);
1683
      
1684
1.19k
      for (uint32 index = 0; index < threadCount; index++)
1685
597
        {
1686
        
1687
597
        fBufferData [index].Reset (allocator->Allocate (bufferSize));
1688
        
1689
597
        }
1690
      
1691
597
      }
1692
1693
    virtual void Process (uint32 threadIndex,
1694
                const dng_rect &tile,
1695
                dng_abort_sniffer * /* sniffer */)
1696
2.59k
      {
1697
      
1698
2.59k
      int32 colIndex = (tile.l - fImage.Bounds ().l) / fUnitCell.h;
1699
2.59k
      int32 rowIndex = (tile.t - fImage.Bounds ().t) / fUnitCell.v;
1700
      
1701
2.59k
      DNG_ASSERT (tile.l == fImage.Bounds ().l + colIndex * fUnitCell.h &&
1702
2.59k
            tile.t == fImage.Bounds ().t + rowIndex * fUnitCell.v,
1703
2.59k
            "Bad tile origin");
1704
      
1705
2.59k
      uint32 tileIndex = rowIndex * fTilesAcross + colIndex;
1706
      
1707
2.59k
      dng_pixel_buffer buffer (tile, 0, fImage.Planes (),
1708
2.59k
         fPixelType, pcPlanar,
1709
2.59k
         fBufferData [threadIndex]->Buffer ());
1710
      
1711
2.59k
      fImage.Get (buffer);
1712
      
1713
2.59k
      uint32 count = buffer.fPlaneStep *
1714
2.59k
               buffer.fPlanes *
1715
2.59k
               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
2.59k
      dng_md5_printer printer;
1752
      
1753
2.59k
      printer.Process (buffer.fData, count);
1754
               
1755
2.59k
      fTileHash [tileIndex] = printer.Result ();
1756
      
1757
2.59k
      }
1758
      
1759
    dng_fingerprint Result ()
1760
597
      {
1761
      
1762
597
      dng_md5_printer printer;
1763
      
1764
3.18k
      for (uint32 tileIndex = 0; tileIndex < fTileCount; tileIndex++)
1765
2.59k
        {
1766
        
1767
2.59k
        printer.Process (fTileHash [tileIndex] . data, 16);
1768
        
1769
2.59k
        }
1770
        
1771
597
      return printer.Result ();
1772
      
1773
597
      }
1774
    
1775
  };
1776
1777
/*****************************************************************************/
1778
1779
void dng_negative::FindNewRawImageDigest (dng_host &host) const
1780
1.09k
  {
1781
  
1782
1.09k
  if (fNewRawImageDigest.IsNull ())
1783
597
    {
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
597
      {
1794
    
1795
597
      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
597
      uint32 rawPixelType = rawImage.PixelType ();
1801
      
1802
597
      if (rawPixelType == ttShort)
1803
1
        {
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
1
        const dng_linearization_info *rangeInfo = GetLinearizationInfo ();
1809
      
1810
1
        if (rangeInfo)
1811
1
          {
1812
1813
1
          if (rangeInfo->fLinearizationTable.Get ())
1814
0
            {
1815
            
1816
0
            uint32 entries = rangeInfo->fLinearizationTable->LogicalSize () >> 1;
1817
            
1818
0
            if (entries <= 256)
1819
0
              {
1820
              
1821
0
              rawPixelType = ttByte;
1822
              
1823
0
              }
1824
                            
1825
0
            }
1826
            
1827
1
          }
1828
1829
1
        }
1830
      
1831
      // Find the fast digest on the raw image.
1832
        
1833
597
      dng_find_new_raw_image_digest_task task (rawImage, rawPixelType);
1834
      
1835
597
      host.PerformAreaTask (task, rawImage.Bounds ());
1836
      
1837
597
      fNewRawImageDigest = task.Result ();
1838
        
1839
597
      }
1840
      
1841
    // If there is a transparancy mask, we need to include that in the
1842
    // digest also.
1843
    
1844
597
    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
597
    }
1875
  
1876
1.09k
  }
1877
                 
1878
/*****************************************************************************/
1879
1880
void dng_negative::ValidateRawImageDigest (dng_host &host)
1881
2.32k
  {
1882
  
1883
2.32k
  if (Stage1Image () && !IsPreview () && (fRawImageDigest   .IsValid () ||
1884
2.32k
                        fNewRawImageDigest.IsValid ()))
1885
475
    {
1886
    
1887
475
    bool isNewDigest = fNewRawImageDigest.IsValid ();
1888
    
1889
475
    dng_fingerprint &rawDigest = isNewDigest ? fNewRawImageDigest
1890
475
                         : 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
475
    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
475
    else
1924
475
      {
1925
    
1926
475
      dng_fingerprint oldDigest = rawDigest;
1927
      
1928
475
      try
1929
475
        {
1930
        
1931
475
        rawDigest.Clear ();
1932
        
1933
475
        if (isNewDigest)
1934
2
          {
1935
          
1936
2
          FindNewRawImageDigest (host);
1937
          
1938
2
          }
1939
          
1940
473
        else
1941
473
          {
1942
          
1943
473
          FindRawImageDigest (host);
1944
          
1945
473
          }
1946
        
1947
475
        }
1948
        
1949
475
      catch (...)
1950
475
        {
1951
        
1952
0
        rawDigest = oldDigest;
1953
        
1954
0
        throw;
1955
        
1956
0
        }
1957
      
1958
475
      if (oldDigest != rawDigest)
1959
474
        {
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
474
        if (!isNewDigest)
1977
472
          {
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
472
            {
1986
          
1987
472
            bool matchLast12 = true;
1988
            
1989
6.13k
            for (uint32 j = 4; j < 16; j++)
1990
5.66k
              {
1991
5.66k
              matchLast12 = matchLast12 && (oldDigest.data [j] == fRawImageDigest.data [j]);
1992
5.66k
              }
1993
              
1994
472
            if (matchLast12)
1995
0
              {
1996
0
              return;
1997
0
              }
1998
              
1999
472
            }
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
472
          if (oldDigest.data [0] == 0x08 &&
2006
472
            oldDigest.data [1] == 0x00 &&
2007
472
            oldDigest.data [2] == 0x00 &&
2008
472
            oldDigest.data [3] == 0x00)
2009
2
            {
2010
2
            return;
2011
2
            }
2012
            
2013
472
          }
2014
          
2015
472
        SetIsDamaged (true);
2016
        
2017
472
        #endif
2018
        
2019
472
        }
2020
        
2021
475
      }
2022
      
2023
475
    }
2024
  
2025
2.32k
  }
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
4.21k
  {
2035
  
2036
4.21k
  if (fRawDataUniqueID.IsNull ())
2037
2.15k
    {
2038
    
2039
2.15k
    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
2.15k
    if (RawJPEGImage () && !RawTransparencyMask ())
2048
1.59k
      {
2049
      
2050
1.59k
      FindRawJPEGImageDigest (host);
2051
      
2052
1.59k
      printer.Put (fRawJPEGImageDigest.data, 16);
2053
      
2054
1.59k
      }
2055
    
2056
    // Include the new raw image digest in the unique ID.
2057
    
2058
561
    else
2059
561
      {
2060
    
2061
561
      FindNewRawImageDigest (host);
2062
          
2063
561
      printer.Put (fNewRawImageDigest.data, 16);
2064
      
2065
561
      }
2066
    
2067
    // Include model name.
2068
          
2069
2.15k
    printer.Put (ModelName ().Get    (),
2070
2.15k
           ModelName ().Length ());
2071
           
2072
    // Include default crop area, since DNG Recover Edges can modify
2073
    // these values and they affect rendering.
2074
           
2075
2.15k
    printer.Put_uint32 (fDefaultCropSizeH.n);
2076
2.15k
    printer.Put_uint32 (fDefaultCropSizeH.d);
2077
    
2078
2.15k
    printer.Put_uint32 (fDefaultCropSizeV.n);
2079
2.15k
    printer.Put_uint32 (fDefaultCropSizeV.d);
2080
    
2081
2.15k
    printer.Put_uint32 (fDefaultCropOriginH.n);
2082
2.15k
    printer.Put_uint32 (fDefaultCropOriginH.d);
2083
    
2084
2.15k
    printer.Put_uint32 (fDefaultCropOriginV.n);
2085
2.15k
    printer.Put_uint32 (fDefaultCropOriginV.d);
2086
2087
    // Include default user crop.
2088
2089
2.15k
    printer.Put_uint32 (fDefaultUserCropT.n);
2090
2.15k
    printer.Put_uint32 (fDefaultUserCropT.d);
2091
    
2092
2.15k
    printer.Put_uint32 (fDefaultUserCropL.n);
2093
2.15k
    printer.Put_uint32 (fDefaultUserCropL.d);
2094
    
2095
2.15k
    printer.Put_uint32 (fDefaultUserCropB.n);
2096
2.15k
    printer.Put_uint32 (fDefaultUserCropB.d);
2097
    
2098
2.15k
    printer.Put_uint32 (fDefaultUserCropR.n);
2099
2.15k
    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
2.15k
    fOpcodeList1.FingerprintToStream (printer);
2105
2.15k
    fOpcodeList2.FingerprintToStream (printer);
2106
2.15k
    fOpcodeList3.FingerprintToStream (printer);
2107
    
2108
2.15k
    fRawDataUniqueID = printer.Result ();
2109
  
2110
2.15k
    }
2111
  
2112
4.21k
  }
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
2.14k
  {
2121
  
2122
2.14k
  fRawDataUniqueID.Clear ();
2123
  
2124
2.14k
  FindRawDataUniqueID (host);
2125
  
2126
2.14k
  }
2127
    
2128
/******************************************************************************/
2129
2130
void dng_negative::FindOriginalRawFileDigest () const
2131
2.07k
  {
2132
2133
2.07k
  if (fOriginalRawFileDigest.IsNull () && fOriginalRawFileData.Get ())
2134
0
    {
2135
    
2136
0
    dng_md5_printer printer;
2137
    
2138
0
    printer.Process (fOriginalRawFileData->Buffer      (),
2139
0
             fOriginalRawFileData->LogicalSize ());
2140
          
2141
0
    fOriginalRawFileDigest = printer.Result ();
2142
  
2143
0
    }
2144
2145
2.07k
  }
2146
    
2147
/*****************************************************************************/
2148
2149
void dng_negative::ValidateOriginalRawFileDigest ()
2150
0
  {
2151
  
2152
0
  if (fOriginalRawFileDigest.IsValid () && fOriginalRawFileData.Get ())
2153
0
    {
2154
    
2155
0
    dng_fingerprint oldDigest = fOriginalRawFileDigest;
2156
    
2157
0
    try
2158
0
      {
2159
      
2160
0
      fOriginalRawFileDigest.Clear ();
2161
      
2162
0
      FindOriginalRawFileDigest ();
2163
      
2164
0
      }
2165
      
2166
0
    catch (...)
2167
0
      {
2168
      
2169
0
      fOriginalRawFileDigest = oldDigest;
2170
      
2171
0
      throw;
2172
      
2173
0
      }
2174
    
2175
0
    if (oldDigest != fOriginalRawFileDigest)
2176
0
      {
2177
      
2178
      #if qDNGValidate
2179
      
2180
      ReportError ("OriginalRawFileDigest does not match OriginalRawFileData");
2181
      
2182
      #else
2183
      
2184
0
      SetIsDamaged (true);
2185
      
2186
0
      #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
0
      fOriginalRawFileDigest = oldDigest;
2194
      
2195
0
      }
2196
      
2197
0
    }
2198
    
2199
0
  }
2200
                 
2201
/******************************************************************************/
2202
2203
dng_rect dng_negative::DefaultCropArea () const
2204
7.84k
  {
2205
  
2206
  // First compute the area using simple rounding.
2207
    
2208
7.84k
  dng_rect result;
2209
  
2210
7.84k
  result.l = Round_int32 (fDefaultCropOriginH.As_real64 () * fRawToFullScaleH);
2211
7.84k
  result.t = Round_int32 (fDefaultCropOriginV.As_real64 () * fRawToFullScaleV);
2212
  
2213
7.84k
  result.r = result.l + Round_int32 (fDefaultCropSizeH.As_real64 () * fRawToFullScaleH);
2214
7.84k
  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
7.84k
  const dng_image *image = Stage3Image ();
2221
  
2222
7.84k
  if (image)
2223
7.84k
    {
2224
  
2225
7.84k
    dng_point imageSize = image->Size ();
2226
    
2227
7.84k
    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
7.84k
    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
7.84k
    }
2240
    
2241
7.84k
  return result;
2242
  
2243
7.84k
  }
2244
2245
/*****************************************************************************/
2246
2247
real64 dng_negative::TotalBaselineExposure (const dng_camera_profile_id &profileID) const
2248
4.67k
  {
2249
  
2250
4.67k
  real64 total = BaselineExposure ();
2251
2252
4.67k
  const dng_camera_profile *profile = ProfileByID (profileID);
2253
  
2254
4.67k
  if (profile)
2255
1.63k
    {
2256
2257
1.63k
    real64 offset = profile->BaselineExposureOffset ().As_real64 ();
2258
2259
1.63k
    total += offset;
2260
    
2261
1.63k
    }
2262
2263
4.67k
  return total;
2264
  
2265
4.67k
  }
2266
2267
/******************************************************************************/
2268
2269
void dng_negative::SetShadowScale (const dng_urational &scale)
2270
3.65k
  {
2271
  
2272
3.65k
  if (scale.d > 0)
2273
3.65k
    {
2274
    
2275
3.65k
    real64 s = scale.As_real64 ();
2276
    
2277
3.65k
    if (s > 0.0 && s <= 1.0)
2278
3.56k
      {
2279
  
2280
3.56k
      fShadowScale = scale;
2281
      
2282
3.56k
      }
2283
    
2284
3.65k
    }
2285
  
2286
3.65k
  }
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
3.72k
  {
2508
  
2509
3.72k
  if (fLinearizationInfo.Get ())
2510
3.72k
    {
2511
    
2512
3.72k
    const dng_linearization_info &info = *fLinearizationInfo.Get ();
2513
                      
2514
3.72k
    return Round_uint32 (info.fWhiteLevel [plane]);
2515
                      
2516
3.72k
    }
2517
    
2518
0
  if (RawImage ().PixelType () == ttFloat)
2519
0
    {
2520
    
2521
0
    return 1;
2522
    
2523
0
    }
2524
    
2525
0
  return 0x0FFFF;
2526
  
2527
0
  }
2528
              
2529
/*****************************************************************************/
2530
2531
void dng_negative::SetWhiteLevel (uint32 white,
2532
                    int32 plane)
2533
2.14k
  {
2534
2535
2.14k
  NeedLinearizationInfo ();
2536
  
2537
2.14k
  dng_linearization_info &info = *fLinearizationInfo.Get ();
2538
                    
2539
2.14k
  if (plane < 0)
2540
2.14k
    {
2541
    
2542
10.7k
    for (uint32 j = 0; j < kMaxSamplesPerPixel; j++)
2543
8.56k
      {
2544
      
2545
8.56k
      info.fWhiteLevel [j] = (real64) white;
2546
      
2547
8.56k
      }
2548
    
2549
2.14k
    }
2550
    
2551
0
  else
2552
0
    {
2553
    
2554
0
    info.fWhiteLevel [plane] = (real64) white;
2555
      
2556
0
    }
2557
  
2558
2.14k
  }
2559
2560
/******************************************************************************/
2561
2562
void dng_negative::SetColorKeys (ColorKeyCode color0,
2563
                   ColorKeyCode color1,
2564
                   ColorKeyCode color2,
2565
                   ColorKeyCode color3)
2566
0
  {
2567
  
2568
0
  NeedMosaicInfo ();
2569
  
2570
0
  dng_mosaic_info &info = *fMosaicInfo.Get ();
2571
               
2572
0
  info.fCFAPlaneColor [0] = color0;
2573
0
  info.fCFAPlaneColor [1] = color1;
2574
0
  info.fCFAPlaneColor [2] = color2;
2575
0
  info.fCFAPlaneColor [3] = color3;
2576
  
2577
0
  }
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
3.65k
  {
2911
  
2912
  // Shared info.
2913
  
2914
3.65k
  dng_shared &shared = *(info.fShared.Get ());
2915
  
2916
  // Find IFD holding the main raw information.
2917
  
2918
3.65k
  dng_ifd &rawIFD = *info.fIFD [info.fMainIndex].Get ();
2919
  
2920
  // Model name.
2921
  
2922
3.65k
  SetModelName (shared.fUniqueCameraModel.Get ());
2923
  
2924
  // Localized model name.
2925
  
2926
3.65k
  SetLocalName (shared.fLocalizedCameraModel.Get ());
2927
  
2928
  // Base orientation.
2929
  
2930
3.65k
    {
2931
  
2932
3.65k
    uint32 orientation = info.fIFD [0]->fOrientation;
2933
    
2934
3.65k
    if (orientation >= 1 && orientation <= 8)
2935
1.23k
      {
2936
      
2937
1.23k
      SetBaseOrientation (dng_orientation::TIFFtoDNG (orientation));
2938
            
2939
1.23k
      }
2940
      
2941
3.65k
    }
2942
    
2943
  // Default crop rectangle.
2944
  
2945
3.65k
  SetDefaultCropSize (rawIFD.fDefaultCropSizeH,
2946
3.65k
              rawIFD.fDefaultCropSizeV);
2947
2948
3.65k
  SetDefaultCropOrigin (rawIFD.fDefaultCropOriginH,
2949
3.65k
              rawIFD.fDefaultCropOriginV);
2950
2951
  // Default user crop rectangle.
2952
2953
3.65k
  SetDefaultUserCrop (rawIFD.fDefaultUserCropT,
2954
3.65k
            rawIFD.fDefaultUserCropL,
2955
3.65k
            rawIFD.fDefaultUserCropB,
2956
3.65k
            rawIFD.fDefaultUserCropR);
2957
                    
2958
  // Default scale.
2959
    
2960
3.65k
  SetDefaultScale (rawIFD.fDefaultScaleH,
2961
3.65k
           rawIFD.fDefaultScaleV);
2962
  
2963
  // Best quality scale.
2964
  
2965
3.65k
  SetBestQualityScale (rawIFD.fBestQualityScale);
2966
  
2967
  // Baseline noise.
2968
2969
3.65k
  SetBaselineNoise (shared.fBaselineNoise.As_real64 ());
2970
  
2971
  // NoiseReductionApplied.
2972
  
2973
3.65k
  SetNoiseReductionApplied (shared.fNoiseReductionApplied);
2974
2975
  // NoiseProfile.
2976
2977
3.65k
  SetNoiseProfile (shared.fNoiseProfile);
2978
  
2979
  // Baseline exposure.
2980
  
2981
3.65k
  SetBaselineExposure (shared.fBaselineExposure.As_real64 ());
2982
2983
  // Baseline sharpness.
2984
  
2985
3.65k
  SetBaselineSharpness (shared.fBaselineSharpness.As_real64 ());
2986
2987
  // Chroma blur radius.
2988
  
2989
3.65k
  SetChromaBlurRadius (rawIFD.fChromaBlurRadius);
2990
2991
  // Anti-alias filter strength.
2992
  
2993
3.65k
  SetAntiAliasStrength (rawIFD.fAntiAliasStrength);
2994
    
2995
  // Linear response limit.
2996
  
2997
3.65k
  SetLinearResponseLimit (shared.fLinearResponseLimit.As_real64 ());
2998
  
2999
  // Shadow scale.
3000
  
3001
3.65k
  SetShadowScale (shared.fShadowScale);
3002
  
3003
  // Colorimetric reference.
3004
  
3005
3.65k
  SetColorimetricReference (shared.fColorimetricReference);
3006
  
3007
  // Color channels.
3008
    
3009
3.65k
  SetColorChannels (shared.fCameraProfile.fColorPlanes);
3010
  
3011
  // Analog balance.
3012
  
3013
3.65k
  if (shared.fAnalogBalance.NotEmpty ())
3014
611
    {
3015
    
3016
611
    SetAnalogBalance (shared.fAnalogBalance);
3017
    
3018
611
    }
3019
3020
  // Camera calibration matrices
3021
3022
3.65k
  if (shared.fCameraCalibration1.NotEmpty ())
3023
150
    {
3024
    
3025
150
    SetCameraCalibration1 (shared.fCameraCalibration1);
3026
    
3027
150
    }
3028
    
3029
3.65k
  if (shared.fCameraCalibration2.NotEmpty ())
3030
0
    {
3031
    
3032
0
    SetCameraCalibration2 (shared.fCameraCalibration2);
3033
    
3034
0
    }
3035
    
3036
3.65k
  if (shared.fCameraCalibration1.NotEmpty () ||
3037
3.65k
    shared.fCameraCalibration2.NotEmpty ())
3038
149
    {
3039
    
3040
149
    SetCameraCalibrationSignature (shared.fCameraCalibrationSignature.Get ());
3041
    
3042
149
    }
3043
3044
  // Embedded camera profiles.
3045
  
3046
3.65k
  if (shared.fCameraProfile.fColorPlanes > 1)
3047
1.65k
    {
3048
  
3049
1.65k
    if (qDNGValidate || host.NeedsMeta () || host.NeedsImage ())
3050
1.65k
      {
3051
      
3052
      // Add profile from main IFD.
3053
      
3054
1.65k
        {
3055
      
3056
1.65k
        AutoPtr<dng_camera_profile> profile (new dng_camera_profile ());
3057
        
3058
1.65k
        dng_camera_profile_info &profileInfo = shared.fCameraProfile;
3059
        
3060
1.65k
        profile->Parse (stream, profileInfo);
3061
        
3062
        // The main embedded profile must be valid.
3063
        
3064
1.65k
        if (!profile->IsValid (shared.fCameraProfile.fColorPlanes))
3065
13
          {
3066
          
3067
13
          ThrowBadFormat ();
3068
          
3069
13
          }
3070
        
3071
1.65k
        profile->SetWasReadFromDNG ();
3072
        
3073
1.65k
        AddProfile (profile);
3074
        
3075
1.65k
        }
3076
        
3077
      // Extra profiles.
3078
3079
1.65k
      for (uint32 index = 0; index < (uint32) shared.fExtraCameraProfiles.size (); index++)
3080
0
        {
3081
        
3082
0
        try
3083
0
          {
3084
3085
0
          AutoPtr<dng_camera_profile> profile (new dng_camera_profile ());
3086
          
3087
0
          dng_camera_profile_info &profileInfo = shared.fExtraCameraProfiles [index];
3088
          
3089
0
          profile->Parse (stream, profileInfo);
3090
          
3091
0
          if (!profile->IsValid (shared.fCameraProfile.fColorPlanes))
3092
0
            {
3093
            
3094
0
            ThrowBadFormat ();
3095
            
3096
0
            }
3097
          
3098
0
          profile->SetWasReadFromDNG ();
3099
          
3100
0
          AddProfile (profile);
3101
3102
0
          }
3103
          
3104
0
        catch (dng_exception &except)
3105
0
          {
3106
          
3107
          // Don't ignore transient errors.
3108
          
3109
0
          if (host.IsTransientError (except.ErrorCode ()))
3110
0
            {
3111
            
3112
0
            throw;
3113
            
3114
0
            }
3115
        
3116
          // Eat other parsing errors.
3117
      
3118
          #if qDNGValidate
3119
          
3120
          ReportWarning ("Unable to parse extra profile");
3121
          
3122
          #endif
3123
          
3124
0
          }
3125
      
3126
0
        }
3127
      
3128
1.65k
      }
3129
      
3130
    // As shot profile name.
3131
    
3132
1.65k
    if (shared.fAsShotProfileName.NotEmpty ())
3133
140
      {
3134
      
3135
140
      SetAsShotProfileName (shared.fAsShotProfileName.Get ());
3136
      
3137
140
      }
3138
      
3139
1.65k
    }
3140
    
3141
  // Raw image data digest.
3142
  
3143
3.65k
  if (shared.fRawImageDigest.IsValid ())
3144
1.09k
    {
3145
    
3146
1.09k
    SetRawImageDigest (shared.fRawImageDigest);
3147
    
3148
1.09k
    }
3149
      
3150
  // New raw image data digest.
3151
  
3152
3.65k
  if (shared.fNewRawImageDigest.IsValid ())
3153
2
    {
3154
    
3155
2
    SetNewRawImageDigest (shared.fNewRawImageDigest);
3156
    
3157
2
    }
3158
      
3159
  // Raw data unique ID.
3160
  
3161
3.65k
  if (shared.fRawDataUniqueID.IsValid ())
3162
1.08k
    {
3163
    
3164
1.08k
    SetRawDataUniqueID (shared.fRawDataUniqueID);
3165
    
3166
1.08k
    }
3167
      
3168
  // Original raw file name.
3169
  
3170
3.65k
  if (shared.fOriginalRawFileName.NotEmpty ())
3171
78
    {
3172
    
3173
78
    SetOriginalRawFileName (shared.fOriginalRawFileName.Get ());
3174
    
3175
78
    }
3176
    
3177
  // Original raw file data.
3178
  
3179
3.65k
  if (shared.fOriginalRawFileDataCount)
3180
8
    {
3181
    
3182
8
    SetHasOriginalRawFileData (true);
3183
          
3184
8
    if (host.KeepOriginalFile ())
3185
0
      {
3186
      
3187
0
      uint32 count = shared.fOriginalRawFileDataCount;
3188
      
3189
0
      AutoPtr<dng_memory_block> block (host.Allocate (count));
3190
      
3191
0
      stream.SetReadPosition (shared.fOriginalRawFileDataOffset);
3192
    
3193
0
      stream.Get (block->Buffer (), count);
3194
            
3195
0
      SetOriginalRawFileData (block);
3196
      
3197
0
      SetOriginalRawFileDigest (shared.fOriginalRawFileDigest);
3198
      
3199
0
      ValidateOriginalRawFileDigest ();
3200
      
3201
0
      }
3202
      
3203
8
    }
3204
      
3205
  // DNG private data.
3206
  
3207
3.65k
  if (shared.fDNGPrivateDataCount && (host.SaveDNGVersion () != dngVersion_None))
3208
85
    {
3209
    
3210
85
    uint32 length = shared.fDNGPrivateDataCount;
3211
    
3212
85
    AutoPtr<dng_memory_block> block (host.Allocate (length));
3213
    
3214
85
    stream.SetReadPosition (shared.fDNGPrivateDataOffset);
3215
      
3216
85
    stream.Get (block->Buffer (), length);
3217
              
3218
85
    SetPrivateData (block);
3219
      
3220
85
    }
3221
    
3222
  // Hand off EXIF metadata to negative.
3223
  
3224
3.65k
  ResetExif (info.fExif.Release ());
3225
  
3226
  // Parse linearization info.
3227
  
3228
3.65k
  NeedLinearizationInfo ();
3229
  
3230
3.65k
  fLinearizationInfo.Get ()->Parse (host,
3231
3.65k
                      stream,
3232
3.65k
                      info);
3233
                      
3234
  // Parse mosaic info.
3235
  
3236
3.65k
  if (rawIFD.fPhotometricInterpretation == piCFA)
3237
0
    {
3238
  
3239
0
    NeedMosaicInfo ();
3240
    
3241
0
    fMosaicInfo.Get ()->Parse (host,
3242
0
                     stream,
3243
0
                     info);
3244
                
3245
0
    }
3246
              
3247
  // Fill in original sizes.
3248
  
3249
3.65k
  if (shared.fOriginalDefaultFinalSize.h > 0 &&
3250
3.65k
    shared.fOriginalDefaultFinalSize.v > 0)
3251
0
    {
3252
    
3253
0
    SetOriginalDefaultFinalSize (shared.fOriginalDefaultFinalSize);
3254
    
3255
0
    SetOriginalBestQualityFinalSize (shared.fOriginalDefaultFinalSize);
3256
    
3257
0
    SetOriginalDefaultCropSize (dng_urational (shared.fOriginalDefaultFinalSize.h, 1),
3258
0
                  dng_urational (shared.fOriginalDefaultFinalSize.v, 1));
3259
    
3260
0
    }
3261
    
3262
3.65k
  if (shared.fOriginalBestQualityFinalSize.h > 0 &&
3263
3.65k
    shared.fOriginalBestQualityFinalSize.v > 0)
3264
0
    {
3265
    
3266
0
    SetOriginalBestQualityFinalSize (shared.fOriginalBestQualityFinalSize);
3267
    
3268
0
    }
3269
    
3270
3.65k
  if (shared.fOriginalDefaultCropSizeH.As_real64 () >= 1.0 &&
3271
3.65k
    shared.fOriginalDefaultCropSizeV.As_real64 () >= 1.0)
3272
0
    {
3273
    
3274
0
    SetOriginalDefaultCropSize (shared.fOriginalDefaultCropSizeH,
3275
0
                  shared.fOriginalDefaultCropSizeV);
3276
    
3277
0
    }
3278
    
3279
3.65k
  }
3280
3281
/*****************************************************************************/
3282
3283
void dng_negative::SetDefaultOriginalSizes ()
3284
3.61k
  {
3285
  
3286
  // Fill in original sizes if we don't have them already.
3287
  
3288
3.61k
  if (OriginalDefaultFinalSize () == dng_point ())
3289
3.61k
    {
3290
    
3291
3.61k
    SetOriginalDefaultFinalSize (dng_point (DefaultFinalHeight (),
3292
3.61k
                        DefaultFinalWidth  ()));
3293
    
3294
3.61k
    }
3295
    
3296
3.61k
  if (OriginalBestQualityFinalSize () == dng_point ())
3297
3.60k
    {
3298
    
3299
3.60k
    SetOriginalBestQualityFinalSize (dng_point (BestQualityFinalHeight (),
3300
3.60k
                          BestQualityFinalWidth  ()));
3301
    
3302
3.60k
    }
3303
    
3304
3.61k
  if (OriginalDefaultCropSizeH ().NotValid () ||
3305
3.61k
    OriginalDefaultCropSizeV ().NotValid ())
3306
3.59k
    {
3307
    
3308
3.59k
    SetOriginalDefaultCropSize (DefaultCropSizeH (),
3309
3.59k
                  DefaultCropSizeV ());
3310
    
3311
3.59k
    }
3312
3313
3.61k
  }
3314
3315
/*****************************************************************************/
3316
3317
void dng_negative::PostParse (dng_host &host,
3318
                  dng_stream &stream,
3319
                  dng_info &info)
3320
3.61k
  {
3321
  
3322
  // Shared info.
3323
  
3324
3.61k
  dng_shared &shared = *(info.fShared.Get ());
3325
  
3326
3.61k
  if (host.NeedsMeta ())
3327
3.61k
    {
3328
    
3329
    // Fill in original sizes if we don't have them already.
3330
    
3331
3.61k
    SetDefaultOriginalSizes ();
3332
        
3333
    // MakerNote.
3334
    
3335
3.61k
    if (shared.fMakerNoteCount)
3336
358
      {
3337
      
3338
      // See if we know if the MakerNote is safe or not.
3339
      
3340
358
      SetMakerNoteSafety (shared.fMakerNoteSafety == 1);
3341
      
3342
      // If the MakerNote is safe, preserve it as a MakerNote.
3343
      
3344
358
      if (IsMakerNoteSafe ())
3345
110
        {
3346
3347
110
        AutoPtr<dng_memory_block> block (host.Allocate (shared.fMakerNoteCount));
3348
        
3349
110
        stream.SetReadPosition (shared.fMakerNoteOffset);
3350
          
3351
110
        stream.Get (block->Buffer (), shared.fMakerNoteCount);
3352
                  
3353
110
        SetMakerNote (block);
3354
              
3355
110
        }
3356
      
3357
358
      }
3358
    
3359
    // IPTC metadata.
3360
    
3361
3.61k
    if (shared.fIPTC_NAA_Count)
3362
48
      {
3363
      
3364
48
      AutoPtr<dng_memory_block> block (host.Allocate (shared.fIPTC_NAA_Count));
3365
      
3366
48
      stream.SetReadPosition (shared.fIPTC_NAA_Offset);
3367
      
3368
48
      uint64 iptcOffset = stream.PositionInOriginalFile();
3369
      
3370
48
      stream.Get (block->Buffer      (), 
3371
48
            block->LogicalSize ());
3372
      
3373
48
      SetIPTC (block, iptcOffset);
3374
              
3375
48
      }
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
3.61k
    if (!IsMonochrome ())
3411
1.60k
      {
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
1.60k
      if (ColorimetricReference () == crICCProfilePCS)
3418
1.00k
        {
3419
        
3420
1.00k
        ClearCameraNeutral ();
3421
        
3422
1.00k
        SetCameraWhiteXY (PCStoXY ());
3423
        
3424
1.00k
        }
3425
        
3426
592
      else
3427
592
        {
3428
                  
3429
        // AsShotNeutral.
3430
        
3431
592
        if (shared.fAsShotNeutral.Count () == ColorChannels ())
3432
52
          {
3433
          
3434
52
          SetCameraNeutral (shared.fAsShotNeutral);
3435
                    
3436
52
          }
3437
          
3438
        // AsShotWhiteXY.
3439
        
3440
592
        if (shared.fAsShotWhiteXY.IsValid () && !HasCameraNeutral ())
3441
206
          {
3442
          
3443
206
          SetCameraWhiteXY (shared.fAsShotWhiteXY);
3444
          
3445
206
          }
3446
          
3447
592
        }
3448
        
3449
1.60k
      }
3450
          
3451
3.61k
    }
3452
    
3453
3.61k
  }
3454
              
3455
/*****************************************************************************/
3456
3457
bool dng_negative::SetFourColorBayer ()
3458
2.32k
  {
3459
  
3460
2.32k
  if (ColorChannels () != 3)
3461
1.39k
    {
3462
1.39k
    return false;
3463
1.39k
    }
3464
    
3465
922
  if (!fMosaicInfo.Get ())
3466
922
    {
3467
922
    return false;
3468
922
    }
3469
    
3470
0
  if (!fMosaicInfo.Get ()->SetFourColorBayer ())
3471
0
    {
3472
0
    return false;
3473
0
    }
3474
    
3475
0
  SetColorChannels (4);
3476
  
3477
0
  if (fCameraNeutral.Count () == 3)
3478
0
    {
3479
    
3480
0
    dng_vector n (4);
3481
    
3482
0
    n [0] = fCameraNeutral [0];
3483
0
    n [1] = fCameraNeutral [1];
3484
0
    n [2] = fCameraNeutral [2];
3485
0
    n [3] = fCameraNeutral [1];
3486
    
3487
0
    fCameraNeutral = n;
3488
    
3489
0
    }
3490
3491
0
  fCameraCalibration1.Clear ();
3492
0
  fCameraCalibration2.Clear ();
3493
  
3494
0
  fCameraCalibrationSignature.Clear ();
3495
  
3496
0
  for (uint32 index = 0; index < (uint32) fCameraProfile.size (); index++)
3497
0
    {
3498
    
3499
0
    fCameraProfile [index]->SetFourColorBayer ();
3500
    
3501
0
    }
3502
      
3503
0
  return true;
3504
  
3505
0
  }
3506
          
3507
/*****************************************************************************/
3508
3509
const dng_image & dng_negative::RawImage () const
3510
9.78k
  {
3511
  
3512
9.78k
  if (fRawImage.Get ())
3513
8.83k
    {
3514
8.83k
    return *fRawImage.Get ();
3515
8.83k
    }
3516
    
3517
948
  if (fStage1Image.Get ())
3518
948
    {
3519
948
    return *fStage1Image.Get ();
3520
948
    }
3521
    
3522
0
  if (fUnflattenedStage3Image.Get ())
3523
0
    {
3524
0
    return *fUnflattenedStage3Image.Get ();
3525
0
    }
3526
    
3527
0
  DNG_ASSERT (fStage3Image.Get (),
3528
0
        "dng_negative::RawImage with no raw image");
3529
        
3530
0
  return *fStage3Image.Get ();
3531
  
3532
0
  }
3533
3534
/*****************************************************************************/
3535
3536
const dng_jpeg_image * dng_negative::RawJPEGImage () const
3537
11.4k
  {
3538
3539
11.4k
  return fRawJPEGImage.Get ();
3540
3541
11.4k
  }
3542
3543
/*****************************************************************************/
3544
3545
void dng_negative::SetRawJPEGImage (AutoPtr<dng_jpeg_image> &jpegImage)
3546
1.59k
  {
3547
3548
1.59k
  fRawJPEGImage.Reset (jpegImage.Release ());
3549
3550
1.59k
  }
3551
3552
/*****************************************************************************/
3553
3554
void dng_negative::ClearRawJPEGImage ()
3555
2.20k
  {
3556
  
3557
2.20k
  fRawJPEGImage.Reset ();
3558
3559
2.20k
  }
3560
3561
/*****************************************************************************/
3562
3563
void dng_negative::FindRawJPEGImageDigest (dng_host &host) const
3564
3.17k
  {
3565
  
3566
3.17k
  if (fRawJPEGImageDigest.IsNull ())
3567
1.59k
    {
3568
    
3569
1.59k
    if (fRawJPEGImage.Get ())
3570
1.59k
      {
3571
      
3572
      #if qDNGValidate
3573
      
3574
      dng_timer timer ("FindRawJPEGImageDigest time");
3575
       
3576
      #endif
3577
      
3578
1.59k
      fRawJPEGImageDigest = fRawJPEGImage->FindDigest (host);
3579
      
3580
1.59k
      }
3581
      
3582
0
    else
3583
0
      {
3584
      
3585
0
      ThrowProgramError ("No raw JPEG image");
3586
      
3587
0
      }
3588
    
3589
1.59k
    }
3590
  
3591
3.17k
  }
3592
    
3593
/*****************************************************************************/
3594
3595
void dng_negative::ReadStage1Image (dng_host &host,
3596
                  dng_stream &stream,
3597
                  dng_info &info)
3598
3.59k
  {
3599
  
3600
  // Allocate image we are reading.
3601
  
3602
3.59k
  dng_ifd &rawIFD = *info.fIFD [info.fMainIndex].Get ();
3603
  
3604
3.59k
  fStage1Image.Reset (host.Make_dng_image (rawIFD.Bounds (),
3605
3.59k
                       rawIFD.fSamplesPerPixel,
3606
3.59k
                       rawIFD.PixelType ()));
3607
          
3608
  // See if we should grab the compressed JPEG data.
3609
  
3610
3.59k
  AutoPtr<dng_jpeg_image> jpegImage;
3611
  
3612
3.59k
  if (host.SaveDNGVersion () >= dngVersion_1_4_0_0 &&
3613
3.59k
    !host.PreferredSize () &&
3614
3.59k
    !host.ForPreview () &&
3615
3.59k
    rawIFD.fCompression == ccLossyJPEG)
3616
2
    {
3617
    
3618
2
    jpegImage.Reset (new dng_jpeg_image);
3619
    
3620
2
    }
3621
    
3622
  // See if we need to compute the digest of the compressed JPEG data
3623
  // while reading.
3624
  
3625
3.59k
  bool needJPEGDigest = (RawImageDigest    ().IsValid () ||
3626
3.59k
               NewRawImageDigest ().IsValid ()) &&
3627
3.59k
              rawIFD.fCompression == ccLossyJPEG &&
3628
3.59k
              jpegImage.Get () == NULL;
3629
  
3630
3.59k
  dng_fingerprint jpegDigest;
3631
  
3632
  // Read the image.
3633
  
3634
3.59k
  rawIFD.ReadImage (host,
3635
3.59k
            stream,
3636
3.59k
            *fStage1Image.Get (),
3637
3.59k
            jpegImage.Get (),
3638
3.59k
            needJPEGDigest ? &jpegDigest : NULL);
3639
            
3640
  // Remember the raw floating point bit depth, if reading from
3641
  // a floating point image.
3642
  
3643
3.59k
  if (fStage1Image->PixelType () == ttFloat)
3644
225
    {
3645
    
3646
225
    SetRawFloatBitDepth (rawIFD.fBitsPerSample [0]);
3647
    
3648
225
    }
3649
            
3650
  // Remember the compressed JPEG data if we read it.
3651
  
3652
3.59k
  if (jpegImage.Get ())
3653
0
    {
3654
        
3655
0
    SetRawJPEGImage (jpegImage);
3656
        
3657
0
    }
3658
    
3659
  // Remember the compressed JPEG digest if we computed it.
3660
  
3661
3.59k
  if (jpegDigest.IsValid ())
3662
0
    {
3663
    
3664
0
    SetRawJPEGImageDigest (jpegDigest);
3665
    
3666
0
    }
3667
            
3668
  // We are are reading the main image, we should read the opcode lists
3669
  // also.
3670
  
3671
3.59k
  if (rawIFD.fOpcodeList1Count)
3672
30
    {
3673
    
3674
    #if qDNGValidate
3675
    
3676
    if (gVerbose)
3677
      {
3678
      printf ("\nParsing OpcodeList1: ");
3679
      }
3680
      
3681
    #endif
3682
    
3683
30
    fOpcodeList1.Parse (host,
3684
30
              stream,
3685
30
              rawIFD.fOpcodeList1Count,
3686
30
              rawIFD.fOpcodeList1Offset);
3687
    
3688
30
    }
3689
    
3690
3.59k
  if (rawIFD.fOpcodeList2Count)
3691
246
    {
3692
    
3693
    #if qDNGValidate
3694
    
3695
    if (gVerbose)
3696
      {
3697
      printf ("\nParsing OpcodeList2: ");
3698
      }
3699
      
3700
    #endif
3701
    
3702
246
    fOpcodeList2.Parse (host,
3703
246
              stream,
3704
246
              rawIFD.fOpcodeList2Count,
3705
246
              rawIFD.fOpcodeList2Offset);
3706
    
3707
246
    }
3708
3709
3.59k
  if (rawIFD.fOpcodeList3Count)
3710
26
    {
3711
    
3712
    #if qDNGValidate
3713
    
3714
    if (gVerbose)
3715
      {
3716
      printf ("\nParsing OpcodeList3: ");
3717
      }
3718
      
3719
    #endif
3720
    
3721
26
    fOpcodeList3.Parse (host,
3722
26
              stream,
3723
26
              rawIFD.fOpcodeList3Count,
3724
26
              rawIFD.fOpcodeList3Offset);
3725
    
3726
26
    }
3727
3728
3.59k
  }
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
2.31k
  {
3761
  
3762
2.31k
  dng_image &stage1 = *fStage1Image.Get ();
3763
    
3764
2.31k
  dng_linearization_info &info = *fLinearizationInfo.Get ();
3765
  
3766
2.31k
  uint32 pixelType = ttShort;
3767
  
3768
2.31k
  if (stage1.PixelType () == ttLong ||
3769
2.31k
    stage1.PixelType () == ttFloat)
3770
631
    {
3771
    
3772
631
    pixelType = ttFloat;
3773
    
3774
631
    }
3775
  
3776
2.31k
  fStage2Image.Reset (host.Make_dng_image (info.fActiveArea.Size (),
3777
2.31k
                       stage1.Planes (),
3778
2.31k
                       pixelType));
3779
                   
3780
2.31k
  info.Linearize (host,
3781
2.31k
          stage1,
3782
2.31k
          *fStage2Image.Get ());
3783
               
3784
2.31k
  }
3785
    
3786
/*****************************************************************************/
3787
3788
void dng_negative::DoPostOpcodeList2 (dng_host & /* host */)
3789
2.27k
  {
3790
  
3791
  // Nothing by default.
3792
  
3793
2.27k
  }
3794
3795
/*****************************************************************************/
3796
3797
bool dng_negative::NeedDefloatStage2 (dng_host &host)
3798
2.27k
  {
3799
  
3800
2.27k
  if (fStage2Image->PixelType () == ttFloat)
3801
629
    {
3802
    
3803
629
    if (fRawImageStage >= rawImageStagePostOpcode2 &&
3804
629
      host.SaveDNGVersion () != dngVersion_None  &&
3805
629
      host.SaveDNGVersion () <  dngVersion_1_4_0_0)
3806
0
      {
3807
      
3808
0
      return true;
3809
      
3810
0
      }
3811
    
3812
629
    }
3813
  
3814
2.27k
  return false;
3815
  
3816
2.27k
  }
3817
    
3818
/*****************************************************************************/
3819
3820
void dng_negative::DefloatStage2 (dng_host & /* host */)
3821
0
  {
3822
  
3823
0
  ThrowNotYetImplemented ("dng_negative::DefloatStage2");
3824
  
3825
0
  }
3826
    
3827
/*****************************************************************************/
3828
3829
void dng_negative::BuildStage2Image (dng_host &host)
3830
2.32k
  {
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
2.32k
  if (host.SaveDNGVersion () != dngVersion_None)
3836
2.32k
    {
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
2.32k
    if (TransparencyMask () && host.SaveDNGVersion () < dngVersion_1_4_0_0)
3843
0
      {
3844
0
      fRawImageStage = rawImageStagePostOpcode3;
3845
0
      }
3846
    
3847
2.32k
    else if (fOpcodeList3.MinVersion (false) > host.SaveDNGVersion () ||
3848
2.32k
           fOpcodeList3.AlwaysApply ())
3849
17
      {
3850
17
      fRawImageStage = rawImageStagePostOpcode3;
3851
17
      }
3852
      
3853
2.30k
    else if (host.SaveLinearDNG (*this))
3854
0
      {
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
0
      if (fOpcodeList3.MinVersion (true) > host.SaveDNGVersion ())
3861
0
        {
3862
0
        fRawImageStage = rawImageStagePostOpcode3;
3863
0
        }
3864
        
3865
0
      else
3866
0
        {
3867
0
        fRawImageStage = rawImageStagePreOpcode3;
3868
0
        }
3869
      
3870
0
      }
3871
      
3872
2.30k
    else if (fOpcodeList2.MinVersion (false) > host.SaveDNGVersion () ||
3873
2.30k
         fOpcodeList2.AlwaysApply ())
3874
9
      {
3875
9
      fRawImageStage = rawImageStagePostOpcode2;
3876
9
      }
3877
      
3878
2.29k
    else if (fOpcodeList1.MinVersion (false) > host.SaveDNGVersion () ||
3879
2.29k
         fOpcodeList1.AlwaysApply ())
3880
3
      {
3881
3
      fRawImageStage = rawImageStagePostOpcode1;
3882
3
      }
3883
      
3884
2.29k
    else
3885
2.29k
      {
3886
2.29k
      fRawImageStage = rawImageStagePreOpcode1;
3887
2.29k
      }
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
2.32k
    if (fStage1Image->PixelType () == ttFloat)
3895
223
      {
3896
      
3897
223
      if (fRawImageStage < rawImageStagePostOpcode2)
3898
223
        {
3899
        
3900
223
        if (host.SaveDNGVersion () < dngVersion_1_4_0_0)
3901
0
          {
3902
          
3903
0
          fRawImageStage = rawImageStagePostOpcode2;
3904
          
3905
0
          }
3906
          
3907
223
        }
3908
        
3909
223
      }
3910
      
3911
2.32k
    }
3912
    
3913
  // Grab clone of raw image if required.
3914
  
3915
2.32k
  if (fRawImageStage == rawImageStagePreOpcode1)
3916
2.29k
    {
3917
    
3918
2.29k
    fRawImage.Reset (fStage1Image->Clone ());
3919
    
3920
2.29k
    if (fTransparencyMask.Get ())
3921
0
      {
3922
0
      fRawTransparencyMask.Reset (fTransparencyMask->Clone ());
3923
0
      }
3924
    
3925
2.29k
    }
3926
3927
29
  else
3928
29
    {
3929
    
3930
    // If we are not keeping the most raw image, we need
3931
    // to recompute the raw image digest.
3932
    
3933
29
    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
29
    ClearRawJPEGImage ();
3939
    
3940
    // Nor is the digest of the raw JPEG data.
3941
    
3942
29
    ClearRawJPEGImageDigest ();
3943
    
3944
    // We also don't know the raw floating point bit depth.
3945
    
3946
29
    SetRawFloatBitDepth (0);
3947
    
3948
29
    }
3949
    
3950
  // Process opcode list 1.
3951
  
3952
2.32k
  host.ApplyOpcodeList (fOpcodeList1, *this, fStage1Image);
3953
  
3954
  // See if we are done with the opcode list 1.
3955
  
3956
2.32k
  if (fRawImageStage > rawImageStagePreOpcode1)
3957
26
    {
3958
    
3959
26
    fOpcodeList1.Clear ();
3960
    
3961
26
    }
3962
  
3963
  // Grab clone of raw image if required.
3964
  
3965
2.32k
  if (fRawImageStage == rawImageStagePostOpcode1)
3966
0
    {
3967
    
3968
0
    fRawImage.Reset (fStage1Image->Clone ());
3969
    
3970
0
    if (fTransparencyMask.Get ())
3971
0
      {
3972
0
      fRawTransparencyMask.Reset (fTransparencyMask->Clone ());
3973
0
      }
3974
    
3975
0
    }
3976
3977
  // Finalize linearization info.
3978
  
3979
2.32k
    {
3980
  
3981
2.32k
    NeedLinearizationInfo ();
3982
  
3983
2.32k
    dng_linearization_info &info = *fLinearizationInfo.Get ();
3984
    
3985
2.32k
    info.PostParse (host, *this);
3986
    
3987
2.32k
    }
3988
    
3989
  // Perform the linearization.
3990
  
3991
2.32k
  DoBuildStage2 (host);
3992
    
3993
  // Delete the stage1 image now that we have computed the stage 2 image.
3994
  
3995
2.32k
  fStage1Image.Reset ();
3996
  
3997
  // Are we done with the linearization info.
3998
  
3999
2.32k
  if (fRawImageStage > rawImageStagePostOpcode1)
4000
26
    {
4001
    
4002
26
    ClearLinearizationInfo ();
4003
    
4004
26
    }
4005
  
4006
  // Process opcode list 2.
4007
  
4008
2.32k
  host.ApplyOpcodeList (fOpcodeList2, *this, fStage2Image);
4009
  
4010
  // See if we are done with the opcode list 2.
4011
  
4012
2.32k
  if (fRawImageStage > rawImageStagePostOpcode1)
4013
19
    {
4014
    
4015
19
    fOpcodeList2.Clear ();
4016
    
4017
19
    }
4018
    
4019
  // Hook for any required processing just after opcode list 2.
4020
  
4021
2.32k
  DoPostOpcodeList2 (host);
4022
    
4023
  // Convert from floating point to integer if required.
4024
  
4025
2.32k
  if (NeedDefloatStage2 (host))
4026
0
    {
4027
    
4028
0
    DefloatStage2 (host);
4029
    
4030
0
    }
4031
    
4032
  // Grab clone of raw image if required.
4033
  
4034
2.32k
  if (fRawImageStage == rawImageStagePostOpcode2)
4035
2
    {
4036
    
4037
2
    fRawImage.Reset (fStage2Image->Clone ());
4038
    
4039
2
    if (fTransparencyMask.Get ())
4040
0
      {
4041
0
      fRawTransparencyMask.Reset (fTransparencyMask->Clone ());
4042
0
      }
4043
    
4044
2
    }
4045
  
4046
2.32k
  }
4047
                    
4048
/*****************************************************************************/
4049
4050
void dng_negative::DoInterpolateStage3 (dng_host &host,
4051
                        int32 srcPlane)
4052
0
  {
4053
  
4054
0
  dng_image &stage2 = *fStage2Image.Get ();
4055
    
4056
0
  dng_mosaic_info &info = *fMosaicInfo.Get ();
4057
  
4058
0
  dng_point downScale = info.DownScale (host.MinimumSize   (),
4059
0
                      host.PreferredSize (),
4060
0
                      host.CropFactor    ());
4061
  
4062
0
  if (downScale != dng_point (1, 1))
4063
0
    {
4064
0
    SetIsPreview (true);
4065
0
    }
4066
  
4067
0
  dng_point dstSize = info.DstSize (downScale);
4068
      
4069
0
  fStage3Image.Reset (host.Make_dng_image (dng_rect (dstSize),
4070
0
                       info.fColorPlanes,
4071
0
                       stage2.PixelType ()));
4072
4073
0
  if (srcPlane < 0 || srcPlane >= (int32) stage2.Planes ())
4074
0
    {
4075
0
    srcPlane = 0;
4076
0
    }
4077
        
4078
0
  info.Interpolate (host,
4079
0
            *this,
4080
0
            stage2,
4081
0
            *fStage3Image.Get (),
4082
0
            downScale,
4083
0
            srcPlane);
4084
4085
0
  }
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
2.27k
  {
4111
  
4112
  // If we don't have a mosaic pattern, then just move the stage 2
4113
  // image on to stage 3.
4114
  
4115
2.27k
  dng_mosaic_info *info = fMosaicInfo.Get ();
4116
4117
2.27k
  if (!info || !info->IsColorFilterArray ())
4118
2.27k
    {
4119
    
4120
2.27k
    fStage3Image.Reset (fStage2Image.Release ());
4121
    
4122
2.27k
    }
4123
    
4124
0
  else
4125
0
    {
4126
    
4127
    // Remember the size of the stage 2 image.
4128
    
4129
0
    dng_point stage2_size = fStage2Image->Size ();
4130
    
4131
    // Special case multi-channel CFA interpolation.
4132
    
4133
0
    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
0
    else
4143
0
      {
4144
        
4145
0
      DoInterpolateStage3 (host, srcPlane);
4146
               
4147
0
      }
4148
    
4149
    // Calculate the ratio of the stage 3 image size to stage 2 image size.
4150
    
4151
0
    dng_point stage3_size = fStage3Image->Size ();
4152
    
4153
0
    fRawToFullScaleH = (real64) stage3_size.h / (real64) stage2_size.h;
4154
0
    fRawToFullScaleV = (real64) stage3_size.v / (real64) stage2_size.v;
4155
    
4156
0
    }
4157
4158
2.27k
  }
4159
                     
4160
/*****************************************************************************/
4161
4162
void dng_negative::BuildStage3Image (dng_host &host,
4163
                   int32 srcPlane)
4164
2.27k
  {
4165
  
4166
  // Finalize the mosaic information.
4167
  
4168
2.27k
  dng_mosaic_info *info = fMosaicInfo.Get ();
4169
  
4170
2.27k
  if (info)
4171
0
    {
4172
    
4173
0
    info->PostParse (host, *this);
4174
    
4175
0
    }
4176
    
4177
  // Do the interpolation as required.
4178
  
4179
2.27k
  DoBuildStage3 (host, srcPlane);
4180
  
4181
  // Delete the stage2 image now that we have computed the stage 3 image.
4182
  
4183
2.27k
  fStage2Image.Reset ();
4184
  
4185
  // Are we done with the mosaic info?
4186
  
4187
2.27k
  if (fRawImageStage >= rawImageStagePreOpcode3)
4188
17
    {
4189
    
4190
17
    ClearMosaicInfo ();
4191
    
4192
    // To support saving linear DNG files, to need to account for
4193
    // and upscaling during interpolation.
4194
4195
17
    if (fRawToFullScaleH > 1.0)
4196
0
      {
4197
      
4198
0
      uint32 adjust = Round_uint32 (fRawToFullScaleH);
4199
      
4200
0
      fDefaultCropSizeH  .n =
4201
0
        SafeUint32Mult (fDefaultCropSizeH.n, adjust);
4202
0
      fDefaultCropOriginH.n =
4203
0
        SafeUint32Mult (fDefaultCropOriginH.n, adjust);
4204
0
      fDefaultScaleH     .d = SafeUint32Mult (fDefaultScaleH.d, adjust);
4205
      
4206
0
      fRawToFullScaleH /= (real64) adjust;
4207
      
4208
0
      }
4209
    
4210
17
    if (fRawToFullScaleV > 1.0)
4211
0
      {
4212
      
4213
0
      uint32 adjust = Round_uint32 (fRawToFullScaleV);
4214
      
4215
0
      fDefaultCropSizeV  .n =
4216
0
        SafeUint32Mult (fDefaultCropSizeV.n, adjust);
4217
0
      fDefaultCropOriginV.n =
4218
0
        SafeUint32Mult (fDefaultCropOriginV.n, adjust);
4219
0
      fDefaultScaleV     .d =
4220
0
        SafeUint32Mult (fDefaultScaleV.d, adjust);
4221
      
4222
0
      fRawToFullScaleV /= (real64) adjust;
4223
      
4224
0
      }
4225
4226
17
    }
4227
    
4228
  // Resample the transparency mask if required.
4229
  
4230
2.27k
  ResizeTransparencyToMatchStage3 (host);
4231
      
4232
  // Grab clone of raw image if required.
4233
  
4234
2.27k
  if (fRawImageStage == rawImageStagePreOpcode3)
4235
0
    {
4236
    
4237
0
    fRawImage.Reset (fStage3Image->Clone ());
4238
    
4239
0
    if (fTransparencyMask.Get ())
4240
0
      {
4241
0
      fRawTransparencyMask.Reset (fTransparencyMask->Clone ());
4242
0
      }
4243
4244
0
    }
4245
    
4246
  // Process opcode list 3.
4247
  
4248
2.27k
  host.ApplyOpcodeList (fOpcodeList3, *this, fStage3Image);
4249
  
4250
  // See if we are done with the opcode list 3.
4251
  
4252
2.27k
  if (fRawImageStage > rawImageStagePreOpcode3)
4253
0
    {
4254
    
4255
0
    fOpcodeList3.Clear ();
4256
    
4257
0
    }
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
2.27k
  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
2.27k
  }
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
3.08k
      : fBlack (black)
4292
3.08k
      , fWhite (white)
4293
3.08k
      , fIsSceneReferred (isSceneReferred)
4294
      
4295
3.08k
      , scale (1.0 / (fWhite - fBlack))
4296
3.08k
      , t1 (1.0 / (27.0 * pow (5.0, 3.0 / 2.0)))
4297
      
4298
3.08k
      {
4299
3.08k
      }
4300
      
4301
    virtual real64 Evaluate (real64 x) const
4302
12.6M
      {
4303
      
4304
12.6M
      x = Pin_real64 (0.0, (x - fBlack) * scale, 1.0);
4305
      
4306
12.6M
      real64 y;
4307
      
4308
12.6M
      if (fIsSceneReferred)
4309
5.63M
        {
4310
      
4311
5.63M
        real64 t = pow (sqrt (25920.0 * x * x + 1.0) * t1 + x * (8.0 / 15.0), 1.0 / 3.0);
4312
        
4313
5.63M
        y = t - 1.0 / (45.0 * t);
4314
        
4315
5.63M
        DNG_ASSERT (Abs_real64 (x - (y / 16.0 + y * y * y * 15.0 / 16.0)) < 0.0000001,
4316
5.63M
              "Round trip error");
4317
              
4318
5.63M
        }
4319
        
4320
7.00M
      else
4321
7.00M
        {
4322
        
4323
7.00M
        y = (sqrt (960.0 * x + 1.0) - 1.0) / 30.0;
4324
        
4325
7.00M
        DNG_ASSERT (Abs_real64 (x - (y / 16.0 + y * y * (15.0 / 16.0))) < 0.0000001,
4326
7.00M
              "Round trip error");
4327
              
4328
7.00M
        }
4329
        
4330
12.6M
      return y;
4331
      
4332
12.6M
      }
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
3.19k
      {
4360
3.19k
      return fSrcImage.RepeatingTile ();
4361
3.19k
      }
4362
      
4363
    virtual dng_rect RepeatingTile2 () const
4364
3.19k
      {
4365
3.19k
      return fDstImage.RepeatingTile ();
4366
3.19k
      }
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
1.59k
  : fSrcImage (srcImage)
4392
1.59k
  , fDstImage (dstImage)
4393
  
4394
1.59k
  {
4395
  
4396
4.68k
  for (uint32 plane = 0; plane < fSrcImage.Planes (); plane++)
4397
3.08k
    {
4398
    
4399
3.08k
    dng_gamma_encode_proxy gamma (black [plane],
4400
3.08k
                    white [plane],
4401
3.08k
                    isSceneReferred);
4402
                    
4403
3.08k
    dng_1d_table table32;
4404
    
4405
3.08k
    table32.Initialize (host.Allocator (), gamma);
4406
    
4407
3.08k
    fTable16 [plane] . Reset (host.Allocate (0x10000 * sizeof (uint16)));
4408
    
4409
3.08k
    table32.Expand16 (fTable16 [plane]->Buffer_uint16 ());
4410
                     
4411
3.08k
    }
4412
    
4413
1.59k
  }
4414
4415
/*****************************************************************************/
4416
4417
void dng_encode_proxy_task::Process (uint32 /* threadIndex */,
4418
                     const dng_rect &tile,
4419
                       dng_abort_sniffer * /* sniffer */)
4420
4.07k
  {
4421
  
4422
4.07k
  dng_const_tile_buffer srcBuffer (fSrcImage, tile);
4423
4.07k
  dng_dirty_tile_buffer dstBuffer (fDstImage, tile);
4424
  
4425
4.07k
  int32 sColStep = srcBuffer.fColStep;
4426
4.07k
  int32 dColStep = dstBuffer.fColStep;
4427
  
4428
4.07k
  const uint16 *noise = dng_dither::Get ().NoiseBuffer16 ();
4429
  
4430
12.8k
  for (uint32 plane = 0; plane < fSrcImage.Planes (); plane++)
4431
8.77k
    {
4432
    
4433
8.77k
    const uint16 *map = fTable16 [plane]->Buffer_uint16 ();
4434
    
4435
1.23M
    for (int32 row = tile.t; row < tile.b; row++)
4436
1.22M
      {
4437
      
4438
1.22M
      const uint16 *sPtr = srcBuffer.ConstPixel_uint16 (row, tile.l, plane);
4439
      
4440
1.22M
      uint8 *dPtr = dstBuffer.DirtyPixel_uint8 (row, tile.l, plane);
4441
      
4442
1.22M
      const uint16 *rPtr = &noise [(row & dng_dither::kRNGMask) * dng_dither::kRNGSize];
4443
4444
174M
      for (int32 col = tile.l; col < tile.r; col++)
4445
173M
        {
4446
        
4447
173M
        uint32 x = *sPtr;
4448
        
4449
173M
        uint32 r = rPtr [col & dng_dither::kRNGMask];
4450
        
4451
173M
        x = map [x];
4452
        
4453
173M
        x = (((x << 8) - x) + r) >> 16;
4454
        
4455
173M
        *dPtr = (uint8) x;
4456
        
4457
173M
        sPtr += sColStep;
4458
173M
        dPtr += dColStep;
4459
        
4460
173M
        }
4461
      
4462
1.22M
      }
4463
      
4464
8.77k
    }
4465
    
4466
4.07k
  }
4467
                  
4468
/******************************************************************************/
4469
4470
dng_image * dng_negative::EncodeRawProxy (dng_host &host,
4471
                      const dng_image &srcImage,
4472
                      dng_opcode_list &opcodeList) const
4473
1.61k
  {
4474
  
4475
1.61k
  if (srcImage.PixelType () != ttShort)
4476
0
    {
4477
0
    return NULL;
4478
0
    }
4479
    
4480
1.61k
  real64 black [kMaxColorPlanes];
4481
1.61k
  real64 white [kMaxColorPlanes];
4482
  
4483
1.61k
  bool isSceneReferred = (ColorimetricReference () == crSceneReferred);
4484
  
4485
1.61k
    {
4486
    
4487
1.61k
    const real64 kClipFraction = 0.00001;
4488
  
4489
1.61k
    uint64 pixels = (uint64) srcImage.Bounds ().H () *
4490
1.61k
            (uint64) srcImage.Bounds ().W ();
4491
            
4492
1.61k
    uint32 limit = Round_int32 ((real64) pixels * kClipFraction);
4493
    
4494
1.61k
    AutoPtr<dng_memory_block> histData (host.Allocate (65536 * sizeof (uint32)));
4495
    
4496
1.61k
    uint32 *hist = histData->Buffer_uint32 ();
4497
      
4498
4.74k
    for (uint32 plane = 0; plane < srcImage.Planes (); plane++)
4499
3.12k
      {
4500
      
4501
3.12k
      HistogramArea (host,
4502
3.12k
               srcImage,
4503
3.12k
               srcImage.Bounds (),
4504
3.12k
               hist,
4505
3.12k
               65535,
4506
3.12k
               plane);
4507
               
4508
3.12k
      uint32 total = 0;
4509
4510
3.12k
      uint32 upper = 65535;
4511
4512
30.6M
      while (total + hist [upper] <= limit && upper > 255)
4513
30.6M
        {
4514
        
4515
30.6M
        total += hist [upper];
4516
        
4517
30.6M
        upper--;
4518
        
4519
30.6M
        }
4520
  
4521
3.12k
      total = 0;
4522
      
4523
3.12k
      uint32 lower = 0;
4524
      
4525
11.6M
      while (total + hist [lower] <= limit && lower < upper - 255)
4526
11.6M
        {
4527
        
4528
11.6M
        total += hist [lower];
4529
        
4530
11.6M
        lower++;
4531
        
4532
11.6M
        }
4533
      
4534
3.12k
      black [plane] = lower / 65535.0;
4535
3.12k
      white [plane] = upper / 65535.0;
4536
    
4537
3.12k
      }
4538
      
4539
1.61k
    }
4540
    
4541
  // Apply the gamma encoding, using dither when downsampling to 8-bit.
4542
  
4543
1.61k
  AutoPtr<dng_image> dstImage (host.Make_dng_image (srcImage.Bounds (),
4544
1.61k
                            srcImage.Planes (),
4545
1.61k
                            ttByte));
4546
4547
1.61k
    {
4548
    
4549
1.61k
    dng_encode_proxy_task task (host,
4550
1.61k
                      srcImage,
4551
1.61k
                  *dstImage,
4552
1.61k
                  black,
4553
1.61k
                  white,
4554
1.61k
                  isSceneReferred);
4555
    
4556
1.61k
    host.PerformAreaTask (task,
4557
1.61k
                srcImage.Bounds ());
4558
  
4559
1.61k
    }
4560
          
4561
  // Add opcodes to undo the gamma encoding.
4562
  
4563
1.61k
    {
4564
  
4565
4.70k
    for (uint32 plane = 0; plane < srcImage.Planes (); plane++)
4566
3.08k
      {
4567
      
4568
3.08k
      dng_area_spec areaSpec (srcImage.Bounds (),
4569
3.08k
                  plane);
4570
      
4571
3.08k
      real64 coefficient [4];
4572
      
4573
3.08k
      coefficient [0] = 0.0;
4574
3.08k
      coefficient [1] = 1.0 / 16.0;
4575
      
4576
3.08k
      if (isSceneReferred)
4577
1.37k
        {
4578
1.37k
        coefficient [2] = 0.0;
4579
1.37k
        coefficient [3] = 15.0 / 16.0;
4580
1.37k
        }
4581
1.71k
      else
4582
1.71k
        {
4583
1.71k
        coefficient [2] = 15.0 / 16.0;
4584
1.71k
        coefficient [3] = 0.0;
4585
1.71k
        }
4586
      
4587
3.08k
      coefficient [0] *= white [plane] - black [plane];
4588
3.08k
      coefficient [1] *= white [plane] - black [plane];
4589
3.08k
      coefficient [2] *= white [plane] - black [plane];
4590
3.08k
      coefficient [3] *= white [plane] - black [plane];
4591
      
4592
3.08k
      coefficient [0] += black [plane];
4593
      
4594
3.08k
      AutoPtr<dng_opcode> opcode (new dng_opcode_MapPolynomial (areaSpec,
4595
3.08k
                                    isSceneReferred ? 3 : 2,
4596
3.08k
                                    coefficient));
4597
                                    
4598
3.08k
      opcodeList.Append (opcode);
4599
      
4600
3.08k
      }
4601
      
4602
1.61k
    }
4603
    
4604
1.61k
  return dstImage.Release ();
4605
  
4606
1.61k
  }
4607
                    
4608
/******************************************************************************/
4609
4610
void dng_negative::AdjustProfileForStage3 ()
4611
2.17k
  {
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
2.17k
  }
4617
                    
4618
/******************************************************************************/
4619
4620
void dng_negative::ConvertToProxy (dng_host &host,
4621
                   dng_image_writer &writer,
4622
                   uint32 proxySize,
4623
                   uint64 proxyCount)
4624
2.25k
  {
4625
  
4626
2.25k
  if (!proxySize)
4627
0
    {
4628
0
    proxySize = kMaxImageSide;
4629
0
    }
4630
  
4631
2.25k
  if (!proxyCount)
4632
2.25k
    {
4633
2.25k
    proxyCount = (uint64) proxySize * proxySize;
4634
2.25k
    }
4635
  
4636
  // Don't need to private data around in non-full size proxies.
4637
  
4638
2.25k
  if (proxySize  < kMaxImageSide ||
4639
2.25k
    proxyCount < kMaxImageSide * kMaxImageSide)
4640
2.25k
    {
4641
  
4642
2.25k
    ClearMakerNote ();
4643
    
4644
2.25k
    ClearPrivateData ();
4645
    
4646
2.25k
    }
4647
  
4648
  // See if we already have an acceptable proxy image.
4649
  
4650
2.25k
  if (fRawImage.Get () &&
4651
2.25k
    fRawImage->PixelType () == ttByte &&
4652
2.25k
    fRawImage->Bounds () == DefaultCropArea () &&
4653
2.25k
    fRawImage->Bounds ().H () <= proxySize &&
4654
2.25k
    fRawImage->Bounds ().W () <= proxySize &&
4655
2.25k
    (uint64) fRawImage->Bounds ().H () *
4656
586
    (uint64) fRawImage->Bounds ().W () <= proxyCount &&
4657
2.25k
    (!GetMosaicInfo () || !GetMosaicInfo ()->IsColorFilterArray ()) &&
4658
2.25k
    fRawJPEGImage.Get () &&
4659
2.25k
    (!RawTransparencyMask () || RawTransparencyMask ()->PixelType () == ttByte))
4660
0
    {
4661
    
4662
0
    return;
4663
    
4664
0
    }
4665
    
4666
2.25k
  if (fRawImage.Get () &&
4667
2.25k
    fRawImage->PixelType () == ttFloat &&
4668
2.25k
    fRawImage->Bounds ().H () <= proxySize &&
4669
2.25k
    fRawImage->Bounds ().W () <= proxySize &&
4670
2.25k
    (uint64) fRawImage->Bounds ().H () *
4671
142
    (uint64) fRawImage->Bounds ().W () <= proxyCount &&
4672
2.25k
    RawFloatBitDepth () == 16 &&
4673
2.25k
    (!RawTransparencyMask () || RawTransparencyMask ()->PixelType () == ttByte))
4674
83
    {
4675
    
4676
83
    return;
4677
    
4678
83
    }
4679
  
4680
  // Clear any grabbed raw image, since we are going to start
4681
  // building the proxy with the stage3 image.
4682
4683
2.17k
  fRawImage.Reset ();
4684
  
4685
2.17k
  ClearRawJPEGImage ();
4686
  
4687
2.17k
  SetRawFloatBitDepth (0);
4688
  
4689
2.17k
  ClearLinearizationInfo ();
4690
  
4691
2.17k
  ClearMosaicInfo ();
4692
  
4693
2.17k
  fOpcodeList1.Clear ();
4694
2.17k
  fOpcodeList2.Clear ();
4695
2.17k
  fOpcodeList3.Clear ();
4696
  
4697
  // Adjust the profile to match the stage 3 image, if required.
4698
  
4699
2.17k
  AdjustProfileForStage3 ();
4700
  
4701
  // Not saving the raw-most image, do the old raw digest is no
4702
  // longer valid.
4703
    
4704
2.17k
  ClearRawImageDigest ();
4705
  
4706
2.17k
  ClearRawJPEGImageDigest ();
4707
  
4708
  // Trim off extra pixels outside the default crop area.
4709
  
4710
2.17k
  dng_rect defaultCropArea = DefaultCropArea ();
4711
  
4712
2.17k
  if (Stage3Image ()->Bounds () != defaultCropArea)
4713
177
    {
4714
    
4715
177
    fStage3Image->Trim (defaultCropArea);
4716
    
4717
177
    if (fTransparencyMask.Get ())
4718
0
      {
4719
0
      fTransparencyMask->Trim (defaultCropArea);
4720
0
      }
4721
    
4722
177
    fDefaultCropOriginH = dng_urational (0, 1);
4723
177
    fDefaultCropOriginV = dng_urational (0, 1);
4724
    
4725
177
    }
4726
    
4727
  // Figure out the requested proxy pixel size.
4728
  
4729
2.17k
  real64 aspectRatio = AspectRatio ();
4730
  
4731
2.17k
  dng_point newSize (proxySize, proxySize);
4732
  
4733
2.17k
  if (aspectRatio >= 1.0)
4734
1.13k
    {
4735
1.13k
    newSize.v = Max_int32 (1, Round_int32 (proxySize / aspectRatio));
4736
1.13k
    }
4737
1.03k
  else
4738
1.03k
    {
4739
1.03k
    newSize.h = Max_int32 (1, Round_int32 (proxySize * aspectRatio));
4740
1.03k
    }
4741
    
4742
2.17k
  newSize.v = Min_int32 (newSize.v, DefaultFinalHeight ());
4743
2.17k
  newSize.h = Min_int32 (newSize.h, DefaultFinalWidth  ());
4744
  
4745
2.17k
  if ((uint64) newSize.v *
4746
2.17k
      (uint64) newSize.h > proxyCount)
4747
51
    {
4748
4749
51
    if (aspectRatio >= 1.0)
4750
22
      {
4751
      
4752
22
      newSize.h = (uint32) sqrt (proxyCount * aspectRatio);
4753
      
4754
22
      newSize.v = Max_int32 (1, Round_int32 (newSize.h / aspectRatio));
4755
      
4756
22
      }
4757
      
4758
29
    else
4759
29
      {
4760
      
4761
29
      newSize.v = (uint32) sqrt (proxyCount / aspectRatio);
4762
      
4763
29
      newSize.h = Max_int32 (1, Round_int32 (newSize.v * aspectRatio));
4764
                           
4765
29
      }
4766
                                 
4767
51
    }
4768
    
4769
  // If this is fewer pixels, downsample the stage 3 image to that size.
4770
  
4771
2.17k
  dng_point oldSize = defaultCropArea.Size ();
4772
  
4773
2.17k
  if ((uint64) newSize.v * (uint64) newSize.h <
4774
2.17k
    (uint64) oldSize.v * (uint64) oldSize.h)
4775
591
    {
4776
    
4777
591
    const dng_image &srcImage (*Stage3Image ());
4778
    
4779
591
    AutoPtr<dng_image> dstImage (host.Make_dng_image (newSize,
4780
591
                              srcImage.Planes (),
4781
591
                              srcImage.PixelType ()));
4782
                              
4783
591
    host.ResampleImage (srcImage,
4784
591
              *dstImage);
4785
                             
4786
591
    fStage3Image.Reset (dstImage.Release ());
4787
    
4788
591
    fDefaultCropSizeH = dng_urational (newSize.h, 1);
4789
591
    fDefaultCropSizeV = dng_urational (newSize.v, 1);
4790
    
4791
591
    fDefaultScaleH = dng_urational (1, 1);
4792
591
    fDefaultScaleV = dng_urational (1, 1);
4793
    
4794
591
    fBestQualityScale = dng_urational (1, 1);
4795
    
4796
591
    fRawToFullScaleH = 1.0;
4797
591
    fRawToFullScaleV = 1.0;
4798
    
4799
591
    }
4800
    
4801
  // Convert 32-bit floating point images to 16-bit floating point to
4802
  // save space.
4803
  
4804
2.17k
  if (Stage3Image ()->PixelType () == ttFloat)
4805
546
    {
4806
    
4807
546
    fRawImage.Reset (host.Make_dng_image (Stage3Image ()->Bounds (),
4808
546
                        Stage3Image ()->Planes (),
4809
546
                        ttFloat));
4810
    
4811
546
    LimitFloatBitDepth (host,
4812
546
              *Stage3Image (),
4813
546
              *fRawImage,
4814
546
              16,
4815
546
              32768.0f);
4816
    
4817
546
    SetRawFloatBitDepth (16);
4818
    
4819
546
    SetWhiteLevel (32768);
4820
    
4821
546
    }
4822
    
4823
1.62k
  else
4824
1.62k
    {
4825
    
4826
    // Convert 16-bit deep images to 8-bit deep image for saving.
4827
    
4828
1.62k
    fRawImage.Reset (EncodeRawProxy (host,
4829
1.62k
                     *Stage3Image (),
4830
1.62k
                     fOpcodeList2));
4831
                     
4832
1.62k
    if (fRawImage.Get ())
4833
1.59k
      {
4834
      
4835
1.59k
      SetWhiteLevel (255);
4836
      
4837
      // Compute JPEG compressed version.
4838
      
4839
1.59k
      if (fRawImage->PixelType () == ttByte &&
4840
1.59k
        host.SaveDNGVersion () >= dngVersion_1_4_0_0)
4841
1.59k
        {
4842
      
4843
1.59k
        AutoPtr<dng_jpeg_image> jpegImage (new dng_jpeg_image);
4844
        
4845
1.59k
        jpegImage->Encode (host,
4846
1.59k
                   *this,
4847
1.59k
                   writer,
4848
1.59k
                   *fRawImage);
4849
                   
4850
1.59k
        SetRawJPEGImage (jpegImage);
4851
                   
4852
1.59k
        }
4853
      
4854
1.59k
      }
4855
      
4856
1.62k
    }
4857
    
4858
  // Deal with transparency mask.
4859
  
4860
2.17k
  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
2.17k
  RecomputeRawDataUniqueID (host);
4874
      
4875
2.17k
  }
4876
4877
/*****************************************************************************/
4878
4879
dng_linearization_info * dng_negative::MakeLinearizationInfo ()
4880
5.76k
  {
4881
  
4882
5.76k
  dng_linearization_info *info = new dng_linearization_info ();
4883
  
4884
5.76k
  if (!info)
4885
0
    {
4886
0
    ThrowMemoryFull ();
4887
0
    }
4888
    
4889
5.76k
  return info;
4890
  
4891
5.76k
  }
4892
4893
/*****************************************************************************/
4894
4895
void dng_negative::NeedLinearizationInfo ()
4896
8.08k
  {
4897
  
4898
8.08k
  if (!fLinearizationInfo.Get ())
4899
5.76k
    {
4900
  
4901
5.76k
    fLinearizationInfo.Reset (MakeLinearizationInfo ());
4902
    
4903
5.76k
    }
4904
  
4905
8.08k
  }
4906
4907
/*****************************************************************************/
4908
4909
dng_mosaic_info * dng_negative::MakeMosaicInfo ()
4910
0
  {
4911
  
4912
0
  dng_mosaic_info *info = new dng_mosaic_info ();
4913
  
4914
0
  if (!info)
4915
0
    {
4916
0
    ThrowMemoryFull ();
4917
0
    }
4918
    
4919
0
  return info;
4920
  
4921
0
  }
4922
4923
/*****************************************************************************/
4924
4925
void dng_negative::NeedMosaicInfo ()
4926
0
  {
4927
  
4928
0
  if (!fMosaicInfo.Get ())
4929
0
    {
4930
  
4931
0
    fMosaicInfo.Reset (MakeMosaicInfo ());
4932
    
4933
0
    }
4934
  
4935
0
  }
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
15.9k
  {
4953
  
4954
15.9k
  return fTransparencyMask.Get ();
4955
  
4956
15.9k
  }
4957
4958
/*****************************************************************************/
4959
4960
const dng_image * dng_negative::RawTransparencyMask () const
4961
4.78k
  {
4962
  
4963
4.78k
  if (fRawTransparencyMask.Get ())
4964
0
    {
4965
    
4966
0
    return fRawTransparencyMask.Get ();
4967
    
4968
0
    }
4969
    
4970
4.78k
  return TransparencyMask ();
4971
  
4972
4.78k
  }
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
4.52k
  {
5051
  
5052
4.52k
  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
4.52k
  }
5080
5081
/*****************************************************************************/
5082
5083
bool dng_negative::NeedFlattenTransparency (dng_host & /* host */)
5084
2.22k
  {
5085
  
5086
2.22k
  if (TransparencyMask ())
5087
0
    {
5088
    
5089
0
    return true;
5090
  
5091
0
    }
5092
  
5093
2.22k
  return false;
5094
    
5095
2.22k
  }
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
/*****************************************************************************/