add status field
This commit is contained in:
@@ -27,8 +27,8 @@ int main(int argc, const char** argv) {
|
|||||||
file.read((char*)data.data(), length);
|
file.read((char*)data.data(), length);
|
||||||
|
|
||||||
// parse image EXIF and XMP metadata
|
// parse image EXIF and XMP metadata
|
||||||
TinyEXIF::EXIFInfo imageEXIF;
|
TinyEXIF::EXIFInfo imageEXIF(data.data(), length);
|
||||||
if (imageEXIF.parseFrom(data.data(), length) == TinyEXIF::PARSE_EXIF_SUCCESS)
|
if (imageEXIF.Fields)
|
||||||
std::cout
|
std::cout
|
||||||
<< "Image Description " << imageEXIF.ImageDescription << "\n"
|
<< "Image Description " << imageEXIF.ImageDescription << "\n"
|
||||||
<< "Image Resolution " << imageEXIF.ImageWidth << "x" << imageEXIF.ImageHeight << " pixels\n"
|
<< "Image Resolution " << imageEXIF.ImageWidth << "x" << imageEXIF.ImageHeight << " pixels\n"
|
||||||
|
|||||||
108
TinyEXIF.cpp
108
TinyEXIF.cpp
@@ -36,6 +36,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <cfloat>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
@@ -252,6 +253,17 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors
|
||||||
|
EXIFInfo::EXIFInfo() : Fields(FIELD_NA) {
|
||||||
|
}
|
||||||
|
EXIFInfo::EXIFInfo(const uint8_t* data, unsigned length) {
|
||||||
|
parseFrom(data, length);
|
||||||
|
}
|
||||||
|
EXIFInfo::EXIFInfo(const std::string& data) {
|
||||||
|
parseFrom(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Parse tag as Image IFD
|
// Parse tag as Image IFD
|
||||||
void EXIFInfo::parseIFDImage(EntryParser& parser, unsigned& exif_sub_ifd_offset, unsigned& gps_sub_ifd_offset) {
|
void EXIFInfo::parseIFDImage(EntryParser& parser, unsigned& exif_sub_ifd_offset, unsigned& gps_sub_ifd_offset) {
|
||||||
switch (parser.GetTag()) {
|
switch (parser.GetTag()) {
|
||||||
@@ -597,31 +609,27 @@ void EXIFInfo::parseIFDGPS(EntryParser& parser) {
|
|||||||
// parseFromEXIFSegment() or parseFromXMPSegment()
|
// parseFromEXIFSegment() or parseFromXMPSegment()
|
||||||
//
|
//
|
||||||
int EXIFInfo::parseFrom(const uint8_t* buf, unsigned len) {
|
int EXIFInfo::parseFrom(const uint8_t* buf, unsigned len) {
|
||||||
|
clear();
|
||||||
|
|
||||||
// Sanity check: all JPEG files start with 0xFFD8 and end with 0xFFD9
|
// Sanity check: all JPEG files start with 0xFFD8 and end with 0xFFD9
|
||||||
// This check also ensures that the user has supplied a correct value for len.
|
// This check also ensures that the user has supplied a correct value for len.
|
||||||
if (!buf || len < 16)
|
if (!buf || len < 16)
|
||||||
return PARSE_EXIF_ERROR_NO_EXIF;
|
return PARSE_INVALID_JPEG;
|
||||||
if (buf[0] != JM_START || buf[1] != JM_SOI)
|
if (buf[0] != JM_START || buf[1] != JM_SOI)
|
||||||
return PARSE_EXIF_ERROR_NO_JPEG;
|
return PARSE_INVALID_JPEG;
|
||||||
// not always valid, sometimes 0xFF is added for padding
|
// not always valid, sometimes 0xFF is added for padding
|
||||||
//if (buf[len-2] != JM_START || buf[len-1] != JM_EOI)
|
//if (buf[len-2] != JM_START || buf[len-1] != JM_EOI)
|
||||||
// return PARSE_EXIF_ERROR_NO_JPEG;
|
// return PARSE_INVALID_JPEG;
|
||||||
|
|
||||||
// Scan for JM_APP1 header (bytes 0xFF 0xE1) and parse its length.
|
// Scan for JM_APP1 header (bytes 0xFF 0xE1) and parse its length.
|
||||||
// Exit if both EXIF and XMP sections were parsed.
|
// Exit if both EXIF and XMP sections were parsed.
|
||||||
enum {
|
|
||||||
APP1_NA = 0,
|
|
||||||
APP1_EXIF = (1 << 0),
|
|
||||||
APP1_XMP = (1 << 1),
|
|
||||||
APP1_ALL = APP1_EXIF|APP1_XMP
|
|
||||||
};
|
|
||||||
struct APP1S {
|
struct APP1S {
|
||||||
uint32_t val;
|
uint32_t& val;
|
||||||
inline APP1S() : val(APP1_NA) {}
|
inline APP1S(uint32_t& v) : val(v) {}
|
||||||
inline operator uint32_t () const { return val; }
|
inline operator uint32_t () const { return val; }
|
||||||
inline operator uint32_t& () { return val; }
|
inline operator uint32_t& () { return val; }
|
||||||
inline int operator () (int code=PARSE_EXIF_ERROR_NO_EXIF) const { return (val&APP1_EXIF) == 0 ? code : (int)PARSE_EXIF_SUCCESS; }
|
inline int operator () (int code=PARSE_ABSENT_DATA) const { return val&FIELD_ALL ? (int)PARSE_SUCCESS : code; }
|
||||||
} app1s;
|
} app1s(Fields);
|
||||||
for (unsigned pos=2; pos<len; ) {
|
for (unsigned pos=2; pos<len; ) {
|
||||||
// find next marker
|
// find next marker
|
||||||
uint8_t marker, prev(0);
|
uint8_t marker, prev(0);
|
||||||
@@ -652,21 +660,21 @@ int EXIFInfo::parseFrom(const uint8_t* buf, unsigned len) {
|
|||||||
const uint16_t section_length(EntryParser::parse16(buf + pos, false));
|
const uint16_t section_length(EntryParser::parse16(buf + pos, false));
|
||||||
int ret;
|
int ret;
|
||||||
switch (ret=parseFromEXIFSegment(buf + pos + 2, section_length - 2)) {
|
switch (ret=parseFromEXIFSegment(buf + pos + 2, section_length - 2)) {
|
||||||
case PARSE_EXIF_ERROR_NO_EXIF:
|
case PARSE_ABSENT_DATA:
|
||||||
switch (ret=parseFromXMPSegment(buf + pos + 2, section_length - 2)) {
|
switch (ret=parseFromXMPSegment(buf + pos + 2, section_length - 2)) {
|
||||||
case PARSE_EXIF_ERROR_NO_XMP:
|
case PARSE_ABSENT_DATA:
|
||||||
break;
|
break;
|
||||||
case PARSE_EXIF_SUCCESS:
|
case PARSE_SUCCESS:
|
||||||
if ((app1s|=APP1_XMP) == APP1_ALL)
|
if ((app1s|=FIELD_XMP) == FIELD_ALL)
|
||||||
return PARSE_EXIF_SUCCESS;
|
return PARSE_SUCCESS;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return app1s(ret); // some error
|
return app1s(ret); // some error
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PARSE_EXIF_SUCCESS:
|
case PARSE_SUCCESS:
|
||||||
if ((app1s|=APP1_EXIF) == APP1_ALL)
|
if ((app1s|=FIELD_EXIF) == FIELD_ALL)
|
||||||
return PARSE_EXIF_SUCCESS;
|
return PARSE_SUCCESS;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return app1s(ret); // some error
|
return app1s(ret); // some error
|
||||||
@@ -676,7 +684,7 @@ int EXIFInfo::parseFrom(const uint8_t* buf, unsigned len) {
|
|||||||
// read section length
|
// read section length
|
||||||
const uint16_t section_length(EntryParser::parse16(buf + pos, false));
|
const uint16_t section_length(EntryParser::parse16(buf + pos, false));
|
||||||
if (pos + section_length > len)
|
if (pos + section_length > len)
|
||||||
return app1s(PARSE_EXIF_ERROR_NO_JPEG);
|
return app1s(PARSE_INVALID_JPEG);
|
||||||
// skip the section
|
// skip the section
|
||||||
pos += section_length;
|
pos += section_length;
|
||||||
}
|
}
|
||||||
@@ -705,13 +713,11 @@ int EXIFInfo::parseFrom(const std::string& data) {
|
|||||||
// PARAM: 'len' length of buffer
|
// PARAM: 'len' length of buffer
|
||||||
//
|
//
|
||||||
int EXIFInfo::parseFromEXIFSegment(const uint8_t* buf, unsigned len) {
|
int EXIFInfo::parseFromEXIFSegment(const uint8_t* buf, unsigned len) {
|
||||||
unsigned offs = 0; // current offset into buffer
|
unsigned offs = 6; // current offset into buffer
|
||||||
if (!buf || len < 6)
|
if (!buf || len < offs)
|
||||||
return PARSE_EXIF_ERROR_NO_EXIF;
|
return PARSE_ABSENT_DATA;
|
||||||
|
if (!std::equal(buf, buf+offs, "Exif\0\0"))
|
||||||
if (!std::equal(buf, buf+6, "Exif\0\0"))
|
return PARSE_ABSENT_DATA;
|
||||||
return PARSE_EXIF_ERROR_NO_EXIF;
|
|
||||||
offs += 6;
|
|
||||||
|
|
||||||
// Now parsing the TIFF header. The first two bytes are either "II" or
|
// Now parsing the TIFF header. The first two bytes are either "II" or
|
||||||
// "MM" for Intel or Motorola byte alignment. Sanity check by parsing
|
// "MM" for Intel or Motorola byte alignment. Sanity check by parsing
|
||||||
@@ -725,7 +731,7 @@ int EXIFInfo::parseFromEXIFSegment(const uint8_t* buf, unsigned len) {
|
|||||||
// -----------------------------
|
// -----------------------------
|
||||||
// 8 bytes
|
// 8 bytes
|
||||||
if (offs + 8 > len)
|
if (offs + 8 > len)
|
||||||
return PARSE_EXIF_ERROR_CORRUPT;
|
return PARSE_CORRUPT_DATA;
|
||||||
bool alignIntel;
|
bool alignIntel;
|
||||||
if (buf[offs] == 'I' && buf[offs+1] == 'I')
|
if (buf[offs] == 'I' && buf[offs+1] == 'I')
|
||||||
alignIntel = true; // 1: Intel byte alignment
|
alignIntel = true; // 1: Intel byte alignment
|
||||||
@@ -733,16 +739,16 @@ int EXIFInfo::parseFromEXIFSegment(const uint8_t* buf, unsigned len) {
|
|||||||
if (buf[offs] == 'M' && buf[offs+1] == 'M')
|
if (buf[offs] == 'M' && buf[offs+1] == 'M')
|
||||||
alignIntel = false; // 0: Motorola byte alignment
|
alignIntel = false; // 0: Motorola byte alignment
|
||||||
else
|
else
|
||||||
return PARSE_EXIF_ERROR_UNKNOWN_BYTEALIGN;
|
return PARSE_UNKNOWN_BYTEALIGN;
|
||||||
EntryParser parser(buf, len, offs, alignIntel);
|
EntryParser parser(buf, len, offs, alignIntel);
|
||||||
offs += 2;
|
offs += 2;
|
||||||
if (0x2a != EntryParser::parse16(buf + offs, alignIntel))
|
if (0x2a != EntryParser::parse16(buf + offs, alignIntel))
|
||||||
return PARSE_EXIF_ERROR_CORRUPT;
|
return PARSE_CORRUPT_DATA;
|
||||||
offs += 2;
|
offs += 2;
|
||||||
const unsigned first_ifd_offset = EntryParser::parse32(buf + offs, alignIntel);
|
const unsigned first_ifd_offset = EntryParser::parse32(buf + offs, alignIntel);
|
||||||
offs += first_ifd_offset - 4;
|
offs += first_ifd_offset - 4;
|
||||||
if (offs >= len)
|
if (offs >= len)
|
||||||
return PARSE_EXIF_ERROR_CORRUPT;
|
return PARSE_CORRUPT_DATA;
|
||||||
|
|
||||||
// Now parsing the first Image File Directory (IFD0, for the main image).
|
// Now parsing the first Image File Directory (IFD0, for the main image).
|
||||||
// An IFD consists of a variable number of 12-byte directory entries. The
|
// An IFD consists of a variable number of 12-byte directory entries. The
|
||||||
@@ -751,10 +757,10 @@ int EXIFInfo::parseFromEXIFSegment(const uint8_t* buf, unsigned len) {
|
|||||||
// to the next IFD, which means this IFD must contain exactly 6 + 12 * num
|
// to the next IFD, which means this IFD must contain exactly 6 + 12 * num
|
||||||
// bytes of data.
|
// bytes of data.
|
||||||
if (offs + 2 > len)
|
if (offs + 2 > len)
|
||||||
return PARSE_EXIF_ERROR_CORRUPT;
|
return PARSE_CORRUPT_DATA;
|
||||||
int num_entries = EntryParser::parse16(buf + offs, alignIntel);
|
int num_entries = EntryParser::parse16(buf + offs, alignIntel);
|
||||||
if (offs + 6 + 12 * num_entries > len)
|
if (offs + 6 + 12 * num_entries > len)
|
||||||
return PARSE_EXIF_ERROR_CORRUPT;
|
return PARSE_CORRUPT_DATA;
|
||||||
unsigned exif_sub_ifd_offset = len;
|
unsigned exif_sub_ifd_offset = len;
|
||||||
unsigned gps_sub_ifd_offset = len;
|
unsigned gps_sub_ifd_offset = len;
|
||||||
parser.Init(offs+2);
|
parser.Init(offs+2);
|
||||||
@@ -771,7 +777,7 @@ int EXIFInfo::parseFromEXIFSegment(const uint8_t* buf, unsigned len) {
|
|||||||
offs = exif_sub_ifd_offset;
|
offs = exif_sub_ifd_offset;
|
||||||
int num_entries = EntryParser::parse16(buf + offs, alignIntel);
|
int num_entries = EntryParser::parse16(buf + offs, alignIntel);
|
||||||
if (offs + 6 + 12 * num_entries > len)
|
if (offs + 6 + 12 * num_entries > len)
|
||||||
return PARSE_EXIF_ERROR_CORRUPT;
|
return PARSE_CORRUPT_DATA;
|
||||||
parser.Init(offs+2);
|
parser.Init(offs+2);
|
||||||
while (--num_entries >= 0) {
|
while (--num_entries >= 0) {
|
||||||
parser.ParseTag();
|
parser.ParseTag();
|
||||||
@@ -785,7 +791,7 @@ int EXIFInfo::parseFromEXIFSegment(const uint8_t* buf, unsigned len) {
|
|||||||
offs = gps_sub_ifd_offset;
|
offs = gps_sub_ifd_offset;
|
||||||
int num_entries = EntryParser::parse16(buf + offs, alignIntel);
|
int num_entries = EntryParser::parse16(buf + offs, alignIntel);
|
||||||
if (offs + 6 + 12 * num_entries > len)
|
if (offs + 6 + 12 * num_entries > len)
|
||||||
return PARSE_EXIF_ERROR_CORRUPT;
|
return PARSE_CORRUPT_DATA;
|
||||||
parser.Init(offs+2);
|
parser.Init(offs+2);
|
||||||
while (--num_entries >= 0) {
|
while (--num_entries >= 0) {
|
||||||
parser.ParseTag();
|
parser.ParseTag();
|
||||||
@@ -794,7 +800,7 @@ int EXIFInfo::parseFromEXIFSegment(const uint8_t* buf, unsigned len) {
|
|||||||
GeoLocation.parseCoords();
|
GeoLocation.parseCoords();
|
||||||
}
|
}
|
||||||
|
|
||||||
return PARSE_EXIF_SUCCESS;
|
return PARSE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -824,15 +830,13 @@ int EXIFInfo::parseFromXMPSegment(const uint8_t* buf, unsigned len) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned offs = 0; // current offset into buffer
|
unsigned offs = 29; // current offset into buffer
|
||||||
if (!buf || len < 29)
|
if (!buf || len < offs)
|
||||||
return PARSE_EXIF_ERROR_NO_XMP;
|
return PARSE_ABSENT_DATA;
|
||||||
|
if (!std::equal(buf, buf+offs, "http://ns.adobe.com/xap/1.0/\0"))
|
||||||
if (!std::equal(buf, buf+29, "http://ns.adobe.com/xap/1.0/\0"))
|
return PARSE_ABSENT_DATA;
|
||||||
return PARSE_EXIF_ERROR_NO_XMP;
|
|
||||||
offs += 29;
|
|
||||||
if (offs >= len)
|
if (offs >= len)
|
||||||
return PARSE_EXIF_ERROR_CORRUPT;
|
return PARSE_CORRUPT_DATA;
|
||||||
len -= offs;
|
len -= offs;
|
||||||
|
|
||||||
// Skip xpacket end section so that tinyxml2 lib parses the section correctly.
|
// Skip xpacket end section so that tinyxml2 lib parses the section correctly.
|
||||||
@@ -847,7 +851,7 @@ int EXIFInfo::parseFromXMPSegment(const uint8_t* buf, unsigned len) {
|
|||||||
((document=doc.FirstChildElement("x:xmpmeta")) == NULL && (document=doc.FirstChildElement("xmp:xmpmeta")) == NULL) ||
|
((document=doc.FirstChildElement("x:xmpmeta")) == NULL && (document=doc.FirstChildElement("xmp:xmpmeta")) == NULL) ||
|
||||||
(document=document->FirstChildElement("rdf:RDF")) == NULL ||
|
(document=document->FirstChildElement("rdf:RDF")) == NULL ||
|
||||||
(document=document->FirstChildElement("rdf:Description")) == NULL)
|
(document=document->FirstChildElement("rdf:Description")) == NULL)
|
||||||
return PARSE_EXIF_SUCCESS;
|
return PARSE_ABSENT_DATA;
|
||||||
|
|
||||||
// Now try parsing the XMP content for projection type.
|
// Now try parsing the XMP content for projection type.
|
||||||
{
|
{
|
||||||
@@ -867,11 +871,11 @@ int EXIFInfo::parseFromXMPSegment(const uint8_t* buf, unsigned len) {
|
|||||||
// Now try parsing the XMP content for DJI info.
|
// Now try parsing the XMP content for DJI info.
|
||||||
document->QueryDoubleAttribute("drone-dji:AbsoluteAltitude", &GeoLocation.Altitude);
|
document->QueryDoubleAttribute("drone-dji:AbsoluteAltitude", &GeoLocation.Altitude);
|
||||||
document->QueryDoubleAttribute("drone-dji:RelativeAltitude", &GeoLocation.RelativeAltitude);
|
document->QueryDoubleAttribute("drone-dji:RelativeAltitude", &GeoLocation.RelativeAltitude);
|
||||||
document->QueryDoubleAttribute("drone-dji:FlightRollDegree", &GeoLocation.RollDegree);
|
document->QueryDoubleAttribute("drone-dji:GimbalRollDegree", &GeoLocation.RollDegree);
|
||||||
document->QueryDoubleAttribute("drone-dji:FlightPitchDegree", &GeoLocation.PitchDegree);
|
document->QueryDoubleAttribute("drone-dji:GimbalPitchDegree", &GeoLocation.PitchDegree);
|
||||||
document->QueryDoubleAttribute("drone-dji:FlightYawDegree", &GeoLocation.YawDegree);
|
document->QueryDoubleAttribute("drone-dji:GimbalYawDegree", &GeoLocation.YawDegree);
|
||||||
|
|
||||||
return PARSE_EXIF_SUCCESS;
|
return PARSE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -920,6 +924,8 @@ bool EXIFInfo::Geolocation_t::hasOrientation() const {
|
|||||||
|
|
||||||
|
|
||||||
void EXIFInfo::clear() {
|
void EXIFInfo::clear() {
|
||||||
|
Fields = FIELD_NA;
|
||||||
|
|
||||||
// Strings
|
// Strings
|
||||||
ImageDescription = "";
|
ImageDescription = "";
|
||||||
Make = "";
|
Make = "";
|
||||||
|
|||||||
32
TinyEXIF.h
32
TinyEXIF.h
@@ -54,12 +54,18 @@
|
|||||||
namespace TinyEXIF {
|
namespace TinyEXIF {
|
||||||
|
|
||||||
enum ErrorCode {
|
enum ErrorCode {
|
||||||
PARSE_EXIF_SUCCESS = 0, // Parse was successful
|
PARSE_SUCCESS = 0, // Parse EXIF and/or XMP was successful
|
||||||
PARSE_EXIF_ERROR_NO_JPEG = 1, // No JPEG markers found in buffer, possibly invalid JPEG file
|
PARSE_INVALID_JPEG = 1, // No JPEG markers found in buffer, possibly invalid JPEG file
|
||||||
PARSE_EXIF_ERROR_NO_EXIF = 2, // No EXIF header found in JPEG file
|
PARSE_UNKNOWN_BYTEALIGN = 2, // Byte alignment specified in EXIF file was unknown (neither Motorola nor Intel)
|
||||||
PARSE_EXIF_ERROR_NO_XMP = 3, // No XMP header found in JPEG file
|
PARSE_ABSENT_DATA = 3, // No EXIF and/or XMP data found in JPEG file
|
||||||
PARSE_EXIF_ERROR_UNKNOWN_BYTEALIGN = 4, // Byte alignment specified in EXIF file was unknown (not Motorola or Intel)
|
PARSE_CORRUPT_DATA = 4, // EXIF and/or XMP header was found, but data was corrupted
|
||||||
PARSE_EXIF_ERROR_CORRUPT = 5, // EXIF header was found, but data was corrupted
|
};
|
||||||
|
|
||||||
|
enum FieldCode {
|
||||||
|
FIELD_NA = 0, // No EXIF or XMP data
|
||||||
|
FIELD_EXIF = (1 << 0), // EXIF data available
|
||||||
|
FIELD_XMP = (1 << 1), // XMP data available
|
||||||
|
FIELD_ALL = FIELD_EXIF|FIELD_XMP
|
||||||
};
|
};
|
||||||
|
|
||||||
class EntryParser;
|
class EntryParser;
|
||||||
@@ -69,16 +75,18 @@ class EntryParser;
|
|||||||
//
|
//
|
||||||
class TINYEXIF_LIB EXIFInfo {
|
class TINYEXIF_LIB EXIFInfo {
|
||||||
public:
|
public:
|
||||||
EXIFInfo() { clear(); }
|
EXIFInfo();
|
||||||
|
EXIFInfo(const uint8_t* data, unsigned length);
|
||||||
|
EXIFInfo(const std::string& data);
|
||||||
|
|
||||||
// Parsing function for an entire JPEG image buffer.
|
// Parsing function for an entire JPEG image stream.
|
||||||
//
|
//
|
||||||
// PARAM 'data': A pointer to a JPEG image.
|
// PARAM 'data': A pointer to a JPEG image.
|
||||||
// PARAM 'length': The length of the JPEG image.
|
// PARAM 'length': The length of the JPEG image.
|
||||||
// RETURN: PARSE_EXIF_SUCCESS (0) on success with 'result' filled out
|
// RETURN: PARSE_SUCCESS (0) on success with 'result' filled out
|
||||||
// error code otherwise, as defined by the PARSE_EXIF_ERROR_* macros
|
// error code otherwise, as defined by the PARSE_* macros
|
||||||
int parseFrom(const uint8_t* data, unsigned length);
|
int parseFrom(const uint8_t* data, unsigned length);
|
||||||
int parseFrom(const std::string &data);
|
int parseFrom(const std::string& data);
|
||||||
|
|
||||||
// Parsing function for an EXIF segment. This is used internally by parseFrom()
|
// Parsing function for an EXIF segment. This is used internally by parseFrom()
|
||||||
// but can be called for special cases where only the EXIF section is
|
// but can be called for special cases where only the EXIF section is
|
||||||
@@ -91,6 +99,7 @@ public:
|
|||||||
int parseFromXMPSegment(const uint8_t* buf, unsigned len);
|
int parseFromXMPSegment(const uint8_t* buf, unsigned len);
|
||||||
|
|
||||||
// Set all data members to default values.
|
// Set all data members to default values.
|
||||||
|
// Should be called before parsing a new stream.
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -103,6 +112,7 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// Data fields
|
// Data fields
|
||||||
|
uint32_t Fields; // Store if EXIF and/or XMP data fields are available
|
||||||
uint32_t ImageWidth; // Image width reported in EXIF data
|
uint32_t ImageWidth; // Image width reported in EXIF data
|
||||||
uint32_t ImageHeight; // Image height reported in EXIF data
|
uint32_t ImageHeight; // Image height reported in EXIF data
|
||||||
uint32_t RelatedImageWidth; // Original image width reported in EXIF data
|
uint32_t RelatedImageWidth; // Original image width reported in EXIF data
|
||||||
|
|||||||
4
main.cpp
4
main.cpp
@@ -29,8 +29,8 @@ int main(int argc, const char** argv)
|
|||||||
file.read((char*)data.data(), length);
|
file.read((char*)data.data(), length);
|
||||||
|
|
||||||
// parse image EXIF and XMP metadata
|
// parse image EXIF and XMP metadata
|
||||||
TinyEXIF::EXIFInfo imageEXIF;
|
TinyEXIF::EXIFInfo imageEXIF(data.data(), (unsigned)length);
|
||||||
if (imageEXIF.parseFrom(data.data(), (unsigned)length) == TinyEXIF::PARSE_EXIF_SUCCESS) {
|
if (imageEXIF.Fields) {
|
||||||
if (imageEXIF.ImageWidth || imageEXIF.ImageHeight)
|
if (imageEXIF.ImageWidth || imageEXIF.ImageHeight)
|
||||||
std::cout << "ImageResolution " << imageEXIF.ImageWidth << "x" << imageEXIF.ImageHeight << " pixels" << "\n";
|
std::cout << "ImageResolution " << imageEXIF.ImageWidth << "x" << imageEXIF.ImageHeight << " pixels" << "\n";
|
||||||
if (imageEXIF.RelatedImageWidth || imageEXIF.RelatedImageHeight)
|
if (imageEXIF.RelatedImageWidth || imageEXIF.RelatedImageHeight)
|
||||||
|
|||||||
Reference in New Issue
Block a user