Coverage Report

Created: 2021-08-22 09:07

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