Coverage Report

Created: 2025-11-09 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dng_sdk/source/dng_image_writer.cpp
Line
Count
Source
1
/*****************************************************************************/
2
// Copyright 2006-2012 Adobe Systems Incorporated
3
// All Rights Reserved.
4
//
5
// NOTICE:  Adobe permits you to use, modify, and distribute this file in
6
// accordance with the terms of the Adobe license agreement accompanying it.
7
/*****************************************************************************/
8
9
/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_image_writer.cpp#4 $ */ 
10
/* $DateTime: 2012/06/14 20:24:41 $ */
11
/* $Change: 835078 $ */
12
/* $Author: tknoll $ */
13
14
/*****************************************************************************/
15
16
#include "dng_image_writer.h"
17
18
#include "dng_abort_sniffer.h"
19
#include "dng_area_task.h"
20
#include "dng_bottlenecks.h"
21
#include "dng_camera_profile.h"
22
#include "dng_color_space.h"
23
#include "dng_exif.h"
24
#include "dng_flags.h"
25
#include "dng_exceptions.h"
26
#include "dng_host.h"
27
#include "dng_ifd.h"
28
#include "dng_image.h"
29
#include "dng_jpeg_image.h"
30
#include "dng_lossless_jpeg.h"
31
#include "dng_memory.h"
32
#include "dng_memory_stream.h"
33
#include "dng_negative.h"
34
#include "dng_pixel_buffer.h"
35
#include "dng_preview.h"
36
#include "dng_read_image.h"
37
#include "dng_safe_arithmetic.h"
38
#include "dng_stream.h"
39
#include "dng_string_list.h"
40
#include "dng_tag_codes.h"
41
#include "dng_tag_values.h"
42
#include "dng_utils.h"
43
44
#if qDNGUseXMP
45
#include "dng_xmp.h"
46
#endif
47
48
#include "zlib.h"
49
50
#if qDNGUseLibJPEG
51
#include "dng_jpeglib.h"
52
#endif
53
54
/*****************************************************************************/
55
56
// Defines for testing DNG 1.2 features.
57
58
//#define qTestRowInterleave 2
59
60
//#define qTestSubTileBlockRows 2
61
//#define qTestSubTileBlockCols 2
62
63
/*****************************************************************************/
64
65
dng_resolution::dng_resolution ()
66
67
66.5k
  : fXResolution ()
68
66.5k
  , fYResolution ()
69
  
70
66.5k
  , fResolutionUnit (0)
71
  
72
66.5k
  {
73
  
74
66.5k
  }
75
76
/******************************************************************************/
77
78
static void SpoolAdobeData (dng_stream &stream,
79
              const dng_metadata *metadata,
80
              const dng_jpeg_preview *preview,
81
              const dng_memory_block *imageResources)
82
66.5k
  {
83
  
84
66.5k
  TempBigEndian tempEndian (stream);
85
  
86
  #if qDNGUseXMP
87
88
  if (metadata && metadata->GetXMP ())
89
    {
90
    
91
    bool marked = false;
92
    
93
    if (metadata->GetXMP ()->GetBoolean (XMP_NS_XAP_RIGHTS,
94
                       "Marked",
95
                       marked))
96
      {
97
      
98
      stream.Put_uint32 (DNG_CHAR4 ('8','B','I','M'));
99
      stream.Put_uint16 (1034);
100
      stream.Put_uint16 (0);
101
      
102
      stream.Put_uint32 (1);
103
      
104
      stream.Put_uint8 (marked ? 1 : 0);
105
      
106
      stream.Put_uint8 (0);
107
      
108
      }
109
      
110
    dng_string webStatement;
111
    
112
    if (metadata->GetXMP ()->GetString (XMP_NS_XAP_RIGHTS,
113
                      "WebStatement",
114
                      webStatement))
115
      {
116
      
117
      dng_memory_data buffer;
118
      
119
      uint32 size = webStatement.Get_SystemEncoding (buffer);
120
      
121
      if (size > 0)
122
        {
123
        
124
        stream.Put_uint32 (DNG_CHAR4 ('8','B','I','M'));
125
        stream.Put_uint16 (1035);
126
        stream.Put_uint16 (0);
127
        
128
        stream.Put_uint32 (size);
129
        
130
        stream.Put (buffer.Buffer (), size);
131
        
132
        if (size & 1)
133
          stream.Put_uint8 (0);
134
          
135
        }
136
      
137
      }
138
    
139
    }
140
  
141
  #endif
142
  
143
66.5k
  if (preview)
144
0
    {
145
    
146
0
    preview->SpoolAdobeThumbnail (stream);
147
        
148
0
    }
149
    
150
66.5k
  if (metadata && metadata->IPTCLength ())
151
27
    {
152
    
153
27
    dng_fingerprint iptcDigest = metadata->IPTCDigest ();
154
155
27
    if (iptcDigest.IsValid ())
156
27
      {
157
      
158
27
      stream.Put_uint32 (DNG_CHAR4 ('8','B','I','M'));
159
27
      stream.Put_uint16 (1061);
160
27
      stream.Put_uint16 (0);
161
      
162
27
      stream.Put_uint32 (16);
163
      
164
27
      stream.Put (iptcDigest.data, 16);
165
      
166
27
      }
167
      
168
27
    }
169
    
170
66.5k
  if (imageResources)
171
0
    {
172
    
173
0
    uint32 size = imageResources->LogicalSize ();
174
    
175
0
    stream.Put (imageResources->Buffer (), size);
176
    
177
0
    if (size & 1)
178
0
      stream.Put_uint8 (0);
179
    
180
0
    }
181
    
182
66.5k
  }
183
184
/******************************************************************************/
185
186
static dng_memory_block * BuildAdobeData (dng_host &host,
187
                      const dng_metadata *metadata,
188
                      const dng_jpeg_preview *preview,
189
                      const dng_memory_block *imageResources)
190
66.5k
  {
191
  
192
66.5k
  dng_memory_stream stream (host.Allocator ());
193
  
194
66.5k
  SpoolAdobeData (stream,
195
66.5k
          metadata,
196
66.5k
          preview,
197
66.5k
          imageResources);
198
          
199
66.5k
  return stream.AsMemoryBlock (host.Allocator ());
200
  
201
66.5k
  }
202
203
/*****************************************************************************/
204
205
tag_string::tag_string (uint16 code,
206
              const dng_string &s,
207
              bool forceASCII)
208
              
209
3.04M
  : tiff_tag (code, ttAscii, 0)
210
  
211
3.04M
  , fString (s)
212
  
213
3.04M
  {
214
      
215
3.04M
  if (forceASCII)
216
2.76M
    {
217
    
218
    // Metadata working group recommendation - go ahead
219
    // write UTF-8 into ASCII tag strings, rather than
220
    // actually force the strings to ASCII.  There is a matching
221
    // change on the reading side to assume UTF-8 if the string
222
    // contains a valid UTF-8 string.
223
    //
224
    // fString.ForceASCII ();
225
    
226
2.76M
    }
227
    
228
280k
  else if (!fString.IsASCII ())
229
977
    {
230
    
231
977
    fType = ttByte;
232
    
233
977
    }
234
    
235
3.04M
  fCount = fString.Length () + 1;
236
  
237
3.04M
  }
238
239
/*****************************************************************************/
240
241
void tag_string::Put (dng_stream &stream) const
242
128k
  {
243
  
244
128k
  stream.Put (fString.Get (), Size ());
245
  
246
128k
  }
247
248
/*****************************************************************************/
249
250
tag_encoded_text::tag_encoded_text (uint16 code,
251
                  const dng_string &text)
252
  
253
264k
  : tiff_tag (code, ttUndefined, 0)
254
  
255
264k
  , fText (text)
256
  
257
264k
  , fUTF16 ()
258
  
259
264k
  {
260
      
261
264k
  if (fText.IsASCII ())
262
264k
    {
263
  
264
264k
    fCount = 8 + fText.Length ();
265
    
266
264k
    }
267
    
268
328
  else
269
328
    {
270
    
271
328
    fCount = 8 + fText.Get_UTF16 (fUTF16) * 2;
272
    
273
328
    }
274
  
275
264k
  }
276
277
/*****************************************************************************/
278
279
void tag_encoded_text::Put (dng_stream &stream) const
280
823
  {
281
  
282
823
  if (fUTF16.Buffer ())
283
328
    {
284
    
285
328
    stream.Put ("UNICODE\000", 8);
286
    
287
328
    uint32 chars = (fCount - 8) >> 1;
288
    
289
328
    const uint16 *buf = fUTF16.Buffer_uint16 ();
290
    
291
6.12k
    for (uint32 j = 0; j < chars; j++)
292
5.79k
      {
293
      
294
5.79k
      stream.Put_uint16 (buf [j]);
295
      
296
5.79k
      }
297
    
298
328
    }
299
    
300
495
  else
301
495
    {
302
    
303
495
    stream.Put ("ASCII\000\000\000", 8);
304
    
305
495
    stream.Put (fText.Get (), fCount - 8);
306
    
307
495
    }
308
    
309
823
  }
310
  
311
/*****************************************************************************/
312
313
void tag_data_ptr::Put (dng_stream &stream) const
314
1.69M
  {
315
  
316
  // If we are swapping bytes, we need to swap with the right size
317
  // entries.
318
  
319
1.69M
  if (stream.SwapBytes ())
320
0
    {
321
  
322
0
    switch (Type ())
323
0
      {
324
      
325
      // Two byte entries.
326
      
327
0
      case ttShort:
328
0
      case ttSShort:
329
0
      case ttUnicode:
330
0
        {
331
        
332
0
        const uint16 *p = (const uint16 *) fData;
333
        
334
0
        uint32 entries = (Size () >> 1);
335
        
336
0
        for (uint32 j = 0; j < entries; j++)
337
0
          {
338
          
339
0
          stream.Put_uint16 (p [j]);
340
          
341
0
          }
342
        
343
0
        return;
344
        
345
0
        }
346
      
347
      // Four byte entries.
348
      
349
0
      case ttLong:
350
0
      case ttSLong:
351
0
      case ttRational:
352
0
      case ttSRational:
353
0
      case ttIFD:
354
0
      case ttFloat:
355
0
      case ttComplex:
356
0
        {
357
        
358
0
        const uint32 *p = (const uint32 *) fData;
359
        
360
0
        uint32 entries = (Size () >> 2);
361
        
362
0
        for (uint32 j = 0; j < entries; j++)
363
0
          {
364
          
365
0
          stream.Put_uint32 (p [j]);
366
          
367
0
          }
368
        
369
0
        return;
370
        
371
0
        }
372
        
373
      // Eight byte entries.
374
      
375
0
      case ttDouble:
376
0
        {
377
        
378
0
        const real64 *p = (const real64 *) fData;
379
        
380
0
        uint32 entries = (Size () >> 3);
381
        
382
0
        for (uint32 j = 0; j < entries; j++)
383
0
          {
384
          
385
0
          stream.Put_real64 (p [j]);
386
          
387
0
          }
388
        
389
0
        return;
390
        
391
0
        }
392
      
393
      // Entries don't need to be byte swapped.  Fall through
394
      // to non-byte swapped case.
395
        
396
0
      default:
397
0
        {
398
        
399
0
        break;
400
        
401
0
        }
402
403
0
      }
404
      
405
0
    }
406
    
407
  // Non-byte swapped case.
408
    
409
1.69M
  stream.Put (fData, Size ());
410
        
411
1.69M
  }
412
413
/******************************************************************************/
414
415
tag_matrix::tag_matrix (uint16 code,
416
              const dng_matrix &m)
417
             
418
480k
  : tag_srational_ptr (code, fEntry, m.Rows () * m.Cols ())
419
  
420
480k
  {
421
  
422
480k
  uint32 index = 0;
423
  
424
712k
  for (uint32 r = 0; r < m.Rows (); r++)
425
928k
    for (uint32 c = 0; c < m.Cols (); c++)
426
696k
      {
427
      
428
696k
      fEntry [index].Set_real64 (m [r] [c], 10000);
429
      
430
696k
      index++;
431
      
432
696k
      }
433
  
434
480k
  }
435
436
/******************************************************************************/
437
438
tag_icc_profile::tag_icc_profile (const void *profileData,
439
                  uint32 profileSize)
440
      
441
66.5k
  : tag_data_ptr (tcICCProfile, 
442
66.5k
            ttUndefined,
443
66.5k
            0,
444
66.5k
            NULL)
445
  
446
66.5k
  {
447
  
448
66.5k
  if (profileData && profileSize)
449
4.72k
    {
450
    
451
4.72k
    SetCount (profileSize);
452
4.72k
    SetData  (profileData);
453
    
454
4.72k
    }
455
  
456
66.5k
  }
457
      
458
/******************************************************************************/
459
460
void tag_cfa_pattern::Put (dng_stream &stream) const
461
131
  {
462
  
463
131
  stream.Put_uint16 ((uint16) fCols);
464
131
  stream.Put_uint16 ((uint16) fRows);
465
  
466
262
  for (uint32 col = 0; col < fCols; col++)
467
262
    for (uint32 row = 0; row < fRows; row++)
468
131
      {
469
      
470
131
      stream.Put_uint8 (fPattern [row * kMaxCFAPattern + col]);
471
      
472
131
      }
473
474
131
  }
475
476
/******************************************************************************/
477
478
tag_exif_date_time::tag_exif_date_time (uint16 code,
479
                          const dng_date_time &dt)
480
             
481
264k
  : tag_data_ptr (code, ttAscii, 20, fData)
482
  
483
264k
  {
484
  
485
264k
  if (dt.IsValid ())
486
1.10k
    {
487
  
488
1.10k
    sprintf (fData,
489
1.10k
         "%04d:%02d:%02d %02d:%02d:%02d",
490
1.10k
         (int) dt.fYear,
491
1.10k
         (int) dt.fMonth,
492
1.10k
         (int) dt.fDay,
493
1.10k
         (int) dt.fHour,
494
1.10k
         (int) dt.fMinute,
495
1.10k
         (int) dt.fSecond);
496
         
497
1.10k
    }
498
  
499
264k
  }
500
501
/******************************************************************************/
502
503
tag_iptc::tag_iptc (const void *data,
504
            uint32 length)
505
  
506
66.5k
  : tiff_tag (tcIPTC_NAA, ttLong, (length + 3) >> 2)
507
  
508
66.5k
  , fData   (data  )
509
66.5k
  , fLength (length)
510
  
511
66.5k
  {
512
  
513
66.5k
  }
514
515
/******************************************************************************/
516
517
void tag_iptc::Put (dng_stream &stream) const
518
27
  {
519
  
520
  // Note: For historical compatiblity reasons, the standard TIFF data 
521
  // type for IPTC data is ttLong, but without byte swapping.  This really
522
  // should be ttUndefined, but doing the right thing would break some
523
  // existing readers.
524
  
525
27
  stream.Put (fData, fLength);
526
  
527
  // Pad with zeros to get to long word boundary.
528
  
529
27
  uint32 extra = fCount * 4 - fLength;
530
  
531
80
  while (extra--)
532
53
    {
533
53
    stream.Put_uint8 (0);
534
53
    }
535
536
27
  }
537
538
/******************************************************************************/
539
540
tag_xmp::tag_xmp (const dng_xmp *xmp)
541
  
542
0
  : tag_uint8_ptr (tcXMP, NULL, 0)
543
  
544
0
  , fBuffer ()
545
  
546
0
  {
547
  
548
  #if qDNGUseXMP
549
  
550
  if (xmp)
551
    {
552
    
553
    fBuffer.Reset (xmp->Serialize (true));
554
    
555
    if (fBuffer.Get ())
556
      {
557
      
558
      SetData (fBuffer->Buffer_uint8 ());
559
      
560
      SetCount (fBuffer->LogicalSize ());
561
      
562
      }
563
    
564
    }
565
  
566
  #endif
567
  
568
0
  }
569
570
/******************************************************************************/
571
572
void dng_tiff_directory::Add (const tiff_tag *tag)
573
2.00M
  {
574
  
575
2.00M
  if (fEntries >= kMaxEntries)
576
0
    {
577
0
    ThrowProgramError ();
578
0
    }
579
  
580
  // Tags must be sorted in increasing order of tag code.
581
  
582
2.00M
  uint32 index = fEntries;
583
  
584
16.7M
  for (uint32 j = 0; j < fEntries; j++)
585
15.7M
    {
586
    
587
15.7M
    if (tag->Code () < fTag [j]->Code ())
588
962k
      {
589
962k
      index = j;
590
962k
      break;
591
962k
      }
592
    
593
15.7M
    }
594
    
595
5.85M
  for (uint32 k = fEntries; k > index; k--)
596
3.84M
    {
597
    
598
3.84M
    fTag [k] = fTag [k - 1];
599
    
600
3.84M
    }
601
  
602
2.00M
  fTag [index] = tag;
603
  
604
2.00M
  fEntries++;
605
  
606
2.00M
  }
607
    
608
/******************************************************************************/
609
610
uint32 dng_tiff_directory::Size () const
611
536k
  {
612
  
613
536k
  if (!fEntries) return 0;
614
  
615
128k
  uint32 size = fEntries * 12 + 6;
616
  
617
1.90M
  for (uint32 index = 0; index < fEntries; index++)
618
1.78M
    {
619
    
620
1.78M
    uint32 tagSize = fTag [index]->Size ();
621
    
622
1.78M
    if (tagSize > 4)
623
485k
      {
624
      
625
485k
      size += (tagSize + 1) & ~1;
626
      
627
485k
      }
628
    
629
1.78M
    }
630
    
631
128k
  return size;
632
  
633
536k
  }
634
    
635
/******************************************************************************/
636
637
void dng_tiff_directory::Put (dng_stream &stream,
638
                  OffsetsBase offsetsBase,
639
                  uint32 explicitBase) const
640
278k
  {
641
  
642
278k
  if (!fEntries) return;
643
  
644
146k
  uint32 index;
645
  
646
146k
  uint32 bigData = fEntries * 12 + 6;
647
  
648
146k
  if (offsetsBase == offsetsRelativeToStream)
649
90.3k
    bigData += (uint32) stream.Position ();
650
651
56.2k
  else if (offsetsBase == offsetsRelativeToExplicitBase)
652
56.2k
    bigData += explicitBase;
653
654
146k
  stream.Put_uint16 ((uint16) fEntries);
655
  
656
1.95M
  for (index = 0; index < fEntries; index++)
657
1.80M
    {
658
    
659
1.80M
    const tiff_tag &tag = *fTag [index];
660
    
661
1.80M
    stream.Put_uint16 (tag.Code  ());
662
1.80M
    stream.Put_uint16 (tag.Type  ());
663
1.80M
    stream.Put_uint32 (tag.Count ());
664
    
665
1.80M
    uint32 size = tag.Size ();
666
    
667
1.80M
    if (size <= 4)
668
1.18M
      {
669
      
670
1.18M
      tag.Put (stream);
671
      
672
2.26M
      while (size < 4)
673
1.08M
        {
674
1.08M
        stream.Put_uint8 (0);
675
1.08M
        size++;
676
1.08M
        }
677
        
678
1.18M
      }
679
      
680
621k
    else
681
621k
      {
682
      
683
621k
      stream.Put_uint32 (bigData);
684
      
685
621k
      bigData += (size + 1) & ~1;
686
            
687
621k
      }
688
    
689
1.80M
    }
690
    
691
146k
  stream.Put_uint32 (fChained);   // Next IFD offset
692
  
693
1.95M
  for (index = 0; index < fEntries; index++)
694
1.80M
    {
695
    
696
1.80M
    const tiff_tag &tag = *fTag [index];
697
    
698
1.80M
    uint32 size = tag.Size ();
699
    
700
1.80M
    if (size > 4)
701
621k
      {
702
      
703
621k
      tag.Put (stream);
704
      
705
621k
      if (size & 1)
706
91.8k
        stream.Put_uint8 (0);
707
      
708
621k
      }
709
    
710
1.80M
    }
711
  
712
146k
  }
713
714
/******************************************************************************/
715
716
dng_basic_tag_set::dng_basic_tag_set (dng_tiff_directory &directory,
717
                    const dng_ifd &info)
718
              
719
94.9k
  : fNewSubFileType (tcNewSubFileType, info.fNewSubFileType)
720
  
721
94.9k
  , fImageWidth  (tcImageWidth , info.fImageWidth )
722
94.9k
  , fImageLength (tcImageLength, info.fImageLength)
723
  
724
94.9k
  , fPhotoInterpretation (tcPhotometricInterpretation,
725
94.9k
                (uint16) info.fPhotometricInterpretation)
726
  
727
94.9k
  , fFillOrder (tcFillOrder, 1)
728
  
729
94.9k
  , fSamplesPerPixel (tcSamplesPerPixel, (uint16) info.fSamplesPerPixel)
730
  
731
94.9k
  , fBitsPerSample (tcBitsPerSample,
732
94.9k
            fBitsPerSampleData,
733
94.9k
            info.fSamplesPerPixel)
734
            
735
94.9k
  , fStrips (info.fUsesStrips)
736
            
737
94.9k
  , fTileWidth (tcTileWidth, info.fTileWidth)
738
  
739
94.9k
  , fTileLength (fStrips ? tcRowsPerStrip : tcTileLength, 
740
94.9k
           info.fTileLength)
741
  
742
94.9k
  , fTileInfoBuffer (info.TilesPerImage (), 8)
743
  
744
94.9k
  , fTileOffsetData (fTileInfoBuffer.Buffer_uint32 ())
745
  
746
94.9k
  , fTileOffsets (fStrips ? tcStripOffsets : tcTileOffsets,
747
94.9k
            fTileOffsetData,
748
94.9k
            info.TilesPerImage ())
749
             
750
94.9k
  , fTileByteCountData (fTileOffsetData + info.TilesPerImage ())
751
  
752
94.9k
  , fTileByteCounts (fStrips ? tcStripByteCounts : tcTileByteCounts,
753
94.9k
             fTileByteCountData,
754
94.9k
             info.TilesPerImage ())
755
              
756
94.9k
  , fPlanarConfiguration (tcPlanarConfiguration, pcInterleaved)
757
  
758
94.9k
  , fCompression (tcCompression, (uint16) info.fCompression)
759
94.9k
  , fPredictor   (tcPredictor  , (uint16) info.fPredictor  )
760
  
761
94.9k
  , fExtraSamples (tcExtraSamples,
762
94.9k
             fExtraSamplesData,
763
94.9k
             info.fExtraSamplesCount)
764
             
765
94.9k
  , fSampleFormat (tcSampleFormat,
766
94.9k
             fSampleFormatData,
767
94.9k
             info.fSamplesPerPixel)
768
             
769
94.9k
  , fRowInterleaveFactor (tcRowInterleaveFactor,
770
94.9k
                (uint16) info.fRowInterleaveFactor)
771
                
772
94.9k
  , fSubTileBlockSize (tcSubTileBlockSize,
773
94.9k
               fSubTileBlockSizeData,
774
94.9k
               2)
775
                 
776
94.9k
  {
777
  
778
94.9k
  uint32 j;
779
  
780
226k
  for (j = 0; j < info.fSamplesPerPixel; j++)
781
132k
    {
782
  
783
132k
    fBitsPerSampleData [j] = (uint16) info.fBitsPerSample [0];
784
    
785
132k
    }
786
  
787
94.9k
  directory.Add (&fNewSubFileType);
788
  
789
94.9k
  directory.Add (&fImageWidth);
790
94.9k
  directory.Add (&fImageLength);
791
  
792
94.9k
  directory.Add (&fPhotoInterpretation);
793
  
794
94.9k
  directory.Add (&fSamplesPerPixel);
795
  
796
94.9k
  directory.Add (&fBitsPerSample);
797
  
798
94.9k
  if (info.fBitsPerSample [0] !=  8 &&
799
76.7k
      info.fBitsPerSample [0] != 16 &&
800
14.0k
      info.fBitsPerSample [0] != 32)
801
57
    {
802
  
803
57
    directory.Add (&fFillOrder);
804
    
805
57
    }
806
    
807
94.9k
  if (!fStrips)
808
21.7k
    {
809
    
810
21.7k
    directory.Add (&fTileWidth);
811
  
812
21.7k
    }
813
814
94.9k
  directory.Add (&fTileLength);
815
  
816
94.9k
  directory.Add (&fTileOffsets);
817
94.9k
  directory.Add (&fTileByteCounts);
818
  
819
94.9k
  directory.Add (&fPlanarConfiguration);
820
  
821
94.9k
  directory.Add (&fCompression);
822
  
823
94.9k
  if (info.fPredictor != cpNullPredictor)
824
34.9k
    {
825
    
826
34.9k
    directory.Add (&fPredictor);
827
    
828
34.9k
    }
829
    
830
94.9k
  if (info.fExtraSamplesCount != 0)
831
876
    {
832
    
833
1.75k
    for (j = 0; j < info.fExtraSamplesCount; j++)
834
876
      {
835
876
      fExtraSamplesData [j] = (uint16) info.fExtraSamples [j];
836
876
      }
837
      
838
876
    directory.Add (&fExtraSamples);
839
    
840
876
    }
841
    
842
94.9k
  if (info.fSampleFormat [0] != sfUnsignedInteger)
843
15.2k
    {
844
    
845
32.3k
    for (j = 0; j < info.fSamplesPerPixel; j++)
846
17.1k
      {
847
17.1k
      fSampleFormatData [j] = (uint16) info.fSampleFormat [j];
848
17.1k
      }
849
      
850
15.2k
    directory.Add (&fSampleFormat);
851
    
852
15.2k
    }
853
    
854
94.9k
  if (info.fRowInterleaveFactor != 1)
855
0
    {
856
    
857
0
    directory.Add (&fRowInterleaveFactor);
858
    
859
0
    }
860
    
861
94.9k
  if (info.fSubTileBlockRows != 1 ||
862
94.9k
    info.fSubTileBlockCols != 1)
863
0
    {
864
    
865
0
    fSubTileBlockSizeData [0] = (uint16) info.fSubTileBlockRows;
866
0
    fSubTileBlockSizeData [1] = (uint16) info.fSubTileBlockCols;
867
    
868
0
    directory.Add (&fSubTileBlockSize);
869
    
870
0
    }
871
  
872
94.9k
  }
873
874
/******************************************************************************/
875
876
exif_tag_set::exif_tag_set (dng_tiff_directory &directory,
877
                const dng_exif &exif,
878
              bool makerNoteSafe,
879
              const void *makerNoteData,
880
              uint32 makerNoteLength,
881
                bool insideDNG)
882
883
88.2k
  : fExifIFD ()
884
88.2k
  , fGPSIFD  ()
885
  
886
88.2k
  , fExifLink (tcExifIFD, 0)
887
88.2k
  , fGPSLink  (tcGPSInfo, 0)
888
  
889
88.2k
  , fAddedExifLink (false)
890
88.2k
  , fAddedGPSLink  (false)
891
  
892
88.2k
  , fExifVersion (tcExifVersion, ttUndefined, 4, fExifVersionData)
893
  
894
88.2k
  , fExposureTime      (tcExposureTime     , exif.fExposureTime     )
895
88.2k
  , fShutterSpeedValue (tcShutterSpeedValue, exif.fShutterSpeedValue)
896
  
897
88.2k
  , fFNumber     (tcFNumber      , exif.fFNumber      )
898
88.2k
  , fApertureValue (tcApertureValue, exif.fApertureValue)
899
  
900
88.2k
  , fBrightnessValue (tcBrightnessValue, exif.fBrightnessValue)
901
  
902
88.2k
  , fExposureBiasValue (tcExposureBiasValue, exif.fExposureBiasValue)
903
  
904
88.2k
  , fMaxApertureValue (tcMaxApertureValue , exif.fMaxApertureValue)
905
  
906
88.2k
  , fSubjectDistance (tcSubjectDistance, exif.fSubjectDistance)
907
  
908
88.2k
  , fFocalLength (tcFocalLength, exif.fFocalLength)
909
  
910
  // Special case: the EXIF 2.2 standard represents ISO speed ratings with 2 bytes,
911
  // which cannot hold ISO speed ratings above 65535 (e.g., 102400). In these
912
  // cases, we write the maximum representable ISO speed rating value in the EXIF
913
  // tag, i.e., 65535.
914
915
88.2k
  , fISOSpeedRatings (tcISOSpeedRatings, 
916
88.2k
              (uint16) Min_uint32 (65535, 
917
88.2k
                         exif.fISOSpeedRatings [0]))
918
919
88.2k
  , fSensitivityType (tcSensitivityType, (uint16) exif.fSensitivityType)
920
921
88.2k
  , fStandardOutputSensitivity (tcStandardOutputSensitivity, exif.fStandardOutputSensitivity)
922
  
923
88.2k
  , fRecommendedExposureIndex (tcRecommendedExposureIndex, exif.fRecommendedExposureIndex)
924
925
88.2k
  , fISOSpeed (tcISOSpeed, exif.fISOSpeed)
926
927
88.2k
  , fISOSpeedLatitudeyyy (tcISOSpeedLatitudeyyy, exif.fISOSpeedLatitudeyyy)
928
929
88.2k
  , fISOSpeedLatitudezzz (tcISOSpeedLatitudezzz, exif.fISOSpeedLatitudezzz)
930
931
88.2k
  , fFlash (tcFlash, (uint16) exif.fFlash)
932
  
933
88.2k
  , fExposureProgram (tcExposureProgram, (uint16) exif.fExposureProgram)
934
  
935
88.2k
  , fMeteringMode (tcMeteringMode, (uint16) exif.fMeteringMode)
936
  
937
88.2k
  , fLightSource (tcLightSource, (uint16) exif.fLightSource)
938
  
939
88.2k
  , fSensingMethod (tcSensingMethodExif, (uint16) exif.fSensingMethod)
940
  
941
88.2k
  , fFocalLength35mm (tcFocalLengthIn35mmFilm, (uint16) exif.fFocalLengthIn35mmFilm)
942
  
943
88.2k
  , fFileSourceData ((uint8) exif.fFileSource)
944
88.2k
  , fFileSource     (tcFileSource, ttUndefined, 1, &fFileSourceData)
945
946
88.2k
  , fSceneTypeData ((uint8) exif.fSceneType)
947
88.2k
  , fSceneType     (tcSceneType, ttUndefined, 1, &fSceneTypeData)
948
  
949
88.2k
  , fCFAPattern (tcCFAPatternExif,
950
88.2k
           exif.fCFARepeatPatternRows,
951
88.2k
           exif.fCFARepeatPatternCols,
952
88.2k
           &exif.fCFAPattern [0] [0])
953
  
954
88.2k
  , fCustomRendered     (tcCustomRendered    , (uint16) exif.fCustomRendered    )
955
88.2k
  , fExposureMode       (tcExposureMode    , (uint16) exif.fExposureMode      )
956
88.2k
  , fWhiteBalance       (tcWhiteBalance    , (uint16) exif.fWhiteBalance      )
957
88.2k
  , fSceneCaptureType     (tcSceneCaptureType  , (uint16) exif.fSceneCaptureType    )
958
88.2k
  , fGainControl      (tcGainControl     , (uint16) exif.fGainControl     )
959
88.2k
  , fContrast         (tcContrast      , (uint16) exif.fContrast        )
960
88.2k
  , fSaturation       (tcSaturation      , (uint16) exif.fSaturation      )
961
88.2k
  , fSharpness        (tcSharpness       , (uint16) exif.fSharpness       )
962
88.2k
  , fSubjectDistanceRange (tcSubjectDistanceRange, (uint16) exif.fSubjectDistanceRange)
963
    
964
88.2k
  , fDigitalZoomRatio (tcDigitalZoomRatio, exif.fDigitalZoomRatio)
965
  
966
88.2k
  , fExposureIndex (tcExposureIndexExif, exif.fExposureIndex)
967
  
968
88.2k
  , fImageNumber (tcImageNumber, exif.fImageNumber)
969
  
970
88.2k
  , fSelfTimerMode (tcSelfTimerMode, (uint16) exif.fSelfTimerMode)
971
  
972
88.2k
  , fBatteryLevelA (tcBatteryLevel, exif.fBatteryLevelA)
973
88.2k
  , fBatteryLevelR (tcBatteryLevel, exif.fBatteryLevelR)
974
  
975
88.2k
  , fFocalPlaneXResolution (tcFocalPlaneXResolutionExif, exif.fFocalPlaneXResolution)
976
88.2k
  , fFocalPlaneYResolution (tcFocalPlaneYResolutionExif, exif.fFocalPlaneYResolution)
977
  
978
88.2k
  , fFocalPlaneResolutionUnit (tcFocalPlaneResolutionUnitExif, (uint16) exif.fFocalPlaneResolutionUnit)
979
  
980
88.2k
  , fSubjectArea (tcSubjectArea, fSubjectAreaData, exif.fSubjectAreaCount)
981
982
88.2k
  , fLensInfo (tcLensInfo, fLensInfoData, 4)
983
  
984
88.2k
  , fDateTime      (tcDateTime       , exif.fDateTime         .DateTime ())
985
88.2k
  , fDateTimeOriginal  (tcDateTimeOriginal , exif.fDateTimeOriginal .DateTime ())
986
88.2k
  , fDateTimeDigitized (tcDateTimeDigitized, exif.fDateTimeDigitized.DateTime ())
987
  
988
88.2k
  , fSubsecTime      (tcSubsecTime,      exif.fDateTime         .Subseconds ())
989
88.2k
  , fSubsecTimeOriginal  (tcSubsecTimeOriginal,  exif.fDateTimeOriginal .Subseconds ())
990
88.2k
  , fSubsecTimeDigitized (tcSubsecTimeDigitized, exif.fDateTimeDigitized.Subseconds ())
991
  
992
88.2k
  , fMake (tcMake, exif.fMake)
993
994
88.2k
  , fModel (tcModel, exif.fModel)
995
  
996
88.2k
  , fArtist (tcArtist, exif.fArtist)
997
  
998
88.2k
  , fSoftware (tcSoftware, exif.fSoftware)
999
  
1000
88.2k
  , fCopyright (tcCopyright, exif.fCopyright)
1001
  
1002
88.2k
  , fMakerNoteSafety (tcMakerNoteSafety, makerNoteSafe ? 1 : 0)
1003
  
1004
88.2k
  , fMakerNote (tcMakerNote, ttUndefined, makerNoteLength, makerNoteData)
1005
          
1006
88.2k
  , fImageDescription (tcImageDescription, exif.fImageDescription)
1007
  
1008
88.2k
  , fSerialNumber (tcCameraSerialNumber, exif.fCameraSerialNumber)
1009
  
1010
88.2k
  , fUserComment (tcUserComment, exif.fUserComment)
1011
  
1012
88.2k
  , fImageUniqueID (tcImageUniqueID, ttAscii, 33, fImageUniqueIDData)
1013
1014
  // EXIF 2.3 tags.
1015
1016
88.2k
  , fCameraOwnerName   (tcCameraOwnerNameExif,    exif.fOwnerName     )
1017
88.2k
  , fBodySerialNumber  (tcCameraSerialNumberExif, exif.fCameraSerialNumber)
1018
88.2k
  , fLensSpecification (tcLensSpecificationExif,  fLensInfoData, 4      )
1019
88.2k
  , fLensMake      (tcLensMakeExif,       exif.fLensMake      )
1020
88.2k
  , fLensModel       (tcLensModelExif,      exif.fLensName      )
1021
88.2k
  , fLensSerialNumber  (tcLensSerialNumberExif,   exif.fLensSerialNumber  )
1022
1023
88.2k
  , fGPSVersionID (tcGPSVersionID, fGPSVersionData, 4)
1024
  
1025
88.2k
  , fGPSLatitudeRef (tcGPSLatitudeRef, exif.fGPSLatitudeRef)
1026
88.2k
  , fGPSLatitude    (tcGPSLatitude,    exif.fGPSLatitude, 3)
1027
  
1028
88.2k
  , fGPSLongitudeRef (tcGPSLongitudeRef, exif.fGPSLongitudeRef)
1029
88.2k
  , fGPSLongitude    (tcGPSLongitude,    exif.fGPSLongitude, 3)
1030
  
1031
88.2k
  , fGPSAltitudeRef (tcGPSAltitudeRef, (uint8) exif.fGPSAltitudeRef)
1032
88.2k
  , fGPSAltitude    (tcGPSAltitude,            exif.fGPSAltitude   )
1033
  
1034
88.2k
  , fGPSTimeStamp (tcGPSTimeStamp, exif.fGPSTimeStamp, 3)
1035
    
1036
88.2k
  , fGPSSatellites  (tcGPSSatellites , exif.fGPSSatellites )
1037
88.2k
  , fGPSStatus      (tcGPSStatus     , exif.fGPSStatus     )
1038
88.2k
  , fGPSMeasureMode (tcGPSMeasureMode, exif.fGPSMeasureMode)
1039
  
1040
88.2k
  , fGPSDOP (tcGPSDOP, exif.fGPSDOP)
1041
    
1042
88.2k
  , fGPSSpeedRef (tcGPSSpeedRef, exif.fGPSSpeedRef)
1043
88.2k
  , fGPSSpeed    (tcGPSSpeed   , exif.fGPSSpeed   )
1044
    
1045
88.2k
  , fGPSTrackRef (tcGPSTrackRef, exif.fGPSTrackRef)
1046
88.2k
  , fGPSTrack    (tcGPSTrack   , exif.fGPSTrack   )
1047
    
1048
88.2k
  , fGPSImgDirectionRef (tcGPSImgDirectionRef, exif.fGPSImgDirectionRef)
1049
88.2k
  , fGPSImgDirection    (tcGPSImgDirection   , exif.fGPSImgDirection   )
1050
  
1051
88.2k
  , fGPSMapDatum (tcGPSMapDatum, exif.fGPSMapDatum)
1052
    
1053
88.2k
  , fGPSDestLatitudeRef (tcGPSDestLatitudeRef, exif.fGPSDestLatitudeRef)
1054
88.2k
  , fGPSDestLatitude    (tcGPSDestLatitude,    exif.fGPSDestLatitude, 3)
1055
  
1056
88.2k
  , fGPSDestLongitudeRef (tcGPSDestLongitudeRef, exif.fGPSDestLongitudeRef)
1057
88.2k
  , fGPSDestLongitude    (tcGPSDestLongitude,    exif.fGPSDestLongitude, 3)
1058
  
1059
88.2k
  , fGPSDestBearingRef (tcGPSDestBearingRef, exif.fGPSDestBearingRef)
1060
88.2k
  , fGPSDestBearing    (tcGPSDestBearing   , exif.fGPSDestBearing   )
1061
    
1062
88.2k
  , fGPSDestDistanceRef (tcGPSDestDistanceRef, exif.fGPSDestDistanceRef)
1063
88.2k
  , fGPSDestDistance    (tcGPSDestDistance   , exif.fGPSDestDistance   )
1064
    
1065
88.2k
  , fGPSProcessingMethod (tcGPSProcessingMethod, exif.fGPSProcessingMethod)
1066
88.2k
  , fGPSAreaInformation  (tcGPSAreaInformation , exif.fGPSAreaInformation )
1067
  
1068
88.2k
  , fGPSDateStamp (tcGPSDateStamp, exif.fGPSDateStamp)
1069
  
1070
88.2k
  , fGPSDifferential (tcGPSDifferential, (uint16) exif.fGPSDifferential)
1071
    
1072
88.2k
  , fGPSHPositioningError (tcGPSHPositioningError, exif.fGPSHPositioningError)
1073
    
1074
88.2k
  {
1075
  
1076
88.2k
  if (exif.fExifVersion)
1077
3.77k
    {
1078
    
1079
3.77k
    fExifVersionData [0] = (uint8) (exif.fExifVersion >> 24);
1080
3.77k
    fExifVersionData [1] = (uint8) (exif.fExifVersion >> 16);
1081
3.77k
    fExifVersionData [2] = (uint8) (exif.fExifVersion >>  8);
1082
3.77k
    fExifVersionData [3] = (uint8) (exif.fExifVersion      );
1083
    
1084
3.77k
    fExifIFD.Add (&fExifVersion);
1085
1086
3.77k
    }
1087
  
1088
88.2k
  if (exif.fExposureTime.IsValid ())
1089
1.60k
    {
1090
1.60k
    fExifIFD.Add (&fExposureTime);
1091
1.60k
    }
1092
    
1093
88.2k
  if (exif.fShutterSpeedValue.IsValid ())
1094
1.60k
    {
1095
1.60k
    fExifIFD.Add (&fShutterSpeedValue);
1096
1.60k
    }
1097
    
1098
88.2k
  if (exif.fFNumber.IsValid ())
1099
1.53k
    {
1100
1.53k
    fExifIFD.Add (&fFNumber);
1101
1.53k
    }
1102
    
1103
88.2k
  if (exif.fApertureValue.IsValid ())
1104
1.17k
    {
1105
1.17k
    fExifIFD.Add (&fApertureValue);
1106
1.17k
    }
1107
    
1108
88.2k
  if (exif.fBrightnessValue.IsValid ())
1109
859
    {
1110
859
    fExifIFD.Add (&fBrightnessValue);
1111
859
    }
1112
    
1113
88.2k
  if (exif.fExposureBiasValue.IsValid ())
1114
2.03k
    {
1115
2.03k
    fExifIFD.Add (&fExposureBiasValue);
1116
2.03k
    }
1117
    
1118
88.2k
  if (exif.fMaxApertureValue.IsValid ())
1119
883
    {
1120
883
    fExifIFD.Add (&fMaxApertureValue);
1121
883
    }
1122
    
1123
88.2k
  if (exif.fSubjectDistance.IsValid ())
1124
843
    {
1125
843
    fExifIFD.Add (&fSubjectDistance);
1126
843
    }
1127
    
1128
88.2k
  if (exif.fFocalLength.IsValid ())
1129
1.21k
    {
1130
1.21k
    fExifIFD.Add (&fFocalLength);
1131
1.21k
    }
1132
  
1133
88.2k
  if (exif.fISOSpeedRatings [0] != 0)
1134
2.32k
    {
1135
2.32k
    fExifIFD.Add (&fISOSpeedRatings);
1136
2.32k
    }
1137
    
1138
88.2k
  if (exif.fFlash <= 0x0FFFF)
1139
953
    {
1140
953
    fExifIFD.Add (&fFlash);
1141
953
    }
1142
    
1143
88.2k
  if (exif.fExposureProgram <= 0x0FFFF)
1144
950
    {
1145
950
    fExifIFD.Add (&fExposureProgram);
1146
950
    }
1147
    
1148
88.2k
  if (exif.fMeteringMode <= 0x0FFFF)
1149
795
    {
1150
795
    fExifIFD.Add (&fMeteringMode);
1151
795
    }
1152
    
1153
88.2k
  if (exif.fLightSource <= 0x0FFFF)
1154
832
    {
1155
832
    fExifIFD.Add (&fLightSource);
1156
832
    }
1157
    
1158
88.2k
  if (exif.fSensingMethod <= 0x0FFFF)
1159
562
    {
1160
562
    fExifIFD.Add (&fSensingMethod);
1161
562
    }
1162
    
1163
88.2k
  if (exif.fFocalLengthIn35mmFilm != 0)
1164
491
    {
1165
491
    fExifIFD.Add (&fFocalLength35mm);
1166
491
    }
1167
    
1168
88.2k
  if (exif.fFileSource <= 0x0FF)
1169
873
    {
1170
873
    fExifIFD.Add (&fFileSource);
1171
873
    }
1172
    
1173
88.2k
  if (exif.fSceneType <= 0x0FF)
1174
1.19k
    {
1175
1.19k
    fExifIFD.Add (&fSceneType);
1176
1.19k
    }
1177
    
1178
88.2k
  if (exif.fCFARepeatPatternRows &&
1179
131
      exif.fCFARepeatPatternCols)
1180
131
    {
1181
131
    fExifIFD.Add (&fCFAPattern);
1182
131
    }
1183
    
1184
88.2k
  if (exif.fCustomRendered <= 0x0FFFF)
1185
650
    {
1186
650
    fExifIFD.Add (&fCustomRendered);
1187
650
    }
1188
    
1189
88.2k
  if (exif.fExposureMode <= 0x0FFFF)
1190
797
    {
1191
797
    fExifIFD.Add (&fExposureMode);
1192
797
    }
1193
    
1194
88.2k
  if (exif.fWhiteBalance <= 0x0FFFF)
1195
885
    {
1196
885
    fExifIFD.Add (&fWhiteBalance);
1197
885
    }
1198
    
1199
88.2k
  if (exif.fSceneCaptureType <= 0x0FFFF)
1200
414
    {
1201
414
    fExifIFD.Add (&fSceneCaptureType);
1202
414
    }
1203
    
1204
88.2k
  if (exif.fGainControl <= 0x0FFFF)
1205
395
    {
1206
395
    fExifIFD.Add (&fGainControl);
1207
395
    }
1208
    
1209
88.2k
  if (exif.fContrast <= 0x0FFFF)
1210
516
    {
1211
516
    fExifIFD.Add (&fContrast);
1212
516
    }
1213
    
1214
88.2k
  if (exif.fSaturation <= 0x0FFFF)
1215
251
    {
1216
251
    fExifIFD.Add (&fSaturation);
1217
251
    }
1218
    
1219
88.2k
  if (exif.fSharpness <= 0x0FFFF)
1220
395
    {
1221
395
    fExifIFD.Add (&fSharpness);
1222
395
    }
1223
    
1224
88.2k
  if (exif.fSubjectDistanceRange <= 0x0FFFF)
1225
449
    {
1226
449
    fExifIFD.Add (&fSubjectDistanceRange);
1227
449
    }
1228
    
1229
88.2k
  if (exif.fDigitalZoomRatio.IsValid ())
1230
709
    {
1231
709
    fExifIFD.Add (&fDigitalZoomRatio);
1232
709
    }
1233
    
1234
88.2k
  if (exif.fExposureIndex.IsValid ())
1235
1.31k
    {
1236
1.31k
    fExifIFD.Add (&fExposureIndex);
1237
1.31k
    }
1238
    
1239
88.2k
  if (insideDNG)  // TIFF-EP only tags
1240
21.7k
    {
1241
    
1242
21.7k
    if (exif.fImageNumber != 0xFFFFFFFF)
1243
772
      {
1244
772
      directory.Add (&fImageNumber);
1245
772
      }
1246
      
1247
21.7k
    if (exif.fSelfTimerMode <= 0x0FFFF)
1248
224
      {
1249
224
      directory.Add (&fSelfTimerMode);
1250
224
      }
1251
      
1252
21.7k
    if (exif.fBatteryLevelA.NotEmpty ())
1253
61
      {
1254
61
      directory.Add (&fBatteryLevelA);
1255
61
      }
1256
      
1257
21.6k
    else if (exif.fBatteryLevelR.IsValid ())
1258
188
      {
1259
188
      directory.Add (&fBatteryLevelR);
1260
188
      }
1261
    
1262
21.7k
    }
1263
    
1264
88.2k
  if (exif.fFocalPlaneXResolution.IsValid ())
1265
1.31k
    {
1266
1.31k
    fExifIFD.Add (&fFocalPlaneXResolution);
1267
1.31k
    }
1268
  
1269
88.2k
  if (exif.fFocalPlaneYResolution.IsValid ())
1270
544
    {
1271
544
    fExifIFD.Add (&fFocalPlaneYResolution);
1272
544
    }
1273
  
1274
88.2k
  if (exif.fFocalPlaneResolutionUnit <= 0x0FFFF)
1275
401
    {
1276
401
    fExifIFD.Add (&fFocalPlaneResolutionUnit);
1277
401
    }
1278
    
1279
88.2k
  if (exif.fSubjectAreaCount)
1280
235
    {
1281
    
1282
235
    fSubjectAreaData [0] = (uint16) exif.fSubjectArea [0];
1283
235
    fSubjectAreaData [1] = (uint16) exif.fSubjectArea [1];
1284
235
    fSubjectAreaData [2] = (uint16) exif.fSubjectArea [2];
1285
235
    fSubjectAreaData [3] = (uint16) exif.fSubjectArea [3];
1286
    
1287
235
    fExifIFD.Add (&fSubjectArea);
1288
    
1289
235
    }
1290
  
1291
88.2k
  if (exif.fLensInfo [0].IsValid () &&
1292
787
    exif.fLensInfo [1].IsValid ())
1293
619
    {
1294
    
1295
619
    fLensInfoData [0] = exif.fLensInfo [0];
1296
619
    fLensInfoData [1] = exif.fLensInfo [1];
1297
619
    fLensInfoData [2] = exif.fLensInfo [2];
1298
619
    fLensInfoData [3] = exif.fLensInfo [3];
1299
1300
619
    if (insideDNG)
1301
538
      {
1302
538
      directory.Add (&fLensInfo);
1303
538
      }
1304
    
1305
619
    }
1306
    
1307
88.2k
  if (exif.fDateTime.IsValid ())
1308
547
    {
1309
    
1310
547
    directory.Add (&fDateTime);
1311
    
1312
547
    if (exif.fDateTime.Subseconds ().NotEmpty ())
1313
176
      {
1314
176
      fExifIFD.Add (&fSubsecTime);
1315
176
      }
1316
    
1317
547
    }
1318
    
1319
88.2k
  if (exif.fDateTimeOriginal.IsValid ())
1320
278
    {
1321
    
1322
278
    fExifIFD.Add (&fDateTimeOriginal);
1323
    
1324
278
    if (exif.fDateTimeOriginal.Subseconds ().NotEmpty ())
1325
129
      {
1326
129
      fExifIFD.Add (&fSubsecTimeOriginal);
1327
129
      }
1328
    
1329
278
    }
1330
    
1331
88.2k
  if (exif.fDateTimeDigitized.IsValid ())
1332
279
    {
1333
    
1334
279
    fExifIFD.Add (&fDateTimeDigitized);
1335
    
1336
279
    if (exif.fDateTimeDigitized.Subseconds ().NotEmpty ())
1337
70
      {
1338
70
      fExifIFD.Add (&fSubsecTimeDigitized);
1339
70
      }
1340
    
1341
279
    }
1342
    
1343
88.2k
  if (exif.fMake.NotEmpty ())
1344
698
    {
1345
698
    directory.Add (&fMake);
1346
698
    }
1347
    
1348
88.2k
  if (exif.fModel.NotEmpty ())
1349
860
    {
1350
860
    directory.Add (&fModel);
1351
860
    }
1352
    
1353
88.2k
  if (exif.fArtist.NotEmpty ())
1354
345
    {
1355
345
    directory.Add (&fArtist);
1356
345
    }
1357
  
1358
88.2k
  if (exif.fSoftware.NotEmpty ())
1359
863
    {
1360
863
    directory.Add (&fSoftware);
1361
863
    }
1362
  
1363
88.2k
  if (exif.fCopyright.NotEmpty ())
1364
746
    {
1365
746
    directory.Add (&fCopyright);
1366
746
    }
1367
  
1368
88.2k
  if (exif.fImageDescription.NotEmpty ())
1369
481
    {
1370
481
    directory.Add (&fImageDescription);
1371
481
    }
1372
  
1373
88.2k
  if (exif.fCameraSerialNumber.NotEmpty () && insideDNG)
1374
526
    {
1375
526
    directory.Add (&fSerialNumber);
1376
526
    }
1377
    
1378
88.2k
  if (makerNoteSafe && makerNoteData)
1379
99
    {
1380
    
1381
99
    directory.Add (&fMakerNoteSafety);
1382
    
1383
99
    fExifIFD.Add (&fMakerNote);
1384
    
1385
99
    }
1386
    
1387
88.2k
  if (exif.fUserComment.NotEmpty ())
1388
652
    {
1389
652
    fExifIFD.Add (&fUserComment);
1390
652
    }
1391
    
1392
88.2k
  if (exif.fImageUniqueID.IsValid ())
1393
171
    {
1394
    
1395
2.90k
    for (uint32 j = 0; j < 16; j++)
1396
2.73k
      {
1397
      
1398
2.73k
      sprintf (fImageUniqueIDData + j * 2,
1399
2.73k
           "%02X",
1400
2.73k
           (unsigned) exif.fImageUniqueID.data [j]);
1401
           
1402
2.73k
      }
1403
    
1404
171
    fExifIFD.Add (&fImageUniqueID);
1405
    
1406
171
    }
1407
1408
88.2k
  if (exif.AtLeastVersion0230 ())
1409
3.46k
    {
1410
1411
3.46k
    if (exif.fSensitivityType != 0)
1412
1.15k
      {
1413
      
1414
1.15k
      fExifIFD.Add (&fSensitivityType);
1415
      
1416
1.15k
      }
1417
1418
    // Sensitivity tags. Do not write these extra tags unless the SensitivityType
1419
    // and PhotographicSensitivity (i.e., ISOSpeedRatings) values are valid.
1420
1421
3.46k
    if (exif.fSensitivityType   != 0 &&
1422
1.15k
      exif.fISOSpeedRatings [0] != 0)
1423
617
      {
1424
1425
      // Standard Output Sensitivity (SOS).
1426
1427
617
      if (exif.fStandardOutputSensitivity != 0)
1428
158
        {
1429
158
        fExifIFD.Add (&fStandardOutputSensitivity); 
1430
158
        }
1431
1432
      // Recommended Exposure Index (REI).
1433
1434
617
      if (exif.fRecommendedExposureIndex != 0)
1435
256
        {
1436
256
        fExifIFD.Add (&fRecommendedExposureIndex);
1437
256
        }
1438
1439
      // ISO Speed.
1440
1441
617
      if (exif.fISOSpeed != 0)
1442
196
        {
1443
1444
196
        fExifIFD.Add (&fISOSpeed);
1445
1446
196
        if (exif.fISOSpeedLatitudeyyy != 0 &&
1447
56
          exif.fISOSpeedLatitudezzz != 0)
1448
26
          {
1449
            
1450
26
          fExifIFD.Add (&fISOSpeedLatitudeyyy);
1451
26
          fExifIFD.Add (&fISOSpeedLatitudezzz);
1452
            
1453
26
          }
1454
1455
196
        }
1456
1457
617
      }
1458
    
1459
3.46k
    if (exif.fOwnerName.NotEmpty ())
1460
160
      {
1461
160
      fExifIFD.Add (&fCameraOwnerName);
1462
160
      }
1463
    
1464
3.46k
    if (exif.fCameraSerialNumber.NotEmpty ())
1465
173
      {
1466
173
      fExifIFD.Add (&fBodySerialNumber);
1467
173
      }
1468
1469
3.46k
    if (exif.fLensInfo [0].IsValid () &&
1470
376
      exif.fLensInfo [1].IsValid ())
1471
329
      {
1472
329
      fExifIFD.Add (&fLensSpecification);
1473
329
      }
1474
    
1475
3.46k
    if (exif.fLensMake.NotEmpty ())
1476
153
      {
1477
153
      fExifIFD.Add (&fLensMake);
1478
153
      }
1479
    
1480
3.46k
    if (exif.fLensName.NotEmpty ())
1481
143
      {
1482
143
      fExifIFD.Add (&fLensModel);
1483
143
      }
1484
    
1485
3.46k
    if (exif.fLensSerialNumber.NotEmpty ())
1486
168
      {
1487
168
      fExifIFD.Add (&fLensSerialNumber);
1488
168
      }
1489
    
1490
3.46k
    }
1491
    
1492
88.2k
  if (exif.fGPSVersionID)
1493
556
    {
1494
    
1495
556
    fGPSVersionData [0] = (uint8) (exif.fGPSVersionID >> 24);
1496
556
    fGPSVersionData [1] = (uint8) (exif.fGPSVersionID >> 16);
1497
556
    fGPSVersionData [2] = (uint8) (exif.fGPSVersionID >>  8);
1498
556
    fGPSVersionData [3] = (uint8) (exif.fGPSVersionID      );
1499
    
1500
556
    fGPSIFD.Add (&fGPSVersionID);
1501
    
1502
556
    }
1503
    
1504
88.2k
  if (exif.fGPSLatitudeRef.NotEmpty () &&
1505
189
    exif.fGPSLatitude [0].IsValid ())
1506
103
    {
1507
103
    fGPSIFD.Add (&fGPSLatitudeRef);
1508
103
    fGPSIFD.Add (&fGPSLatitude   );
1509
103
    }
1510
    
1511
88.2k
  if (exif.fGPSLongitudeRef.NotEmpty () &&
1512
415
    exif.fGPSLongitude [0].IsValid ())
1513
145
    {
1514
145
    fGPSIFD.Add (&fGPSLongitudeRef);
1515
145
    fGPSIFD.Add (&fGPSLongitude   );
1516
145
    }
1517
    
1518
88.2k
  if (exif.fGPSAltitudeRef <= 0x0FF)
1519
165
    {
1520
165
    fGPSIFD.Add (&fGPSAltitudeRef);
1521
165
    }
1522
    
1523
88.2k
  if (exif.fGPSAltitude.IsValid ())
1524
450
    {
1525
450
    fGPSIFD.Add (&fGPSAltitude);
1526
450
    }
1527
    
1528
88.2k
  if (exif.fGPSTimeStamp [0].IsValid ())
1529
85
    {
1530
85
    fGPSIFD.Add (&fGPSTimeStamp);
1531
85
    }
1532
    
1533
88.2k
  if (exif.fGPSSatellites.NotEmpty ())
1534
169
    {
1535
169
    fGPSIFD.Add (&fGPSSatellites);
1536
169
    }
1537
    
1538
88.2k
  if (exif.fGPSStatus.NotEmpty ())
1539
189
    {
1540
189
    fGPSIFD.Add (&fGPSStatus);
1541
189
    }
1542
    
1543
88.2k
  if (exif.fGPSMeasureMode.NotEmpty ())
1544
130
    {
1545
130
    fGPSIFD.Add (&fGPSMeasureMode);
1546
130
    }
1547
    
1548
88.2k
  if (exif.fGPSDOP.IsValid ())
1549
246
    {
1550
246
    fGPSIFD.Add (&fGPSDOP);
1551
246
    }
1552
    
1553
88.2k
  if (exif.fGPSSpeedRef.NotEmpty ())
1554
135
    {
1555
135
    fGPSIFD.Add (&fGPSSpeedRef);
1556
135
    }
1557
    
1558
88.2k
  if (exif.fGPSSpeed.IsValid ())
1559
259
    {
1560
259
    fGPSIFD.Add (&fGPSSpeed);
1561
259
    }
1562
    
1563
88.2k
  if (exif.fGPSTrackRef.NotEmpty ())
1564
187
    {
1565
187
    fGPSIFD.Add (&fGPSTrackRef);
1566
187
    }
1567
    
1568
88.2k
  if (exif.fGPSTrack.IsValid ())
1569
263
    {
1570
263
    fGPSIFD.Add (&fGPSTrack);
1571
263
    }
1572
    
1573
88.2k
  if (exif.fGPSImgDirectionRef.NotEmpty ())
1574
208
    {
1575
208
    fGPSIFD.Add (&fGPSImgDirectionRef);
1576
208
    }
1577
    
1578
88.2k
  if (exif.fGPSImgDirection.IsValid ())
1579
156
    {
1580
156
    fGPSIFD.Add (&fGPSImgDirection);
1581
156
    }
1582
1583
88.2k
  if (exif.fGPSMapDatum.NotEmpty ())
1584
145
    {
1585
145
    fGPSIFD.Add (&fGPSMapDatum);
1586
145
    }
1587
    
1588
88.2k
  if (exif.fGPSDestLatitudeRef.NotEmpty () &&
1589
135
    exif.fGPSDestLatitude [0].IsValid ())
1590
83
    {
1591
83
    fGPSIFD.Add (&fGPSDestLatitudeRef);
1592
83
    fGPSIFD.Add (&fGPSDestLatitude   );
1593
83
    }
1594
    
1595
88.2k
  if (exif.fGPSDestLongitudeRef.NotEmpty () &&
1596
202
    exif.fGPSDestLongitude [0].IsValid ())
1597
69
    {
1598
69
    fGPSIFD.Add (&fGPSDestLongitudeRef);
1599
69
    fGPSIFD.Add (&fGPSDestLongitude   );
1600
69
    }
1601
    
1602
88.2k
  if (exif.fGPSDestBearingRef.NotEmpty ())
1603
142
    {
1604
142
    fGPSIFD.Add (&fGPSDestBearingRef);
1605
142
    }
1606
    
1607
88.2k
  if (exif.fGPSDestBearing.IsValid ())
1608
513
    {
1609
513
    fGPSIFD.Add (&fGPSDestBearing);
1610
513
    }
1611
1612
88.2k
  if (exif.fGPSDestDistanceRef.NotEmpty ())
1613
245
    {
1614
245
    fGPSIFD.Add (&fGPSDestDistanceRef);
1615
245
    }
1616
    
1617
88.2k
  if (exif.fGPSDestDistance.IsValid ())
1618
217
    {
1619
217
    fGPSIFD.Add (&fGPSDestDistance);
1620
217
    }
1621
    
1622
88.2k
  if (exif.fGPSProcessingMethod.NotEmpty ())
1623
66
    {
1624
66
    fGPSIFD.Add (&fGPSProcessingMethod);
1625
66
    }
1626
1627
88.2k
  if (exif.fGPSAreaInformation.NotEmpty ())
1628
105
    {
1629
105
    fGPSIFD.Add (&fGPSAreaInformation);
1630
105
    }
1631
  
1632
88.2k
  if (exif.fGPSDateStamp.NotEmpty ())
1633
230
    {
1634
230
    fGPSIFD.Add (&fGPSDateStamp);
1635
230
    }
1636
  
1637
88.2k
  if (exif.fGPSDifferential <= 0x0FFFF)
1638
159
    {
1639
159
    fGPSIFD.Add (&fGPSDifferential);
1640
159
    }
1641
1642
88.2k
  if (exif.AtLeastVersion0230 ())
1643
3.46k
    {
1644
    
1645
3.46k
    if (exif.fGPSHPositioningError.IsValid ())
1646
143
      {
1647
143
      fGPSIFD.Add (&fGPSHPositioningError);
1648
143
      }
1649
1650
3.46k
    }
1651
    
1652
88.2k
  AddLinks (directory);
1653
  
1654
88.2k
  }
1655
1656
/******************************************************************************/
1657
1658
void exif_tag_set::AddLinks (dng_tiff_directory &directory)
1659
88.2k
  {
1660
  
1661
88.2k
  if (fExifIFD.Size () != 0 && !fAddedExifLink)
1662
9.92k
    {
1663
    
1664
9.92k
    directory.Add (&fExifLink);
1665
    
1666
9.92k
    fAddedExifLink = true;
1667
    
1668
9.92k
    }
1669
  
1670
88.2k
  if (fGPSIFD.Size () != 0 && !fAddedGPSLink)
1671
2.05k
    {
1672
    
1673
2.05k
    directory.Add (&fGPSLink);
1674
    
1675
2.05k
    fAddedGPSLink = true;
1676
    
1677
2.05k
    }
1678
  
1679
88.2k
  }
1680
  
1681
/******************************************************************************/
1682
1683
class range_tag_set
1684
  {
1685
  
1686
  private:
1687
  
1688
    uint32 fActiveAreaData [4];
1689
  
1690
    tag_uint32_ptr fActiveArea;
1691
  
1692
    uint32 fMaskedAreaData [kMaxMaskedAreas * 4];
1693
  
1694
    tag_uint32_ptr fMaskedAreas;
1695
                
1696
    tag_uint16_ptr fLinearizationTable;
1697
  
1698
    uint16 fBlackLevelRepeatDimData [2];
1699
    
1700
    tag_uint16_ptr fBlackLevelRepeatDim;
1701
    
1702
    dng_urational fBlackLevelData [kMaxBlackPattern *
1703
                       kMaxBlackPattern *
1704
                       kMaxSamplesPerPixel];
1705
    
1706
    tag_urational_ptr fBlackLevel;
1707
    
1708
    dng_memory_data fBlackLevelDeltaHData;
1709
    dng_memory_data fBlackLevelDeltaVData;
1710
    
1711
    tag_srational_ptr fBlackLevelDeltaH;
1712
    tag_srational_ptr fBlackLevelDeltaV;
1713
    
1714
    uint16 fWhiteLevelData16 [kMaxSamplesPerPixel];
1715
    uint32 fWhiteLevelData32 [kMaxSamplesPerPixel];
1716
    
1717
    tag_uint16_ptr fWhiteLevel16;
1718
    tag_uint32_ptr fWhiteLevel32;
1719
    
1720
  public:
1721
  
1722
    range_tag_set (dng_tiff_directory &directory,
1723
               const dng_negative &negative);
1724
    
1725
  };
1726
  
1727
/******************************************************************************/
1728
1729
range_tag_set::range_tag_set (dng_tiff_directory &directory,
1730
                    const dng_negative &negative)
1731
                
1732
21.7k
  : fActiveArea (tcActiveArea,
1733
21.7k
           fActiveAreaData,
1734
21.7k
           4)
1735
  
1736
21.7k
  , fMaskedAreas (tcMaskedAreas,
1737
21.7k
            fMaskedAreaData,
1738
21.7k
            0)
1739
  
1740
21.7k
  , fLinearizationTable (tcLinearizationTable,
1741
21.7k
               NULL,
1742
21.7k
               0)
1743
                
1744
21.7k
  , fBlackLevelRepeatDim (tcBlackLevelRepeatDim,
1745
21.7k
                fBlackLevelRepeatDimData,
1746
21.7k
                2)
1747
               
1748
21.7k
  , fBlackLevel (tcBlackLevel,
1749
21.7k
           fBlackLevelData)
1750
           
1751
21.7k
  , fBlackLevelDeltaHData ()
1752
21.7k
  , fBlackLevelDeltaVData ()
1753
           
1754
21.7k
  , fBlackLevelDeltaH (tcBlackLevelDeltaH)
1755
21.7k
  , fBlackLevelDeltaV (tcBlackLevelDeltaV)
1756
 
1757
21.7k
  , fWhiteLevel16 (tcWhiteLevel,
1758
21.7k
             fWhiteLevelData16)
1759
           
1760
21.7k
  , fWhiteLevel32 (tcWhiteLevel,
1761
21.7k
             fWhiteLevelData32)
1762
           
1763
21.7k
  {
1764
  
1765
21.7k
  const dng_image &rawImage (negative.RawImage ());
1766
  
1767
21.7k
  const dng_linearization_info *rangeInfo = negative.GetLinearizationInfo ();
1768
  
1769
21.7k
  if (rangeInfo)
1770
9.37k
    {
1771
    
1772
    // ActiveArea:
1773
    
1774
9.37k
      {
1775
    
1776
9.37k
      const dng_rect &r = rangeInfo->fActiveArea;
1777
      
1778
9.37k
      if (r.NotEmpty ())
1779
957
        {
1780
      
1781
957
        fActiveAreaData [0] = r.t;
1782
957
        fActiveAreaData [1] = r.l;
1783
957
        fActiveAreaData [2] = r.b;
1784
957
        fActiveAreaData [3] = r.r;
1785
        
1786
957
        directory.Add (&fActiveArea);
1787
        
1788
957
        }
1789
        
1790
9.37k
      }
1791
      
1792
    // MaskedAreas:
1793
      
1794
9.37k
    if (rangeInfo->fMaskedAreaCount)
1795
0
      {
1796
      
1797
0
      fMaskedAreas.SetCount (rangeInfo->fMaskedAreaCount * 4);
1798
      
1799
0
      for (uint32 index = 0; index < rangeInfo->fMaskedAreaCount; index++)
1800
0
        {
1801
        
1802
0
        const dng_rect &r = rangeInfo->fMaskedArea [index];
1803
        
1804
0
        fMaskedAreaData [index * 4 + 0] = r.t;
1805
0
        fMaskedAreaData [index * 4 + 1] = r.l;
1806
0
        fMaskedAreaData [index * 4 + 2] = r.b;
1807
0
        fMaskedAreaData [index * 4 + 3] = r.r;
1808
        
1809
0
        }
1810
        
1811
0
      directory.Add (&fMaskedAreas);
1812
      
1813
0
      }
1814
      
1815
    // LinearizationTable:
1816
1817
9.37k
    if (rangeInfo->fLinearizationTable.Get ())
1818
8
      {
1819
      
1820
8
      fLinearizationTable.SetData  (rangeInfo->fLinearizationTable->Buffer_uint16 ()     );
1821
8
      fLinearizationTable.SetCount (rangeInfo->fLinearizationTable->LogicalSize   () >> 1);
1822
      
1823
8
      directory.Add (&fLinearizationTable);
1824
      
1825
8
      }
1826
      
1827
    // BlackLevelRepeatDim:
1828
    
1829
9.37k
      {
1830
    
1831
9.37k
      fBlackLevelRepeatDimData [0] = (uint16) rangeInfo->fBlackLevelRepeatRows;
1832
9.37k
      fBlackLevelRepeatDimData [1] = (uint16) rangeInfo->fBlackLevelRepeatCols;
1833
      
1834
9.37k
      directory.Add (&fBlackLevelRepeatDim);
1835
      
1836
9.37k
      }
1837
    
1838
    // BlackLevel:
1839
    
1840
9.37k
      {
1841
    
1842
9.37k
      uint32 index = 0;
1843
      
1844
18.8k
      for (uint16 v = 0; v < rangeInfo->fBlackLevelRepeatRows; v++)
1845
9.48k
        {
1846
        
1847
19.3k
        for (uint32 h = 0; h < rangeInfo->fBlackLevelRepeatCols; h++)
1848
9.90k
          {
1849
          
1850
22.3k
          for (uint32 c = 0; c < rawImage.Planes (); c++)
1851
12.4k
            {
1852
          
1853
12.4k
            fBlackLevelData [index++] = rangeInfo->BlackLevel (v, h, c);
1854
          
1855
12.4k
            }
1856
            
1857
9.90k
          }
1858
          
1859
9.48k
        }
1860
        
1861
9.37k
      fBlackLevel.SetCount (rangeInfo->fBlackLevelRepeatRows *
1862
9.37k
                  rangeInfo->fBlackLevelRepeatCols * rawImage.Planes ());
1863
      
1864
9.37k
      directory.Add (&fBlackLevel);
1865
      
1866
9.37k
      }
1867
    
1868
    // BlackLevelDeltaH:
1869
        
1870
9.37k
    if (rangeInfo->ColumnBlackCount ())
1871
23
      {
1872
      
1873
23
      uint32 count = rangeInfo->ColumnBlackCount ();
1874
    
1875
23
      fBlackLevelDeltaHData.Allocate (count, sizeof (dng_srational));
1876
                         
1877
23
      dng_srational *blacks = (dng_srational *) fBlackLevelDeltaHData.Buffer ();
1878
      
1879
565
      for (uint32 col = 0; col < count; col++)
1880
542
        {
1881
        
1882
542
        blacks [col] = rangeInfo->ColumnBlack (col);
1883
        
1884
542
        }
1885
                         
1886
23
      fBlackLevelDeltaH.SetData  (blacks);
1887
23
      fBlackLevelDeltaH.SetCount (count );
1888
      
1889
23
      directory.Add (&fBlackLevelDeltaH);
1890
      
1891
23
      }
1892
    
1893
    // BlackLevelDeltaV:
1894
        
1895
9.37k
    if (rangeInfo->RowBlackCount ())
1896
35
      {
1897
      
1898
35
      uint32 count = rangeInfo->RowBlackCount ();
1899
    
1900
35
      fBlackLevelDeltaVData.Allocate (count, sizeof (dng_srational));
1901
                         
1902
35
      dng_srational *blacks = (dng_srational *) fBlackLevelDeltaVData.Buffer ();
1903
      
1904
111
      for (uint32 row = 0; row < count; row++)
1905
76
        {
1906
        
1907
76
        blacks [row] = rangeInfo->RowBlack (row);
1908
        
1909
76
        }
1910
                         
1911
35
      fBlackLevelDeltaV.SetData  (blacks);
1912
35
      fBlackLevelDeltaV.SetCount (count );
1913
      
1914
35
      directory.Add (&fBlackLevelDeltaV);
1915
      
1916
35
      }
1917
      
1918
9.37k
    }
1919
    
1920
  // WhiteLevel:
1921
  
1922
  // Only use the 32-bit data type if we must use it since there
1923
  // are some lazy (non-Adobe) DNG readers out there.
1924
  
1925
21.7k
  bool needs32 = false;
1926
    
1927
21.7k
  fWhiteLevel16.SetCount (rawImage.Planes ());
1928
21.7k
  fWhiteLevel32.SetCount (rawImage.Planes ());
1929
  
1930
50.3k
  for (uint32 c = 0; c < fWhiteLevel16.Count (); c++)
1931
28.6k
    {
1932
    
1933
28.6k
    fWhiteLevelData32 [c] = negative.WhiteLevel (c);
1934
    
1935
28.6k
    if (fWhiteLevelData32 [c] > 0x0FFFF)
1936
149
      {
1937
149
      needs32 = true;
1938
149
      }
1939
      
1940
28.6k
    fWhiteLevelData16 [c] = (uint16) fWhiteLevelData32 [c];
1941
    
1942
28.6k
    }
1943
    
1944
21.7k
  if (needs32)
1945
149
    {
1946
149
    directory.Add (&fWhiteLevel32);
1947
149
    }
1948
    
1949
21.5k
  else
1950
21.5k
    {
1951
21.5k
    directory.Add (&fWhiteLevel16);
1952
21.5k
    }
1953
  
1954
21.7k
  }
1955
1956
/******************************************************************************/
1957
1958
class mosaic_tag_set
1959
  {
1960
  
1961
  private:
1962
  
1963
    uint16 fCFARepeatPatternDimData [2];
1964
    
1965
    tag_uint16_ptr fCFARepeatPatternDim;
1966
                       
1967
    uint8 fCFAPatternData [kMaxCFAPattern *
1968
                 kMaxCFAPattern];
1969
    
1970
    tag_uint8_ptr fCFAPattern;
1971
                 
1972
    uint8 fCFAPlaneColorData [kMaxColorPlanes];
1973
    
1974
    tag_uint8_ptr fCFAPlaneColor;
1975
                  
1976
    tag_uint16 fCFALayout;
1977
    
1978
    tag_uint32 fGreenSplit;
1979
    
1980
  public:
1981
  
1982
    mosaic_tag_set (dng_tiff_directory &directory,
1983
                const dng_mosaic_info &info);
1984
    
1985
  };
1986
  
1987
/******************************************************************************/
1988
1989
mosaic_tag_set::mosaic_tag_set (dng_tiff_directory &directory,
1990
                      const dng_mosaic_info &info)
1991
1992
21.7k
  : fCFARepeatPatternDim (tcCFARepeatPatternDim,
1993
21.7k
                  fCFARepeatPatternDimData,
1994
21.7k
                  2)
1995
                  
1996
21.7k
  , fCFAPattern (tcCFAPattern,
1997
21.7k
           fCFAPatternData)
1998
          
1999
21.7k
  , fCFAPlaneColor (tcCFAPlaneColor,
2000
21.7k
            fCFAPlaneColorData)
2001
            
2002
21.7k
  , fCFALayout (tcCFALayout,
2003
21.7k
          (uint16) info.fCFALayout)
2004
  
2005
21.7k
  , fGreenSplit (tcBayerGreenSplit,
2006
21.7k
           info.fBayerGreenSplit)
2007
  
2008
21.7k
  {
2009
  
2010
21.7k
  if (info.IsColorFilterArray ())
2011
356
    {
2012
  
2013
    // CFARepeatPatternDim:
2014
    
2015
356
    fCFARepeatPatternDimData [0] = (uint16) info.fCFAPatternSize.v;
2016
356
    fCFARepeatPatternDimData [1] = (uint16) info.fCFAPatternSize.h;
2017
        
2018
356
    directory.Add (&fCFARepeatPatternDim);
2019
    
2020
    // CFAPattern:
2021
    
2022
356
    fCFAPattern.SetCount (info.fCFAPatternSize.v *
2023
356
                info.fCFAPatternSize.h);
2024
                
2025
1.04k
    for (int32 r = 0; r < info.fCFAPatternSize.v; r++)
2026
693
      {
2027
      
2028
2.10k
      for (int32 c = 0; c < info.fCFAPatternSize.h; c++)
2029
1.41k
        {
2030
        
2031
1.41k
        fCFAPatternData [r * info.fCFAPatternSize.h + c] = info.fCFAPattern [r] [c];
2032
        
2033
1.41k
        }
2034
        
2035
693
      }
2036
        
2037
356
    directory.Add (&fCFAPattern);
2038
    
2039
    // CFAPlaneColor:
2040
    
2041
356
    fCFAPlaneColor.SetCount (info.fColorPlanes);
2042
    
2043
1.50k
    for (uint32 j = 0; j < info.fColorPlanes; j++)
2044
1.15k
      {
2045
    
2046
1.15k
      fCFAPlaneColorData [j] = info.fCFAPlaneColor [j];
2047
      
2048
1.15k
      }
2049
    
2050
356
    directory.Add (&fCFAPlaneColor);
2051
    
2052
    // CFALayout:
2053
    
2054
356
    fCFALayout.Set ((uint16) info.fCFALayout);
2055
    
2056
356
    directory.Add (&fCFALayout);
2057
    
2058
    // BayerGreenSplit:  (only include if the pattern is a Bayer pattern)
2059
      
2060
356
    if (info.fCFAPatternSize == dng_point (2, 2) &&
2061
311
      info.fColorPlanes    == 3)
2062
206
      {
2063
      
2064
206
      directory.Add (&fGreenSplit);
2065
      
2066
206
      }
2067
      
2068
356
    }
2069
2070
21.7k
  }
2071
  
2072
/******************************************************************************/
2073
2074
class color_tag_set
2075
  {
2076
  
2077
  private:
2078
  
2079
    uint32 fColorChannels;
2080
    
2081
    tag_matrix fCameraCalibration1;
2082
    tag_matrix fCameraCalibration2;
2083
                     
2084
    tag_string fCameraCalibrationSignature;
2085
    
2086
    tag_string fAsShotProfileName;
2087
2088
    dng_urational fAnalogBalanceData [4];
2089
  
2090
    tag_urational_ptr fAnalogBalance;
2091
                    
2092
    dng_urational fAsShotNeutralData [4];
2093
    
2094
    tag_urational_ptr fAsShotNeutral;
2095
                      
2096
    dng_urational fAsShotWhiteXYData [2];
2097
    
2098
    tag_urational_ptr fAsShotWhiteXY;
2099
                      
2100
    tag_urational fLinearResponseLimit;
2101
                      
2102
  public:
2103
  
2104
    color_tag_set (dng_tiff_directory &directory,
2105
               const dng_negative &negative);
2106
    
2107
  };
2108
  
2109
/******************************************************************************/
2110
2111
color_tag_set::color_tag_set (dng_tiff_directory &directory,
2112
                    const dng_negative &negative)
2113
                
2114
16.2k
  : fColorChannels (negative.ColorChannels ())
2115
  
2116
16.2k
  , fCameraCalibration1 (tcCameraCalibration1,
2117
16.2k
                 negative.CameraCalibration1 ())
2118
            
2119
16.2k
  , fCameraCalibration2 (tcCameraCalibration2,
2120
16.2k
                 negative.CameraCalibration2 ())
2121
               
2122
16.2k
  , fCameraCalibrationSignature (tcCameraCalibrationSignature,
2123
16.2k
                   negative.CameraCalibrationSignature ())
2124
                   
2125
16.2k
  , fAsShotProfileName (tcAsShotProfileName,
2126
16.2k
              negative.AsShotProfileName ())
2127
2128
16.2k
  , fAnalogBalance (tcAnalogBalance,
2129
16.2k
            fAnalogBalanceData,
2130
16.2k
            fColorChannels)
2131
            
2132
16.2k
  , fAsShotNeutral (tcAsShotNeutral,
2133
16.2k
            fAsShotNeutralData,
2134
16.2k
            fColorChannels)
2135
            
2136
16.2k
  , fAsShotWhiteXY (tcAsShotWhiteXY,
2137
16.2k
            fAsShotWhiteXYData,
2138
16.2k
            2)
2139
                    
2140
16.2k
  , fLinearResponseLimit (tcLinearResponseLimit,
2141
16.2k
                  negative.LinearResponseLimitR ())
2142
                  
2143
16.2k
  {
2144
  
2145
16.2k
  if (fColorChannels > 1)
2146
16.2k
    {
2147
    
2148
16.2k
    uint32 channels2 = fColorChannels * fColorChannels;
2149
    
2150
16.2k
    if (fCameraCalibration1.Count () == channels2)
2151
75
      {
2152
      
2153
75
      directory.Add (&fCameraCalibration1);
2154
    
2155
75
      }
2156
      
2157
16.2k
    if (fCameraCalibration2.Count () == channels2)
2158
44
      {
2159
      
2160
44
      directory.Add (&fCameraCalibration2);
2161
    
2162
44
      }
2163
      
2164
16.2k
    if (fCameraCalibration1.Count () == channels2 ||
2165
16.1k
      fCameraCalibration2.Count () == channels2)
2166
104
      {
2167
      
2168
104
      if (negative.CameraCalibrationSignature ().NotEmpty ())
2169
49
        {
2170
        
2171
49
        directory.Add (&fCameraCalibrationSignature);
2172
        
2173
49
        }
2174
      
2175
104
      }
2176
      
2177
16.2k
    if (negative.AsShotProfileName ().NotEmpty ())
2178
134
      {
2179
      
2180
134
      directory.Add (&fAsShotProfileName);
2181
        
2182
134
      }
2183
      
2184
71.0k
    for (uint32 j = 0; j < fColorChannels; j++)
2185
54.7k
      {
2186
      
2187
54.7k
      fAnalogBalanceData [j] = negative.AnalogBalanceR (j);
2188
      
2189
54.7k
      }
2190
      
2191
16.2k
    directory.Add (&fAnalogBalance);
2192
    
2193
16.2k
    if (negative.HasCameraNeutral ())
2194
214
      {
2195
      
2196
899
      for (uint32 k = 0; k < fColorChannels; k++)
2197
685
        {
2198
        
2199
685
        fAsShotNeutralData [k] = negative.CameraNeutralR (k);
2200
        
2201
685
        }
2202
      
2203
214
      directory.Add (&fAsShotNeutral);
2204
      
2205
214
      }
2206
      
2207
16.0k
    else if (negative.HasCameraWhiteXY ())
2208
504
      {
2209
      
2210
504
      negative.GetCameraWhiteXY (fAsShotWhiteXYData [0],
2211
504
                     fAsShotWhiteXYData [1]);
2212
                     
2213
504
      directory.Add (&fAsShotWhiteXY);
2214
      
2215
504
      }
2216
    
2217
16.2k
    directory.Add (&fLinearResponseLimit);
2218
    
2219
16.2k
    }
2220
  
2221
16.2k
  }
2222
2223
/******************************************************************************/
2224
2225
class profile_tag_set
2226
  {
2227
  
2228
  private:
2229
  
2230
    tag_uint16 fCalibrationIlluminant1;
2231
    tag_uint16 fCalibrationIlluminant2;
2232
    
2233
    tag_matrix fColorMatrix1;
2234
    tag_matrix fColorMatrix2;
2235
    
2236
    tag_matrix fForwardMatrix1;
2237
    tag_matrix fForwardMatrix2;
2238
2239
    tag_matrix fReductionMatrix1;
2240
    tag_matrix fReductionMatrix2;
2241
    
2242
    tag_string fProfileName;
2243
    
2244
    tag_string fProfileCalibrationSignature;
2245
    
2246
    tag_uint32 fEmbedPolicyTag;
2247
    
2248
    tag_string fCopyrightTag;
2249
    
2250
    uint32 fHueSatMapDimData [3];
2251
    
2252
    tag_uint32_ptr fHueSatMapDims;
2253
2254
    tag_data_ptr fHueSatData1;
2255
    tag_data_ptr fHueSatData2;
2256
    
2257
    tag_uint32 fHueSatMapEncodingTag;
2258
    
2259
    uint32 fLookTableDimData [3];
2260
    
2261
    tag_uint32_ptr fLookTableDims;
2262
2263
    tag_data_ptr fLookTableData;
2264
    
2265
    tag_uint32 fLookTableEncodingTag;
2266
2267
    tag_srational fBaselineExposureOffsetTag;
2268
    
2269
    tag_uint32 fDefaultBlackRenderTag;
2270
2271
    dng_memory_data fToneCurveBuffer;
2272
    
2273
    tag_data_ptr fToneCurveTag;
2274
2275
  public:
2276
  
2277
    profile_tag_set (dng_tiff_directory &directory,
2278
             const dng_camera_profile &profile);
2279
    
2280
  };
2281
  
2282
/******************************************************************************/
2283
2284
profile_tag_set::profile_tag_set (dng_tiff_directory &directory,
2285
                        const dng_camera_profile &profile)
2286
                
2287
72.4k
  : fCalibrationIlluminant1 (tcCalibrationIlluminant1,
2288
72.4k
                 (uint16) profile.CalibrationIlluminant1 ())
2289
                 
2290
72.4k
  , fCalibrationIlluminant2 (tcCalibrationIlluminant2,
2291
72.4k
                 (uint16) profile.CalibrationIlluminant2 ())
2292
  
2293
72.4k
  , fColorMatrix1 (tcColorMatrix1,
2294
72.4k
             profile.ColorMatrix1 ())
2295
            
2296
72.4k
  , fColorMatrix2 (tcColorMatrix2,
2297
72.4k
             profile.ColorMatrix2 ())
2298
2299
72.4k
  , fForwardMatrix1 (tcForwardMatrix1,
2300
72.4k
             profile.ForwardMatrix1 ())
2301
            
2302
72.4k
  , fForwardMatrix2 (tcForwardMatrix2,
2303
72.4k
             profile.ForwardMatrix2 ())
2304
            
2305
72.4k
  , fReductionMatrix1 (tcReductionMatrix1,
2306
72.4k
               profile.ReductionMatrix1 ())
2307
            
2308
72.4k
  , fReductionMatrix2 (tcReductionMatrix2,
2309
72.4k
               profile.ReductionMatrix2 ())
2310
               
2311
72.4k
  , fProfileName (tcProfileName,
2312
72.4k
            profile.Name (),
2313
72.4k
            false)
2314
               
2315
72.4k
  , fProfileCalibrationSignature (tcProfileCalibrationSignature,
2316
72.4k
                    profile.ProfileCalibrationSignature (),
2317
72.4k
                    false)
2318
            
2319
72.4k
  , fEmbedPolicyTag (tcProfileEmbedPolicy,
2320
72.4k
             profile.EmbedPolicy ())
2321
             
2322
72.4k
  , fCopyrightTag (tcProfileCopyright,
2323
72.4k
             profile.Copyright (),
2324
72.4k
             false)
2325
             
2326
72.4k
  , fHueSatMapDims (tcProfileHueSatMapDims, 
2327
72.4k
            fHueSatMapDimData,
2328
72.4k
            3)
2329
    
2330
72.4k
  , fHueSatData1 (tcProfileHueSatMapData1,
2331
72.4k
            ttFloat,
2332
72.4k
            profile.HueSatDeltas1 ().DeltasCount () * 3,
2333
72.4k
            profile.HueSatDeltas1 ().GetConstDeltas ())
2334
            
2335
72.4k
  , fHueSatData2 (tcProfileHueSatMapData2,
2336
72.4k
            ttFloat,
2337
72.4k
            profile.HueSatDeltas2 ().DeltasCount () * 3,
2338
72.4k
            profile.HueSatDeltas2 ().GetConstDeltas ())
2339
            
2340
72.4k
  , fHueSatMapEncodingTag (tcProfileHueSatMapEncoding,
2341
72.4k
                 profile.HueSatMapEncoding ())
2342
             
2343
72.4k
  , fLookTableDims (tcProfileLookTableDims,
2344
72.4k
            fLookTableDimData,
2345
72.4k
            3)
2346
            
2347
72.4k
  , fLookTableData (tcProfileLookTableData,
2348
72.4k
            ttFloat,
2349
72.4k
            profile.LookTable ().DeltasCount () * 3,
2350
72.4k
              profile.LookTable ().GetConstDeltas ())
2351
            
2352
72.4k
  , fLookTableEncodingTag (tcProfileLookTableEncoding,
2353
72.4k
                 profile.LookTableEncoding ())
2354
             
2355
72.4k
  , fBaselineExposureOffsetTag (tcBaselineExposureOffset,
2356
72.4k
                  profile.BaselineExposureOffset ())
2357
             
2358
72.4k
  , fDefaultBlackRenderTag (tcDefaultBlackRender,
2359
72.4k
                profile.DefaultBlackRender ())
2360
             
2361
72.4k
  , fToneCurveBuffer ()
2362
            
2363
72.4k
  , fToneCurveTag (tcProfileToneCurve,
2364
72.4k
             ttFloat,
2365
72.4k
             0,
2366
72.4k
             NULL)
2367
2368
72.4k
  {
2369
  
2370
72.4k
  if (profile.HasColorMatrix1 ())
2371
60.0k
    {
2372
  
2373
60.0k
    uint32 colorChannels = profile.ColorMatrix1 ().Rows ();
2374
    
2375
60.0k
    directory.Add (&fCalibrationIlluminant1);
2376
    
2377
60.0k
    directory.Add (&fColorMatrix1);
2378
    
2379
60.0k
    if (fForwardMatrix1.Count () == colorChannels * 3)
2380
0
      {
2381
      
2382
0
      directory.Add (&fForwardMatrix1);
2383
2384
0
      }
2385
    
2386
60.0k
    if (colorChannels > 3 && fReductionMatrix1.Count () == colorChannels * 3)
2387
0
      {
2388
      
2389
0
      directory.Add (&fReductionMatrix1);
2390
      
2391
0
      }
2392
      
2393
60.0k
    if (profile.HasColorMatrix2 ())
2394
1.44k
      {
2395
    
2396
1.44k
      directory.Add (&fCalibrationIlluminant2);
2397
    
2398
1.44k
      directory.Add (&fColorMatrix2);
2399
        
2400
1.44k
      if (fForwardMatrix2.Count () == colorChannels * 3)
2401
0
        {
2402
        
2403
0
        directory.Add (&fForwardMatrix2);
2404
2405
0
        }
2406
    
2407
1.44k
      if (colorChannels > 3 && fReductionMatrix2.Count () == colorChannels * 3)
2408
0
        {
2409
        
2410
0
        directory.Add (&fReductionMatrix2);
2411
        
2412
0
        }
2413
  
2414
1.44k
      }
2415
      
2416
60.0k
    if (profile.Name ().NotEmpty ())
2417
60.0k
      {
2418
      
2419
60.0k
      directory.Add (&fProfileName);
2420
2421
60.0k
      }
2422
      
2423
60.0k
    if (profile.ProfileCalibrationSignature ().NotEmpty ())
2424
2.29k
      {
2425
      
2426
2.29k
      directory.Add (&fProfileCalibrationSignature);
2427
      
2428
2.29k
      }
2429
      
2430
60.0k
    directory.Add (&fEmbedPolicyTag);
2431
    
2432
60.0k
    if (profile.Copyright ().NotEmpty ())
2433
9.10k
      {
2434
      
2435
9.10k
      directory.Add (&fCopyrightTag);
2436
      
2437
9.10k
      }
2438
    
2439
60.0k
    bool haveHueSat1 = profile.HueSatDeltas1 ().IsValid ();
2440
    
2441
60.0k
    bool haveHueSat2 = profile.HueSatDeltas2 ().IsValid () &&
2442
358
               profile.HasColorMatrix2 ();
2443
2444
60.0k
    if (haveHueSat1 || haveHueSat2)
2445
898
      {
2446
      
2447
898
      uint32 hueDivs = 0;
2448
898
      uint32 satDivs = 0;
2449
898
      uint32 valDivs = 0;
2450
2451
898
      if (haveHueSat1)
2452
602
        {
2453
2454
602
        profile.HueSatDeltas1 ().GetDivisions (hueDivs,
2455
602
                             satDivs,
2456
602
                             valDivs);
2457
2458
602
        }
2459
2460
296
      else
2461
296
        {
2462
2463
296
        profile.HueSatDeltas2 ().GetDivisions (hueDivs,
2464
296
                             satDivs,
2465
296
                             valDivs);
2466
2467
296
        }
2468
        
2469
898
      fHueSatMapDimData [0] = hueDivs;
2470
898
      fHueSatMapDimData [1] = satDivs;
2471
898
      fHueSatMapDimData [2] = valDivs;
2472
      
2473
898
      directory.Add (&fHueSatMapDims);
2474
2475
      // Don't bother including the ProfileHueSatMapEncoding tag unless it's
2476
      // non-linear.
2477
2478
898
      if (profile.HueSatMapEncoding () != encoding_Linear)
2479
0
        {
2480
2481
0
        directory.Add (&fHueSatMapEncodingTag);
2482
2483
0
        }
2484
    
2485
898
      }
2486
      
2487
60.0k
    if (haveHueSat1)
2488
602
      {
2489
      
2490
602
      directory.Add (&fHueSatData1);
2491
      
2492
602
      }
2493
      
2494
60.0k
    if (haveHueSat2)
2495
296
      {
2496
      
2497
296
      directory.Add (&fHueSatData2);
2498
      
2499
296
      }
2500
      
2501
60.0k
    if (profile.HasLookTable ())
2502
13.4k
      {
2503
      
2504
13.4k
      uint32 hueDivs = 0;
2505
13.4k
      uint32 satDivs = 0;
2506
13.4k
      uint32 valDivs = 0;
2507
2508
13.4k
      profile.LookTable ().GetDivisions (hueDivs,
2509
13.4k
                         satDivs,
2510
13.4k
                         valDivs);
2511
2512
13.4k
      fLookTableDimData [0] = hueDivs;
2513
13.4k
      fLookTableDimData [1] = satDivs;
2514
13.4k
      fLookTableDimData [2] = valDivs;
2515
      
2516
13.4k
      directory.Add (&fLookTableDims);
2517
      
2518
13.4k
      directory.Add (&fLookTableData);
2519
      
2520
      // Don't bother including the ProfileLookTableEncoding tag unless it's
2521
      // non-linear.
2522
2523
13.4k
      if (profile.LookTableEncoding () != encoding_Linear)
2524
0
        {
2525
2526
0
        directory.Add (&fLookTableEncodingTag);
2527
2528
0
        }
2529
    
2530
13.4k
      }
2531
2532
    // Don't bother including the BaselineExposureOffset tag unless it's both
2533
    // valid and non-zero.
2534
2535
60.0k
    if (profile.BaselineExposureOffset ().IsValid ())
2536
60.0k
      {
2537
2538
60.0k
      if (profile.BaselineExposureOffset ().As_real64 () != 0.0)
2539
9.74k
        {
2540
      
2541
9.74k
        directory.Add (&fBaselineExposureOffsetTag);
2542
2543
9.74k
        }
2544
        
2545
60.0k
      }
2546
      
2547
60.0k
    if (profile.DefaultBlackRender () != defaultBlackRender_Auto)
2548
11.8k
      {
2549
2550
11.8k
      directory.Add (&fDefaultBlackRenderTag);
2551
2552
11.8k
      }
2553
    
2554
60.0k
    if (profile.ToneCurve ().IsValid ())
2555
23.1k
      {
2556
      
2557
      // Tone curve stored as pairs of 32-bit coordinates.  Probably could do with
2558
      // 16-bits here, but should be small number of points so...
2559
      
2560
23.1k
      uint32 toneCurvePoints = (uint32) (profile.ToneCurve ().fCoord.size ());
2561
2562
23.1k
      fToneCurveBuffer.Allocate (SafeUint32Mult(toneCurvePoints, 2),
2563
23.1k
                     sizeof (real32));
2564
2565
23.1k
      real32 *points = fToneCurveBuffer.Buffer_real32 ();
2566
      
2567
23.1k
      fToneCurveTag.SetCount (toneCurvePoints * 2);
2568
23.1k
      fToneCurveTag.SetData  (points);
2569
      
2570
72.2k
      for (uint32 i = 0; i < toneCurvePoints; i++)
2571
49.0k
        {
2572
2573
        // Transpose coordinates so they are in a more expected
2574
        // order (domain -> range).
2575
2576
49.0k
        points [i * 2    ] = (real32) profile.ToneCurve ().fCoord [i].h;
2577
49.0k
        points [i * 2 + 1] = (real32) profile.ToneCurve ().fCoord [i].v;
2578
2579
49.0k
        }
2580
2581
23.1k
      directory.Add (&fToneCurveTag);
2582
2583
23.1k
      }
2584
2585
60.0k
    }
2586
  
2587
72.4k
  }
2588
2589
/******************************************************************************/
2590
2591
tiff_dng_extended_color_profile::tiff_dng_extended_color_profile 
2592
                 (const dng_camera_profile &profile)
2593
2594
56.2k
  : fProfile (profile)
2595
2596
56.2k
  {
2597
  
2598
56.2k
  }
2599
2600
/******************************************************************************/
2601
2602
void tiff_dng_extended_color_profile::Put (dng_stream &stream,
2603
                       bool includeModelRestriction)
2604
56.2k
  {
2605
  
2606
  // Profile header.
2607
2608
56.2k
  stream.Put_uint16 (stream.BigEndian () ? byteOrderMM : byteOrderII);
2609
2610
56.2k
  stream.Put_uint16 (magicExtendedProfile);
2611
2612
56.2k
  stream.Put_uint32 (8);
2613
  
2614
  // Profile tags.
2615
  
2616
56.2k
  profile_tag_set tagSet (*this, fProfile);
2617
2618
  // Camera this profile is for.
2619
2620
56.2k
  tag_string cameraModelTag (tcUniqueCameraModel, 
2621
56.2k
                 fProfile.UniqueCameraModelRestriction ());
2622
                 
2623
56.2k
  if (includeModelRestriction)
2624
0
    {
2625
    
2626
0
    if (fProfile.UniqueCameraModelRestriction ().NotEmpty ())
2627
0
      {
2628
      
2629
0
      Add (&cameraModelTag);
2630
      
2631
0
      }
2632
      
2633
0
    }
2634
2635
  // Write it all out.
2636
2637
56.2k
  dng_tiff_directory::Put (stream, offsetsRelativeToExplicitBase, 8);
2638
2639
56.2k
  }
2640
2641
/*****************************************************************************/
2642
2643
tag_dng_noise_profile::tag_dng_noise_profile (const dng_noise_profile &profile)
2644
2645
21.7k
  : tag_data_ptr (tcNoiseProfile,
2646
21.7k
            ttDouble,
2647
21.7k
            2 * profile.NumFunctions (),
2648
21.7k
            fValues)
2649
2650
21.7k
  {
2651
2652
21.7k
  DNG_REQUIRE (profile.NumFunctions () <= kMaxColorPlanes,
2653
21.7k
         "Too many noise functions in tag_dng_noise_profile.");
2654
2655
22.5k
  for (uint32 i = 0; i < profile.NumFunctions (); i++)
2656
793
    {
2657
2658
793
    fValues [(2 * i)  ] = profile.NoiseFunction (i).Scale  ();
2659
793
    fValues [(2 * i) + 1] = profile.NoiseFunction (i).Offset ();
2660
2661
793
    }
2662
  
2663
21.7k
  }
2664
    
2665
/*****************************************************************************/
2666
2667
dng_image_writer::dng_image_writer ()
2668
103k
  {
2669
  
2670
103k
  }
2671
2672
/*****************************************************************************/
2673
2674
dng_image_writer::~dng_image_writer ()
2675
103k
  {
2676
  
2677
103k
  }
2678
                
2679
/*****************************************************************************/
2680
2681
uint32 dng_image_writer::CompressedBufferSize (const dng_ifd &ifd,
2682
                         uint32 uncompressedSize)
2683
85.2k
  {
2684
  
2685
85.2k
  switch (ifd.fCompression)
2686
85.2k
    {
2687
    
2688
16.5k
    case ccLZW:
2689
16.5k
      {
2690
      
2691
      // Add lots of slop for LZW to expand data.
2692
        
2693
16.5k
      return SafeUint32Add (SafeUint32Mult (uncompressedSize, 2), 1024);
2694
      
2695
0
      }
2696
      
2697
4.88k
    case ccDeflate:
2698
4.88k
      {
2699
    
2700
      // ZLib says maximum is source size + 0.1% + 12 bytes.
2701
      
2702
4.88k
      return SafeUint32Add (SafeUint32Add (uncompressedSize,
2703
4.88k
                         uncompressedSize >> 8), 64);
2704
      
2705
0
      }
2706
      
2707
11.2k
    case ccJPEG:
2708
11.2k
      {
2709
      
2710
      // If we are saving lossless JPEG from an 8-bit image, reserve
2711
      // space to pad the data out to 16-bits.
2712
      
2713
11.2k
      if (ifd.fBitsPerSample [0] <= 8)
2714
103
        {
2715
        
2716
103
        return SafeUint32Mult (uncompressedSize, 2);
2717
        
2718
103
        }
2719
        
2720
11.1k
      break;
2721
  
2722
11.2k
      }
2723
      
2724
52.5k
    default:
2725
52.5k
      break;
2726
    
2727
85.2k
    }
2728
  
2729
63.7k
  return 0;
2730
  
2731
85.2k
  }
2732
                
2733
/******************************************************************************/
2734
2735
static void EncodeDelta8 (uint8 *dPtr,
2736
              uint32 rows,
2737
              uint32 cols,
2738
              uint32 channels)
2739
0
  {
2740
  
2741
0
  const uint32 dRowStep = cols * channels;
2742
  
2743
0
  for (uint32 row = 0; row < rows; row++)
2744
0
    {
2745
    
2746
0
    for (uint32 col = cols - 1; col > 0; col--)
2747
0
      {
2748
      
2749
0
      for (uint32 channel = 0; channel < channels; channel++)
2750
0
        {
2751
        
2752
0
        dPtr [col * channels + channel] -= dPtr [(col - 1) * channels + channel];
2753
        
2754
0
        }
2755
      
2756
0
      }
2757
    
2758
0
    dPtr += dRowStep;
2759
    
2760
0
    }
2761
2762
0
  }
2763
2764
/******************************************************************************/
2765
2766
static void EncodeDelta16 (uint16 *dPtr,
2767
               uint32 rows,
2768
               uint32 cols,
2769
               uint32 channels)
2770
41.0k
  {
2771
  
2772
41.0k
  const uint32 dRowStep = cols * channels;
2773
  
2774
30.2M
  for (uint32 row = 0; row < rows; row++)
2775
30.2M
    {
2776
    
2777
1.33G
    for (uint32 col = cols - 1; col > 0; col--)
2778
1.30G
      {
2779
      
2780
3.01G
      for (uint32 channel = 0; channel < channels; channel++)
2781
1.71G
        {
2782
        
2783
1.71G
        dPtr [col * channels + channel] -= dPtr [(col - 1) * channels + channel];
2784
        
2785
1.71G
        }
2786
      
2787
1.30G
      }
2788
    
2789
30.2M
    dPtr += dRowStep;
2790
    
2791
30.2M
    }
2792
2793
41.0k
  }
2794
  
2795
/******************************************************************************/
2796
2797
static void EncodeDelta32 (uint32 *dPtr,
2798
               uint32 rows,
2799
               uint32 cols,
2800
               uint32 channels)
2801
1.62k
  {
2802
  
2803
1.62k
  const uint32 dRowStep = cols * channels;
2804
  
2805
709k
  for (uint32 row = 0; row < rows; row++)
2806
707k
    {
2807
    
2808
82.0M
    for (uint32 col = cols - 1; col > 0; col--)
2809
81.3M
      {
2810
      
2811
167M
      for (uint32 channel = 0; channel < channels; channel++)
2812
85.7M
        {
2813
        
2814
85.7M
        dPtr [col * channels + channel] -= dPtr [(col - 1) * channels + channel];
2815
        
2816
85.7M
        }
2817
      
2818
81.3M
      }
2819
    
2820
707k
    dPtr += dRowStep;
2821
    
2822
707k
    }
2823
2824
1.62k
  }
2825
  
2826
/*****************************************************************************/
2827
2828
inline void EncodeDeltaBytes (uint8 *bytePtr, int32 cols, int32 channels)
2829
4.00M
  {
2830
  
2831
4.00M
  if (channels == 1)
2832
3.68M
    {
2833
    
2834
3.68M
    bytePtr += (cols - 1);
2835
    
2836
3.68M
    uint8 this0 = bytePtr [0];
2837
    
2838
2.41G
    for (int32 col = 1; col < cols; col++)
2839
2.41G
      {
2840
      
2841
2.41G
      uint8 prev0 = bytePtr [-1];
2842
      
2843
2.41G
      this0 -= prev0;
2844
      
2845
2.41G
      bytePtr [0] = this0;
2846
      
2847
2.41G
      this0 = prev0;
2848
      
2849
2.41G
      bytePtr -= 1;
2850
2851
2.41G
      }
2852
  
2853
3.68M
    }
2854
    
2855
324k
  else if (channels == 3)
2856
83.5k
    {
2857
    
2858
83.5k
    bytePtr += (cols - 1) * 3;
2859
    
2860
83.5k
    uint8 this0 = bytePtr [0];
2861
83.5k
    uint8 this1 = bytePtr [1];
2862
83.5k
    uint8 this2 = bytePtr [2];
2863
    
2864
24.9M
    for (int32 col = 1; col < cols; col++)
2865
24.8M
      {
2866
      
2867
24.8M
      uint8 prev0 = bytePtr [-3];
2868
24.8M
      uint8 prev1 = bytePtr [-2];
2869
24.8M
      uint8 prev2 = bytePtr [-1];
2870
      
2871
24.8M
      this0 -= prev0;
2872
24.8M
      this1 -= prev1;
2873
24.8M
      this2 -= prev2;
2874
      
2875
24.8M
      bytePtr [0] = this0;
2876
24.8M
      bytePtr [1] = this1;
2877
24.8M
      bytePtr [2] = this2;
2878
      
2879
24.8M
      this0 = prev0;
2880
24.8M
      this1 = prev1;
2881
24.8M
      this2 = prev2;
2882
      
2883
24.8M
      bytePtr -= 3;
2884
2885
24.8M
      }
2886
  
2887
83.5k
    }
2888
    
2889
240k
  else
2890
240k
    {
2891
  
2892
240k
    uint32 rowBytes = cols * channels;
2893
    
2894
240k
    bytePtr += rowBytes - 1;
2895
    
2896
92.2M
    for (uint32 col = channels; col < rowBytes; col++)
2897
91.9M
      {
2898
      
2899
91.9M
      bytePtr [0] -= bytePtr [-channels];
2900
        
2901
91.9M
      bytePtr--;
2902
2903
91.9M
      }
2904
      
2905
240k
    }
2906
2907
4.00M
  }
2908
2909
/*****************************************************************************/
2910
2911
static void EncodeFPDelta (uint8 *buffer,
2912
               uint8 *temp,
2913
               int32 cols,
2914
               int32 channels,
2915
               int32 bytesPerSample)
2916
4.00M
  {
2917
  
2918
4.00M
  int32 rowIncrement = cols * channels;
2919
  
2920
4.00M
  if (bytesPerSample == 2)
2921
1.45M
    {
2922
    
2923
1.45M
    const uint8 *src = buffer;
2924
    
2925
    #if qDNGBigEndian
2926
    uint8 *dst0 = temp;
2927
    uint8 *dst1 = temp + rowIncrement;
2928
    #else
2929
1.45M
    uint8 *dst1 = temp;
2930
1.45M
    uint8 *dst0 = temp + rowIncrement;
2931
1.45M
    #endif
2932
        
2933
217M
    for (int32 col = 0; col < rowIncrement; ++col)
2934
216M
      {
2935
      
2936
216M
      dst0 [col] = src [0];
2937
216M
      dst1 [col] = src [1];
2938
      
2939
216M
      src += 2;
2940
      
2941
216M
      }
2942
      
2943
1.45M
    }
2944
    
2945
2.55M
  else if (bytesPerSample == 3)
2946
115k
    {
2947
    
2948
115k
    const uint8 *src = buffer;
2949
    
2950
115k
    uint8 *dst0 = temp;
2951
115k
    uint8 *dst1 = temp + rowIncrement;
2952
115k
    uint8 *dst2 = temp + rowIncrement * 2;
2953
        
2954
31.1M
    for (int32 col = 0; col < rowIncrement; ++col)
2955
31.0M
      {
2956
      
2957
31.0M
      dst0 [col] = src [0];
2958
31.0M
      dst1 [col] = src [1];
2959
31.0M
      dst2 [col] = src [2];
2960
      
2961
31.0M
      src += 3;
2962
      
2963
31.0M
      }
2964
      
2965
115k
    }
2966
    
2967
2.44M
  else
2968
2.44M
    {
2969
    
2970
2.44M
    const uint8 *src = buffer;
2971
    
2972
    #if qDNGBigEndian
2973
    uint8 *dst0 = temp;
2974
    uint8 *dst1 = temp + rowIncrement;
2975
    uint8 *dst2 = temp + rowIncrement * 2;
2976
    uint8 *dst3 = temp + rowIncrement * 3;
2977
    #else
2978
2.44M
    uint8 *dst3 = temp;
2979
2.44M
    uint8 *dst2 = temp + rowIncrement;
2980
2.44M
    uint8 *dst1 = temp + rowIncrement * 2;
2981
2.44M
    uint8 *dst0 = temp + rowIncrement * 3;
2982
2.44M
    #endif
2983
        
2984
516M
    for (int32 col = 0; col < rowIncrement; ++col)
2985
514M
      {
2986
      
2987
514M
      dst0 [col] = src [0];
2988
514M
      dst1 [col] = src [1];
2989
514M
      dst2 [col] = src [2];
2990
514M
      dst3 [col] = src [3];
2991
      
2992
514M
      src += 4;
2993
      
2994
514M
      }
2995
      
2996
2.44M
    }
2997
    
2998
4.00M
  EncodeDeltaBytes (temp, cols*bytesPerSample, channels);
2999
  
3000
4.00M
  memcpy (buffer, temp, cols*bytesPerSample*channels);
3001
  
3002
4.00M
  }
3003
3004
/*****************************************************************************/
3005
3006
void dng_image_writer::EncodePredictor (dng_host &host,
3007
                      const dng_ifd &ifd,
3008
                          dng_pixel_buffer &buffer,
3009
                    AutoPtr<dng_memory_block> &tempBuffer)
3010
468k
  {
3011
  
3012
468k
  switch (ifd.fPredictor)
3013
468k
    {
3014
    
3015
45.1k
    case cpHorizontalDifference:
3016
45.5k
    case cpHorizontalDifferenceX2:
3017
45.5k
    case cpHorizontalDifferenceX4:
3018
45.5k
      {
3019
      
3020
45.5k
      int32 xFactor = 1;
3021
      
3022
45.5k
      if (ifd.fPredictor == cpHorizontalDifferenceX2)
3023
412
        {
3024
412
        xFactor = 2;
3025
412
        }
3026
        
3027
45.1k
      else if (ifd.fPredictor == cpHorizontalDifferenceX4)
3028
8
        {
3029
8
        xFactor = 4;
3030
8
        }
3031
      
3032
45.5k
      switch (buffer.fPixelType)
3033
45.5k
        {
3034
        
3035
0
        case ttByte:
3036
0
          {
3037
          
3038
0
          EncodeDelta8 ((uint8 *) buffer.fData,
3039
0
                  buffer.fArea.H (),
3040
0
                  buffer.fArea.W () / xFactor,
3041
0
                  buffer.fPlanes    * xFactor);
3042
          
3043
0
          return;
3044
          
3045
0
          }
3046
          
3047
41.0k
        case ttShort:
3048
41.0k
          {
3049
          
3050
41.0k
          EncodeDelta16 ((uint16 *) buffer.fData,
3051
41.0k
                   buffer.fArea.H (),
3052
41.0k
                   buffer.fArea.W () / xFactor,
3053
41.0k
                   buffer.fPlanes    * xFactor);
3054
          
3055
41.0k
          return;
3056
          
3057
0
          }
3058
          
3059
1.62k
        case ttLong:
3060
1.62k
          {
3061
          
3062
1.62k
          EncodeDelta32 ((uint32 *) buffer.fData,
3063
1.62k
                   buffer.fArea.H (),
3064
1.62k
                   buffer.fArea.W () / xFactor,
3065
1.62k
                   buffer.fPlanes    * xFactor);
3066
          
3067
1.62k
          return;
3068
          
3069
0
          }
3070
          
3071
2.95k
        default:
3072
2.95k
          break;
3073
          
3074
45.5k
        }
3075
      
3076
2.95k
      break;
3077
      
3078
45.5k
      }
3079
      
3080
15.5k
    case cpFloatingPoint:
3081
16.3k
    case cpFloatingPointX2:
3082
16.3k
    case cpFloatingPointX4:
3083
16.3k
      {
3084
      
3085
16.3k
      int32 xFactor = 1;
3086
      
3087
16.3k
      if (ifd.fPredictor == cpFloatingPointX2)
3088
799
        {
3089
799
        xFactor = 2;
3090
799
        }
3091
        
3092
15.5k
      else if (ifd.fPredictor == cpFloatingPointX4)
3093
24
        {
3094
24
        xFactor = 4;
3095
24
        }
3096
      
3097
16.3k
      if (buffer.fRowStep < 0)
3098
0
        {
3099
0
        ThrowProgramError ("Row step may not be negative");
3100
0
        }
3101
16.3k
      uint32 tempBufferSize = SafeUint32Mult (
3102
16.3k
        static_cast<uint32>(buffer.fRowStep),
3103
16.3k
        buffer.fPixelSize);
3104
      
3105
16.3k
      if (!tempBuffer.Get () || tempBuffer->LogicalSize () < tempBufferSize)
3106
4.76k
        {
3107
        
3108
4.76k
        tempBuffer.Reset (host.Allocate (tempBufferSize));
3109
        
3110
4.76k
        }
3111
        
3112
4.02M
      for (int32 row = buffer.fArea.t; row < buffer.fArea.b; row++)
3113
4.00M
        {
3114
        
3115
4.00M
        EncodeFPDelta ((uint8 *) buffer.DirtyPixel (row, buffer.fArea.l, buffer.fPlane),
3116
4.00M
                 tempBuffer->Buffer_uint8 (),
3117
4.00M
                 buffer.fArea.W () / xFactor,
3118
4.00M
                 buffer.fPlanes    * xFactor,
3119
4.00M
                 buffer.fPixelSize);
3120
        
3121
4.00M
        }
3122
      
3123
16.3k
      return;
3124
      
3125
16.3k
      }
3126
      
3127
406k
    default:
3128
406k
      break;
3129
    
3130
468k
    }
3131
  
3132
409k
  if (ifd.fPredictor != cpNullPredictor)
3133
2.95k
    {
3134
    
3135
2.95k
    ThrowProgramError ();
3136
    
3137
2.95k
    }
3138
  
3139
409k
  }
3140
                
3141
/*****************************************************************************/
3142
3143
void dng_image_writer::ByteSwapBuffer (dng_host & /* host */,
3144
                     dng_pixel_buffer &buffer)
3145
0
  {
3146
  
3147
0
  uint32 pixels = buffer.fRowStep * buffer.fArea.H ();
3148
  
3149
0
  switch (buffer.fPixelSize)
3150
0
    {
3151
    
3152
0
    case 2:
3153
0
      {
3154
      
3155
0
      DoSwapBytes16 ((uint16 *) buffer.fData,
3156
0
               pixels);
3157
               
3158
0
      break;
3159
      
3160
0
      }
3161
      
3162
0
    case 4:
3163
0
      {
3164
      
3165
0
      DoSwapBytes32 ((uint32 *) buffer.fData,
3166
0
               pixels);
3167
               
3168
0
      break;
3169
      
3170
0
      }
3171
      
3172
0
    default:
3173
0
      break;
3174
      
3175
0
    }
3176
3177
0
  }
3178
                
3179
/*****************************************************************************/
3180
3181
void dng_image_writer::ReorderSubTileBlocks (const dng_ifd &ifd,
3182
                       dng_pixel_buffer &buffer,
3183
                       AutoPtr<dng_memory_block> &uncompressedBuffer,
3184
                       AutoPtr<dng_memory_block> &subTileBlockBuffer)
3185
0
  {
3186
  
3187
0
  uint32 blockRows = ifd.fSubTileBlockRows;
3188
0
  uint32 blockCols = ifd.fSubTileBlockCols;
3189
  
3190
0
  uint32 rowBlocks = buffer.fArea.H () / blockRows;
3191
0
  uint32 colBlocks = buffer.fArea.W () / blockCols;
3192
  
3193
0
  int32 rowStep = buffer.fRowStep * buffer.fPixelSize;
3194
0
  int32 colStep = buffer.fColStep * buffer.fPixelSize;
3195
  
3196
0
  int32 rowBlockStep = rowStep * blockRows;
3197
0
  int32 colBlockStep = colStep * blockCols;
3198
  
3199
0
  uint32 blockColBytes = blockCols * buffer.fPlanes * buffer.fPixelSize;
3200
  
3201
0
  const uint8 *s0 = uncompressedBuffer->Buffer_uint8 ();
3202
0
        uint8 *d0 = subTileBlockBuffer->Buffer_uint8 ();
3203
  
3204
0
  for (uint32 rowBlock = 0; rowBlock < rowBlocks; rowBlock++)
3205
0
    {
3206
    
3207
0
    const uint8 *s1 = s0;
3208
    
3209
0
    for (uint32 colBlock = 0; colBlock < colBlocks; colBlock++)
3210
0
      {
3211
      
3212
0
      const uint8 *s2 = s1;
3213
      
3214
0
      for (uint32 blockRow = 0; blockRow < blockRows; blockRow++)
3215
0
        {
3216
        
3217
0
        for (uint32 j = 0; j < blockColBytes; j++)
3218
0
          {
3219
          
3220
0
          d0 [j] = s2 [j];
3221
          
3222
0
          }
3223
          
3224
0
        d0 += blockColBytes;
3225
        
3226
0
        s2 += rowStep;
3227
        
3228
0
        }
3229
      
3230
0
      s1 += colBlockStep;
3231
      
3232
0
      }
3233
      
3234
0
    s0 += rowBlockStep;
3235
    
3236
0
    }
3237
    
3238
  // Copy back reordered pixels.
3239
    
3240
0
  DoCopyBytes (subTileBlockBuffer->Buffer      (),
3241
0
         uncompressedBuffer->Buffer      (),
3242
0
         uncompressedBuffer->LogicalSize ());
3243
  
3244
0
  }
3245
                
3246
/******************************************************************************/
3247
3248
class dng_lzw_compressor
3249
  {
3250
  
3251
  private:
3252
  
3253
    enum
3254
      {
3255
      kResetCode = 256,
3256
      kEndCode   = 257,
3257
      kTableSize = 4096
3258
      };
3259
3260
    // Compressor nodes have two son pointers.  The low order bit of
3261
    // the next code determines which pointer is used.  This cuts the
3262
    // number of nodes searched for the next code by two on average.
3263
3264
    struct LZWCompressorNode
3265
      {
3266
      int16 final;
3267
      int16 son0;
3268
      int16 son1;
3269
      int16 brother;
3270
      };
3271
      
3272
    dng_memory_data fBuffer;
3273
3274
    LZWCompressorNode *fTable;
3275
    
3276
    uint8 *fDstPtr;
3277
    
3278
    int32 fDstCount;
3279
    
3280
    int32 fBitOffset;
3281
3282
    int32 fNextCode;
3283
    
3284
    int32 fCodeSize;
3285
    
3286
  public:
3287
  
3288
    dng_lzw_compressor ();
3289
    
3290
    void Compress (const uint8 *sPtr,
3291
             uint8 *dPtr,
3292
             uint32 sCount,
3293
             uint32 &dCount);
3294
 
3295
  private:
3296
    
3297
    void InitTable ();
3298
  
3299
    int32 SearchTable (int32 w, int32 k) const
3300
3.06G
      {
3301
      
3302
3.06G
      DNG_ASSERT ((w >= 0) && (w <= kTableSize),
3303
3.06G
            "Bad w value in dng_lzw_compressor::SearchTable");
3304
      
3305
3.06G
      int32 son0 = fTable [w] . son0;
3306
3.06G
      int32 son1 = fTable [w] . son1;
3307
      
3308
      // Branchless version of:
3309
      // int32 code = (k & 1) ? son1 : son0;
3310
      
3311
3.06G
      int32 code = son0 + ((-((int32) (k & 1))) & (son1 - son0));
3312
3313
6.58G
      while (code > 0 && fTable [code].final != k)
3314
3.51G
        {
3315
3.51G
        code = fTable [code].brother;
3316
3.51G
        }
3317
3318
3.06G
      return code;
3319
3320
3.06G
      }
3321
3322
    void AddTable (int32 w, int32 k);
3323
    
3324
    void PutCodeWord (int32 code);
3325
3326
    // Hidden copy constructor and assignment operator.
3327
  
3328
    dng_lzw_compressor (const dng_lzw_compressor &compressor);
3329
    
3330
    dng_lzw_compressor & operator= (const dng_lzw_compressor &compressor);
3331
3332
  };
3333
3334
/******************************************************************************/
3335
3336
dng_lzw_compressor::dng_lzw_compressor ()
3337
3338
27.4k
  : fBuffer    ()
3339
27.4k
  , fTable     (NULL)
3340
27.4k
  , fDstPtr    (NULL)
3341
27.4k
  , fDstCount  (0)
3342
27.4k
  , fBitOffset (0)
3343
27.4k
  , fNextCode  (0)
3344
27.4k
  , fCodeSize  (0)
3345
  
3346
27.4k
  {
3347
  
3348
27.4k
  fBuffer.Allocate (kTableSize, sizeof (LZWCompressorNode));
3349
  
3350
27.4k
  fTable = (LZWCompressorNode *) fBuffer.Buffer ();
3351
  
3352
27.4k
  }
3353
3354
/******************************************************************************/
3355
3356
void dng_lzw_compressor::InitTable ()
3357
204k
  {
3358
3359
204k
  fCodeSize = 9;
3360
3361
204k
  fNextCode = 258;
3362
    
3363
204k
  LZWCompressorNode *node = &fTable [0];
3364
  
3365
52.4M
  for (int32 code = 0; code < 256; ++code)
3366
52.2M
    {
3367
    
3368
52.2M
    node->final   = (int16) code;
3369
52.2M
    node->son0    = -1;
3370
52.2M
    node->son1    = -1;
3371
52.2M
    node->brother = -1;
3372
    
3373
52.2M
    node++;
3374
    
3375
52.2M
    }
3376
    
3377
204k
  }
3378
3379
/******************************************************************************/
3380
3381
void dng_lzw_compressor::AddTable (int32 w, int32 k)
3382
708M
  {
3383
  
3384
708M
  DNG_ASSERT ((w >= 0) && (w <= kTableSize),
3385
708M
        "Bad w value in dng_lzw_compressor::AddTable");
3386
3387
708M
  LZWCompressorNode *node = &fTable [w];
3388
3389
708M
  int32 nextCode = fNextCode;
3390
3391
708M
  DNG_ASSERT ((nextCode >= 0) && (nextCode <= kTableSize),
3392
708M
        "Bad fNextCode value in dng_lzw_compressor::AddTable");
3393
  
3394
708M
  LZWCompressorNode *node2 = &fTable [nextCode];
3395
  
3396
708M
  fNextCode++;
3397
  
3398
708M
  int32 oldSon;
3399
  
3400
708M
  if( k&1 )
3401
341M
    {
3402
341M
    oldSon = node->son1;
3403
341M
    node->son1 = (int16) nextCode;
3404
341M
    }
3405
367M
  else
3406
367M
    {
3407
367M
    oldSon = node->son0;
3408
367M
    node->son0 = (int16) nextCode;
3409
367M
    }
3410
  
3411
708M
  node2->final   = (int16) k;
3412
708M
  node2->son0    = -1;
3413
708M
  node2->son1    = -1;
3414
708M
  node2->brother = (int16) oldSon;
3415
  
3416
708M
  if (nextCode == (1 << fCodeSize) - 1)
3417
570k
    {
3418
570k
    if (fCodeSize != 12)
3419
570k
      fCodeSize++;
3420
570k
    }
3421
    
3422
708M
  }
3423
3424
/******************************************************************************/
3425
3426
void dng_lzw_compressor::PutCodeWord (int32 code)
3427
708M
  {
3428
  
3429
708M
  int32 bit = (int32) (fBitOffset & 7);
3430
  
3431
708M
  int32 offset1 = fBitOffset >> 3;
3432
708M
  int32 offset2 = (fBitOffset + fCodeSize - 1) >> 3;
3433
    
3434
708M
  int32 shift1 = (fCodeSize + bit) -  8;
3435
708M
  int32 shift2 = (fCodeSize + bit) - 16;
3436
  
3437
708M
  uint8 byte1 = (uint8) (code >> shift1);
3438
  
3439
708M
  uint8 *dstPtr1 = fDstPtr + offset1;
3440
708M
  uint8 *dstPtr3 = fDstPtr + offset2;
3441
  
3442
708M
  if (offset1 + 1 == offset2)
3443
452M
    {
3444
    
3445
452M
    uint8 byte2 = (uint8) (code << (-shift2));
3446
    
3447
452M
    if (bit)
3448
422M
      *dstPtr1 |= byte1;
3449
30.1M
    else
3450
30.1M
      *dstPtr1 = byte1;
3451
    
3452
452M
    *dstPtr3 = byte2;
3453
    
3454
452M
    }
3455
3456
256M
  else
3457
256M
    {
3458
    
3459
256M
    int32 shift3 = (fCodeSize + bit) - 24;
3460
    
3461
256M
    uint8 byte2 = (uint8) (code >> shift2);
3462
256M
    uint8 byte3 = (uint8) (code << (-shift3));
3463
    
3464
256M
    uint8 *dstPtr2 = fDstPtr + (offset1 + 1);
3465
    
3466
256M
    if (bit)
3467
256M
      *dstPtr1 |= byte1;
3468
0
    else
3469
0
      *dstPtr1 = byte1;
3470
    
3471
256M
    *dstPtr2 = byte2;
3472
    
3473
256M
    *dstPtr3 = byte3;
3474
    
3475
256M
    }
3476
    
3477
708M
  fBitOffset += fCodeSize;
3478
  
3479
708M
  }
3480
3481
/******************************************************************************/
3482
3483
void dng_lzw_compressor::Compress (const uint8 *sPtr,
3484
                       uint8 *dPtr,
3485
                       uint32 sCount,
3486
                       uint32 &dCount)
3487
27.4k
  {
3488
  
3489
27.4k
  fDstPtr = dPtr;
3490
  
3491
27.4k
  fBitOffset = 0;
3492
  
3493
27.4k
  InitTable ();
3494
  
3495
27.4k
  PutCodeWord (kResetCode);
3496
  
3497
27.4k
  int32 code = -1;
3498
  
3499
27.4k
  int32 pixel;
3500
  
3501
27.4k
  if (sCount > 0)
3502
27.4k
    {
3503
    
3504
27.4k
    pixel = *sPtr;
3505
27.4k
    sPtr = sPtr + 1;
3506
27.4k
    code = pixel;
3507
3508
27.4k
    sCount--;
3509
3510
3.06G
    while (sCount--)
3511
3.06G
      {
3512
3513
3.06G
      pixel = *sPtr;
3514
3.06G
      sPtr = sPtr + 1;
3515
      
3516
3.06G
      int32 newCode = SearchTable (code, pixel);
3517
      
3518
3.06G
      if (newCode == -1)
3519
708M
        {
3520
        
3521
708M
        PutCodeWord (code);
3522
        
3523
708M
        if (fNextCode < 4093)
3524
708M
          {
3525
708M
          AddTable (code, pixel);
3526
708M
          }
3527
176k
        else
3528
176k
          {
3529
176k
          PutCodeWord (kResetCode);
3530
176k
          InitTable ();
3531
176k
          }
3532
          
3533
708M
        code = pixel;
3534
        
3535
708M
        }
3536
        
3537
2.35G
      else
3538
2.35G
        code = newCode;
3539
        
3540
3.06G
      }
3541
    
3542
27.4k
    }
3543
    
3544
27.4k
  if (code != -1)
3545
27.4k
    {
3546
27.4k
    PutCodeWord (code);
3547
27.4k
    AddTable (code, 0);
3548
27.4k
    }
3549
    
3550
27.4k
  PutCodeWord (kEndCode);
3551
3552
27.4k
  dCount = (fBitOffset + 7) >> 3;
3553
3554
27.4k
  }
3555
3556
/*****************************************************************************/
3557
3558
#if qDNGUseLibJPEG
3559
3560
/*****************************************************************************/
3561
3562
static void dng_error_exit (j_common_ptr cinfo)
3563
0
  {
3564
  
3565
  // Output message.
3566
  
3567
0
  (*cinfo->err->output_message) (cinfo);
3568
  
3569
  // Convert to a dng_exception.
3570
3571
0
  switch (cinfo->err->msg_code)
3572
0
    {
3573
    
3574
0
    case JERR_OUT_OF_MEMORY:
3575
0
      {
3576
0
      ThrowMemoryFull ();
3577
0
      break;
3578
0
      }
3579
      
3580
0
    default:
3581
0
      {
3582
0
      ThrowBadFormat ();
3583
0
      }
3584
      
3585
0
    }
3586
      
3587
0
  }
3588
3589
/*****************************************************************************/
3590
3591
static void dng_output_message (j_common_ptr cinfo)
3592
0
  {
3593
  
3594
  // Format message to string.
3595
  
3596
0
  char buffer [JMSG_LENGTH_MAX];
3597
3598
0
  (*cinfo->err->format_message) (cinfo, buffer);
3599
  
3600
  // Report the libjpeg message as a warning.
3601
  
3602
0
  ReportWarning ("libjpeg", buffer);
3603
3604
0
  }
3605
3606
/*****************************************************************************/
3607
3608
struct dng_jpeg_stream_dest
3609
  {
3610
  
3611
  struct jpeg_destination_mgr pub;
3612
  
3613
  dng_stream *fStream;
3614
  
3615
  uint8 fBuffer [4096];
3616
  
3617
  };
3618
3619
/*****************************************************************************/
3620
3621
static void dng_init_destination (j_compress_ptr cinfo)
3622
20.9k
  {
3623
  
3624
20.9k
  dng_jpeg_stream_dest *dest = (dng_jpeg_stream_dest *) cinfo->dest;
3625
3626
20.9k
  dest->pub.next_output_byte = dest->fBuffer;
3627
20.9k
  dest->pub.free_in_buffer   = sizeof (dest->fBuffer);
3628
  
3629
20.9k
  }
3630
3631
/*****************************************************************************/
3632
3633
static boolean dng_empty_output_buffer (j_compress_ptr cinfo)
3634
25.3k
  {
3635
  
3636
25.3k
  dng_jpeg_stream_dest *dest = (dng_jpeg_stream_dest *) cinfo->dest;
3637
  
3638
25.3k
  dest->fStream->Put (dest->fBuffer, sizeof (dest->fBuffer));
3639
3640
25.3k
  dest->pub.next_output_byte = dest->fBuffer;
3641
25.3k
  dest->pub.free_in_buffer   = sizeof (dest->fBuffer);
3642
3643
25.3k
  return TRUE;
3644
  
3645
25.3k
  }
3646
3647
/*****************************************************************************/
3648
3649
static void dng_term_destination (j_compress_ptr cinfo)
3650
20.9k
  {
3651
  
3652
20.9k
  dng_jpeg_stream_dest *dest = (dng_jpeg_stream_dest *) cinfo->dest;
3653
  
3654
20.9k
  uint32 datacount = sizeof (dest->fBuffer) -
3655
20.9k
             (uint32) dest->pub.free_in_buffer;
3656
  
3657
20.9k
  if (datacount)
3658
20.9k
    {
3659
20.9k
    dest->fStream->Put (dest->fBuffer, datacount);
3660
20.9k
    }
3661
3662
20.9k
  }
3663
3664
/*****************************************************************************/
3665
3666
static void jpeg_set_adobe_quality (struct jpeg_compress_struct *cinfo,
3667
                  int32 quality)
3668
20.9k
  {
3669
  
3670
  // If out of range, map to default.
3671
    
3672
20.9k
  if (quality < 0 || quality > 12)
3673
0
    {
3674
0
    quality = 10;
3675
0
    }
3676
    
3677
  // Adobe turns off chroma downsampling at high quality levels.
3678
  
3679
20.9k
  bool useChromaDownsampling = (quality <= 6);
3680
    
3681
  // Approximate mapping from Adobe quality levels to LibJPEG levels.
3682
  
3683
20.9k
  const int kLibJPEGQuality [13] =
3684
20.9k
    {
3685
20.9k
    5, 11, 23, 34, 46, 63, 76, 77, 86, 90, 94, 97, 99
3686
20.9k
    };
3687
    
3688
20.9k
  quality = kLibJPEGQuality [quality];
3689
  
3690
20.9k
  jpeg_set_quality (cinfo, quality, TRUE);
3691
  
3692
  // LibJPEG defaults to always using chroma downsampling.  Turn if off
3693
  // if we need it off to match Adobe.
3694
  
3695
20.9k
  if (!useChromaDownsampling)
3696
19.5k
    {
3697
    
3698
19.5k
    cinfo->comp_info [0].h_samp_factor = 1;
3699
19.5k
    cinfo->comp_info [0].h_samp_factor = 1;
3700
    
3701
19.5k
    }
3702
        
3703
20.9k
  }
3704
3705
/*****************************************************************************/
3706
3707
#endif
3708
3709
/*****************************************************************************/
3710
3711
void dng_image_writer::WriteData (dng_host &host,
3712
                  const dng_ifd &ifd,
3713
                      dng_stream &stream,
3714
                      dng_pixel_buffer &buffer,
3715
                  AutoPtr<dng_memory_block> &compressedBuffer)
3716
465k
  {
3717
  
3718
465k
  switch (ifd.fCompression)
3719
465k
    {
3720
    
3721
215k
    case ccUncompressed:
3722
215k
      {
3723
      
3724
      // Special case support for when we save to 8-bits from
3725
      // 16-bit data.
3726
      
3727
215k
      if (ifd.fBitsPerSample [0] == 8 && buffer.fPixelType == ttShort)
3728
0
        {
3729
        
3730
0
        uint32 count = buffer.fRowStep *
3731
0
                 buffer.fArea.H ();
3732
                 
3733
0
        const uint16 *sPtr = (const uint16 *) buffer.fData;
3734
        
3735
0
        for (uint32 j = 0; j < count; j++)
3736
0
          {
3737
          
3738
0
          stream.Put_uint8 ((uint8) sPtr [j]);
3739
          
3740
0
          }
3741
        
3742
0
        }
3743
        
3744
215k
      else
3745
215k
        {
3746
  
3747
        // Swap bytes if required.
3748
        
3749
215k
        if (stream.SwapBytes ())
3750
0
          {
3751
          
3752
0
          ByteSwapBuffer (host, buffer);
3753
                    
3754
0
          }
3755
      
3756
        // Write the bytes.
3757
        
3758
215k
        stream.Put (buffer.fData, buffer.fRowStep *
3759
215k
                      buffer.fArea.H () *
3760
215k
                      buffer.fPixelSize);
3761
                      
3762
215k
        }
3763
      
3764
215k
      break;
3765
      
3766
0
      }
3767
      
3768
27.4k
    case ccLZW:
3769
45.4k
    case ccDeflate:
3770
45.4k
      {
3771
      
3772
      // Both these compression algorithms are byte based.  The floating
3773
      // point predictor already does byte ordering, so don't ever swap
3774
      // when using it.
3775
      
3776
45.4k
      if (stream.SwapBytes () && ifd.fPredictor != cpFloatingPoint)
3777
0
        {
3778
        
3779
0
        ByteSwapBuffer (host,
3780
0
                buffer);
3781
                
3782
0
        }
3783
      
3784
      // Run the compression algorithm.
3785
        
3786
45.4k
      uint32 sBytes = buffer.fRowStep *
3787
45.4k
              buffer.fArea.H () *
3788
45.4k
              buffer.fPixelSize;
3789
        
3790
45.4k
      uint8 *sBuffer = (uint8 *) buffer.fData;
3791
        
3792
45.4k
      uint32 dBytes = 0;
3793
        
3794
45.4k
      uint8 *dBuffer = compressedBuffer->Buffer_uint8 ();
3795
      
3796
45.4k
      if (ifd.fCompression == ccLZW)
3797
27.4k
        {
3798
        
3799
27.4k
        dng_lzw_compressor lzwCompressor;
3800
        
3801
27.4k
        lzwCompressor.Compress (sBuffer,
3802
27.4k
                    dBuffer,
3803
27.4k
                    sBytes,
3804
27.4k
                    dBytes);
3805
                    
3806
27.4k
        }
3807
        
3808
17.9k
      else
3809
17.9k
        {
3810
        
3811
17.9k
        uLongf dCount = compressedBuffer->LogicalSize ();
3812
        
3813
17.9k
        int32 level = Z_DEFAULT_COMPRESSION;
3814
        
3815
17.9k
        if (ifd.fCompressionQuality >= Z_BEST_SPEED &&
3816
0
          ifd.fCompressionQuality <= Z_BEST_COMPRESSION)
3817
0
          {
3818
          
3819
0
          level = ifd.fCompressionQuality;
3820
          
3821
0
          }
3822
        
3823
17.9k
        int zResult = ::compress2 (dBuffer,
3824
17.9k
                       &dCount,
3825
17.9k
                       sBuffer,
3826
17.9k
                       sBytes,
3827
17.9k
                       level);
3828
                      
3829
17.9k
        if (zResult != Z_OK)
3830
0
          {
3831
          
3832
0
          ThrowMemoryFull ();
3833
          
3834
0
          }
3835
3836
17.9k
        dBytes = (uint32) dCount;
3837
        
3838
17.9k
        }
3839
                    
3840
45.4k
      if (dBytes > compressedBuffer->LogicalSize ())
3841
0
        {
3842
        
3843
0
        DNG_REPORT ("Compression output buffer overflow");
3844
        
3845
0
        ThrowProgramError ();
3846
        
3847
0
        }
3848
                    
3849
45.4k
      stream.Put (dBuffer, dBytes);
3850
        
3851
45.4k
      return;
3852
3853
27.4k
      }
3854
      
3855
174k
    case ccJPEG:
3856
174k
      {
3857
      
3858
174k
      dng_pixel_buffer temp (buffer);
3859
        
3860
174k
      if (buffer.fPixelType == ttByte)
3861
617
        {
3862
        
3863
        // The lossless JPEG encoder needs 16-bit data, so if we are
3864
        // are saving 8 bit data, we need to pad it out to 16-bits.
3865
        
3866
617
        temp.fData = compressedBuffer->Buffer ();
3867
        
3868
617
        temp.fPixelType = ttShort;
3869
617
        temp.fPixelSize = 2;
3870
        
3871
617
        temp.CopyArea (buffer,
3872
617
                 buffer.fArea,
3873
617
                 buffer.fPlane,
3874
617
                 buffer.fPlanes);
3875
        
3876
617
        }
3877
        
3878
174k
      EncodeLosslessJPEG ((const uint16 *) temp.fData,
3879
174k
                temp.fArea.H (),
3880
174k
                temp.fArea.W (),
3881
174k
                temp.fPlanes,
3882
174k
                ifd.fBitsPerSample [0],
3883
174k
                temp.fRowStep,
3884
174k
                temp.fColStep,
3885
174k
                stream);
3886
                    
3887
174k
      break;
3888
      
3889
27.4k
      }
3890
      
3891
0
    #if qDNGUseLibJPEG
3892
    
3893
16.9k
    case ccLossyJPEG:
3894
16.9k
      {
3895
      
3896
16.9k
      struct jpeg_compress_struct cinfo;
3897
  
3898
      // Setup the error manager.
3899
      
3900
16.9k
      struct jpeg_error_mgr jerr;
3901
3902
16.9k
      cinfo.err = jpeg_std_error (&jerr);
3903
      
3904
16.9k
      jerr.error_exit     = dng_error_exit;
3905
16.9k
      jerr.output_message = dng_output_message;
3906
  
3907
16.9k
      try
3908
16.9k
        {
3909
        
3910
        // Create the compression context.
3911
3912
16.9k
        jpeg_create_compress (&cinfo);
3913
        
3914
        // Setup the destination manager to write to stream.
3915
        
3916
16.9k
        dng_jpeg_stream_dest dest;
3917
        
3918
16.9k
        dest.fStream = &stream;
3919
        
3920
16.9k
        dest.pub.init_destination    = dng_init_destination;
3921
16.9k
        dest.pub.empty_output_buffer = dng_empty_output_buffer;
3922
16.9k
        dest.pub.term_destination    = dng_term_destination;
3923
        
3924
16.9k
        cinfo.dest = &dest.pub;
3925
        
3926
        // Setup basic image info.
3927
        
3928
16.9k
        cinfo.image_width      = buffer.fArea.W ();
3929
16.9k
        cinfo.image_height     = buffer.fArea.H ();
3930
16.9k
        cinfo.input_components = buffer.fPlanes;
3931
        
3932
16.9k
        switch (buffer.fPlanes)
3933
16.9k
          {
3934
          
3935
12.2k
          case 1:
3936
12.2k
            cinfo.in_color_space = JCS_GRAYSCALE;
3937
12.2k
            break;
3938
            
3939
2.81k
          case 3:
3940
2.81k
            cinfo.in_color_space = JCS_RGB;
3941
2.81k
            break;
3942
            
3943
1.87k
          case 4:
3944
1.87k
            cinfo.in_color_space = JCS_CMYK;
3945
1.87k
            break;
3946
            
3947
3
          default:
3948
3
            ThrowProgramError ();
3949
            
3950
16.9k
          }
3951
          
3952
        // Setup the compression parameters.
3953
3954
16.9k
        jpeg_set_defaults (&cinfo);
3955
        
3956
16.9k
        jpeg_set_adobe_quality (&cinfo, ifd.fCompressionQuality);
3957
        
3958
        // Write the JPEG header.
3959
        
3960
16.9k
        jpeg_start_compress (&cinfo, TRUE);
3961
        
3962
        // Write the scanlines.
3963
        
3964
3.40M
        for (int32 row = buffer.fArea.t; row < buffer.fArea.b; row++)
3965
3.39M
          {
3966
          
3967
3.39M
          uint8 *sampArray [1];
3968
    
3969
3.39M
          sampArray [0] = buffer.DirtyPixel_uint8 (row,
3970
3.39M
                               buffer.fArea.l,
3971
3.39M
                               0);
3972
3973
3.39M
          jpeg_write_scanlines (&cinfo, sampArray, 1);
3974
          
3975
3.39M
          }
3976
3977
        // Cleanup.
3978
          
3979
16.9k
        jpeg_finish_compress (&cinfo);
3980
3981
16.9k
        jpeg_destroy_compress (&cinfo);
3982
          
3983
16.9k
        }
3984
        
3985
16.9k
      catch (...)
3986
16.9k
        {
3987
        
3988
3
        jpeg_destroy_compress (&cinfo);
3989
        
3990
3
        throw;
3991
        
3992
3
        }
3993
        
3994
16.9k
      return;
3995
      
3996
16.9k
      }
3997
      
3998
0
    #endif
3999
      
4000
13.5k
    default:
4001
13.5k
      {
4002
      
4003
13.5k
      ThrowProgramError ();
4004
      
4005
13.5k
      }
4006
      
4007
465k
    }
4008
  
4009
465k
  }
4010
                
4011
/******************************************************************************/
4012
4013
void dng_image_writer::EncodeJPEGPreview (dng_host &host,
4014
                      const dng_image &image,
4015
                      dng_jpeg_preview &preview,
4016
                      int32 quality)
4017
4.07k
  {
4018
  
4019
4.07k
  #if qDNGUseLibJPEG
4020
    
4021
4.07k
  dng_memory_stream stream (host.Allocator ());
4022
  
4023
4.07k
  struct jpeg_compress_struct cinfo;
4024
4025
  // Setup the error manager.
4026
  
4027
4.07k
  struct jpeg_error_mgr jerr;
4028
4029
4.07k
  cinfo.err = jpeg_std_error (&jerr);
4030
  
4031
4.07k
  jerr.error_exit     = dng_error_exit;
4032
4.07k
  jerr.output_message = dng_output_message;
4033
4034
4.07k
  try
4035
4.07k
    {
4036
    
4037
    // Create the compression context.
4038
4039
4.07k
    jpeg_create_compress (&cinfo);
4040
    
4041
    // Setup the destination manager to write to stream.
4042
    
4043
4.07k
    dng_jpeg_stream_dest dest;
4044
    
4045
4.07k
    dest.fStream = &stream;
4046
    
4047
4.07k
    dest.pub.init_destination    = dng_init_destination;
4048
4.07k
    dest.pub.empty_output_buffer = dng_empty_output_buffer;
4049
4.07k
    dest.pub.term_destination    = dng_term_destination;
4050
    
4051
4.07k
    cinfo.dest = &dest.pub;
4052
    
4053
    // Setup basic image info.
4054
    
4055
4.07k
    cinfo.image_width      = image.Bounds ().W ();
4056
4.07k
    cinfo.image_height     = image.Bounds ().H ();
4057
4.07k
    cinfo.input_components = image.Planes ();
4058
    
4059
4.07k
    switch (image.Planes ())
4060
4.07k
      {
4061
      
4062
3.26k
      case 1:
4063
3.26k
        cinfo.in_color_space = JCS_GRAYSCALE;
4064
3.26k
        break;
4065
        
4066
813
      case 3:
4067
813
        cinfo.in_color_space = JCS_RGB;
4068
813
        break;
4069
        
4070
0
      default:
4071
0
        ThrowProgramError ();
4072
        
4073
4.07k
      }
4074
      
4075
    // Setup the compression parameters.
4076
4077
4.07k
    jpeg_set_defaults (&cinfo);
4078
    
4079
4.07k
    jpeg_set_adobe_quality (&cinfo, quality);
4080
    
4081
    // Find some preview information based on the compression settings.
4082
    
4083
4.07k
    preview.fPreviewSize = image.Size ();
4084
  
4085
4.07k
    if (image.Planes () == 1)
4086
3.26k
      {
4087
      
4088
3.26k
      preview.fPhotometricInterpretation = piBlackIsZero;
4089
      
4090
3.26k
      }
4091
      
4092
813
    else
4093
813
      {
4094
      
4095
813
      preview.fPhotometricInterpretation = piYCbCr;
4096
      
4097
813
      preview.fYCbCrSubSampling.h  = cinfo.comp_info [0].h_samp_factor;
4098
813
      preview.fYCbCrSubSampling.v  = cinfo.comp_info [0].v_samp_factor;
4099
      
4100
813
      }
4101
    
4102
    // Write the JPEG header.
4103
    
4104
4.07k
    jpeg_start_compress (&cinfo, TRUE);
4105
    
4106
    // Write the scanlines.
4107
    
4108
4.07k
    dng_pixel_buffer buffer (image.Bounds (), 0, image.Planes (), ttByte,
4109
4.07k
       pcInterleaved, NULL);
4110
    
4111
4.07k
    AutoPtr<dng_memory_block> bufferData (host.Allocate (buffer.fRowStep));
4112
    
4113
4.07k
    buffer.fData = bufferData->Buffer ();
4114
    
4115
1.01M
    for (uint32 row = 0; row < cinfo.image_height; row++)
4116
1.00M
      {
4117
      
4118
1.00M
      buffer.fArea.t = row;
4119
1.00M
      buffer.fArea.b = row + 1;
4120
      
4121
1.00M
      image.Get (buffer);
4122
      
4123
1.00M
      uint8 *sampArray [1];
4124
4125
1.00M
      sampArray [0] = buffer.DirtyPixel_uint8 (row,
4126
1.00M
                           buffer.fArea.l,
4127
1.00M
                           0);
4128
4129
1.00M
      jpeg_write_scanlines (&cinfo, sampArray, 1);
4130
      
4131
1.00M
      }
4132
4133
    // Cleanup.
4134
      
4135
4.07k
    jpeg_finish_compress (&cinfo);
4136
4137
4.07k
    jpeg_destroy_compress (&cinfo);
4138
      
4139
4.07k
    }
4140
    
4141
4.07k
  catch (...)
4142
4.07k
    {
4143
    
4144
0
    jpeg_destroy_compress (&cinfo);
4145
    
4146
0
    throw;
4147
    
4148
0
    }
4149
           
4150
4.07k
  preview.fCompressedData.Reset (stream.AsMemoryBlock (host.Allocator ()));
4151
4152
  #else
4153
  
4154
  (void) host;
4155
  (void) image;
4156
  (void) preview;
4157
  (void) quality;
4158
  
4159
  ThrowProgramError ("No JPEG encoder");
4160
  
4161
  #endif
4162
    
4163
4.07k
  }
4164
                
4165
/*****************************************************************************/
4166
4167
void dng_image_writer::WriteTile (dng_host &host,
4168
                      const dng_ifd &ifd,
4169
                      dng_stream &stream,
4170
                      const dng_image &image,
4171
                      const dng_rect &tileArea,
4172
                      uint32 fakeChannels,
4173
                  AutoPtr<dng_memory_block> &compressedBuffer,
4174
                  AutoPtr<dng_memory_block> &uncompressedBuffer,
4175
                  AutoPtr<dng_memory_block> &subTileBlockBuffer,
4176
                  AutoPtr<dng_memory_block> &tempBuffer)
4177
468k
  {
4178
  
4179
  // Create pixel buffer to hold uncompressed tile.
4180
  
4181
468k
  dng_pixel_buffer buffer (tileArea, 0, ifd.fSamplesPerPixel,
4182
468k
     image.PixelType(), pcInterleaved, uncompressedBuffer->Buffer());
4183
  
4184
  // Get the uncompressed data.
4185
  
4186
468k
  image.Get (buffer, dng_image::edge_zero);
4187
  
4188
  // Deal with sub-tile blocks.
4189
  
4190
468k
  if (ifd.fSubTileBlockRows > 1)
4191
0
    {
4192
    
4193
0
    ReorderSubTileBlocks (ifd,
4194
0
                buffer,
4195
0
                uncompressedBuffer,
4196
0
                subTileBlockBuffer);
4197
    
4198
0
    }
4199
    
4200
  // Floating point depth conversion.
4201
  
4202
468k
  if (ifd.fSampleFormat [0] == sfFloatingPoint)
4203
63.6k
    {
4204
    
4205
63.6k
    if (ifd.fBitsPerSample [0] == 16)
4206
6.52k
      {
4207
      
4208
6.52k
      uint32 *srcPtr = (uint32 *) buffer.fData;
4209
6.52k
      uint16 *dstPtr = (uint16 *) buffer.fData;
4210
      
4211
6.52k
      uint32 pixels = tileArea.W () * tileArea.H () * buffer.fPlanes;
4212
      
4213
216M
      for (uint32 j = 0; j < pixels; j++)
4214
216M
        {
4215
        
4216
216M
        dstPtr [j] = DNG_FloatToHalf (srcPtr [j]);
4217
        
4218
216M
        }
4219
        
4220
6.52k
      buffer.fPixelSize = 2;
4221
      
4222
6.52k
      }
4223
      
4224
63.6k
    if (ifd.fBitsPerSample [0] == 24)
4225
904
      {
4226
      
4227
904
      uint32 *srcPtr = (uint32 *) buffer.fData;
4228
904
      uint8  *dstPtr = (uint8  *) buffer.fData;
4229
      
4230
904
      uint32 pixels = tileArea.W () * tileArea.H () * buffer.fPlanes;
4231
      
4232
904
      if (stream.BigEndian () || ifd.fPredictor == cpFloatingPoint   ||
4233
404
                     ifd.fPredictor == cpFloatingPointX2 ||
4234
1
                     ifd.fPredictor == cpFloatingPointX4)
4235
904
        {
4236
      
4237
31.0M
        for (uint32 j = 0; j < pixels; j++)
4238
31.0M
          {
4239
          
4240
31.0M
          DNG_FloatToFP24 (srcPtr [j], dstPtr);
4241
          
4242
31.0M
          dstPtr += 3;
4243
          
4244
31.0M
          }
4245
          
4246
904
        }
4247
        
4248
0
      else
4249
0
        {
4250
      
4251
0
        for (uint32 j = 0; j < pixels; j++)
4252
0
          {
4253
          
4254
0
          uint8 output [3];
4255
          
4256
0
          DNG_FloatToFP24 (srcPtr [j], output);
4257
          
4258
0
          dstPtr [0] = output [2];
4259
0
          dstPtr [1] = output [1];
4260
0
          dstPtr [2] = output [0];
4261
          
4262
0
          dstPtr += 3;
4263
          
4264
0
          }
4265
          
4266
0
        }
4267
        
4268
904
      buffer.fPixelSize = 3;
4269
      
4270
904
      }
4271
    
4272
63.6k
    }
4273
  
4274
  // Run predictor.
4275
  
4276
468k
  EncodePredictor (host,
4277
468k
           ifd,
4278
468k
           buffer,
4279
468k
           tempBuffer);
4280
    
4281
  // Adjust pixel buffer for fake channels.
4282
  
4283
468k
  if (fakeChannels > 1)
4284
9.23k
    {
4285
    
4286
9.23k
    buffer.fPlanes  *= fakeChannels;
4287
9.23k
    buffer.fColStep *= fakeChannels;
4288
    
4289
9.23k
    buffer.fArea.r = buffer.fArea.l + (buffer.fArea.W () / fakeChannels);
4290
    
4291
9.23k
    }
4292
    
4293
  // Compress (if required) and write out the data.
4294
  
4295
468k
  WriteData (host,
4296
468k
         ifd,
4297
468k
         stream,
4298
468k
         buffer,
4299
468k
         compressedBuffer);
4300
         
4301
468k
  }
4302
4303
/*****************************************************************************/
4304
4305
class dng_write_tiles_task : public dng_area_task
4306
  {
4307
  
4308
  private:
4309
  
4310
    dng_image_writer &fImageWriter;
4311
    
4312
    dng_host &fHost;
4313
    
4314
    const dng_ifd &fIFD;
4315
    
4316
    dng_basic_tag_set &fBasic;
4317
    
4318
    dng_stream &fStream;
4319
    
4320
    const dng_image &fImage;
4321
    
4322
    uint32 fFakeChannels;
4323
    
4324
    uint32 fTilesDown;
4325
    
4326
    uint32 fTilesAcross;
4327
    
4328
    uint32 fCompressedSize;
4329
    
4330
    uint32 fUncompressedSize;
4331
    
4332
    dng_mutex fMutex1;
4333
    
4334
    uint32 fNextTileIndex;
4335
    
4336
    dng_mutex fMutex2;
4337
    
4338
    dng_condition fCondition;
4339
    
4340
    bool fTaskFailed;
4341
4342
    uint32 fWriteTileIndex;
4343
    
4344
  public:
4345
  
4346
    dng_write_tiles_task (dng_image_writer &imageWriter,
4347
                dng_host &host,
4348
                const dng_ifd &ifd,
4349
                dng_basic_tag_set &basic,
4350
                dng_stream &stream,
4351
                const dng_image &image,
4352
                uint32 fakeChannels,
4353
                uint32 tilesDown,
4354
                uint32 tilesAcross,
4355
                uint32 compressedSize,
4356
                uint32 uncompressedSize)
4357
    
4358
0
      : fImageWriter      (imageWriter)
4359
0
      , fHost         (host)
4360
0
      , fIFD          (ifd)
4361
0
      , fBasic        (basic)
4362
0
      , fStream         (stream)
4363
0
      , fImage          (image)
4364
0
      , fFakeChannels   (fakeChannels)
4365
0
      , fTilesDown        (tilesDown)
4366
0
      , fTilesAcross    (tilesAcross)
4367
0
      , fCompressedSize   (compressedSize)
4368
0
      , fUncompressedSize (uncompressedSize)
4369
0
      , fMutex1       ("dng_write_tiles_task_1")
4370
0
      , fNextTileIndex    (0)
4371
0
      , fMutex2       ("dng_write_tiles_task_2")
4372
0
      , fCondition      ()
4373
0
      , fTaskFailed     (false)
4374
0
      , fWriteTileIndex   (0)
4375
      
4376
0
      {
4377
      
4378
0
      fMinTaskArea = 16 * 16;
4379
0
      fUnitCell    = dng_point (16, 16);
4380
0
      fMaxTileSize = dng_point (16, 16);
4381
      
4382
0
      }
4383
  
4384
    void Process (uint32 /* threadIndex */,
4385
            const dng_rect & /* tile */,
4386
            dng_abort_sniffer *sniffer)
4387
0
      {
4388
      
4389
0
      try
4390
0
        {
4391
      
4392
0
        AutoPtr<dng_memory_block> compressedBuffer;
4393
0
        AutoPtr<dng_memory_block> uncompressedBuffer;
4394
0
        AutoPtr<dng_memory_block> subTileBlockBuffer;
4395
0
        AutoPtr<dng_memory_block> tempBuffer;
4396
        
4397
0
        if (fCompressedSize)
4398
0
          {
4399
0
          compressedBuffer.Reset (fHost.Allocate (fCompressedSize));
4400
0
          }
4401
        
4402
0
        if (fUncompressedSize)
4403
0
          {
4404
0
          uncompressedBuffer.Reset (fHost.Allocate (fUncompressedSize));
4405
0
          }
4406
        
4407
0
        if (fIFD.fSubTileBlockRows > 1 && fUncompressedSize)
4408
0
          {
4409
0
          subTileBlockBuffer.Reset (fHost.Allocate (fUncompressedSize));
4410
0
          }
4411
        
4412
0
        while (true)
4413
0
          {
4414
          
4415
          // Find tile index to compress.
4416
          
4417
0
          uint32 tileIndex;
4418
          
4419
0
            {
4420
            
4421
0
            dng_lock_mutex lock (&fMutex1);
4422
            
4423
0
            if (fNextTileIndex == fTilesDown * fTilesAcross)
4424
0
              {
4425
0
              return;
4426
0
              }
4427
              
4428
0
            tileIndex = fNextTileIndex++;
4429
            
4430
0
            }
4431
            
4432
0
          dng_abort_sniffer::SniffForAbort (sniffer);
4433
          
4434
          // Compress tile.
4435
          
4436
0
          uint32 rowIndex = tileIndex / fTilesAcross;
4437
          
4438
0
          uint32 colIndex = tileIndex - rowIndex * fTilesAcross;
4439
          
4440
0
          dng_rect tileArea = fIFD.TileArea (rowIndex, colIndex);
4441
          
4442
0
          dng_memory_stream tileStream (fHost.Allocator ());
4443
                       
4444
0
          tileStream.SetLittleEndian (fStream.LittleEndian ());
4445
          
4446
0
          dng_host host (&fHost.Allocator (),
4447
0
                   sniffer);
4448
                
4449
0
          fImageWriter.WriteTile (host,
4450
0
                      fIFD,
4451
0
                      tileStream,
4452
0
                      fImage,
4453
0
                      tileArea,
4454
0
                      fFakeChannels,
4455
0
                      compressedBuffer,
4456
0
                      uncompressedBuffer,
4457
0
                      subTileBlockBuffer,
4458
0
                      tempBuffer);
4459
                      
4460
0
          tileStream.Flush ();
4461
                      
4462
0
          uint32 tileByteCount = (uint32) tileStream.Length ();
4463
          
4464
0
          tileStream.SetReadPosition (0);
4465
          
4466
          // Wait until it is our turn to write tile.
4467
4468
0
            {
4469
          
4470
0
            dng_lock_mutex lock (&fMutex2);
4471
          
4472
0
            while (!fTaskFailed &&
4473
0
                 fWriteTileIndex != tileIndex)
4474
0
              {
4475
4476
0
              fCondition.Wait (fMutex2);
4477
              
4478
0
              }
4479
4480
            // If the task failed in another thread, that thread already threw an exception.
4481
4482
0
            if (fTaskFailed)
4483
0
              return;
4484
4485
0
            }           
4486
          
4487
0
          dng_abort_sniffer::SniffForAbort (sniffer);
4488
          
4489
          // Remember this offset.
4490
        
4491
0
          uint32 tileOffset = (uint32) fStream.Position ();
4492
        
4493
0
          fBasic.SetTileOffset (tileIndex, tileOffset);
4494
            
4495
          // Copy tile stream for tile into main stream.
4496
              
4497
0
          tileStream.CopyToStream (fStream, tileByteCount);
4498
              
4499
          // Update tile count.
4500
            
4501
0
          fBasic.SetTileByteCount (tileIndex, tileByteCount);
4502
          
4503
          // Keep the tiles on even byte offsets.
4504
                             
4505
0
          if (tileByteCount & 1)
4506
0
            {
4507
0
            fStream.Put_uint8 (0);
4508
0
            }
4509
              
4510
          // Let other threads know it is safe to write to stream.
4511
          
4512
0
            {
4513
            
4514
0
            dng_lock_mutex lock (&fMutex2);
4515
            
4516
            // If the task failed in another thread, that thread already threw an exception.
4517
4518
0
            if (fTaskFailed)
4519
0
              return;
4520
4521
0
            fWriteTileIndex++;
4522
            
4523
0
            fCondition.Broadcast ();
4524
            
4525
0
            }
4526
            
4527
0
          }
4528
          
4529
0
        }
4530
        
4531
0
      catch (...)
4532
0
        {
4533
        
4534
        // If first to fail, wake up any threads waiting on condition.
4535
        
4536
0
        bool needBroadcast = false;
4537
4538
0
          {
4539
          
4540
0
          dng_lock_mutex lock (&fMutex2);
4541
4542
0
          needBroadcast = !fTaskFailed;
4543
0
          fTaskFailed = true;
4544
          
4545
0
          }
4546
4547
0
        if (needBroadcast)
4548
0
          fCondition.Broadcast ();
4549
        
4550
0
        throw;
4551
        
4552
0
        }
4553
      
4554
0
      }
4555
    
4556
  private:
4557
4558
    // Hidden copy constructor and assignment operator.
4559
4560
    dng_write_tiles_task (const dng_write_tiles_task &);
4561
4562
    dng_write_tiles_task & operator= (const dng_write_tiles_task &);
4563
    
4564
  };
4565
4566
/*****************************************************************************/
4567
4568
void dng_image_writer::WriteImage (dng_host &host,
4569
                       const dng_ifd &ifd,
4570
                       dng_basic_tag_set &basic,
4571
                       dng_stream &stream,
4572
                       const dng_image &image,
4573
                       uint32 fakeChannels)
4574
85.2k
  {
4575
  
4576
  // Deal with row interleaved images.
4577
  
4578
85.2k
  if (ifd.fRowInterleaveFactor > 1 &&
4579
0
    ifd.fRowInterleaveFactor < ifd.fImageLength)
4580
0
    {
4581
    
4582
0
    dng_ifd tempIFD (ifd);
4583
    
4584
0
    tempIFD.fRowInterleaveFactor = 1;
4585
    
4586
0
    dng_row_interleaved_image tempImage (*((dng_image *) &image),
4587
0
                       ifd.fRowInterleaveFactor);
4588
    
4589
0
    WriteImage (host,
4590
0
          tempIFD,
4591
0
          basic,
4592
0
          stream,
4593
0
          tempImage,
4594
0
          fakeChannels);
4595
        
4596
0
    return;
4597
    
4598
0
    }
4599
  
4600
  // Compute basic information.
4601
  
4602
85.2k
  uint32 bytesPerSample = TagTypeSize (image.PixelType ());
4603
  
4604
85.2k
  uint32 bytesPerPixel = SafeUint32Mult (ifd.fSamplesPerPixel,
4605
85.2k
                       bytesPerSample);
4606
  
4607
85.2k
  uint32 tileRowBytes = SafeUint32Mult (ifd.fTileWidth, bytesPerPixel);
4608
  
4609
  // If we can compute the number of bytes needed to store the
4610
  // data, we can split the write for each tile into sub-tiles.
4611
  
4612
85.2k
  uint32 subTileLength = ifd.fTileLength;
4613
  
4614
85.2k
  if (ifd.TileByteCount (ifd.TileArea (0, 0)) != 0)
4615
39.0k
    {
4616
    
4617
39.0k
    subTileLength = Pin_uint32 (ifd.fSubTileBlockRows,
4618
39.0k
                  kImageBufferSize / tileRowBytes, 
4619
39.0k
                  ifd.fTileLength);
4620
          
4621
    // Don't split sub-tiles across subTileBlocks.
4622
    
4623
39.0k
    subTileLength = subTileLength / ifd.fSubTileBlockRows
4624
39.0k
                    * ifd.fSubTileBlockRows;
4625
                  
4626
39.0k
    }
4627
    
4628
  // Find size of uncompressed buffer.
4629
  
4630
85.2k
  uint32 uncompressedSize = SafeUint32Mult(subTileLength, tileRowBytes);
4631
  
4632
  // Find size of compressed buffer, if required.
4633
  
4634
85.2k
  uint32 compressedSize = CompressedBufferSize (ifd, uncompressedSize);
4635
      
4636
  // See if we can do this write using multiple threads.
4637
  
4638
85.2k
  uint32 tilesAcross = ifd.TilesAcross ();
4639
85.2k
  uint32 tilesDown   = ifd.TilesDown   ();
4640
                 
4641
85.2k
  bool useMultipleThreads = (tilesDown * tilesAcross >= 2) &&
4642
7.04k
                (host.PerformAreaTaskThreads () > 1) &&
4643
0
                (subTileLength == ifd.fTileLength) &&
4644
0
                (ifd.fCompression != ccUncompressed);
4645
  
4646
    
4647
#if qImagecore
4648
  useMultipleThreads = false; 
4649
#endif
4650
    
4651
85.2k
  if (useMultipleThreads)
4652
0
    {
4653
    
4654
0
    uint32 threadCount = Min_uint32 (tilesDown * tilesAcross,
4655
0
                     host.PerformAreaTaskThreads ());
4656
                     
4657
0
    dng_write_tiles_task task (*this,
4658
0
                   host,
4659
0
                   ifd,
4660
0
                   basic,
4661
0
                   stream,
4662
0
                   image,
4663
0
                   fakeChannels,
4664
0
                   tilesDown,
4665
0
                   tilesAcross,
4666
0
                   compressedSize,
4667
0
                   uncompressedSize);
4668
                  
4669
0
    host.PerformAreaTask (task,
4670
0
                dng_rect (0, 0, 16, 16 * threadCount));
4671
    
4672
0
    }
4673
    
4674
85.2k
  else
4675
85.2k
    {
4676
                  
4677
85.2k
    AutoPtr<dng_memory_block> compressedBuffer;
4678
85.2k
    AutoPtr<dng_memory_block> uncompressedBuffer;
4679
85.2k
    AutoPtr<dng_memory_block> subTileBlockBuffer;
4680
85.2k
    AutoPtr<dng_memory_block> tempBuffer;
4681
    
4682
85.2k
    if (compressedSize)
4683
21.5k
      {
4684
21.5k
      compressedBuffer.Reset (host.Allocate (compressedSize));
4685
21.5k
      }
4686
    
4687
85.2k
    if (uncompressedSize)
4688
85.2k
      {
4689
85.2k
      uncompressedBuffer.Reset (host.Allocate (uncompressedSize));
4690
85.2k
      }
4691
    
4692
85.2k
    if (ifd.fSubTileBlockRows > 1 && uncompressedSize)
4693
0
      {
4694
0
      subTileBlockBuffer.Reset (host.Allocate (uncompressedSize));
4695
0
      }
4696
        
4697
    // Write out each tile.
4698
    
4699
85.2k
    uint32 tileIndex = 0;
4700
    
4701
199k
    for (uint32 rowIndex = 0; rowIndex < tilesDown; rowIndex++)
4702
114k
      {
4703
      
4704
389k
      for (uint32 colIndex = 0; colIndex < tilesAcross; colIndex++)
4705
275k
        {
4706
        
4707
        // Remember this offset.
4708
        
4709
275k
        uint32 tileOffset = (uint32) stream.Position ();
4710
      
4711
275k
        basic.SetTileOffset (tileIndex, tileOffset);
4712
        
4713
        // Split tile into sub-tiles if possible.
4714
        
4715
275k
        dng_rect tileArea = ifd.TileArea (rowIndex, colIndex);
4716
        
4717
275k
        uint32 subTileCount = (tileArea.H () + subTileLength - 1) /
4718
275k
                    subTileLength;
4719
                    
4720
726k
        for (uint32 subIndex = 0; subIndex < subTileCount; subIndex++)
4721
451k
          {
4722
          
4723
451k
          host.SniffForAbort ();
4724
        
4725
451k
          dng_rect subArea (tileArea);
4726
          
4727
451k
          subArea.t = tileArea.t + subIndex * subTileLength;
4728
          
4729
451k
          subArea.b = Min_int32 (subArea.t + subTileLength,
4730
451k
                       tileArea.b);
4731
                       
4732
          // Write the sub-tile.
4733
          
4734
451k
          WriteTile (host,
4735
451k
                 ifd,
4736
451k
                 stream,
4737
451k
                 image,
4738
451k
                 subArea,
4739
451k
                 fakeChannels,
4740
451k
                 compressedBuffer,
4741
451k
                 uncompressedBuffer,
4742
451k
                 subTileBlockBuffer,
4743
451k
                 tempBuffer);
4744
                 
4745
451k
          }
4746
          
4747
        // Update tile count.
4748
          
4749
275k
        uint32 tileByteCount = (uint32) stream.Position () - tileOffset;
4750
          
4751
275k
        basic.SetTileByteCount (tileIndex, tileByteCount);
4752
        
4753
275k
        tileIndex++;
4754
        
4755
        // Keep the tiles on even byte offsets.
4756
                           
4757
275k
        if (tileByteCount & 1)
4758
128k
          {
4759
128k
          stream.Put_uint8 (0);
4760
128k
          }
4761
          
4762
275k
        }
4763
4764
114k
      }
4765
      
4766
85.2k
    }
4767
    
4768
85.2k
  }
4769
4770
/*****************************************************************************/
4771
4772
#if qDNGUseXMP
4773
4774
static void CopyString (const dng_xmp &oldXMP,
4775
            dng_xmp &newXMP,
4776
            const char *ns,
4777
            const char *path,
4778
            dng_string *exif = NULL)
4779
  {
4780
  
4781
  dng_string s;
4782
  
4783
  if (oldXMP.GetString (ns, path, s))
4784
    {
4785
    
4786
    if (s.NotEmpty ())
4787
      {
4788
      
4789
      newXMP.SetString (ns, path, s);
4790
      
4791
      if (exif)
4792
        {
4793
        
4794
        *exif = s;
4795
        
4796
        }
4797
      
4798
      }
4799
      
4800
    }
4801
  
4802
  }
4803
                 
4804
/*****************************************************************************/
4805
4806
static void CopyStringList (const dng_xmp &oldXMP,
4807
              dng_xmp &newXMP,
4808
              const char *ns,
4809
              const char *path,
4810
              bool isBag)
4811
  {
4812
  
4813
  dng_string_list list;
4814
  
4815
  if (oldXMP.GetStringList (ns, path, list))
4816
    {
4817
    
4818
    if (list.Count ())
4819
      {
4820
      
4821
      newXMP.SetStringList (ns, path, list, isBag);
4822
            
4823
      }
4824
      
4825
    }
4826
  
4827
  }
4828
                 
4829
/*****************************************************************************/
4830
4831
static void CopyAltLangDefault (const dng_xmp &oldXMP,
4832
                dng_xmp &newXMP,
4833
                const char *ns,
4834
                const char *path,
4835
                dng_string *exif = NULL)
4836
  {
4837
  
4838
  dng_string s;
4839
  
4840
  if (oldXMP.GetAltLangDefault (ns, path, s))
4841
    {
4842
    
4843
    if (s.NotEmpty ())
4844
      {
4845
      
4846
      newXMP.SetAltLangDefault (ns, path, s);
4847
      
4848
      if (exif)
4849
        {
4850
        
4851
        *exif = s;
4852
        
4853
        }
4854
      
4855
      }
4856
      
4857
    }
4858
  
4859
  }
4860
                 
4861
/*****************************************************************************/
4862
4863
static void CopyStructField (const dng_xmp &oldXMP,
4864
               dng_xmp &newXMP,
4865
               const char *ns,
4866
               const char *path,
4867
               const char *field)
4868
  {
4869
  
4870
  dng_string s;
4871
  
4872
  if (oldXMP.GetStructField (ns, path, ns, field, s))
4873
    {
4874
    
4875
    if (s.NotEmpty ())
4876
      {
4877
      
4878
      newXMP.SetStructField (ns, path, ns, field, s);
4879
      
4880
      }
4881
      
4882
    }
4883
  
4884
  }
4885
4886
/*****************************************************************************/
4887
4888
static void CopyBoolean (const dng_xmp &oldXMP,
4889
             dng_xmp &newXMP,
4890
             const char *ns,
4891
             const char *path)
4892
  {
4893
  
4894
  bool b;
4895
  
4896
  if (oldXMP.GetBoolean (ns, path, b))
4897
    {
4898
    
4899
    newXMP.SetBoolean (ns, path, b);
4900
            
4901
    }
4902
  
4903
  }
4904
  
4905
#endif
4906
               
4907
/*****************************************************************************/
4908
4909
void dng_image_writer::CleanUpMetadata (dng_host &host,
4910
                    dng_metadata &metadata,
4911
                    dng_metadata_subset metadataSubset,
4912
                    const char *dstMIMI,
4913
                    const char *software)
4914
26.5k
  {
4915
  
4916
  #if qDNGUseXMP
4917
  
4918
  if (metadata.GetXMP () && metadata.GetExif ())
4919
    {
4920
    
4921
    dng_xmp  &newXMP  (*metadata.GetXMP  ());
4922
    dng_exif &newEXIF (*metadata.GetExif ());
4923
    
4924
    // Update software tag.
4925
    
4926
    if (software)
4927
      {
4928
  
4929
      newEXIF.fSoftware.Set (software);
4930
      
4931
      newXMP.Set (XMP_NS_XAP,
4932
            "CreatorTool",
4933
            software);
4934
      
4935
      }
4936
    
4937
    #if qDNGXMPDocOps
4938
    
4939
    newXMP.DocOpsPrepareForSave (metadata.SourceMIMI ().Get (),
4940
                   dstMIMI);
4941
                          
4942
    #else
4943
    
4944
    metadata.UpdateDateTimeToNow ();
4945
    
4946
    #endif
4947
    
4948
    // Update EXIF version to at least 2.3 so all the exif tags
4949
    // can be written.
4950
    
4951
    if (newEXIF.fExifVersion < DNG_CHAR4 ('0','2','3','0'))
4952
      {
4953
    
4954
      newEXIF.fExifVersion = DNG_CHAR4 ('0','2','3','0');
4955
      
4956
      newXMP.Set (XMP_NS_EXIF, "ExifVersion", "0230");
4957
      
4958
      }
4959
      
4960
    // Resync EXIF, remove EXIF tags from XMP.
4961
  
4962
    newXMP.SyncExif (newEXIF,
4963
             metadata.GetOriginalExif (),
4964
             false,
4965
             true);
4966
                    
4967
    // Deal with ImageIngesterPro bug.  This program is adding lots of
4968
    // empty metadata strings into the XMP, which is screwing up Adobe CS4.
4969
    // We are saving a new file, so this is a chance to clean up this mess.
4970
    
4971
    newXMP.RemoveEmptyStringsAndArrays (XMP_NS_DC);
4972
    newXMP.RemoveEmptyStringsAndArrays (XMP_NS_XAP);
4973
    newXMP.RemoveEmptyStringsAndArrays (XMP_NS_PHOTOSHOP);
4974
    newXMP.RemoveEmptyStringsAndArrays (XMP_NS_IPTC);
4975
    newXMP.RemoveEmptyStringsAndArrays (XMP_NS_XAP_RIGHTS);
4976
    newXMP.RemoveEmptyStringsAndArrays ("http://ns.iview-multimedia.com/mediapro/1.0/");
4977
4978
    // Process metadata subset.
4979
    
4980
    if (metadataSubset == kMetadataSubset_CopyrightOnly ||
4981
      metadataSubset == kMetadataSubset_CopyrightAndContact)
4982
      {
4983
      
4984
      dng_xmp  oldXMP  (newXMP );
4985
      dng_exif oldEXIF (newEXIF);
4986
      
4987
      // For these options, we start from nothing, and only fill in the
4988
      // fields that we absolutely need.
4989
      
4990
      newXMP.RemoveProperties (NULL);
4991
      
4992
      newEXIF.SetEmpty ();
4993
      
4994
      metadata.ClearMakerNote ();
4995
      
4996
      // Move copyright related fields over.
4997
      
4998
      CopyAltLangDefault (oldXMP,
4999
                newXMP,
5000
                XMP_NS_DC,
5001
                "rights",
5002
                &newEXIF.fCopyright);
5003
                        
5004
      CopyAltLangDefault (oldXMP,
5005
                newXMP,
5006
                XMP_NS_XAP_RIGHTS,
5007
                "UsageTerms");
5008
                
5009
      CopyString (oldXMP,
5010
            newXMP,
5011
            XMP_NS_XAP_RIGHTS,
5012
            "WebStatement");
5013
            
5014
      CopyBoolean (oldXMP,
5015
             newXMP,
5016
             XMP_NS_XAP_RIGHTS,
5017
             "Marked");
5018
             
5019
      #if qDNGXMPDocOps
5020
      
5021
      // Include basic DocOps fields, but not the full history.
5022
      
5023
      CopyString (oldXMP,
5024
            newXMP,
5025
            XMP_NS_MM,
5026
            "OriginalDocumentID");
5027
            
5028
      CopyString (oldXMP,
5029
            newXMP,
5030
            XMP_NS_MM,
5031
            "DocumentID");
5032
      
5033
      CopyString (oldXMP,
5034
            newXMP,
5035
            XMP_NS_MM,
5036
            "InstanceID");
5037
      
5038
      CopyString (oldXMP,
5039
            newXMP,
5040
            XMP_NS_XAP,
5041
            "MetadataDate");
5042
      
5043
      #endif
5044
      
5045
      // Copyright and Contact adds the contact info fields.
5046
      
5047
      if (metadataSubset == kMetadataSubset_CopyrightAndContact)
5048
        {
5049
        
5050
        // Note: Save for Web is not including the dc:creator list, but it
5051
        // is part of the IPTC contract info metadata panel, so I 
5052
        // think it should be copied as part of the contact info.
5053
        
5054
        CopyStringList (oldXMP,
5055
                newXMP,
5056
                XMP_NS_DC,
5057
                "creator",
5058
                false);
5059
                
5060
        // The first string dc:creator list is mirrored to the
5061
        // the exif artist tag, so copy that also.
5062
                
5063
        newEXIF.fArtist = oldEXIF.fArtist;
5064
        
5065
        // Copy other contact fields.
5066
        
5067
        CopyString (oldXMP,
5068
              newXMP,
5069
              XMP_NS_PHOTOSHOP,
5070
              "AuthorsPosition");
5071
              
5072
        CopyStructField (oldXMP,
5073
                 newXMP,
5074
                 XMP_NS_IPTC,
5075
                 "CreatorContactInfo",
5076
                 "CiEmailWork");
5077
              
5078
        CopyStructField (oldXMP,
5079
                 newXMP,
5080
                 XMP_NS_IPTC,
5081
                 "CreatorContactInfo",
5082
                 "CiAdrExtadr");
5083
              
5084
        CopyStructField (oldXMP,
5085
                 newXMP,
5086
                 XMP_NS_IPTC,
5087
                 "CreatorContactInfo",
5088
                 "CiAdrCity");
5089
              
5090
        CopyStructField (oldXMP,
5091
                 newXMP,
5092
                 XMP_NS_IPTC,
5093
                 "CreatorContactInfo",
5094
                 "CiAdrRegion");
5095
              
5096
        CopyStructField (oldXMP,
5097
                 newXMP,
5098
                 XMP_NS_IPTC,
5099
                 "CreatorContactInfo",
5100
                 "CiAdrPcode");
5101
              
5102
        CopyStructField (oldXMP,
5103
                 newXMP,
5104
                 XMP_NS_IPTC,
5105
                 "CreatorContactInfo",
5106
                 "CiAdrCtry");
5107
              
5108
        CopyStructField (oldXMP,
5109
                 newXMP,
5110
                 XMP_NS_IPTC,
5111
                 "CreatorContactInfo",
5112
                 "CiTelWork");
5113
              
5114
        CopyStructField (oldXMP,
5115
                 newXMP,
5116
                 XMP_NS_IPTC,
5117
                 "CreatorContactInfo",
5118
                 "CiUrlWork");
5119
                 
5120
        CopyAltLangDefault (oldXMP,
5121
                  newXMP,
5122
                  XMP_NS_DC,
5123
                  "title");
5124
                        
5125
        }
5126
5127
      }
5128
      
5129
    else if (metadataSubset == kMetadataSubset_AllExceptCameraInfo        ||
5130
         metadataSubset == kMetadataSubset_AllExceptCameraAndLocation ||
5131
         metadataSubset == kMetadataSubset_AllExceptLocationInfo)
5132
      {
5133
      
5134
      dng_xmp  oldXMP  (newXMP );
5135
      dng_exif oldEXIF (newEXIF);
5136
      
5137
      if (metadataSubset == kMetadataSubset_AllExceptCameraInfo ||
5138
        metadataSubset == kMetadataSubset_AllExceptCameraAndLocation)
5139
        {
5140
      
5141
        // This removes most of the EXIF info, so just copy the fields
5142
        // we are not deleting.
5143
        
5144
        newEXIF.SetEmpty ();
5145
        
5146
        newEXIF.fImageDescription  = oldEXIF.fImageDescription;   // Note: Differs from SFW
5147
        newEXIF.fSoftware          = oldEXIF.fSoftware;
5148
        newEXIF.fArtist            = oldEXIF.fArtist;
5149
        newEXIF.fCopyright         = oldEXIF.fCopyright;
5150
        newEXIF.fCopyright2        = oldEXIF.fCopyright2;
5151
        newEXIF.fDateTime          = oldEXIF.fDateTime;
5152
        newEXIF.fDateTimeOriginal  = oldEXIF.fDateTimeOriginal;
5153
        newEXIF.fDateTimeDigitized = oldEXIF.fDateTimeDigitized;
5154
        newEXIF.fExifVersion       = oldEXIF.fExifVersion;
5155
        newEXIF.fImageUniqueID     = oldEXIF.fImageUniqueID;
5156
        
5157
        newEXIF.CopyGPSFrom (oldEXIF);
5158
        
5159
        // Remove exif info from XMP.
5160
        
5161
        newXMP.RemoveProperties (XMP_NS_EXIF);
5162
        newXMP.RemoveProperties (XMP_NS_AUX);
5163
        
5164
        // Remove Camera Raw info
5165
        
5166
        newXMP.RemoveProperties (XMP_NS_CRS);
5167
        newXMP.RemoveProperties (XMP_NS_CRSS);
5168
        newXMP.RemoveProperties (XMP_NS_CRX);
5169
        
5170
        // Remove DocOps history, since it contains the original
5171
        // camera format.
5172
        
5173
        newXMP.Remove (XMP_NS_MM, "History");
5174
        
5175
        // MakerNote contains camera info.
5176
        
5177
        metadata.ClearMakerNote ();
5178
      
5179
        }
5180
        
5181
      if (metadataSubset == kMetadataSubset_AllExceptLocationInfo ||
5182
        metadataSubset == kMetadataSubset_AllExceptCameraAndLocation)
5183
        {
5184
        
5185
        // Remove GPS fields.
5186
        
5187
        dng_exif blankExif;
5188
        
5189
        newEXIF.CopyGPSFrom (blankExif);
5190
        
5191
        // Remove MakerNote just in case, because we don't know
5192
        // all of what is in it.
5193
        
5194
        metadata.ClearMakerNote ();
5195
        
5196
        // Remove XMP & IPTC location fields.
5197
        
5198
        newXMP.Remove (XMP_NS_PHOTOSHOP, "City");
5199
        newXMP.Remove (XMP_NS_PHOTOSHOP, "State");
5200
        newXMP.Remove (XMP_NS_PHOTOSHOP, "Country");
5201
        newXMP.Remove (XMP_NS_IPTC, "Location");
5202
        newXMP.Remove (XMP_NS_IPTC, "CountryCode");
5203
        newXMP.Remove (XMP_NS_IPTC_EXT, "LocationCreated");
5204
        newXMP.Remove (XMP_NS_IPTC_EXT, "LocationShown");
5205
        
5206
        }
5207
      
5208
      }
5209
                    
5210
    // Rebuild the legacy IPTC block, if needed.
5211
    
5212
    bool isTIFF = (strcmp (dstMIMI, "image/tiff") == 0);
5213
    bool isDNG  = (strcmp (dstMIMI, "image/dng" ) == 0);
5214
5215
    if (!isDNG)
5216
      {
5217
    
5218
      metadata.RebuildIPTC (host.Allocator (),
5219
                  isTIFF);
5220
                  
5221
      }
5222
      
5223
    else
5224
      {
5225
      
5226
      metadata.ClearIPTC ();
5227
      
5228
      }
5229
  
5230
    // Clear format related XMP.
5231
                    
5232
    newXMP.ClearOrientation ();
5233
    
5234
    newXMP.ClearImageInfo ();
5235
    
5236
    newXMP.RemoveProperties (XMP_NS_DNG);
5237
    
5238
    // All the formats we care about already keep the IPTC digest
5239
    // elsewhere, do we don't need to write it to the XMP.
5240
    
5241
    newXMP.ClearIPTCDigest ();
5242
    
5243
    // Make sure that sidecar specific tags never get written to files.
5244
    
5245
    newXMP.Remove (XMP_NS_PHOTOSHOP, "SidecarForExtension");
5246
    newXMP.Remove (XMP_NS_PHOTOSHOP, "EmbeddedXMPDigest");
5247
    
5248
    }
5249
  
5250
  #endif
5251
  
5252
26.5k
  }
5253
5254
/*****************************************************************************/
5255
5256
void dng_image_writer::WriteTIFF (dng_host &host,
5257
                  dng_stream &stream,
5258
                  const dng_image &image,
5259
                  uint32 photometricInterpretation,
5260
                  uint32 compression,
5261
                  dng_negative *negative,
5262
                  const dng_color_space *space,
5263
                  const dng_resolution *resolution,
5264
                  const dng_jpeg_preview *thumbnail,
5265
                  const dng_memory_block *imageResources,
5266
                  dng_metadata_subset metadataSubset)
5267
4.72k
  {
5268
  
5269
4.72k
  WriteTIFF (host,
5270
4.72k
         stream,
5271
4.72k
         image,
5272
4.72k
         photometricInterpretation,
5273
4.72k
         compression,
5274
4.72k
         negative ? &(negative->Metadata ()) : NULL,
5275
4.72k
         space,
5276
4.72k
         resolution,
5277
4.72k
         thumbnail,
5278
4.72k
         imageResources,
5279
4.72k
         metadataSubset);
5280
  
5281
4.72k
  }
5282
  
5283
/*****************************************************************************/
5284
5285
void dng_image_writer::WriteTIFF (dng_host &host,
5286
                  dng_stream &stream,
5287
                  const dng_image &image,
5288
                  uint32 photometricInterpretation,
5289
                  uint32 compression,
5290
                  const dng_metadata *metadata,
5291
                  const dng_color_space *space,
5292
                  const dng_resolution *resolution,
5293
                  const dng_jpeg_preview *thumbnail,
5294
                  const dng_memory_block *imageResources,
5295
                  dng_metadata_subset metadataSubset)
5296
66.5k
  {
5297
  
5298
66.5k
  const void *profileData = NULL;
5299
66.5k
  uint32 profileSize = 0;
5300
  
5301
66.5k
  const uint8 *data = NULL;
5302
66.5k
  uint32 size = 0;
5303
  
5304
66.5k
  if (space && space->ICCProfile (size, data))
5305
4.72k
    {
5306
    
5307
4.72k
    profileData = data;
5308
4.72k
    profileSize = size;
5309
    
5310
4.72k
    }
5311
    
5312
66.5k
  WriteTIFFWithProfile (host,
5313
66.5k
              stream,
5314
66.5k
              image,
5315
66.5k
              photometricInterpretation,
5316
66.5k
              compression,
5317
66.5k
              metadata,
5318
66.5k
              profileData,
5319
66.5k
              profileSize,
5320
66.5k
              resolution,
5321
66.5k
              thumbnail,
5322
66.5k
              imageResources,
5323
66.5k
              metadataSubset);
5324
  
5325
66.5k
  }
5326
5327
/*****************************************************************************/
5328
5329
void dng_image_writer::WriteTIFFWithProfile (dng_host &host,
5330
                       dng_stream &stream,
5331
                       const dng_image &image,
5332
                       uint32 photometricInterpretation,
5333
                       uint32 compression,
5334
                       dng_negative *negative,
5335
                       const void *profileData,
5336
                       uint32 profileSize,
5337
                       const dng_resolution *resolution,
5338
                       const dng_jpeg_preview *thumbnail,
5339
                       const dng_memory_block *imageResources,
5340
                       dng_metadata_subset metadataSubset)
5341
0
  {
5342
  
5343
0
  WriteTIFFWithProfile (host,
5344
0
              stream,
5345
0
              image,
5346
0
              photometricInterpretation,
5347
0
              compression,
5348
0
              negative ? &(negative->Metadata ()) : NULL,
5349
0
              profileData,
5350
0
              profileSize,
5351
0
              resolution,
5352
0
              thumbnail,
5353
0
              imageResources,
5354
0
              metadataSubset);
5355
  
5356
0
  }
5357
  
5358
/*****************************************************************************/
5359
5360
void dng_image_writer::WriteTIFFWithProfile (dng_host &host,
5361
                       dng_stream &stream,
5362
                       const dng_image &image,
5363
                       uint32 photometricInterpretation,
5364
                       uint32 compression,
5365
                       const dng_metadata *constMetadata,
5366
                       const void *profileData,
5367
                       uint32 profileSize,
5368
                       const dng_resolution *resolution,
5369
                       const dng_jpeg_preview *thumbnail,
5370
                       const dng_memory_block *imageResources,
5371
                       dng_metadata_subset metadataSubset)
5372
66.5k
  {
5373
  
5374
66.5k
  uint32 j;
5375
  
5376
66.5k
  AutoPtr<dng_metadata> metadata;
5377
  
5378
66.5k
  if (constMetadata)
5379
4.72k
    {
5380
    
5381
4.72k
    metadata.Reset (constMetadata->Clone (host.Allocator ()));
5382
    
5383
4.72k
    CleanUpMetadata (host, 
5384
4.72k
             *metadata,
5385
4.72k
             metadataSubset,
5386
4.72k
             "image/tiff");
5387
    
5388
4.72k
    }
5389
  
5390
66.5k
  dng_ifd ifd;
5391
  
5392
66.5k
  ifd.fNewSubFileType = sfMainImage;
5393
  
5394
66.5k
  ifd.fImageWidth  = image.Bounds ().W ();
5395
66.5k
  ifd.fImageLength = image.Bounds ().H ();
5396
  
5397
66.5k
  ifd.fSamplesPerPixel = image.Planes ();
5398
  
5399
66.5k
  ifd.fBitsPerSample [0] = TagTypeSize (image.PixelType ()) * 8;
5400
  
5401
93.7k
  for (j = 1; j < ifd.fSamplesPerPixel; j++)
5402
27.2k
    {
5403
27.2k
    ifd.fBitsPerSample [j] = ifd.fBitsPerSample [0];
5404
27.2k
    }
5405
    
5406
66.5k
  ifd.fPhotometricInterpretation = photometricInterpretation;
5407
  
5408
66.5k
  ifd.fCompression = compression;
5409
  
5410
66.5k
  if (ifd.fCompression == ccUncompressed)
5411
36.4k
    {
5412
    
5413
36.4k
    ifd.SetSingleStrip ();
5414
    
5415
36.4k
    }
5416
    
5417
30.0k
  else
5418
30.0k
    {
5419
    
5420
30.0k
    ifd.FindStripSize (128 * 1024);
5421
    
5422
30.0k
    ifd.fPredictor = cpHorizontalDifference;
5423
    
5424
30.0k
    }
5425
5426
66.5k
  uint32 extraSamples = 0;
5427
  
5428
66.5k
  switch (photometricInterpretation)
5429
66.5k
    {
5430
    
5431
53.3k
    case piBlackIsZero:
5432
53.3k
      {
5433
53.3k
      extraSamples = image.Planes () - 1;
5434
53.3k
      break;
5435
0
      }
5436
      
5437
13.1k
    case piRGB:
5438
13.1k
      {
5439
13.1k
      extraSamples = image.Planes () - 3;
5440
13.1k
      break;
5441
0
      }
5442
      
5443
0
    default:
5444
0
      break;
5445
      
5446
66.5k
    }
5447
    
5448
66.5k
  ifd.fExtraSamplesCount = extraSamples;
5449
  
5450
66.5k
  if (image.PixelType () == ttFloat)
5451
10.4k
    {
5452
    
5453
22.0k
    for (j = 0; j < ifd.fSamplesPerPixel; j++)
5454
11.5k
      {
5455
11.5k
      ifd.fSampleFormat [j] = sfFloatingPoint;
5456
11.5k
      }
5457
      
5458
10.4k
    }
5459
  
5460
66.5k
  dng_tiff_directory mainIFD;
5461
  
5462
66.5k
  dng_basic_tag_set basic (mainIFD, ifd);
5463
  
5464
  // Resolution.
5465
  
5466
66.5k
  dng_resolution res;
5467
  
5468
66.5k
  if (resolution)
5469
0
    {
5470
0
    res = *resolution;
5471
0
    }
5472
  
5473
66.5k
  tag_urational tagXResolution (tcXResolution, res.fXResolution);
5474
66.5k
  tag_urational tagYResolution (tcYResolution, res.fYResolution);
5475
  
5476
66.5k
  tag_uint16 tagResolutionUnit (tcResolutionUnit, res.fResolutionUnit);
5477
  
5478
66.5k
  if (resolution)
5479
0
    {
5480
0
    mainIFD.Add (&tagXResolution   );
5481
0
    mainIFD.Add (&tagYResolution   );
5482
0
    mainIFD.Add (&tagResolutionUnit);
5483
0
    }
5484
5485
  // ICC Profile.
5486
  
5487
66.5k
  tag_icc_profile iccProfileTag (profileData, profileSize);
5488
  
5489
66.5k
  if (iccProfileTag.Count ())
5490
4.72k
    {
5491
4.72k
    mainIFD.Add (&iccProfileTag);
5492
4.72k
    }
5493
    
5494
  // XMP metadata.
5495
  
5496
  #if qDNGUseXMP
5497
  
5498
  tag_xmp tagXMP (metadata.Get () ? metadata->GetXMP () : NULL);
5499
  
5500
  if (tagXMP.Count ())
5501
    {
5502
    mainIFD.Add (&tagXMP);
5503
    }
5504
    
5505
  #endif
5506
  
5507
  // IPTC metadata.
5508
  
5509
66.5k
  tag_iptc tagIPTC (metadata.Get () ? metadata->IPTCData   () : NULL,
5510
66.5k
            metadata.Get () ? metadata->IPTCLength () : 0);
5511
    
5512
66.5k
  if (tagIPTC.Count ())
5513
27
    {
5514
27
    mainIFD.Add (&tagIPTC);
5515
27
    }
5516
    
5517
  // Adobe data (thumbnail and IPTC digest)
5518
  
5519
66.5k
  AutoPtr<dng_memory_block> adobeData (BuildAdobeData (host,
5520
66.5k
                             metadata.Get (),
5521
66.5k
                             thumbnail,
5522
66.5k
                             imageResources));
5523
                             
5524
66.5k
  tag_uint8_ptr tagAdobe (tcAdobeData,
5525
66.5k
              adobeData->Buffer_uint8 (),
5526
66.5k
              adobeData->LogicalSize ());
5527
                   
5528
66.5k
  if (tagAdobe.Count ())
5529
27
    {
5530
27
    mainIFD.Add (&tagAdobe);
5531
27
    }
5532
    
5533
  // Exif metadata.
5534
  
5535
66.5k
  exif_tag_set exifSet (mainIFD,
5536
66.5k
              metadata.Get () && metadata->GetExif () ? *metadata->GetExif () 
5537
66.5k
                                  : dng_exif (),
5538
66.5k
              metadata.Get () ? metadata->IsMakerNoteSafe () : false,
5539
66.5k
              metadata.Get () ? metadata->MakerNoteData   () : NULL,
5540
66.5k
              metadata.Get () ? metadata->MakerNoteLength () : 0,
5541
66.5k
              false);
5542
5543
  // Find offset to main image data.
5544
  
5545
66.5k
  uint32 offsetMainIFD = 8;
5546
  
5547
66.5k
  uint32 offsetExifData = offsetMainIFD + mainIFD.Size ();
5548
  
5549
66.5k
  exifSet.Locate (offsetExifData);
5550
  
5551
66.5k
  uint32 offsetMainData = offsetExifData + exifSet.Size ();
5552
    
5553
66.5k
  stream.SetWritePosition (offsetMainData);
5554
  
5555
  // Write the main image data.
5556
  
5557
66.5k
  WriteImage (host,
5558
66.5k
        ifd,
5559
66.5k
        basic,
5560
66.5k
        stream,
5561
66.5k
        image);
5562
        
5563
  // Trim the file to this length.
5564
  
5565
66.5k
  stream.SetLength (stream.Position ());
5566
  
5567
  // TIFF has a 4G size limit.
5568
  
5569
66.5k
  if (stream.Length () > 0x0FFFFFFFFL)
5570
0
    {
5571
0
    ThrowImageTooBigTIFF ();
5572
0
    }
5573
  
5574
  // Write TIFF Header.
5575
  
5576
66.5k
  stream.SetWritePosition (0);
5577
  
5578
66.5k
  stream.Put_uint16 (stream.BigEndian () ? byteOrderMM : byteOrderII);
5579
  
5580
66.5k
  stream.Put_uint16 (42);
5581
  
5582
66.5k
  stream.Put_uint32 (offsetMainIFD);
5583
  
5584
  // Write the IFDs.
5585
  
5586
66.5k
  mainIFD.Put (stream);
5587
  
5588
66.5k
  exifSet.Put (stream);
5589
  
5590
66.5k
  stream.Flush ();
5591
  
5592
66.5k
  }
5593
                 
5594
/*****************************************************************************/
5595
5596
void dng_image_writer::WriteDNG (dng_host &host,
5597
                   dng_stream &stream,
5598
                   dng_negative &negative,
5599
                   const dng_preview_list *previewList,
5600
                 uint32 maxBackwardVersion,
5601
                   bool uncompressed)
5602
21.8k
  {
5603
  
5604
21.8k
  WriteDNG (host,
5605
21.8k
        stream,
5606
21.8k
        negative,
5607
21.8k
        negative.Metadata (),
5608
21.8k
        previewList,
5609
21.8k
        maxBackwardVersion,
5610
21.8k
        uncompressed);
5611
  
5612
21.8k
  }
5613
  
5614
/*****************************************************************************/
5615
5616
void dng_image_writer::WriteDNG (dng_host &host,
5617
                   dng_stream &stream,
5618
                   const dng_negative &negative,
5619
                 const dng_metadata &constMetadata,
5620
                 const dng_preview_list *previewList,
5621
                 uint32 maxBackwardVersion,
5622
                   bool uncompressed)
5623
21.8k
  {
5624
5625
21.8k
  uint32 j;
5626
  
5627
  // Clean up metadata per MWG recommendations.
5628
  
5629
21.8k
  AutoPtr<dng_metadata> metadata (constMetadata.Clone (host.Allocator ()));
5630
5631
21.8k
  CleanUpMetadata (host, 
5632
21.8k
           *metadata,
5633
21.8k
           kMetadataSubset_All,
5634
21.8k
           "image/dng");
5635
           
5636
  // Figure out the compression to use.  Most of the time this is lossless
5637
  // JPEG.
5638
  
5639
21.8k
  uint32 compression = uncompressed ? ccUncompressed : ccJPEG;
5640
    
5641
  // Was the the original file lossy JPEG compressed?
5642
  
5643
21.8k
  const dng_jpeg_image *rawJPEGImage = negative.RawJPEGImage ();
5644
  
5645
  // If so, can we save it using the requested compression and DNG version?
5646
  
5647
21.8k
  if (uncompressed || maxBackwardVersion < dngVersion_1_4_0_0)
5648
9.88k
    {
5649
    
5650
9.88k
    if (rawJPEGImage || negative.RawJPEGImageDigest ().IsValid ())
5651
0
      {
5652
      
5653
0
      rawJPEGImage = NULL;
5654
      
5655
0
      negative.ClearRawJPEGImageDigest ();
5656
      
5657
0
      negative.ClearRawImageDigest ();
5658
      
5659
0
      }
5660
    
5661
9.88k
    }
5662
    
5663
11.9k
  else if (rawJPEGImage)
5664
5.62k
    {
5665
    
5666
5.62k
    compression = ccLossyJPEG;
5667
    
5668
5.62k
    }
5669
    
5670
  // Are we saving the original size tags?
5671
  
5672
21.8k
  bool saveOriginalDefaultFinalSize     = false;
5673
21.8k
  bool saveOriginalBestQualityFinalSize = false;
5674
21.8k
  bool saveOriginalDefaultCropSize      = false;
5675
  
5676
21.8k
    {
5677
    
5678
    // See if we are saving a proxy image.
5679
    
5680
21.8k
    dng_point defaultFinalSize (negative.DefaultFinalHeight (),
5681
21.8k
                  negative.DefaultFinalWidth  ());
5682
                  
5683
21.8k
    saveOriginalDefaultFinalSize = (negative.OriginalDefaultFinalSize () !=
5684
21.8k
                    defaultFinalSize);
5685
    
5686
21.8k
    if (saveOriginalDefaultFinalSize)
5687
4.46k
      {
5688
      
5689
      // If the save OriginalDefaultFinalSize tag, this changes the defaults
5690
      // for the OriginalBestQualityFinalSize and OriginalDefaultCropSize tags.
5691
      
5692
4.46k
      saveOriginalBestQualityFinalSize = (negative.OriginalBestQualityFinalSize () != 
5693
4.46k
                        defaultFinalSize);
5694
                        
5695
4.46k
      saveOriginalDefaultCropSize = (negative.OriginalDefaultCropSizeV () !=
5696
4.46k
                       dng_urational (defaultFinalSize.v, 1)) ||
5697
417
                      (negative.OriginalDefaultCropSizeH () !=
5698
417
                       dng_urational (defaultFinalSize.h, 1));
5699
5700
4.46k
      }
5701
      
5702
17.3k
    else
5703
17.3k
      {
5704
      
5705
      // Else these two tags default to the normal non-proxy size image values.
5706
      
5707
17.3k
      dng_point bestQualityFinalSize (negative.BestQualityFinalHeight (),
5708
17.3k
                      negative.BestQualityFinalWidth  ());
5709
                      
5710
17.3k
      saveOriginalBestQualityFinalSize = (negative.OriginalBestQualityFinalSize () != 
5711
17.3k
                        bestQualityFinalSize);
5712
                        
5713
17.3k
      saveOriginalDefaultCropSize = (negative.OriginalDefaultCropSizeV () !=
5714
17.3k
                       negative.DefaultCropSizeV ()) ||
5715
17.1k
                      (negative.OriginalDefaultCropSizeH () !=
5716
17.1k
                       negative.DefaultCropSizeH ());
5717
      
5718
17.3k
      }
5719
    
5720
21.8k
    }
5721
    
5722
  // Is this a floating point image that we are saving?
5723
  
5724
21.8k
  bool isFloatingPoint = (negative.RawImage ().PixelType () == ttFloat);
5725
  
5726
  // Does this image have a transparency mask?
5727
  
5728
21.8k
  bool hasTransparencyMask = (negative.RawTransparencyMask () != NULL);
5729
  
5730
  // Should we save a compressed 32-bit integer file?
5731
  
5732
21.8k
  bool isCompressed32BitInteger = (negative.RawImage ().PixelType () == ttLong) &&
5733
123
                    (maxBackwardVersion >= dngVersion_1_4_0_0) &&
5734
123
                  (!uncompressed);
5735
  
5736
  // Figure out what main version to use.
5737
  
5738
21.8k
  uint32 dngVersion = dngVersion_Current;
5739
  
5740
  // Don't write version 1.4 files unless we actually use some feature of the 1.4 spec.
5741
  
5742
21.8k
  if (dngVersion == dngVersion_1_4_0_0)
5743
21.7k
    {
5744
    
5745
21.7k
    if (!rawJPEGImage                     &&
5746
16.1k
      !isFloatingPoint          &&
5747
11.3k
      !hasTransparencyMask        &&
5748
11.3k
      !isCompressed32BitInteger      &&
5749
11.2k
      !saveOriginalDefaultFinalSize     &&
5750
11.2k
      !saveOriginalBestQualityFinalSize &&
5751
11.2k
      !saveOriginalDefaultCropSize      )
5752
11.1k
      {
5753
        
5754
11.1k
      dngVersion = dngVersion_1_3_0_0;
5755
        
5756
11.1k
      }
5757
      
5758
21.7k
    }
5759
  
5760
  // Figure out what backward version to use.
5761
  
5762
21.8k
  uint32 dngBackwardVersion = dngVersion_1_1_0_0;
5763
  
5764
  #if defined(qTestRowInterleave) || defined(qTestSubTileBlockRows) || defined(qTestSubTileBlockCols)
5765
  dngBackwardVersion = Max_uint32 (dngBackwardVersion, dngVersion_1_2_0_0);
5766
  #endif
5767
  
5768
21.8k
  dngBackwardVersion = Max_uint32 (dngBackwardVersion,
5769
21.8k
                   negative.OpcodeList1 ().MinVersion (false));
5770
5771
21.8k
  dngBackwardVersion = Max_uint32 (dngBackwardVersion,
5772
21.8k
                   negative.OpcodeList2 ().MinVersion (false));
5773
5774
21.8k
  dngBackwardVersion = Max_uint32 (dngBackwardVersion,
5775
21.8k
                   negative.OpcodeList3 ().MinVersion (false));
5776
                   
5777
21.8k
  if (negative.GetMosaicInfo () &&
5778
387
    negative.GetMosaicInfo ()->fCFALayout >= 6)
5779
9
    {
5780
9
    dngBackwardVersion = Max_uint32 (dngBackwardVersion, dngVersion_1_3_0_0);
5781
9
    }
5782
    
5783
21.8k
  if (rawJPEGImage || isFloatingPoint || hasTransparencyMask || isCompressed32BitInteger)
5784
10.5k
    {
5785
10.5k
    dngBackwardVersion = Max_uint32 (dngBackwardVersion, dngVersion_1_4_0_0);
5786
10.5k
    }
5787
                   
5788
21.8k
  if (dngBackwardVersion > dngVersion)
5789
27
    {
5790
27
    ThrowProgramError ();
5791
27
    }
5792
    
5793
  // Find best thumbnail from preview list, if any.
5794
5795
21.8k
  const dng_preview *thumbnail = NULL;
5796
  
5797
21.8k
  if (previewList)
5798
21.7k
    {
5799
    
5800
21.7k
    uint32 thumbArea = 0;
5801
    
5802
28.4k
    for (j = 0; j < previewList->Count (); j++)
5803
6.67k
      {
5804
      
5805
6.67k
      const dng_image_preview *imagePreview = dynamic_cast<const dng_image_preview *>(&previewList->Preview (j));
5806
      
5807
6.67k
      if (imagePreview)
5808
2.59k
        {
5809
        
5810
2.59k
        uint32 thisArea = imagePreview->fImage->Bounds ().W () *
5811
2.59k
                  imagePreview->fImage->Bounds ().H ();
5812
                  
5813
2.59k
        if (!thumbnail || thisArea < thumbArea)
5814
2.59k
          {
5815
          
5816
2.59k
          thumbnail = &previewList->Preview (j);
5817
          
5818
2.59k
          thumbArea = thisArea;
5819
          
5820
2.59k
          }
5821
      
5822
2.59k
        }
5823
        
5824
6.67k
      const dng_jpeg_preview *jpegPreview = dynamic_cast<const dng_jpeg_preview *>(&previewList->Preview (j));
5825
      
5826
6.67k
      if (jpegPreview)
5827
4.07k
        {
5828
        
5829
4.07k
        uint32 thisArea = jpegPreview->fPreviewSize.h *
5830
4.07k
                  jpegPreview->fPreviewSize.v;
5831
                  
5832
4.07k
        if (!thumbnail || thisArea < thumbArea)
5833
2.63k
          {
5834
          
5835
2.63k
          thumbnail = &previewList->Preview (j);
5836
          
5837
2.63k
          thumbArea = thisArea;
5838
          
5839
2.63k
          }
5840
        
5841
4.07k
        }
5842
        
5843
6.67k
      }
5844
    
5845
21.7k
    }
5846
    
5847
  // Create the main IFD
5848
                     
5849
21.8k
  dng_tiff_directory mainIFD;
5850
  
5851
  // Create the IFD for the raw data. If there is no thumnail, this is
5852
  // just a reference the main IFD.  Otherwise allocate a new one.
5853
  
5854
21.8k
  AutoPtr<dng_tiff_directory> rawIFD_IfNotMain;
5855
  
5856
21.8k
  if (thumbnail)
5857
5.22k
    {
5858
5.22k
    rawIFD_IfNotMain.Reset (new dng_tiff_directory);
5859
5.22k
    }
5860
5861
21.8k
  dng_tiff_directory &rawIFD (thumbnail ? *rawIFD_IfNotMain : mainIFD);
5862
  
5863
  // Include DNG version tags.
5864
  
5865
21.8k
  uint8 dngVersionData [4];
5866
  
5867
21.8k
  dngVersionData [0] = (uint8) (dngVersion >> 24);
5868
21.8k
  dngVersionData [1] = (uint8) (dngVersion >> 16);
5869
21.8k
  dngVersionData [2] = (uint8) (dngVersion >>  8);
5870
21.8k
  dngVersionData [3] = (uint8) (dngVersion      );
5871
  
5872
21.8k
  tag_uint8_ptr tagDNGVersion (tcDNGVersion, dngVersionData, 4);
5873
  
5874
21.8k
  mainIFD.Add (&tagDNGVersion);
5875
  
5876
21.8k
  uint8 dngBackwardVersionData [4];
5877
5878
21.8k
  dngBackwardVersionData [0] = (uint8) (dngBackwardVersion >> 24);
5879
21.8k
  dngBackwardVersionData [1] = (uint8) (dngBackwardVersion >> 16);
5880
21.8k
  dngBackwardVersionData [2] = (uint8) (dngBackwardVersion >>  8);
5881
21.8k
  dngBackwardVersionData [3] = (uint8) (dngBackwardVersion      );
5882
  
5883
21.8k
  tag_uint8_ptr tagDNGBackwardVersion (tcDNGBackwardVersion, dngBackwardVersionData, 4);
5884
  
5885
21.8k
  mainIFD.Add (&tagDNGBackwardVersion);
5886
  
5887
  // The main IFD contains the thumbnail, if there is a thumbnail.
5888
                
5889
21.8k
  AutoPtr<dng_basic_tag_set> thmBasic;
5890
  
5891
21.8k
  if (thumbnail)
5892
5.22k
    {
5893
5.22k
    thmBasic.Reset (thumbnail->AddTagSet (mainIFD));
5894
5.22k
    }
5895
              
5896
  // Get the raw image we are writing.
5897
  
5898
21.8k
  const dng_image &rawImage (negative.RawImage ());
5899
  
5900
  // For floating point, we only support ZIP compression.
5901
  
5902
21.8k
  if (isFloatingPoint && !uncompressed)
5903
4.76k
    {
5904
    
5905
4.76k
    compression = ccDeflate;
5906
    
5907
4.76k
    }
5908
  
5909
  // For 32-bit integer images, we only support ZIP and uncompressed.
5910
  
5911
21.8k
  if (rawImage.PixelType () == ttLong)
5912
123
    {
5913
    
5914
123
    if (isCompressed32BitInteger)
5915
123
      {
5916
123
      compression = ccDeflate;
5917
123
      }
5918
      
5919
0
    else
5920
0
      {
5921
0
      compression = ccUncompressed;
5922
0
      }
5923
  
5924
123
    }
5925
  
5926
  // Get a copy of the mosaic info.
5927
  
5928
21.8k
  dng_mosaic_info mosaicInfo;
5929
  
5930
21.8k
  if (negative.GetMosaicInfo ())
5931
387
    {
5932
387
    mosaicInfo = *(negative.GetMosaicInfo ());
5933
387
    }
5934
    
5935
  // Create a dng_ifd record for the raw image.
5936
  
5937
21.8k
  dng_ifd info;
5938
  
5939
21.8k
  info.fImageWidth  = rawImage.Width  ();
5940
21.8k
  info.fImageLength = rawImage.Height ();
5941
  
5942
21.8k
  info.fSamplesPerPixel = rawImage.Planes ();
5943
  
5944
21.8k
  info.fPhotometricInterpretation = mosaicInfo.IsColorFilterArray () ? piCFA
5945
21.8k
                                     : piLinearRaw;
5946
      
5947
21.8k
  info.fCompression = compression;
5948
  
5949
21.8k
  if (isFloatingPoint && compression == ccDeflate)
5950
4.76k
    {
5951
    
5952
4.76k
    info.fPredictor = cpFloatingPoint;
5953
    
5954
4.76k
    if (mosaicInfo.IsColorFilterArray ())
5955
60
      {
5956
      
5957
60
      if (mosaicInfo.fCFAPatternSize.h == 2)
5958
55
        {
5959
55
        info.fPredictor = cpFloatingPointX2;
5960
55
        }
5961
        
5962
5
      else if (mosaicInfo.fCFAPatternSize.h == 4)
5963
3
        {
5964
3
        info.fPredictor = cpFloatingPointX4;
5965
3
        }
5966
        
5967
60
      }
5968
      
5969
4.76k
    } 
5970
    
5971
21.8k
  if (isCompressed32BitInteger)
5972
123
    {
5973
    
5974
123
    info.fPredictor = cpHorizontalDifference;
5975
    
5976
123
    if (mosaicInfo.IsColorFilterArray ())
5977
43
      {
5978
      
5979
43
      if (mosaicInfo.fCFAPatternSize.h == 2)
5980
31
        {
5981
31
        info.fPredictor = cpHorizontalDifferenceX2;
5982
31
        }
5983
        
5984
12
      else if (mosaicInfo.fCFAPatternSize.h == 4)
5985
5
        {
5986
5
        info.fPredictor = cpHorizontalDifferenceX4;
5987
5
        }
5988
        
5989
43
      }
5990
      
5991
123
    }
5992
  
5993
21.8k
  uint32 rawPixelType = rawImage.PixelType ();
5994
  
5995
21.8k
  if (rawPixelType == ttShort)
5996
11.1k
    {
5997
    
5998
    // See if we are using a linearization table with <= 256 entries, in which
5999
    // case the useful data will all fit within 8-bits.
6000
    
6001
11.1k
    const dng_linearization_info *rangeInfo = negative.GetLinearizationInfo ();
6002
  
6003
11.1k
    if (rangeInfo)
6004
562
      {
6005
6006
562
      if (rangeInfo->fLinearizationTable.Get ())
6007
7
        {
6008
        
6009
7
        uint32 entries = rangeInfo->fLinearizationTable->LogicalSize () >> 1;
6010
        
6011
7
        if (entries <= 256)
6012
2
          {
6013
          
6014
2
          rawPixelType = ttByte;
6015
          
6016
2
          }
6017
                        
6018
7
        }
6019
        
6020
562
      }
6021
6022
11.1k
    }
6023
  
6024
21.8k
  switch (rawPixelType)
6025
21.8k
    {
6026
    
6027
5.71k
    case ttByte:
6028
5.71k
      {
6029
5.71k
      info.fBitsPerSample [0] = 8;
6030
5.71k
      break;
6031
0
      }
6032
    
6033
11.1k
    case ttShort:
6034
11.1k
      {
6035
11.1k
      info.fBitsPerSample [0] = 16;
6036
11.1k
      break;
6037
0
      }
6038
      
6039
123
    case ttLong:
6040
123
      {
6041
123
      info.fBitsPerSample [0] = 32;
6042
123
      break;
6043
0
      }
6044
      
6045
4.76k
    case ttFloat:
6046
4.76k
      {
6047
      
6048
4.76k
      if (negative.RawFloatBitDepth () == 16)
6049
2.89k
        {
6050
2.89k
        info.fBitsPerSample [0] = 16;
6051
2.89k
        }
6052
        
6053
1.86k
      else if (negative.RawFloatBitDepth () == 24)
6054
57
        {
6055
57
        info.fBitsPerSample [0] = 24;
6056
57
        }
6057
        
6058
1.80k
      else
6059
1.80k
        {
6060
1.80k
        info.fBitsPerSample [0] = 32;
6061
1.80k
        }
6062
6063
10.3k
      for (j = 0; j < info.fSamplesPerPixel; j++)
6064
5.56k
        {
6065
5.56k
        info.fSampleFormat [j] = sfFloatingPoint;
6066
5.56k
        }
6067
6068
4.76k
      break;
6069
      
6070
0
      }
6071
      
6072
0
    default:
6073
0
      {
6074
0
      ThrowProgramError ();
6075
0
      }
6076
      
6077
21.8k
    }
6078
  
6079
  // For lossless JPEG compression, we often lie about the
6080
  // actual channel count to get the predictors to work across
6081
  // same color mosaic pixels.
6082
  
6083
21.7k
  uint32 fakeChannels = 1;
6084
  
6085
21.7k
  if (info.fCompression == ccJPEG)
6086
11.2k
    {
6087
    
6088
11.2k
    if (mosaicInfo.IsColorFilterArray ())
6089
253
      {
6090
      
6091
253
      if (mosaicInfo.fCFAPatternSize.h == 4)
6092
24
        {
6093
24
        fakeChannels = 4;
6094
24
        }
6095
        
6096
229
      else if (mosaicInfo.fCFAPatternSize.h == 2)
6097
226
        {
6098
226
        fakeChannels = 2;
6099
226
        }
6100
      
6101
      // However, lossless JEPG is limited to four channels,
6102
      // so compromise might be required.
6103
      
6104
253
      while (fakeChannels * info.fSamplesPerPixel > 4 &&
6105
0
           fakeChannels > 1)
6106
0
        {
6107
        
6108
0
        fakeChannels >>= 1;
6109
        
6110
0
        }
6111
      
6112
253
      }
6113
  
6114
11.2k
    }
6115
    
6116
  // Figure out tile sizes.
6117
  
6118
21.7k
  if (rawJPEGImage)
6119
5.61k
    {
6120
    
6121
5.61k
    DNG_ASSERT (rawPixelType == ttByte,
6122
5.61k
          "Unexpected jpeg pixel type");
6123
    
6124
5.61k
    DNG_ASSERT (info.fImageWidth  == (uint32) rawJPEGImage->fImageSize.h &&
6125
5.61k
          info.fImageLength == (uint32) rawJPEGImage->fImageSize.v,
6126
5.61k
          "Unexpected jpeg image size");
6127
          
6128
5.61k
    info.fTileWidth  = rawJPEGImage->fTileSize.h;
6129
5.61k
    info.fTileLength = rawJPEGImage->fTileSize.v;
6130
6131
5.61k
    info.fUsesStrips = rawJPEGImage->fUsesStrips;
6132
    
6133
5.61k
    info.fUsesTiles = !info.fUsesStrips;
6134
    
6135
5.61k
    }
6136
  
6137
16.1k
  else if (info.fCompression == ccJPEG)
6138
11.2k
    {
6139
    
6140
11.2k
    info.FindTileSize (128 * 1024);
6141
    
6142
11.2k
    }
6143
    
6144
4.88k
  else if (info.fCompression == ccDeflate)
6145
4.88k
    {
6146
    
6147
4.88k
    info.FindTileSize (512 * 1024);
6148
    
6149
4.88k
    }
6150
    
6151
0
  else if (info.fCompression == ccLossyJPEG)
6152
0
    {
6153
    
6154
0
    ThrowProgramError ("No JPEG compressed image");
6155
        
6156
0
    }
6157
    
6158
  // Don't use tiles for uncompressed images.
6159
    
6160
0
  else
6161
0
    {
6162
    
6163
0
    info.SetSingleStrip ();
6164
    
6165
0
    }
6166
    
6167
  #ifdef qTestRowInterleave
6168
  
6169
  info.fRowInterleaveFactor = qTestRowInterleave;
6170
  
6171
  #endif
6172
      
6173
  #if defined(qTestSubTileBlockRows) && defined(qTestSubTileBlockCols)
6174
  
6175
  info.fSubTileBlockRows = qTestSubTileBlockRows;
6176
  info.fSubTileBlockCols = qTestSubTileBlockCols;
6177
  
6178
  if (fakeChannels == 2)
6179
    fakeChannels = 4;
6180
  
6181
  #endif
6182
  
6183
  // Basic information.
6184
  
6185
21.7k
  dng_basic_tag_set rawBasic (rawIFD, info);
6186
  
6187
  // JPEG tables, if any.
6188
  
6189
21.7k
  tag_data_ptr tagJPEGTables (tcJPEGTables,
6190
21.7k
                ttUndefined,
6191
21.7k
                0,
6192
21.7k
                NULL);
6193
                
6194
21.7k
  if (rawJPEGImage && rawJPEGImage->fJPEGTables.Get ())
6195
0
    {
6196
    
6197
0
    tagJPEGTables.SetData (rawJPEGImage->fJPEGTables->Buffer ());
6198
    
6199
0
    tagJPEGTables.SetCount (rawJPEGImage->fJPEGTables->LogicalSize ());
6200
    
6201
0
    rawIFD.Add (&tagJPEGTables);
6202
    
6203
0
    }
6204
              
6205
  // DefaultScale tag.
6206
6207
21.7k
  dng_urational defaultScaleData [2];
6208
  
6209
21.7k
  defaultScaleData [0] = negative.DefaultScaleH ();
6210
21.7k
  defaultScaleData [1] = negative.DefaultScaleV ();
6211
                        
6212
21.7k
  tag_urational_ptr tagDefaultScale (tcDefaultScale,
6213
21.7k
                       defaultScaleData,
6214
21.7k
                       2);
6215
6216
21.7k
  rawIFD.Add (&tagDefaultScale);
6217
  
6218
  // Best quality scale tag.
6219
  
6220
21.7k
  tag_urational tagBestQualityScale (tcBestQualityScale,
6221
21.7k
                     negative.BestQualityScale ());
6222
                    
6223
21.7k
  rawIFD.Add (&tagBestQualityScale);
6224
  
6225
  // DefaultCropOrigin tag.
6226
6227
21.7k
  dng_urational defaultCropOriginData [2];
6228
  
6229
21.7k
  defaultCropOriginData [0] = negative.DefaultCropOriginH ();
6230
21.7k
  defaultCropOriginData [1] = negative.DefaultCropOriginV ();
6231
                        
6232
21.7k
  tag_urational_ptr tagDefaultCropOrigin (tcDefaultCropOrigin,
6233
21.7k
                            defaultCropOriginData,
6234
21.7k
                            2);
6235
6236
21.7k
  rawIFD.Add (&tagDefaultCropOrigin);
6237
  
6238
  // DefaultCropSize tag.
6239
6240
21.7k
  dng_urational defaultCropSizeData [2];
6241
  
6242
21.7k
  defaultCropSizeData [0] = negative.DefaultCropSizeH ();
6243
21.7k
  defaultCropSizeData [1] = negative.DefaultCropSizeV ();
6244
                        
6245
21.7k
  tag_urational_ptr tagDefaultCropSize (tcDefaultCropSize,
6246
21.7k
                          defaultCropSizeData,
6247
21.7k
                          2);
6248
6249
21.7k
  rawIFD.Add (&tagDefaultCropSize);
6250
  
6251
  // DefaultUserCrop tag.
6252
6253
21.7k
  dng_urational defaultUserCropData [4];
6254
  
6255
21.7k
  defaultUserCropData [0] = negative.DefaultUserCropT ();
6256
21.7k
  defaultUserCropData [1] = negative.DefaultUserCropL ();
6257
21.7k
  defaultUserCropData [2] = negative.DefaultUserCropB ();
6258
21.7k
  defaultUserCropData [3] = negative.DefaultUserCropR ();
6259
                        
6260
21.7k
  tag_urational_ptr tagDefaultUserCrop (tcDefaultUserCrop,
6261
21.7k
                      defaultUserCropData,
6262
21.7k
                      4);
6263
6264
21.7k
  rawIFD.Add (&tagDefaultUserCrop);
6265
  
6266
  // Range mapping tag set.
6267
  
6268
21.7k
  range_tag_set rangeSet (rawIFD, negative);
6269
              
6270
  // Mosaic pattern information.
6271
  
6272
21.7k
  mosaic_tag_set mosaicSet (rawIFD, mosaicInfo);
6273
      
6274
  // Chroma blur radius.
6275
  
6276
21.7k
  tag_urational tagChromaBlurRadius (tcChromaBlurRadius,
6277
21.7k
                     negative.ChromaBlurRadius ());
6278
                    
6279
21.7k
  if (negative.ChromaBlurRadius ().IsValid ())
6280
2.42k
    {
6281
    
6282
2.42k
    rawIFD.Add (&tagChromaBlurRadius);
6283
    
6284
2.42k
    }
6285
  
6286
  // Anti-alias filter strength.
6287
  
6288
21.7k
  tag_urational tagAntiAliasStrength (tcAntiAliasStrength,
6289
21.7k
                      negative.AntiAliasStrength ());
6290
                    
6291
21.7k
  if (negative.AntiAliasStrength ().IsValid ())
6292
21.6k
    {
6293
    
6294
21.6k
    rawIFD.Add (&tagAntiAliasStrength);
6295
    
6296
21.6k
    }
6297
    
6298
  // Profile and other color related tags.
6299
  
6300
21.7k
  AutoPtr<profile_tag_set> profileSet;
6301
  
6302
21.7k
  AutoPtr<color_tag_set> colorSet;
6303
  
6304
21.7k
  dng_std_vector<uint32> extraProfileIndex;
6305
  
6306
21.7k
  if (!negative.IsMonochrome ())
6307
16.2k
    {
6308
    
6309
16.2k
    const dng_camera_profile &mainProfile (*negative.ComputeCameraProfileToEmbed (constMetadata));
6310
    
6311
16.2k
    profileSet.Reset (new profile_tag_set (mainIFD,
6312
16.2k
                         mainProfile));
6313
    
6314
16.2k
    colorSet.Reset (new color_tag_set (mainIFD,
6315
16.2k
                       negative));
6316
                       
6317
    // Build list of profile indices to include in extra profiles tag.
6318
                       
6319
16.2k
    uint32 profileCount = negative.ProfileCount ();
6320
    
6321
91.3k
    for (uint32 index = 0; index < profileCount; index++)
6322
75.1k
      {
6323
      
6324
75.1k
      const dng_camera_profile &profile (negative.ProfileByIndex (index));
6325
      
6326
75.1k
      if (&profile != &mainProfile)
6327
58.8k
        {
6328
        
6329
58.8k
        if (profile.WasReadFromDNG ())
6330
56.2k
          {
6331
          
6332
56.2k
          extraProfileIndex.push_back (index);
6333
          
6334
56.2k
          }
6335
        
6336
58.8k
        }
6337
        
6338
75.1k
      }
6339
                       
6340
16.2k
    }
6341
    
6342
  // Extra camera profiles tag.
6343
  
6344
21.7k
  uint32 extraProfileCount = (uint32) extraProfileIndex.size ();
6345
  
6346
21.7k
  dng_memory_data extraProfileOffsets (extraProfileCount, sizeof (uint32));
6347
  
6348
21.7k
  tag_uint32_ptr extraProfileTag (tcExtraCameraProfiles,
6349
21.7k
                  extraProfileOffsets.Buffer_uint32 (),
6350
21.7k
                  extraProfileCount);
6351
                  
6352
21.7k
  if (extraProfileCount)
6353
1.43k
    {
6354
    
6355
1.43k
    mainIFD.Add (&extraProfileTag);
6356
6357
1.43k
    }
6358
      
6359
  // Other tags.
6360
  
6361
21.7k
  tag_uint16 tagOrientation (tcOrientation,
6362
21.7k
                   (uint16) negative.ComputeOrientation (constMetadata).GetTIFF ());
6363
                 
6364
21.7k
  mainIFD.Add (&tagOrientation);
6365
6366
21.7k
  tag_srational tagBaselineExposure (tcBaselineExposure,
6367
21.7k
                       negative.BaselineExposureR ());
6368
                      
6369
21.7k
  mainIFD.Add (&tagBaselineExposure);
6370
6371
21.7k
  tag_urational tagBaselineNoise (tcBaselineNoise,
6372
21.7k
                      negative.BaselineNoiseR ());
6373
                      
6374
21.7k
  mainIFD.Add (&tagBaselineNoise);
6375
  
6376
21.7k
  tag_urational tagNoiseReductionApplied (tcNoiseReductionApplied,
6377
21.7k
                      negative.NoiseReductionApplied ());
6378
                      
6379
21.7k
  if (negative.NoiseReductionApplied ().IsValid ())
6380
1.17k
    {
6381
    
6382
1.17k
    mainIFD.Add (&tagNoiseReductionApplied);
6383
  
6384
1.17k
    }
6385
6386
21.7k
  tag_dng_noise_profile tagNoiseProfile (negative.NoiseProfile ());
6387
    
6388
21.7k
  if (negative.NoiseProfile ().IsValidForNegative (negative))
6389
146
    {
6390
6391
146
    mainIFD.Add (&tagNoiseProfile);
6392
    
6393
146
    }
6394
6395
21.7k
  tag_urational tagBaselineSharpness (tcBaselineSharpness,
6396
21.7k
                        negative.BaselineSharpnessR ());
6397
                      
6398
21.7k
  mainIFD.Add (&tagBaselineSharpness);
6399
6400
21.7k
  tag_string tagUniqueName (tcUniqueCameraModel,
6401
21.7k
                  negative.ModelName (),
6402
21.7k
                  true);
6403
                
6404
21.7k
  mainIFD.Add (&tagUniqueName);
6405
  
6406
21.7k
  tag_string tagLocalName (tcLocalizedCameraModel,
6407
21.7k
                 negative.LocalName (),
6408
21.7k
                 false);
6409
               
6410
21.7k
  if (negative.LocalName ().NotEmpty ())
6411
648
    {
6412
    
6413
648
    mainIFD.Add (&tagLocalName);
6414
  
6415
648
    }
6416
  
6417
21.7k
  tag_urational tagShadowScale (tcShadowScale,
6418
21.7k
                    negative.ShadowScaleR ());
6419
                      
6420
21.7k
  mainIFD.Add (&tagShadowScale);
6421
  
6422
21.7k
  tag_uint16 tagColorimetricReference (tcColorimetricReference,
6423
21.7k
                     (uint16) negative.ColorimetricReference ());
6424
                     
6425
21.7k
  if (negative.ColorimetricReference () != crSceneReferred)
6426
2.75k
    {
6427
    
6428
2.75k
    mainIFD.Add (&tagColorimetricReference);
6429
    
6430
2.75k
    }
6431
    
6432
21.7k
  bool useNewDigest = (maxBackwardVersion >= dngVersion_1_4_0_0);
6433
    
6434
21.7k
  if (compression == ccLossyJPEG)
6435
5.61k
    {
6436
    
6437
5.61k
    negative.FindRawJPEGImageDigest (host);
6438
    
6439
5.61k
    }
6440
    
6441
16.1k
  else
6442
16.1k
    {
6443
    
6444
16.1k
    if (useNewDigest)
6445
6.27k
      {
6446
6.27k
      negative.FindNewRawImageDigest (host);
6447
6.27k
      }
6448
9.84k
    else
6449
9.84k
      {
6450
9.84k
      negative.FindRawImageDigest (host);
6451
9.84k
      }
6452
    
6453
16.1k
    }
6454
  
6455
21.7k
  tag_uint8_ptr tagRawImageDigest (useNewDigest ? tcNewRawImageDigest : tcRawImageDigest,
6456
21.7k
                   compression == ccLossyJPEG ?
6457
5.61k
                   negative.RawJPEGImageDigest ().data :
6458
21.7k
                   (useNewDigest ? negative.NewRawImageDigest ().data
6459
16.1k
                           : negative.RawImageDigest    ().data),
6460
21.7k
                     16);
6461
                      
6462
21.7k
  mainIFD.Add (&tagRawImageDigest);
6463
  
6464
21.7k
  negative.FindRawDataUniqueID (host);
6465
  
6466
21.7k
  tag_uint8_ptr tagRawDataUniqueID (tcRawDataUniqueID,
6467
21.7k
                      negative.RawDataUniqueID ().data,
6468
21.7k
                      16);
6469
                      
6470
21.7k
  if (negative.RawDataUniqueID ().IsValid ())
6471
21.7k
    {
6472
                 
6473
21.7k
    mainIFD.Add (&tagRawDataUniqueID);
6474
    
6475
21.7k
    }
6476
  
6477
21.7k
  tag_string tagOriginalRawFileName (tcOriginalRawFileName,
6478
21.7k
                       negative.OriginalRawFileName (),
6479
21.7k
                       false);
6480
               
6481
21.7k
  if (negative.HasOriginalRawFileName ())
6482
144
    {
6483
    
6484
144
    mainIFD.Add (&tagOriginalRawFileName);
6485
  
6486
144
    }
6487
    
6488
21.7k
  negative.FindOriginalRawFileDigest ();
6489
    
6490
21.7k
  tag_data_ptr tagOriginalRawFileData (tcOriginalRawFileData,
6491
21.7k
                     ttUndefined,
6492
21.7k
                     negative.OriginalRawFileDataLength (),
6493
21.7k
                     negative.OriginalRawFileData       ());
6494
                     
6495
21.7k
  tag_uint8_ptr tagOriginalRawFileDigest (tcOriginalRawFileDigest,
6496
21.7k
                      negative.OriginalRawFileDigest ().data,
6497
21.7k
                      16);
6498
                     
6499
21.7k
  if (negative.OriginalRawFileData ())
6500
190
    {
6501
    
6502
190
    mainIFD.Add (&tagOriginalRawFileData);
6503
    
6504
190
    mainIFD.Add (&tagOriginalRawFileDigest);
6505
  
6506
190
    }
6507
6508
  // XMP metadata.
6509
6510
  #if qDNGUseXMP
6511
    
6512
  tag_xmp tagXMP (metadata->GetXMP ());
6513
  
6514
  if (tagXMP.Count ())
6515
    {
6516
    
6517
    mainIFD.Add (&tagXMP);
6518
    
6519
    }
6520
    
6521
  #endif
6522
  
6523
  // Exif tags.
6524
  
6525
21.7k
  exif_tag_set exifSet (mainIFD,
6526
21.7k
              *metadata->GetExif (),
6527
21.7k
              metadata->IsMakerNoteSafe (),
6528
21.7k
              metadata->MakerNoteData   (),
6529
21.7k
              metadata->MakerNoteLength (),
6530
21.7k
              true);
6531
            
6532
  // Private data.
6533
  
6534
21.7k
  tag_uint8_ptr tagPrivateData (tcDNGPrivateData,
6535
21.7k
                    negative.PrivateData (),
6536
21.7k
                    negative.PrivateLength ());
6537
               
6538
21.7k
  if (negative.PrivateLength ())
6539
238
    {
6540
    
6541
238
    mainIFD.Add (&tagPrivateData);
6542
    
6543
238
    }
6544
    
6545
  // Proxy size tags.
6546
  
6547
21.7k
  uint32 originalDefaultFinalSizeData [2];
6548
  
6549
21.7k
  originalDefaultFinalSizeData [0] = negative.OriginalDefaultFinalSize ().h;
6550
21.7k
  originalDefaultFinalSizeData [1] = negative.OriginalDefaultFinalSize ().v;
6551
  
6552
21.7k
  tag_uint32_ptr tagOriginalDefaultFinalSize (tcOriginalDefaultFinalSize,
6553
21.7k
                        originalDefaultFinalSizeData,
6554
21.7k
                        2);
6555
  
6556
21.7k
  if (saveOriginalDefaultFinalSize)
6557
4.46k
    {
6558
    
6559
4.46k
    mainIFD.Add (&tagOriginalDefaultFinalSize);
6560
    
6561
4.46k
    }
6562
    
6563
21.7k
  uint32 originalBestQualityFinalSizeData [2];
6564
  
6565
21.7k
  originalBestQualityFinalSizeData [0] = negative.OriginalBestQualityFinalSize ().h;
6566
21.7k
  originalBestQualityFinalSizeData [1] = negative.OriginalBestQualityFinalSize ().v;
6567
  
6568
21.7k
  tag_uint32_ptr tagOriginalBestQualityFinalSize (tcOriginalBestQualityFinalSize,
6569
21.7k
                          originalBestQualityFinalSizeData,
6570
21.7k
                          2);
6571
  
6572
21.7k
  if (saveOriginalBestQualityFinalSize)
6573
4.55k
    {
6574
    
6575
4.55k
    mainIFD.Add (&tagOriginalBestQualityFinalSize);
6576
    
6577
4.55k
    }
6578
    
6579
21.7k
  dng_urational originalDefaultCropSizeData [2];
6580
  
6581
21.7k
  originalDefaultCropSizeData [0] = negative.OriginalDefaultCropSizeH ();
6582
21.7k
  originalDefaultCropSizeData [1] = negative.OriginalDefaultCropSizeV ();
6583
  
6584
21.7k
  tag_urational_ptr tagOriginalDefaultCropSize (tcOriginalDefaultCropSize,
6585
21.7k
                          originalDefaultCropSizeData,
6586
21.7k
                          2);
6587
  
6588
21.7k
  if (saveOriginalDefaultCropSize)
6589
4.70k
    {
6590
    
6591
4.70k
    mainIFD.Add (&tagOriginalDefaultCropSize);
6592
    
6593
4.70k
    }
6594
    
6595
  // Opcode list 1.
6596
  
6597
21.7k
  AutoPtr<dng_memory_block> opcodeList1Data (negative.OpcodeList1 ().Spool (host));
6598
  
6599
21.7k
  tag_data_ptr tagOpcodeList1 (tcOpcodeList1,
6600
21.7k
                 ttUndefined,
6601
21.7k
                 opcodeList1Data.Get () ? opcodeList1Data->LogicalSize () : 0,
6602
21.7k
                 opcodeList1Data.Get () ? opcodeList1Data->Buffer      () : NULL);
6603
                 
6604
21.7k
  if (opcodeList1Data.Get ())
6605
0
    {
6606
    
6607
0
    rawIFD.Add (&tagOpcodeList1);
6608
    
6609
0
    }
6610
    
6611
  // Opcode list 2.
6612
  
6613
21.7k
  AutoPtr<dng_memory_block> opcodeList2Data (negative.OpcodeList2 ().Spool (host));
6614
  
6615
21.7k
  tag_data_ptr tagOpcodeList2 (tcOpcodeList2,
6616
21.7k
                 ttUndefined,
6617
21.7k
                 opcodeList2Data.Get () ? opcodeList2Data->LogicalSize () : 0,
6618
21.7k
                 opcodeList2Data.Get () ? opcodeList2Data->Buffer      () : NULL);
6619
                 
6620
21.7k
  if (opcodeList2Data.Get ())
6621
5.61k
    {
6622
    
6623
5.61k
    rawIFD.Add (&tagOpcodeList2);
6624
    
6625
5.61k
    }
6626
    
6627
  // Opcode list 3.
6628
  
6629
21.7k
  AutoPtr<dng_memory_block> opcodeList3Data (negative.OpcodeList3 ().Spool (host));
6630
  
6631
21.7k
  tag_data_ptr tagOpcodeList3 (tcOpcodeList3,
6632
21.7k
                 ttUndefined,
6633
21.7k
                 opcodeList3Data.Get () ? opcodeList3Data->LogicalSize () : 0,
6634
21.7k
                 opcodeList3Data.Get () ? opcodeList3Data->Buffer      () : NULL);
6635
                 
6636
21.7k
  if (opcodeList3Data.Get ())
6637
46
    {
6638
    
6639
46
    rawIFD.Add (&tagOpcodeList3);
6640
    
6641
46
    }
6642
    
6643
  // Transparency mask, if any.
6644
  
6645
21.7k
  AutoPtr<dng_ifd> maskInfo;
6646
  
6647
21.7k
  AutoPtr<dng_tiff_directory> maskIFD;
6648
  
6649
21.7k
  AutoPtr<dng_basic_tag_set> maskBasic;
6650
  
6651
21.7k
  if (hasTransparencyMask)
6652
0
    {
6653
    
6654
    // Create mask IFD.
6655
    
6656
0
    maskInfo.Reset (new dng_ifd);
6657
    
6658
0
    maskInfo->fNewSubFileType = sfTransparencyMask;
6659
    
6660
0
    maskInfo->fImageWidth  = negative.RawTransparencyMask ()->Bounds ().W ();
6661
0
    maskInfo->fImageLength = negative.RawTransparencyMask ()->Bounds ().H ();
6662
    
6663
0
    maskInfo->fSamplesPerPixel = 1;
6664
    
6665
0
    maskInfo->fBitsPerSample [0] = negative.RawTransparencyMaskBitDepth ();
6666
    
6667
0
    maskInfo->fPhotometricInterpretation = piTransparencyMask;
6668
    
6669
0
    maskInfo->fCompression = uncompressed ? ccUncompressed  : ccDeflate;
6670
0
    maskInfo->fPredictor   = uncompressed ? cpNullPredictor : cpHorizontalDifference;
6671
    
6672
0
    if (negative.RawTransparencyMask ()->PixelType () == ttFloat)
6673
0
      {
6674
      
6675
0
      maskInfo->fSampleFormat [0] = sfFloatingPoint;
6676
      
6677
0
      if (maskInfo->fCompression == ccDeflate)
6678
0
        {
6679
0
        maskInfo->fPredictor = cpFloatingPoint;
6680
0
        }
6681
      
6682
0
      }
6683
        
6684
0
    if (maskInfo->fCompression == ccDeflate)
6685
0
      {
6686
0
      maskInfo->FindTileSize (512 * 1024);
6687
0
      }
6688
0
    else
6689
0
      {
6690
0
      maskInfo->SetSingleStrip ();
6691
0
      }
6692
      
6693
    // Create mask tiff directory.
6694
      
6695
0
    maskIFD.Reset (new dng_tiff_directory);
6696
    
6697
    // Add mask basic tag set.
6698
    
6699
0
    maskBasic.Reset (new dng_basic_tag_set (*maskIFD, *maskInfo));
6700
        
6701
0
    }
6702
    
6703
  // Add other subfiles.
6704
    
6705
21.7k
  uint32 subFileCount = thumbnail ? 1 : 0;
6706
  
6707
21.7k
  if (hasTransparencyMask)
6708
0
    {
6709
0
    subFileCount++;
6710
0
    }
6711
  
6712
  // Add previews.
6713
  
6714
21.7k
  uint32 previewCount = previewList ? previewList->Count () : 0;
6715
  
6716
21.7k
  AutoPtr<dng_tiff_directory> previewIFD [kMaxDNGPreviews];
6717
  
6718
21.7k
  AutoPtr<dng_basic_tag_set> previewBasic [kMaxDNGPreviews];
6719
  
6720
28.4k
  for (j = 0; j < previewCount; j++)
6721
6.67k
    {
6722
    
6723
6.67k
    if (thumbnail != &previewList->Preview (j))
6724
1.44k
      {
6725
    
6726
1.44k
      previewIFD [j] . Reset (new dng_tiff_directory);
6727
      
6728
1.44k
      previewBasic [j] . Reset (previewList->Preview (j).AddTagSet (*previewIFD [j]));
6729
        
6730
1.44k
      subFileCount++;
6731
      
6732
1.44k
      }
6733
    
6734
6.67k
    }
6735
    
6736
  // And a link to the raw and JPEG image IFDs.
6737
  
6738
21.7k
  uint32 subFileData [kMaxDNGPreviews + 2];
6739
  
6740
21.7k
  tag_uint32_ptr tagSubFile (tcSubIFDs,
6741
21.7k
                 subFileData,
6742
21.7k
                 subFileCount);
6743
                 
6744
21.7k
  if (subFileCount)
6745
5.22k
    {
6746
  
6747
5.22k
    mainIFD.Add (&tagSubFile);
6748
    
6749
5.22k
    }
6750
  
6751
  // Skip past the header and IFDs for now.
6752
  
6753
21.7k
  uint32 currentOffset = 8;
6754
  
6755
21.7k
  currentOffset += mainIFD.Size ();
6756
  
6757
21.7k
  uint32 subFileIndex = 0;
6758
  
6759
21.7k
  if (thumbnail)
6760
5.22k
    {
6761
  
6762
5.22k
    subFileData [subFileIndex++] = currentOffset;
6763
  
6764
5.22k
    currentOffset += rawIFD.Size ();
6765
    
6766
5.22k
    }
6767
    
6768
21.7k
  if (hasTransparencyMask)
6769
0
    {
6770
    
6771
0
    subFileData [subFileIndex++] = currentOffset;
6772
    
6773
0
    currentOffset += maskIFD->Size ();
6774
    
6775
0
    }
6776
  
6777
28.4k
  for (j = 0; j < previewCount; j++)
6778
6.67k
    {
6779
    
6780
6.67k
    if (thumbnail != &previewList->Preview (j))
6781
1.44k
      {
6782
  
6783
1.44k
      subFileData [subFileIndex++] = currentOffset;
6784
6785
1.44k
      currentOffset += previewIFD [j]->Size ();
6786
      
6787
1.44k
      }
6788
    
6789
6.67k
    }
6790
    
6791
21.7k
  exifSet.Locate (currentOffset);
6792
  
6793
21.7k
  currentOffset += exifSet.Size ();
6794
  
6795
21.7k
  stream.SetWritePosition (currentOffset);
6796
  
6797
  // Write the extra profiles.
6798
  
6799
21.7k
  if (extraProfileCount)
6800
1.43k
    {
6801
    
6802
57.6k
    for (j = 0; j < extraProfileCount; j++)
6803
56.2k
      {
6804
      
6805
56.2k
      extraProfileOffsets.Buffer_uint32 () [j] = (uint32) stream.Position ();
6806
      
6807
56.2k
      uint32 index = extraProfileIndex [j];
6808
      
6809
56.2k
      const dng_camera_profile &profile (negative.ProfileByIndex (index));
6810
      
6811
56.2k
      tiff_dng_extended_color_profile extraWriter (profile);
6812
      
6813
56.2k
      extraWriter.Put (stream, false);
6814
      
6815
56.2k
      }
6816
    
6817
1.43k
    }
6818
  
6819
  // Write the thumbnail data.
6820
  
6821
21.7k
  if (thumbnail)
6822
5.22k
    {
6823
  
6824
5.22k
    thumbnail->WriteData (host,
6825
5.22k
                *this,
6826
5.22k
                *thmBasic,
6827
5.22k
                stream);
6828
               
6829
5.22k
    }
6830
  
6831
  // Write the preview data.
6832
  
6833
28.4k
  for (j = 0; j < previewCount; j++)
6834
6.67k
    {
6835
    
6836
6.67k
    if (thumbnail != &previewList->Preview (j))
6837
1.44k
      {
6838
  
6839
1.44k
      previewList->Preview (j).WriteData (host,
6840
1.44k
                        *this,
6841
1.44k
                        *previewBasic [j],
6842
1.44k
                        stream);
6843
                        
6844
1.44k
      }
6845
      
6846
6.67k
    }
6847
    
6848
  // Write the raw data.
6849
  
6850
21.7k
  if (rawJPEGImage)
6851
5.61k
    {
6852
    
6853
5.61k
    uint32 tileCount = info.TilesAcross () *
6854
5.61k
               info.TilesDown   ();
6855
              
6856
22.4k
    for (uint32 tileIndex = 0; tileIndex < tileCount; tileIndex++)
6857
16.8k
      {
6858
      
6859
      // Remember this offset.
6860
      
6861
16.8k
      uint32 tileOffset = (uint32) stream.Position ();
6862
    
6863
16.8k
      rawBasic.SetTileOffset (tileIndex, tileOffset);
6864
      
6865
      // Write JPEG data.
6866
      
6867
16.8k
      stream.Put (rawJPEGImage->fJPEGData [tileIndex]->Buffer      (),
6868
16.8k
            rawJPEGImage->fJPEGData [tileIndex]->LogicalSize ());
6869
              
6870
      // Update tile count.
6871
        
6872
16.8k
      uint32 tileByteCount = (uint32) stream.Position () - tileOffset;
6873
        
6874
16.8k
      rawBasic.SetTileByteCount (tileIndex, tileByteCount);
6875
      
6876
      // Keep the tiles on even byte offsets.
6877
                         
6878
16.8k
      if (tileByteCount & 1)
6879
9.82k
        {
6880
9.82k
        stream.Put_uint8 (0);
6881
9.82k
        }
6882
6883
16.8k
      }
6884
    
6885
5.61k
    }
6886
    
6887
16.1k
  else
6888
16.1k
    {
6889
    
6890
    #if qDNGValidate
6891
    dng_timer timer ("Write raw image time");
6892
    #endif
6893
  
6894
16.1k
    WriteImage (host,
6895
16.1k
          info,
6896
16.1k
          rawBasic,
6897
16.1k
          stream,
6898
16.1k
          rawImage,
6899
16.1k
          fakeChannels);
6900
          
6901
16.1k
    }
6902
    
6903
  // Write transparency mask image.
6904
  
6905
21.7k
  if (hasTransparencyMask)
6906
0
    {
6907
    
6908
    #if qDNGValidate
6909
    dng_timer timer ("Write transparency mask time");
6910
    #endif
6911
  
6912
0
    WriteImage (host,
6913
0
          *maskInfo,
6914
0
          *maskBasic,
6915
0
          stream,
6916
0
          *negative.RawTransparencyMask ());
6917
          
6918
0
    }
6919
          
6920
  // Trim the file to this length.
6921
  
6922
21.7k
  stream.SetLength (stream.Position ());
6923
  
6924
  // DNG has a 4G size limit.
6925
  
6926
21.7k
  if (stream.Length () > 0x0FFFFFFFFL)
6927
0
    {
6928
0
    ThrowImageTooBigDNG ();
6929
0
    }
6930
  
6931
  // Write TIFF Header.
6932
  
6933
21.7k
  stream.SetWritePosition (0);
6934
  
6935
21.7k
  stream.Put_uint16 (stream.BigEndian () ? byteOrderMM : byteOrderII);
6936
  
6937
21.7k
  stream.Put_uint16 (42);
6938
  
6939
21.7k
  stream.Put_uint32 (8);
6940
  
6941
  // Write the IFDs.
6942
  
6943
21.7k
  mainIFD.Put (stream);
6944
  
6945
21.7k
  if (thumbnail)
6946
5.22k
    {
6947
  
6948
5.22k
    rawIFD.Put (stream);
6949
    
6950
5.22k
    }
6951
  
6952
21.7k
  if (hasTransparencyMask)
6953
0
    {
6954
    
6955
0
    maskIFD->Put (stream);
6956
    
6957
0
    }
6958
    
6959
28.4k
  for (j = 0; j < previewCount; j++)
6960
6.67k
    {
6961
    
6962
6.67k
    if (thumbnail != &previewList->Preview (j))
6963
1.44k
      {
6964
  
6965
1.44k
      previewIFD [j]->Put (stream);
6966
      
6967
1.44k
      }
6968
    
6969
6.67k
    }
6970
    
6971
21.7k
  exifSet.Put (stream);
6972
  
6973
21.7k
  stream.Flush ();
6974
  
6975
21.7k
  }
6976
                 
6977
/*****************************************************************************/