Coverage Report

Created: 2026-04-01 06:23

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