File indexing completed on 2025-01-19 03:54:57
0001 /*****************************************************************************/ 0002 // Copyright 2006-2019 Adobe Systems Incorporated 0003 // All Rights Reserved. 0004 // 0005 // NOTICE: Adobe permits you to use, modify, and distribute this file in 0006 // accordance with the terms of the Adobe license agreement accompanying it. 0007 /*****************************************************************************/ 0008 0009 #include "dng_exif.h" 0010 0011 #include "dng_tag_codes.h" 0012 #include "dng_tag_types.h" 0013 #include "dng_parse_utils.h" 0014 #include "dng_globals.h" 0015 #include "dng_exceptions.h" 0016 #include "dng_tag_values.h" 0017 #include "dng_utils.h" 0018 0019 /*****************************************************************************/ 0020 0021 dng_exif::dng_exif () 0022 0023 : fImageDescription () 0024 , fMake () 0025 , fModel () 0026 , fSoftware () 0027 , fArtist () 0028 , fCopyright () 0029 , fCopyright2 () 0030 , fUserComment () 0031 0032 , fDateTime () 0033 , fDateTimeStorageInfo () 0034 0035 , fDateTimeOriginal () 0036 , fDateTimeOriginalStorageInfo () 0037 0038 , fDateTimeDigitized () 0039 , fDateTimeDigitizedStorageInfo () 0040 0041 , fTIFF_EP_StandardID (0) 0042 , fExifVersion (0) 0043 , fFlashPixVersion (0) 0044 0045 , fExposureTime () 0046 , fFNumber () 0047 , fShutterSpeedValue () 0048 , fApertureValue () 0049 , fBrightnessValue () 0050 , fExposureBiasValue () 0051 , fMaxApertureValue () 0052 , fFocalLength () 0053 , fDigitalZoomRatio () 0054 , fExposureIndex () 0055 , fSubjectDistance () 0056 , fGamma () 0057 0058 , fBatteryLevelR () 0059 , fBatteryLevelA () 0060 0061 , fExposureProgram (0xFFFFFFFF) 0062 , fMeteringMode (0xFFFFFFFF) 0063 , fLightSource (0xFFFFFFFF) 0064 , fFlash (0xFFFFFFFF) 0065 , fFlashMask (0x0000FFFF) 0066 , fSensingMethod (0xFFFFFFFF) 0067 , fColorSpace (0xFFFFFFFF) 0068 , fFileSource (0xFFFFFFFF) 0069 , fSceneType (0xFFFFFFFF) 0070 , fCustomRendered (0xFFFFFFFF) 0071 , fExposureMode (0xFFFFFFFF) 0072 , fWhiteBalance (0xFFFFFFFF) 0073 , fSceneCaptureType (0xFFFFFFFF) 0074 , fGainControl (0xFFFFFFFF) 0075 , fContrast (0xFFFFFFFF) 0076 , fSaturation (0xFFFFFFFF) 0077 , fSharpness (0xFFFFFFFF) 0078 , fSubjectDistanceRange (0xFFFFFFFF) 0079 , fSelfTimerMode (0xFFFFFFFF) 0080 , fImageNumber (0xFFFFFFFF) 0081 0082 , fFocalLengthIn35mmFilm (0) 0083 0084 , fSensitivityType (0) 0085 , fStandardOutputSensitivity (0) 0086 , fRecommendedExposureIndex (0) 0087 , fISOSpeed (0) 0088 , fISOSpeedLatitudeyyy (0) 0089 , fISOSpeedLatitudezzz (0) 0090 0091 , fSubjectAreaCount (0) 0092 0093 , fComponentsConfiguration (0) 0094 0095 , fCompresssedBitsPerPixel () 0096 0097 , fPixelXDimension (0) 0098 , fPixelYDimension (0) 0099 0100 , fFocalPlaneXResolution () 0101 , fFocalPlaneYResolution () 0102 0103 , fFocalPlaneResolutionUnit (0xFFFFFFFF) 0104 0105 , fCFARepeatPatternRows (0) 0106 , fCFARepeatPatternCols (0) 0107 0108 , fImageUniqueID () 0109 0110 , fGPSVersionID (0) 0111 , fGPSLatitudeRef () 0112 , fGPSLongitudeRef () 0113 , fGPSAltitudeRef (0xFFFFFFFF) 0114 , fGPSAltitude () 0115 , fGPSSatellites () 0116 , fGPSStatus () 0117 , fGPSMeasureMode () 0118 , fGPSDOP () 0119 , fGPSSpeedRef () 0120 , fGPSSpeed () 0121 , fGPSTrackRef () 0122 , fGPSTrack () 0123 , fGPSImgDirectionRef () 0124 , fGPSImgDirection () 0125 , fGPSMapDatum () 0126 , fGPSDestLatitudeRef () 0127 , fGPSDestLongitudeRef () 0128 , fGPSDestBearingRef () 0129 , fGPSDestBearing () 0130 , fGPSDestDistanceRef () 0131 , fGPSDestDistance () 0132 , fGPSProcessingMethod () 0133 , fGPSAreaInformation () 0134 , fGPSDateStamp () 0135 , fGPSDifferential (0xFFFFFFFF) 0136 , fGPSHPositioningError () 0137 0138 , fInteroperabilityIndex () 0139 0140 , fInteroperabilityVersion (0) 0141 0142 , fRelatedImageFileFormat () 0143 0144 , fRelatedImageWidth (0) 0145 , fRelatedImageLength (0) 0146 0147 , fCameraSerialNumber () 0148 0149 , fLensID () 0150 , fLensMake () 0151 , fLensName () 0152 , fLensSerialNumber () 0153 0154 , fLensNameWasReadFromExif (false) 0155 0156 , fApproxFocusDistance () 0157 0158 , fFlashCompensation () 0159 0160 , fOwnerName () 0161 , fFirmware () 0162 0163 , fTemperature () 0164 , fHumidity () 0165 , fPressure () 0166 , fWaterDepth () 0167 , fAcceleration () 0168 , fCameraElevationAngle () 0169 0170 , fTitle () 0171 0172 { 0173 0174 uint32 j; 0175 uint32 k; 0176 0177 fISOSpeedRatings [0] = 0; 0178 fISOSpeedRatings [1] = 0; 0179 fISOSpeedRatings [2] = 0; 0180 0181 for (j = 0; j < kMaxCFAPattern; j++) 0182 for (k = 0; k < kMaxCFAPattern; k++) 0183 { 0184 fCFAPattern [j] [k] = 255; 0185 } 0186 0187 memset (fLensDistortInfo, 0, sizeof (fLensDistortInfo)); 0188 0189 } 0190 0191 /*****************************************************************************/ 0192 0193 dng_exif::~dng_exif () 0194 { 0195 0196 } 0197 0198 /*****************************************************************************/ 0199 0200 dng_exif * dng_exif::Clone () const 0201 { 0202 0203 dng_exif *result = new dng_exif (*this); 0204 0205 if (!result) 0206 { 0207 ThrowMemoryFull (); 0208 } 0209 0210 return result; 0211 0212 } 0213 0214 /*****************************************************************************/ 0215 0216 void dng_exif::SetEmpty () 0217 { 0218 0219 *this = dng_exif (); 0220 0221 } 0222 0223 /*****************************************************************************/ 0224 0225 void dng_exif::CopyGPSFrom (const dng_exif &exif) 0226 { 0227 0228 fGPSVersionID = exif.fGPSVersionID; 0229 fGPSLatitudeRef = exif.fGPSLatitudeRef; 0230 fGPSLatitude [0] = exif.fGPSLatitude [0]; 0231 fGPSLatitude [1] = exif.fGPSLatitude [1]; 0232 fGPSLatitude [2] = exif.fGPSLatitude [2]; 0233 fGPSLongitudeRef = exif.fGPSLongitudeRef; 0234 fGPSLongitude [0] = exif.fGPSLongitude [0]; 0235 fGPSLongitude [1] = exif.fGPSLongitude [1]; 0236 fGPSLongitude [2] = exif.fGPSLongitude [2]; 0237 fGPSAltitudeRef = exif.fGPSAltitudeRef; 0238 fGPSAltitude = exif.fGPSAltitude; 0239 fGPSTimeStamp [0] = exif.fGPSTimeStamp [0]; 0240 fGPSTimeStamp [1] = exif.fGPSTimeStamp [1]; 0241 fGPSTimeStamp [2] = exif.fGPSTimeStamp [2]; 0242 fGPSSatellites = exif.fGPSSatellites; 0243 fGPSStatus = exif.fGPSStatus; 0244 fGPSMeasureMode = exif.fGPSMeasureMode; 0245 fGPSDOP = exif.fGPSDOP; 0246 fGPSSpeedRef = exif.fGPSSpeedRef; 0247 fGPSSpeed = exif.fGPSSpeed; 0248 fGPSTrackRef = exif.fGPSTrackRef; 0249 fGPSTrack = exif.fGPSTrack; 0250 fGPSImgDirectionRef = exif.fGPSImgDirectionRef; 0251 fGPSImgDirection = exif.fGPSImgDirection; 0252 fGPSMapDatum = exif.fGPSMapDatum; 0253 fGPSDestLatitudeRef = exif.fGPSDestLatitudeRef; 0254 fGPSDestLatitude [0] = exif.fGPSDestLatitude [0]; 0255 fGPSDestLatitude [1] = exif.fGPSDestLatitude [1]; 0256 fGPSDestLatitude [2] = exif.fGPSDestLatitude [2]; 0257 fGPSDestLongitudeRef = exif.fGPSDestLongitudeRef; 0258 fGPSDestLongitude [0] = exif.fGPSDestLongitude [0]; 0259 fGPSDestLongitude [1] = exif.fGPSDestLongitude [1]; 0260 fGPSDestLongitude [2] = exif.fGPSDestLongitude [2]; 0261 fGPSDestBearingRef = exif.fGPSDestBearingRef; 0262 fGPSDestBearing = exif.fGPSDestBearing; 0263 fGPSDestDistanceRef = exif.fGPSDestDistanceRef; 0264 fGPSDestDistance = exif.fGPSDestDistance; 0265 fGPSProcessingMethod = exif.fGPSProcessingMethod; 0266 fGPSAreaInformation = exif.fGPSAreaInformation; 0267 fGPSDateStamp = exif.fGPSDateStamp; 0268 fGPSDifferential = exif.fGPSDifferential; 0269 fGPSHPositioningError = exif.fGPSHPositioningError; 0270 0271 } 0272 0273 /*****************************************************************************/ 0274 0275 // Fix up common errors and rounding issues with EXIF exposure times. 0276 0277 real64 dng_exif::SnapExposureTime (real64 et) 0278 { 0279 0280 // Protection against invalid values. 0281 0282 if (et <= 0.0) 0283 return 0.0; 0284 0285 // If near a standard shutter speed, snap to it. 0286 0287 static const real64 kStandardSpeed [] = 0288 { 0289 30.0, 0290 25.0, 0291 20.0, 0292 15.0, 0293 13.0, 0294 10.0, 0295 8.0, 0296 6.0, 0297 5.0, 0298 4.0, 0299 3.2, 0300 3.0, 0301 2.5, 0302 2.0, 0303 1.6, 0304 1.5, 0305 1.3, 0306 1.0, 0307 0.8, 0308 0.7, 0309 0.6, 0310 0.5, 0311 0.4, 0312 0.3, 0313 1.0 / 4.0, 0314 1.0 / 5.0, 0315 1.0 / 6.0, 0316 1.0 / 8.0, 0317 1.0 / 10.0, 0318 1.0 / 13.0, 0319 1.0 / 15.0, 0320 1.0 / 20.0, 0321 1.0 / 25.0, 0322 1.0 / 30.0, 0323 1.0 / 40.0, 0324 1.0 / 45.0, 0325 1.0 / 50.0, 0326 1.0 / 60.0, 0327 1.0 / 80.0, 0328 1.0 / 90.0, 0329 1.0 / 100.0, 0330 1.0 / 125.0, 0331 1.0 / 160.0, 0332 1.0 / 180.0, 0333 1.0 / 200.0, 0334 1.0 / 250.0, 0335 1.0 / 320.0, 0336 1.0 / 350.0, 0337 1.0 / 400.0, 0338 1.0 / 500.0, 0339 1.0 / 640.0, 0340 1.0 / 750.0, 0341 1.0 / 800.0, 0342 1.0 / 1000.0, 0343 1.0 / 1250.0, 0344 1.0 / 1500.0, 0345 1.0 / 1600.0, 0346 1.0 / 2000.0, 0347 1.0 / 2500.0, 0348 1.0 / 3000.0, 0349 1.0 / 3200.0, 0350 1.0 / 4000.0, 0351 1.0 / 5000.0, 0352 1.0 / 6000.0, 0353 1.0 / 6400.0, 0354 1.0 / 8000.0, 0355 1.0 / 10000.0, 0356 1.0 / 12000.0, 0357 1.0 / 12800.0, 0358 1.0 / 16000.0 0359 }; 0360 0361 uint32 count = sizeof (kStandardSpeed ) / 0362 sizeof (kStandardSpeed [0]); 0363 0364 for (uint32 fudge = 0; fudge <= 1; fudge++) 0365 { 0366 0367 real64 testSpeed = et; 0368 0369 if (fudge == 1) 0370 { 0371 0372 // Often APEX values are rounded to a power of two, 0373 // which results in non-standard shutter speeds. 0374 0375 if (et >= 0.1) 0376 { 0377 0378 // No fudging slower than 1/10 second 0379 0380 break; 0381 0382 } 0383 0384 else if (et >= 0.01) 0385 { 0386 0387 // Between 1/10 and 1/100 the commonly misrounded 0388 // speeds are 1/15, 1/30, 1/60, which are often encoded as 0389 // 1/16, 1/32, 1/64. Try fudging and see if we get 0390 // near a standard speed. 0391 0392 testSpeed *= 16.0 / 15.0; 0393 0394 } 0395 0396 else 0397 { 0398 0399 // Faster than 1/100, the commonly misrounded 0400 // speeds are 1/125, 1/250, 1/500, etc., which 0401 // are often encoded as 1/128, 1/256, 1/512. 0402 0403 testSpeed *= 128.0 / 125.0; 0404 0405 } 0406 0407 } 0408 0409 for (uint32 index = 0; index < count; index++) 0410 { 0411 0412 if (testSpeed >= kStandardSpeed [index] * 0.98 && 0413 testSpeed <= kStandardSpeed [index] * 1.02) 0414 { 0415 0416 return kStandardSpeed [index]; 0417 0418 } 0419 0420 } 0421 0422 } 0423 0424 // We are not near any standard speeds. Round the non-standard value to something 0425 // that looks reasonable. 0426 0427 if (et >= 10.0) 0428 { 0429 0430 // Round to nearest second. 0431 0432 et = floor (et + 0.5); 0433 0434 } 0435 0436 else if (et >= 0.5) 0437 { 0438 0439 // Round to nearest 1/10 second 0440 0441 et = floor (et * 10.0 + 0.5) * 0.1; 0442 0443 } 0444 0445 else if (et >= 1.0 / 20.0) 0446 { 0447 0448 // Round to an exact inverse. 0449 0450 et = 1.0 / floor (1.0 / et + 0.5); 0451 0452 } 0453 0454 else if (et >= 1.0 / 130.0) 0455 { 0456 0457 // Round inverse to multiple of 5 0458 0459 et = 0.2 / floor (0.2 / et + 0.5); 0460 0461 } 0462 0463 else if (et >= 1.0 / 750.0) 0464 { 0465 0466 // Round inverse to multiple of 10 0467 0468 et = 0.1 / floor (0.1 / et + 0.5); 0469 0470 } 0471 0472 else if (et >= 1.0 / 1300.0) 0473 { 0474 0475 // Round inverse to multiple of 50 0476 0477 et = 0.02 / floor (0.02 / et + 0.5); 0478 0479 } 0480 0481 else if (et >= 1.0 / 15000.0) 0482 { 0483 0484 // Round inverse to multiple of 100 0485 0486 et = 0.01 / floor (0.01 / et + 0.5); 0487 0488 } 0489 0490 else 0491 { 0492 0493 // Round inverse to multiple of 1000 0494 0495 et = 0.001 / floor (0.001 / et + 0.5); 0496 0497 } 0498 0499 return et; 0500 0501 } 0502 0503 /*****************************************************************************/ 0504 0505 void dng_exif::SetExposureTime (real64 et, bool snap) 0506 { 0507 0508 fExposureTime.Clear (); 0509 0510 fShutterSpeedValue.Clear (); 0511 0512 if (snap) 0513 { 0514 0515 et = SnapExposureTime (et); 0516 0517 } 0518 0519 if (et >= 1.0 / 1073741824.0 && et <= 1073741824.0) 0520 { 0521 0522 if (et >= 100.0) 0523 { 0524 0525 fExposureTime.Set_real64 (et, 1); 0526 0527 } 0528 0529 else if (et >= 1.0) 0530 { 0531 0532 fExposureTime.Set_real64 (et, 10); 0533 0534 fExposureTime.ReduceByFactor (10); 0535 0536 } 0537 0538 else if (et <= 0.1) 0539 { 0540 0541 fExposureTime = dng_urational (1, Round_uint32 (1.0 / et)); 0542 0543 } 0544 0545 else 0546 { 0547 0548 fExposureTime.Set_real64 (et, 100); 0549 0550 fExposureTime.ReduceByFactor (10); 0551 0552 for (uint32 f = 2; f <= 9; f++) 0553 { 0554 0555 real64 z = 1.0 / (real64) f / et; 0556 0557 if (z >= 0.99 && z <= 1.01) 0558 { 0559 0560 fExposureTime = dng_urational (1, f); 0561 0562 break; 0563 0564 } 0565 0566 } 0567 0568 } 0569 0570 // Now mirror this value to the ShutterSpeedValue field. 0571 0572 et = fExposureTime.As_real64 (); 0573 0574 fShutterSpeedValue.Set_real64 (-log (et) / log (2.0), 1000000); 0575 0576 fShutterSpeedValue.ReduceByFactor (10); 0577 fShutterSpeedValue.ReduceByFactor (10); 0578 fShutterSpeedValue.ReduceByFactor (10); 0579 fShutterSpeedValue.ReduceByFactor (10); 0580 fShutterSpeedValue.ReduceByFactor (10); 0581 fShutterSpeedValue.ReduceByFactor (10); 0582 0583 } 0584 0585 } 0586 0587 /*****************************************************************************/ 0588 0589 void dng_exif::SetShutterSpeedValue (real64 ss) 0590 { 0591 0592 if (fExposureTime.NotValid ()) 0593 { 0594 0595 real64 et = pow (2.0, -ss); 0596 0597 SetExposureTime (et, true); 0598 0599 } 0600 0601 } 0602 0603 /******************************************************************************/ 0604 0605 dng_urational dng_exif::EncodeFNumber (real64 fs) 0606 { 0607 0608 dng_urational y; 0609 0610 if (fs > 10.0) 0611 { 0612 0613 y.Set_real64 (fs, 1); 0614 0615 } 0616 0617 else if (fs < 1.0) 0618 { 0619 0620 y.Set_real64 (fs, 100); 0621 0622 y.ReduceByFactor (10); 0623 y.ReduceByFactor (10); 0624 0625 } 0626 0627 else 0628 { 0629 0630 y.Set_real64 (fs, 10); 0631 0632 y.ReduceByFactor (10); 0633 0634 } 0635 0636 return y; 0637 0638 } 0639 0640 /*****************************************************************************/ 0641 0642 void dng_exif::SetFNumber (real64 fs) 0643 { 0644 0645 fFNumber.Clear (); 0646 0647 fApertureValue.Clear (); 0648 0649 // Allow f-number values less than 1.0 (e.g., f/0.95), even though they would 0650 // correspond to negative APEX values, which the EXIF specification does not 0651 // support (ApertureValue is a rational, not srational). The ApertureValue tag 0652 // will be omitted in the case where fs < 1.0. 0653 0654 if (fs > 0.0 && fs <= 32768.0) 0655 { 0656 0657 fFNumber = EncodeFNumber (fs); 0658 0659 // Now mirror this value to the ApertureValue field. 0660 0661 real64 av = FNumberToApertureValue (fFNumber); 0662 0663 if (av >= 0.0 && av <= 99.99) 0664 { 0665 0666 fApertureValue.Set_real64 (av, 1000000); 0667 0668 fApertureValue.ReduceByFactor (10); 0669 fApertureValue.ReduceByFactor (10); 0670 fApertureValue.ReduceByFactor (10); 0671 fApertureValue.ReduceByFactor (10); 0672 fApertureValue.ReduceByFactor (10); 0673 fApertureValue.ReduceByFactor (10); 0674 0675 } 0676 0677 } 0678 0679 } 0680 0681 /*****************************************************************************/ 0682 0683 void dng_exif::SetApertureValue (real64 av) 0684 { 0685 0686 if (fFNumber.NotValid ()) 0687 { 0688 0689 SetFNumber (ApertureValueToFNumber (av)); 0690 0691 } 0692 0693 } 0694 0695 /*****************************************************************************/ 0696 0697 real64 dng_exif::ApertureValueToFNumber (real64 av) 0698 { 0699 0700 return pow (2.0, 0.5 * av); 0701 0702 } 0703 0704 /*****************************************************************************/ 0705 0706 real64 dng_exif::ApertureValueToFNumber (const dng_urational &av) 0707 { 0708 0709 return ApertureValueToFNumber (av.As_real64 ()); 0710 0711 } 0712 0713 /*****************************************************************************/ 0714 0715 real64 dng_exif::FNumberToApertureValue (real64 fNumber) 0716 { 0717 0718 return 2.0 * log (fNumber) / log (2.0); 0719 0720 } 0721 0722 /*****************************************************************************/ 0723 0724 real64 dng_exif::FNumberToApertureValue (const dng_urational &fNumber) 0725 { 0726 0727 return FNumberToApertureValue (fNumber.As_real64 ()); 0728 0729 } 0730 0731 /*****************************************************************************/ 0732 0733 void dng_exif::UpdateDateTime (const dng_date_time_info &dt) 0734 { 0735 0736 fDateTime = dt; 0737 0738 } 0739 0740 /*****************************************************************************/ 0741 0742 bool dng_exif::AtLeastVersion0230 () const 0743 { 0744 0745 return fExifVersion >= DNG_CHAR4 ('0','2','3','0'); 0746 0747 } 0748 0749 /*****************************************************************************/ 0750 0751 bool dng_exif::AtLeastVersion0231 () const 0752 { 0753 0754 return fExifVersion >= DNG_CHAR4 ('0','2','3','1'); 0755 0756 } 0757 0758 /*****************************************************************************/ 0759 0760 void dng_exif::SetVersion0231 () 0761 { 0762 0763 fExifVersion = DNG_CHAR4 ('0','2','3','1'); 0764 0765 } 0766 0767 /*****************************************************************************/ 0768 0769 bool dng_exif::HasLensDistortInfo () const 0770 { 0771 0772 return (fLensDistortInfo [0] . IsValid () && 0773 fLensDistortInfo [1] . IsValid () && 0774 fLensDistortInfo [2] . IsValid () && 0775 fLensDistortInfo [3] . IsValid ()); 0776 0777 } 0778 0779 /*****************************************************************************/ 0780 0781 void dng_exif::SetLensDistortInfo (const dng_vector ¶ms) 0782 { 0783 0784 if (params.Count () != 4) 0785 { 0786 return; 0787 } 0788 0789 fLensDistortInfo [0] . Set_real64 (params [0]); 0790 fLensDistortInfo [1] . Set_real64 (params [1]); 0791 fLensDistortInfo [2] . Set_real64 (params [2]); 0792 fLensDistortInfo [3] . Set_real64 (params [3]); 0793 0794 } 0795 0796 /*****************************************************************************/ 0797 0798 bool dng_exif::ParseTag (dng_stream &stream, 0799 dng_shared &shared, 0800 uint32 parentCode, 0801 bool isMainIFD, 0802 uint32 tagCode, 0803 uint32 tagType, 0804 uint32 tagCount, 0805 uint64 tagOffset) 0806 { 0807 0808 if (parentCode == 0) 0809 { 0810 0811 if (Parse_ifd0 (stream, 0812 shared, 0813 parentCode, 0814 tagCode, 0815 tagType, 0816 tagCount, 0817 tagOffset)) 0818 { 0819 0820 return true; 0821 0822 } 0823 0824 } 0825 0826 if (parentCode == 0 || isMainIFD) 0827 { 0828 0829 if (Parse_ifd0_main (stream, 0830 shared, 0831 parentCode, 0832 tagCode, 0833 tagType, 0834 tagCount, 0835 tagOffset)) 0836 { 0837 0838 return true; 0839 0840 } 0841 0842 } 0843 0844 if (parentCode == 0 || 0845 parentCode == tcExifIFD) 0846 { 0847 0848 if (Parse_ifd0_exif (stream, 0849 shared, 0850 parentCode, 0851 tagCode, 0852 tagType, 0853 tagCount, 0854 tagOffset)) 0855 { 0856 0857 return true; 0858 0859 } 0860 0861 } 0862 0863 if (parentCode == tcGPSInfo) 0864 { 0865 0866 if (Parse_gps (stream, 0867 shared, 0868 parentCode, 0869 tagCode, 0870 tagType, 0871 tagCount, 0872 tagOffset)) 0873 { 0874 0875 return true; 0876 0877 } 0878 0879 } 0880 0881 if (parentCode == tcInteroperabilityIFD) 0882 { 0883 0884 if (Parse_interoperability (stream, 0885 shared, 0886 parentCode, 0887 tagCode, 0888 tagType, 0889 tagCount, 0890 tagOffset)) 0891 { 0892 0893 return true; 0894 0895 } 0896 0897 } 0898 0899 return false; 0900 0901 } 0902 0903 /*****************************************************************************/ 0904 0905 // Parses tags that should only appear in IFD 0. 0906 0907 bool dng_exif::Parse_ifd0 (dng_stream &stream, 0908 dng_shared & /* shared */, 0909 uint32 parentCode, 0910 uint32 tagCode, 0911 uint32 tagType, 0912 uint32 tagCount, 0913 uint64 /* tagOffset */) 0914 { 0915 0916 switch (tagCode) 0917 { 0918 0919 case tcImageDescription: 0920 { 0921 0922 CheckTagType (parentCode, tagCode, tagType, ttAscii); 0923 0924 ParseStringTag (stream, 0925 parentCode, 0926 tagCode, 0927 tagCount, 0928 fImageDescription); 0929 0930 #if qDNGValidate 0931 0932 if (gVerbose) 0933 { 0934 0935 printf ("ImageDescription: "); 0936 0937 DumpString (fImageDescription); 0938 0939 printf ("\n"); 0940 0941 } 0942 0943 #endif 0944 0945 break; 0946 0947 } 0948 0949 case tcMake: 0950 { 0951 0952 CheckTagType (parentCode, tagCode, tagType, ttAscii); 0953 0954 ParseStringTag (stream, 0955 parentCode, 0956 tagCode, 0957 tagCount, 0958 fMake); 0959 0960 #if qDNGValidate 0961 0962 if (gVerbose) 0963 { 0964 0965 printf ("Make: "); 0966 0967 DumpString (fMake); 0968 0969 printf ("\n"); 0970 0971 } 0972 0973 #endif 0974 0975 break; 0976 0977 } 0978 0979 case tcModel: 0980 { 0981 0982 CheckTagType (parentCode, tagCode, tagType, ttAscii); 0983 0984 ParseStringTag (stream, 0985 parentCode, 0986 tagCode, 0987 tagCount, 0988 fModel); 0989 0990 #if qDNGValidate 0991 0992 if (gVerbose) 0993 { 0994 0995 printf ("Model: "); 0996 0997 DumpString (fModel); 0998 0999 printf ("\n"); 1000 1001 } 1002 1003 #endif 1004 1005 break; 1006 1007 } 1008 1009 case tcSoftware: 1010 { 1011 1012 CheckTagType (parentCode, tagCode, tagType, ttAscii); 1013 1014 ParseStringTag (stream, 1015 parentCode, 1016 tagCode, 1017 tagCount, 1018 fSoftware); 1019 1020 #if qDNGValidate 1021 1022 if (gVerbose) 1023 { 1024 1025 printf ("Software: "); 1026 1027 DumpString (fSoftware); 1028 1029 printf ("\n"); 1030 1031 } 1032 1033 #endif 1034 1035 break; 1036 1037 } 1038 1039 case tcDateTime: 1040 { 1041 1042 uint64 tagPosition = stream.PositionInOriginalFile (); 1043 1044 dng_date_time dt; 1045 1046 if (!ParseDateTimeTag (stream, 1047 parentCode, 1048 tagCode, 1049 tagType, 1050 tagCount, 1051 dt)) 1052 { 1053 return false; 1054 } 1055 1056 fDateTime.SetDateTime (dt); 1057 1058 fDateTimeStorageInfo = dng_date_time_storage_info (tagPosition, 1059 dng_date_time_format_exif); 1060 1061 #if qDNGValidate 1062 1063 if (gVerbose) 1064 { 1065 1066 printf ("DateTime: "); 1067 1068 DumpDateTime (fDateTime.DateTime ()); 1069 1070 printf ("\n"); 1071 1072 } 1073 1074 #endif 1075 1076 break; 1077 1078 } 1079 1080 case tcArtist: 1081 { 1082 1083 CheckTagType (parentCode, tagCode, tagType, ttAscii); 1084 1085 ParseStringTag (stream, 1086 parentCode, 1087 tagCode, 1088 tagCount, 1089 fArtist); 1090 1091 #if qDNGValidate 1092 1093 if (gVerbose) 1094 { 1095 1096 printf ("Artist: "); 1097 1098 DumpString (fArtist); 1099 1100 printf ("\n"); 1101 1102 } 1103 1104 #endif 1105 1106 break; 1107 1108 } 1109 1110 case tcCopyright: 1111 { 1112 1113 CheckTagType (parentCode, tagCode, tagType, ttAscii); 1114 1115 ParseDualStringTag (stream, 1116 parentCode, 1117 tagCode, 1118 tagCount, 1119 fCopyright, 1120 fCopyright2); 1121 1122 #if qDNGValidate 1123 1124 if (gVerbose) 1125 { 1126 1127 printf ("Copyright: "); 1128 1129 DumpString (fCopyright); 1130 1131 if (fCopyright2.Get () [0] != 0) 1132 { 1133 1134 printf (" "); 1135 1136 DumpString (fCopyright2); 1137 1138 } 1139 1140 printf ("\n"); 1141 1142 } 1143 1144 #endif 1145 1146 break; 1147 1148 } 1149 1150 case tcTIFF_EP_StandardID: 1151 { 1152 1153 CheckTagType (parentCode, tagCode, tagType, ttByte); 1154 1155 CheckTagCount (parentCode, tagCode, tagCount, 4); 1156 1157 uint32 b0 = stream.Get_uint8 (); 1158 uint32 b1 = stream.Get_uint8 (); 1159 uint32 b2 = stream.Get_uint8 (); 1160 uint32 b3 = stream.Get_uint8 (); 1161 1162 fTIFF_EP_StandardID = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; 1163 1164 #if qDNGValidate 1165 1166 if (gVerbose) 1167 { 1168 printf ("TIFF/EPStandardID: %u.%u.%u.%u\n", 1169 (unsigned) b0, 1170 (unsigned) b1, 1171 (unsigned) b2, 1172 (unsigned) b3); 1173 } 1174 1175 #endif 1176 1177 break; 1178 1179 } 1180 1181 case tcCameraSerialNumber: 1182 case tcKodakCameraSerialNumber: // Kodak uses a very similar tag. 1183 { 1184 1185 CheckTagType (parentCode, tagCode, tagType, ttAscii); 1186 1187 ParseStringTag (stream, 1188 parentCode, 1189 tagCode, 1190 tagCount, 1191 fCameraSerialNumber); 1192 1193 #if qDNGValidate 1194 1195 if (gVerbose) 1196 { 1197 1198 printf ("%s: ", LookupTagCode (parentCode, tagCode)); 1199 1200 DumpString (fCameraSerialNumber); 1201 1202 printf ("\n"); 1203 1204 } 1205 1206 #endif 1207 1208 break; 1209 1210 } 1211 1212 case tcLensInfo: 1213 { 1214 1215 CheckTagType (parentCode, tagCode, tagType, ttRational); 1216 1217 if (!CheckTagCount (parentCode, tagCode, tagCount, 4)) 1218 return false; 1219 1220 fLensInfo [0] = stream.TagValue_urational (tagType); 1221 fLensInfo [1] = stream.TagValue_urational (tagType); 1222 fLensInfo [2] = stream.TagValue_urational (tagType); 1223 fLensInfo [3] = stream.TagValue_urational (tagType); 1224 1225 // Some third party software wrote zero rather and undefined values 1226 // for unknown entries. Work around this bug. 1227 1228 for (uint32 j = 0; j < 4; j++) 1229 { 1230 1231 if (fLensInfo [j].IsValid () && fLensInfo [j].As_real64 () <= 0.0) 1232 { 1233 1234 fLensInfo [j] = dng_urational (0, 0); 1235 1236 #if qDNGValidate 1237 1238 ReportWarning ("Zero entry in LensInfo tag--should be undefined"); 1239 1240 #endif 1241 1242 } 1243 1244 } 1245 1246 #if qDNGValidate 1247 1248 if (gVerbose) 1249 { 1250 1251 printf ("LensInfo: "); 1252 1253 real64 minFL = fLensInfo [0].As_real64 (); 1254 real64 maxFL = fLensInfo [1].As_real64 (); 1255 1256 if (minFL == maxFL) 1257 printf ("%0.1f mm", minFL); 1258 else 1259 printf ("%0.1f-%0.1f mm", minFL, maxFL); 1260 1261 if (fLensInfo [2].d) 1262 { 1263 1264 real64 minFS = fLensInfo [2].As_real64 (); 1265 real64 maxFS = fLensInfo [3].As_real64 (); 1266 1267 if (minFS == maxFS) 1268 printf (" f/%0.1f", minFS); 1269 else 1270 printf (" f/%0.1f-%0.1f", minFS, maxFS); 1271 1272 } 1273 1274 printf ("\n"); 1275 1276 } 1277 1278 #endif 1279 1280 break; 1281 1282 } 1283 1284 default: 1285 { 1286 1287 return false; 1288 1289 } 1290 1291 } 1292 1293 return true; 1294 1295 } 1296 1297 /*****************************************************************************/ 1298 1299 // Parses tags that should only appear in IFD 0 or the main image IFD. 1300 1301 bool dng_exif::Parse_ifd0_main (dng_stream &stream, 1302 dng_shared & /* shared */, 1303 uint32 parentCode, 1304 uint32 tagCode, 1305 uint32 tagType, 1306 uint32 tagCount, 1307 uint64 /* tagOffset */) 1308 { 1309 1310 switch (tagCode) 1311 { 1312 1313 case tcFocalPlaneXResolution: 1314 { 1315 1316 CheckTagType (parentCode, tagCode, tagType, ttRational); 1317 1318 CheckTagCount (parentCode, tagCode, tagCount, 1); 1319 1320 fFocalPlaneXResolution = stream.TagValue_urational (tagType); 1321 1322 #if qDNGValidate 1323 1324 if (gVerbose) 1325 { 1326 1327 printf ("FocalPlaneXResolution: %0.4f\n", 1328 fFocalPlaneXResolution.As_real64 ()); 1329 1330 } 1331 1332 #endif 1333 1334 break; 1335 1336 } 1337 1338 case tcFocalPlaneYResolution: 1339 { 1340 1341 CheckTagType (parentCode, tagCode, tagType, ttRational); 1342 1343 CheckTagCount (parentCode, tagCode, tagCount, 1); 1344 1345 fFocalPlaneYResolution = stream.TagValue_urational (tagType); 1346 1347 #if qDNGValidate 1348 1349 if (gVerbose) 1350 { 1351 1352 printf ("FocalPlaneYResolution: %0.4f\n", 1353 fFocalPlaneYResolution.As_real64 ()); 1354 1355 } 1356 1357 #endif 1358 1359 break; 1360 1361 } 1362 1363 case tcFocalPlaneResolutionUnit: 1364 { 1365 1366 CheckTagType (parentCode, tagCode, tagType, ttShort); 1367 1368 CheckTagCount (parentCode, tagCode, tagCount, 1); 1369 1370 fFocalPlaneResolutionUnit = stream.TagValue_uint32 (tagType); 1371 1372 #if qDNGValidate 1373 1374 if (gVerbose) 1375 { 1376 1377 printf ("FocalPlaneResolutionUnit: %s\n", 1378 LookupResolutionUnit (fFocalPlaneResolutionUnit)); 1379 1380 } 1381 1382 #endif 1383 1384 break; 1385 1386 } 1387 1388 case tcSensingMethod: 1389 { 1390 1391 CheckTagType (parentCode, tagCode, tagType, ttShort); 1392 1393 CheckTagCount (parentCode, tagCode, tagCount, 1); 1394 1395 fSensingMethod = stream.TagValue_uint32 (tagType); 1396 1397 #if qDNGValidate 1398 1399 if (gVerbose) 1400 { 1401 1402 printf ("SensingMethod: %s\n", 1403 LookupSensingMethod (fSensingMethod)); 1404 1405 } 1406 1407 #endif 1408 1409 break; 1410 1411 } 1412 1413 default: 1414 { 1415 1416 return false; 1417 1418 } 1419 1420 } 1421 1422 return true; 1423 1424 } 1425 1426 /*****************************************************************************/ 1427 1428 // Parses tags that should only appear in IFD 0 or EXIF IFD. 1429 1430 bool dng_exif::Parse_ifd0_exif (dng_stream &stream, 1431 dng_shared & /* shared */, 1432 uint32 parentCode, 1433 uint32 tagCode, 1434 uint32 tagType, 1435 uint32 tagCount, 1436 uint64 /* tagOffset */) 1437 { 1438 1439 switch (tagCode) 1440 { 1441 1442 case tcBatteryLevel: 1443 { 1444 1445 CheckTagType (parentCode, tagCode, tagType, ttRational, ttAscii); 1446 1447 if (tagType == ttAscii) 1448 { 1449 1450 ParseStringTag (stream, 1451 parentCode, 1452 tagCode, 1453 tagCount, 1454 fBatteryLevelA); 1455 1456 } 1457 1458 else 1459 { 1460 1461 CheckTagCount (parentCode, tagCode, tagCount, 1); 1462 1463 fBatteryLevelR = stream.TagValue_urational (tagType); 1464 1465 } 1466 1467 #if qDNGValidate 1468 1469 if (gVerbose) 1470 { 1471 1472 printf ("BatteryLevel: "); 1473 1474 if (tagType == ttAscii) 1475 { 1476 1477 DumpString (fBatteryLevelA); 1478 1479 } 1480 1481 else 1482 { 1483 1484 printf ("%0.2f", fBatteryLevelR.As_real64 ()); 1485 1486 } 1487 1488 printf ("\n"); 1489 1490 } 1491 1492 #endif 1493 1494 break; 1495 1496 } 1497 1498 case tcExposureTime: 1499 { 1500 1501 CheckTagType (parentCode, tagCode, tagType, ttRational); 1502 1503 CheckTagCount (parentCode, tagCode, tagCount, 1); 1504 1505 dng_urational et = stream.TagValue_urational (tagType); 1506 1507 SetExposureTime (et.As_real64 (), true); 1508 1509 #if qDNGValidate 1510 1511 if (gVerbose) 1512 { 1513 1514 printf ("ExposureTime: "); 1515 1516 DumpExposureTime (et.As_real64 ()); 1517 1518 printf ("\n"); 1519 1520 } 1521 1522 if (et.As_real64 () <= 0.0) 1523 { 1524 1525 ReportWarning ("The ExposureTime is <= 0"); 1526 1527 } 1528 1529 #endif 1530 1531 break; 1532 1533 } 1534 1535 case tcFNumber: 1536 { 1537 1538 CheckTagType (parentCode, tagCode, tagType, ttRational); 1539 1540 CheckTagCount (parentCode, tagCode, tagCount, 1); 1541 1542 dng_urational fs = stream.TagValue_urational (tagType); 1543 1544 // Sometimes "unknown" is recorded as zero. 1545 1546 if (fs.As_real64 () <= 0.0) 1547 { 1548 fs.Clear (); 1549 } 1550 1551 #if qDNGValidate 1552 1553 if (gVerbose) 1554 { 1555 1556 printf ("FNumber: f/%0.2f\n", 1557 fs.As_real64 ()); 1558 1559 } 1560 1561 #endif 1562 1563 SetFNumber (fs.As_real64 ()); 1564 1565 break; 1566 1567 } 1568 1569 case tcExposureProgram: 1570 { 1571 1572 CheckTagType (parentCode, tagCode, tagType, ttShort); 1573 1574 CheckTagCount (parentCode, tagCode, tagCount, 1); 1575 1576 fExposureProgram = stream.TagValue_uint32 (tagType); 1577 1578 #if qDNGValidate 1579 1580 if (gVerbose) 1581 { 1582 1583 printf ("ExposureProgram: %s\n", 1584 LookupExposureProgram (fExposureProgram)); 1585 1586 } 1587 1588 #endif 1589 1590 break; 1591 1592 } 1593 1594 case tcISOSpeedRatings: 1595 { 1596 1597 CheckTagType (parentCode, tagCode, tagType, ttShort); 1598 1599 CheckTagCount (parentCode, tagCode, tagCount, 1, 3); 1600 1601 for (uint32 j = 0; j < tagCount && j < 3; j++) 1602 { 1603 1604 fISOSpeedRatings [j] = stream.TagValue_uint32 (tagType); 1605 1606 } 1607 1608 #if qDNGValidate 1609 1610 if (gVerbose) 1611 { 1612 1613 printf ("ISOSpeedRatings:"); 1614 1615 for (uint32 j = 0; j < tagCount && j < 3; j++) 1616 { 1617 1618 printf (" %u", (unsigned) fISOSpeedRatings [j]); 1619 1620 } 1621 1622 printf ("\n"); 1623 1624 } 1625 1626 #endif 1627 1628 break; 1629 1630 } 1631 1632 case tcSensitivityType: 1633 { 1634 1635 CheckTagType (parentCode, tagCode, tagType, ttShort); 1636 1637 CheckTagCount (parentCode, tagCode, tagCount, 1); 1638 1639 fSensitivityType = (uint32) stream.Get_uint16 (); 1640 1641 #if qDNGValidate 1642 1643 if (gVerbose) 1644 { 1645 1646 printf ("SensitivityType: %s\n", 1647 LookupSensitivityType (fSensitivityType)); 1648 1649 } 1650 1651 #endif 1652 1653 break; 1654 1655 } 1656 1657 case tcStandardOutputSensitivity: 1658 { 1659 1660 CheckTagType (parentCode, tagCode, tagType, ttLong); 1661 1662 CheckTagCount (parentCode, tagCode, tagCount, 1); 1663 1664 fStandardOutputSensitivity = stream.TagValue_uint32 (tagType); 1665 1666 #if qDNGValidate 1667 1668 if (gVerbose) 1669 { 1670 1671 printf ("StandardOutputSensitivity: %u\n", 1672 (unsigned) fStandardOutputSensitivity); 1673 1674 } 1675 1676 #endif 1677 1678 break; 1679 1680 } 1681 1682 case tcRecommendedExposureIndex: 1683 { 1684 1685 CheckTagType (parentCode, tagCode, tagType, ttLong); 1686 1687 CheckTagCount (parentCode, tagCode, tagCount, 1); 1688 1689 fRecommendedExposureIndex = stream.TagValue_uint32 (tagType); 1690 1691 #if qDNGValidate 1692 1693 if (gVerbose) 1694 { 1695 1696 printf ("RecommendedExposureIndex: %u\n", 1697 (unsigned) fRecommendedExposureIndex); 1698 1699 } 1700 1701 #endif 1702 1703 break; 1704 1705 } 1706 1707 case tcISOSpeed: 1708 { 1709 1710 CheckTagType (parentCode, tagCode, tagType, ttLong); 1711 1712 CheckTagCount (parentCode, tagCode, tagCount, 1); 1713 1714 fISOSpeed = stream.TagValue_uint32 (tagType); 1715 1716 #if qDNGValidate 1717 1718 if (gVerbose) 1719 { 1720 1721 printf ("ISOSpeed: %u\n", 1722 (unsigned) fISOSpeed); 1723 1724 } 1725 1726 #endif 1727 1728 break; 1729 1730 } 1731 1732 case tcISOSpeedLatitudeyyy: 1733 { 1734 1735 CheckTagType (parentCode, tagCode, tagType, ttLong); 1736 1737 CheckTagCount (parentCode, tagCode, tagCount, 1); 1738 1739 fISOSpeedLatitudeyyy = stream.TagValue_uint32 (tagType); 1740 1741 #if qDNGValidate 1742 1743 if (gVerbose) 1744 { 1745 1746 printf ("ISOSpeedLatitudeyyy: %u\n", 1747 (unsigned) fISOSpeedLatitudeyyy); 1748 1749 } 1750 1751 #endif 1752 1753 break; 1754 1755 } 1756 1757 case tcISOSpeedLatitudezzz: 1758 { 1759 1760 CheckTagType (parentCode, tagCode, tagType, ttLong); 1761 1762 CheckTagCount (parentCode, tagCode, tagCount, 1); 1763 1764 fISOSpeedLatitudezzz = stream.TagValue_uint32 (tagType); 1765 1766 #if qDNGValidate 1767 1768 if (gVerbose) 1769 { 1770 1771 printf ("ISOSpeedLatitudezzz: %u\n", 1772 (unsigned) fISOSpeedLatitudezzz); 1773 1774 } 1775 1776 #endif 1777 1778 break; 1779 1780 } 1781 1782 case tcTimeZoneOffset: 1783 { 1784 1785 CheckTagType (parentCode, tagCode, tagType, ttSShort); 1786 1787 CheckTagCount (parentCode, tagCode, tagCount, 1, 2); 1788 1789 dng_time_zone zoneOriginal; 1790 1791 zoneOriginal.SetOffsetHours (stream.TagValue_int32 (tagType)); 1792 1793 fDateTimeOriginal.SetZone (zoneOriginal); 1794 1795 #if 0 // MWG: Not filling in time zones unless we are sure. 1796 1797 // Note that there is no "TimeZoneOffsetDigitized" field, so 1798 // we assume the same tone zone as the original. 1799 1800 fDateTimeDigitized.SetZone (zoneOriginal); 1801 1802 #endif 1803 1804 dng_time_zone zoneCurrent; 1805 1806 if (tagCount >= 2) 1807 { 1808 1809 zoneCurrent.SetOffsetHours (stream.TagValue_int32 (tagType)); 1810 1811 fDateTime.SetZone (zoneCurrent); 1812 1813 } 1814 1815 #if qDNGValidate 1816 1817 if (gVerbose) 1818 { 1819 1820 printf ("TimeZoneOffset: DateTimeOriginal = %d", 1821 (int) zoneOriginal.ExactHourOffset ()); 1822 1823 if (tagCount >= 2) 1824 { 1825 1826 printf (", DateTime = %d", 1827 (int) zoneCurrent.ExactHourOffset ()); 1828 1829 } 1830 1831 printf ("\n"); 1832 1833 } 1834 1835 #endif 1836 1837 break; 1838 1839 } 1840 1841 case tcSelfTimerMode: 1842 { 1843 1844 CheckTagType (parentCode, tagCode, tagType, ttShort); 1845 1846 CheckTagCount (parentCode, tagCode, tagCount, 1); 1847 1848 fSelfTimerMode = stream.TagValue_uint32 (tagType); 1849 1850 #if qDNGValidate 1851 1852 if (gVerbose) 1853 { 1854 1855 printf ("SelfTimerMode: "); 1856 1857 if (fSelfTimerMode) 1858 { 1859 1860 printf ("%u sec", (unsigned) fSelfTimerMode); 1861 1862 } 1863 1864 else 1865 { 1866 1867 printf ("Off"); 1868 1869 } 1870 1871 printf ("\n"); 1872 1873 } 1874 1875 #endif 1876 1877 break; 1878 1879 } 1880 1881 case tcExifVersion: 1882 { 1883 1884 CheckTagType (parentCode, tagCode, tagType, ttUndefined); 1885 1886 CheckTagCount (parentCode, tagCode, tagCount, 4); 1887 1888 uint32 b0 = stream.Get_uint8 (); 1889 uint32 b1 = stream.Get_uint8 (); 1890 uint32 b2 = stream.Get_uint8 (); 1891 uint32 b3 = stream.Get_uint8 (); 1892 1893 fExifVersion = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; 1894 1895 #if qDNGValidate 1896 1897 if (gVerbose) 1898 { 1899 1900 real64 x = (b0 - '0') * 10.00 + 1901 (b1 - '0') * 1.00 + 1902 (b2 - '0') * 0.10 + 1903 (b3 - '0') * 0.01; 1904 1905 printf ("ExifVersion: %0.2f\n", x); 1906 1907 } 1908 1909 #endif 1910 1911 break; 1912 1913 } 1914 1915 case tcDateTimeOriginal: 1916 { 1917 1918 uint64 tagPosition = stream.PositionInOriginalFile (); 1919 1920 dng_date_time dt; 1921 1922 if (!ParseDateTimeTag (stream, 1923 parentCode, 1924 tagCode, 1925 tagType, 1926 tagCount, 1927 dt)) 1928 { 1929 return false; 1930 } 1931 1932 fDateTimeOriginal.SetDateTime (dt); 1933 1934 fDateTimeOriginalStorageInfo = dng_date_time_storage_info (tagPosition, 1935 dng_date_time_format_exif); 1936 1937 #if qDNGValidate 1938 1939 if (gVerbose) 1940 { 1941 1942 printf ("DateTimeOriginal: "); 1943 1944 DumpDateTime (fDateTimeOriginal.DateTime ()); 1945 1946 printf ("\n"); 1947 1948 } 1949 1950 #endif 1951 1952 break; 1953 1954 } 1955 1956 case tcDateTimeDigitized: 1957 { 1958 1959 uint64 tagPosition = stream.PositionInOriginalFile (); 1960 1961 dng_date_time dt; 1962 1963 if (!ParseDateTimeTag (stream, 1964 parentCode, 1965 tagCode, 1966 tagType, 1967 tagCount, 1968 dt)) 1969 { 1970 return false; 1971 } 1972 1973 fDateTimeDigitized.SetDateTime (dt); 1974 1975 fDateTimeDigitizedStorageInfo = dng_date_time_storage_info (tagPosition, 1976 dng_date_time_format_exif); 1977 1978 #if qDNGValidate 1979 1980 if (gVerbose) 1981 { 1982 1983 printf ("DateTimeDigitized: "); 1984 1985 DumpDateTime (fDateTimeDigitized.DateTime ()); 1986 1987 printf ("\n"); 1988 1989 } 1990 1991 #endif 1992 1993 break; 1994 1995 } 1996 1997 case tcOffsetTime: 1998 { 1999 2000 CheckTagType (parentCode, tagCode, tagType, ttAscii); 2001 2002 dng_string offsetTime; 2003 2004 ParseStringTag (stream, 2005 parentCode, 2006 tagCode, 2007 tagCount, 2008 offsetTime); 2009 2010 fDateTime.SetOffsetTime (offsetTime); 2011 2012 // The offset time tags were added to EXIF spec 2.3.1. 2013 // We need EXIF spec version to figure out legacy fake time 2014 // zones in XMP, so force a correct exif spec version if 2015 // these EXIF tags are used. 2016 2017 if (!AtLeastVersion0231 ()) 2018 { 2019 SetVersion0231 (); 2020 } 2021 2022 #if qDNGValidate 2023 2024 if (gVerbose) 2025 { 2026 2027 printf ("OffsetTime: "); 2028 2029 DumpString (offsetTime); 2030 2031 printf ("\n"); 2032 2033 } 2034 2035 #endif 2036 2037 break; 2038 2039 } 2040 2041 case tcOffsetTimeOriginal: 2042 { 2043 2044 CheckTagType (parentCode, tagCode, tagType, ttAscii); 2045 2046 dng_string offsetTime; 2047 2048 ParseStringTag (stream, 2049 parentCode, 2050 tagCode, 2051 tagCount, 2052 offsetTime); 2053 2054 fDateTimeOriginal.SetOffsetTime (offsetTime); 2055 2056 // The offset time tags were added to EXIF spec 2.3.1. 2057 // We need EXIF spec version to figure out legacy fake time 2058 // zones in XMP, so force a correct exif spec version if 2059 // these EXIF tags are used. 2060 2061 if (!AtLeastVersion0231 ()) 2062 { 2063 SetVersion0231 (); 2064 } 2065 2066 #if qDNGValidate 2067 2068 if (gVerbose) 2069 { 2070 2071 printf ("OffsetTimeOriginal: "); 2072 2073 DumpString (offsetTime); 2074 2075 printf ("\n"); 2076 2077 } 2078 2079 #endif 2080 2081 break; 2082 2083 } 2084 2085 case tcOffsetTimeDigitized: 2086 { 2087 2088 CheckTagType (parentCode, tagCode, tagType, ttAscii); 2089 2090 dng_string offsetTime; 2091 2092 ParseStringTag (stream, 2093 parentCode, 2094 tagCode, 2095 tagCount, 2096 offsetTime); 2097 2098 fDateTimeDigitized.SetOffsetTime (offsetTime); 2099 2100 // The offset time tags were added to EXIF spec 2.3.1. 2101 // We need EXIF spec version to figure out legacy fake time 2102 // zones in XMP, so force a correct exif spec version if 2103 // these EXIF tags are used. 2104 2105 if (!AtLeastVersion0231 ()) 2106 { 2107 SetVersion0231 (); 2108 } 2109 2110 #if qDNGValidate 2111 2112 if (gVerbose) 2113 { 2114 2115 printf ("OffsetTimeDigitized: "); 2116 2117 DumpString (offsetTime); 2118 2119 printf ("\n"); 2120 2121 } 2122 2123 #endif 2124 2125 break; 2126 2127 } 2128 2129 case tcComponentsConfiguration: 2130 { 2131 2132 CheckTagType (parentCode, tagCode, tagType, ttUndefined); 2133 2134 CheckTagCount (parentCode, tagCode, tagCount, 4); 2135 2136 uint32 b0 = stream.Get_uint8 (); 2137 uint32 b1 = stream.Get_uint8 (); 2138 uint32 b2 = stream.Get_uint8 (); 2139 uint32 b3 = stream.Get_uint8 (); 2140 2141 fComponentsConfiguration = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; 2142 2143 #if qDNGValidate 2144 2145 if (gVerbose) 2146 { 2147 2148 printf ("ComponentsConfiguration: %s %s %s %s\n", 2149 LookupComponent (b0), 2150 LookupComponent (b1), 2151 LookupComponent (b2), 2152 LookupComponent (b3)); 2153 2154 } 2155 2156 #endif 2157 2158 break; 2159 2160 } 2161 2162 case tcCompressedBitsPerPixel: 2163 { 2164 2165 CheckTagType (parentCode, tagCode, tagType, ttRational); 2166 2167 CheckTagCount (parentCode, tagCode, tagCount, 1); 2168 2169 fCompresssedBitsPerPixel = stream.TagValue_urational (tagType); 2170 2171 #if qDNGValidate 2172 2173 if (gVerbose) 2174 { 2175 2176 printf ("CompressedBitsPerPixel: %0.2f\n", 2177 fCompresssedBitsPerPixel.As_real64 ()); 2178 2179 } 2180 2181 #endif 2182 2183 break; 2184 2185 } 2186 2187 case tcShutterSpeedValue: 2188 { 2189 2190 CheckTagType (parentCode, tagCode, tagType, ttSRational); 2191 2192 CheckTagCount (parentCode, tagCode, tagCount, 1); 2193 2194 dng_srational ss = stream.TagValue_srational (tagType); 2195 2196 #if qDNGValidate 2197 2198 if (gVerbose) 2199 { 2200 2201 printf ("ShutterSpeedValue: "); 2202 2203 real64 x = pow (2.0, -ss.As_real64 ()); 2204 2205 DumpExposureTime (x); 2206 2207 printf ("\n"); 2208 2209 } 2210 2211 // The ExposureTime and ShutterSpeedValue tags should be consistent. 2212 2213 if (fExposureTime.IsValid ()) 2214 { 2215 2216 real64 et = fExposureTime.As_real64 (); 2217 2218 real64 tv1 = -1.0 * log (et) / log (2.0); 2219 2220 real64 tv2 = ss.As_real64 (); 2221 2222 // Make sure they are within 0.25 APEX values. 2223 2224 if (Abs_real64 (tv1 - tv2) > 0.25) 2225 { 2226 2227 ReportWarning ("The ExposureTime and ShutterSpeedValue tags have conflicting values"); 2228 2229 } 2230 2231 } 2232 2233 #endif 2234 2235 SetShutterSpeedValue (ss.As_real64 ()); 2236 2237 break; 2238 2239 } 2240 2241 case tcApertureValue: 2242 { 2243 2244 CheckTagType (parentCode, tagCode, tagType, ttRational); 2245 2246 CheckTagCount (parentCode, tagCode, tagCount, 1); 2247 2248 dng_urational av = stream.TagValue_urational (tagType); 2249 2250 #if qDNGValidate 2251 2252 if (gVerbose) 2253 { 2254 2255 real64 x = pow (2.0, 0.5 * av.As_real64 ()); 2256 2257 printf ("ApertureValue: f/%0.2f\n", x); 2258 2259 } 2260 2261 // The FNumber and ApertureValue tags should be consistent. 2262 2263 if (fFNumber.IsValid () && av.IsValid ()) 2264 { 2265 2266 real64 fs = fFNumber.As_real64 (); 2267 2268 real64 av1 = FNumberToApertureValue (fs); 2269 2270 real64 av2 = av.As_real64 (); 2271 2272 if (Abs_real64 (av1 - av2) > 0.25) 2273 { 2274 2275 ReportWarning ("The FNumber and ApertureValue tags have conflicting values"); 2276 2277 } 2278 2279 } 2280 2281 #endif 2282 2283 SetApertureValue (av.As_real64 ()); 2284 2285 break; 2286 2287 } 2288 2289 case tcBrightnessValue: 2290 { 2291 2292 CheckTagType (parentCode, tagCode, tagType, ttSRational); 2293 2294 CheckTagCount (parentCode, tagCode, tagCount, 1); 2295 2296 fBrightnessValue = stream.TagValue_srational (tagType); 2297 2298 #if qDNGValidate 2299 2300 if (gVerbose) 2301 { 2302 2303 printf ("BrightnessValue: %0.2f\n", 2304 fBrightnessValue.As_real64 ()); 2305 2306 } 2307 2308 #endif 2309 2310 break; 2311 2312 } 2313 2314 case tcExposureBiasValue: 2315 { 2316 2317 CheckTagType (parentCode, tagCode, tagType, ttSRational); 2318 2319 CheckTagCount (parentCode, tagCode, tagCount, 1); 2320 2321 fExposureBiasValue = stream.TagValue_srational (tagType); 2322 2323 #if qDNGValidate 2324 2325 if (gVerbose) 2326 { 2327 2328 printf ("ExposureBiasValue: %0.2f\n", 2329 fExposureBiasValue.As_real64 ()); 2330 2331 } 2332 2333 #endif 2334 2335 break; 2336 2337 } 2338 2339 case tcMaxApertureValue: 2340 { 2341 2342 CheckTagType (parentCode, tagCode, tagType, ttRational); 2343 2344 CheckTagCount (parentCode, tagCode, tagCount, 1); 2345 2346 fMaxApertureValue = stream.TagValue_urational (tagType); 2347 2348 #if qDNGValidate 2349 2350 if (gVerbose) 2351 { 2352 2353 real64 x = pow (2.0, 0.5 * fMaxApertureValue.As_real64 ()); 2354 2355 printf ("MaxApertureValue: f/%0.1f\n", x); 2356 2357 } 2358 2359 #endif 2360 2361 break; 2362 2363 } 2364 2365 case tcSubjectDistance: 2366 { 2367 2368 CheckTagType (parentCode, tagCode, tagType, ttRational); 2369 2370 CheckTagCount (parentCode, tagCode, tagCount, 1); 2371 2372 fSubjectDistance = stream.TagValue_urational (tagType); 2373 2374 fApproxFocusDistance = fSubjectDistance; 2375 2376 #if qDNGValidate 2377 2378 if (gVerbose) 2379 { 2380 2381 printf ("SubjectDistance: %u/%u\n", 2382 (unsigned) fSubjectDistance.n, 2383 (unsigned) fSubjectDistance.d); 2384 2385 } 2386 2387 #endif 2388 2389 break; 2390 2391 } 2392 2393 case tcMeteringMode: 2394 { 2395 2396 CheckTagType (parentCode, tagCode, tagType, ttShort); 2397 2398 CheckTagCount (parentCode, tagCode, tagCount, 1); 2399 2400 fMeteringMode = stream.TagValue_uint32 (tagType); 2401 2402 #if qDNGValidate 2403 2404 if (gVerbose) 2405 { 2406 2407 printf ("MeteringMode: %s\n", 2408 LookupMeteringMode (fMeteringMode)); 2409 2410 } 2411 2412 #endif 2413 2414 break; 2415 2416 } 2417 2418 case tcLightSource: 2419 { 2420 2421 CheckTagType (parentCode, tagCode, tagType, ttShort); 2422 2423 CheckTagCount (parentCode, tagCode, tagCount, 1); 2424 2425 fLightSource = stream.TagValue_uint32 (tagType); 2426 2427 #if qDNGValidate 2428 2429 if (gVerbose) 2430 { 2431 2432 printf ("LightSource: %s\n", 2433 LookupLightSource (fLightSource)); 2434 2435 } 2436 2437 #endif 2438 2439 break; 2440 2441 } 2442 2443 case tcFlash: 2444 { 2445 2446 CheckTagType (parentCode, tagCode, tagType, ttShort); 2447 2448 CheckTagCount (parentCode, tagCode, tagCount, 1); 2449 2450 fFlash = stream.TagValue_uint32 (tagType); 2451 2452 #if qDNGValidate 2453 2454 if (gVerbose) 2455 { 2456 2457 printf ("Flash: %u\n", (unsigned) fFlash); 2458 2459 if ((fFlash >> 5) & 1) 2460 { 2461 printf (" No flash function\n"); 2462 } 2463 2464 else 2465 { 2466 2467 if (fFlash & 0x1) 2468 { 2469 2470 printf (" Flash fired\n"); 2471 2472 switch ((fFlash >> 1) & 0x3) 2473 { 2474 2475 case 2: 2476 printf (" Strobe return light not detected\n"); 2477 break; 2478 2479 case 3: 2480 printf (" Strobe return light detected\n"); 2481 break; 2482 2483 } 2484 2485 } 2486 2487 else 2488 { 2489 printf (" Flash did not fire\n"); 2490 } 2491 2492 switch ((fFlash >> 3) & 0x3) 2493 { 2494 2495 case 1: 2496 printf (" Compulsory flash firing\n"); 2497 break; 2498 2499 case 2: 2500 printf (" Compulsory flash suppression\n"); 2501 break; 2502 2503 case 3: 2504 printf (" Auto mode\n"); 2505 break; 2506 2507 } 2508 2509 if ((fFlash >> 6) & 1) 2510 { 2511 printf (" Red-eye reduction supported\n"); 2512 } 2513 2514 } 2515 2516 } 2517 2518 #endif 2519 2520 break; 2521 2522 } 2523 2524 case tcFocalLength: 2525 { 2526 2527 CheckTagType (parentCode, tagCode, tagType, ttRational); 2528 2529 CheckTagCount (parentCode, tagCode, tagCount, 1); 2530 2531 fFocalLength = stream.TagValue_urational (tagType); 2532 2533 // Sometimes "unknown" is recorded as zero. 2534 2535 if (fFocalLength.As_real64 () <= 0.0) 2536 { 2537 fFocalLength.Clear (); 2538 } 2539 2540 #if qDNGValidate 2541 2542 if (gVerbose) 2543 { 2544 2545 printf ("FocalLength: %0.1f mm\n", 2546 fFocalLength.As_real64 ()); 2547 2548 } 2549 2550 #endif 2551 2552 break; 2553 2554 } 2555 2556 case tcImageNumber: 2557 { 2558 2559 CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong); 2560 2561 CheckTagCount (parentCode, tagCode, tagCount, 1); 2562 2563 fImageNumber = stream.TagValue_uint32 (tagType); 2564 2565 #if qDNGValidate 2566 2567 if (gVerbose) 2568 { 2569 printf ("ImageNumber: %u\n", (unsigned) fImageNumber); 2570 } 2571 2572 #endif 2573 2574 break; 2575 2576 } 2577 2578 case tcExposureIndex: 2579 case tcExposureIndexExif: 2580 { 2581 2582 CheckTagType (parentCode, tagCode, tagType, ttRational); 2583 2584 CheckTagCount (parentCode, tagCode, tagCount, 1); 2585 2586 fExposureIndex = stream.TagValue_urational (tagType); 2587 2588 #if qDNGValidate 2589 2590 if (gVerbose) 2591 { 2592 2593 printf ("%s: ISO %0.1f\n", 2594 LookupTagCode (parentCode, tagCode), 2595 fExposureIndex.As_real64 ()); 2596 2597 } 2598 2599 #endif 2600 2601 break; 2602 2603 } 2604 2605 case tcUserComment: 2606 { 2607 2608 CheckTagType (parentCode, tagCode, tagType, ttUndefined); 2609 2610 ParseEncodedStringTag (stream, 2611 parentCode, 2612 tagCode, 2613 tagCount, 2614 fUserComment); 2615 2616 #if qDNGValidate 2617 2618 if (gVerbose) 2619 { 2620 2621 printf ("UserComment: "); 2622 2623 DumpString (fUserComment); 2624 2625 printf ("\n"); 2626 2627 } 2628 2629 #endif 2630 2631 break; 2632 2633 } 2634 2635 case tcSubsecTime: 2636 { 2637 2638 CheckTagType (parentCode, tagCode, tagType, ttAscii); 2639 2640 dng_string subsecs; 2641 2642 ParseStringTag (stream, 2643 parentCode, 2644 tagCode, 2645 tagCount, 2646 subsecs); 2647 2648 fDateTime.SetSubseconds (subsecs); 2649 2650 #if qDNGValidate 2651 2652 if (gVerbose) 2653 { 2654 2655 printf ("SubsecTime: "); 2656 2657 DumpString (subsecs); 2658 2659 printf ("\n"); 2660 2661 } 2662 2663 #endif 2664 2665 break; 2666 2667 } 2668 2669 case tcSubsecTimeOriginal: 2670 { 2671 2672 CheckTagType (parentCode, tagCode, tagType, ttAscii); 2673 2674 dng_string subsecs; 2675 2676 ParseStringTag (stream, 2677 parentCode, 2678 tagCode, 2679 tagCount, 2680 subsecs); 2681 2682 fDateTimeOriginal.SetSubseconds (subsecs); 2683 2684 #if qDNGValidate 2685 2686 if (gVerbose) 2687 { 2688 2689 printf ("SubsecTimeOriginal: "); 2690 2691 DumpString (subsecs); 2692 2693 printf ("\n"); 2694 2695 } 2696 2697 #endif 2698 2699 break; 2700 2701 } 2702 2703 case tcSubsecTimeDigitized: 2704 { 2705 2706 CheckTagType (parentCode, tagCode, tagType, ttAscii); 2707 2708 dng_string subsecs; 2709 2710 ParseStringTag (stream, 2711 parentCode, 2712 tagCode, 2713 tagCount, 2714 subsecs); 2715 2716 fDateTimeDigitized.SetSubseconds (subsecs); 2717 2718 #if qDNGValidate 2719 2720 if (gVerbose) 2721 { 2722 2723 printf ("SubsecTimeDigitized: "); 2724 2725 DumpString (subsecs); 2726 2727 printf ("\n"); 2728 2729 } 2730 2731 #endif 2732 2733 break; 2734 2735 } 2736 2737 case tcTemperature: 2738 { 2739 2740 CheckTagType (parentCode, tagCode, tagType, ttSRational); 2741 2742 CheckTagCount (parentCode, tagCode, tagCount, 1); 2743 2744 fTemperature = stream.TagValue_srational (tagType); 2745 2746 if (!AtLeastVersion0231 ()) 2747 { 2748 SetVersion0231 (); 2749 } 2750 2751 #if qDNGValidate 2752 2753 if (gVerbose) 2754 { 2755 2756 printf ("Temperature: %0.1f\n", 2757 fTemperature.As_real64 ()); 2758 2759 } 2760 2761 #endif 2762 2763 break; 2764 2765 } 2766 2767 case tcHumidity: 2768 { 2769 2770 CheckTagType (parentCode, tagCode, tagType, ttRational); 2771 2772 CheckTagCount (parentCode, tagCode, tagCount, 1); 2773 2774 fHumidity = stream.TagValue_urational (tagType); 2775 2776 if (!AtLeastVersion0231 ()) 2777 { 2778 SetVersion0231 (); 2779 } 2780 2781 #if qDNGValidate 2782 2783 if (gVerbose) 2784 { 2785 2786 printf ("Humidity: %0.1f\n", 2787 fHumidity.As_real64 ()); 2788 2789 } 2790 2791 #endif 2792 2793 break; 2794 2795 } 2796 2797 case tcPressure: 2798 { 2799 2800 CheckTagType (parentCode, tagCode, tagType, ttRational); 2801 2802 CheckTagCount (parentCode, tagCode, tagCount, 1); 2803 2804 fPressure = stream.TagValue_urational (tagType); 2805 2806 if (!AtLeastVersion0231 ()) 2807 { 2808 SetVersion0231 (); 2809 } 2810 2811 #if qDNGValidate 2812 2813 if (gVerbose) 2814 { 2815 2816 printf ("Pressure: %0.1f\n", 2817 fPressure.As_real64 ()); 2818 2819 } 2820 2821 #endif 2822 2823 break; 2824 2825 } 2826 2827 case tcWaterDepth: 2828 { 2829 2830 CheckTagType (parentCode, tagCode, tagType, ttSRational); 2831 2832 CheckTagCount (parentCode, tagCode, tagCount, 1); 2833 2834 fWaterDepth = stream.TagValue_srational (tagType); 2835 2836 if (!AtLeastVersion0231 ()) 2837 { 2838 SetVersion0231 (); 2839 } 2840 2841 #if qDNGValidate 2842 2843 if (gVerbose) 2844 { 2845 2846 printf ("WaterDepth: %0.1f\n", 2847 fWaterDepth.As_real64 ()); 2848 2849 } 2850 2851 #endif 2852 2853 break; 2854 2855 } 2856 2857 case tcAcceleration: 2858 { 2859 2860 CheckTagType (parentCode, tagCode, tagType, ttRational); 2861 2862 CheckTagCount (parentCode, tagCode, tagCount, 1); 2863 2864 fAcceleration = stream.TagValue_urational (tagType); 2865 2866 if (!AtLeastVersion0231 ()) 2867 { 2868 SetVersion0231 (); 2869 } 2870 2871 #if qDNGValidate 2872 2873 if (gVerbose) 2874 { 2875 2876 printf ("Acceleration: %0.1f\n", 2877 fAcceleration.As_real64 ()); 2878 2879 } 2880 2881 #endif 2882 2883 break; 2884 2885 } 2886 2887 case tcCameraElevationAngle: 2888 { 2889 2890 CheckTagType (parentCode, tagCode, tagType, ttSRational); 2891 2892 CheckTagCount (parentCode, tagCode, tagCount, 1); 2893 2894 fCameraElevationAngle = stream.TagValue_srational (tagType); 2895 2896 if (!AtLeastVersion0231 ()) 2897 { 2898 SetVersion0231 (); 2899 } 2900 2901 #if qDNGValidate 2902 2903 if (gVerbose) 2904 { 2905 2906 printf ("CameraElevationAngle: %0.1f\n", 2907 fCameraElevationAngle.As_real64 ()); 2908 2909 } 2910 2911 #endif 2912 2913 break; 2914 2915 } 2916 2917 case tcFlashPixVersion: 2918 { 2919 2920 CheckTagType (parentCode, tagCode, tagType, ttUndefined); 2921 2922 CheckTagCount (parentCode, tagCode, tagCount, 4); 2923 2924 uint32 b0 = stream.Get_uint8 (); 2925 uint32 b1 = stream.Get_uint8 (); 2926 uint32 b2 = stream.Get_uint8 (); 2927 uint32 b3 = stream.Get_uint8 (); 2928 2929 fFlashPixVersion = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; 2930 2931 #if qDNGValidate 2932 2933 if (gVerbose) 2934 { 2935 2936 real64 x = (b0 - '0') * 10.00 + 2937 (b1 - '0') * 1.00 + 2938 (b2 - '0') * 0.10 + 2939 (b3 - '0') * 0.01; 2940 2941 printf ("FlashPixVersion: %0.2f\n", x); 2942 2943 } 2944 2945 #endif 2946 2947 break; 2948 2949 } 2950 2951 case tcColorSpace: 2952 { 2953 2954 CheckTagType (parentCode, tagCode, tagType, ttShort); 2955 2956 CheckTagCount (parentCode, tagCode, tagCount, 1); 2957 2958 fColorSpace = stream.TagValue_uint32 (tagType); 2959 2960 #if qDNGValidate 2961 2962 if (gVerbose) 2963 { 2964 2965 printf ("ColorSpace: %s\n", 2966 LookupColorSpace (fColorSpace)); 2967 2968 } 2969 2970 #endif 2971 2972 break; 2973 2974 } 2975 2976 case tcPixelXDimension: 2977 { 2978 2979 CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong); 2980 2981 CheckTagCount (parentCode, tagCode, tagCount, 1); 2982 2983 fPixelXDimension = stream.TagValue_uint32 (tagType); 2984 2985 #if qDNGValidate 2986 2987 if (gVerbose) 2988 { 2989 printf ("PixelXDimension: %u\n", (unsigned) fPixelXDimension); 2990 } 2991 2992 #endif 2993 2994 break; 2995 2996 } 2997 2998 case tcPixelYDimension: 2999 { 3000 3001 CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong); 3002 3003 CheckTagCount (parentCode, tagCode, tagCount, 1); 3004 3005 fPixelYDimension = stream.TagValue_uint32 (tagType); 3006 3007 #if qDNGValidate 3008 3009 if (gVerbose) 3010 { 3011 printf ("PixelYDimension: %u\n", (unsigned) fPixelYDimension); 3012 } 3013 3014 #endif 3015 3016 break; 3017 3018 } 3019 3020 case tcFocalPlaneXResolutionExif: 3021 { 3022 3023 CheckTagType (parentCode, tagCode, tagType, ttRational); 3024 3025 CheckTagCount (parentCode, tagCode, tagCount, 1); 3026 3027 fFocalPlaneXResolution = stream.TagValue_urational (tagType); 3028 3029 #if qDNGValidate 3030 3031 if (gVerbose) 3032 { 3033 3034 printf ("FocalPlaneXResolutionExif: %0.4f\n", 3035 fFocalPlaneXResolution.As_real64 ()); 3036 3037 } 3038 3039 #endif 3040 3041 break; 3042 3043 } 3044 3045 case tcFocalPlaneYResolutionExif: 3046 { 3047 3048 CheckTagType (parentCode, tagCode, tagType, ttRational); 3049 3050 CheckTagCount (parentCode, tagCode, tagCount, 1); 3051 3052 fFocalPlaneYResolution = stream.TagValue_urational (tagType); 3053 3054 #if qDNGValidate 3055 3056 if (gVerbose) 3057 { 3058 3059 printf ("FocalPlaneYResolutionExif: %0.4f\n", 3060 fFocalPlaneYResolution.As_real64 ()); 3061 3062 } 3063 3064 #endif 3065 3066 break; 3067 3068 } 3069 3070 case tcFocalPlaneResolutionUnitExif: 3071 { 3072 3073 CheckTagType (parentCode, tagCode, tagType, ttShort); 3074 3075 CheckTagCount (parentCode, tagCode, tagCount, 1); 3076 3077 fFocalPlaneResolutionUnit = stream.TagValue_uint32 (tagType); 3078 3079 #if qDNGValidate 3080 3081 if (gVerbose) 3082 { 3083 3084 printf ("FocalPlaneResolutionUnitExif: %s\n", 3085 LookupResolutionUnit (fFocalPlaneResolutionUnit)); 3086 3087 } 3088 3089 #endif 3090 3091 break; 3092 3093 } 3094 3095 case tcSensingMethodExif: 3096 { 3097 3098 CheckTagType (parentCode, tagCode, tagType, ttShort); 3099 3100 CheckTagCount (parentCode, tagCode, tagCount, 1); 3101 3102 fSensingMethod = stream.TagValue_uint32 (tagType); 3103 3104 #if qDNGValidate 3105 3106 if (gVerbose) 3107 { 3108 3109 printf ("SensingMethodExif: %s\n", 3110 LookupSensingMethod (fSensingMethod)); 3111 3112 } 3113 3114 #endif 3115 3116 break; 3117 3118 } 3119 3120 case tcFileSource: 3121 { 3122 3123 CheckTagType (parentCode, tagCode, tagType, ttUndefined); 3124 3125 CheckTagCount (parentCode, tagCode, tagCount, 1); 3126 3127 fFileSource = stream.Get_uint8 (); 3128 3129 #if qDNGValidate 3130 3131 if (gVerbose) 3132 { 3133 3134 printf ("FileSource: %s\n", 3135 LookupFileSource (fFileSource)); 3136 3137 } 3138 3139 #endif 3140 3141 break; 3142 3143 } 3144 3145 case tcSceneType: 3146 { 3147 3148 CheckTagType (parentCode, tagCode, tagType, ttUndefined); 3149 3150 CheckTagCount (parentCode, tagCode, tagCount, 1); 3151 3152 fSceneType = stream.Get_uint8 (); 3153 3154 #if qDNGValidate 3155 3156 if (gVerbose) 3157 { 3158 3159 printf ("SceneType: %s\n", 3160 LookupSceneType (fSceneType)); 3161 3162 } 3163 3164 #endif 3165 3166 break; 3167 3168 } 3169 3170 case tcCFAPatternExif: 3171 { 3172 3173 CheckTagType (parentCode, tagCode, tagType, ttUndefined); 3174 3175 if (tagCount <= 4) 3176 { 3177 return false; 3178 } 3179 3180 uint32 cols = stream.Get_uint16 (); 3181 uint32 rows = stream.Get_uint16 (); 3182 3183 if (tagCount != 4 + cols * rows) 3184 { 3185 return false; 3186 } 3187 3188 if (cols < 1 || cols > kMaxCFAPattern || 3189 rows < 1 || rows > kMaxCFAPattern) 3190 { 3191 return false; 3192 } 3193 3194 fCFARepeatPatternCols = cols; 3195 fCFARepeatPatternRows = rows; 3196 3197 // Note that the Exif spec stores this array in a different 3198 // scan order than the TIFF-EP spec. 3199 3200 for (uint32 j = 0; j < fCFARepeatPatternCols; j++) 3201 for (uint32 k = 0; k < fCFARepeatPatternRows; k++) 3202 { 3203 3204 fCFAPattern [k] [j] = stream.Get_uint8 (); 3205 3206 } 3207 3208 #if qDNGValidate 3209 3210 if (gVerbose) 3211 { 3212 3213 printf ("CFAPatternExif:\n"); 3214 3215 for (uint32 j = 0; j < fCFARepeatPatternRows; j++) 3216 { 3217 3218 int32 spaces = 4; 3219 3220 for (uint32 k = 0; k < fCFARepeatPatternCols; k++) 3221 { 3222 3223 while (spaces-- > 0) 3224 { 3225 printf (" "); 3226 } 3227 3228 const char *name = LookupCFAColor (fCFAPattern [j] [k]); 3229 3230 spaces = 9 - (int32) strlen (name); 3231 3232 printf ("%s", name); 3233 3234 } 3235 3236 printf ("\n"); 3237 3238 } 3239 3240 } 3241 3242 #endif 3243 3244 break; 3245 3246 } 3247 3248 case tcCustomRendered: 3249 { 3250 3251 CheckTagType (parentCode, tagCode, tagType, ttShort); 3252 3253 CheckTagCount (parentCode, tagCode, tagCount, 1); 3254 3255 fCustomRendered = stream.TagValue_uint32 (tagType); 3256 3257 #if qDNGValidate 3258 3259 if (gVerbose) 3260 { 3261 3262 printf ("CustomRendered: %s\n", 3263 LookupCustomRendered (fCustomRendered)); 3264 3265 } 3266 3267 #endif 3268 3269 break; 3270 3271 } 3272 3273 case tcExposureMode: 3274 { 3275 3276 CheckTagType (parentCode, tagCode, tagType, ttShort); 3277 3278 CheckTagCount (parentCode, tagCode, tagCount, 1); 3279 3280 fExposureMode = stream.TagValue_uint32 (tagType); 3281 3282 #if qDNGValidate 3283 3284 if (gVerbose) 3285 { 3286 3287 printf ("ExposureMode: %s\n", 3288 LookupExposureMode (fExposureMode)); 3289 3290 } 3291 3292 #endif 3293 3294 break; 3295 3296 } 3297 3298 case tcWhiteBalance: 3299 { 3300 3301 CheckTagType (parentCode, tagCode, tagType, ttShort); 3302 3303 CheckTagCount (parentCode, tagCode, tagCount, 1); 3304 3305 fWhiteBalance = stream.TagValue_uint32 (tagType); 3306 3307 #if qDNGValidate 3308 3309 if (gVerbose) 3310 { 3311 3312 printf ("WhiteBalance: %s\n", 3313 LookupWhiteBalance (fWhiteBalance)); 3314 3315 } 3316 3317 #endif 3318 3319 break; 3320 3321 } 3322 3323 case tcDigitalZoomRatio: 3324 { 3325 3326 CheckTagType (parentCode, tagCode, tagType, ttRational); 3327 3328 CheckTagCount (parentCode, tagCode, tagCount, 1); 3329 3330 fDigitalZoomRatio = stream.TagValue_urational (tagType); 3331 3332 #if qDNGValidate 3333 3334 if (gVerbose) 3335 { 3336 3337 printf ("DigitalZoomRatio: "); 3338 3339 if (fDigitalZoomRatio.n == 0 || 3340 fDigitalZoomRatio.d == 0) 3341 { 3342 3343 printf ("Not used\n"); 3344 3345 } 3346 3347 else 3348 { 3349 3350 printf ("%0.2f\n", fDigitalZoomRatio.As_real64 ()); 3351 3352 } 3353 3354 } 3355 3356 #endif 3357 3358 break; 3359 3360 } 3361 3362 case tcFocalLengthIn35mmFilm: 3363 { 3364 3365 CheckTagType (parentCode, tagCode, tagType, ttShort); 3366 3367 CheckTagCount (parentCode, tagCode, tagCount, 1); 3368 3369 fFocalLengthIn35mmFilm = stream.TagValue_uint32 (tagType); 3370 3371 #if qDNGValidate 3372 3373 if (gVerbose) 3374 { 3375 3376 printf ("FocalLengthIn35mmFilm: %u mm\n", 3377 (unsigned) fFocalLengthIn35mmFilm); 3378 3379 } 3380 3381 #endif 3382 3383 break; 3384 3385 } 3386 3387 case tcSceneCaptureType: 3388 { 3389 3390 CheckTagType (parentCode, tagCode, tagType, ttShort); 3391 3392 CheckTagCount (parentCode, tagCode, tagCount, 1); 3393 3394 fSceneCaptureType = stream.TagValue_uint32 (tagType); 3395 3396 #if qDNGValidate 3397 3398 if (gVerbose) 3399 { 3400 3401 printf ("SceneCaptureType: %s\n", 3402 LookupSceneCaptureType (fSceneCaptureType)); 3403 3404 } 3405 3406 #endif 3407 3408 break; 3409 3410 } 3411 3412 case tcGainControl: 3413 { 3414 3415 CheckTagType (parentCode, tagCode, tagType, ttShort); 3416 3417 CheckTagCount (parentCode, tagCode, tagCount, 1); 3418 3419 fGainControl = stream.TagValue_uint32 (tagType); 3420 3421 #if qDNGValidate 3422 3423 if (gVerbose) 3424 { 3425 3426 printf ("GainControl: %s\n", 3427 LookupGainControl (fGainControl)); 3428 3429 } 3430 3431 #endif 3432 3433 break; 3434 3435 } 3436 3437 case tcContrast: 3438 { 3439 3440 CheckTagType (parentCode, tagCode, tagType, ttShort); 3441 3442 CheckTagCount (parentCode, tagCode, tagCount, 1); 3443 3444 fContrast = stream.TagValue_uint32 (tagType); 3445 3446 #if qDNGValidate 3447 3448 if (gVerbose) 3449 { 3450 3451 printf ("Contrast: %s\n", 3452 LookupContrast (fContrast)); 3453 3454 } 3455 3456 #endif 3457 3458 break; 3459 3460 } 3461 3462 case tcSaturation: 3463 { 3464 3465 CheckTagType (parentCode, tagCode, tagType, ttShort); 3466 3467 CheckTagCount (parentCode, tagCode, tagCount, 1); 3468 3469 fSaturation = stream.TagValue_uint32 (tagType); 3470 3471 #if qDNGValidate 3472 3473 if (gVerbose) 3474 { 3475 3476 printf ("Saturation: %s\n", 3477 LookupSaturation (fSaturation)); 3478 3479 } 3480 3481 #endif 3482 3483 break; 3484 3485 } 3486 3487 case tcSharpness: 3488 { 3489 3490 CheckTagType (parentCode, tagCode, tagType, ttShort); 3491 3492 CheckTagCount (parentCode, tagCode, tagCount, 1); 3493 3494 fSharpness = stream.TagValue_uint32 (tagType); 3495 3496 #if qDNGValidate 3497 3498 if (gVerbose) 3499 { 3500 3501 printf ("Sharpness: %s\n", 3502 LookupSharpness (fSharpness)); 3503 3504 } 3505 3506 #endif 3507 3508 break; 3509 3510 } 3511 3512 case tcSubjectDistanceRange: 3513 { 3514 3515 CheckTagType (parentCode, tagCode, tagType, ttShort); 3516 3517 CheckTagCount (parentCode, tagCode, tagCount, 1); 3518 3519 fSubjectDistanceRange = stream.TagValue_uint32 (tagType); 3520 3521 #if qDNGValidate 3522 3523 if (gVerbose) 3524 { 3525 3526 printf ("SubjectDistanceRange: %s\n", 3527 LookupSubjectDistanceRange (fSubjectDistanceRange)); 3528 3529 } 3530 3531 #endif 3532 3533 break; 3534 3535 } 3536 3537 case tcSubjectArea: 3538 case tcSubjectLocation: 3539 { 3540 3541 CheckTagType (parentCode, tagCode, tagType, ttShort); 3542 3543 if (!CheckTagCount (parentCode, tagCode, tagCount, 2, 4)) 3544 { 3545 return false; 3546 } 3547 3548 if (tagCode == tcSubjectLocation) 3549 { 3550 CheckTagCount (parentCode, tagCode, tagCount, 2); 3551 } 3552 3553 fSubjectAreaCount = tagCount; 3554 3555 for (uint32 j = 0; j < tagCount; j++) 3556 { 3557 3558 fSubjectArea [j] = stream.TagValue_uint32 (tagType); 3559 3560 } 3561 3562 #if qDNGValidate 3563 3564 if (gVerbose) 3565 { 3566 3567 printf ("%s:", LookupTagCode (parentCode, tagCode)); 3568 3569 for (uint32 j = 0; j < fSubjectAreaCount; j++) 3570 { 3571 3572 printf (" %u", (unsigned) fSubjectArea [j]); 3573 3574 } 3575 3576 printf ("\n"); 3577 3578 } 3579 3580 #endif 3581 3582 break; 3583 3584 } 3585 3586 case tcGamma: 3587 { 3588 3589 CheckTagType (parentCode, tagCode, tagType, ttRational); 3590 3591 CheckTagCount (parentCode, tagCode, tagCount, 1); 3592 3593 fGamma = stream.TagValue_urational (tagType); 3594 3595 #if qDNGValidate 3596 3597 if (gVerbose) 3598 { 3599 3600 printf ("Gamma: %0.2f\n", 3601 fGamma.As_real64 ()); 3602 3603 } 3604 3605 #endif 3606 3607 break; 3608 3609 } 3610 3611 case tcImageUniqueID: 3612 { 3613 3614 if (!CheckTagType (parentCode, tagCode, tagType, ttAscii)) 3615 return false; 3616 3617 if (!CheckTagCount (parentCode, tagCode, tagCount, 33)) 3618 return false; 3619 3620 dng_string s; 3621 3622 ParseStringTag (stream, 3623 parentCode, 3624 tagCode, 3625 tagCount, 3626 s); 3627 3628 if (s.Length () != 32) 3629 return false; 3630 3631 dng_fingerprint f; 3632 3633 for (uint32 j = 0; j < 32; j++) 3634 { 3635 3636 char c = ForceUppercase (s.Get () [j]); 3637 3638 uint32 digit; 3639 3640 if (c >= '0' && c <= '9') 3641 { 3642 digit = c - '0'; 3643 } 3644 3645 else if (c >= 'A' && c <= 'F') 3646 { 3647 digit = c - 'A' + 10; 3648 } 3649 3650 else 3651 return false; 3652 3653 f.data [j >> 1] *= 16; 3654 f.data [j >> 1] += (uint8) digit; 3655 3656 } 3657 3658 fImageUniqueID = f; 3659 3660 #if qDNGValidate 3661 3662 if (gVerbose) 3663 { 3664 3665 printf ("ImageUniqueID: "); 3666 3667 DumpFingerprint (fImageUniqueID); 3668 3669 printf ("\n"); 3670 3671 } 3672 3673 #endif 3674 3675 break; 3676 3677 } 3678 3679 case tcCameraOwnerNameExif: 3680 { 3681 3682 CheckTagType (parentCode, tagCode, tagType, ttAscii); 3683 3684 ParseStringTag (stream, 3685 parentCode, 3686 tagCode, 3687 tagCount, 3688 fOwnerName); 3689 3690 #if qDNGValidate 3691 3692 if (gVerbose) 3693 { 3694 3695 printf ("CameraOwnerName: "); 3696 3697 DumpString (fOwnerName); 3698 3699 printf ("\n"); 3700 3701 } 3702 3703 #endif 3704 3705 break; 3706 3707 } 3708 3709 case tcCameraSerialNumberExif: 3710 { 3711 3712 CheckTagType (parentCode, tagCode, tagType, ttAscii); 3713 3714 ParseStringTag (stream, 3715 parentCode, 3716 tagCode, 3717 tagCount, 3718 fCameraSerialNumber); 3719 3720 #if qDNGValidate 3721 3722 if (gVerbose) 3723 { 3724 3725 printf ("%s: ", LookupTagCode (parentCode, tagCode)); 3726 3727 DumpString (fCameraSerialNumber); 3728 3729 printf ("\n"); 3730 3731 } 3732 3733 #endif 3734 3735 break; 3736 3737 } 3738 3739 case tcLensSpecificationExif: 3740 { 3741 3742 CheckTagType (parentCode, tagCode, tagType, ttRational); 3743 3744 if (!CheckTagCount (parentCode, tagCode, tagCount, 4)) 3745 return false; 3746 3747 fLensInfo [0] = stream.TagValue_urational (tagType); 3748 fLensInfo [1] = stream.TagValue_urational (tagType); 3749 fLensInfo [2] = stream.TagValue_urational (tagType); 3750 fLensInfo [3] = stream.TagValue_urational (tagType); 3751 3752 // Some third party software wrote zero rather than undefined values for 3753 // unknown entries. Work around this bug. 3754 3755 for (uint32 j = 0; j < 4; j++) 3756 { 3757 3758 if (fLensInfo [j].IsValid () && fLensInfo [j].As_real64 () <= 0.0) 3759 { 3760 3761 fLensInfo [j] = dng_urational (0, 0); 3762 3763 #if qDNGValidate 3764 3765 ReportWarning ("Zero entry in LensSpecification tag--should be undefined"); 3766 3767 #endif 3768 3769 } 3770 3771 } 3772 3773 #if qDNGValidate 3774 3775 if (gVerbose) 3776 { 3777 3778 printf ("LensSpecificationExif: "); 3779 3780 real64 minFL = fLensInfo [0].As_real64 (); 3781 real64 maxFL = fLensInfo [1].As_real64 (); 3782 3783 if (minFL == maxFL) 3784 printf ("%0.1f mm", minFL); 3785 else 3786 printf ("%0.1f-%0.1f mm", minFL, maxFL); 3787 3788 if (fLensInfo [2].d) 3789 { 3790 3791 real64 minFS = fLensInfo [2].As_real64 (); 3792 real64 maxFS = fLensInfo [3].As_real64 (); 3793 3794 if (minFS == maxFS) 3795 printf (" f/%0.1f", minFS); 3796 else 3797 printf (" f/%0.1f-%0.1f", minFS, maxFS); 3798 3799 } 3800 3801 printf ("\n"); 3802 3803 } 3804 3805 #endif 3806 3807 break; 3808 3809 } 3810 3811 case tcLensMakeExif: 3812 { 3813 3814 CheckTagType (parentCode, tagCode, tagType, ttAscii); 3815 3816 ParseStringTag (stream, 3817 parentCode, 3818 tagCode, 3819 tagCount, 3820 fLensMake); 3821 3822 #if qDNGValidate 3823 3824 if (gVerbose) 3825 { 3826 3827 printf ("%s: ", LookupTagCode (parentCode, tagCode)); 3828 3829 DumpString (fLensMake); 3830 3831 printf ("\n"); 3832 3833 } 3834 3835 #endif 3836 3837 break; 3838 3839 } 3840 3841 case tcLensModelExif: 3842 { 3843 3844 CheckTagType (parentCode, tagCode, tagType, ttAscii); 3845 3846 ParseStringTag (stream, 3847 parentCode, 3848 tagCode, 3849 tagCount, 3850 fLensName); 3851 3852 fLensNameWasReadFromExif = fLensName.NotEmpty (); 3853 3854 #if qDNGValidate 3855 3856 if (gVerbose) 3857 { 3858 3859 printf ("%s: ", LookupTagCode (parentCode, tagCode)); 3860 3861 DumpString (fLensName); 3862 3863 printf ("\n"); 3864 3865 } 3866 3867 #endif 3868 3869 break; 3870 3871 } 3872 3873 case tcLensSerialNumberExif: 3874 { 3875 3876 CheckTagType (parentCode, tagCode, tagType, ttAscii); 3877 3878 ParseStringTag (stream, 3879 parentCode, 3880 tagCode, 3881 tagCount, 3882 fLensSerialNumber); 3883 3884 #if qDNGValidate 3885 3886 if (gVerbose) 3887 { 3888 3889 printf ("%s: ", LookupTagCode (parentCode, tagCode)); 3890 3891 DumpString (fLensSerialNumber); 3892 3893 printf ("\n"); 3894 3895 } 3896 3897 #endif 3898 3899 break; 3900 3901 } 3902 3903 default: 3904 { 3905 3906 return false; 3907 3908 } 3909 3910 } 3911 3912 return true; 3913 3914 } 3915 3916 /*****************************************************************************/ 3917 3918 // Parses tags that should only appear in GPS IFD 3919 3920 bool dng_exif::Parse_gps (dng_stream &stream, 3921 dng_shared & /* shared */, 3922 uint32 parentCode, 3923 uint32 tagCode, 3924 uint32 tagType, 3925 uint32 tagCount, 3926 uint64 /* tagOffset */) 3927 { 3928 3929 switch (tagCode) 3930 { 3931 3932 case tcGPSVersionID: 3933 { 3934 3935 CheckTagType (parentCode, tagCode, tagType, ttByte); 3936 3937 CheckTagCount (parentCode, tagCode, tagCount, 4); 3938 3939 uint32 b0 = stream.Get_uint8 (); 3940 uint32 b1 = stream.Get_uint8 (); 3941 uint32 b2 = stream.Get_uint8 (); 3942 uint32 b3 = stream.Get_uint8 (); 3943 3944 fGPSVersionID = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; 3945 3946 #if qDNGValidate 3947 3948 if (gVerbose) 3949 { 3950 printf ("GPSVersionID: %u.%u.%u.%u\n", 3951 (unsigned) b0, 3952 (unsigned) b1, 3953 (unsigned) b2, 3954 (unsigned) b3); 3955 } 3956 3957 #endif 3958 3959 break; 3960 3961 } 3962 3963 case tcGPSLatitudeRef: 3964 case tcGPSLongitudeRef: 3965 case tcGPSSatellites: 3966 case tcGPSStatus: 3967 case tcGPSMeasureMode: 3968 case tcGPSSpeedRef: 3969 case tcGPSTrackRef: 3970 case tcGPSImgDirectionRef: 3971 case tcGPSMapDatum: 3972 case tcGPSDestLatitudeRef: 3973 case tcGPSDestLongitudeRef: 3974 case tcGPSDestBearingRef: 3975 case tcGPSDestDistanceRef: 3976 case tcGPSDateStamp: 3977 { 3978 3979 if (!CheckTagType (parentCode, tagCode, tagType, ttAscii)) 3980 return false; 3981 3982 dng_string *s; 3983 3984 switch (tagCode) 3985 { 3986 3987 case tcGPSLatitudeRef: 3988 s = &fGPSLatitudeRef; 3989 break; 3990 3991 case tcGPSLongitudeRef: 3992 s = &fGPSLongitudeRef; 3993 break; 3994 3995 case tcGPSSatellites: 3996 s = &fGPSSatellites; 3997 break; 3998 3999 case tcGPSStatus: 4000 s = &fGPSStatus; 4001 break; 4002 4003 case tcGPSMeasureMode: 4004 s = &fGPSMeasureMode; 4005 break; 4006 4007 case tcGPSSpeedRef: 4008 s = &fGPSSpeedRef; 4009 break; 4010 4011 case tcGPSTrackRef: 4012 s = &fGPSTrackRef; 4013 break; 4014 4015 case tcGPSImgDirectionRef: 4016 s = &fGPSImgDirectionRef; 4017 break; 4018 4019 case tcGPSMapDatum: 4020 s = &fGPSMapDatum; 4021 break; 4022 4023 case tcGPSDestLatitudeRef: 4024 s = &fGPSDestLatitudeRef; 4025 break; 4026 4027 case tcGPSDestLongitudeRef: 4028 s = &fGPSDestLongitudeRef; 4029 break; 4030 4031 case tcGPSDestBearingRef: 4032 s = &fGPSDestBearingRef; 4033 break; 4034 4035 case tcGPSDestDistanceRef: 4036 s = &fGPSDestDistanceRef; 4037 break; 4038 4039 case tcGPSDateStamp: 4040 s = &fGPSDateStamp; 4041 break; 4042 4043 default: 4044 return false; 4045 4046 } 4047 4048 ParseStringTag (stream, 4049 parentCode, 4050 tagCode, 4051 tagCount, 4052 *s); 4053 4054 #if qDNGValidate 4055 4056 if (gVerbose) 4057 { 4058 4059 printf ("%s: ", LookupTagCode (parentCode, tagCode)); 4060 4061 DumpString (*s); 4062 4063 printf ("\n"); 4064 4065 } 4066 4067 #endif 4068 4069 break; 4070 4071 } 4072 4073 case tcGPSLatitude: 4074 case tcGPSLongitude: 4075 case tcGPSTimeStamp: 4076 case tcGPSDestLatitude: 4077 case tcGPSDestLongitude: 4078 { 4079 4080 // Should really be ttRational per EXIF spec, but allow 4081 // ttSRational too because some JPEGs from Nexus 5 4082 // apparently use ttSRational type. 4083 4084 if (!CheckTagType (parentCode, tagCode, tagType, ttRational) && 4085 !CheckTagType (parentCode, tagCode, tagType, ttSRational)) 4086 return false; 4087 4088 if (!CheckTagCount (parentCode, tagCode, tagCount, 3)) 4089 return false; 4090 4091 dng_urational *u; 4092 4093 switch (tagCode) 4094 { 4095 4096 case tcGPSLatitude: 4097 u = fGPSLatitude; 4098 break; 4099 4100 case tcGPSLongitude: 4101 u = fGPSLongitude; 4102 break; 4103 4104 case tcGPSTimeStamp: 4105 u = fGPSTimeStamp; 4106 break; 4107 4108 case tcGPSDestLatitude: 4109 u = fGPSDestLatitude; 4110 break; 4111 4112 case tcGPSDestLongitude: 4113 u = fGPSDestLongitude; 4114 break; 4115 4116 default: 4117 return false; 4118 4119 } 4120 4121 u [0] = stream.TagValue_urational (tagType); 4122 u [1] = stream.TagValue_urational (tagType); 4123 u [2] = stream.TagValue_urational (tagType); 4124 4125 #if qDNGValidate 4126 4127 if (gVerbose) 4128 { 4129 4130 printf ("%s:", LookupTagCode (parentCode, tagCode)); 4131 4132 for (uint32 j = 0; j < 3; j++) 4133 { 4134 4135 if (u [j].d == 0) 4136 printf (" -"); 4137 4138 else 4139 printf (" %0.4f", u [j].As_real64 ()); 4140 4141 } 4142 4143 printf ("\n"); 4144 4145 } 4146 4147 #endif 4148 4149 break; 4150 4151 } 4152 4153 case tcGPSAltitudeRef: 4154 { 4155 4156 CheckTagType (parentCode, tagCode, tagType, ttByte); 4157 4158 CheckTagCount (parentCode, tagCode, tagCount, 1); 4159 4160 fGPSAltitudeRef = stream.TagValue_uint32 (tagType); 4161 4162 #if qDNGValidate 4163 4164 if (gVerbose) 4165 { 4166 4167 printf ("GPSAltitudeRef: "); 4168 4169 switch (fGPSAltitudeRef) 4170 { 4171 4172 case 0: 4173 printf ("Sea level"); 4174 break; 4175 4176 case 1: 4177 printf ("Sea level reference (negative value)"); 4178 break; 4179 4180 default: 4181 printf ("%u", (unsigned) fGPSAltitudeRef); 4182 break; 4183 4184 } 4185 4186 printf ("\n"); 4187 4188 } 4189 4190 #endif 4191 4192 break; 4193 4194 } 4195 4196 case tcGPSAltitude: 4197 case tcGPSDOP: 4198 case tcGPSSpeed: 4199 case tcGPSTrack: 4200 case tcGPSImgDirection: 4201 case tcGPSDestBearing: 4202 case tcGPSDestDistance: 4203 case tcGPSHPositioningError: 4204 { 4205 4206 if (!CheckTagType (parentCode, tagCode, tagType, ttRational)) 4207 return false; 4208 4209 CheckTagCount (parentCode, tagCode, tagCount, 1); 4210 4211 dng_urational *u; 4212 4213 switch (tagCode) 4214 { 4215 4216 case tcGPSAltitude: 4217 u = &fGPSAltitude; 4218 break; 4219 4220 case tcGPSDOP: 4221 u = &fGPSDOP; 4222 break; 4223 4224 case tcGPSSpeed: 4225 u = &fGPSSpeed; 4226 break; 4227 4228 case tcGPSTrack: 4229 u = &fGPSTrack; 4230 break; 4231 4232 case tcGPSImgDirection: 4233 u = &fGPSImgDirection; 4234 break; 4235 4236 case tcGPSDestBearing: 4237 u = &fGPSDestBearing; 4238 break; 4239 4240 case tcGPSDestDistance: 4241 u = &fGPSDestDistance; 4242 break; 4243 4244 case tcGPSHPositioningError: 4245 u = &fGPSHPositioningError; 4246 break; 4247 4248 default: 4249 return false; 4250 4251 } 4252 4253 *u = stream.TagValue_urational (tagType); 4254 4255 #if qDNGValidate 4256 4257 if (gVerbose) 4258 { 4259 4260 printf ("%s:", LookupTagCode (parentCode, tagCode)); 4261 4262 if (u->d == 0) 4263 printf (" -"); 4264 4265 else 4266 printf (" %0.4f", u->As_real64 ()); 4267 4268 printf ("\n"); 4269 4270 } 4271 4272 #endif 4273 4274 break; 4275 4276 } 4277 4278 case tcGPSProcessingMethod: 4279 case tcGPSAreaInformation: 4280 { 4281 4282 if (!CheckTagType (parentCode, tagCode, tagType, ttUndefined)) 4283 return false; 4284 4285 dng_string *s; 4286 4287 switch (tagCode) 4288 { 4289 4290 case tcGPSProcessingMethod: 4291 s = &fGPSProcessingMethod; 4292 break; 4293 4294 case tcGPSAreaInformation: 4295 s = &fGPSAreaInformation; 4296 break; 4297 4298 default: 4299 return false; 4300 4301 } 4302 4303 ParseEncodedStringTag (stream, 4304 parentCode, 4305 tagCode, 4306 tagCount, 4307 *s); 4308 4309 #if qDNGValidate 4310 4311 if (gVerbose) 4312 { 4313 4314 printf ("%s: ", LookupTagCode (parentCode, tagCode)); 4315 4316 DumpString (*s); 4317 4318 printf ("\n"); 4319 4320 } 4321 4322 #endif 4323 4324 break; 4325 4326 } 4327 4328 case tcGPSDifferential: 4329 { 4330 4331 CheckTagType (parentCode, tagCode, tagType, ttShort); 4332 4333 CheckTagCount (parentCode, tagCode, tagCount, 1); 4334 4335 fGPSDifferential = stream.TagValue_uint32 (tagType); 4336 4337 #if qDNGValidate 4338 4339 if (gVerbose) 4340 { 4341 4342 printf ("GPSDifferential: "); 4343 4344 switch (fGPSDifferential) 4345 { 4346 4347 case 0: 4348 printf ("Measurement without differential correction"); 4349 break; 4350 4351 case 1: 4352 printf ("Differential correction applied"); 4353 break; 4354 4355 default: 4356 printf ("%u", (unsigned) fGPSDifferential); 4357 4358 } 4359 4360 printf ("\n"); 4361 4362 } 4363 4364 #endif 4365 4366 break; 4367 4368 } 4369 4370 default: 4371 { 4372 4373 return false; 4374 4375 } 4376 4377 } 4378 4379 return true; 4380 4381 } 4382 4383 /*****************************************************************************/ 4384 4385 // Parses tags that should only appear in Interoperability IFD 4386 4387 bool dng_exif::Parse_interoperability (dng_stream &stream, 4388 dng_shared & /* shared */, 4389 uint32 parentCode, 4390 uint32 tagCode, 4391 uint32 tagType, 4392 uint32 tagCount, 4393 uint64 /* tagOffset */) 4394 { 4395 4396 switch (tagCode) 4397 { 4398 4399 case tcInteroperabilityIndex: 4400 { 4401 4402 CheckTagType (parentCode, tagCode, tagType, ttAscii); 4403 4404 CheckTagCount (parentCode, tagCode, tagCount, 4); 4405 4406 ParseStringTag (stream, 4407 parentCode, 4408 tagCode, 4409 tagCount, 4410 fInteroperabilityIndex); 4411 4412 #if qDNGValidate 4413 4414 if (gVerbose) 4415 { 4416 4417 printf ("InteroperabilityIndex: "); 4418 4419 DumpString (fInteroperabilityIndex); 4420 4421 printf ("\n"); 4422 4423 } 4424 4425 #endif 4426 4427 break; 4428 4429 } 4430 4431 case tcInteroperabilityVersion: 4432 { 4433 4434 CheckTagType (parentCode, tagCode, tagType, ttUndefined); 4435 4436 CheckTagCount (parentCode, tagCode, tagCount, 4); 4437 4438 uint32 b0 = stream.Get_uint8 (); 4439 uint32 b1 = stream.Get_uint8 (); 4440 uint32 b2 = stream.Get_uint8 (); 4441 uint32 b3 = stream.Get_uint8 (); 4442 4443 fInteroperabilityVersion = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3; 4444 4445 #if qDNGValidate 4446 4447 if (gVerbose) 4448 { 4449 4450 real64 x = (b0 - '0') * 10.00 + 4451 (b1 - '0') * 1.00 + 4452 (b2 - '0') * 0.10 + 4453 (b3 - '0') * 0.01; 4454 4455 printf ("InteroperabilityVersion: %0.2f\n", x); 4456 4457 } 4458 4459 #endif 4460 4461 break; 4462 4463 } 4464 4465 case tcRelatedImageFileFormat: 4466 { 4467 4468 CheckTagType (parentCode, tagCode, tagType, ttAscii); 4469 4470 ParseStringTag (stream, 4471 parentCode, 4472 tagCode, 4473 tagCount, 4474 fRelatedImageFileFormat); 4475 4476 #if qDNGValidate 4477 4478 if (gVerbose) 4479 { 4480 4481 printf ("RelatedImageFileFormat: "); 4482 4483 DumpString (fRelatedImageFileFormat); 4484 4485 printf ("\n"); 4486 4487 } 4488 4489 #endif 4490 4491 break; 4492 4493 } 4494 4495 case tcRelatedImageWidth: 4496 { 4497 4498 CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong); 4499 4500 CheckTagCount (parentCode, tagCode, tagCount, 1); 4501 4502 fRelatedImageWidth = stream.TagValue_uint32 (tagType); 4503 4504 #if qDNGValidate 4505 4506 if (gVerbose) 4507 { 4508 printf ("RelatedImageWidth: %u\n", (unsigned) fRelatedImageWidth); 4509 } 4510 4511 #endif 4512 4513 break; 4514 4515 } 4516 4517 case tcRelatedImageLength: 4518 { 4519 4520 CheckTagType (parentCode, tagCode, tagType, ttShort, ttLong); 4521 4522 CheckTagCount (parentCode, tagCode, tagCount, 1); 4523 4524 fRelatedImageLength = stream.TagValue_uint32 (tagType); 4525 4526 #if qDNGValidate 4527 4528 if (gVerbose) 4529 { 4530 printf ("RelatedImageLength: %u\n", (unsigned) fRelatedImageLength); 4531 } 4532 4533 #endif 4534 4535 break; 4536 4537 } 4538 4539 default: 4540 { 4541 4542 return false; 4543 4544 } 4545 4546 } 4547 4548 return true; 4549 4550 } 4551 4552 /*****************************************************************************/ 4553 4554 void dng_exif::PostParse (dng_host & /* host */, 4555 dng_shared & /* shared */) 4556 { 4557 4558 #if qDNGValidate 4559 4560 const real64 kAPEX_Slop = 0.25; 4561 4562 // Sanity check on MaxApertureValue. 4563 4564 if (fMaxApertureValue.d) 4565 { 4566 4567 real64 mav = fMaxApertureValue.As_real64 (); 4568 4569 // Compare against ApertureValue or FNumber. 4570 4571 real64 av = mav; 4572 4573 if (fApertureValue.d) 4574 { 4575 4576 av = fApertureValue.As_real64 (); 4577 4578 } 4579 4580 else if (fFNumber.d) 4581 { 4582 4583 real64 fs = fFNumber.As_real64 (); 4584 4585 if (fs >= 1.0) 4586 { 4587 4588 av = FNumberToApertureValue (fs); 4589 4590 } 4591 4592 } 4593 4594 if (mav > av + kAPEX_Slop) 4595 { 4596 4597 ReportWarning ("MaxApertureValue conflicts with ApertureValue and/or FNumber"); 4598 4599 } 4600 4601 // Compare against LensInfo 4602 4603 if (fLensInfo [2].d && fLensInfo [3].d) 4604 { 4605 4606 real64 fs1 = fLensInfo [2].As_real64 (); 4607 real64 fs2 = fLensInfo [3].As_real64 (); 4608 4609 if (fs1 >= 1.0 && fs2 >= 1.0 && fs2 >= fs1) 4610 { 4611 4612 real64 av1 = FNumberToApertureValue (fs1); 4613 real64 av2 = FNumberToApertureValue (fs2); 4614 4615 // Wide angle adapters might create an effective 4616 // wide FS, and tele-extenders always result 4617 // in a higher FS. 4618 4619 if (mav < av1 - kAPEX_Slop - 1.0 || 4620 mav > av2 + kAPEX_Slop + 2.0) 4621 { 4622 4623 ReportWarning ("Possible MaxApertureValue conflict with LensInfo"); 4624 4625 } 4626 4627 } 4628 4629 } 4630 4631 } 4632 4633 // Sanity check on FocalLength. 4634 4635 if (fFocalLength.d) 4636 { 4637 4638 real64 fl = fFocalLength.As_real64 (); 4639 4640 if (fl < 1.0) 4641 { 4642 4643 ReportWarning ("FocalLength is less than 1.0 mm (legal but unlikely)"); 4644 4645 } 4646 4647 else if (fLensInfo [0].d && fLensInfo [1].d) 4648 { 4649 4650 real64 minFL = fLensInfo [0].As_real64 (); 4651 real64 maxFL = fLensInfo [1].As_real64 (); 4652 4653 // Allow for wide-angle converters and tele-extenders. 4654 4655 if (fl < minFL * 0.6 || 4656 fl > maxFL * 2.1) 4657 { 4658 4659 ReportWarning ("Possible FocalLength conflict with LensInfo"); 4660 4661 } 4662 4663 } 4664 4665 } 4666 4667 #endif 4668 4669 // Mirror DateTimeOriginal to DateTime. 4670 4671 if (fDateTime.NotValid () && fDateTimeOriginal.IsValid ()) 4672 { 4673 4674 fDateTime = fDateTimeOriginal; 4675 4676 } 4677 4678 // Mirror EXIF 2.3 sensitivity tags to ISOSpeedRatings. 4679 4680 if (fISOSpeedRatings [0] == 0 || fISOSpeedRatings [0] == 65535) 4681 { 4682 4683 // Prefer Recommended Exposure Index, then Standard Output Sensitivity, then 4684 // ISO Speed, then Exposure Index. 4685 4686 if (fRecommendedExposureIndex != 0 && 4687 (fSensitivityType == stRecommendedExposureIndex || 4688 fSensitivityType == stSOSandREI || 4689 fSensitivityType == stREIandISOSpeed || 4690 fSensitivityType == stSOSandREIandISOSpeed)) 4691 { 4692 4693 fISOSpeedRatings [0] = fRecommendedExposureIndex; 4694 4695 } 4696 4697 else if (fStandardOutputSensitivity != 0 && 4698 (fSensitivityType == stStandardOutputSensitivity || 4699 fSensitivityType == stSOSandREI || 4700 fSensitivityType == stSOSandISOSpeed || 4701 fSensitivityType == stSOSandREIandISOSpeed)) 4702 { 4703 4704 fISOSpeedRatings [0] = fStandardOutputSensitivity; 4705 4706 } 4707 4708 else if (fISOSpeed != 0 && 4709 (fSensitivityType == stISOSpeed || 4710 fSensitivityType == stSOSandISOSpeed || 4711 fSensitivityType == stREIandISOSpeed || 4712 fSensitivityType == stSOSandREIandISOSpeed)) 4713 { 4714 4715 fISOSpeedRatings [0] = fISOSpeed; 4716 4717 } 4718 4719 } 4720 4721 // Mirror ExposureIndex to ISOSpeedRatings. 4722 4723 if (fExposureIndex.IsValid () && fISOSpeedRatings [0] == 0) 4724 { 4725 4726 fISOSpeedRatings [0] = Round_uint32 (fExposureIndex.As_real64 ()); 4727 4728 } 4729 4730 // Kodak sets the GPSAltitudeRef without setting the GPSAltitude. 4731 4732 if (fGPSAltitude.NotValid ()) 4733 { 4734 4735 fGPSAltitudeRef = 0xFFFFFFFF; 4736 4737 } 4738 4739 // If there is no valid GPS data, clear the GPS version number. 4740 4741 if (fGPSLatitude [0].NotValid () && 4742 fGPSLongitude [0].NotValid () && 4743 fGPSAltitude .NotValid () && 4744 fGPSTimeStamp [0].NotValid () && 4745 fGPSDateStamp .IsEmpty ()) 4746 { 4747 4748 fGPSVersionID = 0; 4749 4750 } 4751 4752 } 4753 4754 /*****************************************************************************/