Coverage Report

Created: 2026-08-03 06:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dng_sdk/source/dng_exif.cpp
Line
Count
Source
1
/*****************************************************************************/
2
// Copyright 2006-2008 Adobe Systems Incorporated
3
// All Rights Reserved.
4
//
5
// NOTICE:  Adobe permits you to use, modify, and distribute this file in
6
// accordance with the terms of the Adobe license agreement accompanying it.
7
/*****************************************************************************/
8
9
/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_exif.cpp#1 $ */ 
10
/* $DateTime: 2012/05/30 13:28:51 $ */
11
/* $Change: 832332 $ */
12
/* $Author: tknoll $ */
13
14
/*****************************************************************************/
15
16
#include "dng_exif.h"
17
18
#include "dng_tag_codes.h"
19
#include "dng_tag_types.h"
20
#include "dng_parse_utils.h"
21
#include "dng_globals.h"
22
#include "dng_exceptions.h"
23
#include "dng_tag_values.h"
24
#include "dng_utils.h"
25
26
/*****************************************************************************/
27
28
dng_exif::dng_exif ()
29
30
207k
  : fImageDescription ()
31
207k
  , fMake             ()
32
207k
  , fModel            ()
33
207k
  , fSoftware         ()
34
207k
  , fArtist           ()
35
207k
  , fCopyright        ()
36
207k
  , fCopyright2       ()
37
207k
  , fUserComment      ()
38
39
207k
  , fDateTime            ()
40
207k
  , fDateTimeStorageInfo ()
41
  
42
207k
  , fDateTimeOriginal  ()
43
207k
  , fDateTimeOriginalStorageInfo ()
44
  
45
207k
  , fDateTimeDigitized ()
46
207k
  , fDateTimeDigitizedStorageInfo ()
47
    
48
207k
  , fTIFF_EP_StandardID (0)
49
207k
  , fExifVersion        (0)
50
207k
  , fFlashPixVersion  (0)
51
  
52
207k
  , fExposureTime      ()
53
207k
  , fFNumber           ()
54
207k
  , fShutterSpeedValue ()
55
207k
  , fApertureValue     ()
56
207k
  , fBrightnessValue   ()
57
207k
  , fExposureBiasValue ()
58
207k
  , fMaxApertureValue  ()
59
207k
  , fFocalLength       ()
60
207k
  , fDigitalZoomRatio  ()
61
207k
  , fExposureIndex     ()
62
207k
  , fSubjectDistance   ()
63
207k
  , fGamma             ()
64
    
65
207k
  , fBatteryLevelR ()
66
207k
  , fBatteryLevelA ()
67
    
68
207k
  , fExposureProgram      (0xFFFFFFFF)
69
207k
  , fMeteringMode         (0xFFFFFFFF)
70
207k
  , fLightSource          (0xFFFFFFFF)
71
207k
  , fFlash            (0xFFFFFFFF)
72
207k
  , fFlashMask        (0x0000FFFF)
73
207k
  , fSensingMethod        (0xFFFFFFFF)
74
207k
  , fColorSpace           (0xFFFFFFFF)
75
207k
  , fFileSource           (0xFFFFFFFF)
76
207k
  , fSceneType          (0xFFFFFFFF)
77
207k
  , fCustomRendered       (0xFFFFFFFF)
78
207k
  , fExposureMode       (0xFFFFFFFF)
79
207k
  , fWhiteBalance         (0xFFFFFFFF)
80
207k
  , fSceneCaptureType     (0xFFFFFFFF)
81
207k
  , fGainControl      (0xFFFFFFFF)
82
207k
  , fContrast         (0xFFFFFFFF)
83
207k
  , fSaturation       (0xFFFFFFFF)
84
207k
  , fSharpness        (0xFFFFFFFF)
85
207k
  , fSubjectDistanceRange (0xFFFFFFFF)
86
207k
  , fSelfTimerMode      (0xFFFFFFFF)
87
207k
  , fImageNumber      (0xFFFFFFFF)
88
  
89
207k
  , fFocalLengthIn35mmFilm (0)
90
91
207k
  , fSensitivityType       (0)
92
207k
  , fStandardOutputSensitivity (0)
93
207k
  , fRecommendedExposureIndex  (0)
94
207k
  , fISOSpeed          (0)
95
207k
  , fISOSpeedLatitudeyyy     (0)
96
207k
  , fISOSpeedLatitudezzz     (0)
97
98
207k
  , fSubjectAreaCount (0)
99
  
100
207k
  , fComponentsConfiguration (0)
101
  
102
207k
  , fCompresssedBitsPerPixel ()
103
  
104
207k
  , fPixelXDimension (0)
105
207k
  , fPixelYDimension (0)
106
  
107
207k
  , fFocalPlaneXResolution ()
108
207k
  , fFocalPlaneYResolution ()
109
    
110
207k
  , fFocalPlaneResolutionUnit (0xFFFFFFFF)
111
  
112
207k
  , fCFARepeatPatternRows (0)
113
207k
  , fCFARepeatPatternCols (0)
114
  
115
207k
  , fImageUniqueID ()
116
  
117
207k
  , fGPSVersionID     (0)
118
207k
  , fGPSLatitudeRef     ()
119
207k
  , fGPSLongitudeRef    ()
120
207k
  , fGPSAltitudeRef     (0xFFFFFFFF)
121
207k
  , fGPSAltitude      ()
122
207k
  , fGPSSatellites      ()
123
207k
  , fGPSStatus        ()
124
207k
  , fGPSMeasureMode     ()
125
207k
  , fGPSDOP         ()
126
207k
  , fGPSSpeedRef      ()
127
207k
  , fGPSSpeed       ()
128
207k
  , fGPSTrackRef      ()
129
207k
  , fGPSTrack       ()
130
207k
  , fGPSImgDirectionRef   ()
131
207k
  , fGPSImgDirection    ()
132
207k
  , fGPSMapDatum      ()
133
207k
  , fGPSDestLatitudeRef   ()
134
207k
  , fGPSDestLongitudeRef  ()
135
207k
  , fGPSDestBearingRef    ()
136
207k
  , fGPSDestBearing     ()
137
207k
  , fGPSDestDistanceRef   ()
138
207k
  , fGPSDestDistance    ()
139
207k
  , fGPSProcessingMethod  ()
140
207k
  , fGPSAreaInformation   ()
141
207k
  , fGPSDateStamp     ()
142
207k
  , fGPSDifferential    (0xFFFFFFFF)
143
207k
  , fGPSHPositioningError ()
144
  
145
207k
  , fInteroperabilityIndex ()
146
147
207k
  , fInteroperabilityVersion (0)
148
  
149
207k
  , fRelatedImageFileFormat ()
150
  
151
207k
  , fRelatedImageWidth  (0)
152
207k
  , fRelatedImageLength (0)
153
  
154
207k
  , fCameraSerialNumber ()
155
  
156
207k
  , fLensID       ()
157
207k
  , fLensMake     ()
158
207k
  , fLensName     ()
159
207k
  , fLensSerialNumber ()
160
  
161
207k
  , fLensNameWasReadFromExif (false)
162
163
207k
  , fApproxFocusDistance ()
164
165
207k
  , fFlashCompensation ()
166
  
167
207k
  , fOwnerName ()
168
207k
  , fFirmware  ()
169
  
170
207k
  {
171
  
172
207k
  uint32 j;
173
207k
  uint32 k;
174
  
175
207k
  fISOSpeedRatings [0] = 0;
176
207k
  fISOSpeedRatings [1] = 0;
177
207k
  fISOSpeedRatings [2] = 0;
178
  
179
1.86M
  for (j = 0; j < kMaxCFAPattern; j++)
180
14.9M
    for (k = 0; k < kMaxCFAPattern; k++)
181
13.2M
      {
182
13.2M
      fCFAPattern [j] [k] = 255;
183
13.2M
      }
184
    
185
207k
  }
186
  
187
/*****************************************************************************/
188
189
dng_exif::~dng_exif ()
190
274k
  {
191
  
192
274k
  }
193
    
194
/*****************************************************************************/
195
196
dng_exif * dng_exif::Clone () const
197
63.1k
  {
198
  
199
63.1k
  dng_exif *result = new dng_exif (*this);
200
  
201
63.1k
  if (!result)
202
0
    {
203
0
    ThrowMemoryFull ();
204
0
    }
205
  
206
63.1k
  return result;
207
  
208
63.1k
  }
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
15.6k
  {
275
  
276
  // Protection against invalid values.
277
  
278
15.6k
  if (et <= 0.0)
279
2.25k
    return 0.0;
280
  
281
  // If near a standard shutter speed, snap to it.
282
  
283
13.3k
  static const real64 kStandardSpeed [] =
284
13.3k
    {
285
13.3k
    30.0,
286
13.3k
    25.0,
287
13.3k
    20.0,
288
13.3k
    15.0,
289
13.3k
    13.0,
290
13.3k
    10.0,
291
13.3k
    8.0,
292
13.3k
    6.0,
293
13.3k
    5.0,
294
13.3k
    4.0,
295
13.3k
    3.2,
296
13.3k
    3.0,
297
13.3k
    2.5,
298
13.3k
    2.0,
299
13.3k
    1.6,
300
13.3k
    1.5,
301
13.3k
    1.3,
302
13.3k
    1.0,
303
13.3k
    0.8,
304
13.3k
    0.7,
305
13.3k
    0.6,
306
13.3k
    0.5,
307
13.3k
    0.4,
308
13.3k
    0.3,
309
13.3k
    1.0 / 4.0,
310
13.3k
    1.0 / 5.0,
311
13.3k
    1.0 / 6.0,
312
13.3k
    1.0 / 8.0,
313
13.3k
    1.0 / 10.0,
314
13.3k
    1.0 / 13.0,
315
13.3k
    1.0 / 15.0,
316
13.3k
    1.0 / 20.0,
317
13.3k
    1.0 / 25.0,
318
13.3k
    1.0 / 30.0,
319
13.3k
    1.0 / 40.0,
320
13.3k
    1.0 / 45.0,
321
13.3k
    1.0 / 50.0,
322
13.3k
    1.0 / 60.0,
323
13.3k
    1.0 / 80.0,
324
13.3k
    1.0 / 90.0,
325
13.3k
    1.0 / 100.0,
326
13.3k
    1.0 / 125.0,
327
13.3k
    1.0 / 160.0,
328
13.3k
    1.0 / 180.0,
329
13.3k
    1.0 / 200.0,
330
13.3k
    1.0 / 250.0,
331
13.3k
    1.0 / 320.0,
332
13.3k
    1.0 / 350.0,
333
13.3k
    1.0 / 400.0,
334
13.3k
    1.0 / 500.0,
335
13.3k
    1.0 / 640.0,
336
13.3k
    1.0 / 750.0,
337
13.3k
    1.0 / 800.0,
338
13.3k
    1.0 / 1000.0,
339
13.3k
    1.0 / 1250.0,
340
13.3k
    1.0 / 1500.0,
341
13.3k
    1.0 / 1600.0,
342
13.3k
    1.0 / 2000.0,
343
13.3k
    1.0 / 2500.0,
344
13.3k
    1.0 / 3000.0,
345
13.3k
    1.0 / 3200.0,
346
13.3k
    1.0 / 4000.0,
347
13.3k
    1.0 / 5000.0,
348
13.3k
    1.0 / 6000.0,
349
13.3k
    1.0 / 6400.0,
350
13.3k
    1.0 / 8000.0,
351
13.3k
    1.0 / 10000.0,
352
13.3k
    1.0 / 12000.0,
353
13.3k
    1.0 / 12800.0,
354
13.3k
    1.0 / 16000.0
355
13.3k
    };
356
    
357
13.3k
  uint32 count = sizeof (kStandardSpeed    ) /
358
13.3k
           sizeof (kStandardSpeed [0]);
359
             
360
27.6k
  for (uint32 fudge = 0; fudge <= 1; fudge++)
361
23.6k
    {
362
    
363
23.6k
    real64 testSpeed = et;
364
    
365
23.6k
    if (fudge == 1)
366
10.2k
      {
367
      
368
      // Often APEX values are rounded to a power of two,
369
      // which results in non-standard shutter speeds.
370
      
371
10.2k
      if (et >= 0.1)
372
5.46k
        {
373
        
374
        // No fudging slower than 1/10 second
375
        
376
5.46k
        break;
377
        
378
5.46k
        }
379
      
380
4.79k
      else if (et >= 0.01)
381
919
        {
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
919
        testSpeed *= 16.0 / 15.0;
389
        
390
919
        }
391
        
392
3.87k
      else
393
3.87k
        {
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
3.87k
        testSpeed *= 128.0 / 125.0;
400
        
401
3.87k
        }
402
      
403
10.2k
      }
404
      
405
1.11M
    for (uint32 index = 0; index < count; index++)
406
1.09M
      {
407
      
408
1.09M
      if (testSpeed >= kStandardSpeed [index] * 0.98 &&
409
470k
        testSpeed <= kStandardSpeed [index] * 1.02)
410
3.82k
        {
411
        
412
3.82k
        return kStandardSpeed [index];
413
        
414
3.82k
        }
415
        
416
1.09M
      }
417
      
418
18.1k
    }
419
    
420
  // We are not near any standard speeds.  Round the non-standard value to something
421
  // that looks reasonable.
422
  
423
9.51k
  if (et >= 10.0)
424
2.85k
    {
425
    
426
    // Round to nearest second.
427
    
428
2.85k
    et = floor (et + 0.5);
429
    
430
2.85k
    }
431
    
432
6.66k
  else if (et >= 0.5)
433
1.55k
    {
434
    
435
    // Round to nearest 1/10 second
436
    
437
1.55k
    et = floor (et * 10.0 + 0.5) * 0.1;
438
    
439
1.55k
    }
440
    
441
5.11k
  else if (et >= 1.0 / 20.0)
442
1.16k
    {
443
    
444
    // Round to an exact inverse.
445
    
446
1.16k
    et = 1.0 / floor (1.0 / et + 0.5);
447
    
448
1.16k
    }
449
    
450
3.94k
  else if (et >= 1.0 / 130.0)
451
790
    {
452
    
453
    // Round inverse to multiple of 5
454
    
455
790
    et = 0.2 / floor (0.2 / et + 0.5);
456
    
457
790
    }
458
    
459
3.15k
  else if (et >= 1.0 / 750.0)
460
810
    {
461
    
462
    // Round inverse to multiple of 10
463
    
464
810
    et = 0.1 / floor (0.1 / et + 0.5);
465
    
466
810
    }
467
    
468
2.34k
  else if (et >= 1.0 / 1300.0)
469
373
    {
470
    
471
    // Round inverse to multiple of 50
472
    
473
373
    et = 0.02 / floor (0.02 / et + 0.5);
474
    
475
373
    }
476
    
477
1.97k
  else if (et >= 1.0 / 15000.0)
478
449
    {
479
    
480
    // Round inverse to multiple of 100
481
    
482
449
    et = 0.01 / floor (0.01 / et + 0.5);
483
    
484
449
    }
485
    
486
1.52k
  else
487
1.52k
    {
488
    
489
    // Round inverse to multiple of 1000
490
    
491
1.52k
    et = 0.001 / floor (0.001 / et + 0.5);
492
    
493
1.52k
    }
494
    
495
9.51k
  return et;
496
  
497
13.3k
  }
498
499
/*****************************************************************************/
500
501
void dng_exif::SetExposureTime (real64 et, bool snap)
502
15.6k
  {
503
  
504
15.6k
  fExposureTime.Clear ();
505
  
506
15.6k
  fShutterSpeedValue.Clear ();
507
  
508
15.6k
  if (snap)
509
15.6k
    {
510
    
511
15.6k
    et = SnapExposureTime (et);
512
    
513
15.6k
    }
514
    
515
15.6k
  if (et >= 1.0 / 32768.0 && et <= 32768.0)
516
10.8k
    {
517
    
518
10.8k
    if (et >= 100.0)
519
1.12k
      {
520
      
521
1.12k
      fExposureTime.Set_real64 (et, 1);
522
      
523
1.12k
      }
524
      
525
9.74k
    else if (et >= 1.0)
526
3.07k
      {
527
      
528
3.07k
      fExposureTime.Set_real64 (et, 10);
529
      
530
3.07k
      fExposureTime.ReduceByFactor (10);
531
      
532
3.07k
      }
533
      
534
6.66k
    else if (et <= 0.1)
535
3.67k
      {
536
      
537
3.67k
      fExposureTime = dng_urational (1, Round_uint32 (1.0 / et));
538
      
539
3.67k
      }
540
      
541
2.99k
    else
542
2.99k
      {
543
      
544
2.99k
      fExposureTime.Set_real64 (et, 100);
545
      
546
2.99k
      fExposureTime.ReduceByFactor (10);
547
        
548
19.5k
      for (uint32 f = 2; f <= 9; f++)
549
18.0k
        {
550
        
551
18.0k
        real64 z = 1.0 / (real64) f / et;
552
        
553
18.0k
        if (z >= 0.99 && z <= 1.01)
554
1.50k
          {
555
          
556
1.50k
          fExposureTime = dng_urational (1, f);
557
          
558
1.50k
          break;
559
          
560
1.50k
          }
561
        
562
18.0k
        }
563
          
564
2.99k
      }
565
    
566
    // Now mirror this value to the ShutterSpeedValue field.
567
    
568
10.8k
    et = fExposureTime.As_real64 ();
569
    
570
10.8k
    fShutterSpeedValue.Set_real64 (-log (et) / log (2.0), 1000000);
571
                        
572
10.8k
    fShutterSpeedValue.ReduceByFactor (10);                 
573
10.8k
    fShutterSpeedValue.ReduceByFactor (10);                 
574
10.8k
    fShutterSpeedValue.ReduceByFactor (10);                 
575
10.8k
    fShutterSpeedValue.ReduceByFactor (10);                 
576
10.8k
    fShutterSpeedValue.ReduceByFactor (10);                 
577
10.8k
    fShutterSpeedValue.ReduceByFactor (10);                 
578
579
10.8k
    }
580
    
581
15.6k
  }
582
583
/*****************************************************************************/
584
585
void dng_exif::SetShutterSpeedValue (real64 ss)
586
4.13k
  {
587
  
588
4.13k
  if (fExposureTime.NotValid ())
589
2.24k
    {
590
    
591
2.24k
    real64 et = pow (2.0, -ss);
592
    
593
2.24k
    SetExposureTime (et, true);
594
    
595
2.24k
    }
596
  
597
4.13k
  }
598
599
/******************************************************************************/
600
601
dng_urational dng_exif::EncodeFNumber (real64 fs)
602
8.28k
  {
603
  
604
8.28k
  dng_urational y;
605
606
8.28k
  if (fs > 10.0)
607
1.71k
    {
608
    
609
1.71k
    y.Set_real64 (fs, 1);
610
    
611
1.71k
    }
612
    
613
6.56k
  else if (fs < 1.0)
614
3.72k
    {
615
    
616
3.72k
    y.Set_real64 (fs, 100);
617
    
618
3.72k
    y.ReduceByFactor (10);
619
3.72k
    y.ReduceByFactor (10);
620
    
621
3.72k
    }
622
    
623
2.84k
  else
624
2.84k
    {
625
    
626
2.84k
    y.Set_real64 (fs, 10);
627
    
628
2.84k
    y.ReduceByFactor (10);
629
    
630
2.84k
    }
631
    
632
8.28k
  return y;
633
      
634
8.28k
  }
635
    
636
/*****************************************************************************/
637
638
void dng_exif::SetFNumber (real64 fs)
639
13.5k
  {
640
  
641
13.5k
  fFNumber.Clear ();
642
  
643
13.5k
  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
13.5k
  if (fs > 0.0 && fs <= 32768.0)
651
8.28k
    {
652
  
653
8.28k
    fFNumber = EncodeFNumber (fs);
654
    
655
    // Now mirror this value to the ApertureValue field.
656
    
657
8.28k
    real64 av = FNumberToApertureValue (fFNumber);
658
659
8.28k
    if (av >= 0.0 && av <= 99.99)
660
4.93k
      {
661
      
662
4.93k
      fApertureValue.Set_real64 (av, 1000000);
663
      
664
4.93k
      fApertureValue.ReduceByFactor (10);                 
665
4.93k
      fApertureValue.ReduceByFactor (10);                 
666
4.93k
      fApertureValue.ReduceByFactor (10);                 
667
4.93k
      fApertureValue.ReduceByFactor (10);                 
668
4.93k
      fApertureValue.ReduceByFactor (10);                 
669
4.93k
      fApertureValue.ReduceByFactor (10);                 
670
      
671
4.93k
      }
672
    
673
8.28k
    }
674
  
675
13.5k
  }
676
      
677
/*****************************************************************************/
678
679
void dng_exif::SetApertureValue (real64 av)
680
3.87k
  {
681
682
3.87k
  if (fFNumber.NotValid ())
683
1.98k
    {
684
    
685
1.98k
    SetFNumber (ApertureValueToFNumber (av));
686
            
687
1.98k
    }
688
    
689
3.87k
  }
690
691
/*****************************************************************************/
692
693
real64 dng_exif::ApertureValueToFNumber (real64 av)
694
1.98k
  {
695
  
696
1.98k
  return pow (2.0, 0.5 * av);
697
  
698
1.98k
  }
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
8.28k
  {
713
  
714
8.28k
  return 2.0 * log (fNumber) / log (2.0);
715
  
716
8.28k
  }
717
718
/*****************************************************************************/
719
720
real64 dng_exif::FNumberToApertureValue (const dng_urational &fNumber)
721
8.28k
  {
722
  
723
8.28k
  return FNumberToApertureValue (fNumber.As_real64 ());
724
  
725
8.28k
  }
726
      
727
/*****************************************************************************/
728
729
void dng_exif::UpdateDateTime (const dng_date_time_info &dt)
730
0
  {
731
  
732
0
  fDateTime = dt;
733
  
734
0
  }
735
736
/*****************************************************************************/
737
738
bool dng_exif::AtLeastVersion0230 () const
739
134k
  {
740
  
741
134k
  uint32 b0 = (fExifVersion >> 24) & 0xff;
742
134k
  uint32 b1 = (fExifVersion >> 16) & 0xff;
743
134k
  uint32 b2 = (fExifVersion >>  8) & 0xff;
744
745
134k
  return (b0 > 0) || (b1 >= 2 && b2 >= 3);
746
  
747
134k
  }
748
    
749
/*****************************************************************************/
750
751
bool dng_exif::ParseTag (dng_stream &stream,
752
             dng_shared &shared,
753
             uint32 parentCode,
754
             bool isMainIFD,
755
             uint32 tagCode,
756
             uint32 tagType,
757
             uint32 tagCount,
758
             uint64 tagOffset)
759
2.94M
  {
760
  
761
2.94M
  if (parentCode == 0)
762
1.29M
    {
763
    
764
1.29M
    if (Parse_ifd0 (stream,
765
1.29M
            shared,
766
1.29M
            parentCode,
767
1.29M
            tagCode,
768
1.29M
            tagType,
769
1.29M
            tagCount,
770
1.29M
            tagOffset))
771
116k
      {
772
      
773
116k
      return true;
774
      
775
116k
      }
776
777
1.29M
    }
778
    
779
2.82M
  if (parentCode == 0 || isMainIFD)
780
1.51M
    {
781
    
782
1.51M
    if (Parse_ifd0_main (stream,
783
1.51M
                 shared,
784
1.51M
               parentCode,
785
1.51M
               tagCode,
786
1.51M
               tagType,
787
1.51M
               tagCount,
788
1.51M
               tagOffset))
789
10.0k
      {
790
      
791
10.0k
      return true;
792
      
793
10.0k
      }
794
795
1.51M
    }
796
    
797
2.81M
  if (parentCode == 0 ||
798
1.64M
    parentCode == tcExifIFD)
799
1.24M
    {
800
    
801
1.24M
    if (Parse_ifd0_exif (stream,
802
1.24M
                 shared,
803
1.24M
               parentCode,
804
1.24M
               tagCode,
805
1.24M
               tagType,
806
1.24M
               tagCount,
807
1.24M
               tagOffset))
808
237k
      {
809
      
810
237k
      return true;
811
      
812
237k
      }
813
814
1.24M
    }
815
    
816
2.58M
  if (parentCode == tcGPSInfo)
817
182k
    {
818
    
819
182k
    if (Parse_gps (stream,
820
182k
             shared,
821
182k
             parentCode,
822
182k
             tagCode,
823
182k
             tagType,
824
182k
             tagCount,
825
182k
             tagOffset))
826
65.5k
      {
827
      
828
65.5k
      return true;
829
      
830
65.5k
      }
831
832
182k
    }
833
    
834
2.51M
  if (parentCode == tcInteroperabilityIFD)
835
1.49k
    {
836
    
837
1.49k
    if (Parse_interoperability (stream,
838
1.49k
                    shared,
839
1.49k
                  parentCode,
840
1.49k
                  tagCode,
841
1.49k
                  tagType,
842
1.49k
                  tagCount,
843
1.49k
                  tagOffset))
844
771
      {
845
      
846
771
      return true;
847
      
848
771
      }
849
850
1.49k
    }
851
    
852
2.51M
  return false;
853
    
854
2.51M
  }
855
856
/*****************************************************************************/
857
858
// Parses tags that should only appear in IFD 0.
859
860
bool dng_exif::Parse_ifd0 (dng_stream &stream,
861
                 dng_shared & /* shared */,
862
               uint32 parentCode,
863
               uint32 tagCode,
864
               uint32 tagType,
865
               uint32 tagCount,
866
               uint64 /* tagOffset */)
867
1.29M
  {
868
  
869
1.29M
  switch (tagCode)
870
1.29M
    {
871
      
872
2.11k
    case tcImageDescription:
873
2.11k
      {
874
      
875
2.11k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
876
      
877
2.11k
      ParseStringTag (stream,
878
2.11k
              parentCode,
879
2.11k
              tagCode,
880
2.11k
              tagCount,
881
2.11k
              fImageDescription);
882
              
883
      #if qDNGValidate
884
      
885
      if (gVerbose)
886
        {
887
        
888
        printf ("ImageDescription: ");
889
        
890
        DumpString (fImageDescription);
891
        
892
        printf ("\n");
893
        
894
        }
895
        
896
      #endif
897
        
898
2.11k
      break;
899
      
900
0
      }
901
      
902
4.84k
    case tcMake:
903
4.84k
      {
904
      
905
4.84k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
906
      
907
4.84k
      ParseStringTag (stream,
908
4.84k
              parentCode,
909
4.84k
              tagCode,
910
4.84k
              tagCount,
911
4.84k
              fMake);
912
        
913
      #if qDNGValidate
914
      
915
      if (gVerbose)
916
        {
917
        
918
        printf ("Make: ");
919
        
920
        DumpString (fMake);
921
        
922
        printf ("\n");
923
        
924
        }
925
        
926
      #endif
927
      
928
4.84k
      break;
929
      
930
0
      }
931
        
932
11.7k
    case tcModel:
933
11.7k
      {
934
935
11.7k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
936
      
937
11.7k
      ParseStringTag (stream,
938
11.7k
              parentCode,
939
11.7k
              tagCode,
940
11.7k
              tagCount,
941
11.7k
              fModel);
942
      
943
      #if qDNGValidate
944
      
945
      if (gVerbose)
946
        {
947
        
948
        printf ("Model: ");
949
        
950
        DumpString (fModel);
951
        
952
        printf ("\n");
953
        
954
        }
955
        
956
      #endif
957
      
958
11.7k
      break;
959
      
960
0
      }
961
        
962
15.7k
    case tcSoftware:
963
15.7k
      {
964
      
965
15.7k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
966
      
967
15.7k
      ParseStringTag (stream,
968
15.7k
              parentCode,
969
15.7k
              tagCode,
970
15.7k
              tagCount,
971
15.7k
              fSoftware);
972
      
973
      #if qDNGValidate
974
      
975
      if (gVerbose)
976
        {
977
        
978
        printf ("Software: ");
979
        
980
        DumpString (fSoftware);
981
        
982
        printf ("\n");
983
        
984
        }
985
        
986
      #endif
987
      
988
15.7k
      break;
989
      
990
0
      }
991
992
20.0k
    case tcDateTime:
993
20.0k
      {
994
      
995
20.0k
      uint64 tagPosition = stream.PositionInOriginalFile ();
996
      
997
20.0k
      dng_date_time dt;
998
        
999
20.0k
      if (!ParseDateTimeTag (stream,
1000
20.0k
                   parentCode,
1001
20.0k
                   tagCode,
1002
20.0k
                   tagType,
1003
20.0k
                   tagCount,
1004
20.0k
                   dt))
1005
13.6k
        {
1006
13.6k
        return false;
1007
13.6k
        }
1008
        
1009
6.43k
      fDateTime.SetDateTime (dt);
1010
        
1011
6.43k
      fDateTimeStorageInfo = dng_date_time_storage_info (tagPosition,
1012
6.43k
                                 dng_date_time_format_exif);
1013
        
1014
      #if qDNGValidate
1015
      
1016
      if (gVerbose)
1017
        {
1018
        
1019
        printf ("DateTime: ");
1020
        
1021
        DumpDateTime (fDateTime.DateTime ());
1022
        
1023
        printf ("\n");
1024
        
1025
        }
1026
        
1027
      #endif
1028
1029
6.43k
      break;
1030
      
1031
20.0k
      }
1032
1033
2.01k
    case tcArtist:
1034
2.01k
      {
1035
      
1036
2.01k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
1037
      
1038
2.01k
      ParseStringTag (stream,
1039
2.01k
              parentCode,
1040
2.01k
              tagCode,
1041
2.01k
              tagCount,
1042
2.01k
              fArtist);
1043
      
1044
      #if qDNGValidate
1045
      
1046
      if (gVerbose)
1047
        {
1048
        
1049
        printf ("Artist: ");
1050
        
1051
        DumpString (fArtist);
1052
        
1053
        printf ("\n");
1054
        
1055
        }
1056
        
1057
      #endif
1058
      
1059
2.01k
      break;
1060
      
1061
20.0k
      }
1062
1063
29.9k
    case tcCopyright:
1064
29.9k
      {
1065
      
1066
29.9k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
1067
      
1068
29.9k
      ParseDualStringTag (stream,
1069
29.9k
                parentCode,
1070
29.9k
                tagCode,
1071
29.9k
                tagCount,
1072
29.9k
                fCopyright,
1073
29.9k
                fCopyright2);
1074
      
1075
      #if qDNGValidate
1076
      
1077
      if (gVerbose)
1078
        {
1079
        
1080
        printf ("Copyright: ");
1081
        
1082
        DumpString (fCopyright);
1083
        
1084
        if (fCopyright2.Get () [0] != 0)
1085
          {
1086
          
1087
          printf (" ");
1088
          
1089
          DumpString (fCopyright2);
1090
          
1091
          }
1092
        
1093
        printf ("\n");
1094
        
1095
        }
1096
        
1097
      #endif
1098
      
1099
29.9k
      break;
1100
      
1101
20.0k
      }
1102
1103
33.5k
    case tcTIFF_EP_StandardID:
1104
33.5k
      {
1105
      
1106
33.5k
      CheckTagType (parentCode, tagCode, tagType, ttByte);
1107
      
1108
33.5k
      CheckTagCount (parentCode, tagCode, tagCount, 4);
1109
      
1110
33.5k
      uint32 b0 = stream.Get_uint8 ();
1111
33.5k
      uint32 b1 = stream.Get_uint8 ();
1112
33.5k
      uint32 b2 = stream.Get_uint8 ();
1113
33.5k
      uint32 b3 = stream.Get_uint8 ();
1114
      
1115
33.5k
      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
33.5k
      break;
1131
      
1132
20.0k
      }
1133
        
1134
4.34k
    case tcCameraSerialNumber:
1135
4.57k
    case tcKodakCameraSerialNumber:   // Kodak uses a very similar tag.
1136
4.57k
      {
1137
      
1138
4.57k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
1139
      
1140
4.57k
      ParseStringTag (stream,
1141
4.57k
              parentCode,
1142
4.57k
              tagCode,
1143
4.57k
              tagCount,
1144
4.57k
              fCameraSerialNumber);
1145
        
1146
      #if qDNGValidate
1147
1148
      if (gVerbose)
1149
        {
1150
        
1151
        printf ("%s: ", LookupTagCode (parentCode, tagCode));
1152
        
1153
        DumpString (fCameraSerialNumber);
1154
        
1155
        printf ("\n");
1156
        
1157
        }
1158
        
1159
      #endif
1160
      
1161
4.57k
      break;
1162
      
1163
4.34k
      }
1164
      
1165
9.94k
    case tcLensInfo:
1166
9.94k
      {
1167
      
1168
9.94k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
1169
      
1170
9.94k
      if (!CheckTagCount (parentCode, tagCode, tagCount, 4))
1171
3.68k
        return false;
1172
        
1173
6.26k
      fLensInfo [0] = stream.TagValue_urational (tagType);
1174
6.26k
      fLensInfo [1] = stream.TagValue_urational (tagType);
1175
6.26k
      fLensInfo [2] = stream.TagValue_urational (tagType);
1176
6.26k
      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
30.9k
      for (uint32 j = 0; j < 4; j++)
1182
24.7k
        {
1183
      
1184
24.7k
        if (fLensInfo [j].IsValid () && fLensInfo [j].As_real64 () <= 0.0)
1185
10.8k
          {
1186
          
1187
10.8k
          fLensInfo [j] = dng_urational (0, 0);
1188
          
1189
          #if qDNGValidate
1190
          
1191
          ReportWarning ("Zero entry in LensInfo tag--should be undefined");
1192
          
1193
          #endif
1194
1195
10.8k
          }
1196
          
1197
24.7k
        }
1198
        
1199
      #if qDNGValidate
1200
1201
      if (gVerbose)
1202
        {
1203
        
1204
        printf ("LensInfo: ");
1205
        
1206
        real64 minFL = fLensInfo [0].As_real64 ();
1207
        real64 maxFL = fLensInfo [1].As_real64 ();
1208
        
1209
        if (minFL == maxFL)
1210
          printf ("%0.1f mm", minFL);
1211
        else
1212
          printf ("%0.1f-%0.1f mm", minFL, maxFL);
1213
          
1214
        if (fLensInfo [2].d)
1215
          {
1216
          
1217
          real64 minFS = fLensInfo [2].As_real64 ();
1218
          real64 maxFS = fLensInfo [3].As_real64 ();
1219
          
1220
          if (minFS == maxFS)
1221
            printf (" f/%0.1f", minFS);
1222
          else
1223
            printf (" f/%0.1f-%0.1f", minFS, maxFS);
1224
          
1225
          }
1226
          
1227
        printf ("\n");
1228
        
1229
        }
1230
        
1231
      #endif
1232
      
1233
6.26k
      break;
1234
      
1235
9.94k
      }
1236
        
1237
1.15M
    default:
1238
1.15M
      {
1239
      
1240
1.15M
      return false;
1241
      
1242
9.94k
      }
1243
      
1244
1.29M
    }
1245
  
1246
116k
  return true;
1247
  
1248
1.29M
  }
1249
  
1250
/*****************************************************************************/
1251
1252
// Parses tags that should only appear in IFD 0 or the main image IFD.
1253
1254
bool dng_exif::Parse_ifd0_main (dng_stream &stream,
1255
                      dng_shared & /* shared */,
1256
                    uint32 parentCode,
1257
                    uint32 tagCode,
1258
                    uint32 tagType,
1259
                    uint32 tagCount,
1260
                    uint64 /* tagOffset */)
1261
1.51M
  {
1262
  
1263
1.51M
  switch (tagCode)
1264
1.51M
    {
1265
      
1266
2.98k
    case tcFocalPlaneXResolution:
1267
2.98k
      {
1268
1269
2.98k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
1270
      
1271
2.98k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1272
      
1273
2.98k
      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
2.98k
      break;
1288
      
1289
0
      }
1290
      
1291
1.80k
    case tcFocalPlaneYResolution:
1292
1.80k
      {
1293
1294
1.80k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
1295
      
1296
1.80k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1297
      
1298
1.80k
      fFocalPlaneYResolution = stream.TagValue_urational (tagType);
1299
      
1300
      #if qDNGValidate
1301
1302
      if (gVerbose)
1303
        {
1304
        
1305
        printf ("FocalPlaneYResolution: %0.4f\n",
1306
            fFocalPlaneYResolution.As_real64 ());
1307
            
1308
        }
1309
        
1310
      #endif
1311
      
1312
1.80k
      break;
1313
      
1314
0
      }
1315
      
1316
2.32k
    case tcFocalPlaneResolutionUnit:
1317
2.32k
      {
1318
      
1319
2.32k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
1320
      
1321
2.32k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1322
      
1323
2.32k
      fFocalPlaneResolutionUnit = stream.TagValue_uint32 (tagType);
1324
      
1325
      #if qDNGValidate
1326
1327
      if (gVerbose)
1328
        {
1329
        
1330
        printf ("FocalPlaneResolutionUnit: %s\n",
1331
              LookupResolutionUnit (fFocalPlaneResolutionUnit));
1332
        
1333
        }
1334
        
1335
      #endif
1336
        
1337
2.32k
      break;
1338
      
1339
0
      }
1340
1341
2.90k
    case tcSensingMethod:
1342
2.90k
      {
1343
      
1344
2.90k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
1345
      
1346
2.90k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1347
      
1348
2.90k
      fSensingMethod = stream.TagValue_uint32 (tagType);
1349
      
1350
      #if qDNGValidate
1351
1352
      if (gVerbose)
1353
        {
1354
        
1355
        printf ("SensingMethod: %s\n",
1356
            LookupSensingMethod (fSensingMethod));
1357
1358
        }
1359
        
1360
      #endif
1361
      
1362
2.90k
      break;
1363
      
1364
0
      }
1365
      
1366
1.50M
    default:
1367
1.50M
      {
1368
      
1369
1.50M
      return false;
1370
      
1371
0
      }
1372
      
1373
1.51M
    }
1374
    
1375
10.0k
  return true;
1376
  
1377
1.51M
  }
1378
      
1379
/*****************************************************************************/
1380
1381
// Parses tags that should only appear in IFD 0 or EXIF IFD.
1382
1383
bool dng_exif::Parse_ifd0_exif (dng_stream &stream,
1384
                dng_shared & /* shared */,
1385
                    uint32 parentCode,
1386
                    uint32 tagCode,
1387
                    uint32 tagType,
1388
                    uint32 tagCount,
1389
                    uint64 /* tagOffset */)
1390
1.24M
  {
1391
  
1392
1.24M
  switch (tagCode)
1393
1.24M
    {
1394
    
1395
1.28k
    case tcBatteryLevel:
1396
1.28k
      {
1397
      
1398
1.28k
      CheckTagType (parentCode, tagCode, tagType, ttRational, ttAscii);
1399
      
1400
1.28k
      if (tagType == ttAscii)
1401
472
        {
1402
        
1403
472
        ParseStringTag (stream,
1404
472
                parentCode,
1405
472
                tagCode,
1406
472
                tagCount,
1407
472
                fBatteryLevelA);
1408
      
1409
472
        }
1410
        
1411
814
      else
1412
814
        {
1413
      
1414
814
        CheckTagCount (parentCode, tagCode, tagCount, 1);
1415
        
1416
814
        fBatteryLevelR = stream.TagValue_urational (tagType);
1417
        
1418
814
        }
1419
      
1420
      #if qDNGValidate
1421
1422
      if (gVerbose)
1423
        {
1424
        
1425
        printf ("BatteryLevel: ");
1426
        
1427
        if (tagType == ttAscii)
1428
          {
1429
          
1430
          DumpString (fBatteryLevelA);
1431
          
1432
          }
1433
          
1434
        else
1435
          {
1436
        
1437
          printf ("%0.2f", fBatteryLevelR.As_real64 ());
1438
          
1439
          }
1440
          
1441
        printf ("\n");
1442
        
1443
        }
1444
        
1445
      #endif
1446
      
1447
1.28k
      break;
1448
      
1449
0
      }
1450
    
1451
13.3k
    case tcExposureTime:
1452
13.3k
      {
1453
      
1454
13.3k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
1455
      
1456
13.3k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1457
      
1458
13.3k
      dng_urational et = stream.TagValue_urational (tagType);
1459
      
1460
13.3k
      SetExposureTime (et.As_real64 (), true);
1461
      
1462
      #if qDNGValidate
1463
1464
      if (gVerbose)
1465
        {
1466
        
1467
        printf ("ExposureTime: ");
1468
        
1469
        DumpExposureTime (et.As_real64 ());
1470
                  
1471
        printf ("\n");
1472
1473
        }
1474
        
1475
      if (et.As_real64 () <= 0.0)
1476
        {
1477
        
1478
        ReportWarning ("The ExposureTime is <= 0");
1479
               
1480
        }
1481
      
1482
      #endif
1483
      
1484
13.3k
      break;
1485
      
1486
0
      }
1487
1488
11.5k
    case tcFNumber:
1489
11.5k
      {
1490
      
1491
11.5k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
1492
      
1493
11.5k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1494
      
1495
11.5k
      dng_urational fs = stream.TagValue_urational (tagType);
1496
      
1497
      // Sometimes "unknown" is recorded as zero.
1498
      
1499
11.5k
      if (fs.As_real64 () <= 0.0)
1500
3.44k
        {
1501
3.44k
        fs.Clear ();
1502
3.44k
        }
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
11.5k
      SetFNumber (fs.As_real64 ());
1517
      
1518
11.5k
      break;
1519
      
1520
0
      }
1521
1522
9.80k
    case tcExposureProgram:
1523
9.80k
      {
1524
      
1525
9.80k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
1526
      
1527
9.80k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1528
      
1529
9.80k
      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
9.80k
      break;
1544
      
1545
0
      }
1546
1547
8.39k
    case tcISOSpeedRatings:
1548
8.39k
      {
1549
      
1550
8.39k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
1551
      
1552
8.39k
      CheckTagCount (parentCode, tagCode, tagCount, 1, 3);
1553
      
1554
24.0k
      for (uint32 j = 0; j < tagCount && j < 3; j++)
1555
15.6k
        {
1556
        
1557
15.6k
        fISOSpeedRatings [j] = stream.TagValue_uint32 (tagType);
1558
        
1559
15.6k
        }
1560
      
1561
      #if qDNGValidate
1562
1563
      if (gVerbose)
1564
        {
1565
        
1566
        printf ("ISOSpeedRatings:");
1567
        
1568
        for (uint32 j = 0; j < tagCount && j < 3; j++)
1569
          {
1570
          
1571
          printf (" %u", (unsigned) fISOSpeedRatings [j]);
1572
          
1573
          }
1574
          
1575
        printf ("\n");
1576
          
1577
        }
1578
        
1579
      #endif
1580
      
1581
8.39k
      break;
1582
      
1583
0
      }
1584
      
1585
4.58k
    case tcSensitivityType:
1586
4.58k
      {
1587
      
1588
4.58k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
1589
      
1590
4.58k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1591
1592
4.58k
      fSensitivityType = (uint32) stream.Get_uint16 ();
1593
      
1594
      #if qDNGValidate
1595
1596
      if (gVerbose)
1597
        {
1598
        
1599
        printf ("SensitivityType: %s\n",
1600
            LookupSensitivityType (fSensitivityType));
1601
        
1602
        }
1603
        
1604
      #endif
1605
      
1606
4.58k
      break;
1607
      
1608
0
      }
1609
      
1610
1.74k
    case tcStandardOutputSensitivity:
1611
1.74k
      {
1612
      
1613
1.74k
      CheckTagType (parentCode, tagCode, tagType, ttLong);
1614
      
1615
1.74k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1616
1617
1.74k
      fStandardOutputSensitivity = stream.TagValue_uint32 (tagType);
1618
      
1619
      #if qDNGValidate
1620
1621
      if (gVerbose)
1622
        {
1623
        
1624
        printf ("StandardOutputSensitivity: %u\n",
1625
            (unsigned) fStandardOutputSensitivity);
1626
        
1627
        }
1628
        
1629
      #endif
1630
      
1631
1.74k
      break;
1632
      
1633
0
      }
1634
      
1635
1.86k
    case tcRecommendedExposureIndex:
1636
1.86k
      {
1637
      
1638
1.86k
      CheckTagType (parentCode, tagCode, tagType, ttLong);
1639
      
1640
1.86k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1641
1642
1.86k
      fRecommendedExposureIndex = stream.TagValue_uint32 (tagType);
1643
      
1644
      #if qDNGValidate
1645
1646
      if (gVerbose)
1647
        {
1648
        
1649
        printf ("RecommendedExposureIndex: %u\n",
1650
            (unsigned) fRecommendedExposureIndex);
1651
        
1652
        }
1653
        
1654
      #endif
1655
      
1656
1.86k
      break;
1657
      
1658
0
      }
1659
      
1660
965
    case tcISOSpeed:
1661
965
      {
1662
      
1663
965
      CheckTagType (parentCode, tagCode, tagType, ttLong);
1664
      
1665
965
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1666
1667
965
      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
965
      break;
1682
      
1683
0
      }
1684
      
1685
1.37k
    case tcISOSpeedLatitudeyyy:
1686
1.37k
      {
1687
      
1688
1.37k
      CheckTagType (parentCode, tagCode, tagType, ttLong);
1689
      
1690
1.37k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1691
1692
1.37k
      fISOSpeedLatitudeyyy = stream.TagValue_uint32 (tagType);
1693
      
1694
      #if qDNGValidate
1695
1696
      if (gVerbose)
1697
        {
1698
        
1699
        printf ("ISOSpeedLatitudeyyy: %u\n",
1700
            (unsigned) fISOSpeedLatitudeyyy);
1701
        
1702
        }
1703
        
1704
      #endif
1705
      
1706
1.37k
      break;
1707
      
1708
0
      }
1709
      
1710
1.39k
    case tcISOSpeedLatitudezzz:
1711
1.39k
      {
1712
      
1713
1.39k
      CheckTagType (parentCode, tagCode, tagType, ttLong);
1714
      
1715
1.39k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1716
1717
1.39k
      fISOSpeedLatitudezzz = stream.TagValue_uint32 (tagType);
1718
      
1719
      #if qDNGValidate
1720
1721
      if (gVerbose)
1722
        {
1723
        
1724
        printf ("ISOSpeedLatitudezzz: %u\n",
1725
            (unsigned) fISOSpeedLatitudezzz);
1726
        
1727
        }
1728
        
1729
      #endif
1730
      
1731
1.39k
      break;
1732
      
1733
0
      }
1734
      
1735
1.55k
    case tcTimeZoneOffset:
1736
1.55k
      {
1737
      
1738
1.55k
      CheckTagType (parentCode, tagCode, tagType, ttSShort);
1739
      
1740
1.55k
      CheckTagCount (parentCode, tagCode, tagCount, 1, 2);
1741
      
1742
1.55k
      dng_time_zone zoneOriginal;
1743
      
1744
1.55k
      zoneOriginal.SetOffsetHours (stream.TagValue_int32 (tagType));
1745
      
1746
1.55k
      fDateTimeOriginal.SetZone (zoneOriginal);
1747
      
1748
      #if 0 // MWG: Not filling in time zones unless we are sure.
1749
      
1750
      // Note that there is no "TimeZoneOffsetDigitized" field, so
1751
      // we assume the same tone zone as the original.
1752
      
1753
      fDateTimeDigitized.SetZone (zoneOriginal);
1754
      
1755
      #endif
1756
1757
1.55k
      dng_time_zone zoneCurrent;
1758
1759
1.55k
      if (tagCount >= 2)
1760
985
        {
1761
        
1762
985
        zoneCurrent.SetOffsetHours (stream.TagValue_int32 (tagType));
1763
        
1764
985
        fDateTime.SetZone (zoneCurrent);
1765
        
1766
985
        }
1767
        
1768
      #if qDNGValidate
1769
1770
      if (gVerbose)
1771
        {
1772
        
1773
        printf ("TimeZoneOffset: DateTimeOriginal = %d", 
1774
            (int) zoneOriginal.ExactHourOffset ());
1775
            
1776
        if (tagCount >= 2)
1777
          {
1778
        
1779
          printf (", DateTime = %d",
1780
              (int) zoneCurrent.ExactHourOffset ());
1781
              
1782
          }
1783
          
1784
        printf ("\n");
1785
        
1786
        }
1787
        
1788
      #endif
1789
      
1790
1.55k
      break;
1791
      
1792
0
      }
1793
1794
1.15k
    case tcSelfTimerMode:
1795
1.15k
      {
1796
      
1797
1.15k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
1798
      
1799
1.15k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1800
      
1801
1.15k
      fSelfTimerMode = stream.TagValue_uint32 (tagType);
1802
      
1803
      #if qDNGValidate
1804
1805
      if (gVerbose)
1806
        {
1807
        
1808
        printf ("SelfTimerMode: ");
1809
        
1810
        if (fSelfTimerMode)
1811
          {
1812
          
1813
          printf ("%u sec", (unsigned) fSelfTimerMode);
1814
          
1815
          }
1816
          
1817
        else
1818
          {
1819
          
1820
          printf ("Off");
1821
          
1822
          }
1823
          
1824
        printf ("\n");
1825
        
1826
        }
1827
        
1828
      #endif
1829
      
1830
1.15k
      break;
1831
      
1832
0
      }
1833
1834
13.6k
    case tcExifVersion:
1835
13.6k
      {
1836
      
1837
13.6k
      CheckTagType (parentCode, tagCode, tagType, ttUndefined);
1838
      
1839
13.6k
      CheckTagCount (parentCode, tagCode, tagCount, 4);
1840
      
1841
13.6k
      uint32 b0 = stream.Get_uint8 ();
1842
13.6k
      uint32 b1 = stream.Get_uint8 ();
1843
13.6k
      uint32 b2 = stream.Get_uint8 ();
1844
13.6k
      uint32 b3 = stream.Get_uint8 ();
1845
      
1846
13.6k
      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
13.6k
      break;
1865
      
1866
0
      }
1867
1868
9.92k
    case tcDateTimeOriginal:
1869
9.92k
      {
1870
      
1871
9.92k
      uint64 tagPosition = stream.PositionInOriginalFile ();
1872
      
1873
9.92k
      dng_date_time dt;
1874
      
1875
9.92k
      if (!ParseDateTimeTag (stream,
1876
9.92k
                   parentCode,
1877
9.92k
                   tagCode,
1878
9.92k
                   tagType,
1879
9.92k
                   tagCount,
1880
9.92k
                   dt))
1881
5.57k
        {
1882
5.57k
        return false;
1883
5.57k
        }
1884
        
1885
4.34k
      fDateTimeOriginal.SetDateTime (dt);
1886
      
1887
4.34k
      fDateTimeOriginalStorageInfo = dng_date_time_storage_info (tagPosition,
1888
4.34k
                                     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
4.34k
      break;
1906
      
1907
9.92k
      }
1908
1909
11.8k
    case tcDateTimeDigitized:
1910
11.8k
      {
1911
      
1912
11.8k
      uint64 tagPosition = stream.PositionInOriginalFile ();
1913
      
1914
11.8k
      dng_date_time dt;
1915
      
1916
11.8k
      if (!ParseDateTimeTag (stream,
1917
11.8k
                   parentCode,
1918
11.8k
                   tagCode,
1919
11.8k
                   tagType,
1920
11.8k
                   tagCount,
1921
11.8k
                   dt))
1922
7.93k
        {
1923
7.93k
        return false;
1924
7.93k
        }
1925
        
1926
3.92k
      fDateTimeDigitized.SetDateTime (dt);
1927
      
1928
3.92k
      fDateTimeDigitizedStorageInfo = dng_date_time_storage_info (tagPosition,
1929
3.92k
                                      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
3.92k
      break;
1947
      
1948
11.8k
      }
1949
      
1950
4.46k
    case tcComponentsConfiguration:
1951
4.46k
      {
1952
      
1953
4.46k
      CheckTagType (parentCode, tagCode, tagType, ttUndefined);
1954
      
1955
4.46k
      CheckTagCount (parentCode, tagCode, tagCount, 4);
1956
      
1957
4.46k
      uint32 b0 = stream.Get_uint8 ();
1958
4.46k
      uint32 b1 = stream.Get_uint8 ();
1959
4.46k
      uint32 b2 = stream.Get_uint8 ();
1960
4.46k
      uint32 b3 = stream.Get_uint8 ();
1961
      
1962
4.46k
      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
4.46k
      break;
1980
      
1981
11.8k
      }
1982
      
1983
1.52k
    case tcCompressedBitsPerPixel:
1984
1.52k
      {
1985
      
1986
1.52k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
1987
      
1988
1.52k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
1989
      
1990
1.52k
      fCompresssedBitsPerPixel = stream.TagValue_urational (tagType);
1991
      
1992
      #if qDNGValidate
1993
1994
      if (gVerbose)
1995
        {
1996
        
1997
        printf ("CompressedBitsPerPixel: %0.2f\n",
1998
            fCompresssedBitsPerPixel.As_real64 ());
1999
                
2000
        }
2001
        
2002
      #endif
2003
      
2004
1.52k
      break;
2005
      
2006
11.8k
      }
2007
      
2008
4.15k
    case tcShutterSpeedValue:
2009
4.15k
      {
2010
      
2011
4.15k
      CheckTagType (parentCode, tagCode, tagType, ttSRational);
2012
      
2013
4.15k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2014
      
2015
4.15k
      dng_srational ss = stream.TagValue_srational (tagType);
2016
      
2017
      #if qDNGValidate
2018
2019
      if (gVerbose)
2020
        {
2021
        
2022
        printf ("ShutterSpeedValue: ");
2023
        
2024
        real64 x = pow (2.0, -ss.As_real64 ());
2025
        
2026
        DumpExposureTime (x);
2027
                            
2028
        printf ("\n");
2029
2030
        }
2031
        
2032
      // The ExposureTime and ShutterSpeedValue tags should be consistent.
2033
      
2034
      if (fExposureTime.IsValid ())
2035
        {
2036
        
2037
        real64 et = fExposureTime.As_real64 ();
2038
        
2039
        real64 tv1 = -1.0 * log (et) / log (2.0);
2040
        
2041
        real64 tv2 = ss.As_real64 ();
2042
        
2043
        // Make sure they are within 0.25 APEX values.
2044
        
2045
        if (Abs_real64 (tv1 - tv2) > 0.25)
2046
          {
2047
          
2048
          ReportWarning ("The ExposureTime and ShutterSpeedValue tags have conflicting values");
2049
                 
2050
          }
2051
          
2052
        }
2053
      
2054
      #endif
2055
      
2056
4.15k
      SetShutterSpeedValue (ss.As_real64 ());
2057
        
2058
4.15k
      break;
2059
      
2060
11.8k
      }
2061
      
2062
3.87k
    case tcApertureValue:
2063
3.87k
      {
2064
      
2065
3.87k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
2066
      
2067
3.87k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2068
      
2069
3.87k
      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
3.87k
      SetApertureValue (av.As_real64 ());
2105
        
2106
3.87k
      break;
2107
      
2108
11.8k
      }
2109
      
2110
1.36k
    case tcBrightnessValue:
2111
1.36k
      {
2112
      
2113
1.36k
      CheckTagType (parentCode, tagCode, tagType, ttSRational);
2114
      
2115
1.36k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2116
      
2117
1.36k
      fBrightnessValue = stream.TagValue_srational (tagType);
2118
      
2119
      #if qDNGValidate
2120
2121
      if (gVerbose)
2122
        {
2123
        
2124
        printf ("BrightnessValue: %0.2f\n",
2125
            fBrightnessValue.As_real64 ());
2126
        
2127
        }
2128
        
2129
      #endif
2130
        
2131
1.36k
      break;
2132
      
2133
11.8k
      }
2134
      
2135
4.62k
    case tcExposureBiasValue:
2136
4.62k
      {
2137
      
2138
4.62k
      CheckTagType (parentCode, tagCode, tagType, ttSRational);
2139
      
2140
4.62k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2141
      
2142
4.62k
      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
4.62k
      break;
2157
      
2158
11.8k
      }
2159
2160
3.98k
    case tcMaxApertureValue:
2161
3.98k
      {
2162
      
2163
3.98k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
2164
      
2165
3.98k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2166
      
2167
3.98k
      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
3.98k
      break;
2183
      
2184
11.8k
      }
2185
      
2186
3.08k
    case tcSubjectDistance:
2187
3.08k
      {
2188
      
2189
3.08k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
2190
      
2191
3.08k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2192
      
2193
3.08k
      fSubjectDistance = stream.TagValue_urational (tagType);
2194
2195
3.08k
      fApproxFocusDistance = fSubjectDistance;
2196
      
2197
      #if qDNGValidate
2198
      
2199
      if (gVerbose)
2200
        {
2201
        
2202
        printf ("SubjectDistance: %u/%u\n",
2203
            (unsigned) fSubjectDistance.n,
2204
            (unsigned) fSubjectDistance.d);
2205
        
2206
        }
2207
      
2208
      #endif
2209
      
2210
3.08k
      break;
2211
      
2212
11.8k
      }
2213
2214
5.28k
    case tcMeteringMode:
2215
5.28k
      {
2216
      
2217
5.28k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
2218
      
2219
5.28k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2220
      
2221
5.28k
      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
5.28k
      break;
2236
      
2237
11.8k
      }
2238
      
2239
4.31k
    case tcLightSource:
2240
4.31k
      {
2241
      
2242
4.31k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
2243
      
2244
4.31k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2245
      
2246
4.31k
      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
4.31k
      break;
2261
      
2262
11.8k
      }
2263
2264
5.02k
    case tcFlash:
2265
5.02k
      {
2266
      
2267
5.02k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
2268
      
2269
5.02k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2270
      
2271
5.02k
      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
5.02k
      break;
2342
      
2343
11.8k
      }
2344
      
2345
5.39k
    case tcFocalLength:
2346
5.39k
      {
2347
      
2348
5.39k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
2349
      
2350
5.39k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2351
      
2352
5.39k
      fFocalLength = stream.TagValue_urational (tagType);
2353
      
2354
      // Sometimes "unknown" is recorded as zero.
2355
      
2356
5.39k
      if (fFocalLength.As_real64 () <= 0.0)
2357
961
        {
2358
961
        fFocalLength.Clear ();
2359
961
        }
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
5.39k
      break;
2374
      
2375
11.8k
      }
2376
      
2377
1.36k
    case tcImageNumber:
2378
1.36k
      {
2379
      
2380
1.36k
      CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
2381
      
2382
1.36k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2383
      
2384
1.36k
      fImageNumber = stream.TagValue_uint32 (tagType);
2385
      
2386
      #if qDNGValidate
2387
2388
      if (gVerbose)
2389
        {
2390
        printf ("ImageNumber: %u\n", (unsigned) fImageNumber);
2391
        }
2392
        
2393
      #endif
2394
        
2395
1.36k
      break;
2396
      
2397
11.8k
      }
2398
    
2399
8.19k
    case tcExposureIndex:
2400
8.70k
    case tcExposureIndexExif:
2401
8.70k
      {
2402
      
2403
8.70k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
2404
      
2405
8.70k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2406
      
2407
8.70k
      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
8.70k
      break;
2423
      
2424
8.19k
      }
2425
      
2426
15.9k
    case tcUserComment:
2427
15.9k
      {
2428
      
2429
15.9k
      CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2430
      
2431
15.9k
      ParseEncodedStringTag (stream,
2432
15.9k
                   parentCode,
2433
15.9k
                   tagCode,
2434
15.9k
                     tagCount,
2435
15.9k
                     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
15.9k
      break;
2453
      
2454
8.19k
      }
2455
2456
824
    case tcSubsecTime:
2457
824
      {
2458
      
2459
824
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
2460
      
2461
824
      dng_string subsecs;
2462
      
2463
824
      ParseStringTag (stream,
2464
824
              parentCode,
2465
824
              tagCode,
2466
824
              tagCount,
2467
824
              subsecs);
2468
              
2469
824
      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
824
      break;
2487
      
2488
8.19k
      }
2489
2490
819
    case tcSubsecTimeOriginal:
2491
819
      {
2492
      
2493
819
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
2494
      
2495
819
      dng_string subsecs;
2496
      
2497
819
      ParseStringTag (stream,
2498
819
              parentCode,
2499
819
              tagCode,
2500
819
              tagCount,
2501
819
              subsecs);
2502
              
2503
819
      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
819
      break;
2521
      
2522
8.19k
      }
2523
2524
599
    case tcSubsecTimeDigitized:
2525
599
      {
2526
      
2527
599
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
2528
      
2529
599
      dng_string subsecs;
2530
      
2531
599
      ParseStringTag (stream,
2532
599
              parentCode,
2533
599
              tagCode,
2534
599
              tagCount,
2535
599
              subsecs);
2536
              
2537
599
      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
599
      break;
2555
      
2556
8.19k
      }
2557
      
2558
9.20k
    case tcFlashPixVersion:
2559
9.20k
      {
2560
      
2561
9.20k
      CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2562
      
2563
9.20k
      CheckTagCount (parentCode, tagCode, tagCount, 4);
2564
      
2565
9.20k
      uint32 b0 = stream.Get_uint8 ();
2566
9.20k
      uint32 b1 = stream.Get_uint8 ();
2567
9.20k
      uint32 b2 = stream.Get_uint8 ();
2568
9.20k
      uint32 b3 = stream.Get_uint8 ();
2569
      
2570
9.20k
      fFlashPixVersion = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
2571
      
2572
      #if qDNGValidate
2573
2574
      if (gVerbose)
2575
        {
2576
        
2577
        real64 x = (b0 - '0') * 10.00 +
2578
               (b1 - '0') *  1.00 +
2579
               (b2 - '0') *  0.10 +
2580
               (b3 - '0') *  0.01;
2581
               
2582
        printf ("FlashPixVersion: %0.2f\n", x);
2583
        
2584
        }
2585
        
2586
      #endif
2587
      
2588
9.20k
      break;
2589
      
2590
8.19k
      }
2591
      
2592
4.00k
    case tcColorSpace:
2593
4.00k
      {
2594
      
2595
4.00k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
2596
      
2597
4.00k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2598
      
2599
4.00k
      fColorSpace = stream.TagValue_uint32 (tagType);
2600
      
2601
      #if qDNGValidate
2602
2603
      if (gVerbose)
2604
        {
2605
        
2606
        printf ("ColorSpace: %s\n",
2607
            LookupColorSpace (fColorSpace));
2608
        
2609
        }
2610
        
2611
      #endif
2612
      
2613
4.00k
      break;
2614
      
2615
8.19k
      }
2616
      
2617
3.38k
    case tcPixelXDimension:
2618
3.38k
      {
2619
      
2620
3.38k
      CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
2621
      
2622
3.38k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2623
      
2624
3.38k
      fPixelXDimension = stream.TagValue_uint32 (tagType);
2625
      
2626
      #if qDNGValidate
2627
2628
      if (gVerbose)
2629
        {
2630
        printf ("PixelXDimension: %u\n", (unsigned) fPixelXDimension);
2631
        }
2632
        
2633
      #endif
2634
        
2635
3.38k
      break;
2636
      
2637
8.19k
      }
2638
      
2639
2.56k
    case tcPixelYDimension:
2640
2.56k
      {
2641
      
2642
2.56k
      CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
2643
      
2644
2.56k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2645
      
2646
2.56k
      fPixelYDimension = stream.TagValue_uint32 (tagType);
2647
      
2648
      #if qDNGValidate
2649
2650
      if (gVerbose)
2651
        {
2652
        printf ("PixelYDimension: %u\n", (unsigned) fPixelYDimension);
2653
        }
2654
        
2655
      #endif
2656
      
2657
2.56k
      break;
2658
      
2659
8.19k
      }
2660
2661
1.14k
    case tcFocalPlaneXResolutionExif:
2662
1.14k
      {
2663
2664
1.14k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
2665
      
2666
1.14k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2667
      
2668
1.14k
      fFocalPlaneXResolution = stream.TagValue_urational (tagType);
2669
      
2670
      #if qDNGValidate
2671
2672
      if (gVerbose)
2673
        {
2674
        
2675
        printf ("FocalPlaneXResolutionExif: %0.4f\n",
2676
            fFocalPlaneXResolution.As_real64 ());
2677
            
2678
        }
2679
      
2680
      #endif
2681
      
2682
1.14k
      break;
2683
      
2684
8.19k
      }
2685
      
2686
1.55k
    case tcFocalPlaneYResolutionExif:
2687
1.55k
      {
2688
2689
1.55k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
2690
      
2691
1.55k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2692
      
2693
1.55k
      fFocalPlaneYResolution = stream.TagValue_urational (tagType);
2694
      
2695
      #if qDNGValidate
2696
2697
      if (gVerbose)
2698
        {
2699
        
2700
        printf ("FocalPlaneYResolutionExif: %0.4f\n",
2701
            fFocalPlaneYResolution.As_real64 ());
2702
            
2703
        }
2704
      
2705
      #endif
2706
      
2707
1.55k
      break;
2708
      
2709
8.19k
      }
2710
      
2711
888
    case tcFocalPlaneResolutionUnitExif:
2712
888
      {
2713
      
2714
888
      CheckTagType (parentCode, tagCode, tagType, ttShort);
2715
      
2716
888
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2717
      
2718
888
      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
888
      break;
2733
      
2734
8.19k
      }
2735
2736
1.12k
    case tcSensingMethodExif:
2737
1.12k
      {
2738
      
2739
1.12k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
2740
      
2741
1.12k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2742
      
2743
1.12k
      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
1.12k
      break;
2758
      
2759
8.19k
      }
2760
      
2761
3.60k
    case tcFileSource:
2762
3.60k
      {
2763
      
2764
3.60k
      CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2765
      
2766
3.60k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2767
      
2768
3.60k
      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
3.60k
      break;
2783
      
2784
8.19k
      }
2785
      
2786
4.14k
    case tcSceneType:
2787
4.14k
      {
2788
      
2789
4.14k
      CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2790
      
2791
4.14k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2792
      
2793
4.14k
      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
4.14k
      break;
2808
      
2809
8.19k
      }
2810
      
2811
2.48k
    case tcCFAPatternExif:
2812
2.48k
      {
2813
      
2814
2.48k
      CheckTagType (parentCode, tagCode, tagType, ttUndefined);
2815
      
2816
2.48k
      if (tagCount <= 4)
2817
338
        {
2818
338
        return false;
2819
338
        }
2820
        
2821
2.15k
      uint32 cols = stream.Get_uint16 ();
2822
2.15k
      uint32 rows = stream.Get_uint16 ();
2823
      
2824
2.15k
      if (tagCount != 4 + cols * rows)
2825
738
        {
2826
738
        return false;
2827
738
        }
2828
        
2829
1.41k
      if (cols < 1 || cols > kMaxCFAPattern ||
2830
1.30k
        rows < 1 || rows > kMaxCFAPattern)
2831
147
        {
2832
147
        return false;
2833
147
        }
2834
      
2835
1.26k
      fCFARepeatPatternCols = cols;
2836
1.26k
      fCFARepeatPatternRows = rows;
2837
      
2838
      // Note that the Exif spec stores this array in a different
2839
      // scan order than the TIFF-EP spec.
2840
      
2841
3.53k
      for (uint32 j = 0; j < fCFARepeatPatternCols; j++)
2842
6.12k
        for (uint32 k = 0; k < fCFARepeatPatternRows; k++)
2843
3.86k
          {
2844
          
2845
3.86k
          fCFAPattern [k] [j] = stream.Get_uint8 ();
2846
          
2847
3.86k
          }
2848
      
2849
      #if qDNGValidate
2850
2851
      if (gVerbose)
2852
        {
2853
        
2854
        printf ("CFAPatternExif:\n");
2855
        
2856
        for (uint32 j = 0; j < fCFARepeatPatternRows; j++)
2857
          {
2858
          
2859
          int32 spaces = 4;
2860
          
2861
          for (uint32 k = 0; k < fCFARepeatPatternCols; k++)
2862
            {
2863
            
2864
            while (spaces-- > 0)
2865
              {
2866
              printf (" ");
2867
              }
2868
              
2869
            const char *name = LookupCFAColor (fCFAPattern [j] [k]);
2870
            
2871
            spaces = 9 - (int32) strlen (name);
2872
            
2873
            printf ("%s", name);
2874
            
2875
            }
2876
            
2877
          printf ("\n");
2878
          
2879
          }
2880
          
2881
        }
2882
      
2883
      #endif
2884
      
2885
1.26k
      break;
2886
      
2887
1.41k
      }
2888
      
2889
2.52k
    case tcCustomRendered:
2890
2.52k
      {
2891
      
2892
2.52k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
2893
      
2894
2.52k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2895
      
2896
2.52k
      fCustomRendered = stream.TagValue_uint32 (tagType);
2897
      
2898
      #if qDNGValidate
2899
2900
      if (gVerbose)
2901
        {
2902
        
2903
        printf ("CustomRendered: %s\n",
2904
            LookupCustomRendered (fCustomRendered));
2905
2906
        }
2907
      
2908
      #endif
2909
      
2910
2.52k
      break;
2911
      
2912
1.41k
      }
2913
      
2914
1.93k
    case tcExposureMode:
2915
1.93k
      {
2916
      
2917
1.93k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
2918
      
2919
1.93k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2920
      
2921
1.93k
      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
1.93k
      break;
2936
      
2937
1.41k
      }
2938
      
2939
2.75k
    case tcWhiteBalance:
2940
2.75k
      {
2941
      
2942
2.75k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
2943
      
2944
2.75k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2945
      
2946
2.75k
      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
2.75k
      break;
2961
      
2962
1.41k
      }
2963
      
2964
2.42k
    case tcDigitalZoomRatio:
2965
2.42k
      {
2966
      
2967
2.42k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
2968
      
2969
2.42k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
2970
      
2971
2.42k
      fDigitalZoomRatio = stream.TagValue_urational (tagType);
2972
      
2973
      #if qDNGValidate
2974
2975
      if (gVerbose)
2976
        {
2977
        
2978
        printf ("DigitalZoomRatio: ");
2979
        
2980
        if (fDigitalZoomRatio.n == 0 ||
2981
          fDigitalZoomRatio.d == 0)
2982
          {
2983
          
2984
          printf ("Not used\n");
2985
          
2986
          }
2987
          
2988
        else
2989
          {
2990
        
2991
          printf ("%0.2f\n", fDigitalZoomRatio.As_real64 ());
2992
          
2993
          }
2994
  
2995
        }
2996
      
2997
      #endif
2998
      
2999
2.42k
      break;
3000
      
3001
1.41k
      }
3002
3003
1.83k
    case tcFocalLengthIn35mmFilm:
3004
1.83k
      {
3005
      
3006
1.83k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
3007
      
3008
1.83k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3009
      
3010
1.83k
      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
1.83k
      break;
3025
      
3026
1.41k
      }
3027
3028
3.05k
    case tcSceneCaptureType:
3029
3.05k
      {
3030
      
3031
3.05k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
3032
      
3033
3.05k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3034
      
3035
3.05k
      fSceneCaptureType = stream.TagValue_uint32 (tagType);
3036
      
3037
      #if qDNGValidate
3038
3039
      if (gVerbose)
3040
        {
3041
        
3042
        printf ("SceneCaptureType: %s\n",
3043
            LookupSceneCaptureType (fSceneCaptureType));
3044
3045
        }
3046
      
3047
      #endif
3048
      
3049
3.05k
      break;
3050
      
3051
1.41k
      }
3052
      
3053
2.29k
    case tcGainControl:
3054
2.29k
      {
3055
      
3056
2.29k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
3057
      
3058
2.29k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3059
      
3060
2.29k
      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.29k
      break;
3075
      
3076
1.41k
      }
3077
      
3078
2.53k
    case tcContrast:
3079
2.53k
      {
3080
      
3081
2.53k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
3082
      
3083
2.53k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3084
      
3085
2.53k
      fContrast = stream.TagValue_uint32 (tagType);
3086
      
3087
      #if qDNGValidate
3088
3089
      if (gVerbose)
3090
        {
3091
        
3092
        printf ("Contrast: %s\n",
3093
            LookupContrast (fContrast));
3094
3095
        }
3096
      
3097
      #endif
3098
      
3099
2.53k
      break;
3100
      
3101
1.41k
      }
3102
      
3103
766
    case tcSaturation:
3104
766
      {
3105
      
3106
766
      CheckTagType (parentCode, tagCode, tagType, ttShort);
3107
      
3108
766
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3109
      
3110
766
      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
766
      break;
3125
      
3126
1.41k
      }
3127
      
3128
6.46k
    case tcSharpness:
3129
6.46k
      {
3130
      
3131
6.46k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
3132
      
3133
6.46k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3134
      
3135
6.46k
      fSharpness = stream.TagValue_uint32 (tagType);
3136
      
3137
      #if qDNGValidate
3138
3139
      if (gVerbose)
3140
        {
3141
        
3142
        printf ("Sharpness: %s\n",
3143
            LookupSharpness (fSharpness));
3144
3145
        }
3146
      
3147
      #endif
3148
      
3149
6.46k
      break;
3150
      
3151
1.41k
      }
3152
      
3153
1.12k
    case tcSubjectDistanceRange:
3154
1.12k
      {
3155
      
3156
1.12k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
3157
      
3158
1.12k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3159
      
3160
1.12k
      fSubjectDistanceRange = stream.TagValue_uint32 (tagType);
3161
      
3162
      #if qDNGValidate
3163
3164
      if (gVerbose)
3165
        {
3166
        
3167
        printf ("SubjectDistanceRange: %s\n",
3168
            LookupSubjectDistanceRange (fSubjectDistanceRange));
3169
3170
        }
3171
        
3172
      #endif
3173
      
3174
1.12k
      break;
3175
      
3176
1.41k
      }
3177
      
3178
1.62k
    case tcSubjectArea:
3179
3.25k
    case tcSubjectLocation:
3180
3.25k
      {
3181
      
3182
3.25k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
3183
      
3184
3.25k
      if (!CheckTagCount (parentCode, tagCode, tagCount, 2, 4))
3185
1.17k
        {
3186
1.17k
        return false;
3187
1.17k
        }
3188
        
3189
2.08k
      if (tagCode == tcSubjectLocation)
3190
1.06k
        {
3191
1.06k
        CheckTagCount (parentCode, tagCode, tagCount, 2);
3192
1.06k
        }
3193
        
3194
2.08k
      fSubjectAreaCount = tagCount;
3195
      
3196
10.2k
      for (uint32 j = 0; j < tagCount; j++)
3197
8.20k
        {
3198
        
3199
8.20k
        fSubjectArea [j] = stream.TagValue_uint32 (tagType);
3200
        
3201
8.20k
        }
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
2.08k
      break;
3224
      
3225
3.25k
      }
3226
      
3227
610
    case tcGamma:
3228
610
      {
3229
      
3230
610
      CheckTagType (parentCode, tagCode, tagType, ttRational);
3231
      
3232
610
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3233
      
3234
610
      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
610
      break;
3249
      
3250
3.25k
      }
3251
      
3252
3.02k
    case tcImageUniqueID:
3253
3.02k
      {
3254
      
3255
3.02k
      if (!CheckTagType (parentCode, tagCode, tagType, ttAscii))
3256
335
        return false;
3257
        
3258
2.68k
      if (!CheckTagCount (parentCode, tagCode, tagCount, 33))
3259
573
        return false;
3260
      
3261
2.11k
      dng_string s;
3262
      
3263
2.11k
      ParseStringTag (stream,
3264
2.11k
              parentCode,
3265
2.11k
              tagCode,
3266
2.11k
              tagCount,
3267
2.11k
              s);
3268
              
3269
2.11k
      if (s.Length () != 32)
3270
663
        return false;
3271
        
3272
1.45k
      dng_fingerprint f;
3273
      
3274
22.1k
      for (uint32 j = 0; j < 32; j++)
3275
21.6k
        {
3276
        
3277
21.6k
        char c = ForceUppercase (s.Get () [j]);
3278
        
3279
21.6k
        uint32 digit;
3280
        
3281
21.6k
        if (c >= '0' && c <= '9')
3282
16.5k
          {
3283
16.5k
          digit = c - '0';
3284
16.5k
          }
3285
          
3286
5.16k
        else if (c >= 'A' && c <= 'F')
3287
4.21k
          {
3288
4.21k
          digit = c - 'A' + 10;
3289
4.21k
          }
3290
          
3291
951
        else
3292
951
          return false;
3293
        
3294
20.7k
        f.data [j >> 1] *= 16;
3295
20.7k
        f.data [j >> 1] += (uint8) digit;
3296
          
3297
20.7k
        }
3298
        
3299
499
      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
499
      break;
3317
      
3318
1.45k
      }
3319
3320
1.46k
    case tcCameraOwnerNameExif:
3321
1.46k
      {
3322
3323
1.46k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
3324
      
3325
1.46k
      ParseStringTag (stream,
3326
1.46k
              parentCode,
3327
1.46k
              tagCode,
3328
1.46k
              tagCount,
3329
1.46k
              fOwnerName);
3330
              
3331
      #if qDNGValidate
3332
      
3333
      if (gVerbose)
3334
        {
3335
        
3336
        printf ("CameraOwnerName: ");
3337
        
3338
        DumpString (fOwnerName);
3339
        
3340
        printf ("\n");
3341
        
3342
        }
3343
        
3344
      #endif
3345
      
3346
1.46k
      break;
3347
      
3348
1.45k
      }
3349
3350
3.19k
    case tcCameraSerialNumberExif:
3351
3.19k
      {
3352
      
3353
3.19k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
3354
      
3355
3.19k
      ParseStringTag (stream,
3356
3.19k
              parentCode,
3357
3.19k
              tagCode,
3358
3.19k
              tagCount,
3359
3.19k
              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
3.19k
      break;
3377
      
3378
1.45k
      }
3379
3380
10.2k
    case tcLensSpecificationExif:
3381
10.2k
      {
3382
      
3383
10.2k
      CheckTagType (parentCode, tagCode, tagType, ttRational);
3384
      
3385
10.2k
      if (!CheckTagCount (parentCode, tagCode, tagCount, 4))
3386
4.90k
        return false;
3387
        
3388
5.32k
      fLensInfo [0] = stream.TagValue_urational (tagType);
3389
5.32k
      fLensInfo [1] = stream.TagValue_urational (tagType);
3390
5.32k
      fLensInfo [2] = stream.TagValue_urational (tagType);
3391
5.32k
      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
26.5k
      for (uint32 j = 0; j < 4; j++)
3397
21.2k
        {
3398
      
3399
21.2k
        if (fLensInfo [j].IsValid () && fLensInfo [j].As_real64 () <= 0.0)
3400
6.79k
          {
3401
          
3402
6.79k
          fLensInfo [j] = dng_urational (0, 0);
3403
          
3404
          #if qDNGValidate
3405
          
3406
          ReportWarning ("Zero entry in LensSpecification tag--should be undefined");
3407
          
3408
          #endif
3409
3410
6.79k
          }
3411
          
3412
21.2k
        }
3413
        
3414
      #if qDNGValidate
3415
3416
      if (gVerbose)
3417
        {
3418
        
3419
        printf ("LensSpecificationExif: ");
3420
        
3421
        real64 minFL = fLensInfo [0].As_real64 ();
3422
        real64 maxFL = fLensInfo [1].As_real64 ();
3423
        
3424
        if (minFL == maxFL)
3425
          printf ("%0.1f mm", minFL);
3426
        else
3427
          printf ("%0.1f-%0.1f mm", minFL, maxFL);
3428
          
3429
        if (fLensInfo [2].d)
3430
          {
3431
          
3432
          real64 minFS = fLensInfo [2].As_real64 ();
3433
          real64 maxFS = fLensInfo [3].As_real64 ();
3434
          
3435
          if (minFS == maxFS)
3436
            printf (" f/%0.1f", minFS);
3437
          else
3438
            printf (" f/%0.1f-%0.1f", minFS, maxFS);
3439
          
3440
          }
3441
          
3442
        printf ("\n");
3443
        
3444
        }
3445
        
3446
      #endif
3447
      
3448
5.32k
      break;
3449
      
3450
10.2k
      }
3451
3452
1.69k
    case tcLensMakeExif:
3453
1.69k
      {
3454
      
3455
1.69k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
3456
      
3457
1.69k
      ParseStringTag (stream,
3458
1.69k
              parentCode,
3459
1.69k
              tagCode,
3460
1.69k
              tagCount,
3461
1.69k
              fLensMake);
3462
        
3463
      #if qDNGValidate
3464
3465
      if (gVerbose)
3466
        {
3467
        
3468
        printf ("%s: ", LookupTagCode (parentCode, tagCode));
3469
        
3470
        DumpString (fLensMake);
3471
        
3472
        printf ("\n");
3473
        
3474
        }
3475
        
3476
      #endif
3477
      
3478
1.69k
      break;
3479
      
3480
10.2k
      }
3481
3482
2.10k
    case tcLensModelExif:
3483
2.10k
      {
3484
3485
2.10k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
3486
      
3487
2.10k
      ParseStringTag (stream,
3488
2.10k
              parentCode,
3489
2.10k
              tagCode,
3490
2.10k
              tagCount,
3491
2.10k
              fLensName);
3492
              
3493
2.10k
      fLensNameWasReadFromExif = fLensName.NotEmpty ();
3494
        
3495
      #if qDNGValidate
3496
3497
      if (gVerbose)
3498
        {
3499
        
3500
        printf ("%s: ", LookupTagCode (parentCode, tagCode));
3501
        
3502
        DumpString (fLensName);
3503
        
3504
        printf ("\n");
3505
        
3506
        }
3507
        
3508
      #endif
3509
      
3510
2.10k
      break;
3511
      
3512
10.2k
      }
3513
3514
4.33k
    case tcLensSerialNumberExif:
3515
4.33k
      {
3516
      
3517
4.33k
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
3518
      
3519
4.33k
      ParseStringTag (stream,
3520
4.33k
              parentCode,
3521
4.33k
              tagCode,
3522
4.33k
              tagCount,
3523
4.33k
              fLensSerialNumber);
3524
        
3525
      #if qDNGValidate
3526
3527
      if (gVerbose)
3528
        {
3529
        
3530
        printf ("%s: ", LookupTagCode (parentCode, tagCode));
3531
        
3532
        DumpString (fLensSerialNumber);
3533
        
3534
        printf ("\n");
3535
        
3536
        }
3537
        
3538
      #endif
3539
      
3540
4.33k
      break;
3541
      
3542
10.2k
      }
3543
3544
983k
    default:
3545
983k
      {
3546
      
3547
983k
      return false;
3548
      
3549
10.2k
      }
3550
      
3551
1.24M
    }
3552
    
3553
237k
  return true;
3554
  
3555
1.24M
  }
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
182k
  {
3569
  
3570
182k
  switch (tagCode)
3571
182k
    {
3572
3573
30.6k
    case tcGPSVersionID:
3574
30.6k
      {
3575
      
3576
30.6k
      CheckTagType (parentCode, tagCode, tagType, ttByte);
3577
      
3578
30.6k
      CheckTagCount (parentCode, tagCode, tagCount, 4);
3579
      
3580
30.6k
      uint32 b0 = stream.Get_uint8 ();
3581
30.6k
      uint32 b1 = stream.Get_uint8 ();
3582
30.6k
      uint32 b2 = stream.Get_uint8 ();
3583
30.6k
      uint32 b3 = stream.Get_uint8 ();
3584
      
3585
30.6k
      fGPSVersionID = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
3586
      
3587
      #if qDNGValidate
3588
      
3589
      if (gVerbose)
3590
        {
3591
        printf ("GPSVersionID: %u.%u.%u.%u\n",
3592
            (unsigned) b0,
3593
            (unsigned) b1,
3594
            (unsigned) b2,
3595
            (unsigned) b3);
3596
        }
3597
        
3598
      #endif
3599
3600
30.6k
      break;
3601
      
3602
0
      }
3603
      
3604
1.54k
    case tcGPSLatitudeRef:
3605
4.30k
    case tcGPSLongitudeRef:
3606
7.38k
    case tcGPSSatellites:
3607
9.16k
    case tcGPSStatus:
3608
10.6k
    case tcGPSMeasureMode:
3609
11.4k
    case tcGPSSpeedRef:
3610
13.7k
    case tcGPSTrackRef:
3611
15.1k
    case tcGPSImgDirectionRef:
3612
15.8k
    case tcGPSMapDatum:
3613
16.2k
    case tcGPSDestLatitudeRef:
3614
17.1k
    case tcGPSDestLongitudeRef:
3615
17.6k
    case tcGPSDestBearingRef:
3616
18.1k
    case tcGPSDestDistanceRef:
3617
18.9k
    case tcGPSDateStamp:
3618
18.9k
      {
3619
      
3620
18.9k
      if (!CheckTagType (parentCode, tagCode, tagType, ttAscii))
3621
3.02k
        return false;
3622
      
3623
15.9k
      dng_string *s;
3624
      
3625
15.9k
      switch (tagCode)
3626
15.9k
        {
3627
        
3628
1.15k
        case tcGPSLatitudeRef:
3629
1.15k
          s = &fGPSLatitudeRef;
3630
1.15k
          break;
3631
          
3632
2.39k
        case tcGPSLongitudeRef:
3633
2.39k
          s = &fGPSLongitudeRef;
3634
2.39k
          break;
3635
          
3636
2.66k
        case tcGPSSatellites:
3637
2.66k
          s = &fGPSSatellites;
3638
2.66k
          break;
3639
          
3640
1.68k
        case tcGPSStatus:
3641
1.68k
          s = &fGPSStatus;
3642
1.68k
          break;
3643
          
3644
942
        case tcGPSMeasureMode:
3645
942
          s = &fGPSMeasureMode;
3646
942
          break;
3647
3648
766
        case tcGPSSpeedRef:
3649
766
          s = &fGPSSpeedRef;
3650
766
          break;
3651
3652
1.58k
        case tcGPSTrackRef:
3653
1.58k
          s = &fGPSTrackRef;
3654
1.58k
          break;
3655
3656
1.22k
        case tcGPSImgDirectionRef:
3657
1.22k
          s = &fGPSImgDirectionRef;
3658
1.22k
          break;
3659
3660
660
        case tcGPSMapDatum:
3661
660
          s = &fGPSMapDatum;
3662
660
          break;
3663
        
3664
233
        case tcGPSDestLatitudeRef:
3665
233
          s = &fGPSDestLatitudeRef;
3666
233
          break;
3667
        
3668
927
        case tcGPSDestLongitudeRef:
3669
927
          s = &fGPSDestLongitudeRef;
3670
927
          break;
3671
        
3672
374
        case tcGPSDestBearingRef:
3673
374
          s = &fGPSDestBearingRef;
3674
374
          break;
3675
        
3676
538
        case tcGPSDestDistanceRef:
3677
538
          s = &fGPSDestDistanceRef;
3678
538
          break;
3679
        
3680
768
        case tcGPSDateStamp:
3681
768
          s = &fGPSDateStamp;
3682
768
          break;
3683
          
3684
0
        default:
3685
0
          return false;
3686
          
3687
15.9k
        }
3688
        
3689
15.9k
      ParseStringTag (stream,
3690
15.9k
              parentCode,
3691
15.9k
              tagCode,
3692
15.9k
              tagCount,
3693
15.9k
              *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
15.9k
      break;
3711
      
3712
15.9k
      }
3713
      
3714
1.57k
    case tcGPSLatitude:
3715
4.91k
    case tcGPSLongitude:
3716
6.53k
    case tcGPSTimeStamp:
3717
7.36k
    case tcGPSDestLatitude:
3718
8.71k
    case tcGPSDestLongitude:
3719
8.71k
      {
3720
      
3721
8.71k
      if (!CheckTagType (parentCode, tagCode, tagType, ttRational))
3722
2.95k
        return false;
3723
      
3724
5.76k
      if (!CheckTagCount (parentCode, tagCode, tagCount, 3))
3725
1.28k
        return false;
3726
      
3727
4.47k
      dng_urational *u;
3728
      
3729
4.47k
      switch (tagCode)
3730
4.47k
        {
3731
        
3732
1.01k
        case tcGPSLatitude:
3733
1.01k
          u = fGPSLatitude;
3734
1.01k
          break;
3735
          
3736
1.46k
        case tcGPSLongitude:
3737
1.46k
          u = fGPSLongitude;
3738
1.46k
          break;
3739
          
3740
660
        case tcGPSTimeStamp:
3741
660
          u = fGPSTimeStamp;
3742
660
          break;
3743
          
3744
710
        case tcGPSDestLatitude:
3745
710
          u = fGPSDestLatitude;
3746
710
          break;
3747
          
3748
622
        case tcGPSDestLongitude:
3749
622
          u = fGPSDestLongitude;
3750
622
          break;
3751
3752
0
        default:
3753
0
          return false;
3754
          
3755
4.47k
        }
3756
        
3757
4.47k
      u [0] = stream.TagValue_urational (tagType);
3758
4.47k
      u [1] = stream.TagValue_urational (tagType);
3759
4.47k
      u [2] = stream.TagValue_urational (tagType);
3760
      
3761
      #if qDNGValidate
3762
      
3763
      if (gVerbose)
3764
        {
3765
        
3766
        printf ("%s:", LookupTagCode (parentCode, tagCode));
3767
        
3768
        for (uint32 j = 0; j < 3; j++)
3769
          {
3770
          
3771
          if (u [j].d == 0)
3772
            printf (" -");
3773
            
3774
          else
3775
            printf (" %0.4f", u [j].As_real64 ());
3776
            
3777
          }
3778
        
3779
        printf ("\n");
3780
        
3781
        }
3782
        
3783
      #endif
3784
        
3785
4.47k
      break;
3786
      
3787
4.47k
      }
3788
      
3789
1.46k
    case tcGPSAltitudeRef:
3790
1.46k
      {
3791
      
3792
1.46k
      CheckTagType (parentCode, tagCode, tagType, ttByte);
3793
      
3794
1.46k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3795
      
3796
1.46k
      fGPSAltitudeRef = stream.TagValue_uint32 (tagType);
3797
      
3798
      #if qDNGValidate
3799
      
3800
      if (gVerbose)
3801
        {
3802
        
3803
        printf ("GPSAltitudeRef: ");
3804
        
3805
        switch (fGPSAltitudeRef)
3806
          {
3807
          
3808
          case 0:
3809
            printf ("Sea level");
3810
            break;
3811
            
3812
          case 1:
3813
            printf ("Sea level reference (negative value)");
3814
            break;
3815
            
3816
          default:
3817
            printf ("%u", (unsigned) fGPSAltitudeRef);
3818
            break;
3819
            
3820
          }
3821
          
3822
        printf ("\n");
3823
        
3824
        }
3825
        
3826
      #endif
3827
      
3828
1.46k
      break;
3829
      
3830
4.47k
      }
3831
3832
1.42k
    case tcGPSAltitude:
3833
3.84k
    case tcGPSDOP:
3834
5.71k
    case tcGPSSpeed:
3835
7.00k
    case tcGPSTrack:
3836
7.71k
    case tcGPSImgDirection:
3837
9.46k
    case tcGPSDestBearing:
3838
10.3k
    case tcGPSDestDistance:
3839
12.8k
    case tcGPSHPositioningError:
3840
12.8k
      {
3841
      
3842
12.8k
      if (!CheckTagType (parentCode, tagCode, tagType, ttRational))
3843
2.22k
        return false;
3844
      
3845
10.5k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3846
      
3847
10.5k
      dng_urational *u;
3848
      
3849
10.5k
      switch (tagCode)
3850
10.5k
        {
3851
        
3852
1.39k
        case tcGPSAltitude:
3853
1.39k
          u = &fGPSAltitude;
3854
1.39k
          break;
3855
          
3856
1.36k
        case tcGPSDOP:
3857
1.36k
          u = &fGPSDOP;
3858
1.36k
          break;
3859
          
3860
1.58k
        case tcGPSSpeed:
3861
1.58k
          u = &fGPSSpeed;
3862
1.58k
          break;
3863
  
3864
728
        case tcGPSTrack:
3865
728
          u = &fGPSTrack;
3866
728
          break;
3867
  
3868
618
        case tcGPSImgDirection:
3869
618
          u = &fGPSImgDirection;
3870
618
          break;
3871
        
3872
1.66k
        case tcGPSDestBearing:
3873
1.66k
          u = &fGPSDestBearing;
3874
1.66k
          break;
3875
        
3876
855
        case tcGPSDestDistance:
3877
855
          u = &fGPSDestDistance;
3878
855
          break;
3879
        
3880
2.39k
        case tcGPSHPositioningError:
3881
2.39k
          u = &fGPSHPositioningError;
3882
2.39k
          break;
3883
        
3884
0
        default:
3885
0
          return false;
3886
          
3887
10.5k
        }
3888
        
3889
10.5k
      *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
10.5k
      break;
3911
      
3912
10.5k
      }
3913
      
3914
1.50k
    case tcGPSProcessingMethod:
3915
2.05k
    case tcGPSAreaInformation:
3916
2.05k
      {
3917
      
3918
2.05k
      if (!CheckTagType (parentCode, tagCode, tagType, ttUndefined))
3919
1.09k
        return false;
3920
      
3921
955
      dng_string *s;
3922
      
3923
955
      switch (tagCode)
3924
955
        {
3925
        
3926
529
        case tcGPSProcessingMethod:
3927
529
          s = &fGPSProcessingMethod;
3928
529
          break;
3929
          
3930
426
        case tcGPSAreaInformation:
3931
426
          s = &fGPSAreaInformation;
3932
426
          break;
3933
          
3934
0
        default:
3935
0
          return false;
3936
          
3937
955
        }
3938
        
3939
955
      ParseEncodedStringTag (stream,
3940
955
                   parentCode,
3941
955
                   tagCode,
3942
955
                     tagCount,
3943
955
                       *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
955
      break;
3961
      
3962
955
      }
3963
      
3964
1.65k
    case tcGPSDifferential:
3965
1.65k
      {
3966
      
3967
1.65k
      CheckTagType (parentCode, tagCode, tagType, ttShort);
3968
      
3969
1.65k
      CheckTagCount (parentCode, tagCode, tagCount, 1);
3970
      
3971
1.65k
      fGPSDifferential = stream.TagValue_uint32 (tagType);
3972
      
3973
      #if qDNGValidate
3974
      
3975
      if (gVerbose)
3976
        {
3977
        
3978
        printf ("GPSDifferential: ");
3979
        
3980
        switch (fGPSDifferential)
3981
          {
3982
          
3983
          case 0:
3984
            printf ("Measurement without differential correction");
3985
            break;
3986
            
3987
          case 1:
3988
            printf ("Differential correction applied");
3989
            break;
3990
            
3991
          default:
3992
            printf ("%u", (unsigned) fGPSDifferential);
3993
            
3994
          }
3995
        
3996
        printf ("\n");
3997
        
3998
        }
3999
        
4000
      #endif
4001
      
4002
1.65k
      break;
4003
      
4004
955
      }
4005
      
4006
105k
    default:
4007
105k
      {
4008
      
4009
105k
      return false;
4010
      
4011
955
      }
4012
      
4013
182k
    }
4014
    
4015
65.5k
  return true;
4016
  
4017
182k
  }
4018
      
4019
/*****************************************************************************/
4020
4021
// Parses tags that should only appear in Interoperability IFD
4022
4023
bool dng_exif::Parse_interoperability (dng_stream &stream,
4024
                       dng_shared & /* shared */,
4025
                     uint32 parentCode,
4026
                     uint32 tagCode,
4027
                     uint32 tagType,
4028
                     uint32 tagCount,
4029
                     uint64 /* tagOffset */)
4030
1.49k
  {
4031
  
4032
1.49k
  switch (tagCode)
4033
1.49k
    {
4034
    
4035
106
    case tcInteroperabilityIndex:
4036
106
      {
4037
      
4038
106
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
4039
      
4040
106
      CheckTagCount (parentCode, tagCode, tagCount, 4);
4041
      
4042
106
      ParseStringTag (stream,
4043
106
              parentCode,
4044
106
              tagCode,
4045
106
              tagCount,
4046
106
              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
106
      break;
4064
      
4065
0
      }
4066
4067
496
    case tcInteroperabilityVersion:
4068
496
      {
4069
      
4070
496
      CheckTagType (parentCode, tagCode, tagType, ttUndefined);
4071
      
4072
496
      CheckTagCount (parentCode, tagCode, tagCount, 4);
4073
      
4074
496
      uint32 b0 = stream.Get_uint8 ();
4075
496
      uint32 b1 = stream.Get_uint8 ();
4076
496
      uint32 b2 = stream.Get_uint8 ();
4077
496
      uint32 b3 = stream.Get_uint8 ();
4078
      
4079
496
      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
496
      break;
4098
      
4099
0
      }
4100
4101
84
    case tcRelatedImageFileFormat:
4102
84
      {
4103
      
4104
84
      CheckTagType (parentCode, tagCode, tagType, ttAscii);
4105
      
4106
84
      ParseStringTag (stream,
4107
84
              parentCode,
4108
84
              tagCode,
4109
84
              tagCount,
4110
84
              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
84
      break;
4128
      
4129
0
      }
4130
4131
33
    case tcRelatedImageWidth:
4132
33
      {
4133
      
4134
33
      CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
4135
      
4136
33
      CheckTagCount (parentCode, tagCode, tagCount, 1);
4137
      
4138
33
      fRelatedImageWidth = stream.TagValue_uint32 (tagType);
4139
      
4140
      #if qDNGValidate
4141
      
4142
      if (gVerbose)
4143
        {
4144
        printf ("RelatedImageWidth: %u\n", (unsigned) fRelatedImageWidth);
4145
        }
4146
        
4147
      #endif
4148
        
4149
33
      break;
4150
      
4151
0
      }
4152
    
4153
52
    case tcRelatedImageLength:
4154
52
      {
4155
      
4156
52
      CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong);
4157
      
4158
52
      CheckTagCount (parentCode, tagCode, tagCount, 1);
4159
      
4160
52
      fRelatedImageLength = stream.TagValue_uint32 (tagType);
4161
      
4162
      #if qDNGValidate
4163
      
4164
      if (gVerbose)
4165
        {
4166
        printf ("RelatedImageLength: %u\n", (unsigned) fRelatedImageLength);
4167
        }
4168
        
4169
      #endif
4170
        
4171
52
      break;
4172
      
4173
0
      }
4174
    
4175
719
    default:
4176
719
      {
4177
      
4178
719
      return false;
4179
      
4180
0
      }
4181
      
4182
1.49k
    }
4183
    
4184
771
  return true;
4185
  
4186
1.49k
  }
4187
                 
4188
/*****************************************************************************/
4189
4190
void dng_exif::PostParse (dng_host & /* host */,
4191
              dng_shared & /* shared */)
4192
80.2k
  {
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
80.2k
  if (fDateTime.NotValid () && fDateTimeOriginal.IsValid ())
4308
421
    {
4309
    
4310
421
    fDateTime = fDateTimeOriginal;
4311
    
4312
421
    }
4313
4314
  // Mirror EXIF 2.3 sensitivity tags to ISOSpeedRatings.
4315
4316
80.2k
  if (fISOSpeedRatings [0] == 0 || fISOSpeedRatings [0] == 65535)
4317
77.6k
    {
4318
4319
    // Prefer Recommended Exposure Index, then Standard Output Sensitivity, then
4320
    // ISO Speed, then Exposure Index.
4321
    
4322
77.6k
    if (fRecommendedExposureIndex != 0 &&
4323
593
      (fSensitivityType == stRecommendedExposureIndex ||
4324
582
       fSensitivityType == stSOSandREI        ||
4325
424
       fSensitivityType == stREIandISOSpeed      ||
4326
408
       fSensitivityType == stSOSandREIandISOSpeed))
4327
195
      {
4328
      
4329
195
      fISOSpeedRatings [0] = fRecommendedExposureIndex;
4330
      
4331
195
      }
4332
      
4333
77.4k
    else if (fStandardOutputSensitivity != 0 &&
4334
550
         (fSensitivityType == stStandardOutputSensitivity ||
4335
532
          fSensitivityType == stSOSandREI          ||
4336
355
          fSensitivityType == stSOSandISOSpeed        ||
4337
322
          fSensitivityType == stSOSandREIandISOSpeed))
4338
239
      {
4339
      
4340
239
      fISOSpeedRatings [0] = fStandardOutputSensitivity;
4341
      
4342
239
      }
4343
4344
77.2k
    else if (fISOSpeed != 0 &&
4345
443
         (fSensitivityType == stISOSpeed     ||
4346
417
          fSensitivityType == stSOSandISOSpeed ||
4347
401
          fSensitivityType == stREIandISOSpeed ||
4348
378
          fSensitivityType == stSOSandREIandISOSpeed))
4349
74
      {
4350
      
4351
74
      fISOSpeedRatings [0] = fISOSpeed;
4352
      
4353
74
      }
4354
    
4355
77.6k
    }
4356
  
4357
  // Mirror ExposureIndex to ISOSpeedRatings.
4358
4359
80.2k
  if (fExposureIndex.IsValid () && fISOSpeedRatings [0] == 0)
4360
5.91k
    {
4361
4362
5.91k
    fISOSpeedRatings [0] = Round_uint32 (fExposureIndex.As_real64 ());
4363
4364
5.91k
    }
4365
4366
  // Kodak sets the GPSAltitudeRef without setting the GPSAltitude.
4367
  
4368
80.2k
  if (fGPSAltitude.NotValid ())
4369
79.4k
    {
4370
    
4371
79.4k
    fGPSAltitudeRef = 0xFFFFFFFF;
4372
    
4373
79.4k
    }
4374
    
4375
  // If there is no valid GPS data, clear the GPS version number.
4376
  
4377
80.2k
  if (fGPSLatitude  [0].NotValid () &&
4378
79.8k
    fGPSLongitude [0].NotValid () &&
4379
79.4k
    fGPSAltitude     .NotValid () &&
4380
78.8k
    fGPSTimeStamp [0].NotValid () &&
4381
78.5k
    fGPSDateStamp    .IsEmpty  ())
4382
78.2k
    {
4383
    
4384
78.2k
    fGPSVersionID = 0;
4385
    
4386
78.2k
    }
4387
    
4388
80.2k
  }
4389
           
4390
/*****************************************************************************/