parse projection type

This commit is contained in:
cdcseacave
2016-12-29 15:03:42 +02:00
parent 0931775e1e
commit f0f1ccdb97
3 changed files with 89 additions and 9 deletions

View File

@@ -1,3 +1,39 @@
# TinyEXIF: Tiny ISO-compliant C++ EXIF and XMP parsing library for JPEG
## Introduction
TinyEXIF is a tiny, lightweight C++ library for parsing the metadata existing inside JPEG files. No third party dependencies are needed to parse EXIF data, however for accesing XMP data the TinyXML2 library is needed. TinyEXIF is easy to use, simply copy the two source files in you project and pass the JPEG data to EXIFInfo class. Currently common information like the camera make/model, original resolution, timestamp, focal length, lens info, F-stop/exposure time, GPS information, etc, embedded in the EXIF/XMP metadata are fetched. It is easy though to extend it and add any missing or new EXIF/XMP fields.
## Usage example
```
#include "TinyEXIF.h"
#include <iostream> // std::cout
#include <fstream> // std::ifstream
#include <vector> // std::vector
int main(int argc, const char** argv) {
if (argc != 2) {
std::cout << "Usage: TinyEXIF <image_file>" << std::endl;
return -1;
}
// read entire image file
std::ifstream file(argv[1], std::ifstream::in|std::ifstream::binary);
file.seekg(0,std::ios::end);
std::streampos length = file.tellg();
file.seekg(0,std::ios::beg);
std::vector<uint8_t> data(length);
file.read((char*)data.data(), length);
// parse image EXIF and XMP metadata
TinyEXIF::EXIFInfo imageEXIF;
if (imageEXIF.parseFrom(data.data(), length) == TinyEXIF::PARSE_EXIF_SUCCESS)
std::cout
<< "Image Description " << imageEXIF.ImageDescription << "\n"
<< "Image Resolution " << imageEXIF.ImageWidth << "x" << imageEXIF.ImageHeight << " pixels\n"
<< "Camera Model " << imageEXIF.Make << " - " << imageEXIF.Model << "\n"
<< "Focal Length " << imageEXIF.FocalLength << " mm" << std::endl;
return 0;
}
```

View File

@@ -38,6 +38,15 @@
#include <stdio.h>
#include <vector>
#ifdef _MSC_VER
#include <tchar.h>
#else
#include <strings.h>
#define _tcsncmp strncmp
#define _tcsicmp strcasecmp
#endif
namespace TinyEXIF {
enum JPEG_MARKERS {
@@ -345,8 +354,8 @@ int EXIFInfo::parseFrom(const std::string &data) {
// Do a sanity check by looking for bytes "Exif\0\0".
// The marker has to contain at least the TIFF header, otherwise the
// JM_APP1 data is corrupt. So the minimum length specified here has to be:
// 6 bytes: "Exif\0\0" std::string
// 2 bytes: TIFF header (either "II" or "MM" std::string)
// 6 bytes: "Exif\0\0" string
// 2 bytes: TIFF header (either "II" or "MM" string)
// 2 bytes: TIFF magic (short 0x2a00 in Motorola byte order)
// 4 bytes: Offset to first IFD
// =========
@@ -671,7 +680,7 @@ int EXIFInfo::parseFromEXIFSegment(const uint8_t* buf, unsigned len) {
parser.Fetch(m, 1);
parser.Fetch(s, 2);
char buffer[256];
snprintf(buffer, 256, "%f %f %f", h, m, s);
snprintf(buffer, 256, "%g %g %g", h, m, s);
this->GeoLocation.GPSTimeStamp = buffer;
}
break;
@@ -707,7 +716,7 @@ int EXIFInfo::parseFromEXIFSegment(const uint8_t* buf, unsigned len) {
// Main parsing function for a XMP segment.
// Do a sanity check by looking for bytes "http://ns.adobe.com/xap/1.0/\0".
// So the minimum length specified here has to be:
// 29 bytes: "http://ns.adobe.com/xap/1.0/\0" std::string
// 29 bytes: "http://ns.adobe.com/xap/1.0/\0" string
//
// PARAM: 'buf' start of the XMP header, which must be the bytes "http://ns.adobe.com/xap/1.0/\0".
// PARAM: 'len' length of buffer
@@ -722,7 +731,7 @@ int EXIFInfo::parseFromXMPSegment(const uint8_t* buf, unsigned len) {
return NULL;
for (size_t i=len-needle_len; i-- > 0; ) {
if (haystack[0] == needle[0] &&
0 == strncmp(haystack, needle, needle_len))
0 == _tcsncmp(haystack, needle, needle_len))
return haystack;
haystack++;
}
@@ -748,19 +757,35 @@ int EXIFInfo::parseFromXMPSegment(const uint8_t* buf, unsigned len) {
// Now try parsing the XML packet.
tinyxml2::XMLDocument doc;
tinyxml2::XMLElement* document;
const tinyxml2::XMLElement* document;
if (doc.Parse(strXMP, len) != tinyxml2::XML_SUCCESS ||
((document=doc.FirstChildElement("x:xmpmeta")) == NULL && (document=doc.FirstChildElement("xmp:xmpmeta")) == NULL) ||
(document=document->FirstChildElement("rdf:RDF")) == NULL ||
(document=document->FirstChildElement("rdf:Description")) == NULL)
return PARSE_EXIF_SUCCESS;
// Now try parsing the XMP content of DJI.
// Now try parsing the XMP content for projection type.
{
const tinyxml2::XMLElement* const element(document->FirstChildElement("GPano:ProjectionType"));
if (element != NULL) {
const char* const szProjectionType(element->GetText());
if (szProjectionType != NULL) {
if (0 == _tcsicmp(szProjectionType, "perspective"))
ProjectionType = 1;
else if (0 == _tcsicmp(szProjectionType, "equirectangular") ||
0 == _tcsicmp(szProjectionType, "spherical"))
ProjectionType = 2;
}
}
}
// Now try parsing the XMP content for DJI info.
document->QueryDoubleAttribute("drone-dji:AbsoluteAltitude", &GeoLocation.Altitude);
document->QueryDoubleAttribute("drone-dji:RelativeAltitude", &GeoLocation.RelativeAltitude);
document->QueryDoubleAttribute("drone-dji:FlightRollDegree", &GeoLocation.RollDegree);
document->QueryDoubleAttribute("drone-dji:FlightPitchDegree", &GeoLocation.PitchDegree);
document->QueryDoubleAttribute("drone-dji:FlightYawDegree", &GeoLocation.YawDegree);
return PARSE_EXIF_SUCCESS;
}
@@ -834,6 +859,7 @@ void EXIFInfo::clear() {
FocalLength = 0;
Flash = 0;
MeteringMode = 0;
ProjectionType = 0;
ImageWidth = 0;
ImageHeight = 0;

View File

@@ -36,6 +36,20 @@
#include <string>
#ifdef _MSC_VER
# ifdef TINYEXIF_EXPORT
# define TINYEXIF_LIB __declspec(dllexport)
# elif defined(TINYEXIF_IMPORT)
# define TINYEXIF_LIB __declspec(dllimport)
# else
# define TINYEXIF_LIB
# endif
#elif __GNUC__ >= 4
# define TINYEXIF_LIB __attribute__((visibility("default")))
#else
# define TINYEXIF_LIB
#endif
namespace TinyEXIF {
enum ErrorCode {
@@ -47,10 +61,10 @@ enum ErrorCode {
PARSE_EXIF_ERROR_CORRUPT = 5, // EXIF header was found, but data was corrupted
};
//
//
// Class responsible for storing and parsing EXIF information from a JPEG blob
//
class EXIFInfo {
class TINYEXIF_LIB EXIFInfo {
public:
EXIFInfo() { clear(); }
@@ -118,6 +132,10 @@ public:
// 3: spot
// 4: multi-spot
// 5: multi-segment
uint16_t ProjectionType; // Projection type
// 0: unknown projection
// 1: perspective projection
// 2: equirectangular/spherical projection
uint32_t ImageWidth; // Image width reported in EXIF data
uint32_t ImageHeight; // Image height reported in EXIF data
struct LensInfo_t { // Lens information