Coverage Report

Created: 2026-01-09 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dng_sdk/source/dng_exif.cpp
Line
Count
Source
1
/*****************************************************************************/
2
// Copyright 2006-2008 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_exif.cpp#1 $ */ 
10
/* $DateTime: 2012/05/30 13:28:51 $ */
11
/* $Change: 832332 $ */
12
/* $Author: tknoll $ */
13
14
/*****************************************************************************/
15
16
#include "dng_exif.h"
17
18
#include "dng_tag_codes.h"
19
#include "dng_tag_types.h"
20
#include "dng_parse_utils.h"
21
#include "dng_globals.h"
22
#include "dng_exceptions.h"
23
#include "dng_tag_values.h"
24
#include "dng_utils.h"
25
26
/*****************************************************************************/
27
28
dng_exif::dng_exif ()
29
30
310k
  : fImageDescription ()
31
310k
  , fMake             ()
32
310k
  , fModel            ()
33
310k
  , fSoftware         ()
34
310k
  , fArtist           ()
35
310k
  , fCopyright        ()
36
310k
  , fCopyright2       ()
37
310k
  , fUserComment      ()
38
39
310k
  , fDateTime            ()
40
310k
  , fDateTimeStorageInfo ()
41
  
42
310k
  , fDateTimeOriginal  ()
43
310k
  , fDateTimeOriginalStorageInfo ()
44
  
45
310k
  , fDateTimeDigitized ()
46
310k
  , fDateTimeDigitizedStorageInfo ()
47
    
48
310k
  , fTIFF_EP_StandardID (0)
49
310k
  , fExifVersion        (0)
50
310k
  , fFlashPixVersion  (0)
51
  
52
310k
  , fExposureTime      ()
53
310k
  , fFNumber           ()
54
310k
  , fShutterSpeedValue ()
55
310k
  , fApertureValue     ()
56
310k
  , fBrightnessValue   ()
57
310k
  , fExposureBiasValue ()
58
310k
  , fMaxApertureValue  ()
59
310k
  , fFocalLength       ()
60
310k
  , fDigitalZoomRatio  ()
61
310k
  , fExposureIndex     ()
62
310k
  , fSubjectDistance   ()
63
310k
  , fGamma             ()
64
    
65
310k
  , fBatteryLevelR ()
66
310k
  , fBatteryLevelA ()
67
    
68
310k
  , fExposureProgram      (0xFFFFFFFF)
69
310k
  , fMeteringMode         (0xFFFFFFFF)
70
310k
  , fLightSource          (0xFFFFFFFF)
71
310k
  , fFlash            (0xFFFFFFFF)
72
310k
  , fFlashMask        (0x0000FFFF)
73
310k
  , fSensingMethod        (0xFFFFFFFF)
74
310k
  , fColorSpace           (0xFFFFFFFF)
75
310k
  , fFileSource           (0xFFFFFFFF)
76
310k
  , fSceneType          (0xFFFFFFFF)
77
310k
  , fCustomRendered       (0xFFFFFFFF)
78
310k
  , fExposureMode       (0xFFFFFFFF)
79
310k
  , fWhiteBalance         (0xFFFFFFFF)
80
310k
  , fSceneCaptureType     (0xFFFFFFFF)
81
310k
  , fGainControl      (0xFFFFFFFF)
82
310k
  , fContrast         (0xFFFFFFFF)
83
310k
  , fSaturation       (0xFFFFFFFF)
84
310k
  , fSharpness        (0xFFFFFFFF)
85
310k
  , fSubjectDistanceRange (0xFFFFFFFF)
86
310k
  , fSelfTimerMode      (0xFFFFFFFF)
87
310k
  , fImageNumber      (0xFFFFFFFF)
88
  
89
310k
  , fFocalLengthIn35mmFilm (0)
90
91
310k
  , fSensitivityType       (0)
92
310k
  , fStandardOutputSensitivity (0)
93
310k
  , fRecommendedExposureIndex  (0)
94
310k
  , fISOSpeed          (0)
95
310k
  , fISOSpeedLatitudeyyy     (0)
96
310k
  , fISOSpeedLatitudezzz     (0)
97
98
310k
  , fSubjectAreaCount (0)
99
  
100
310k
  , fComponentsConfiguration (0)
101
  
102
310k
  , fCompresssedBitsPerPixel ()
103
  
104
310k
  , fPixelXDimension (0)
105
310k
  , fPixelYDimension (0)
106
  
107
310k
  , fFocalPlaneXResolution ()
108
310k
  , fFocalPlaneYResolution ()
109
    
110
310k
  , fFocalPlaneResolutionUnit (0xFFFFFFFF)
111
  
112
310k
  , fCFARepeatPatternRows (0)
113
310k
  , fCFARepeatPatternCols (0)
114
  
115
310k
  , fImageUniqueID ()
116
  
117
310k
  , fGPSVersionID     (0)
118
310k
  , fGPSLatitudeRef     ()
119
310k
  , fGPSLongitudeRef    ()
120
310k
  , fGPSAltitudeRef     (0xFFFFFFFF)
121
310k
  , fGPSAltitude      ()
122
310k
  , fGPSSatellites      ()
123
310k
  , fGPSStatus        ()
124
310k
  , fGPSMeasureMode     ()
125
310k
  , fGPSDOP         ()
126
310k
  , fGPSSpeedRef      ()
127
310k
  , fGPSSpeed       ()
128
310k
  , fGPSTrackRef      ()
129
310k
  , fGPSTrack       ()
130
310k
  , fGPSImgDirectionRef   ()
131
310k
  , fGPSImgDirection    ()
132
310k
  , fGPSMapDatum      ()
133
310k
  , fGPSDestLatitudeRef   ()
134
310k
  , fGPSDestLongitudeRef  ()
135
310k
  , fGPSDestBearingRef    ()
136
310k
  , fGPSDestBearing     ()
137
310k
  , fGPSDestDistanceRef   ()
138
310k
  , fGPSDestDistance    ()
139
310k
  , fGPSProcessingMethod  ()
140
310k
  , fGPSAreaInformation   ()
141
310k
  , fGPSDateStamp     ()
142
310k
  , fGPSDifferential    (0xFFFFFFFF)
143
310k
  , fGPSHPositioningError ()
144
  
145
310k
  , fInteroperabilityIndex ()
146
147
310k
  , fInteroperabilityVersion (0)
148
  
149
310k
  , fRelatedImageFileFormat ()
150
  
151
310k
  , fRelatedImageWidth  (0)
152
310k
  , fRelatedImageLength (0)
153
  
154
310k
  , fCameraSerialNumber ()
155
  
156
310k
  , fLensID       ()
157
310k
  , fLensMake     ()
158
310k
  , fLensName     ()
159
310k
  , fLensSerialNumber ()
160
  
161
310k
  , fLensNameWasReadFromExif (false)
162
163
310k
  , fApproxFocusDistance ()
164
165
310k
  , fFlashCompensation ()
166
  
167
310k
  , fOwnerName ()
168
310k
  , fFirmware  ()
169
  
170
310k
  {
171
  
172
310k
  uint32 j;
173
310k
  uint32 k;
174
  
175
310k
  fISOSpeedRatings [0] = 0;
176
310k
  fISOSpeedRatings [1] = 0;
177
310k
  fISOSpeedRatings [2] = 0;
178
  
179
2.79M
  for (j = 0; j < kMaxCFAPattern; j++)
180
22.3M
    for (k = 0; k < kMaxCFAPattern; k++)
181
19.8M
      {
182
19.8M
      fCFAPattern [j] [k] = 255;
183
19.8M
      }
184
    
185
310k
  }
186
  
187
/*****************************************************************************/
188
189
dng_exif::~dng_exif ()
190
407k
  {
191
  
192
407k
  }
193
    
194
/*****************************************************************************/
195
196
dng_exif * dng_exif::Clone () const
197
91.9k
  {
198
  
199
91.9k
  dng_exif *result = new dng_exif (*this);
200
  
201
91.9k
  if (!result)
202
0
    {
203
0
    ThrowMemoryFull ();
204
0
    }
205
  
206
91.9k
  return result;
207
  
208
91.9k
  }
209
    
210
/*****************************************************************************/
211
212
void dng_exif::SetEmpty ()
213
0
  {
214
  
215
0
  *this = dng_exif ();
216
  
217
0
  }
218
    
219
/*****************************************************************************/
220
221
void dng_exif::CopyGPSFrom (const dng_exif &exif)
222
0
  {
223
      
224
0
  fGPSVersionID         = exif.fGPSVersionID;
225
0
  fGPSLatitudeRef       = exif.fGPSLatitudeRef;
226
0
  fGPSLatitude [0]    = exif.fGPSLatitude [0];
227
0
  fGPSLatitude [1]    = exif.fGPSLatitude [1];
228
0
  fGPSLatitude [2]    = exif.fGPSLatitude [2];
229
0
  fGPSLongitudeRef      = exif.fGPSLongitudeRef;
230
0
  fGPSLongitude [0]   = exif.fGPSLongitude [0];
231
0
  fGPSLongitude [1]   = exif.fGPSLongitude [1];
232
0
  fGPSLongitude [2]   = exif.fGPSLongitude [2];
233
0
  fGPSAltitudeRef       = exif.fGPSAltitudeRef;
234
0
  fGPSAltitude          = exif.fGPSAltitude;
235
0
  fGPSTimeStamp [0]     = exif.fGPSTimeStamp [0];
236
0
  fGPSTimeStamp [1]     = exif.fGPSTimeStamp [1];
237
0
  fGPSTimeStamp [2]     = exif.fGPSTimeStamp [2];
238
0
  fGPSSatellites        = exif.fGPSSatellites;
239
0
  fGPSStatus            = exif.fGPSStatus;
240
0
  fGPSMeasureMode       = exif.fGPSMeasureMode;
241
0
  fGPSDOP               = exif.fGPSDOP;
242
0
  fGPSSpeedRef          = exif.fGPSSpeedRef;
243
0
  fGPSSpeed             = exif.fGPSSpeed;
244
0
  fGPSTrackRef          = exif.fGPSTrackRef;
245
0
  fGPSTrack             = exif.fGPSTrack;
246
0
  fGPSImgDirectionRef   = exif.fGPSImgDirectionRef;
247
0
  fGPSImgDirection      = exif.fGPSImgDirection;
248
0
  fGPSMapDatum          = exif.fGPSMapDatum;
249
0
  fGPSDestLatitudeRef   = exif.fGPSDestLatitudeRef;
250
0
  fGPSDestLatitude [0]  = exif.fGPSDestLatitude [0];
251
0
  fGPSDestLatitude [1]  = exif.fGPSDestLatitude [1];
252
0
  fGPSDestLatitude [2]  = exif.fGPSDestLatitude [2];
253
0
  fGPSDestLongitudeRef  = exif.fGPSDestLongitudeRef;
254
0
  fGPSDestLongitude [0] = exif.fGPSDestLongitude [0];
255
0
  fGPSDestLongitude [1] = exif.fGPSDestLongitude [1];
256
0
  fGPSDestLongitude [2] = exif.fGPSDestLongitude [2];
257
0
  fGPSDestBearingRef    = exif.fGPSDestBearingRef;
258
0
  fGPSDestBearing       = exif.fGPSDestBearing;
259
0
  fGPSDestDistanceRef   = exif.fGPSDestDistanceRef;
260
0
  fGPSDestDistance      = exif.fGPSDestDistance;
261
0
  fGPSProcessingMethod  = exif.fGPSProcessingMethod;
262
0
  fGPSAreaInformation   = exif.fGPSAreaInformation;
263
0
  fGPSDateStamp         = exif.fGPSDateStamp;
264
0
  fGPSDifferential      = exif.fGPSDifferential;
265
0
  fGPSHPositioningError = exif.fGPSHPositioningError;
266
267
0
  }
268
269
/*****************************************************************************/
270
271
// Fix up common errors and rounding issues with EXIF exposure times.
272
  
273
real64 dng_exif::SnapExposureTime (real64 et)
274
23.2k
  {
275
  
276
  // Protection against invalid values.
277
  
278
23.2k
  if (et <= 0.0)
279
7.04k
    return 0.0;
280
  
281
  // If near a standard shutter speed, snap to it.
282
  
283
16.2k
  static const real64 kStandardSpeed [] =
284
16.2k
    {
285
16.2k
    30.0,
286
16.2k
    25.0,
287
16.2k
    20.0,
288
16.2k
    15.0,
289
16.2k
    13.0,
290
16.2k
    10.0,
291
16.2k
    8.0,
292
16.2k
    6.0,
293
16.2k
    5.0,
294
16.2k
    4.0,
295
16.2k
    3.2,
296
16.2k
    3.0,
297
16.2k
    2.5,
298
16.2k
    2.0,
299
16.2k
    1.6,
300
16.2k
    1.5,
301
16.2k
    1.3,
302
16.2k
    1.0,
303
16.2k
    0.8,
304
16.2k
    0.7,
305
16.2k
    0.6,
306
16.2k
    0.5,
307
16.2k
    0.4,
308
16.2k
    0.3,
309
16.2k
    1.0 / 4.0,
310
16.2k
    1.0 / 5.0,
311
16.2k
    1.0 / 6.0,
312
16.2k
    1.0 / 8.0,
313
16.2k
    1.0 / 10.0,
314
16.2k
    1.0 / 13.0,
315
16.2k
    1.0 / 15.0,
316
16.2k
    1.0 / 20.0,
317
16.2k
    1.0 / 25.0,
318
16.2k
    1.0 / 30.0,
319
16.2k
    1.0 / 40.0,
320
16.2k
    1.0 / 45.0,
321
16.2k
    1.0 / 50.0,
322
16.2k
    1.0 / 60.0,
323
16.2k
    1.0 / 80.0,
324
16.2k
    1.0 / 90.0,
325
16.2k
    1.0 / 100.0,
326
16.2k
    1.0 / 125.0,
327
16.2k
    1.0 / 160.0,
328
16.2k
    1.0 / 180.0,
329
16.2k
    1.0 / 200.0,
330
16.2k
    1.0 / 250.0,
331
16.2k
    1.0 / 320.0,
332
16.2k
    1.0 / 350.0,
333
16.2k
    1.0 / 400.0,
334
16.2k
    1.0 / 500.0,
335
16.2k
    1.0 / 640.0,
336
16.2k
    1.0 / 750.0,
337
16.2k
    1.0 / 800.0,
338
16.2k
    1.0 / 1000.0,
339
16.2k
    1.0 / 1250.0,
340
16.2k
    1.0 / 1500.0,
341
16.2k
    1.0 / 1600.0,
342
16.2k
    1.0 / 2000.0,
343
16.2k
    1.0 / 2500.0,
344
16.2k
    1.0 / 3000.0,
345
16.2k
    1.0 / 3200.0,
346
16.2k
    1.0 / 4000.0,
347
16.2k
    1.0 / 5000.0,
348
16.2k
    1.0 / 6000.0,
349
16.2k
    1.0 / 6400.0,
350
16.2k
    1.0 / 8000.0,
351
16.2k
    1.0 / 10000.0,
352
16.2k
    1.0 / 12000.0,
353
16.2k
    1.0 / 12800.0,
354
16.2k
    1.0 / 16000.0
355
16.2k
    };
356
    
357
16.2k
  uint32 count = sizeof (kStandardSpeed    ) /
358
16.2k
           sizeof (kStandardSpeed [0]);
359
             
360
33.2k
  for (uint32 fudge = 0; fudge <= 1; fudge++)
361
28.5k
    {
362
    
363
28.5k
    real64 testSpeed = et;
364
    
365
28.5k
    if (fudge == 1)
366
12.2k
      {
367
      
368
      // Often APEX values are rounded to a power of two,
369
      // which results in non-standard shutter speeds.
370
      
371
12.2k
      if (et >= 0.1)
372
6.99k
        {
373
        
374
        // No fudging slower than 1/10 second
375
        
376
6.99k
        break;
377
        
378
6.99k
        }
379
      
380
5.27k
      else if (et >= 0.01)
381
1.10k
        {
382
        
383
        // Between 1/10 and 1/100 the commonly misrounded
384
        // speeds are 1/15, 1/30, 1/60, which are often encoded as
385
        // 1/16, 1/32, 1/64.  Try fudging and see if we get
386
        // near a standard speed.
387
        
388
1.10k
        testSpeed *= 16.0 / 15.0;
389
        
390
1.10k
        }
391
        
392
4.17k
      else
393
4.17k
        {
394
        
395
        // Faster than 1/100, the commonly misrounded
396
        // speeds are 1/125, 1/250, 1/500, etc., which
397
        // are often encoded as 1/128, 1/256, 1/512.
398
        
399
4.17k
        testSpeed *= 128.0 / 125.0;
400
        
401
4.17k
        }
402
      
403
12.2k
      }
404
      
405
1.31M
    for (uint32 index = 0; index < count; index++)
406
1.29M
      {
407
      
408
1.29M
      if (testSpeed >= kStandardSpeed [index] * 0.98 &&
409
566k
        testSpeed <= kStandardSpeed [index] * 1.02)
410
4.48k
        {
411
        
412
4.48k
        return kStandardSpeed [index];
413
        
414
4.48k
        }
415
        
416
1.29M
      }
417
      
418
21.5k
    }
419
    
420
  // We are not near any standard speeds.  Round the non-standard value to something
421
  // that looks reasonable.
422
  
423
11.7k
  if (et >= 10.0)
424
3.58k
    {
425
    
426
    // Round to nearest second.
427
    
428
3.58k
    et = floor (et + 0.5);
429
    
430
3.58k
    }
431
    
432
8.17k
  else if (et >= 0.5)
433
1.39k
    {
434
    
435
    // Round to nearest 1/10 second
436
    
437
1.39k
    et = floor (et * 10.0 + 0.5) * 0.1;
438
    
439
1.39k
    }
440
    
441
6.78k
  else if (et >= 1.0 / 20.0)
442
2.09k
    {
443
    
444
    // Round to an exact inverse.
445
    
446
2.09k
    et = 1.0 / floor (1.0 / et + 0.5);
447
    
448
2.09k
    }
449
    
450
4.68k
  else if (et >= 1.0 / 130.0)
451
621
    {
452
    
453
    // Round inverse to multiple of 5
454
    
455
621
    et = 0.2 / floor (0.2 / et + 0.5);
456
    
457
621
    }
458
    
459
4.06k
  else if (et >= 1.0 / 750.0)
460
1.04k
    {
461
    
462
    // Round inverse to multiple of 10
463
    
464
1.04k
    et = 0.1 / floor (0.1 / et + 0.5);
465
    
466
1.04k
    }
467
    
468
3.02k
  else if (et >= 1.0 / 1300.0)
469
668
    {
470
    
471
    // Round inverse to multiple of 50
472
    
473
668
    et = 0.02 / floor (0.02 / et + 0.5);
474
    
475
668
    }
476
    
477
2.36k
  else if (et >= 1.0 / 15000.0)
478
575
    {
479
    
480
    // Round inverse to multiple of 100
481
    
482
575
    et = 0.01 / floor (0.01 / et + 0.5);
483
    
484
575
    }
485
    
486
1.78k
  else
487
1.78k
    {
488
    
489
    // Round inverse to multiple of 1000
490
    
491
1.78k
    et = 0.001 / floor (0.001 / et + 0.5);
492
    
493
1.78k
    }
494
    
495
11.7k
  return et;
496
  
497
16.2k
  }
498
499
/*****************************************************************************/
500
501
void dng_exif::SetExposureTime (real64 et, bool snap)
502
23.2k
  {
503
  
504
23.2k
  fExposureTime.Clear ();
505
  
506
23.2k
  fShutterSpeedValue.Clear ();
507
  
508
23.2k
  if (snap)
509
23.2k
    {
510
    
511
23.2k
    et = SnapExposureTime (et);
512
    
513
23.2k
    }
514
    
515
23.2k
  if (et >= 1.0 / 32768.0 && et <= 32768.0)
516
12.8k
    {
517
    
518
12.8k
    if (et >= 100.0)
519
1.21k
      {
520
      
521
1.21k
      fExposureTime.Set_real64 (et, 1);
522
      
523
1.21k
      }
524
      
525
11.6k
    else if (et >= 1.0)
526
3.95k
      {
527
      
528
3.95k
      fExposureTime.Set_real64 (et, 10);
529
      
530
3.95k
      fExposureTime.ReduceByFactor (10);
531
      
532
3.95k
      }
533
      
534
7.66k
    else if (et <= 0.1)
535
3.91k
      {
536
      
537
3.91k
      fExposureTime = dng_urational (1, Round_uint32 (1.0 / et));
538
      
539
3.91k
      }
540
      
541
3.74k
    else
542
3.74k
      {
543
      
544
3.74k
      fExposureTime.Set_real64 (et, 100);
545
      
546
3.74k
      fExposureTime.ReduceByFactor (10);
547
        
548
17.1k
      for (uint32 f = 2; f <= 9; f++)
549
16.1k
        {
550
        
551
16.1k
        real64 z = 1.0 / (real64) f / et;
552
        
553
16.1k
        if (z >= 0.99 && z <= 1.01)
554
2.76k
          {
555
          
556
2.76k
          fExposureTime = dng_urational (1, f);
557
          
558
2.76k
          break;
559
          
560
2.76k
          }
561
        
562
16.1k
        }
563
          
564
3.74k
      }
565
    
566
    // Now mirror this value to the ShutterSpeedValue field.
567
    
568
12.8k
    et = fExposureTime.As_real64 ();
569
    
570
12.8k
    fShutterSpeedValue.Set_real64 (-log (et) / log (2.0), 1000000);
571
                        
572
12.8k
    fShutterSpeedValue.ReduceByFactor (10);                 
573
12.8k
    fShutterSpeedValue.ReduceByFactor (10);                 
574
12.8k
    fShutterSpeedValue.ReduceByFactor (10);                 
575
12.8k
    fShutterSpeedValue.ReduceByFactor (10);                 
576
12.8k
    fShutterSpeedValue.ReduceByFactor (10);                 
577
12.8k
    fShutterSpeedValue.ReduceByFactor (10);                 
578
579
12.8k
    }
580
    
581
23.2k
  }
582
583
/*****************************************************************************/
584
585
void dng_exif::SetShutterSpeedValue (real64 ss)
586
6.64k
  {
587
  
588
6.64k
  if (fExposureTime.NotValid ())
589
4.00k
    {
590
    
591
4.00k
    real64 et = pow (2.0, -ss);
592
    
593
4.00k
    SetExposureTime (et, true);
594
    
595
4.00k
    }
596
  
597
6.64k
  }
598
599
/******************************************************************************/
600
601
dng_urational dng_exif::EncodeFNumber (real64 fs)
602
10.7k
  {
603
  
604
10.7k
  dng_urational y;
605
606
10.7k
  if (fs > 10.0)
607
2.28k
    {
608
    
609
2.28k
    y.Set_real64 (fs, 1);
610
    
611
2.28k
    }
612
    
613
8.42k
  else if (fs < 1.0)
614
4.11k
    {
615
    
616
4.11k
    y.Set_real64 (fs, 100);
617
    
618
4.11k
    y.ReduceByFactor (10);
619
4.11k
    y.ReduceByFactor (10);
620
    
621
4.11k
    }
622
    
623
4.30k
  else
624
4.30k
    {
625
    
626
4.30k
    y.Set_real64 (fs, 10);
627
    
628
4.30k
    y.ReduceByFactor (10);
629
    
630
4.30k
    }
631
    
632
10.7k
  return y;
633
      
634
10.7k
  }
635
    
636
/*****************************************************************************/
637
638
void dng_exif::SetFNumber (real64 fs)
639
15.8k
  {
640
  
641
15.8k
  fFNumber.Clear ();
642
  
643
15.8k
  fApertureValue.Clear ();
644
645
  // Allow f-number values less than 1.0 (e.g., f/0.95), even though they would
646
  // correspond to negative APEX values, which the EXIF specification does not
647
  // support (ApertureValue is a rational, not srational). The ApertureValue tag
648
  // will be omitted in the case where fs < 1.0.
649
  
650
15.8k
  if (fs > 0.0 && fs <= 32768.0)
651
10.7k
    {
652
  
653
10.7k
    fFNumber = EncodeFNumber (fs);
654
    
655
    // Now mirror this value to the ApertureValue field.
656
    
657
10.7k
    real64 av = FNumberToApertureValue (fFNumber);
658
659
10.7k
    if (av >= 0.0 && av <= 99.99)
660
6.86k
      {
661
      
662
6.86k
      fApertureValue.Set_real64 (av, 1000000);
663
      
664
6.86k
      fApertureValue.ReduceByFactor (10);                 
665
6.86k
      fApertureValue.ReduceByFactor (10);                 
666
6.86k
      fApertureValue.ReduceByFactor (10);                 
667
6.86k
      fApertureValue.ReduceByFactor (10);                 
668
6.86k
      fApertureValue.ReduceByFactor (10);                 
669
6.86k
      fApertureValue.ReduceByFactor (10);                 
670
      
671
6.86k
      }
672
    
673
10.7k
    }
674
  
675
15.8k
  }
676
      
677
/*****************************************************************************/
678
679
void dng_exif::SetApertureValue (real64 av)
680
5.39k
  {
681
682
5.39k
  if (fFNumber.NotValid ())
683
2.47k
    {
684
    
685
2.47k
    SetFNumber (ApertureValueToFNumber (av));
686
            
687
2.47k
    }
688
    
689
5.39k
  }
690
691
/*****************************************************************************/
692
693
real64 dng_exif::ApertureValueToFNumber (real64 av)
694
2.47k
  {
695
  
696
2.47k
  return pow (2.0, 0.5 * av);
697
  
698
2.47k
  }
699
700
/*****************************************************************************/
701
702
real64 dng_exif::ApertureValueToFNumber (const dng_urational &av)
703
0
  {
704
  
705
0
  return ApertureValueToFNumber (av.As_real64 ());
706
  
707
0
  }
708
709
/*****************************************************************************/
710
711
real64 dng_exif::FNumberToApertureValue (real64 fNumber)
712
10.7k
  {
713
  
714
10.7k
  return 2.0 * log (fNumber) / log (2.0);
715
  
716
10.7k
  }
717
718
/*****************************************************************************/
719
720
real64 dng_exif::FNumberToApertureValue (const dng_urational &fNumber)
721
10.7k
  {
722
  
723
10.7k
  return FNumberToApertureValue (fNumber.As_real64 ());
724
  
725
10.7k
  }
726
      
727
/*****************************************************************************/
728
729
void dng_exif::UpdateDateTime (const dng_date_time_info &dt)
730
0
  {
731
  
732
0
  fDateTime = dt;
733
  
734
0
  }
735
736
/*****************************************************************************/
737
738
bool dng_exif::AtLeastVersion0230 () const
739
202k
  {
740
  
741
202k
  uint32 b0 = (fExifVersion >> 24) & 0xff;
742
202k
  uint32 b1 = (fExifVersion >> 16) & 0xff;
743
202k
  uint32 b2 = (fExifVersion >>  8) & 0xff;
744
745
202k
  return (b0 > 0) || (b1 >= 2 && b2 >= 3);
746
  
747
202k
  }
748
    
749
/*****************************************************************************/
750
751
bool dng_exif::ParseTag (dng_stream &stream,
752
             dng_shared &shared,
753
             uint32 parentCode,
754
             bool isMainIFD,
755
             uint32 tagCode,
756
             uint32 tagType,
757
             uint32 tagCount,
758
             uint64 tagOffset)
759
3.42M
  {
760
  
761
3.42M
  if (parentCode == 0)
762
1.74M
    {
763
    
764
1.74M
    if (Parse_ifd0 (stream,
765
1.74M
            shared,
766
1.74M
            parentCode,
767
1.74M
            tagCode,
768
1.74M
            tagType,
769
1.74M
            tagCount,
770
1.74M
            tagOffset))
771
146k
      {
772
      
773
146k
      return true;
774
      
775
146k
      }
776
777
1.74M
    }
778
    
779
3.28M
  if (parentCode == 0 || isMainIFD)
780
1.87M
    {
781
    
782
1.87M
    if (Parse_ifd0_main (stream,
783
1.87M
                 shared,
784
1.87M
               parentCode,
785
1.87M
               tagCode,
786
1.87M
               tagType,
787
1.87M
               tagCount,
788
1.87M
               tagOffset))
789
10.5k
      {
790
      
791
10.5k
      return true;
792
      
793
10.5k
      }
794
795
1.87M
    }
796
    
797
3.27M
  if (parentCode == 0 ||
798
1.68M
    parentCode == tcExifIFD)
799
1.73M
    {
800
    
801
1.73M
    if (Parse_ifd0_exif (stream,
802
1.73M
                 shared,
803
1.73M
               parentCode,
804
1.73M
               tagCode,
805
1.73M
               tagType,
806
1.73M
               tagCount,
807
1.73M
               tagOffset))
808
298k
      {
809
      
810
298k
      return true;
811
      
812
298k
      }
813
814
1.73M
    }
815
    
816
2.97M
  if (parentCode == tcGPSInfo)
817
220k
    {
818
    
819
220k
    if (Parse_gps (stream,
820
220k
             shared,
821
220k
             parentCode,
822
220k
             tagCode,
823
220k
             tagType,
824
220k
             tagCount,
825
220k
             tagOffset))
826
53.5k
      {
827
      
828
53.5k
      return true;
829
      
830
53.5k
      }
831
832
220k
    }
833
    
834
2.92M
  if (parentCode == tcInteroperabilityIFD)
835
1.83k
    {
836
    
837
1.83k
    if (Parse_interoperability (stream,
838
1.83k
                    shared,
839
1.83k
                  parentCode,
840
1.83k
                  tagCode,
841
1.83k
                  tagType,
842
1.83k
                  tagCount,
843
1.83k
                  tagOffset))
844
848
      {
845
      
846
848
      return true;
847
      
848
848
      }
849
850
1.83k
    }
851
    
852
2.91M
  return false;
853
    
854
2.92M
  }
855
856
/*****************************************************************************/
857
858
// Parses tags that should only appear in IFD 0.
859
860
bool dng_exif::Parse_ifd0 (dng_stream &stream,
861
                 dng_shared & /* shared */,
862
               uint32 parentCode,
863
               uint32 tagCode,
864
               uint32 tagType,
865
               uint32 tagCount,
866
               uint64 /* tagOffset */)
867
1.74M
  {
868
  
869
1.74M
  switch (tagCode)
870
1.74M
    {
871
      
872
2.39k
    case tcImageDescription:
873
2.39k
      {
874
      
875
2.39k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
876
      
877
2.39k
      ParseStringTag (stream,
878
2.39k
              parentCode,
879
2.39k
              tagCode,
880
2.39k
              tagCount,
881
2.39k
              fImageDescription);
882
              
883
      #if qDNGValidate
884
      
885
      if (gVerbose)
886
        {
887
        
888
        printf ("ImageDescription: ");
889
        
890
        DumpString (fImageDescription);
891
        
892
        printf ("\n");
893
        
894
        }
895
        
896
      #endif
897
        
898
2.39k
      break;
899
      
900
0
      }
901
      
902
3.94k
    case tcMake:
903
3.94k
      {
904
      
905
3.94k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
906
      
907
3.94k
      ParseStringTag (stream,
908
3.94k
              parentCode,
909
3.94k
              tagCode,
910
3.94k
              tagCount,
911
3.94k
              fMake);
912
        
913
      #if qDNGValidate
914
      
915
      if (gVerbose)
916
        {
917
        
918
        printf ("Make: ");
919
        
920
        DumpString (fMake);
921
        
922
        printf ("\n");
923
        
924
        }
925
        
926
      #endif
927
      
928
3.94k
      break;
929
      
930
0
      }
931
        
932
8.11k
    case tcModel:
933
8.11k
      {
934
935
8.11k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
936
      
937
8.11k
      ParseStringTag (stream,
938
8.11k
              parentCode,
939
8.11k
              tagCode,
940
8.11k
              tagCount,
941
8.11k
              fModel);
942
      
943
      #if qDNGValidate
944
      
945
      if (gVerbose)
946
        {
947
        
948
        printf ("Model: ");
949
        
950
        DumpString (fModel);
951
        
952
        printf ("\n");
953
        
954
        }
955
        
956
      #endif
957
      
958
8.11k
      break;
959
      
960
0
      }
961
        
962
21.0k
    case tcSoftware:
963
21.0k
      {
964
      
965
21.0k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
966
      
967
21.0k
      ParseStringTag (stream,
968
21.0k
              parentCode,
969
21.0k
              tagCode,
970
21.0k
              tagCount,
971
21.0k
              fSoftware);
972
      
973
      #if qDNGValidate
974
      
975
      if (gVerbose)
976
        {
977
        
978
        printf ("Software: ");
979
        
980
        DumpString (fSoftware);
981
        
982
        printf ("\n");
983
        
984
        }
985
        
986
      #endif
987
      
988
21.0k
      break;
989
      
990
0
      }
991
992
28.5k
    case tcDateTime:
993
28.5k
      {
994
      
995
28.5k
      uint64 tagPosition = stream.PositionInOriginalFile ();
996
      
997
28.5k
      dng_date_time dt;
998
        
999
28.5k
      if (!ParseDateTimeTag (stream,
1000
28.5k
                   parentCode,
1001
28.5k
                   tagCode,
1002
28.5k
                   tagType,
1003
28.5k
                   tagCount,
1004
28.5k
                   dt))
1005
18.3k
        {
1006
18.3k
        return false;
1007
18.3k
        }
1008
        
1009
10.2k
      fDateTime.SetDateTime (dt);
1010
        
1011
10.2k
      fDateTimeStorageInfo = dng_date_time_storage_info (tagPosition,
1012
10.2k
                                 dng_date_time_format_exif);
1013
        
1014
      #if qDNGValidate
1015
      
1016
      if (gVerbose)
1017
        {
1018
        
1019
        printf ("DateTime: ");
1020
        
1021
        DumpDateTime (fDateTime.DateTime ());
1022
        
1023
        printf ("\n");
1024
        
1025
        }
1026
        
1027
      #endif
1028
1029
10.2k
      break;
1030
      
1031
28.5k
      }
1032
1033
1.58k
    case tcArtist:
1034
1.58k
      {
1035
      
1036
1.58k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
1037
      
1038
1.58k
      ParseStringTag (stream,
1039
1.58k
              parentCode,
1040
1.58k
              tagCode,
1041
1.58k
              tagCount,
1042
1.58k
              fArtist);
1043
      
1044
      #if qDNGValidate
1045
      
1046
      if (gVerbose)
1047
        {
1048
        
1049
        printf ("Artist: ");
1050
        
1051
        DumpString (fArtist);
1052
        
1053
        printf ("\n");
1054
        
1055
        }
1056
        
1057
      #endif
1058
      
1059
1.58k
      break;
1060
      
1061
28.5k
      }
1062
1063
47.9k
    case tcCopyright:
1064
47.9k
      {
1065
      
1066
47.9k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
1067
      
1068
47.9k
      ParseDualStringTag (stream,
1069
47.9k
                parentCode,
1070
47.9k
                tagCode,
1071
47.9k
                tagCount,
1072
47.9k
                fCopyright,
1073
47.9k
                fCopyright2);
1074
      
1075
      #if qDNGValidate
1076
      
1077
      if (gVerbose)
1078
        {
1079
        
1080
        printf ("Copyright: ");
1081
        
1082
        DumpString (fCopyright);
1083
        
1084
        if (fCopyright2.Get () [0] != 0)
1085
          {
1086
          
1087
          printf (" ");
1088
          
1089
          DumpString (fCopyright2);
1090
          
1091
          }
1092
        
1093
        printf ("\n");
1094
        
1095
        }
1096
        
1097
      #endif
1098
      
1099
47.9k
      break;
1100
      
1101
28.5k
      }
1102
1103
36.3k
    case tcTIFF_EP_StandardID:
1104
36.3k
      {
1105
      
1106
36.3k
      CheckTagType (parentCode, tagCode, tagType, ttByte);
1107
      
1108
36.3k
      CheckTagCount (parentCode, tagCode, tagCount, 4);
1109
      
1110
36.3k
      uint32 b0 = stream.Get_uint8 ();
1111
36.3k
      uint32 b1 = stream.Get_uint8 ();
1112
36.3k
      uint32 b2 = stream.Get_uint8 ();
1113
36.3k
      uint32 b3 = stream.Get_uint8 ();
1114
      
1115
36.3k
      fTIFF_EP_StandardID = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
1116
      
1117
      #if qDNGValidate
1118
      
1119
      if (gVerbose)
1120
        {
1121
        printf ("TIFF/EPStandardID: %u.%u.%u.%u\n",
1122
            (unsigned) b0,
1123
            (unsigned) b1, 
1124
            (unsigned) b2,
1125
            (unsigned) b3);
1126
        }
1127
        
1128
      #endif
1129
      
1130
36.3k
      break;
1131
      
1132
28.5k
      }
1133
        
1134
9.51k
    case tcCameraSerialNumber:
1135
10.0k
    case tcKodakCameraSerialNumber:   // Kodak uses a very similar tag.
1136
10.0k
      {
1137
      
1138
10.0k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
1139
      
1140
10.0k
      ParseStringTag (stream,
1141
10.0k
              parentCode,
1142
10.0k
              tagCode,
1143
10.0k
              tagCount,
1144
10.0k
              fCameraSerialNumber);
1145
        
1146
      #if qDNGValidate
1147
1148
      if (gVerbose)
1149
        {
1150
        
1151
        printf ("%s: ", LookupTagCode (parentCode, tagCode));
1152
        
1153
        DumpString (fCameraSerialNumber);
1154
        
1155
        printf ("\n");
1156
        
1157
        }
1158
        
1159
      #endif
1160
      
1161
10.0k
      break;
1162
      
1163
9.51k
      }
1164
      
1165
12.2k
    case tcLensInfo:
1166
12.2k
      {
1167
      
1168
12.2k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
1169
      
1170
12.2k
      if (!CheckTagCount (parentCode, tagCode, tagCount, 4))
1171
6.88k
        return false;
1172
        
1173
5.35k
      fLensInfo [0] = stream.TagValue_urational (tagType);
1174
5.35k
      fLensInfo [1] = stream.TagValue_urational (tagType);
1175
5.35k
      fLensInfo [2] = stream.TagValue_urational (tagType);
1176
5.35k
      fLensInfo [3] = stream.TagValue_urational (tagType);
1177
      
1178
      // Some third party software wrote zero rather and undefined values
1179
      // for unknown entries.  Work around this bug.
1180
      
1181
26.4k
      for (uint32 j = 0; j < 4; j++)
1182
21.0k
        {
1183
      
1184
21.0k
        if (fLensInfo [j].IsValid () && fLensInfo [j].As_real64 () <= 0.0)
1185
10.2k
          {
1186
          
1187
10.2k
          fLensInfo [j] = dng_urational (0, 0);
1188
          
1189
          #if qDNGValidate
1190
          
1191
          ReportWarning ("Zero entry in LensInfo tag--should be undefined");
1192
          
1193
          #endif
1194
1195
10.2k
          }
1196
          
1197
21.0k
        }
1198
        
1199
      #if qDNGValidate
1200
1201
      if (gVerbose)
1202
        {
1203
        
1204
        printf ("LensInfo: ");
1205
        
1206
        real64 minFL = fLensInfo [0].As_real64 ();
1207
        real64 maxFL = fLensInfo [1].As_real64 ();
1208
        
1209
        if (minFL == maxFL)
1210
          printf ("%0.1f mm", minFL);
1211
        else
1212
          printf ("%0.1f-%0.1f mm", minFL, maxFL);
1213
          
1214
        if (fLensInfo [2].d)
1215
          {
1216
          
1217
          real64 minFS = fLensInfo [2].As_real64 ();
1218
          real64 maxFS = fLensInfo [3].As_real64 ();
1219
          
1220
          if (minFS == maxFS)
1221
            printf (" f/%0.1f", minFS);
1222
          else
1223
            printf (" f/%0.1f-%0.1f", minFS, maxFS);
1224
          
1225
          }
1226
          
1227
        printf ("\n");
1228
        
1229
        }
1230
        
1231
      #endif
1232
      
1233
5.35k
      break;
1234
      
1235
12.2k
      }
1236
        
1237
1.56M
    default:
1238
1.56M
      {
1239
      
1240
1.56M
      return false;
1241
      
1242
12.2k
      }
1243
      
1244
1.74M
    }
1245
  
1246
146k
  return true;
1247
  
1248
1.74M
  }
1249
  
1250
/*****************************************************************************/
1251
1252
// Parses tags that should only appear in IFD 0 or the main image IFD.
1253
1254
bool dng_exif::Parse_ifd0_main (dng_stream &stream,
1255
                      dng_shared & /* shared */,
1256
                    uint32 parentCode,
1257
                    uint32 tagCode,
1258
                    uint32 tagType,
1259
                    uint32 tagCount,
1260
                    uint64 /* tagOffset */)
1261
1.87M
  {
1262
  
1263
1.87M
  switch (tagCode)
1264
1.87M
    {
1265
      
1266
4.04k
    case tcFocalPlaneXResolution:
1267
4.04k
      {
1268
1269
4.04k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
1270
      
1271
4.04k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1272
      
1273
4.04k
      fFocalPlaneXResolution = stream.TagValue_urational (tagType);
1274
      
1275
      #if qDNGValidate
1276
1277
      if (gVerbose)
1278
        {
1279
        
1280
        printf ("FocalPlaneXResolution: %0.4f\n",
1281
            fFocalPlaneXResolution.As_real64 ());
1282
            
1283
        }
1284
        
1285
      #endif
1286
      
1287
4.04k
      break;
1288
      
1289
0
      }
1290
      
1291
1.80k
    case tcFocalPlaneYResolution:
1292
1.80k
      {
1293
1294
1.80k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
1295
      
1296
1.80k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1297
      
1298
1.80k
      fFocalPlaneYResolution = stream.TagValue_urational (tagType);
1299
      
1300
      #if qDNGValidate
1301
1302
      if (gVerbose)
1303
        {
1304
        
1305
        printf ("FocalPlaneYResolution: %0.4f\n",
1306
            fFocalPlaneYResolution.As_real64 ());
1307
            
1308
        }
1309
        
1310
      #endif
1311
      
1312
1.80k
      break;
1313
      
1314
0
      }
1315
      
1316
2.55k
    case tcFocalPlaneResolutionUnit:
1317
2.55k
      {
1318
      
1319
2.55k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
1320
      
1321
2.55k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1322
      
1323
2.55k
      fFocalPlaneResolutionUnit = stream.TagValue_uint32 (tagType);
1324
      
1325
      #if qDNGValidate
1326
1327
      if (gVerbose)
1328
        {
1329
        
1330
        printf ("FocalPlaneResolutionUnit: %s\n",
1331
              LookupResolutionUnit (fFocalPlaneResolutionUnit));
1332
        
1333
        }
1334
        
1335
      #endif
1336
        
1337
2.55k
      break;
1338
      
1339
0
      }
1340
1341
2.13k
    case tcSensingMethod:
1342
2.13k
      {
1343
      
1344
2.13k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
1345
      
1346
2.13k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1347
      
1348
2.13k
      fSensingMethod = stream.TagValue_uint32 (tagType);
1349
      
1350
      #if qDNGValidate
1351
1352
      if (gVerbose)
1353
        {
1354
        
1355
        printf ("SensingMethod: %s\n",
1356
            LookupSensingMethod (fSensingMethod));
1357
1358
        }
1359
        
1360
      #endif
1361
      
1362
2.13k
      break;
1363
      
1364
0
      }
1365
      
1366
1.86M
    default:
1367
1.86M
      {
1368
      
1369
1.86M
      return false;
1370
      
1371
0
      }
1372
      
1373
1.87M
    }
1374
    
1375
10.5k
  return true;
1376
  
1377
1.87M
  }
1378
      
1379
/*****************************************************************************/
1380
1381
// Parses tags that should only appear in IFD 0 or EXIF IFD.
1382
1383
bool dng_exif::Parse_ifd0_exif (dng_stream &stream,
1384
                dng_shared & /* shared */,
1385
                    uint32 parentCode,
1386
                    uint32 tagCode,
1387
                    uint32 tagType,
1388
                    uint32 tagCount,
1389
                    uint64 /* tagOffset */)
1390
1.73M
  {
1391
  
1392
1.73M
  switch (tagCode)
1393
1.73M
    {
1394
    
1395
1.51k
    case tcBatteryLevel:
1396
1.51k
      {
1397
      
1398
1.51k
      CheckTagType (parentCode, tagCode, tagType, ttRational, ttAscii);
1399
      
1400
1.51k
      if (tagType == ttAscii)
1401
458
        {
1402
        
1403
458
        ParseStringTag (stream,
1404
458
                parentCode,
1405
458
                tagCode,
1406
458
                tagCount,
1407
458
                fBatteryLevelA);
1408
      
1409
458
        }
1410
        
1411
1.05k
      else
1412
1.05k
        {
1413
      
1414
1.05k
        CheckTagCount (parentCode, tagCode, tagCount, 1);
1415
        
1416
1.05k
        fBatteryLevelR = stream.TagValue_urational (tagType);
1417
        
1418
1.05k
        }
1419
      
1420
      #if qDNGValidate
1421
1422
      if (gVerbose)
1423
        {
1424
        
1425
        printf ("BatteryLevel: ");
1426
        
1427
        if (tagType == ttAscii)
1428
          {
1429
          
1430
          DumpString (fBatteryLevelA);
1431
          
1432
          }
1433
          
1434
        else
1435
          {
1436
        
1437
          printf ("%0.2f", fBatteryLevelR.As_real64 ());
1438
          
1439
          }
1440
          
1441
        printf ("\n");
1442
        
1443
        }
1444
        
1445
      #endif
1446
      
1447
1.51k
      break;
1448
      
1449
0
      }
1450
    
1451
19.3k
    case tcExposureTime:
1452
19.3k
      {
1453
      
1454
19.3k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
1455
      
1456
19.3k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1457
      
1458
19.3k
      dng_urational et = stream.TagValue_urational (tagType);
1459
      
1460
19.3k
      SetExposureTime (et.As_real64 (), true);
1461
      
1462
      #if qDNGValidate
1463
1464
      if (gVerbose)
1465
        {
1466
        
1467
        printf ("ExposureTime: ");
1468
        
1469
        DumpExposureTime (et.As_real64 ());
1470
                  
1471
        printf ("\n");
1472
1473
        }
1474
        
1475
      if (et.As_real64 () <= 0.0)
1476
        {
1477
        
1478
        ReportWarning ("The ExposureTime is <= 0");
1479
               
1480
        }
1481
      
1482
      #endif
1483
      
1484
19.3k
      break;
1485
      
1486
0
      }
1487
1488
13.3k
    case tcFNumber:
1489
13.3k
      {
1490
      
1491
13.3k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
1492
      
1493
13.3k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1494
      
1495
13.3k
      dng_urational fs = stream.TagValue_urational (tagType);
1496
      
1497
      // Sometimes "unknown" is recorded as zero.
1498
      
1499
13.3k
      if (fs.As_real64 () <= 0.0)
1500
2.79k
        {
1501
2.79k
        fs.Clear ();
1502
2.79k
        }
1503
      
1504
      #if qDNGValidate
1505
1506
      if (gVerbose)
1507
        {
1508
        
1509
        printf ("FNumber: f/%0.2f\n",
1510
            fs.As_real64 ());
1511
        
1512
        }
1513
        
1514
      #endif
1515
      
1516
13.3k
      SetFNumber (fs.As_real64 ());
1517
      
1518
13.3k
      break;
1519
      
1520
0
      }
1521
1522
13.7k
    case tcExposureProgram:
1523
13.7k
      {
1524
      
1525
13.7k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
1526
      
1527
13.7k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1528
      
1529
13.7k
      fExposureProgram = stream.TagValue_uint32 (tagType);
1530
      
1531
      #if qDNGValidate
1532
1533
      if (gVerbose)
1534
        {
1535
        
1536
        printf ("ExposureProgram: %s\n",
1537
            LookupExposureProgram (fExposureProgram));
1538
        
1539
        }
1540
        
1541
      #endif
1542
      
1543
13.7k
      break;
1544
      
1545
0
      }
1546
1547
12.0k
    case tcISOSpeedRatings:
1548
12.0k
      {
1549
      
1550
12.0k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
1551
      
1552
12.0k
      CheckTagCount (parentCode, tagCode, tagCount, 1, 3);
1553
      
1554
36.8k
      for (uint32 j = 0; j < tagCount && j < 3; j++)
1555
24.7k
        {
1556
        
1557
24.7k
        fISOSpeedRatings [j] = stream.TagValue_uint32 (tagType);
1558
        
1559
24.7k
        }
1560
      
1561
      #if qDNGValidate
1562
1563
      if (gVerbose)
1564
        {
1565
        
1566
        printf ("ISOSpeedRatings:");
1567
        
1568
        for (uint32 j = 0; j < tagCount && j < 3; j++)
1569
          {
1570
          
1571
          printf (" %u", (unsigned) fISOSpeedRatings [j]);
1572
          
1573
          }
1574
          
1575
        printf ("\n");
1576
          
1577
        }
1578
        
1579
      #endif
1580
      
1581
12.0k
      break;
1582
      
1583
0
      }
1584
      
1585
5.97k
    case tcSensitivityType:
1586
5.97k
      {
1587
      
1588
5.97k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
1589
      
1590
5.97k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1591
1592
5.97k
      fSensitivityType = (uint32) stream.Get_uint16 ();
1593
      
1594
      #if qDNGValidate
1595
1596
      if (gVerbose)
1597
        {
1598
        
1599
        printf ("SensitivityType: %s\n",
1600
            LookupSensitivityType (fSensitivityType));
1601
        
1602
        }
1603
        
1604
      #endif
1605
      
1606
5.97k
      break;
1607
      
1608
0
      }
1609
      
1610
2.83k
    case tcStandardOutputSensitivity:
1611
2.83k
      {
1612
      
1613
2.83k
      CheckTagType (parentCode, tagCode, tagType, ttLong);
1614
      
1615
2.83k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1616
1617
2.83k
      fStandardOutputSensitivity = stream.TagValue_uint32 (tagType);
1618
      
1619
      #if qDNGValidate
1620
1621
      if (gVerbose)
1622
        {
1623
        
1624
        printf ("StandardOutputSensitivity: %u\n",
1625
            (unsigned) fStandardOutputSensitivity);
1626
        
1627
        }
1628
        
1629
      #endif
1630
      
1631
2.83k
      break;
1632
      
1633
0
      }
1634
      
1635
3.13k
    case tcRecommendedExposureIndex:
1636
3.13k
      {
1637
      
1638
3.13k
      CheckTagType (parentCode, tagCode, tagType, ttLong);
1639
      
1640
3.13k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1641
1642
3.13k
      fRecommendedExposureIndex = stream.TagValue_uint32 (tagType);
1643
      
1644
      #if qDNGValidate
1645
1646
      if (gVerbose)
1647
        {
1648
        
1649
        printf ("RecommendedExposureIndex: %u\n",
1650
            (unsigned) fRecommendedExposureIndex);
1651
        
1652
        }
1653
        
1654
      #endif
1655
      
1656
3.13k
      break;
1657
      
1658
0
      }
1659
      
1660
1.35k
    case tcISOSpeed:
1661
1.35k
      {
1662
      
1663
1.35k
      CheckTagType (parentCode, tagCode, tagType, ttLong);
1664
      
1665
1.35k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1666
1667
1.35k
      fISOSpeed = stream.TagValue_uint32 (tagType);
1668
      
1669
      #if qDNGValidate
1670
1671
      if (gVerbose)
1672
        {
1673
        
1674
        printf ("ISOSpeed: %u\n",
1675
            (unsigned) fISOSpeed);
1676
        
1677
        }
1678
        
1679
      #endif
1680
      
1681
1.35k
      break;
1682
      
1683
0
      }
1684
      
1685
1.73k
    case tcISOSpeedLatitudeyyy:
1686
1.73k
      {
1687
      
1688
1.73k
      CheckTagType (parentCode, tagCode, tagType, ttLong);
1689
      
1690
1.73k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1691
1692
1.73k
      fISOSpeedLatitudeyyy = stream.TagValue_uint32 (tagType);
1693
      
1694
      #if qDNGValidate
1695
1696
      if (gVerbose)
1697
        {
1698
        
1699
        printf ("ISOSpeedLatitudeyyy: %u\n",
1700
            (unsigned) fISOSpeedLatitudeyyy);
1701
        
1702
        }
1703
        
1704
      #endif
1705
      
1706
1.73k
      break;
1707
      
1708
0
      }
1709
      
1710
2.00k
    case tcISOSpeedLatitudezzz:
1711
2.00k
      {
1712
      
1713
2.00k
      CheckTagType (parentCode, tagCode, tagType, ttLong);
1714
      
1715
2.00k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1716
1717
2.00k
      fISOSpeedLatitudezzz = stream.TagValue_uint32 (tagType);
1718
      
1719
      #if qDNGValidate
1720
1721
      if (gVerbose)
1722
        {
1723
        
1724
        printf ("ISOSpeedLatitudezzz: %u\n",
1725
            (unsigned) fISOSpeedLatitudezzz);
1726
        
1727
        }
1728
        
1729
      #endif
1730
      
1731
2.00k
      break;
1732
      
1733
0
      }
1734
      
1735
1.82k
    case tcTimeZoneOffset:
1736
1.82k
      {
1737
      
1738
1.82k
      CheckTagType (parentCode, tagCode, tagType, ttSShort);
1739
      
1740
1.82k
      CheckTagCount (parentCode, tagCode, tagCount, 1, 2);
1741
      
1742
1.82k
      dng_time_zone zoneOriginal;
1743
      
1744
1.82k
      zoneOriginal.SetOffsetHours (stream.TagValue_int32 (tagType));
1745
      
1746
1.82k
      fDateTimeOriginal.SetZone (zoneOriginal);
1747
      
1748
      #if 0 // MWG: Not filling in time zones unless we are sure.
1749
      
1750
      // Note that there is no "TimeZoneOffsetDigitized" field, so
1751
      // we assume the same tone zone as the original.
1752
      
1753
      fDateTimeDigitized.SetZone (zoneOriginal);
1754
      
1755
      #endif
1756
1757
1.82k
      dng_time_zone zoneCurrent;
1758
1759
1.82k
      if (tagCount >= 2)
1760
1.03k
        {
1761
        
1762
1.03k
        zoneCurrent.SetOffsetHours (stream.TagValue_int32 (tagType));
1763
        
1764
1.03k
        fDateTime.SetZone (zoneCurrent);
1765
        
1766
1.03k
        }
1767
        
1768
      #if qDNGValidate
1769
1770
      if (gVerbose)
1771
        {
1772
        
1773
        printf ("TimeZoneOffset: DateTimeOriginal = %d", 
1774
            (int) zoneOriginal.ExactHourOffset ());
1775
            
1776
        if (tagCount >= 2)
1777
          {
1778
        
1779
          printf (", DateTime = %d",
1780
              (int) zoneCurrent.ExactHourOffset ());
1781
              
1782
          }
1783
          
1784
        printf ("\n");
1785
        
1786
        }
1787
        
1788
      #endif
1789
      
1790
1.82k
      break;
1791
      
1792
0
      }
1793
1794
1.40k
    case tcSelfTimerMode:
1795
1.40k
      {
1796
      
1797
1.40k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
1798
      
1799
1.40k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1800
      
1801
1.40k
      fSelfTimerMode = stream.TagValue_uint32 (tagType);
1802
      
1803
      #if qDNGValidate
1804
1805
      if (gVerbose)
1806
        {
1807
        
1808
        printf ("SelfTimerMode: ");
1809
        
1810
        if (fSelfTimerMode)
1811
          {
1812
          
1813
          printf ("%u sec", (unsigned) fSelfTimerMode);
1814
          
1815
          }
1816
          
1817
        else
1818
          {
1819
          
1820
          printf ("Off");
1821
          
1822
          }
1823
          
1824
        printf ("\n");
1825
        
1826
        }
1827
        
1828
      #endif
1829
      
1830
1.40k
      break;
1831
      
1832
0
      }
1833
1834
17.1k
    case tcExifVersion:
1835
17.1k
      {
1836
      
1837
17.1k
      CheckTagType (parentCode, tagCode, tagType, ttUndefined);
1838
      
1839
17.1k
      CheckTagCount (parentCode, tagCode, tagCount, 4);
1840
      
1841
17.1k
      uint32 b0 = stream.Get_uint8 ();
1842
17.1k
      uint32 b1 = stream.Get_uint8 ();
1843
17.1k
      uint32 b2 = stream.Get_uint8 ();
1844
17.1k
      uint32 b3 = stream.Get_uint8 ();
1845
      
1846
17.1k
      fExifVersion = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
1847
      
1848
      #if qDNGValidate
1849
1850
      if (gVerbose)
1851
        {
1852
        
1853
        real64 x = (b0 - '0') * 10.00 +
1854
               (b1 - '0') *  1.00 +
1855
               (b2 - '0') *  0.10 +
1856
               (b3 - '0') *  0.01;
1857
               
1858
        printf ("ExifVersion: %0.2f\n", x);
1859
        
1860
        }
1861
        
1862
      #endif
1863
      
1864
17.1k
      break;
1865
      
1866
0
      }
1867
1868
14.0k
    case tcDateTimeOriginal:
1869
14.0k
      {
1870
      
1871
14.0k
      uint64 tagPosition = stream.PositionInOriginalFile ();
1872
      
1873
14.0k
      dng_date_time dt;
1874
      
1875
14.0k
      if (!ParseDateTimeTag (stream,
1876
14.0k
                   parentCode,
1877
14.0k
                   tagCode,
1878
14.0k
                   tagType,
1879
14.0k
                   tagCount,
1880
14.0k
                   dt))
1881
8.42k
        {
1882
8.42k
        return false;
1883
8.42k
        }
1884
        
1885
5.58k
      fDateTimeOriginal.SetDateTime (dt);
1886
      
1887
5.58k
      fDateTimeOriginalStorageInfo = dng_date_time_storage_info (tagPosition,
1888
5.58k
                                     dng_date_time_format_exif);
1889
        
1890
      #if qDNGValidate
1891
      
1892
      if (gVerbose)
1893
        {
1894
        
1895
        printf ("DateTimeOriginal: ");
1896
        
1897
        DumpDateTime (fDateTimeOriginal.DateTime ());
1898
        
1899
        printf ("\n");
1900
        
1901
        }
1902
        
1903
      #endif
1904
1905
5.58k
      break;
1906
      
1907
14.0k
      }
1908
1909
14.0k
    case tcDateTimeDigitized:
1910
14.0k
      {
1911
      
1912
14.0k
      uint64 tagPosition = stream.PositionInOriginalFile ();
1913
      
1914
14.0k
      dng_date_time dt;
1915
      
1916
14.0k
      if (!ParseDateTimeTag (stream,
1917
14.0k
                   parentCode,
1918
14.0k
                   tagCode,
1919
14.0k
                   tagType,
1920
14.0k
                   tagCount,
1921
14.0k
                   dt))
1922
9.94k
        {
1923
9.94k
        return false;
1924
9.94k
        }
1925
        
1926
4.13k
      fDateTimeDigitized.SetDateTime (dt);
1927
      
1928
4.13k
      fDateTimeDigitizedStorageInfo = dng_date_time_storage_info (tagPosition,
1929
4.13k
                                      dng_date_time_format_exif);
1930
1931
      #if qDNGValidate
1932
      
1933
      if (gVerbose)
1934
        {
1935
        
1936
        printf ("DateTimeDigitized: ");
1937
        
1938
        DumpDateTime (fDateTimeDigitized.DateTime ());
1939
        
1940
        printf ("\n");
1941
        
1942
        }
1943
        
1944
      #endif
1945
1946
4.13k
      break;
1947
      
1948
14.0k
      }
1949
      
1950
6.21k
    case tcComponentsConfiguration:
1951
6.21k
      {
1952
      
1953
6.21k
      CheckTagType (parentCode, tagCode, tagType, ttUndefined);
1954
      
1955
6.21k
      CheckTagCount (parentCode, tagCode, tagCount, 4);
1956
      
1957
6.21k
      uint32 b0 = stream.Get_uint8 ();
1958
6.21k
      uint32 b1 = stream.Get_uint8 ();
1959
6.21k
      uint32 b2 = stream.Get_uint8 ();
1960
6.21k
      uint32 b3 = stream.Get_uint8 ();
1961
      
1962
6.21k
      fComponentsConfiguration = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
1963
      
1964
      #if qDNGValidate
1965
1966
      if (gVerbose)
1967
        {
1968
        
1969
        printf ("ComponentsConfiguration: %s %s %s %s\n",
1970
            LookupComponent (b0),
1971
            LookupComponent (b1),
1972
            LookupComponent (b2),
1973
            LookupComponent (b3));
1974
                
1975
        }
1976
        
1977
      #endif
1978
      
1979
6.21k
      break;
1980
      
1981
14.0k
      }
1982
      
1983
2.13k
    case tcCompressedBitsPerPixel:
1984
2.13k
      {
1985
      
1986
2.13k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
1987
      
1988
2.13k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1989
      
1990
2.13k
      fCompresssedBitsPerPixel = stream.TagValue_urational (tagType);
1991
      
1992
      #if qDNGValidate
1993
1994
      if (gVerbose)
1995
        {
1996
        
1997
        printf ("CompressedBitsPerPixel: %0.2f\n",
1998
            fCompresssedBitsPerPixel.As_real64 ());
1999
                
2000
        }
2001
        
2002
      #endif
2003
      
2004
2.13k
      break;
2005
      
2006
14.0k
      }
2007
      
2008
6.66k
    case tcShutterSpeedValue:
2009
6.66k
      {
2010
      
2011
6.66k
      CheckTagType (parentCode, tagCode, tagType, ttSRational);
2012
      
2013
6.66k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2014
      
2015
6.66k
      dng_srational ss = stream.TagValue_srational (tagType);
2016
      
2017
      #if qDNGValidate
2018
2019
      if (gVerbose)
2020
        {
2021
        
2022
        printf ("ShutterSpeedValue: ");
2023
        
2024
        real64 x = pow (2.0, -ss.As_real64 ());
2025
        
2026
        DumpExposureTime (x);
2027
                            
2028
        printf ("\n");
2029
2030
        }
2031
        
2032
      // The ExposureTime and ShutterSpeedValue tags should be consistent.
2033
      
2034
      if (fExposureTime.IsValid ())
2035
        {
2036
        
2037
        real64 et = fExposureTime.As_real64 ();
2038
        
2039
        real64 tv1 = -1.0 * log (et) / log (2.0);
2040
        
2041
        real64 tv2 = ss.As_real64 ();
2042
        
2043
        // Make sure they are within 0.25 APEX values.
2044
        
2045
        if (Abs_real64 (tv1 - tv2) > 0.25)
2046
          {
2047
          
2048
          ReportWarning ("The ExposureTime and ShutterSpeedValue tags have conflicting values");
2049
                 
2050
          }
2051
          
2052
        }
2053
      
2054
      #endif
2055
      
2056
6.66k
      SetShutterSpeedValue (ss.As_real64 ());
2057
        
2058
6.66k
      break;
2059
      
2060
14.0k
      }
2061
      
2062
5.39k
    case tcApertureValue:
2063
5.39k
      {
2064
      
2065
5.39k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
2066
      
2067
5.39k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2068
      
2069
5.39k
      dng_urational av = stream.TagValue_urational (tagType);
2070
      
2071
      #if qDNGValidate
2072
2073
      if (gVerbose)
2074
        {
2075
        
2076
        real64 x = pow (2.0, 0.5 * av.As_real64 ());
2077
                
2078
        printf ("ApertureValue: f/%0.2f\n", x);
2079
        
2080
        }
2081
        
2082
      // The FNumber and ApertureValue tags should be consistent.
2083
      
2084
      if (fFNumber.IsValid () && av.IsValid ())
2085
        {
2086
        
2087
        real64 fs = fFNumber.As_real64 ();
2088
        
2089
        real64 av1 = FNumberToApertureValue (fs);
2090
      
2091
        real64 av2 = av.As_real64 ();
2092
      
2093
        if (Abs_real64 (av1 - av2) > 0.25)
2094
          {
2095
          
2096
          ReportWarning ("The FNumber and ApertureValue tags have conflicting values");
2097
                 
2098
          }
2099
2100
        }
2101
    
2102
      #endif
2103
      
2104
5.39k
      SetApertureValue (av.As_real64 ());
2105
        
2106
5.39k
      break;
2107
      
2108
14.0k
      }
2109
      
2110
2.17k
    case tcBrightnessValue:
2111
2.17k
      {
2112
      
2113
2.17k
      CheckTagType (parentCode, tagCode, tagType, ttSRational);
2114
      
2115
2.17k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2116
      
2117
2.17k
      fBrightnessValue = stream.TagValue_srational (tagType);
2118
      
2119
      #if qDNGValidate
2120
2121
      if (gVerbose)
2122
        {
2123
        
2124
        printf ("BrightnessValue: %0.2f\n",
2125
            fBrightnessValue.As_real64 ());
2126
        
2127
        }
2128
        
2129
      #endif
2130
        
2131
2.17k
      break;
2132
      
2133
14.0k
      }
2134
      
2135
6.52k
    case tcExposureBiasValue:
2136
6.52k
      {
2137
      
2138
6.52k
      CheckTagType (parentCode, tagCode, tagType, ttSRational);
2139
      
2140
6.52k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2141
      
2142
6.52k
      fExposureBiasValue = stream.TagValue_srational (tagType);
2143
      
2144
      #if qDNGValidate
2145
2146
      if (gVerbose)
2147
        {
2148
        
2149
        printf ("ExposureBiasValue: %0.2f\n",
2150
            fExposureBiasValue.As_real64 ());
2151
        
2152
        }
2153
        
2154
      #endif
2155
      
2156
6.52k
      break;
2157
      
2158
14.0k
      }
2159
2160
5.92k
    case tcMaxApertureValue:
2161
5.92k
      {
2162
      
2163
5.92k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
2164
      
2165
5.92k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2166
      
2167
5.92k
      fMaxApertureValue = stream.TagValue_urational (tagType);
2168
      
2169
      #if qDNGValidate
2170
2171
      if (gVerbose)
2172
        {
2173
        
2174
        real64 x = pow (2.0, 0.5 * fMaxApertureValue.As_real64 ());
2175
                
2176
        printf ("MaxApertureValue: f/%0.1f\n", x);
2177
        
2178
        }
2179
        
2180
      #endif
2181
        
2182
5.92k
      break;
2183
      
2184
14.0k
      }
2185
      
2186
3.44k
    case tcSubjectDistance:
2187
3.44k
      {
2188
      
2189
3.44k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
2190
      
2191
3.44k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2192
      
2193
3.44k
      fSubjectDistance = stream.TagValue_urational (tagType);
2194
2195
3.44k
      fApproxFocusDistance = fSubjectDistance;
2196
      
2197
      #if qDNGValidate
2198
      
2199
      if (gVerbose)
2200
        {
2201
        
2202
        printf ("SubjectDistance: %u/%u\n",
2203
            (unsigned) fSubjectDistance.n,
2204
            (unsigned) fSubjectDistance.d);
2205
        
2206
        }
2207
      
2208
      #endif
2209
      
2210
3.44k
      break;
2211
      
2212
14.0k
      }
2213
2214
6.54k
    case tcMeteringMode:
2215
6.54k
      {
2216
      
2217
6.54k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
2218
      
2219
6.54k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2220
      
2221
6.54k
      fMeteringMode = stream.TagValue_uint32 (tagType);
2222
      
2223
      #if qDNGValidate
2224
2225
      if (gVerbose)
2226
        {
2227
        
2228
        printf ("MeteringMode: %s\n",
2229
            LookupMeteringMode (fMeteringMode));
2230
        
2231
        }
2232
        
2233
      #endif
2234
      
2235
6.54k
      break;
2236
      
2237
14.0k
      }
2238
      
2239
6.03k
    case tcLightSource:
2240
6.03k
      {
2241
      
2242
6.03k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
2243
      
2244
6.03k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2245
      
2246
6.03k
      fLightSource = stream.TagValue_uint32 (tagType);
2247
      
2248
      #if qDNGValidate
2249
2250
      if (gVerbose)
2251
        {
2252
        
2253
        printf ("LightSource: %s\n",
2254
            LookupLightSource (fLightSource));
2255
        
2256
        }
2257
        
2258
      #endif
2259
      
2260
6.03k
      break;
2261
      
2262
14.0k
      }
2263
2264
7.99k
    case tcFlash:
2265
7.99k
      {
2266
      
2267
7.99k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
2268
      
2269
7.99k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2270
      
2271
7.99k
      fFlash = stream.TagValue_uint32 (tagType);
2272
      
2273
      #if qDNGValidate
2274
2275
      if (gVerbose)
2276
        {
2277
        
2278
        printf ("Flash: %u\n", (unsigned) fFlash);
2279
        
2280
        if ((fFlash >> 5) & 1)
2281
          {
2282
          printf ("    No flash function\n");
2283
          }
2284
          
2285
        else
2286
          {
2287
          
2288
          if (fFlash & 0x1)
2289
            {
2290
            
2291
            printf ("    Flash fired\n");
2292
            
2293
            switch ((fFlash >> 1) & 0x3)
2294
              {
2295
              
2296
              case 2:
2297
                printf ("    Strobe return light not detected\n");
2298
                break;
2299
                
2300
              case 3:
2301
                printf ("    Strobe return light detected\n");
2302
                break;
2303
                
2304
              }
2305
                
2306
            }
2307
            
2308
          else
2309
            {
2310
            printf ("    Flash did not fire\n");
2311
            }
2312
            
2313
          switch ((fFlash >> 3) & 0x3)
2314
            {
2315
            
2316
            case 1:
2317
              printf ("    Compulsory flash firing\n");
2318
              break;
2319
              
2320
            case 2:
2321
              printf ("    Compulsory flash suppression\n");
2322
              break;
2323
              
2324
            case 3:
2325
              printf ("    Auto mode\n");
2326
              break;
2327
              
2328
            }
2329
            
2330
          if ((fFlash >> 6) & 1)
2331
            {
2332
            printf ("    Red-eye reduction supported\n");
2333
            }
2334
2335
          }
2336
          
2337
        }
2338
        
2339
      #endif
2340
      
2341
7.99k
      break;
2342
      
2343
14.0k
      }
2344
      
2345
9.35k
    case tcFocalLength:
2346
9.35k
      {
2347
      
2348
9.35k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
2349
      
2350
9.35k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2351
      
2352
9.35k
      fFocalLength = stream.TagValue_urational (tagType);
2353
      
2354
      // Sometimes "unknown" is recorded as zero.
2355
      
2356
9.35k
      if (fFocalLength.As_real64 () <= 0.0)
2357
2.23k
        {
2358
2.23k
        fFocalLength.Clear ();
2359
2.23k
        }
2360
      
2361
      #if qDNGValidate
2362
2363
      if (gVerbose)
2364
        {
2365
        
2366
        printf ("FocalLength: %0.1f mm\n",
2367
            fFocalLength.As_real64 ());
2368
        
2369
        }
2370
        
2371
      #endif
2372
        
2373
9.35k
      break;
2374
      
2375
14.0k
      }
2376
      
2377
2.24k
    case tcImageNumber:
2378
2.24k
      {
2379
      
2380
2.24k
      CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
2381
      
2382
2.24k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2383
      
2384
2.24k
      fImageNumber = stream.TagValue_uint32 (tagType);
2385
      
2386
      #if qDNGValidate
2387
2388
      if (gVerbose)
2389
        {
2390
        printf ("ImageNumber: %u\n", (unsigned) fImageNumber);
2391
        }
2392
        
2393
      #endif
2394
        
2395
2.24k
      break;
2396
      
2397
14.0k
      }
2398
    
2399
10.6k
    case tcExposureIndex:
2400
10.9k
    case tcExposureIndexExif:
2401
10.9k
      {
2402
      
2403
10.9k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
2404
      
2405
10.9k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2406
      
2407
10.9k
      fExposureIndex = stream.TagValue_urational (tagType);
2408
      
2409
      #if qDNGValidate
2410
2411
      if (gVerbose)
2412
        {
2413
        
2414
        printf ("%s: ISO %0.1f\n",
2415
            LookupTagCode (parentCode, tagCode),
2416
            fExposureIndex.As_real64 ());
2417
        
2418
        }
2419
        
2420
      #endif
2421
      
2422
10.9k
      break;
2423
      
2424
10.6k
      }
2425
      
2426
22.1k
    case tcUserComment:
2427
22.1k
      {
2428
      
2429
22.1k
      CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2430
      
2431
22.1k
      ParseEncodedStringTag (stream,
2432
22.1k
                   parentCode,
2433
22.1k
                   tagCode,
2434
22.1k
                     tagCount,
2435
22.1k
                     fUserComment);
2436
      
2437
      #if qDNGValidate
2438
2439
      if (gVerbose)
2440
        {
2441
        
2442
        printf ("UserComment: ");
2443
        
2444
        DumpString (fUserComment);
2445
        
2446
        printf ("\n");
2447
        
2448
        }
2449
        
2450
      #endif
2451
        
2452
22.1k
      break;
2453
      
2454
10.6k
      }
2455
2456
802
    case tcSubsecTime:
2457
802
      {
2458
      
2459
802
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
2460
      
2461
802
      dng_string subsecs;
2462
      
2463
802
      ParseStringTag (stream,
2464
802
              parentCode,
2465
802
              tagCode,
2466
802
              tagCount,
2467
802
              subsecs);
2468
              
2469
802
      fDateTime.SetSubseconds (subsecs);
2470
      
2471
      #if qDNGValidate
2472
2473
      if (gVerbose)
2474
        {
2475
        
2476
        printf ("SubsecTime: ");
2477
        
2478
        DumpString (subsecs);
2479
        
2480
        printf ("\n");
2481
        
2482
        }
2483
        
2484
      #endif
2485
2486
802
      break;
2487
      
2488
10.6k
      }
2489
2490
1.21k
    case tcSubsecTimeOriginal:
2491
1.21k
      {
2492
      
2493
1.21k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
2494
      
2495
1.21k
      dng_string subsecs;
2496
      
2497
1.21k
      ParseStringTag (stream,
2498
1.21k
              parentCode,
2499
1.21k
              tagCode,
2500
1.21k
              tagCount,
2501
1.21k
              subsecs);
2502
              
2503
1.21k
      fDateTimeOriginal.SetSubseconds (subsecs);
2504
2505
      #if qDNGValidate
2506
2507
      if (gVerbose)
2508
        {
2509
        
2510
        printf ("SubsecTimeOriginal: ");
2511
        
2512
        DumpString (subsecs);
2513
        
2514
        printf ("\n");
2515
        
2516
        }
2517
        
2518
      #endif
2519
2520
1.21k
      break;
2521
      
2522
10.6k
      }
2523
2524
655
    case tcSubsecTimeDigitized:
2525
655
      {
2526
      
2527
655
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
2528
      
2529
655
      dng_string subsecs;
2530
      
2531
655
      ParseStringTag (stream,
2532
655
              parentCode,
2533
655
              tagCode,
2534
655
              tagCount,
2535
655
              subsecs);
2536
              
2537
655
      fDateTimeDigitized.SetSubseconds (subsecs);
2538
      
2539
      #if qDNGValidate
2540
2541
      if (gVerbose)
2542
        {
2543
        
2544
        printf ("SubsecTimeDigitized: ");
2545
        
2546
        DumpString (subsecs);
2547
        
2548
        printf ("\n");
2549
        
2550
        }
2551
        
2552
      #endif
2553
2554
655
      break;
2555
      
2556
10.6k
      }
2557
      
2558
7.67k
    case tcFlashPixVersion:
2559
7.67k
      {
2560
      
2561
7.67k
      CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2562
      
2563
7.67k
      CheckTagCount (parentCode, tagCode, tagCount, 4);
2564
      
2565
7.67k
      uint32 b0 = stream.Get_uint8 ();
2566
7.67k
      uint32 b1 = stream.Get_uint8 ();
2567
7.67k
      uint32 b2 = stream.Get_uint8 ();
2568
7.67k
      uint32 b3 = stream.Get_uint8 ();
2569
      
2570
7.67k
      fFlashPixVersion = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
2571
      
2572
      #if qDNGValidate
2573
2574
      if (gVerbose)
2575
        {
2576
        
2577
        real64 x = (b0 - '0') * 10.00 +
2578
               (b1 - '0') *  1.00 +
2579
               (b2 - '0') *  0.10 +
2580
               (b3 - '0') *  0.01;
2581
               
2582
        printf ("FlashPixVersion: %0.2f\n", x);
2583
        
2584
        }
2585
        
2586
      #endif
2587
      
2588
7.67k
      break;
2589
      
2590
10.6k
      }
2591
      
2592
5.82k
    case tcColorSpace:
2593
5.82k
      {
2594
      
2595
5.82k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
2596
      
2597
5.82k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2598
      
2599
5.82k
      fColorSpace = stream.TagValue_uint32 (tagType);
2600
      
2601
      #if qDNGValidate
2602
2603
      if (gVerbose)
2604
        {
2605
        
2606
        printf ("ColorSpace: %s\n",
2607
            LookupColorSpace (fColorSpace));
2608
        
2609
        }
2610
        
2611
      #endif
2612
      
2613
5.82k
      break;
2614
      
2615
10.6k
      }
2616
      
2617
3.50k
    case tcPixelXDimension:
2618
3.50k
      {
2619
      
2620
3.50k
      CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
2621
      
2622
3.50k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2623
      
2624
3.50k
      fPixelXDimension = stream.TagValue_uint32 (tagType);
2625
      
2626
      #if qDNGValidate
2627
2628
      if (gVerbose)
2629
        {
2630
        printf ("PixelXDimension: %u\n", (unsigned) fPixelXDimension);
2631
        }
2632
        
2633
      #endif
2634
        
2635
3.50k
      break;
2636
      
2637
10.6k
      }
2638
      
2639
2.66k
    case tcPixelYDimension:
2640
2.66k
      {
2641
      
2642
2.66k
      CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
2643
      
2644
2.66k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2645
      
2646
2.66k
      fPixelYDimension = stream.TagValue_uint32 (tagType);
2647
      
2648
      #if qDNGValidate
2649
2650
      if (gVerbose)
2651
        {
2652
        printf ("PixelYDimension: %u\n", (unsigned) fPixelYDimension);
2653
        }
2654
        
2655
      #endif
2656
      
2657
2.66k
      break;
2658
      
2659
10.6k
      }
2660
2661
902
    case tcFocalPlaneXResolutionExif:
2662
902
      {
2663
2664
902
      CheckTagType (parentCode, tagCode, tagType, ttRational);
2665
      
2666
902
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2667
      
2668
902
      fFocalPlaneXResolution = stream.TagValue_urational (tagType);
2669
      
2670
      #if qDNGValidate
2671
2672
      if (gVerbose)
2673
        {
2674
        
2675
        printf ("FocalPlaneXResolutionExif: %0.4f\n",
2676
            fFocalPlaneXResolution.As_real64 ());
2677
            
2678
        }
2679
      
2680
      #endif
2681
      
2682
902
      break;
2683
      
2684
10.6k
      }
2685
      
2686
527
    case tcFocalPlaneYResolutionExif:
2687
527
      {
2688
2689
527
      CheckTagType (parentCode, tagCode, tagType, ttRational);
2690
      
2691
527
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2692
      
2693
527
      fFocalPlaneYResolution = stream.TagValue_urational (tagType);
2694
      
2695
      #if qDNGValidate
2696
2697
      if (gVerbose)
2698
        {
2699
        
2700
        printf ("FocalPlaneYResolutionExif: %0.4f\n",
2701
            fFocalPlaneYResolution.As_real64 ());
2702
            
2703
        }
2704
      
2705
      #endif
2706
      
2707
527
      break;
2708
      
2709
10.6k
      }
2710
      
2711
303
    case tcFocalPlaneResolutionUnitExif:
2712
303
      {
2713
      
2714
303
      CheckTagType (parentCode, tagCode, tagType, ttShort);
2715
      
2716
303
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2717
      
2718
303
      fFocalPlaneResolutionUnit = stream.TagValue_uint32 (tagType);
2719
      
2720
      #if qDNGValidate
2721
2722
      if (gVerbose)
2723
        {
2724
        
2725
        printf ("FocalPlaneResolutionUnitExif: %s\n",
2726
              LookupResolutionUnit (fFocalPlaneResolutionUnit));
2727
        
2728
        }
2729
        
2730
      #endif
2731
      
2732
303
      break;
2733
      
2734
10.6k
      }
2735
2736
811
    case tcSensingMethodExif:
2737
811
      {
2738
      
2739
811
      CheckTagType (parentCode, tagCode, tagType, ttShort);
2740
      
2741
811
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2742
      
2743
811
      fSensingMethod = stream.TagValue_uint32 (tagType);
2744
      
2745
      #if qDNGValidate
2746
2747
      if (gVerbose)
2748
        {
2749
        
2750
        printf ("SensingMethodExif: %s\n",
2751
            LookupSensingMethod (fSensingMethod));
2752
2753
        }
2754
      
2755
      #endif
2756
      
2757
811
      break;
2758
      
2759
10.6k
      }
2760
      
2761
7.18k
    case tcFileSource:
2762
7.18k
      {
2763
      
2764
7.18k
      CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2765
      
2766
7.18k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2767
      
2768
7.18k
      fFileSource = stream.Get_uint8 ();
2769
      
2770
      #if qDNGValidate
2771
2772
      if (gVerbose)
2773
        {
2774
        
2775
        printf ("FileSource: %s\n",
2776
            LookupFileSource (fFileSource));
2777
2778
        }
2779
      
2780
      #endif
2781
      
2782
7.18k
      break;
2783
      
2784
10.6k
      }
2785
      
2786
5.37k
    case tcSceneType:
2787
5.37k
      {
2788
      
2789
5.37k
      CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2790
      
2791
5.37k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2792
      
2793
5.37k
      fSceneType = stream.Get_uint8 ();
2794
      
2795
      #if qDNGValidate
2796
2797
      if (gVerbose)
2798
        {
2799
        
2800
        printf ("SceneType: %s\n",
2801
            LookupSceneType (fSceneType));
2802
2803
        }
2804
      
2805
      #endif
2806
      
2807
5.37k
      break;
2808
      
2809
10.6k
      }
2810
      
2811
5.68k
    case tcCFAPatternExif:
2812
5.68k
      {
2813
      
2814
5.68k
      CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2815
      
2816
5.68k
      if (tagCount <= 4)
2817
985
        {
2818
985
        return false;
2819
985
        }
2820
        
2821
4.70k
      uint32 cols = stream.Get_uint16 ();
2822
4.70k
      uint32 rows = stream.Get_uint16 ();
2823
      
2824
4.70k
      if (tagCount != 4 + cols * rows)
2825
3.27k
        {
2826
3.27k
        return false;
2827
3.27k
        }
2828
        
2829
1.42k
      if (cols < 1 || cols > kMaxCFAPattern ||
2830
1.05k
        rows < 1 || rows > kMaxCFAPattern)
2831
384
        {
2832
384
        return false;
2833
384
        }
2834
      
2835
1.04k
      fCFARepeatPatternCols = cols;
2836
1.04k
      fCFARepeatPatternRows = rows;
2837
      
2838
      // Note that the Exif spec stores this array in a different
2839
      // scan order than the TIFF-EP spec.
2840
      
2841
2.79k
      for (uint32 j = 0; j < fCFARepeatPatternCols; j++)
2842
4.61k
        for (uint32 k = 0; k < fCFARepeatPatternRows; k++)
2843
2.86k
          {
2844
          
2845
2.86k
          fCFAPattern [k] [j] = stream.Get_uint8 ();
2846
          
2847
2.86k
          }
2848
      
2849
      #if qDNGValidate
2850
2851
      if (gVerbose)
2852
        {
2853
        
2854
        printf ("CFAPatternExif:\n");
2855
        
2856
        for (uint32 j = 0; j < fCFARepeatPatternRows; j++)
2857
          {
2858
          
2859
          int32 spaces = 4;
2860
          
2861
          for (uint32 k = 0; k < fCFARepeatPatternCols; k++)
2862
            {
2863
            
2864
            while (spaces-- > 0)
2865
              {
2866
              printf (" ");
2867
              }
2868
              
2869
            const char *name = LookupCFAColor (fCFAPattern [j] [k]);
2870
            
2871
            spaces = 9 - (int32) strlen (name);
2872
            
2873
            printf ("%s", name);
2874
            
2875
            }
2876
            
2877
          printf ("\n");
2878
          
2879
          }
2880
          
2881
        }
2882
      
2883
      #endif
2884
      
2885
1.04k
      break;
2886
      
2887
1.42k
      }
2888
      
2889
3.52k
    case tcCustomRendered:
2890
3.52k
      {
2891
      
2892
3.52k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
2893
      
2894
3.52k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2895
      
2896
3.52k
      fCustomRendered = stream.TagValue_uint32 (tagType);
2897
      
2898
      #if qDNGValidate
2899
2900
      if (gVerbose)
2901
        {
2902
        
2903
        printf ("CustomRendered: %s\n",
2904
            LookupCustomRendered (fCustomRendered));
2905
2906
        }
2907
      
2908
      #endif
2909
      
2910
3.52k
      break;
2911
      
2912
1.42k
      }
2913
      
2914
2.58k
    case tcExposureMode:
2915
2.58k
      {
2916
      
2917
2.58k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
2918
      
2919
2.58k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2920
      
2921
2.58k
      fExposureMode = stream.TagValue_uint32 (tagType);
2922
      
2923
      #if qDNGValidate
2924
2925
      if (gVerbose)
2926
        {
2927
        
2928
        printf ("ExposureMode: %s\n",
2929
            LookupExposureMode (fExposureMode));
2930
2931
        }
2932
      
2933
      #endif
2934
      
2935
2.58k
      break;
2936
      
2937
1.42k
      }
2938
      
2939
3.85k
    case tcWhiteBalance:
2940
3.85k
      {
2941
      
2942
3.85k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
2943
      
2944
3.85k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2945
      
2946
3.85k
      fWhiteBalance = stream.TagValue_uint32 (tagType);
2947
      
2948
      #if qDNGValidate
2949
2950
      if (gVerbose)
2951
        {
2952
        
2953
        printf ("WhiteBalance: %s\n",
2954
            LookupWhiteBalance (fWhiteBalance));
2955
2956
        }
2957
      
2958
      #endif
2959
      
2960
3.85k
      break;
2961
      
2962
1.42k
      }
2963
      
2964
2.53k
    case tcDigitalZoomRatio:
2965
2.53k
      {
2966
      
2967
2.53k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
2968
      
2969
2.53k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2970
      
2971
2.53k
      fDigitalZoomRatio = stream.TagValue_urational (tagType);
2972
      
2973
      #if qDNGValidate
2974
2975
      if (gVerbose)
2976
        {
2977
        
2978
        printf ("DigitalZoomRatio: ");
2979
        
2980
        if (fDigitalZoomRatio.n == 0 ||
2981
          fDigitalZoomRatio.d == 0)
2982
          {
2983
          
2984
          printf ("Not used\n");
2985
          
2986
          }
2987
          
2988
        else
2989
          {
2990
        
2991
          printf ("%0.2f\n", fDigitalZoomRatio.As_real64 ());
2992
          
2993
          }
2994
  
2995
        }
2996
      
2997
      #endif
2998
      
2999
2.53k
      break;
3000
      
3001
1.42k
      }
3002
3003
2.64k
    case tcFocalLengthIn35mmFilm:
3004
2.64k
      {
3005
      
3006
2.64k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
3007
      
3008
2.64k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3009
      
3010
2.64k
      fFocalLengthIn35mmFilm = stream.TagValue_uint32 (tagType);
3011
      
3012
      #if qDNGValidate
3013
3014
      if (gVerbose)
3015
        {
3016
        
3017
        printf ("FocalLengthIn35mmFilm: %u mm\n",
3018
            (unsigned) fFocalLengthIn35mmFilm);
3019
          
3020
        }
3021
      
3022
      #endif
3023
      
3024
2.64k
      break;
3025
      
3026
1.42k
      }
3027
3028
3.11k
    case tcSceneCaptureType:
3029
3.11k
      {
3030
      
3031
3.11k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
3032
      
3033
3.11k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3034
      
3035
3.11k
      fSceneCaptureType = stream.TagValue_uint32 (tagType);
3036
      
3037
      #if qDNGValidate
3038
3039
      if (gVerbose)
3040
        {
3041
        
3042
        printf ("SceneCaptureType: %s\n",
3043
            LookupSceneCaptureType (fSceneCaptureType));
3044
3045
        }
3046
      
3047
      #endif
3048
      
3049
3.11k
      break;
3050
      
3051
1.42k
      }
3052
      
3053
3.49k
    case tcGainControl:
3054
3.49k
      {
3055
      
3056
3.49k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
3057
      
3058
3.49k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3059
      
3060
3.49k
      fGainControl = stream.TagValue_uint32 (tagType);
3061
      
3062
      #if qDNGValidate
3063
3064
      if (gVerbose)
3065
        {
3066
        
3067
        printf ("GainControl: %s\n",
3068
            LookupGainControl (fGainControl));
3069
3070
        }
3071
      
3072
      #endif
3073
      
3074
3.49k
      break;
3075
      
3076
1.42k
      }
3077
      
3078
3.31k
    case tcContrast:
3079
3.31k
      {
3080
      
3081
3.31k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
3082
      
3083
3.31k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3084
      
3085
3.31k
      fContrast = stream.TagValue_uint32 (tagType);
3086
      
3087
      #if qDNGValidate
3088
3089
      if (gVerbose)
3090
        {
3091
        
3092
        printf ("Contrast: %s\n",
3093
            LookupContrast (fContrast));
3094
3095
        }
3096
      
3097
      #endif
3098
      
3099
3.31k
      break;
3100
      
3101
1.42k
      }
3102
      
3103
1.04k
    case tcSaturation:
3104
1.04k
      {
3105
      
3106
1.04k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
3107
      
3108
1.04k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3109
      
3110
1.04k
      fSaturation = stream.TagValue_uint32 (tagType);
3111
      
3112
      #if qDNGValidate
3113
3114
      if (gVerbose)
3115
        {
3116
        
3117
        printf ("Saturation: %s\n",
3118
            LookupSaturation (fSaturation));
3119
3120
        }
3121
      
3122
      #endif
3123
      
3124
1.04k
      break;
3125
      
3126
1.42k
      }
3127
      
3128
6.77k
    case tcSharpness:
3129
6.77k
      {
3130
      
3131
6.77k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
3132
      
3133
6.77k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3134
      
3135
6.77k
      fSharpness = stream.TagValue_uint32 (tagType);
3136
      
3137
      #if qDNGValidate
3138
3139
      if (gVerbose)
3140
        {
3141
        
3142
        printf ("Sharpness: %s\n",
3143
            LookupSharpness (fSharpness));
3144
3145
        }
3146
      
3147
      #endif
3148
      
3149
6.77k
      break;
3150
      
3151
1.42k
      }
3152
      
3153
1.55k
    case tcSubjectDistanceRange:
3154
1.55k
      {
3155
      
3156
1.55k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
3157
      
3158
1.55k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3159
      
3160
1.55k
      fSubjectDistanceRange = stream.TagValue_uint32 (tagType);
3161
      
3162
      #if qDNGValidate
3163
3164
      if (gVerbose)
3165
        {
3166
        
3167
        printf ("SubjectDistanceRange: %s\n",
3168
            LookupSubjectDistanceRange (fSubjectDistanceRange));
3169
3170
        }
3171
        
3172
      #endif
3173
      
3174
1.55k
      break;
3175
      
3176
1.42k
      }
3177
      
3178
1.17k
    case tcSubjectArea:
3179
2.12k
    case tcSubjectLocation:
3180
2.12k
      {
3181
      
3182
2.12k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
3183
      
3184
2.12k
      if (!CheckTagCount (parentCode, tagCode, tagCount, 2, 4))
3185
839
        {
3186
839
        return false;
3187
839
        }
3188
        
3189
1.28k
      if (tagCode == tcSubjectLocation)
3190
516
        {
3191
516
        CheckTagCount (parentCode, tagCode, tagCount, 2);
3192
516
        }
3193
        
3194
1.28k
      fSubjectAreaCount = tagCount;
3195
      
3196
6.21k
      for (uint32 j = 0; j < tagCount; j++)
3197
4.93k
        {
3198
        
3199
4.93k
        fSubjectArea [j] = stream.TagValue_uint32 (tagType);
3200
        
3201
4.93k
        }
3202
      
3203
      #if qDNGValidate
3204
3205
      if (gVerbose)
3206
        {
3207
        
3208
        printf ("%s:", LookupTagCode (parentCode, tagCode));
3209
        
3210
        for (uint32 j = 0; j < fSubjectAreaCount; j++)
3211
          {
3212
          
3213
          printf (" %u", (unsigned) fSubjectArea [j]);
3214
          
3215
          }
3216
          
3217
        printf ("\n");
3218
3219
        }
3220
        
3221
      #endif
3222
      
3223
1.28k
      break;
3224
      
3225
2.12k
      }
3226
      
3227
798
    case tcGamma:
3228
798
      {
3229
      
3230
798
      CheckTagType (parentCode, tagCode, tagType, ttRational);
3231
      
3232
798
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3233
      
3234
798
      fGamma = stream.TagValue_urational (tagType);
3235
      
3236
      #if qDNGValidate
3237
3238
      if (gVerbose)
3239
        {
3240
        
3241
        printf ("Gamma: %0.2f\n",
3242
            fGamma.As_real64 ());
3243
        
3244
        }
3245
        
3246
      #endif
3247
        
3248
798
      break;
3249
      
3250
2.12k
      }
3251
      
3252
2.58k
    case tcImageUniqueID:
3253
2.58k
      {
3254
      
3255
2.58k
      if (!CheckTagType (parentCode, tagCode, tagType, ttAscii))
3256
247
        return false;
3257
        
3258
2.33k
      if (!CheckTagCount (parentCode, tagCode, tagCount, 33))
3259
420
        return false;
3260
      
3261
1.91k
      dng_string s;
3262
      
3263
1.91k
      ParseStringTag (stream,
3264
1.91k
              parentCode,
3265
1.91k
              tagCode,
3266
1.91k
              tagCount,
3267
1.91k
              s);
3268
              
3269
1.91k
      if (s.Length () != 32)
3270
690
        return false;
3271
        
3272
1.22k
      dng_fingerprint f;
3273
      
3274
22.0k
      for (uint32 j = 0; j < 32; j++)
3275
21.6k
        {
3276
        
3277
21.6k
        char c = ForceUppercase (s.Get () [j]);
3278
        
3279
21.6k
        uint32 digit;
3280
        
3281
21.6k
        if (c >= '0' && c <= '9')
3282
17.5k
          {
3283
17.5k
          digit = c - '0';
3284
17.5k
          }
3285
          
3286
4.08k
        else if (c >= 'A' && c <= 'F')
3287
3.30k
          {
3288
3.30k
          digit = c - 'A' + 10;
3289
3.30k
          }
3290
          
3291
782
        else
3292
782
          return false;
3293
        
3294
20.8k
        f.data [j >> 1] *= 16;
3295
20.8k
        f.data [j >> 1] += (uint8) digit;
3296
          
3297
20.8k
        }
3298
        
3299
443
      fImageUniqueID = f;
3300
      
3301
      #if qDNGValidate
3302
3303
      if (gVerbose)
3304
        {
3305
                
3306
        printf ("ImageUniqueID: ");
3307
        
3308
        DumpFingerprint (fImageUniqueID);
3309
                  
3310
        printf ("\n");
3311
3312
        }
3313
        
3314
      #endif
3315
      
3316
443
      break;
3317
      
3318
1.22k
      }
3319
3320
1.13k
    case tcCameraOwnerNameExif:
3321
1.13k
      {
3322
3323
1.13k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
3324
      
3325
1.13k
      ParseStringTag (stream,
3326
1.13k
              parentCode,
3327
1.13k
              tagCode,
3328
1.13k
              tagCount,
3329
1.13k
              fOwnerName);
3330
              
3331
      #if qDNGValidate
3332
      
3333
      if (gVerbose)
3334
        {
3335
        
3336
        printf ("CameraOwnerName: ");
3337
        
3338
        DumpString (fOwnerName);
3339
        
3340
        printf ("\n");
3341
        
3342
        }
3343
        
3344
      #endif
3345
      
3346
1.13k
      break;
3347
      
3348
1.22k
      }
3349
3350
2.35k
    case tcCameraSerialNumberExif:
3351
2.35k
      {
3352
      
3353
2.35k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
3354
      
3355
2.35k
      ParseStringTag (stream,
3356
2.35k
              parentCode,
3357
2.35k
              tagCode,
3358
2.35k
              tagCount,
3359
2.35k
              fCameraSerialNumber);
3360
        
3361
      #if qDNGValidate
3362
3363
      if (gVerbose)
3364
        {
3365
        
3366
        printf ("%s: ", LookupTagCode (parentCode, tagCode));
3367
        
3368
        DumpString (fCameraSerialNumber);
3369
        
3370
        printf ("\n");
3371
        
3372
        }
3373
        
3374
      #endif
3375
      
3376
2.35k
      break;
3377
      
3378
1.22k
      }
3379
3380
7.52k
    case tcLensSpecificationExif:
3381
7.52k
      {
3382
      
3383
7.52k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
3384
      
3385
7.52k
      if (!CheckTagCount (parentCode, tagCode, tagCount, 4))
3386
2.08k
        return false;
3387
        
3388
5.44k
      fLensInfo [0] = stream.TagValue_urational (tagType);
3389
5.44k
      fLensInfo [1] = stream.TagValue_urational (tagType);
3390
5.44k
      fLensInfo [2] = stream.TagValue_urational (tagType);
3391
5.44k
      fLensInfo [3] = stream.TagValue_urational (tagType);
3392
      
3393
      // Some third party software wrote zero rather than undefined values for
3394
      // unknown entries. Work around this bug.
3395
      
3396
27.1k
      for (uint32 j = 0; j < 4; j++)
3397
21.7k
        {
3398
      
3399
21.7k
        if (fLensInfo [j].IsValid () && fLensInfo [j].As_real64 () <= 0.0)
3400
7.75k
          {
3401
          
3402
7.75k
          fLensInfo [j] = dng_urational (0, 0);
3403
          
3404
          #if qDNGValidate
3405
          
3406
          ReportWarning ("Zero entry in LensSpecification tag--should be undefined");
3407
          
3408
          #endif
3409
3410
7.75k
          }
3411
          
3412
21.7k
        }
3413
        
3414
      #if qDNGValidate
3415
3416
      if (gVerbose)
3417
        {
3418
        
3419
        printf ("LensSpecificationExif: ");
3420
        
3421
        real64 minFL = fLensInfo [0].As_real64 ();
3422
        real64 maxFL = fLensInfo [1].As_real64 ();
3423
        
3424
        if (minFL == maxFL)
3425
          printf ("%0.1f mm", minFL);
3426
        else
3427
          printf ("%0.1f-%0.1f mm", minFL, maxFL);
3428
          
3429
        if (fLensInfo [2].d)
3430
          {
3431
          
3432
          real64 minFS = fLensInfo [2].As_real64 ();
3433
          real64 maxFS = fLensInfo [3].As_real64 ();
3434
          
3435
          if (minFS == maxFS)
3436
            printf (" f/%0.1f", minFS);
3437
          else
3438
            printf (" f/%0.1f-%0.1f", minFS, maxFS);
3439
          
3440
          }
3441
          
3442
        printf ("\n");
3443
        
3444
        }
3445
        
3446
      #endif
3447
      
3448
5.44k
      break;
3449
      
3450
7.52k
      }
3451
3452
985
    case tcLensMakeExif:
3453
985
      {
3454
      
3455
985
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
3456
      
3457
985
      ParseStringTag (stream,
3458
985
              parentCode,
3459
985
              tagCode,
3460
985
              tagCount,
3461
985
              fLensMake);
3462
        
3463
      #if qDNGValidate
3464
3465
      if (gVerbose)
3466
        {
3467
        
3468
        printf ("%s: ", LookupTagCode (parentCode, tagCode));
3469
        
3470
        DumpString (fLensMake);
3471
        
3472
        printf ("\n");
3473
        
3474
        }
3475
        
3476
      #endif
3477
      
3478
985
      break;
3479
      
3480
7.52k
      }
3481
3482
1.78k
    case tcLensModelExif:
3483
1.78k
      {
3484
3485
1.78k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
3486
      
3487
1.78k
      ParseStringTag (stream,
3488
1.78k
              parentCode,
3489
1.78k
              tagCode,
3490
1.78k
              tagCount,
3491
1.78k
              fLensName);
3492
              
3493
1.78k
      fLensNameWasReadFromExif = fLensName.NotEmpty ();
3494
        
3495
      #if qDNGValidate
3496
3497
      if (gVerbose)
3498
        {
3499
        
3500
        printf ("%s: ", LookupTagCode (parentCode, tagCode));
3501
        
3502
        DumpString (fLensName);
3503
        
3504
        printf ("\n");
3505
        
3506
        }
3507
        
3508
      #endif
3509
      
3510
1.78k
      break;
3511
      
3512
7.52k
      }
3513
3514
2.57k
    case tcLensSerialNumberExif:
3515
2.57k
      {
3516
      
3517
2.57k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
3518
      
3519
2.57k
      ParseStringTag (stream,
3520
2.57k
              parentCode,
3521
2.57k
              tagCode,
3522
2.57k
              tagCount,
3523
2.57k
              fLensSerialNumber);
3524
        
3525
      #if qDNGValidate
3526
3527
      if (gVerbose)
3528
        {
3529
        
3530
        printf ("%s: ", LookupTagCode (parentCode, tagCode));
3531
        
3532
        DumpString (fLensSerialNumber);
3533
        
3534
        printf ("\n");
3535
        
3536
        }
3537
        
3538
      #endif
3539
      
3540
2.57k
      break;
3541
      
3542
7.52k
      }
3543
3544
1.40M
    default:
3545
1.40M
      {
3546
      
3547
1.40M
      return false;
3548
      
3549
7.52k
      }
3550
      
3551
1.73M
    }
3552
    
3553
298k
  return true;
3554
  
3555
1.73M
  }
3556
      
3557
/*****************************************************************************/
3558
3559
// Parses tags that should only appear in GPS IFD
3560
3561
bool dng_exif::Parse_gps (dng_stream &stream,
3562
              dng_shared & /* shared */,
3563
              uint32 parentCode,
3564
              uint32 tagCode,
3565
              uint32 tagType,
3566
              uint32 tagCount,
3567
              uint64 /* tagOffset */)
3568
220k
  {
3569
  
3570
220k
  switch (tagCode)
3571
220k
    {
3572
3573
22.6k
    case tcGPSVersionID:
3574
22.6k
      {
3575
      
3576
22.6k
      CheckTagType (parentCode, tagCode, tagType, ttByte);
3577
      
3578
22.6k
      CheckTagCount (parentCode, tagCode, tagCount, 4);
3579
      
3580
22.6k
      uint32 b0 = stream.Get_uint8 ();
3581
22.6k
      uint32 b1 = stream.Get_uint8 ();
3582
22.6k
      uint32 b2 = stream.Get_uint8 ();
3583
22.6k
      uint32 b3 = stream.Get_uint8 ();
3584
      
3585
22.6k
      fGPSVersionID = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
3586
      
3587
      #if qDNGValidate
3588
      
3589
      if (gVerbose)
3590
        {
3591
        printf ("GPSVersionID: %u.%u.%u.%u\n",
3592
            (unsigned) b0,
3593
            (unsigned) b1,
3594
            (unsigned) b2,
3595
            (unsigned) b3);
3596
        }
3597
        
3598
      #endif
3599
3600
22.6k
      break;
3601
      
3602
0
      }
3603
      
3604
1.58k
    case tcGPSLatitudeRef:
3605
4.71k
    case tcGPSLongitudeRef:
3606
5.76k
    case tcGPSSatellites:
3607
7.33k
    case tcGPSStatus:
3608
8.71k
    case tcGPSMeasureMode:
3609
9.62k
    case tcGPSSpeedRef:
3610
11.0k
    case tcGPSTrackRef:
3611
12.3k
    case tcGPSImgDirectionRef:
3612
12.9k
    case tcGPSMapDatum:
3613
13.5k
    case tcGPSDestLatitudeRef:
3614
14.2k
    case tcGPSDestLongitudeRef:
3615
14.7k
    case tcGPSDestBearingRef:
3616
15.7k
    case tcGPSDestDistanceRef:
3617
16.4k
    case tcGPSDateStamp:
3618
16.4k
      {
3619
      
3620
16.4k
      if (!CheckTagType (parentCode, tagCode, tagType, ttAscii))
3621
3.15k
        return false;
3622
      
3623
13.2k
      dng_string *s;
3624
      
3625
13.2k
      switch (tagCode)
3626
13.2k
        {
3627
        
3628
892
        case tcGPSLatitudeRef:
3629
892
          s = &fGPSLatitudeRef;
3630
892
          break;
3631
          
3632
2.78k
        case tcGPSLongitudeRef:
3633
2.78k
          s = &fGPSLongitudeRef;
3634
2.78k
          break;
3635
          
3636
695
        case tcGPSSatellites:
3637
695
          s = &fGPSSatellites;
3638
695
          break;
3639
          
3640
1.43k
        case tcGPSStatus:
3641
1.43k
          s = &fGPSStatus;
3642
1.43k
          break;
3643
          
3644
1.09k
        case tcGPSMeasureMode:
3645
1.09k
          s = &fGPSMeasureMode;
3646
1.09k
          break;
3647
3648
853
        case tcGPSSpeedRef:
3649
853
          s = &fGPSSpeedRef;
3650
853
          break;
3651
3652
1.08k
        case tcGPSTrackRef:
3653
1.08k
          s = &fGPSTrackRef;
3654
1.08k
          break;
3655
3656
1.02k
        case tcGPSImgDirectionRef:
3657
1.02k
          s = &fGPSImgDirectionRef;
3658
1.02k
          break;
3659
3660
494
        case tcGPSMapDatum:
3661
494
          s = &fGPSMapDatum;
3662
494
          break;
3663
        
3664
312
        case tcGPSDestLatitudeRef:
3665
312
          s = &fGPSDestLatitudeRef;
3666
312
          break;
3667
        
3668
676
        case tcGPSDestLongitudeRef:
3669
676
          s = &fGPSDestLongitudeRef;
3670
676
          break;
3671
        
3672
400
        case tcGPSDestBearingRef:
3673
400
          s = &fGPSDestBearingRef;
3674
400
          break;
3675
        
3676
886
        case tcGPSDestDistanceRef:
3677
886
          s = &fGPSDestDistanceRef;
3678
886
          break;
3679
        
3680
656
        case tcGPSDateStamp:
3681
656
          s = &fGPSDateStamp;
3682
656
          break;
3683
          
3684
0
        default:
3685
0
          return false;
3686
          
3687
13.2k
        }
3688
        
3689
13.2k
      ParseStringTag (stream,
3690
13.2k
              parentCode,
3691
13.2k
              tagCode,
3692
13.2k
              tagCount,
3693
13.2k
              *s);
3694
              
3695
      #if qDNGValidate
3696
      
3697
      if (gVerbose)
3698
        {
3699
        
3700
        printf ("%s: ", LookupTagCode (parentCode, tagCode));
3701
        
3702
        DumpString (*s);
3703
        
3704
        printf ("\n");
3705
        
3706
        }
3707
        
3708
      #endif
3709
        
3710
13.2k
      break;
3711
      
3712
13.2k
      }
3713
      
3714
1.34k
    case tcGPSLatitude:
3715
5.07k
    case tcGPSLongitude:
3716
8.00k
    case tcGPSTimeStamp:
3717
9.20k
    case tcGPSDestLatitude:
3718
11.6k
    case tcGPSDestLongitude:
3719
11.6k
      {
3720
      
3721
11.6k
      if (!CheckTagType (parentCode, tagCode, tagType, ttRational))
3722
3.30k
        return false;
3723
      
3724
8.33k
      if (!CheckTagCount (parentCode, tagCode, tagCount, 3))
3725
2.93k
        return false;
3726
      
3727
5.40k
      dng_urational *u;
3728
      
3729
5.40k
      switch (tagCode)
3730
5.40k
        {
3731
        
3732
594
        case tcGPSLatitude:
3733
594
          u = fGPSLatitude;
3734
594
          break;
3735
          
3736
1.65k
        case tcGPSLongitude:
3737
1.65k
          u = fGPSLongitude;
3738
1.65k
          break;
3739
          
3740
1.04k
        case tcGPSTimeStamp:
3741
1.04k
          u = fGPSTimeStamp;
3742
1.04k
          break;
3743
          
3744
1.03k
        case tcGPSDestLatitude:
3745
1.03k
          u = fGPSDestLatitude;
3746
1.03k
          break;
3747
          
3748
1.06k
        case tcGPSDestLongitude:
3749
1.06k
          u = fGPSDestLongitude;
3750
1.06k
          break;
3751
3752
0
        default:
3753
0
          return false;
3754
          
3755
5.40k
        }
3756
        
3757
5.40k
      u [0] = stream.TagValue_urational (tagType);
3758
5.40k
      u [1] = stream.TagValue_urational (tagType);
3759
5.40k
      u [2] = stream.TagValue_urational (tagType);
3760
      
3761
      #if qDNGValidate
3762
      
3763
      if (gVerbose)
3764
        {
3765
        
3766
        printf ("%s:", LookupTagCode (parentCode, tagCode));
3767
        
3768
        for (uint32 j = 0; j < 3; j++)
3769
          {
3770
          
3771
          if (u [j].d == 0)
3772
            printf (" -");
3773
            
3774
          else
3775
            printf (" %0.4f", u [j].As_real64 ());
3776
            
3777
          }
3778
        
3779
        printf ("\n");
3780
        
3781
        }
3782
        
3783
      #endif
3784
        
3785
5.40k
      break;
3786
      
3787
5.40k
      }
3788
      
3789
1.85k
    case tcGPSAltitudeRef:
3790
1.85k
      {
3791
      
3792
1.85k
      CheckTagType (parentCode, tagCode, tagType, ttByte);
3793
      
3794
1.85k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3795
      
3796
1.85k
      fGPSAltitudeRef = stream.TagValue_uint32 (tagType);
3797
      
3798
      #if qDNGValidate
3799
      
3800
      if (gVerbose)
3801
        {
3802
        
3803
        printf ("GPSAltitudeRef: ");
3804
        
3805
        switch (fGPSAltitudeRef)
3806
          {
3807
          
3808
          case 0:
3809
            printf ("Sea level");
3810
            break;
3811
            
3812
          case 1:
3813
            printf ("Sea level reference (negative value)");
3814
            break;
3815
            
3816
          default:
3817
            printf ("%u", (unsigned) fGPSAltitudeRef);
3818
            break;
3819
            
3820
          }
3821
          
3822
        printf ("\n");
3823
        
3824
        }
3825
        
3826
      #endif
3827
      
3828
1.85k
      break;
3829
      
3830
5.40k
      }
3831
3832
1.43k
    case tcGPSAltitude:
3833
2.42k
    case tcGPSDOP:
3834
4.24k
    case tcGPSSpeed:
3835
5.96k
    case tcGPSTrack:
3836
7.66k
    case tcGPSImgDirection:
3837
9.13k
    case tcGPSDestBearing:
3838
10.3k
    case tcGPSDestDistance:
3839
10.8k
    case tcGPSHPositioningError:
3840
10.8k
      {
3841
      
3842
10.8k
      if (!CheckTagType (parentCode, tagCode, tagType, ttRational))
3843
2.21k
        return false;
3844
      
3845
8.62k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3846
      
3847
8.62k
      dng_urational *u;
3848
      
3849
8.62k
      switch (tagCode)
3850
8.62k
        {
3851
        
3852
1.36k
        case tcGPSAltitude:
3853
1.36k
          u = &fGPSAltitude;
3854
1.36k
          break;
3855
          
3856
945
        case tcGPSDOP:
3857
945
          u = &fGPSDOP;
3858
945
          break;
3859
          
3860
1.37k
        case tcGPSSpeed:
3861
1.37k
          u = &fGPSSpeed;
3862
1.37k
          break;
3863
  
3864
798
        case tcGPSTrack:
3865
798
          u = &fGPSTrack;
3866
798
          break;
3867
  
3868
1.27k
        case tcGPSImgDirection:
3869
1.27k
          u = &fGPSImgDirection;
3870
1.27k
          break;
3871
        
3872
1.30k
        case tcGPSDestBearing:
3873
1.30k
          u = &fGPSDestBearing;
3874
1.30k
          break;
3875
        
3876
1.11k
        case tcGPSDestDistance:
3877
1.11k
          u = &fGPSDestDistance;
3878
1.11k
          break;
3879
        
3880
448
        case tcGPSHPositioningError:
3881
448
          u = &fGPSHPositioningError;
3882
448
          break;
3883
        
3884
0
        default:
3885
0
          return false;
3886
          
3887
8.62k
        }
3888
        
3889
8.62k
      *u = stream.TagValue_urational (tagType);
3890
3891
      #if qDNGValidate
3892
      
3893
      if (gVerbose)
3894
        {
3895
        
3896
        printf ("%s:", LookupTagCode (parentCode, tagCode));
3897
        
3898
        if (u->d == 0)
3899
          printf (" -");
3900
          
3901
        else
3902
          printf (" %0.4f", u->As_real64 ());
3903
          
3904
        printf ("\n");
3905
        
3906
        }
3907
        
3908
      #endif
3909
        
3910
8.62k
      break;
3911
      
3912
8.62k
      }
3913
      
3914
860
    case tcGPSProcessingMethod:
3915
1.53k
    case tcGPSAreaInformation:
3916
1.53k
      {
3917
      
3918
1.53k
      if (!CheckTagType (parentCode, tagCode, tagType, ttUndefined))
3919
695
        return false;
3920
      
3921
840
      dng_string *s;
3922
      
3923
840
      switch (tagCode)
3924
840
        {
3925
        
3926
444
        case tcGPSProcessingMethod:
3927
444
          s = &fGPSProcessingMethod;
3928
444
          break;
3929
          
3930
396
        case tcGPSAreaInformation:
3931
396
          s = &fGPSAreaInformation;
3932
396
          break;
3933
          
3934
0
        default:
3935
0
          return false;
3936
          
3937
840
        }
3938
        
3939
840
      ParseEncodedStringTag (stream,
3940
840
                   parentCode,
3941
840
                   tagCode,
3942
840
                     tagCount,
3943
840
                       *s);
3944
          
3945
      #if qDNGValidate
3946
      
3947
      if (gVerbose)
3948
        {
3949
        
3950
        printf ("%s: ", LookupTagCode (parentCode, tagCode));
3951
        
3952
        DumpString (*s);
3953
        
3954
        printf ("\n");
3955
        
3956
        }
3957
        
3958
      #endif
3959
        
3960
840
      break;
3961
      
3962
840
      }
3963
      
3964
1.06k
    case tcGPSDifferential:
3965
1.06k
      {
3966
      
3967
1.06k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
3968
      
3969
1.06k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3970
      
3971
1.06k
      fGPSDifferential = stream.TagValue_uint32 (tagType);
3972
      
3973
      #if qDNGValidate
3974
      
3975
      if (gVerbose)
3976
        {
3977
        
3978
        printf ("GPSDifferential: ");
3979
        
3980
        switch (fGPSDifferential)
3981
          {
3982
          
3983
          case 0:
3984
            printf ("Measurement without differential correction");
3985
            break;
3986
            
3987
          case 1:
3988
            printf ("Differential correction applied");
3989
            break;
3990
            
3991
          default:
3992
            printf ("%u", (unsigned) fGPSDifferential);
3993
            
3994
          }
3995
        
3996
        printf ("\n");
3997
        
3998
        }
3999
        
4000
      #endif
4001
      
4002
1.06k
      break;
4003
      
4004
840
      }
4005
      
4006
154k
    default:
4007
154k
      {
4008
      
4009
154k
      return false;
4010
      
4011
840
      }
4012
      
4013
220k
    }
4014
    
4015
53.5k
  return true;
4016
  
4017
220k
  }
4018
      
4019
/*****************************************************************************/
4020
4021
// Parses tags that should only appear in Interoperability IFD
4022
4023
bool dng_exif::Parse_interoperability (dng_stream &stream,
4024
                       dng_shared & /* shared */,
4025
                     uint32 parentCode,
4026
                     uint32 tagCode,
4027
                     uint32 tagType,
4028
                     uint32 tagCount,
4029
                     uint64 /* tagOffset */)
4030
1.83k
  {
4031
  
4032
1.83k
  switch (tagCode)
4033
1.83k
    {
4034
    
4035
128
    case tcInteroperabilityIndex:
4036
128
      {
4037
      
4038
128
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
4039
      
4040
128
      CheckTagCount (parentCode, tagCode, tagCount, 4);
4041
      
4042
128
      ParseStringTag (stream,
4043
128
              parentCode,
4044
128
              tagCode,
4045
128
              tagCount,
4046
128
              fInteroperabilityIndex);
4047
              
4048
      #if qDNGValidate
4049
      
4050
      if (gVerbose)
4051
        {
4052
        
4053
        printf ("InteroperabilityIndex: ");
4054
        
4055
        DumpString (fInteroperabilityIndex);
4056
        
4057
        printf ("\n");
4058
        
4059
        }
4060
        
4061
      #endif
4062
        
4063
128
      break;
4064
      
4065
0
      }
4066
4067
552
    case tcInteroperabilityVersion:
4068
552
      {
4069
      
4070
552
      CheckTagType (parentCode, tagCode, tagType, ttUndefined);
4071
      
4072
552
      CheckTagCount (parentCode, tagCode, tagCount, 4);
4073
      
4074
552
      uint32 b0 = stream.Get_uint8 ();
4075
552
      uint32 b1 = stream.Get_uint8 ();
4076
552
      uint32 b2 = stream.Get_uint8 ();
4077
552
      uint32 b3 = stream.Get_uint8 ();
4078
      
4079
552
      fInteroperabilityVersion = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
4080
      
4081
      #if qDNGValidate
4082
      
4083
      if (gVerbose)
4084
        {
4085
        
4086
        real64 x = (b0 - '0') * 10.00 +
4087
               (b1 - '0') *  1.00 +
4088
               (b2 - '0') *  0.10 +
4089
               (b3 - '0') *  0.01;
4090
               
4091
        printf ("InteroperabilityVersion: %0.2f\n", x);
4092
        
4093
        }
4094
        
4095
      #endif
4096
      
4097
552
      break;
4098
      
4099
0
      }
4100
4101
60
    case tcRelatedImageFileFormat:
4102
60
      {
4103
      
4104
60
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
4105
      
4106
60
      ParseStringTag (stream,
4107
60
              parentCode,
4108
60
              tagCode,
4109
60
              tagCount,
4110
60
              fRelatedImageFileFormat);
4111
      
4112
      #if qDNGValidate
4113
      
4114
      if (gVerbose)
4115
        {
4116
        
4117
        printf ("RelatedImageFileFormat: ");
4118
        
4119
        DumpString (fRelatedImageFileFormat);
4120
        
4121
        printf ("\n");
4122
        
4123
        }
4124
        
4125
      #endif
4126
        
4127
60
      break;
4128
      
4129
0
      }
4130
4131
34
    case tcRelatedImageWidth:
4132
34
      {
4133
      
4134
34
      CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
4135
      
4136
34
      CheckTagCount (parentCode, tagCode, tagCount, 1);
4137
      
4138
34
      fRelatedImageWidth = stream.TagValue_uint32 (tagType);
4139
      
4140
      #if qDNGValidate
4141
      
4142
      if (gVerbose)
4143
        {
4144
        printf ("RelatedImageWidth: %u\n", (unsigned) fRelatedImageWidth);
4145
        }
4146
        
4147
      #endif
4148
        
4149
34
      break;
4150
      
4151
0
      }
4152
    
4153
74
    case tcRelatedImageLength:
4154
74
      {
4155
      
4156
74
      CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
4157
      
4158
74
      CheckTagCount (parentCode, tagCode, tagCount, 1);
4159
      
4160
74
      fRelatedImageLength = stream.TagValue_uint32 (tagType);
4161
      
4162
      #if qDNGValidate
4163
      
4164
      if (gVerbose)
4165
        {
4166
        printf ("RelatedImageLength: %u\n", (unsigned) fRelatedImageLength);
4167
        }
4168
        
4169
      #endif
4170
        
4171
74
      break;
4172
      
4173
0
      }
4174
    
4175
989
    default:
4176
989
      {
4177
      
4178
989
      return false;
4179
      
4180
0
      }
4181
      
4182
1.83k
    }
4183
    
4184
848
  return true;
4185
  
4186
1.83k
  }
4187
                 
4188
/*****************************************************************************/
4189
4190
void dng_exif::PostParse (dng_host & /* host */,
4191
              dng_shared & /* shared */)
4192
123k
  {
4193
  
4194
  #if qDNGValidate
4195
  
4196
  const real64 kAPEX_Slop = 0.25;
4197
  
4198
  // Sanity check on MaxApertureValue.
4199
    
4200
  if (fMaxApertureValue.d)
4201
    {
4202
    
4203
    real64 mav = fMaxApertureValue.As_real64 ();
4204
    
4205
    // Compare against ApertureValue or FNumber.
4206
    
4207
    real64 av = mav;
4208
    
4209
    if (fApertureValue.d)
4210
      {
4211
      
4212
      av = fApertureValue.As_real64 ();
4213
      
4214
      }
4215
      
4216
    else if (fFNumber.d)
4217
      {
4218
      
4219
      real64 fs = fFNumber.As_real64 ();
4220
      
4221
      if (fs >= 1.0)
4222
        {
4223
        
4224
        av = FNumberToApertureValue (fs);
4225
    
4226
        }
4227
      
4228
      }
4229
      
4230
    if (mav > av + kAPEX_Slop)
4231
      {
4232
        
4233
      ReportWarning ("MaxApertureValue conflicts with ApertureValue and/or FNumber");
4234
             
4235
      }
4236
      
4237
    // Compare against LensInfo
4238
    
4239
    if (fLensInfo [2].d && fLensInfo [3].d)
4240
      {
4241
      
4242
      real64 fs1 = fLensInfo [2].As_real64 ();
4243
      real64 fs2 = fLensInfo [3].As_real64 ();
4244
                  
4245
      if (fs1 >= 1.0 && fs2 >= 1.0 && fs2 >= fs1)
4246
        {
4247
        
4248
        real64 av1 = FNumberToApertureValue (fs1);
4249
        real64 av2 = FNumberToApertureValue (fs2);
4250
        
4251
        // Wide angle adapters might create an effective
4252
        // wide FS, and tele-extenders always result
4253
        // in a higher FS.
4254
        
4255
        if (mav < av1 - kAPEX_Slop - 1.0 ||
4256
          mav > av2 + kAPEX_Slop + 2.0)
4257
          {
4258
            
4259
          ReportWarning ("Possible MaxApertureValue conflict with LensInfo");
4260
                 
4261
          }
4262
    
4263
        }
4264
      
4265
      }
4266
    
4267
    }
4268
    
4269
  // Sanity check on FocalLength.
4270
  
4271
  if (fFocalLength.d)
4272
    {
4273
    
4274
    real64 fl = fFocalLength.As_real64 ();
4275
    
4276
    if (fl < 1.0)
4277
      {
4278
      
4279
      ReportWarning ("FocalLength is less than 1.0 mm (legal but unlikely)");
4280
             
4281
      }
4282
      
4283
    else if (fLensInfo [0].d && fLensInfo [1].d)
4284
      {
4285
      
4286
      real64 minFL = fLensInfo [0].As_real64 ();
4287
      real64 maxFL = fLensInfo [1].As_real64 ();
4288
      
4289
      // Allow for wide-angle converters and tele-extenders.
4290
      
4291
      if (fl < minFL * 0.6 ||
4292
          fl > maxFL * 2.1)
4293
        {
4294
        
4295
        ReportWarning ("Possible FocalLength conflict with LensInfo");
4296
             
4297
        }
4298
      
4299
      }
4300
    
4301
    }
4302
  
4303
  #endif
4304
  
4305
  // Mirror DateTimeOriginal to DateTime.
4306
  
4307
123k
  if (fDateTime.NotValid () && fDateTimeOriginal.IsValid ())
4308
403
    {
4309
    
4310
403
    fDateTime = fDateTimeOriginal;
4311
    
4312
403
    }
4313
4314
  // Mirror EXIF 2.3 sensitivity tags to ISOSpeedRatings.
4315
4316
123k
  if (fISOSpeedRatings [0] == 0 || fISOSpeedRatings [0] == 65535)
4317
119k
    {
4318
4319
    // Prefer Recommended Exposure Index, then Standard Output Sensitivity, then
4320
    // ISO Speed, then Exposure Index.
4321
    
4322
119k
    if (fRecommendedExposureIndex != 0 &&
4323
1.50k
      (fSensitivityType == stRecommendedExposureIndex ||
4324
1.49k
       fSensitivityType == stSOSandREI        ||
4325
1.05k
       fSensitivityType == stREIandISOSpeed      ||
4326
1.03k
       fSensitivityType == stSOSandREIandISOSpeed))
4327
474
      {
4328
      
4329
474
      fISOSpeedRatings [0] = fRecommendedExposureIndex;
4330
      
4331
474
      }
4332
      
4333
119k
    else if (fStandardOutputSensitivity != 0 &&
4334
1.51k
         (fSensitivityType == stStandardOutputSensitivity ||
4335
1.49k
          fSensitivityType == stSOSandREI          ||
4336
1.31k
          fSensitivityType == stSOSandISOSpeed        ||
4337
1.17k
          fSensitivityType == stSOSandREIandISOSpeed))
4338
352
      {
4339
      
4340
352
      fISOSpeedRatings [0] = fStandardOutputSensitivity;
4341
      
4342
352
      }
4343
4344
118k
    else if (fISOSpeed != 0 &&
4345
801
         (fSensitivityType == stISOSpeed     ||
4346
792
          fSensitivityType == stSOSandISOSpeed ||
4347
783
          fSensitivityType == stREIandISOSpeed ||
4348
749
          fSensitivityType == stSOSandREIandISOSpeed))
4349
77
      {
4350
      
4351
77
      fISOSpeedRatings [0] = fISOSpeed;
4352
      
4353
77
      }
4354
    
4355
119k
    }
4356
  
4357
  // Mirror ExposureIndex to ISOSpeedRatings.
4358
4359
123k
  if (fExposureIndex.IsValid () && fISOSpeedRatings [0] == 0)
4360
7.71k
    {
4361
4362
7.71k
    fISOSpeedRatings [0] = Round_uint32 (fExposureIndex.As_real64 ());
4363
4364
7.71k
    }
4365
4366
  // Kodak sets the GPSAltitudeRef without setting the GPSAltitude.
4367
  
4368
123k
  if (fGPSAltitude.NotValid ())
4369
122k
    {
4370
    
4371
122k
    fGPSAltitudeRef = 0xFFFFFFFF;
4372
    
4373
122k
    }
4374
    
4375
  // If there is no valid GPS data, clear the GPS version number.
4376
  
4377
123k
  if (fGPSLatitude  [0].NotValid () &&
4378
122k
    fGPSLongitude [0].NotValid () &&
4379
121k
    fGPSAltitude     .NotValid () &&
4380
120k
    fGPSTimeStamp [0].NotValid () &&
4381
120k
    fGPSDateStamp    .IsEmpty  ())
4382
120k
    {
4383
    
4384
120k
    fGPSVersionID = 0;
4385
    
4386
120k
    }
4387
    
4388
123k
  }
4389
           
4390
/*****************************************************************************/