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