Coverage Report

Created: 2026-08-31 06:33

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
214k
  : fImageDescription ()
31
214k
  , fMake             ()
32
214k
  , fModel            ()
33
214k
  , fSoftware         ()
34
214k
  , fArtist           ()
35
214k
  , fCopyright        ()
36
214k
  , fCopyright2       ()
37
214k
  , fUserComment      ()
38
39
214k
  , fDateTime            ()
40
214k
  , fDateTimeStorageInfo ()
41
  
42
214k
  , fDateTimeOriginal  ()
43
214k
  , fDateTimeOriginalStorageInfo ()
44
  
45
214k
  , fDateTimeDigitized ()
46
214k
  , fDateTimeDigitizedStorageInfo ()
47
    
48
214k
  , fTIFF_EP_StandardID (0)
49
214k
  , fExifVersion        (0)
50
214k
  , fFlashPixVersion  (0)
51
  
52
214k
  , fExposureTime      ()
53
214k
  , fFNumber           ()
54
214k
  , fShutterSpeedValue ()
55
214k
  , fApertureValue     ()
56
214k
  , fBrightnessValue   ()
57
214k
  , fExposureBiasValue ()
58
214k
  , fMaxApertureValue  ()
59
214k
  , fFocalLength       ()
60
214k
  , fDigitalZoomRatio  ()
61
214k
  , fExposureIndex     ()
62
214k
  , fSubjectDistance   ()
63
214k
  , fGamma             ()
64
    
65
214k
  , fBatteryLevelR ()
66
214k
  , fBatteryLevelA ()
67
    
68
214k
  , fExposureProgram      (0xFFFFFFFF)
69
214k
  , fMeteringMode         (0xFFFFFFFF)
70
214k
  , fLightSource          (0xFFFFFFFF)
71
214k
  , fFlash            (0xFFFFFFFF)
72
214k
  , fFlashMask        (0x0000FFFF)
73
214k
  , fSensingMethod        (0xFFFFFFFF)
74
214k
  , fColorSpace           (0xFFFFFFFF)
75
214k
  , fFileSource           (0xFFFFFFFF)
76
214k
  , fSceneType          (0xFFFFFFFF)
77
214k
  , fCustomRendered       (0xFFFFFFFF)
78
214k
  , fExposureMode       (0xFFFFFFFF)
79
214k
  , fWhiteBalance         (0xFFFFFFFF)
80
214k
  , fSceneCaptureType     (0xFFFFFFFF)
81
214k
  , fGainControl      (0xFFFFFFFF)
82
214k
  , fContrast         (0xFFFFFFFF)
83
214k
  , fSaturation       (0xFFFFFFFF)
84
214k
  , fSharpness        (0xFFFFFFFF)
85
214k
  , fSubjectDistanceRange (0xFFFFFFFF)
86
214k
  , fSelfTimerMode      (0xFFFFFFFF)
87
214k
  , fImageNumber      (0xFFFFFFFF)
88
  
89
214k
  , fFocalLengthIn35mmFilm (0)
90
91
214k
  , fSensitivityType       (0)
92
214k
  , fStandardOutputSensitivity (0)
93
214k
  , fRecommendedExposureIndex  (0)
94
214k
  , fISOSpeed          (0)
95
214k
  , fISOSpeedLatitudeyyy     (0)
96
214k
  , fISOSpeedLatitudezzz     (0)
97
98
214k
  , fSubjectAreaCount (0)
99
  
100
214k
  , fComponentsConfiguration (0)
101
  
102
214k
  , fCompresssedBitsPerPixel ()
103
  
104
214k
  , fPixelXDimension (0)
105
214k
  , fPixelYDimension (0)
106
  
107
214k
  , fFocalPlaneXResolution ()
108
214k
  , fFocalPlaneYResolution ()
109
    
110
214k
  , fFocalPlaneResolutionUnit (0xFFFFFFFF)
111
  
112
214k
  , fCFARepeatPatternRows (0)
113
214k
  , fCFARepeatPatternCols (0)
114
  
115
214k
  , fImageUniqueID ()
116
  
117
214k
  , fGPSVersionID     (0)
118
214k
  , fGPSLatitudeRef     ()
119
214k
  , fGPSLongitudeRef    ()
120
214k
  , fGPSAltitudeRef     (0xFFFFFFFF)
121
214k
  , fGPSAltitude      ()
122
214k
  , fGPSSatellites      ()
123
214k
  , fGPSStatus        ()
124
214k
  , fGPSMeasureMode     ()
125
214k
  , fGPSDOP         ()
126
214k
  , fGPSSpeedRef      ()
127
214k
  , fGPSSpeed       ()
128
214k
  , fGPSTrackRef      ()
129
214k
  , fGPSTrack       ()
130
214k
  , fGPSImgDirectionRef   ()
131
214k
  , fGPSImgDirection    ()
132
214k
  , fGPSMapDatum      ()
133
214k
  , fGPSDestLatitudeRef   ()
134
214k
  , fGPSDestLongitudeRef  ()
135
214k
  , fGPSDestBearingRef    ()
136
214k
  , fGPSDestBearing     ()
137
214k
  , fGPSDestDistanceRef   ()
138
214k
  , fGPSDestDistance    ()
139
214k
  , fGPSProcessingMethod  ()
140
214k
  , fGPSAreaInformation   ()
141
214k
  , fGPSDateStamp     ()
142
214k
  , fGPSDifferential    (0xFFFFFFFF)
143
214k
  , fGPSHPositioningError ()
144
  
145
214k
  , fInteroperabilityIndex ()
146
147
214k
  , fInteroperabilityVersion (0)
148
  
149
214k
  , fRelatedImageFileFormat ()
150
  
151
214k
  , fRelatedImageWidth  (0)
152
214k
  , fRelatedImageLength (0)
153
  
154
214k
  , fCameraSerialNumber ()
155
  
156
214k
  , fLensID       ()
157
214k
  , fLensMake     ()
158
214k
  , fLensName     ()
159
214k
  , fLensSerialNumber ()
160
  
161
214k
  , fLensNameWasReadFromExif (false)
162
163
214k
  , fApproxFocusDistance ()
164
165
214k
  , fFlashCompensation ()
166
  
167
214k
  , fOwnerName ()
168
214k
  , fFirmware  ()
169
  
170
214k
  {
171
  
172
214k
  uint32 j;
173
214k
  uint32 k;
174
  
175
214k
  fISOSpeedRatings [0] = 0;
176
214k
  fISOSpeedRatings [1] = 0;
177
214k
  fISOSpeedRatings [2] = 0;
178
  
179
1.93M
  for (j = 0; j < kMaxCFAPattern; j++)
180
15.4M
    for (k = 0; k < kMaxCFAPattern; k++)
181
13.7M
      {
182
13.7M
      fCFAPattern [j] [k] = 255;
183
13.7M
      }
184
    
185
214k
  }
186
  
187
/*****************************************************************************/
188
189
dng_exif::~dng_exif ()
190
281k
  {
191
  
192
281k
  }
193
    
194
/*****************************************************************************/
195
196
dng_exif * dng_exif::Clone () const
197
62.8k
  {
198
  
199
62.8k
  dng_exif *result = new dng_exif (*this);
200
  
201
62.8k
  if (!result)
202
0
    {
203
0
    ThrowMemoryFull ();
204
0
    }
205
  
206
62.8k
  return result;
207
  
208
62.8k
  }
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
18.0k
  {
275
  
276
  // Protection against invalid values.
277
  
278
18.0k
  if (et <= 0.0)
279
2.58k
    return 0.0;
280
  
281
  // If near a standard shutter speed, snap to it.
282
  
283
15.4k
  static const real64 kStandardSpeed [] =
284
15.4k
    {
285
15.4k
    30.0,
286
15.4k
    25.0,
287
15.4k
    20.0,
288
15.4k
    15.0,
289
15.4k
    13.0,
290
15.4k
    10.0,
291
15.4k
    8.0,
292
15.4k
    6.0,
293
15.4k
    5.0,
294
15.4k
    4.0,
295
15.4k
    3.2,
296
15.4k
    3.0,
297
15.4k
    2.5,
298
15.4k
    2.0,
299
15.4k
    1.6,
300
15.4k
    1.5,
301
15.4k
    1.3,
302
15.4k
    1.0,
303
15.4k
    0.8,
304
15.4k
    0.7,
305
15.4k
    0.6,
306
15.4k
    0.5,
307
15.4k
    0.4,
308
15.4k
    0.3,
309
15.4k
    1.0 / 4.0,
310
15.4k
    1.0 / 5.0,
311
15.4k
    1.0 / 6.0,
312
15.4k
    1.0 / 8.0,
313
15.4k
    1.0 / 10.0,
314
15.4k
    1.0 / 13.0,
315
15.4k
    1.0 / 15.0,
316
15.4k
    1.0 / 20.0,
317
15.4k
    1.0 / 25.0,
318
15.4k
    1.0 / 30.0,
319
15.4k
    1.0 / 40.0,
320
15.4k
    1.0 / 45.0,
321
15.4k
    1.0 / 50.0,
322
15.4k
    1.0 / 60.0,
323
15.4k
    1.0 / 80.0,
324
15.4k
    1.0 / 90.0,
325
15.4k
    1.0 / 100.0,
326
15.4k
    1.0 / 125.0,
327
15.4k
    1.0 / 160.0,
328
15.4k
    1.0 / 180.0,
329
15.4k
    1.0 / 200.0,
330
15.4k
    1.0 / 250.0,
331
15.4k
    1.0 / 320.0,
332
15.4k
    1.0 / 350.0,
333
15.4k
    1.0 / 400.0,
334
15.4k
    1.0 / 500.0,
335
15.4k
    1.0 / 640.0,
336
15.4k
    1.0 / 750.0,
337
15.4k
    1.0 / 800.0,
338
15.4k
    1.0 / 1000.0,
339
15.4k
    1.0 / 1250.0,
340
15.4k
    1.0 / 1500.0,
341
15.4k
    1.0 / 1600.0,
342
15.4k
    1.0 / 2000.0,
343
15.4k
    1.0 / 2500.0,
344
15.4k
    1.0 / 3000.0,
345
15.4k
    1.0 / 3200.0,
346
15.4k
    1.0 / 4000.0,
347
15.4k
    1.0 / 5000.0,
348
15.4k
    1.0 / 6000.0,
349
15.4k
    1.0 / 6400.0,
350
15.4k
    1.0 / 8000.0,
351
15.4k
    1.0 / 10000.0,
352
15.4k
    1.0 / 12000.0,
353
15.4k
    1.0 / 12800.0,
354
15.4k
    1.0 / 16000.0
355
15.4k
    };
356
    
357
15.4k
  uint32 count = sizeof (kStandardSpeed    ) /
358
15.4k
           sizeof (kStandardSpeed [0]);
359
             
360
32.3k
  for (uint32 fudge = 0; fudge <= 1; fudge++)
361
27.5k
    {
362
    
363
27.5k
    real64 testSpeed = et;
364
    
365
27.5k
    if (fudge == 1)
366
12.0k
      {
367
      
368
      // Often APEX values are rounded to a power of two,
369
      // which results in non-standard shutter speeds.
370
      
371
12.0k
      if (et >= 0.1)
372
6.47k
        {
373
        
374
        // No fudging slower than 1/10 second
375
        
376
6.47k
        break;
377
        
378
6.47k
        }
379
      
380
5.60k
      else if (et >= 0.01)
381
872
        {
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
872
        testSpeed *= 16.0 / 15.0;
389
        
390
872
        }
391
        
392
4.73k
      else
393
4.73k
        {
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.73k
        testSpeed *= 128.0 / 125.0;
400
        
401
4.73k
        }
402
      
403
12.0k
      }
404
      
405
1.30M
    for (uint32 index = 0; index < count; index++)
406
1.28M
      {
407
      
408
1.28M
      if (testSpeed >= kStandardSpeed [index] * 0.98 &&
409
550k
        testSpeed <= kStandardSpeed [index] * 1.02)
410
4.23k
        {
411
        
412
4.23k
        return kStandardSpeed [index];
413
        
414
4.23k
        }
415
        
416
1.28M
      }
417
      
418
21.0k
    }
419
    
420
  // We are not near any standard speeds.  Round the non-standard value to something
421
  // that looks reasonable.
422
  
423
11.2k
  if (et >= 10.0)
424
3.25k
    {
425
    
426
    // Round to nearest second.
427
    
428
3.25k
    et = floor (et + 0.5);
429
    
430
3.25k
    }
431
    
432
7.98k
  else if (et >= 0.5)
433
1.80k
    {
434
    
435
    // Round to nearest 1/10 second
436
    
437
1.80k
    et = floor (et * 10.0 + 0.5) * 0.1;
438
    
439
1.80k
    }
440
    
441
6.18k
  else if (et >= 1.0 / 20.0)
442
1.54k
    {
443
    
444
    // Round to an exact inverse.
445
    
446
1.54k
    et = 1.0 / floor (1.0 / et + 0.5);
447
    
448
1.54k
    }
449
    
450
4.63k
  else if (et >= 1.0 / 130.0)
451
874
    {
452
    
453
    // Round inverse to multiple of 5
454
    
455
874
    et = 0.2 / floor (0.2 / et + 0.5);
456
    
457
874
    }
458
    
459
3.76k
  else if (et >= 1.0 / 750.0)
460
897
    {
461
    
462
    // Round inverse to multiple of 10
463
    
464
897
    et = 0.1 / floor (0.1 / et + 0.5);
465
    
466
897
    }
467
    
468
2.86k
  else if (et >= 1.0 / 1300.0)
469
639
    {
470
    
471
    // Round inverse to multiple of 50
472
    
473
639
    et = 0.02 / floor (0.02 / et + 0.5);
474
    
475
639
    }
476
    
477
2.22k
  else if (et >= 1.0 / 15000.0)
478
771
    {
479
    
480
    // Round inverse to multiple of 100
481
    
482
771
    et = 0.01 / floor (0.01 / et + 0.5);
483
    
484
771
    }
485
    
486
1.45k
  else
487
1.45k
    {
488
    
489
    // Round inverse to multiple of 1000
490
    
491
1.45k
    et = 0.001 / floor (0.001 / et + 0.5);
492
    
493
1.45k
    }
494
    
495
11.2k
  return et;
496
  
497
15.4k
  }
498
499
/*****************************************************************************/
500
501
void dng_exif::SetExposureTime (real64 et, bool snap)
502
18.0k
  {
503
  
504
18.0k
  fExposureTime.Clear ();
505
  
506
18.0k
  fShutterSpeedValue.Clear ();
507
  
508
18.0k
  if (snap)
509
18.0k
    {
510
    
511
18.0k
    et = SnapExposureTime (et);
512
    
513
18.0k
    }
514
    
515
18.0k
  if (et >= 1.0 / 32768.0 && et <= 32768.0)
516
12.8k
    {
517
    
518
12.8k
    if (et >= 100.0)
519
1.04k
      {
520
      
521
1.04k
      fExposureTime.Set_real64 (et, 1);
522
      
523
1.04k
      }
524
      
525
11.7k
    else if (et >= 1.0)
526
3.64k
      {
527
      
528
3.64k
      fExposureTime.Set_real64 (et, 10);
529
      
530
3.64k
      fExposureTime.ReduceByFactor (10);
531
      
532
3.64k
      }
533
      
534
8.13k
    else if (et <= 0.1)
535
4.49k
      {
536
      
537
4.49k
      fExposureTime = dng_urational (1, Round_uint32 (1.0 / et));
538
      
539
4.49k
      }
540
      
541
3.64k
    else
542
3.64k
      {
543
      
544
3.64k
      fExposureTime.Set_real64 (et, 100);
545
      
546
3.64k
      fExposureTime.ReduceByFactor (10);
547
        
548
20.0k
      for (uint32 f = 2; f <= 9; f++)
549
18.6k
        {
550
        
551
18.6k
        real64 z = 1.0 / (real64) f / et;
552
        
553
18.6k
        if (z >= 0.99 && z <= 1.01)
554
2.23k
          {
555
          
556
2.23k
          fExposureTime = dng_urational (1, f);
557
          
558
2.23k
          break;
559
          
560
2.23k
          }
561
        
562
18.6k
        }
563
          
564
3.64k
      }
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
18.0k
  }
582
583
/*****************************************************************************/
584
585
void dng_exif::SetShutterSpeedValue (real64 ss)
586
4.58k
  {
587
  
588
4.58k
  if (fExposureTime.NotValid ())
589
2.57k
    {
590
    
591
2.57k
    real64 et = pow (2.0, -ss);
592
    
593
2.57k
    SetExposureTime (et, true);
594
    
595
2.57k
    }
596
  
597
4.58k
  }
598
599
/******************************************************************************/
600
601
dng_urational dng_exif::EncodeFNumber (real64 fs)
602
9.69k
  {
603
  
604
9.69k
  dng_urational y;
605
606
9.69k
  if (fs > 10.0)
607
1.96k
    {
608
    
609
1.96k
    y.Set_real64 (fs, 1);
610
    
611
1.96k
    }
612
    
613
7.72k
  else if (fs < 1.0)
614
4.50k
    {
615
    
616
4.50k
    y.Set_real64 (fs, 100);
617
    
618
4.50k
    y.ReduceByFactor (10);
619
4.50k
    y.ReduceByFactor (10);
620
    
621
4.50k
    }
622
    
623
3.22k
  else
624
3.22k
    {
625
    
626
3.22k
    y.Set_real64 (fs, 10);
627
    
628
3.22k
    y.ReduceByFactor (10);
629
    
630
3.22k
    }
631
    
632
9.69k
  return y;
633
      
634
9.69k
  }
635
    
636
/*****************************************************************************/
637
638
void dng_exif::SetFNumber (real64 fs)
639
14.9k
  {
640
  
641
14.9k
  fFNumber.Clear ();
642
  
643
14.9k
  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
14.9k
  if (fs > 0.0 && fs <= 32768.0)
651
9.69k
    {
652
  
653
9.69k
    fFNumber = EncodeFNumber (fs);
654
    
655
    // Now mirror this value to the ApertureValue field.
656
    
657
9.69k
    real64 av = FNumberToApertureValue (fFNumber);
658
659
9.69k
    if (av >= 0.0 && av <= 99.99)
660
5.61k
      {
661
      
662
5.61k
      fApertureValue.Set_real64 (av, 1000000);
663
      
664
5.61k
      fApertureValue.ReduceByFactor (10);                 
665
5.61k
      fApertureValue.ReduceByFactor (10);                 
666
5.61k
      fApertureValue.ReduceByFactor (10);                 
667
5.61k
      fApertureValue.ReduceByFactor (10);                 
668
5.61k
      fApertureValue.ReduceByFactor (10);                 
669
5.61k
      fApertureValue.ReduceByFactor (10);                 
670
      
671
5.61k
      }
672
    
673
9.69k
    }
674
  
675
14.9k
  }
676
      
677
/*****************************************************************************/
678
679
void dng_exif::SetApertureValue (real64 av)
680
4.01k
  {
681
682
4.01k
  if (fFNumber.NotValid ())
683
1.73k
    {
684
    
685
1.73k
    SetFNumber (ApertureValueToFNumber (av));
686
            
687
1.73k
    }
688
    
689
4.01k
  }
690
691
/*****************************************************************************/
692
693
real64 dng_exif::ApertureValueToFNumber (real64 av)
694
1.73k
  {
695
  
696
1.73k
  return pow (2.0, 0.5 * av);
697
  
698
1.73k
  }
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
9.69k
  {
713
  
714
9.69k
  return 2.0 * log (fNumber) / log (2.0);
715
  
716
9.69k
  }
717
718
/*****************************************************************************/
719
720
real64 dng_exif::FNumberToApertureValue (const dng_urational &fNumber)
721
9.69k
  {
722
  
723
9.69k
  return FNumberToApertureValue (fNumber.As_real64 ());
724
  
725
9.69k
  }
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
134k
  {
740
  
741
134k
  uint32 b0 = (fExifVersion >> 24) & 0xff;
742
134k
  uint32 b1 = (fExifVersion >> 16) & 0xff;
743
134k
  uint32 b2 = (fExifVersion >>  8) & 0xff;
744
745
134k
  return (b0 > 0) || (b1 >= 2 && b2 >= 3);
746
  
747
134k
  }
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.10M
  {
760
  
761
3.10M
  if (parentCode == 0)
762
1.32M
    {
763
    
764
1.32M
    if (Parse_ifd0 (stream,
765
1.32M
            shared,
766
1.32M
            parentCode,
767
1.32M
            tagCode,
768
1.32M
            tagType,
769
1.32M
            tagCount,
770
1.32M
            tagOffset))
771
107k
      {
772
      
773
107k
      return true;
774
      
775
107k
      }
776
777
1.32M
    }
778
    
779
2.99M
  if (parentCode == 0 || isMainIFD)
780
1.60M
    {
781
    
782
1.60M
    if (Parse_ifd0_main (stream,
783
1.60M
                 shared,
784
1.60M
               parentCode,
785
1.60M
               tagCode,
786
1.60M
               tagType,
787
1.60M
               tagCount,
788
1.60M
               tagOffset))
789
10.2k
      {
790
      
791
10.2k
      return true;
792
      
793
10.2k
      }
794
795
1.60M
    }
796
    
797
2.98M
  if (parentCode == 0 ||
798
1.76M
    parentCode == tcExifIFD)
799
1.32M
    {
800
    
801
1.32M
    if (Parse_ifd0_exif (stream,
802
1.32M
                 shared,
803
1.32M
               parentCode,
804
1.32M
               tagCode,
805
1.32M
               tagType,
806
1.32M
               tagCount,
807
1.32M
               tagOffset))
808
268k
      {
809
      
810
268k
      return true;
811
      
812
268k
      }
813
814
1.32M
    }
815
    
816
2.71M
  if (parentCode == tcGPSInfo)
817
172k
    {
818
    
819
172k
    if (Parse_gps (stream,
820
172k
             shared,
821
172k
             parentCode,
822
172k
             tagCode,
823
172k
             tagType,
824
172k
             tagCount,
825
172k
             tagOffset))
826
63.0k
      {
827
      
828
63.0k
      return true;
829
      
830
63.0k
      }
831
832
172k
    }
833
    
834
2.65M
  if (parentCode == tcInteroperabilityIFD)
835
1.66k
    {
836
    
837
1.66k
    if (Parse_interoperability (stream,
838
1.66k
                    shared,
839
1.66k
                  parentCode,
840
1.66k
                  tagCode,
841
1.66k
                  tagType,
842
1.66k
                  tagCount,
843
1.66k
                  tagOffset))
844
902
      {
845
      
846
902
      return true;
847
      
848
902
      }
849
850
1.66k
    }
851
    
852
2.65M
  return false;
853
    
854
2.65M
  }
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.32M
  {
868
  
869
1.32M
  switch (tagCode)
870
1.32M
    {
871
      
872
2.23k
    case tcImageDescription:
873
2.23k
      {
874
      
875
2.23k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
876
      
877
2.23k
      ParseStringTag (stream,
878
2.23k
              parentCode,
879
2.23k
              tagCode,
880
2.23k
              tagCount,
881
2.23k
              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.23k
      break;
899
      
900
0
      }
901
      
902
4.26k
    case tcMake:
903
4.26k
      {
904
      
905
4.26k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
906
      
907
4.26k
      ParseStringTag (stream,
908
4.26k
              parentCode,
909
4.26k
              tagCode,
910
4.26k
              tagCount,
911
4.26k
              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
4.26k
      break;
929
      
930
0
      }
931
        
932
11.5k
    case tcModel:
933
11.5k
      {
934
935
11.5k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
936
      
937
11.5k
      ParseStringTag (stream,
938
11.5k
              parentCode,
939
11.5k
              tagCode,
940
11.5k
              tagCount,
941
11.5k
              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
11.5k
      break;
959
      
960
0
      }
961
        
962
15.4k
    case tcSoftware:
963
15.4k
      {
964
      
965
15.4k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
966
      
967
15.4k
      ParseStringTag (stream,
968
15.4k
              parentCode,
969
15.4k
              tagCode,
970
15.4k
              tagCount,
971
15.4k
              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
15.4k
      break;
989
      
990
0
      }
991
992
21.1k
    case tcDateTime:
993
21.1k
      {
994
      
995
21.1k
      uint64 tagPosition = stream.PositionInOriginalFile ();
996
      
997
21.1k
      dng_date_time dt;
998
        
999
21.1k
      if (!ParseDateTimeTag (stream,
1000
21.1k
                   parentCode,
1001
21.1k
                   tagCode,
1002
21.1k
                   tagType,
1003
21.1k
                   tagCount,
1004
21.1k
                   dt))
1005
14.5k
        {
1006
14.5k
        return false;
1007
14.5k
        }
1008
        
1009
6.63k
      fDateTime.SetDateTime (dt);
1010
        
1011
6.63k
      fDateTimeStorageInfo = dng_date_time_storage_info (tagPosition,
1012
6.63k
                                 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
6.63k
      break;
1030
      
1031
21.1k
      }
1032
1033
2.40k
    case tcArtist:
1034
2.40k
      {
1035
      
1036
2.40k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
1037
      
1038
2.40k
      ParseStringTag (stream,
1039
2.40k
              parentCode,
1040
2.40k
              tagCode,
1041
2.40k
              tagCount,
1042
2.40k
              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
2.40k
      break;
1060
      
1061
21.1k
      }
1062
1063
27.3k
    case tcCopyright:
1064
27.3k
      {
1065
      
1066
27.3k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
1067
      
1068
27.3k
      ParseDualStringTag (stream,
1069
27.3k
                parentCode,
1070
27.3k
                tagCode,
1071
27.3k
                tagCount,
1072
27.3k
                fCopyright,
1073
27.3k
                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
27.3k
      break;
1100
      
1101
21.1k
      }
1102
1103
26.9k
    case tcTIFF_EP_StandardID:
1104
26.9k
      {
1105
      
1106
26.9k
      CheckTagType (parentCode, tagCode, tagType, ttByte);
1107
      
1108
26.9k
      CheckTagCount (parentCode, tagCode, tagCount, 4);
1109
      
1110
26.9k
      uint32 b0 = stream.Get_uint8 ();
1111
26.9k
      uint32 b1 = stream.Get_uint8 ();
1112
26.9k
      uint32 b2 = stream.Get_uint8 ();
1113
26.9k
      uint32 b3 = stream.Get_uint8 ();
1114
      
1115
26.9k
      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
26.9k
      break;
1131
      
1132
21.1k
      }
1133
        
1134
4.39k
    case tcCameraSerialNumber:
1135
4.64k
    case tcKodakCameraSerialNumber:   // Kodak uses a very similar tag.
1136
4.64k
      {
1137
      
1138
4.64k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
1139
      
1140
4.64k
      ParseStringTag (stream,
1141
4.64k
              parentCode,
1142
4.64k
              tagCode,
1143
4.64k
              tagCount,
1144
4.64k
              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
4.64k
      break;
1162
      
1163
4.39k
      }
1164
      
1165
10.1k
    case tcLensInfo:
1166
10.1k
      {
1167
      
1168
10.1k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
1169
      
1170
10.1k
      if (!CheckTagCount (parentCode, tagCode, tagCount, 4))
1171
3.64k
        return false;
1172
        
1173
6.53k
      fLensInfo [0] = stream.TagValue_urational (tagType);
1174
6.53k
      fLensInfo [1] = stream.TagValue_urational (tagType);
1175
6.53k
      fLensInfo [2] = stream.TagValue_urational (tagType);
1176
6.53k
      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
32.3k
      for (uint32 j = 0; j < 4; j++)
1182
25.7k
        {
1183
      
1184
25.7k
        if (fLensInfo [j].IsValid () && fLensInfo [j].As_real64 () <= 0.0)
1185
11.2k
          {
1186
          
1187
11.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
11.2k
          }
1196
          
1197
25.7k
        }
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
6.53k
      break;
1234
      
1235
10.1k
      }
1236
        
1237
1.20M
    default:
1238
1.20M
      {
1239
      
1240
1.20M
      return false;
1241
      
1242
10.1k
      }
1243
      
1244
1.32M
    }
1245
  
1246
107k
  return true;
1247
  
1248
1.32M
  }
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.60M
  {
1262
  
1263
1.60M
  switch (tagCode)
1264
1.60M
    {
1265
      
1266
3.15k
    case tcFocalPlaneXResolution:
1267
3.15k
      {
1268
1269
3.15k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
1270
      
1271
3.15k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1272
      
1273
3.15k
      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
3.15k
      break;
1288
      
1289
0
      }
1290
      
1291
1.52k
    case tcFocalPlaneYResolution:
1292
1.52k
      {
1293
1294
1.52k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
1295
      
1296
1.52k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1297
      
1298
1.52k
      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.52k
      break;
1313
      
1314
0
      }
1315
      
1316
2.28k
    case tcFocalPlaneResolutionUnit:
1317
2.28k
      {
1318
      
1319
2.28k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
1320
      
1321
2.28k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1322
      
1323
2.28k
      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.28k
      break;
1338
      
1339
0
      }
1340
1341
3.27k
    case tcSensingMethod:
1342
3.27k
      {
1343
      
1344
3.27k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
1345
      
1346
3.27k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1347
      
1348
3.27k
      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
3.27k
      break;
1363
      
1364
0
      }
1365
      
1366
1.59M
    default:
1367
1.59M
      {
1368
      
1369
1.59M
      return false;
1370
      
1371
0
      }
1372
      
1373
1.60M
    }
1374
    
1375
10.2k
  return true;
1376
  
1377
1.60M
  }
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.32M
  {
1391
  
1392
1.32M
  switch (tagCode)
1393
1.32M
    {
1394
    
1395
1.65k
    case tcBatteryLevel:
1396
1.65k
      {
1397
      
1398
1.65k
      CheckTagType (parentCode, tagCode, tagType, ttRational, ttAscii);
1399
      
1400
1.65k
      if (tagType == ttAscii)
1401
812
        {
1402
        
1403
812
        ParseStringTag (stream,
1404
812
                parentCode,
1405
812
                tagCode,
1406
812
                tagCount,
1407
812
                fBatteryLevelA);
1408
      
1409
812
        }
1410
        
1411
842
      else
1412
842
        {
1413
      
1414
842
        CheckTagCount (parentCode, tagCode, tagCount, 1);
1415
        
1416
842
        fBatteryLevelR = stream.TagValue_urational (tagType);
1417
        
1418
842
        }
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.65k
      break;
1448
      
1449
0
      }
1450
    
1451
15.5k
    case tcExposureTime:
1452
15.5k
      {
1453
      
1454
15.5k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
1455
      
1456
15.5k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1457
      
1458
15.5k
      dng_urational et = stream.TagValue_urational (tagType);
1459
      
1460
15.5k
      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
15.5k
      break;
1485
      
1486
0
      }
1487
1488
13.2k
    case tcFNumber:
1489
13.2k
      {
1490
      
1491
13.2k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
1492
      
1493
13.2k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1494
      
1495
13.2k
      dng_urational fs = stream.TagValue_urational (tagType);
1496
      
1497
      // Sometimes "unknown" is recorded as zero.
1498
      
1499
13.2k
      if (fs.As_real64 () <= 0.0)
1500
3.70k
        {
1501
3.70k
        fs.Clear ();
1502
3.70k
        }
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.2k
      SetFNumber (fs.As_real64 ());
1517
      
1518
13.2k
      break;
1519
      
1520
0
      }
1521
1522
11.2k
    case tcExposureProgram:
1523
11.2k
      {
1524
      
1525
11.2k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
1526
      
1527
11.2k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1528
      
1529
11.2k
      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
11.2k
      break;
1544
      
1545
0
      }
1546
1547
8.39k
    case tcISOSpeedRatings:
1548
8.39k
      {
1549
      
1550
8.39k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
1551
      
1552
8.39k
      CheckTagCount (parentCode, tagCode, tagCount, 1, 3);
1553
      
1554
23.8k
      for (uint32 j = 0; j < tagCount && j < 3; j++)
1555
15.4k
        {
1556
        
1557
15.4k
        fISOSpeedRatings [j] = stream.TagValue_uint32 (tagType);
1558
        
1559
15.4k
        }
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
8.39k
      break;
1582
      
1583
0
      }
1584
      
1585
4.49k
    case tcSensitivityType:
1586
4.49k
      {
1587
      
1588
4.49k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
1589
      
1590
4.49k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1591
1592
4.49k
      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
4.49k
      break;
1607
      
1608
0
      }
1609
      
1610
1.55k
    case tcStandardOutputSensitivity:
1611
1.55k
      {
1612
      
1613
1.55k
      CheckTagType (parentCode, tagCode, tagType, ttLong);
1614
      
1615
1.55k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1616
1617
1.55k
      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
1.55k
      break;
1632
      
1633
0
      }
1634
      
1635
1.66k
    case tcRecommendedExposureIndex:
1636
1.66k
      {
1637
      
1638
1.66k
      CheckTagType (parentCode, tagCode, tagType, ttLong);
1639
      
1640
1.66k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1641
1642
1.66k
      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
1.66k
      break;
1657
      
1658
0
      }
1659
      
1660
936
    case tcISOSpeed:
1661
936
      {
1662
      
1663
936
      CheckTagType (parentCode, tagCode, tagType, ttLong);
1664
      
1665
936
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1666
1667
936
      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
936
      break;
1682
      
1683
0
      }
1684
      
1685
899
    case tcISOSpeedLatitudeyyy:
1686
899
      {
1687
      
1688
899
      CheckTagType (parentCode, tagCode, tagType, ttLong);
1689
      
1690
899
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1691
1692
899
      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
899
      break;
1707
      
1708
0
      }
1709
      
1710
1.66k
    case tcISOSpeedLatitudezzz:
1711
1.66k
      {
1712
      
1713
1.66k
      CheckTagType (parentCode, tagCode, tagType, ttLong);
1714
      
1715
1.66k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1716
1717
1.66k
      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
1.66k
      break;
1732
      
1733
0
      }
1734
      
1735
1.60k
    case tcTimeZoneOffset:
1736
1.60k
      {
1737
      
1738
1.60k
      CheckTagType (parentCode, tagCode, tagType, ttSShort);
1739
      
1740
1.60k
      CheckTagCount (parentCode, tagCode, tagCount, 1, 2);
1741
      
1742
1.60k
      dng_time_zone zoneOriginal;
1743
      
1744
1.60k
      zoneOriginal.SetOffsetHours (stream.TagValue_int32 (tagType));
1745
      
1746
1.60k
      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.60k
      dng_time_zone zoneCurrent;
1758
1759
1.60k
      if (tagCount >= 2)
1760
1.00k
        {
1761
        
1762
1.00k
        zoneCurrent.SetOffsetHours (stream.TagValue_int32 (tagType));
1763
        
1764
1.00k
        fDateTime.SetZone (zoneCurrent);
1765
        
1766
1.00k
        }
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.60k
      break;
1791
      
1792
0
      }
1793
1794
1.63k
    case tcSelfTimerMode:
1795
1.63k
      {
1796
      
1797
1.63k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
1798
      
1799
1.63k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1800
      
1801
1.63k
      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.63k
      break;
1831
      
1832
0
      }
1833
1834
14.8k
    case tcExifVersion:
1835
14.8k
      {
1836
      
1837
14.8k
      CheckTagType (parentCode, tagCode, tagType, ttUndefined);
1838
      
1839
14.8k
      CheckTagCount (parentCode, tagCode, tagCount, 4);
1840
      
1841
14.8k
      uint32 b0 = stream.Get_uint8 ();
1842
14.8k
      uint32 b1 = stream.Get_uint8 ();
1843
14.8k
      uint32 b2 = stream.Get_uint8 ();
1844
14.8k
      uint32 b3 = stream.Get_uint8 ();
1845
      
1846
14.8k
      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
14.8k
      break;
1865
      
1866
0
      }
1867
1868
12.6k
    case tcDateTimeOriginal:
1869
12.6k
      {
1870
      
1871
12.6k
      uint64 tagPosition = stream.PositionInOriginalFile ();
1872
      
1873
12.6k
      dng_date_time dt;
1874
      
1875
12.6k
      if (!ParseDateTimeTag (stream,
1876
12.6k
                   parentCode,
1877
12.6k
                   tagCode,
1878
12.6k
                   tagType,
1879
12.6k
                   tagCount,
1880
12.6k
                   dt))
1881
6.49k
        {
1882
6.49k
        return false;
1883
6.49k
        }
1884
        
1885
6.15k
      fDateTimeOriginal.SetDateTime (dt);
1886
      
1887
6.15k
      fDateTimeOriginalStorageInfo = dng_date_time_storage_info (tagPosition,
1888
6.15k
                                     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
6.15k
      break;
1906
      
1907
12.6k
      }
1908
1909
12.8k
    case tcDateTimeDigitized:
1910
12.8k
      {
1911
      
1912
12.8k
      uint64 tagPosition = stream.PositionInOriginalFile ();
1913
      
1914
12.8k
      dng_date_time dt;
1915
      
1916
12.8k
      if (!ParseDateTimeTag (stream,
1917
12.8k
                   parentCode,
1918
12.8k
                   tagCode,
1919
12.8k
                   tagType,
1920
12.8k
                   tagCount,
1921
12.8k
                   dt))
1922
8.35k
        {
1923
8.35k
        return false;
1924
8.35k
        }
1925
        
1926
4.52k
      fDateTimeDigitized.SetDateTime (dt);
1927
      
1928
4.52k
      fDateTimeDigitizedStorageInfo = dng_date_time_storage_info (tagPosition,
1929
4.52k
                                      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.52k
      break;
1947
      
1948
12.8k
      }
1949
      
1950
6.01k
    case tcComponentsConfiguration:
1951
6.01k
      {
1952
      
1953
6.01k
      CheckTagType (parentCode, tagCode, tagType, ttUndefined);
1954
      
1955
6.01k
      CheckTagCount (parentCode, tagCode, tagCount, 4);
1956
      
1957
6.01k
      uint32 b0 = stream.Get_uint8 ();
1958
6.01k
      uint32 b1 = stream.Get_uint8 ();
1959
6.01k
      uint32 b2 = stream.Get_uint8 ();
1960
6.01k
      uint32 b3 = stream.Get_uint8 ();
1961
      
1962
6.01k
      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.01k
      break;
1980
      
1981
12.8k
      }
1982
      
1983
1.90k
    case tcCompressedBitsPerPixel:
1984
1.90k
      {
1985
      
1986
1.90k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
1987
      
1988
1.90k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1989
      
1990
1.90k
      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
1.90k
      break;
2005
      
2006
12.8k
      }
2007
      
2008
4.60k
    case tcShutterSpeedValue:
2009
4.60k
      {
2010
      
2011
4.60k
      CheckTagType (parentCode, tagCode, tagType, ttSRational);
2012
      
2013
4.60k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2014
      
2015
4.60k
      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
4.60k
      SetShutterSpeedValue (ss.As_real64 ());
2057
        
2058
4.60k
      break;
2059
      
2060
12.8k
      }
2061
      
2062
4.01k
    case tcApertureValue:
2063
4.01k
      {
2064
      
2065
4.01k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
2066
      
2067
4.01k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2068
      
2069
4.01k
      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
4.01k
      SetApertureValue (av.As_real64 ());
2105
        
2106
4.01k
      break;
2107
      
2108
12.8k
      }
2109
      
2110
1.73k
    case tcBrightnessValue:
2111
1.73k
      {
2112
      
2113
1.73k
      CheckTagType (parentCode, tagCode, tagType, ttSRational);
2114
      
2115
1.73k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2116
      
2117
1.73k
      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
1.73k
      break;
2132
      
2133
12.8k
      }
2134
      
2135
5.68k
    case tcExposureBiasValue:
2136
5.68k
      {
2137
      
2138
5.68k
      CheckTagType (parentCode, tagCode, tagType, ttSRational);
2139
      
2140
5.68k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2141
      
2142
5.68k
      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
5.68k
      break;
2157
      
2158
12.8k
      }
2159
2160
5.96k
    case tcMaxApertureValue:
2161
5.96k
      {
2162
      
2163
5.96k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
2164
      
2165
5.96k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2166
      
2167
5.96k
      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.96k
      break;
2183
      
2184
12.8k
      }
2185
      
2186
3.22k
    case tcSubjectDistance:
2187
3.22k
      {
2188
      
2189
3.22k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
2190
      
2191
3.22k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2192
      
2193
3.22k
      fSubjectDistance = stream.TagValue_urational (tagType);
2194
2195
3.22k
      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.22k
      break;
2211
      
2212
12.8k
      }
2213
2214
7.26k
    case tcMeteringMode:
2215
7.26k
      {
2216
      
2217
7.26k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
2218
      
2219
7.26k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2220
      
2221
7.26k
      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
7.26k
      break;
2236
      
2237
12.8k
      }
2238
      
2239
6.05k
    case tcLightSource:
2240
6.05k
      {
2241
      
2242
6.05k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
2243
      
2244
6.05k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2245
      
2246
6.05k
      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.05k
      break;
2261
      
2262
12.8k
      }
2263
2264
7.18k
    case tcFlash:
2265
7.18k
      {
2266
      
2267
7.18k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
2268
      
2269
7.18k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2270
      
2271
7.18k
      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.18k
      break;
2342
      
2343
12.8k
      }
2344
      
2345
7.39k
    case tcFocalLength:
2346
7.39k
      {
2347
      
2348
7.39k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
2349
      
2350
7.39k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2351
      
2352
7.39k
      fFocalLength = stream.TagValue_urational (tagType);
2353
      
2354
      // Sometimes "unknown" is recorded as zero.
2355
      
2356
7.39k
      if (fFocalLength.As_real64 () <= 0.0)
2357
1.51k
        {
2358
1.51k
        fFocalLength.Clear ();
2359
1.51k
        }
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
7.39k
      break;
2374
      
2375
12.8k
      }
2376
      
2377
1.42k
    case tcImageNumber:
2378
1.42k
      {
2379
      
2380
1.42k
      CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
2381
      
2382
1.42k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2383
      
2384
1.42k
      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
1.42k
      break;
2396
      
2397
12.8k
      }
2398
    
2399
9.05k
    case tcExposureIndex:
2400
9.83k
    case tcExposureIndexExif:
2401
9.83k
      {
2402
      
2403
9.83k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
2404
      
2405
9.83k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2406
      
2407
9.83k
      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
9.83k
      break;
2423
      
2424
9.05k
      }
2425
      
2426
19.0k
    case tcUserComment:
2427
19.0k
      {
2428
      
2429
19.0k
      CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2430
      
2431
19.0k
      ParseEncodedStringTag (stream,
2432
19.0k
                   parentCode,
2433
19.0k
                   tagCode,
2434
19.0k
                     tagCount,
2435
19.0k
                     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
19.0k
      break;
2453
      
2454
9.05k
      }
2455
2456
917
    case tcSubsecTime:
2457
917
      {
2458
      
2459
917
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
2460
      
2461
917
      dng_string subsecs;
2462
      
2463
917
      ParseStringTag (stream,
2464
917
              parentCode,
2465
917
              tagCode,
2466
917
              tagCount,
2467
917
              subsecs);
2468
              
2469
917
      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
917
      break;
2487
      
2488
9.05k
      }
2489
2490
962
    case tcSubsecTimeOriginal:
2491
962
      {
2492
      
2493
962
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
2494
      
2495
962
      dng_string subsecs;
2496
      
2497
962
      ParseStringTag (stream,
2498
962
              parentCode,
2499
962
              tagCode,
2500
962
              tagCount,
2501
962
              subsecs);
2502
              
2503
962
      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
962
      break;
2521
      
2522
9.05k
      }
2523
2524
558
    case tcSubsecTimeDigitized:
2525
558
      {
2526
      
2527
558
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
2528
      
2529
558
      dng_string subsecs;
2530
      
2531
558
      ParseStringTag (stream,
2532
558
              parentCode,
2533
558
              tagCode,
2534
558
              tagCount,
2535
558
              subsecs);
2536
              
2537
558
      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
558
      break;
2555
      
2556
9.05k
      }
2557
      
2558
9.36k
    case tcFlashPixVersion:
2559
9.36k
      {
2560
      
2561
9.36k
      CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2562
      
2563
9.36k
      CheckTagCount (parentCode, tagCode, tagCount, 4);
2564
      
2565
9.36k
      uint32 b0 = stream.Get_uint8 ();
2566
9.36k
      uint32 b1 = stream.Get_uint8 ();
2567
9.36k
      uint32 b2 = stream.Get_uint8 ();
2568
9.36k
      uint32 b3 = stream.Get_uint8 ();
2569
      
2570
9.36k
      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
9.36k
      break;
2589
      
2590
9.05k
      }
2591
      
2592
4.25k
    case tcColorSpace:
2593
4.25k
      {
2594
      
2595
4.25k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
2596
      
2597
4.25k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2598
      
2599
4.25k
      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
4.25k
      break;
2614
      
2615
9.05k
      }
2616
      
2617
3.66k
    case tcPixelXDimension:
2618
3.66k
      {
2619
      
2620
3.66k
      CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
2621
      
2622
3.66k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2623
      
2624
3.66k
      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.66k
      break;
2636
      
2637
9.05k
      }
2638
      
2639
2.74k
    case tcPixelYDimension:
2640
2.74k
      {
2641
      
2642
2.74k
      CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
2643
      
2644
2.74k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2645
      
2646
2.74k
      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.74k
      break;
2658
      
2659
9.05k
      }
2660
2661
1.39k
    case tcFocalPlaneXResolutionExif:
2662
1.39k
      {
2663
2664
1.39k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
2665
      
2666
1.39k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2667
      
2668
1.39k
      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
1.39k
      break;
2683
      
2684
9.05k
      }
2685
      
2686
1.65k
    case tcFocalPlaneYResolutionExif:
2687
1.65k
      {
2688
2689
1.65k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
2690
      
2691
1.65k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2692
      
2693
1.65k
      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
1.65k
      break;
2708
      
2709
9.05k
      }
2710
      
2711
963
    case tcFocalPlaneResolutionUnitExif:
2712
963
      {
2713
      
2714
963
      CheckTagType (parentCode, tagCode, tagType, ttShort);
2715
      
2716
963
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2717
      
2718
963
      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
963
      break;
2733
      
2734
9.05k
      }
2735
2736
954
    case tcSensingMethodExif:
2737
954
      {
2738
      
2739
954
      CheckTagType (parentCode, tagCode, tagType, ttShort);
2740
      
2741
954
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2742
      
2743
954
      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
954
      break;
2758
      
2759
9.05k
      }
2760
      
2761
4.43k
    case tcFileSource:
2762
4.43k
      {
2763
      
2764
4.43k
      CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2765
      
2766
4.43k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2767
      
2768
4.43k
      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
4.43k
      break;
2783
      
2784
9.05k
      }
2785
      
2786
3.76k
    case tcSceneType:
2787
3.76k
      {
2788
      
2789
3.76k
      CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2790
      
2791
3.76k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2792
      
2793
3.76k
      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
3.76k
      break;
2808
      
2809
9.05k
      }
2810
      
2811
4.29k
    case tcCFAPatternExif:
2812
4.29k
      {
2813
      
2814
4.29k
      CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2815
      
2816
4.29k
      if (tagCount <= 4)
2817
1.03k
        {
2818
1.03k
        return false;
2819
1.03k
        }
2820
        
2821
3.26k
      uint32 cols = stream.Get_uint16 ();
2822
3.26k
      uint32 rows = stream.Get_uint16 ();
2823
      
2824
3.26k
      if (tagCount != 4 + cols * rows)
2825
1.79k
        {
2826
1.79k
        return false;
2827
1.79k
        }
2828
        
2829
1.46k
      if (cols < 1 || cols > kMaxCFAPattern ||
2830
1.35k
        rows < 1 || rows > kMaxCFAPattern)
2831
147
        {
2832
147
        return false;
2833
147
        }
2834
      
2835
1.31k
      fCFARepeatPatternCols = cols;
2836
1.31k
      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
3.81k
      for (uint32 j = 0; j < fCFARepeatPatternCols; j++)
2842
6.56k
        for (uint32 k = 0; k < fCFARepeatPatternRows; k++)
2843
4.06k
          {
2844
          
2845
4.06k
          fCFAPattern [k] [j] = stream.Get_uint8 ();
2846
          
2847
4.06k
          }
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.31k
      break;
2886
      
2887
1.46k
      }
2888
      
2889
2.78k
    case tcCustomRendered:
2890
2.78k
      {
2891
      
2892
2.78k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
2893
      
2894
2.78k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2895
      
2896
2.78k
      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
2.78k
      break;
2911
      
2912
1.46k
      }
2913
      
2914
2.06k
    case tcExposureMode:
2915
2.06k
      {
2916
      
2917
2.06k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
2918
      
2919
2.06k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2920
      
2921
2.06k
      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.06k
      break;
2936
      
2937
1.46k
      }
2938
      
2939
3.03k
    case tcWhiteBalance:
2940
3.03k
      {
2941
      
2942
3.03k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
2943
      
2944
3.03k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2945
      
2946
3.03k
      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.03k
      break;
2961
      
2962
1.46k
      }
2963
      
2964
2.47k
    case tcDigitalZoomRatio:
2965
2.47k
      {
2966
      
2967
2.47k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
2968
      
2969
2.47k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2970
      
2971
2.47k
      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.47k
      break;
3000
      
3001
1.46k
      }
3002
3003
2.03k
    case tcFocalLengthIn35mmFilm:
3004
2.03k
      {
3005
      
3006
2.03k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
3007
      
3008
2.03k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3009
      
3010
2.03k
      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.03k
      break;
3025
      
3026
1.46k
      }
3027
3028
3.53k
    case tcSceneCaptureType:
3029
3.53k
      {
3030
      
3031
3.53k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
3032
      
3033
3.53k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3034
      
3035
3.53k
      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.53k
      break;
3050
      
3051
1.46k
      }
3052
      
3053
2.85k
    case tcGainControl:
3054
2.85k
      {
3055
      
3056
2.85k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
3057
      
3058
2.85k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3059
      
3060
2.85k
      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
2.85k
      break;
3075
      
3076
1.46k
      }
3077
      
3078
2.13k
    case tcContrast:
3079
2.13k
      {
3080
      
3081
2.13k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
3082
      
3083
2.13k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3084
      
3085
2.13k
      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
2.13k
      break;
3100
      
3101
1.46k
      }
3102
      
3103
742
    case tcSaturation:
3104
742
      {
3105
      
3106
742
      CheckTagType (parentCode, tagCode, tagType, ttShort);
3107
      
3108
742
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3109
      
3110
742
      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
742
      break;
3125
      
3126
1.46k
      }
3127
      
3128
4.95k
    case tcSharpness:
3129
4.95k
      {
3130
      
3131
4.95k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
3132
      
3133
4.95k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3134
      
3135
4.95k
      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
4.95k
      break;
3150
      
3151
1.46k
      }
3152
      
3153
2.43k
    case tcSubjectDistanceRange:
3154
2.43k
      {
3155
      
3156
2.43k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
3157
      
3158
2.43k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3159
      
3160
2.43k
      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
2.43k
      break;
3175
      
3176
1.46k
      }
3177
      
3178
2.38k
    case tcSubjectArea:
3179
3.28k
    case tcSubjectLocation:
3180
3.28k
      {
3181
      
3182
3.28k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
3183
      
3184
3.28k
      if (!CheckTagCount (parentCode, tagCode, tagCount, 2, 4))
3185
1.79k
        {
3186
1.79k
        return false;
3187
1.79k
        }
3188
        
3189
1.48k
      if (tagCode == tcSubjectLocation)
3190
517
        {
3191
517
        CheckTagCount (parentCode, tagCode, tagCount, 2);
3192
517
        }
3193
        
3194
1.48k
      fSubjectAreaCount = tagCount;
3195
      
3196
7.26k
      for (uint32 j = 0; j < tagCount; j++)
3197
5.77k
        {
3198
        
3199
5.77k
        fSubjectArea [j] = stream.TagValue_uint32 (tagType);
3200
        
3201
5.77k
        }
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.48k
      break;
3224
      
3225
3.28k
      }
3226
      
3227
1.02k
    case tcGamma:
3228
1.02k
      {
3229
      
3230
1.02k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
3231
      
3232
1.02k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3233
      
3234
1.02k
      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
1.02k
      break;
3249
      
3250
3.28k
      }
3251
      
3252
3.29k
    case tcImageUniqueID:
3253
3.29k
      {
3254
      
3255
3.29k
      if (!CheckTagType (parentCode, tagCode, tagType, ttAscii))
3256
335
        return false;
3257
        
3258
2.95k
      if (!CheckTagCount (parentCode, tagCode, tagCount, 33))
3259
655
        return false;
3260
      
3261
2.30k
      dng_string s;
3262
      
3263
2.30k
      ParseStringTag (stream,
3264
2.30k
              parentCode,
3265
2.30k
              tagCode,
3266
2.30k
              tagCount,
3267
2.30k
              s);
3268
              
3269
2.30k
      if (s.Length () != 32)
3270
671
        return false;
3271
        
3272
1.63k
      dng_fingerprint f;
3273
      
3274
27.9k
      for (uint32 j = 0; j < 32; j++)
3275
27.3k
        {
3276
        
3277
27.3k
        char c = ForceUppercase (s.Get () [j]);
3278
        
3279
27.3k
        uint32 digit;
3280
        
3281
27.3k
        if (c >= '0' && c <= '9')
3282
17.6k
          {
3283
17.6k
          digit = c - '0';
3284
17.6k
          }
3285
          
3286
9.77k
        else if (c >= 'A' && c <= 'F')
3287
8.67k
          {
3288
8.67k
          digit = c - 'A' + 10;
3289
8.67k
          }
3290
          
3291
1.09k
        else
3292
1.09k
          return false;
3293
        
3294
26.2k
        f.data [j >> 1] *= 16;
3295
26.2k
        f.data [j >> 1] += (uint8) digit;
3296
          
3297
26.2k
        }
3298
        
3299
531
      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
531
      break;
3317
      
3318
1.63k
      }
3319
3320
1.65k
    case tcCameraOwnerNameExif:
3321
1.65k
      {
3322
3323
1.65k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
3324
      
3325
1.65k
      ParseStringTag (stream,
3326
1.65k
              parentCode,
3327
1.65k
              tagCode,
3328
1.65k
              tagCount,
3329
1.65k
              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.65k
      break;
3347
      
3348
1.63k
      }
3349
3350
2.93k
    case tcCameraSerialNumberExif:
3351
2.93k
      {
3352
      
3353
2.93k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
3354
      
3355
2.93k
      ParseStringTag (stream,
3356
2.93k
              parentCode,
3357
2.93k
              tagCode,
3358
2.93k
              tagCount,
3359
2.93k
              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.93k
      break;
3377
      
3378
1.63k
      }
3379
3380
10.2k
    case tcLensSpecificationExif:
3381
10.2k
      {
3382
      
3383
10.2k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
3384
      
3385
10.2k
      if (!CheckTagCount (parentCode, tagCode, tagCount, 4))
3386
4.70k
        return false;
3387
        
3388
5.55k
      fLensInfo [0] = stream.TagValue_urational (tagType);
3389
5.55k
      fLensInfo [1] = stream.TagValue_urational (tagType);
3390
5.55k
      fLensInfo [2] = stream.TagValue_urational (tagType);
3391
5.55k
      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.6k
      for (uint32 j = 0; j < 4; j++)
3397
22.1k
        {
3398
      
3399
22.1k
        if (fLensInfo [j].IsValid () && fLensInfo [j].As_real64 () <= 0.0)
3400
6.53k
          {
3401
          
3402
6.53k
          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
6.53k
          }
3411
          
3412
22.1k
        }
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.55k
      break;
3449
      
3450
10.2k
      }
3451
3452
1.96k
    case tcLensMakeExif:
3453
1.96k
      {
3454
      
3455
1.96k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
3456
      
3457
1.96k
      ParseStringTag (stream,
3458
1.96k
              parentCode,
3459
1.96k
              tagCode,
3460
1.96k
              tagCount,
3461
1.96k
              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
1.96k
      break;
3479
      
3480
10.2k
      }
3481
3482
2.44k
    case tcLensModelExif:
3483
2.44k
      {
3484
3485
2.44k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
3486
      
3487
2.44k
      ParseStringTag (stream,
3488
2.44k
              parentCode,
3489
2.44k
              tagCode,
3490
2.44k
              tagCount,
3491
2.44k
              fLensName);
3492
              
3493
2.44k
      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
2.44k
      break;
3511
      
3512
10.2k
      }
3513
3514
4.24k
    case tcLensSerialNumberExif:
3515
4.24k
      {
3516
      
3517
4.24k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
3518
      
3519
4.24k
      ParseStringTag (stream,
3520
4.24k
              parentCode,
3521
4.24k
              tagCode,
3522
4.24k
              tagCount,
3523
4.24k
              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
4.24k
      break;
3541
      
3542
10.2k
      }
3543
3544
1.02M
    default:
3545
1.02M
      {
3546
      
3547
1.02M
      return false;
3548
      
3549
10.2k
      }
3550
      
3551
1.32M
    }
3552
    
3553
268k
  return true;
3554
  
3555
1.32M
  }
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
172k
  {
3569
  
3570
172k
  switch (tagCode)
3571
172k
    {
3572
3573
25.7k
    case tcGPSVersionID:
3574
25.7k
      {
3575
      
3576
25.7k
      CheckTagType (parentCode, tagCode, tagType, ttByte);
3577
      
3578
25.7k
      CheckTagCount (parentCode, tagCode, tagCount, 4);
3579
      
3580
25.7k
      uint32 b0 = stream.Get_uint8 ();
3581
25.7k
      uint32 b1 = stream.Get_uint8 ();
3582
25.7k
      uint32 b2 = stream.Get_uint8 ();
3583
25.7k
      uint32 b3 = stream.Get_uint8 ();
3584
      
3585
25.7k
      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
25.7k
      break;
3601
      
3602
0
      }
3603
      
3604
2.48k
    case tcGPSLatitudeRef:
3605
5.58k
    case tcGPSLongitudeRef:
3606
8.67k
    case tcGPSSatellites:
3607
10.5k
    case tcGPSStatus:
3608
11.8k
    case tcGPSMeasureMode:
3609
12.7k
    case tcGPSSpeedRef:
3610
15.1k
    case tcGPSTrackRef:
3611
16.7k
    case tcGPSImgDirectionRef:
3612
17.4k
    case tcGPSMapDatum:
3613
17.9k
    case tcGPSDestLatitudeRef:
3614
18.8k
    case tcGPSDestLongitudeRef:
3615
19.3k
    case tcGPSDestBearingRef:
3616
20.4k
    case tcGPSDestDistanceRef:
3617
21.2k
    case tcGPSDateStamp:
3618
21.2k
      {
3619
      
3620
21.2k
      if (!CheckTagType (parentCode, tagCode, tagType, ttAscii))
3621
4.67k
        return false;
3622
      
3623
16.5k
      dng_string *s;
3624
      
3625
16.5k
      switch (tagCode)
3626
16.5k
        {
3627
        
3628
1.19k
        case tcGPSLatitudeRef:
3629
1.19k
          s = &fGPSLatitudeRef;
3630
1.19k
          break;
3631
          
3632
2.77k
        case tcGPSLongitudeRef:
3633
2.77k
          s = &fGPSLongitudeRef;
3634
2.77k
          break;
3635
          
3636
2.77k
        case tcGPSSatellites:
3637
2.77k
          s = &fGPSSatellites;
3638
2.77k
          break;
3639
          
3640
1.73k
        case tcGPSStatus:
3641
1.73k
          s = &fGPSStatus;
3642
1.73k
          break;
3643
          
3644
858
        case tcGPSMeasureMode:
3645
858
          s = &fGPSMeasureMode;
3646
858
          break;
3647
3648
753
        case tcGPSSpeedRef:
3649
753
          s = &fGPSSpeedRef;
3650
753
          break;
3651
3652
1.69k
        case tcGPSTrackRef:
3653
1.69k
          s = &fGPSTrackRef;
3654
1.69k
          break;
3655
3656
1.40k
        case tcGPSImgDirectionRef:
3657
1.40k
          s = &fGPSImgDirectionRef;
3658
1.40k
          break;
3659
3660
573
        case tcGPSMapDatum:
3661
573
          s = &fGPSMapDatum;
3662
573
          break;
3663
        
3664
257
        case tcGPSDestLatitudeRef:
3665
257
          s = &fGPSDestLatitudeRef;
3666
257
          break;
3667
        
3668
861
        case tcGPSDestLongitudeRef:
3669
861
          s = &fGPSDestLongitudeRef;
3670
861
          break;
3671
        
3672
374
        case tcGPSDestBearingRef:
3673
374
          s = &fGPSDestBearingRef;
3674
374
          break;
3675
        
3676
597
        case tcGPSDestDistanceRef:
3677
597
          s = &fGPSDestDistanceRef;
3678
597
          break;
3679
        
3680
698
        case tcGPSDateStamp:
3681
698
          s = &fGPSDateStamp;
3682
698
          break;
3683
          
3684
0
        default:
3685
0
          return false;
3686
          
3687
16.5k
        }
3688
        
3689
16.5k
      ParseStringTag (stream,
3690
16.5k
              parentCode,
3691
16.5k
              tagCode,
3692
16.5k
              tagCount,
3693
16.5k
              *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
16.5k
      break;
3711
      
3712
16.5k
      }
3713
      
3714
2.01k
    case tcGPSLatitude:
3715
5.84k
    case tcGPSLongitude:
3716
7.95k
    case tcGPSTimeStamp:
3717
9.07k
    case tcGPSDestLatitude:
3718
10.4k
    case tcGPSDestLongitude:
3719
10.4k
      {
3720
      
3721
10.4k
      if (!CheckTagType (parentCode, tagCode, tagType, ttRational))
3722
3.42k
        return false;
3723
      
3724
7.06k
      if (!CheckTagCount (parentCode, tagCode, tagCount, 3))
3725
2.14k
        return false;
3726
      
3727
4.92k
      dng_urational *u;
3728
      
3729
4.92k
      switch (tagCode)
3730
4.92k
        {
3731
        
3732
1.01k
        case tcGPSLatitude:
3733
1.01k
          u = fGPSLatitude;
3734
1.01k
          break;
3735
          
3736
1.61k
        case tcGPSLongitude:
3737
1.61k
          u = fGPSLongitude;
3738
1.61k
          break;
3739
          
3740
916
        case tcGPSTimeStamp:
3741
916
          u = fGPSTimeStamp;
3742
916
          break;
3743
          
3744
751
        case tcGPSDestLatitude:
3745
751
          u = fGPSDestLatitude;
3746
751
          break;
3747
          
3748
622
        case tcGPSDestLongitude:
3749
622
          u = fGPSDestLongitude;
3750
622
          break;
3751
3752
0
        default:
3753
0
          return false;
3754
          
3755
4.92k
        }
3756
        
3757
4.92k
      u [0] = stream.TagValue_urational (tagType);
3758
4.92k
      u [1] = stream.TagValue_urational (tagType);
3759
4.92k
      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
4.92k
      break;
3786
      
3787
4.92k
      }
3788
      
3789
1.66k
    case tcGPSAltitudeRef:
3790
1.66k
      {
3791
      
3792
1.66k
      CheckTagType (parentCode, tagCode, tagType, ttByte);
3793
      
3794
1.66k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3795
      
3796
1.66k
      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.66k
      break;
3829
      
3830
4.92k
      }
3831
3832
1.53k
    case tcGPSAltitude:
3833
4.07k
    case tcGPSDOP:
3834
6.65k
    case tcGPSSpeed:
3835
8.33k
    case tcGPSTrack:
3836
8.97k
    case tcGPSImgDirection:
3837
11.3k
    case tcGPSDestBearing:
3838
12.3k
    case tcGPSDestDistance:
3839
14.8k
    case tcGPSHPositioningError:
3840
14.8k
      {
3841
      
3842
14.8k
      if (!CheckTagType (parentCode, tagCode, tagType, ttRational))
3843
3.11k
        return false;
3844
      
3845
11.7k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3846
      
3847
11.7k
      dng_urational *u;
3848
      
3849
11.7k
      switch (tagCode)
3850
11.7k
        {
3851
        
3852
1.49k
        case tcGPSAltitude:
3853
1.49k
          u = &fGPSAltitude;
3854
1.49k
          break;
3855
          
3856
1.49k
        case tcGPSDOP:
3857
1.49k
          u = &fGPSDOP;
3858
1.49k
          break;
3859
          
3860
2.26k
        case tcGPSSpeed:
3861
2.26k
          u = &fGPSSpeed;
3862
2.26k
          break;
3863
  
3864
841
        case tcGPSTrack:
3865
841
          u = &fGPSTrack;
3866
841
          break;
3867
  
3868
588
        case tcGPSImgDirection:
3869
588
          u = &fGPSImgDirection;
3870
588
          break;
3871
        
3872
2.28k
        case tcGPSDestBearing:
3873
2.28k
          u = &fGPSDestBearing;
3874
2.28k
          break;
3875
        
3876
714
        case tcGPSDestDistance:
3877
714
          u = &fGPSDestDistance;
3878
714
          break;
3879
        
3880
2.07k
        case tcGPSHPositioningError:
3881
2.07k
          u = &fGPSHPositioningError;
3882
2.07k
          break;
3883
        
3884
0
        default:
3885
0
          return false;
3886
          
3887
11.7k
        }
3888
        
3889
11.7k
      *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
11.7k
      break;
3911
      
3912
11.7k
      }
3913
      
3914
1.72k
    case tcGPSProcessingMethod:
3915
2.43k
    case tcGPSAreaInformation:
3916
2.43k
      {
3917
      
3918
2.43k
      if (!CheckTagType (parentCode, tagCode, tagType, ttUndefined))
3919
1.15k
        return false;
3920
      
3921
1.28k
      dng_string *s;
3922
      
3923
1.28k
      switch (tagCode)
3924
1.28k
        {
3925
        
3926
796
        case tcGPSProcessingMethod:
3927
796
          s = &fGPSProcessingMethod;
3928
796
          break;
3929
          
3930
486
        case tcGPSAreaInformation:
3931
486
          s = &fGPSAreaInformation;
3932
486
          break;
3933
          
3934
0
        default:
3935
0
          return false;
3936
          
3937
1.28k
        }
3938
        
3939
1.28k
      ParseEncodedStringTag (stream,
3940
1.28k
                   parentCode,
3941
1.28k
                   tagCode,
3942
1.28k
                     tagCount,
3943
1.28k
                       *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
1.28k
      break;
3961
      
3962
1.28k
      }
3963
      
3964
1.29k
    case tcGPSDifferential:
3965
1.29k
      {
3966
      
3967
1.29k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
3968
      
3969
1.29k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3970
      
3971
1.29k
      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.29k
      break;
4003
      
4004
1.28k
      }
4005
      
4006
95.2k
    default:
4007
95.2k
      {
4008
      
4009
95.2k
      return false;
4010
      
4011
1.28k
      }
4012
      
4013
172k
    }
4014
    
4015
63.0k
  return true;
4016
  
4017
172k
  }
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.66k
  {
4031
  
4032
1.66k
  switch (tagCode)
4033
1.66k
    {
4034
    
4035
144
    case tcInteroperabilityIndex:
4036
144
      {
4037
      
4038
144
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
4039
      
4040
144
      CheckTagCount (parentCode, tagCode, tagCount, 4);
4041
      
4042
144
      ParseStringTag (stream,
4043
144
              parentCode,
4044
144
              tagCode,
4045
144
              tagCount,
4046
144
              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
144
      break;
4064
      
4065
0
      }
4066
4067
593
    case tcInteroperabilityVersion:
4068
593
      {
4069
      
4070
593
      CheckTagType (parentCode, tagCode, tagType, ttUndefined);
4071
      
4072
593
      CheckTagCount (parentCode, tagCode, tagCount, 4);
4073
      
4074
593
      uint32 b0 = stream.Get_uint8 ();
4075
593
      uint32 b1 = stream.Get_uint8 ();
4076
593
      uint32 b2 = stream.Get_uint8 ();
4077
593
      uint32 b3 = stream.Get_uint8 ();
4078
      
4079
593
      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
593
      break;
4098
      
4099
0
      }
4100
4101
80
    case tcRelatedImageFileFormat:
4102
80
      {
4103
      
4104
80
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
4105
      
4106
80
      ParseStringTag (stream,
4107
80
              parentCode,
4108
80
              tagCode,
4109
80
              tagCount,
4110
80
              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
80
      break;
4128
      
4129
0
      }
4130
4131
33
    case tcRelatedImageWidth:
4132
33
      {
4133
      
4134
33
      CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
4135
      
4136
33
      CheckTagCount (parentCode, tagCode, tagCount, 1);
4137
      
4138
33
      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
33
      break;
4150
      
4151
0
      }
4152
    
4153
52
    case tcRelatedImageLength:
4154
52
      {
4155
      
4156
52
      CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
4157
      
4158
52
      CheckTagCount (parentCode, tagCode, tagCount, 1);
4159
      
4160
52
      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
52
      break;
4172
      
4173
0
      }
4174
    
4175
758
    default:
4176
758
      {
4177
      
4178
758
      return false;
4179
      
4180
0
      }
4181
      
4182
1.66k
    }
4183
    
4184
902
  return true;
4185
  
4186
1.66k
  }
4187
                 
4188
/*****************************************************************************/
4189
4190
void dng_exif::PostParse (dng_host & /* host */,
4191
              dng_shared & /* shared */)
4192
83.7k
  {
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
83.7k
  if (fDateTime.NotValid () && fDateTimeOriginal.IsValid ())
4308
416
    {
4309
    
4310
416
    fDateTime = fDateTimeOriginal;
4311
    
4312
416
    }
4313
4314
  // Mirror EXIF 2.3 sensitivity tags to ISOSpeedRatings.
4315
4316
83.7k
  if (fISOSpeedRatings [0] == 0 || fISOSpeedRatings [0] == 65535)
4317
81.1k
    {
4318
4319
    // Prefer Recommended Exposure Index, then Standard Output Sensitivity, then
4320
    // ISO Speed, then Exposure Index.
4321
    
4322
81.1k
    if (fRecommendedExposureIndex != 0 &&
4323
577
      (fSensitivityType == stRecommendedExposureIndex ||
4324
566
       fSensitivityType == stSOSandREI        ||
4325
411
       fSensitivityType == stREIandISOSpeed      ||
4326
395
       fSensitivityType == stSOSandREIandISOSpeed))
4327
192
      {
4328
      
4329
192
      fISOSpeedRatings [0] = fRecommendedExposureIndex;
4330
      
4331
192
      }
4332
      
4333
80.9k
    else if (fStandardOutputSensitivity != 0 &&
4334
549
         (fSensitivityType == stStandardOutputSensitivity ||
4335
528
          fSensitivityType == stSOSandREI          ||
4336
374
          fSensitivityType == stSOSandISOSpeed        ||
4337
341
          fSensitivityType == stSOSandREIandISOSpeed))
4338
219
      {
4339
      
4340
219
      fISOSpeedRatings [0] = fStandardOutputSensitivity;
4341
      
4342
219
      }
4343
4344
80.6k
    else if (fISOSpeed != 0 &&
4345
463
         (fSensitivityType == stISOSpeed     ||
4346
437
          fSensitivityType == stSOSandISOSpeed ||
4347
420
          fSensitivityType == stREIandISOSpeed ||
4348
397
          fSensitivityType == stSOSandREIandISOSpeed))
4349
75
      {
4350
      
4351
75
      fISOSpeedRatings [0] = fISOSpeed;
4352
      
4353
75
      }
4354
    
4355
81.1k
    }
4356
  
4357
  // Mirror ExposureIndex to ISOSpeedRatings.
4358
4359
83.7k
  if (fExposureIndex.IsValid () && fISOSpeedRatings [0] == 0)
4360
6.37k
    {
4361
4362
6.37k
    fISOSpeedRatings [0] = Round_uint32 (fExposureIndex.As_real64 ());
4363
4364
6.37k
    }
4365
4366
  // Kodak sets the GPSAltitudeRef without setting the GPSAltitude.
4367
  
4368
83.7k
  if (fGPSAltitude.NotValid ())
4369
83.0k
    {
4370
    
4371
83.0k
    fGPSAltitudeRef = 0xFFFFFFFF;
4372
    
4373
83.0k
    }
4374
    
4375
  // If there is no valid GPS data, clear the GPS version number.
4376
  
4377
83.7k
  if (fGPSLatitude  [0].NotValid () &&
4378
83.3k
    fGPSLongitude [0].NotValid () &&
4379
82.8k
    fGPSAltitude     .NotValid () &&
4380
82.2k
    fGPSTimeStamp [0].NotValid () &&
4381
81.9k
    fGPSDateStamp    .IsEmpty  ())
4382
81.6k
    {
4383
    
4384
81.6k
    fGPSVersionID = 0;
4385
    
4386
81.6k
    }
4387
    
4388
83.7k
  }
4389
           
4390
/*****************************************************************************/