add Sentera camera support to XMP
This commit is contained in:
76
TinyEXIF.cpp
76
TinyEXIF.cpp
@@ -49,6 +49,43 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
namespace Tools {
|
||||||
|
|
||||||
|
// search string inside a string, case sensitive
|
||||||
|
static const char* strrnstr(const char* haystack, const char* needle, size_t len) {
|
||||||
|
const size_t needle_len(strlen(needle));
|
||||||
|
if (0 == needle_len)
|
||||||
|
return haystack;
|
||||||
|
if (len <= needle_len)
|
||||||
|
return NULL;
|
||||||
|
for (size_t i=len-needle_len; i-- > 0; ) {
|
||||||
|
if (haystack[0] == needle[0] &&
|
||||||
|
0 == _tcsncmp(haystack, needle, needle_len))
|
||||||
|
return haystack;
|
||||||
|
haystack++;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// split an input string with a delimiter and fill a string vector
|
||||||
|
static void strSplit(const std::string& str, TCHAR delim, std::vector<std::string>& values) {
|
||||||
|
values.clear();
|
||||||
|
std::string::size_type start(0), end(0);
|
||||||
|
while (end != std::string::npos) {
|
||||||
|
end = str.find(delim, start);
|
||||||
|
values.emplace_back(str.substr(start, end-start));
|
||||||
|
start = end + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure the given degrees value is between -180 and 180
|
||||||
|
static double NormD180(double d) {
|
||||||
|
return (d = fmod(d+180.0, 360.0)) < 0 ? d+180.0 : d-180.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Tools
|
||||||
|
|
||||||
|
|
||||||
namespace TinyEXIF {
|
namespace TinyEXIF {
|
||||||
|
|
||||||
enum JPEG_MARKERS {
|
enum JPEG_MARKERS {
|
||||||
@@ -953,26 +990,6 @@ int EXIFInfo::parseFromXMPSegment(const uint8_t* buf, unsigned len) {
|
|||||||
return parseFromXMPSegmentXML((const char*)(buf + offs), len - offs);
|
return parseFromXMPSegmentXML((const char*)(buf + offs), len - offs);
|
||||||
}
|
}
|
||||||
int EXIFInfo::parseFromXMPSegmentXML(const char* szXML, unsigned len) {
|
int EXIFInfo::parseFromXMPSegmentXML(const char* szXML, unsigned len) {
|
||||||
struct Tools {
|
|
||||||
static const char* strrnstr(const char* haystack, const char* needle, size_t len) {
|
|
||||||
const size_t needle_len(strlen(needle));
|
|
||||||
if (0 == needle_len)
|
|
||||||
return haystack;
|
|
||||||
if (len <= needle_len)
|
|
||||||
return NULL;
|
|
||||||
for (size_t i=len-needle_len; i-- > 0; ) {
|
|
||||||
if (haystack[0] == needle[0] &&
|
|
||||||
0 == _tcsncmp(haystack, needle, needle_len))
|
|
||||||
return haystack;
|
|
||||||
haystack++;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
static double NormD180(double d) {
|
|
||||||
return (d = fmod(d+180.0, 360.0)) < 0 ? d+180.0 : d-180.0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Skip xpacket end section so that tinyxml2 lib parses the section correctly.
|
// Skip xpacket end section so that tinyxml2 lib parses the section correctly.
|
||||||
const char* szEnd(Tools::strrnstr(szXML, "<?xpacket end=", len));
|
const char* szEnd(Tools::strrnstr(szXML, "<?xpacket end=", len));
|
||||||
if (szEnd != NULL)
|
if (szEnd != NULL)
|
||||||
@@ -1024,12 +1041,21 @@ int EXIFInfo::parseFromXMPSegmentXML(const char* szXML, unsigned len) {
|
|||||||
|
|
||||||
// Try parsing the XMP content for supported maker's info.
|
// Try parsing the XMP content for supported maker's info.
|
||||||
struct ParseXMP {
|
struct ParseXMP {
|
||||||
|
// try yo fetch the value both from the attribute and child element
|
||||||
|
// and parse if needed rational numbers stored as string fraction
|
||||||
static bool Value(const tinyxml2::XMLElement* document, const char* name, double& value) {
|
static bool Value(const tinyxml2::XMLElement* document, const char* name, double& value) {
|
||||||
if (document->QueryDoubleAttribute(name, &value) == tinyxml2::XML_SUCCESS)
|
const char* szAttribute = document->Attribute(name);
|
||||||
return true;
|
if (szAttribute == NULL) {
|
||||||
const tinyxml2::XMLElement* const element(document->FirstChildElement(name));
|
const tinyxml2::XMLElement* const element(document->FirstChildElement(name));
|
||||||
if (element != NULL && element->QueryDoubleText(&value) == tinyxml2::XML_SUCCESS)
|
if (element == NULL || (szAttribute=element->GetText()) == NULL)
|
||||||
return true;
|
return false;
|
||||||
|
}
|
||||||
|
std::vector<std::string> values;
|
||||||
|
Tools::strSplit(szAttribute, '/', values);
|
||||||
|
switch (values.size()) {
|
||||||
|
case 1: value = strtod(values.front().c_str(), NULL); return true;
|
||||||
|
case 2: value = strtod(values.front().c_str(), NULL)/strtod(values.back().c_str(), NULL); return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -1044,7 +1070,7 @@ int EXIFInfo::parseFromXMPSegmentXML(const char* szXML, unsigned len) {
|
|||||||
ParseXMP::Value(document, "drone-dji:CalibratedOpticalCenterX", Calibration.OpticalCenterX);
|
ParseXMP::Value(document, "drone-dji:CalibratedOpticalCenterX", Calibration.OpticalCenterX);
|
||||||
ParseXMP::Value(document, "drone-dji:CalibratedOpticalCenterY", Calibration.OpticalCenterY);
|
ParseXMP::Value(document, "drone-dji:CalibratedOpticalCenterY", Calibration.OpticalCenterY);
|
||||||
} else
|
} else
|
||||||
if (0 == _tcsicmp(Make.c_str(), "senseFly")) {
|
if (0 == _tcsicmp(Make.c_str(), "senseFly") || 0 == _tcsicmp(Make.c_str(), "Sentera")) {
|
||||||
ParseXMP::Value(document, "Camera:Roll", GeoLocation.RollDegree);
|
ParseXMP::Value(document, "Camera:Roll", GeoLocation.RollDegree);
|
||||||
if (ParseXMP::Value(document, "Camera:Pitch", GeoLocation.PitchDegree)) {
|
if (ParseXMP::Value(document, "Camera:Pitch", GeoLocation.PitchDegree)) {
|
||||||
// convert to DJI format: senseFly uses pitch 0 as NADIR, whereas DJI -90
|
// convert to DJI format: senseFly uses pitch 0 as NADIR, whereas DJI -90
|
||||||
|
|||||||
Reference in New Issue
Block a user