Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 60 additions & 3 deletions TinyEXIF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,19 @@
*/

#include "TinyEXIF.h"
#include <cstddef>

#ifndef TINYEXIF_NO_XMP_SUPPORT
#include <tinyxml2.h>
#endif // TINYEXIF_NO_XMP_SUPPORT

#include <cstdint>
#include <cstdio>
#include <cmath>
#include <cfloat>
#include <vector>
#include <algorithm>
#include <iostream>
#include <sstream>

#ifdef _MSC_VER
namespace {
Expand Down Expand Up @@ -1114,8 +1115,19 @@ int EXIFInfo::parseFromXMPSegmentXML(const char* szXML, unsigned len) {
if (element == NULL || (szAttribute = element->GetText()) == NULL)
return false;
}
value = strtoul(szAttribute, NULL, 0); return true;
return false;
value = strtoul(szAttribute, NULL, 0);
return true;
}
// same as previous function but with std::string
static bool Value(const tinyxml2::XMLElement* document, const char* name, std::string& value) {
const char* szAttribute = document->Attribute(name);
if (szAttribute == NULL) {
const tinyxml2::XMLElement* const element(document->FirstChildElement(name));
if (element == NULL || (szAttribute = element->GetText()) == NULL)
return false;
}
value = std::string(szAttribute);
return true;
}
};
const char* szAbout(document->Attribute("rdf:about"));
Expand All @@ -1128,6 +1140,29 @@ int EXIFInfo::parseFromXMPSegmentXML(const char* szXML, unsigned len) {
ParseXMP::Value(document, "drone-dji:CalibratedFocalLength", Calibration.FocalLength);
ParseXMP::Value(document, "drone-dji:CalibratedOpticalCenterX", Calibration.OpticalCenterX);
ParseXMP::Value(document, "drone-dji:CalibratedOpticalCenterY", Calibration.OpticalCenterY);
ParseXMP::Value(document, "drone-dji:CalibratedOpticalCenterY", Calibration.OpticalCenterY);
std::string dewarpData;
ParseXMP::Value(document, "drone-dji:DewarpFlag", Distortion.DewarpFlag);
ParseXMP::Value(document, "drone-dji:DewarpData", dewarpData);
std::vector<double> distortionParams;
size_t pos = dewarpData.find(';');
if (pos != std::string::npos) {
std::stringstream ss(dewarpData.substr(pos + 1));
std::string item;
while (std::getline(ss, item, ',')) {
distortionParams.push_back(std::stod(item));
}
}
// The DewarpData string has the following format:
// date;Fx,Fy,Cx,Cy,K1,K2,P1,P2,K3
// , where Fx, Fy are focal lengths in pixels, Cx, Cy are optical center offsets from the image center in pixels
if (distortionParams.size() == 9) {
Distortion.K1 = distortionParams[4];
Distortion.K2 = distortionParams[5];
Distortion.P1 = distortionParams[6];
Distortion.P2 = distortionParams[7];
Distortion.K3 = distortionParams[8];
}
} else
if (0 == strcasecmp(Make.c_str(), "senseFly") || 0 == strcasecmp(Make.c_str(), "Sentera")) {
ParseXMP::Value(document, "Camera:Roll", GeoLocation.RollDegree);
Expand Down Expand Up @@ -1165,6 +1200,17 @@ int EXIFInfo::parseFromXMPSegmentXML(const char* szXML, unsigned len) {

#endif // TINYEXIF_NO_XMP_SUPPORT

bool EXIFInfo::Calibration_t::hasCalibration() const {
return FocalLength > 0.0 && OpticalCenterX > 0.0 && OpticalCenterY > 0.0;
}

bool EXIFInfo::Distortion_t::hasDewarpFlag() const {
return DewarpFlag != UINT32_MAX;
}
bool EXIFInfo::Distortion_t::hasDistortion() const {
return K1 != 0.0 || K2 != 0.0 || P1 != 0.0 || P2 != 0.0 || K3 != 0.0;
}

void EXIFInfo::Geolocation_t::parseCoords() {
// Convert GPS latitude
if (LatComponents.degrees != DBL_MAX ||
Expand Down Expand Up @@ -1210,6 +1256,9 @@ bool EXIFInfo::Geolocation_t::hasOrientation() const {
bool EXIFInfo::Geolocation_t::hasSpeed() const {
return SpeedX != DBL_MAX && SpeedY != DBL_MAX && SpeedZ != DBL_MAX;
}
bool EXIFInfo::Geolocation_t::hasAccuracy() const {
return AccuracyXY != 0 && AccuracyZ != 0;
}

bool EXIFInfo::GPano_t::hasPosePitchDegrees() const {
return PosePitchDegrees != DBL_MAX;
Expand Down Expand Up @@ -1306,6 +1355,14 @@ void EXIFInfo::clear() {
GeoLocation.LonComponents.seconds = 0;
GeoLocation.LonComponents.direction = 0;

// Distortion
Distortion.DewarpFlag = UINT32_MAX;
Distortion.K1 = 0;
Distortion.K2 = 0;
Distortion.P1 = 0;
Distortion.P2 = 0;
Distortion.K3 = 0;

// GPano
GPano.PosePitchDegrees = DBL_MAX;
GPano.PoseRollDegrees = DBL_MAX;
Expand Down
15 changes: 15 additions & 0 deletions TinyEXIF.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,21 @@ class TINYEXIF_LIB EXIFInfo {
double FocalLength; // Focal length (pixels)
double OpticalCenterX; // Principal point X (pixels)
double OpticalCenterY; // Principal point Y (pixels)
bool hasCalibration() const; // Return true if FocalLength, OpticalCenterX, OpticalCenterY are available (nonzero)
} Calibration;
struct TINYEXIF_LIB Distortion_t { // Lens distortion information
uint32_t DewarpFlag; // Dewarp flag - indicates whether undistortion has been applied to the image
// UINT32_MAX: flag missing from EXIF data
// 0: no dewarp (raw image) - the image is distorted, should also have coefficients
// 1: dewarp applied (undistorted image)
double K1;
double K2;
double P1;
double P2;
double K3;
bool hasDewarpFlag() const; // Return true if DewarpFlag is available
bool hasDistortion() const; // Return true if any of K1, K2, P1, P2, K3 are available
} Distortion;
struct TINYEXIF_LIB LensInfo_t { // Lens information
double FStopMin; // Min aperture (f-stop)
double FStopMax; // Max aperture (f-stop)
Expand Down Expand Up @@ -302,6 +316,7 @@ class TINYEXIF_LIB EXIFInfo {
bool hasRelativeAltitude()const;// Return true if (rel_alt) is available
bool hasOrientation() const; // Return true if (roll,yaw,pitch) is available
bool hasSpeed() const; // Return true if (speedX,speedY,speedZ) is available
bool hasAccuracy() const; // Return true if (accuracyXY,accuracyZ) is available
} GeoLocation;
struct TINYEXIF_LIB GPano_t { // Spherical metadata. https://developers.google.com/streetview/spherical-metadata
double PosePitchDegrees; // Pitch, measured in degrees above the horizon, for the center in the image. Value must be >= -90 and <= 90.
Expand Down