add few more tags
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## Introduction
|
## 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.
|
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](https://github.com/leethomason/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
|
## Usage example
|
||||||
|
|
||||||
|
|||||||
257
TinyEXIF.cpp
257
TinyEXIF.cpp
@@ -126,7 +126,7 @@ private:
|
|||||||
const bool alignIntel; // byte alignment (defined in EXIF header)
|
const bool alignIntel; // byte alignment (defined in EXIF header)
|
||||||
unsigned offs; // current offset into buffer
|
unsigned offs; // current offset into buffer
|
||||||
uint16_t tag, format;
|
uint16_t tag, format;
|
||||||
uint32_t length, data;
|
uint32_t length;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
EntryParser(const uint8_t* _buf, unsigned _len, unsigned _tiff_header_start, bool _alignIntel)
|
EntryParser(const uint8_t* _buf, unsigned _len, unsigned _tiff_header_start, bool _alignIntel)
|
||||||
@@ -141,88 +141,79 @@ public:
|
|||||||
tag = parse16(buf + offs, alignIntel);
|
tag = parse16(buf + offs, alignIntel);
|
||||||
format = parse16(buf + offs + 2, alignIntel);
|
format = parse16(buf + offs + 2, alignIntel);
|
||||||
length = parse32(buf + offs + 4, alignIntel);
|
length = parse32(buf + offs + 4, alignIntel);
|
||||||
data = parse32(buf + offs + 8, alignIntel);
|
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t GetTag() const { return tag; }
|
uint16_t GetTag() const { return tag; }
|
||||||
uint16_t GetFormat() const { return format; }
|
|
||||||
uint32_t GetLength() const { return length; }
|
uint32_t GetLength() const { return length; }
|
||||||
uint32_t GetData() const { return data; }
|
uint32_t GetData() const { return parse32(buf + offs + 8, alignIntel); }
|
||||||
|
uint32_t GetSubIFD() const { return tiff_header_start + GetData(); }
|
||||||
|
|
||||||
|
bool IsRational() const { return format == 5 || format == 10; }
|
||||||
|
|
||||||
bool Fetch(std::string& val) const {
|
bool Fetch(std::string& val) const {
|
||||||
if (format != 2)
|
if (format != 2)
|
||||||
return false;
|
return false;
|
||||||
val = parseEXIFString(buf, length, data, tiff_header_start, len, alignIntel);
|
val = parseEXIFString(buf, length, GetData(), tiff_header_start, len, alignIntel);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
bool Fetch(uint8_t& val) const {
|
||||||
bool Fetch(int8_t& val) const {
|
if (format != 1 && format != 2 && format != 6)
|
||||||
if (format != 2)
|
|
||||||
return false;
|
return false;
|
||||||
val = (int8_t)parse16(buf + offs + 8, alignIntel);
|
val = parse8(buf + offs + 8);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Fetch(uint16_t& val) const {
|
bool Fetch(uint16_t& val) const {
|
||||||
if (format != 3)
|
if (format != 3)
|
||||||
return false;
|
return false;
|
||||||
val = parse16(buf + offs + 8, alignIntel);
|
val = parse16(buf + offs + 8, alignIntel);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Fetch(uint32_t& val) const {
|
bool Fetch(uint32_t& val) const {
|
||||||
if (format != 4)
|
if (format != 4)
|
||||||
return false;
|
return false;
|
||||||
val = data;
|
val = parse32(buf + offs + 8, alignIntel);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Fetch(double& val) const {
|
bool Fetch(double& val) const {
|
||||||
if (format != 5)
|
if (!IsRational())
|
||||||
return false;
|
return false;
|
||||||
val = parseEXIFRational(buf + data + tiff_header_start, alignIntel);
|
val = parseEXIFRational(buf + GetSubIFD(), alignIntel);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool Fetch(double& val, uint32_t idx) const {
|
bool Fetch(double& val, uint32_t idx) const {
|
||||||
if (format != 5 || length <= idx)
|
if (!IsRational() || length <= idx)
|
||||||
return false;
|
return false;
|
||||||
val = parseEXIFRational(buf + data + tiff_header_start + idx*8, alignIntel);
|
val = parseEXIFRational(buf + GetSubIFD() + idx*8, alignIntel);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned FetchSubIFD() const {
|
|
||||||
return tiff_header_start + data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
static uint8_t parse8(const uint8_t* buf) {
|
||||||
|
return buf[0];
|
||||||
|
}
|
||||||
static uint16_t parse16(const uint8_t* buf, bool intel) {
|
static uint16_t parse16(const uint8_t* buf, bool intel) {
|
||||||
if (intel)
|
if (intel)
|
||||||
return ((uint16_t)buf[1]<<8) | buf[0];
|
return ((uint16_t)buf[1]<<8) | buf[0];
|
||||||
return ((uint16_t)buf[0]<<8) | buf[1];
|
return ((uint16_t)buf[0]<<8) | buf[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t parse32(const uint8_t* buf, bool intel) {
|
static uint32_t parse32(const uint8_t* buf, bool intel) {
|
||||||
if (intel)
|
if (intel)
|
||||||
return ((uint32_t)buf[3]<<24) |
|
return ((uint32_t)buf[3]<<24) |
|
||||||
((uint32_t)buf[2]<<16) |
|
((uint32_t)buf[2]<<16) |
|
||||||
((uint32_t)buf[1]<<8) |
|
((uint32_t)buf[1]<<8) |
|
||||||
buf[0];
|
buf[0];
|
||||||
|
|
||||||
return ((uint32_t)buf[0]<<24) |
|
return ((uint32_t)buf[0]<<24) |
|
||||||
((uint32_t)buf[1]<<16) |
|
((uint32_t)buf[1]<<16) |
|
||||||
((uint32_t)buf[2]<<8) |
|
((uint32_t)buf[2]<<8) |
|
||||||
buf[3];
|
buf[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
static double parseEXIFRational(const uint8_t* buf, bool intel) {
|
static double parseEXIFRational(const uint8_t* buf, bool intel) {
|
||||||
const uint32_t denominator = parse32(buf+4, intel);
|
const uint32_t denominator = parse32(buf+4, intel);
|
||||||
if (denominator == 0)
|
if (denominator == 0)
|
||||||
return 0.0;
|
return 0.0;
|
||||||
const uint32_t numerator = parse32(buf, intel);
|
const uint32_t numerator = parse32(buf, intel);
|
||||||
return (double)numerator/(double)denominator;
|
return (double)(int32_t)numerator/(double)(int32_t)denominator;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string parseEXIFString(const uint8_t* buf,
|
static std::string parseEXIFString(const uint8_t* buf,
|
||||||
unsigned num_components,
|
unsigned num_components,
|
||||||
unsigned data,
|
unsigned data,
|
||||||
@@ -388,10 +379,10 @@ int EXIFInfo::parseFromEXIFSegment(const uint8_t* buf, unsigned len) {
|
|||||||
return PARSE_EXIF_ERROR_CORRUPT;
|
return PARSE_EXIF_ERROR_CORRUPT;
|
||||||
const unsigned tiff_header_start = offs;
|
const unsigned tiff_header_start = offs;
|
||||||
if (buf[offs] == 'I' && buf[offs+1] == 'I')
|
if (buf[offs] == 'I' && buf[offs+1] == 'I')
|
||||||
this->ByteAlign = 1;
|
ByteAlign = 1;
|
||||||
else {
|
else {
|
||||||
if (buf[offs] == 'M' && buf[offs+1] == 'M')
|
if (buf[offs] == 'M' && buf[offs+1] == 'M')
|
||||||
this->ByteAlign = 0;
|
ByteAlign = 0;
|
||||||
else
|
else
|
||||||
return PARSE_EXIF_ERROR_UNKNOWN_BYTEALIGN;
|
return PARSE_EXIF_ERROR_UNKNOWN_BYTEALIGN;
|
||||||
}
|
}
|
||||||
@@ -421,69 +412,96 @@ int EXIFInfo::parseFromEXIFSegment(const uint8_t* buf, unsigned len) {
|
|||||||
parser.Init(offs+2);
|
parser.Init(offs+2);
|
||||||
while (--num_entries >= 0) {
|
while (--num_entries >= 0) {
|
||||||
switch (parser.ParseTag()) {
|
switch (parser.ParseTag()) {
|
||||||
case 0x102:
|
case 0x0102:
|
||||||
// Bits per sample
|
// Bits per sample
|
||||||
parser.Fetch(this->BitsPerSample);
|
parser.Fetch(BitsPerSample);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x10E:
|
case 0x010e:
|
||||||
// Image description
|
// Image description
|
||||||
parser.Fetch(this->ImageDescription);
|
parser.Fetch(ImageDescription);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x10F:
|
case 0x010f:
|
||||||
// Camera maker
|
// Camera maker
|
||||||
parser.Fetch(this->Make);
|
parser.Fetch(Make);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x110:
|
case 0x0110:
|
||||||
// Camera model
|
// Camera model
|
||||||
parser.Fetch(this->Model);
|
parser.Fetch(Model);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x112:
|
case 0x0112:
|
||||||
// Orientation of image
|
// Orientation of image
|
||||||
parser.Fetch(this->Orientation);
|
parser.Fetch(Orientation);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x011a:
|
case 0x011a:
|
||||||
// XResolution
|
// XResolution
|
||||||
parser.Fetch(this->XResolution);
|
parser.Fetch(XResolution);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x011b:
|
case 0x011b:
|
||||||
// YResolution
|
// YResolution
|
||||||
parser.Fetch(this->YResolution);
|
parser.Fetch(YResolution);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x128:
|
case 0x0128:
|
||||||
// Resolution Unit
|
// Resolution Unit
|
||||||
parser.Fetch(this->ResolutionUnit);
|
parser.Fetch(ResolutionUnit);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x131:
|
case 0x0131:
|
||||||
// Software used for image
|
// Software used for image
|
||||||
parser.Fetch(this->Software);
|
parser.Fetch(Software);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x132:
|
case 0x0132:
|
||||||
// EXIF/TIFF date/time of image modification
|
// EXIF/TIFF date/time of image modification
|
||||||
parser.Fetch(this->DateTime);
|
parser.Fetch(DateTime);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x1001:
|
||||||
|
// Original Image width
|
||||||
|
if (!parser.Fetch(RelatedImageWidth)) {
|
||||||
|
uint16_t _RelatedImageWidth;
|
||||||
|
if (parser.Fetch(_RelatedImageWidth))
|
||||||
|
RelatedImageWidth = _RelatedImageWidth;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x1002:
|
||||||
|
// Original Image height
|
||||||
|
if (!parser.Fetch(RelatedImageHeight)) {
|
||||||
|
uint16_t _RelatedImageHeight;
|
||||||
|
if (parser.Fetch(_RelatedImageHeight))
|
||||||
|
RelatedImageHeight = _RelatedImageHeight;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x8298:
|
case 0x8298:
|
||||||
// Copyright information
|
// Copyright information
|
||||||
parser.Fetch(this->Copyright);
|
parser.Fetch(Copyright);
|
||||||
break;
|
|
||||||
|
|
||||||
case 0x8825:
|
|
||||||
// GPS IFS offset
|
|
||||||
gps_sub_ifd_offset = parser.FetchSubIFD();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x8769:
|
case 0x8769:
|
||||||
// EXIF SubIFD offset
|
// EXIF SubIFD offset
|
||||||
exif_sub_ifd_offset = parser.FetchSubIFD();
|
exif_sub_ifd_offset = parser.GetSubIFD();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x8825:
|
||||||
|
// GPS IFS offset
|
||||||
|
gps_sub_ifd_offset = parser.GetSubIFD();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xa405:
|
||||||
|
// Focal length in 35mm film
|
||||||
|
if (!parser.Fetch(LensInfo.FocalLengthIn35mm)) {
|
||||||
|
uint16_t _FocalLengthIn35mm;
|
||||||
|
if (parser.Fetch(_FocalLengthIn35mm))
|
||||||
|
LensInfo.FocalLengthIn35mm = (double)_FocalLengthIn35mm;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -502,123 +520,132 @@ int EXIFInfo::parseFromEXIFSegment(const uint8_t* buf, unsigned len) {
|
|||||||
switch (parser.ParseTag()) {
|
switch (parser.ParseTag()) {
|
||||||
case 0x829a:
|
case 0x829a:
|
||||||
// Exposure time in seconds
|
// Exposure time in seconds
|
||||||
parser.Fetch(this->ExposureTime);
|
parser.Fetch(ExposureTime);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x829d:
|
case 0x829d:
|
||||||
// FNumber
|
// FNumber
|
||||||
parser.Fetch(this->FNumber);
|
parser.Fetch(FNumber);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x8827:
|
case 0x8827:
|
||||||
// ISO Speed Rating
|
// ISO Speed Rating
|
||||||
parser.Fetch(this->ISOSpeedRatings);
|
parser.Fetch(ISOSpeedRatings);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x9003:
|
case 0x9003:
|
||||||
// Original date and time
|
// Original date and time
|
||||||
parser.Fetch(this->DateTimeOriginal);
|
parser.Fetch(DateTimeOriginal);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x9004:
|
case 0x9004:
|
||||||
// Digitization date and time
|
// Digitization date and time
|
||||||
parser.Fetch(this->DateTimeDigitized);
|
parser.Fetch(DateTimeDigitized);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x9201:
|
case 0x9201:
|
||||||
// Shutter speed value
|
// Shutter speed value
|
||||||
parser.Fetch(this->ShutterSpeedValue);
|
parser.Fetch(ShutterSpeedValue);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x9202:
|
||||||
|
// Aperture value
|
||||||
|
parser.Fetch(ApertureValue);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x9203:
|
||||||
|
// Brightness value
|
||||||
|
parser.Fetch(BrightnessValue);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x9204:
|
case 0x9204:
|
||||||
// Exposure bias value
|
// Exposure bias value
|
||||||
parser.Fetch(this->ExposureBiasValue);
|
parser.Fetch(ExposureBiasValue);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x9206:
|
case 0x9206:
|
||||||
// Subject distance
|
// Subject distance
|
||||||
parser.Fetch(this->SubjectDistance);
|
parser.Fetch(SubjectDistance);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x9209:
|
case 0x9209:
|
||||||
// Flash used
|
// Flash used
|
||||||
if (parser.GetFormat() == 3)
|
parser.Fetch(Flash);
|
||||||
this->Flash = parser.GetData() ? 1 : 0;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x920a:
|
case 0x920a:
|
||||||
// Focal length
|
// Focal length
|
||||||
parser.Fetch(this->FocalLength);
|
parser.Fetch(FocalLength);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x9207:
|
case 0x9207:
|
||||||
// Metering mode
|
// Metering mode
|
||||||
parser.Fetch(this->MeteringMode);
|
parser.Fetch(MeteringMode);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x9291:
|
case 0x9291:
|
||||||
// Subsecond original time
|
// Fractions of seconds for DateTimeOriginal
|
||||||
parser.Fetch(this->SubSecTimeOriginal);
|
parser.Fetch(SubSecTimeOriginal);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xa002:
|
case 0xa002:
|
||||||
// EXIF Image width
|
// EXIF Image width
|
||||||
if (!parser.Fetch(this->ImageWidth)) {
|
if (!parser.Fetch(ImageWidth)) {
|
||||||
uint16_t _ImageWidth;
|
uint16_t _ImageWidth;
|
||||||
if (parser.Fetch(_ImageWidth))
|
if (parser.Fetch(_ImageWidth))
|
||||||
this->ImageWidth = _ImageWidth;
|
ImageWidth = _ImageWidth;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xa003:
|
case 0xa003:
|
||||||
// EXIF Image height
|
// EXIF Image height
|
||||||
if (!parser.Fetch(this->ImageHeight)) {
|
if (!parser.Fetch(ImageHeight)) {
|
||||||
uint16_t _ImageHeight;
|
uint16_t _ImageHeight;
|
||||||
if (parser.Fetch(_ImageHeight))
|
if (parser.Fetch(_ImageHeight))
|
||||||
this->ImageHeight = _ImageHeight;
|
ImageHeight = _ImageHeight;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xa20e:
|
case 0xa20e:
|
||||||
// Focal plane X resolution
|
// Focal plane X resolution
|
||||||
parser.Fetch(this->LensInfo.FocalPlaneXResolution);
|
parser.Fetch(LensInfo.FocalPlaneXResolution);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xa20f:
|
case 0xa20f:
|
||||||
// Focal plane Y resolution
|
// Focal plane Y resolution
|
||||||
parser.Fetch(this->LensInfo.FocalPlaneYResolution);
|
parser.Fetch(LensInfo.FocalPlaneYResolution);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xa210:
|
case 0xa210:
|
||||||
// Focal plane resolution unit
|
// Focal plane resolution unit
|
||||||
parser.Fetch(this->LensInfo.FocalPlaneResolutionUnit);
|
parser.Fetch(LensInfo.FocalPlaneResolutionUnit);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xa405:
|
case 0xa405:
|
||||||
// Focal length in 35mm film
|
// Focal length in 35mm film
|
||||||
if (!parser.Fetch(this->LensInfo.FocalLengthIn35mm)) {
|
if (!parser.Fetch(LensInfo.FocalLengthIn35mm)) {
|
||||||
uint16_t FocalLengthIn35mm;
|
uint16_t _FocalLengthIn35mm;
|
||||||
if (parser.Fetch(FocalLengthIn35mm))
|
if (parser.Fetch(_FocalLengthIn35mm))
|
||||||
this->LensInfo.FocalLengthIn35mm = (double)FocalLengthIn35mm;
|
LensInfo.FocalLengthIn35mm = (double)_FocalLengthIn35mm;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xa432:
|
case 0xa432:
|
||||||
// Focal length and FStop.
|
// Focal length and FStop.
|
||||||
if (parser.Fetch(this->LensInfo.FocalLengthMin, 0))
|
if (parser.Fetch(LensInfo.FocalLengthMin, 0))
|
||||||
if (parser.Fetch(this->LensInfo.FocalLengthMax, 1))
|
if (parser.Fetch(LensInfo.FocalLengthMax, 1))
|
||||||
if (parser.Fetch(this->LensInfo.FStopMin, 2))
|
if (parser.Fetch(LensInfo.FStopMin, 2))
|
||||||
parser.Fetch(this->LensInfo.FStopMax, 3);
|
parser.Fetch(LensInfo.FStopMax, 3);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xa433:
|
case 0xa433:
|
||||||
// Lens make.
|
// Lens make.
|
||||||
parser.Fetch(this->LensInfo.Make);
|
parser.Fetch(LensInfo.Make);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xa434:
|
case 0xa434:
|
||||||
// Lens model.
|
// Lens model.
|
||||||
parser.Fetch(this->LensInfo.Model);
|
parser.Fetch(LensInfo.Model);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -636,77 +663,77 @@ int EXIFInfo::parseFromEXIFSegment(const uint8_t* buf, unsigned len) {
|
|||||||
switch (parser.ParseTag()) {
|
switch (parser.ParseTag()) {
|
||||||
case 1:
|
case 1:
|
||||||
// GPS north or south
|
// GPS north or south
|
||||||
parser.Fetch(this->GeoLocation.LatComponents.direction);
|
parser.Fetch(GeoLocation.LatComponents.direction);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
// GPS latitude
|
// GPS latitude
|
||||||
if (parser.GetFormat() == 5 && parser.GetLength() == 3) {
|
if (parser.IsRational() && parser.GetLength() == 3) {
|
||||||
parser.Fetch(this->GeoLocation.LatComponents.degrees, 0);
|
parser.Fetch(GeoLocation.LatComponents.degrees, 0);
|
||||||
parser.Fetch(this->GeoLocation.LatComponents.minutes, 1);
|
parser.Fetch(GeoLocation.LatComponents.minutes, 1);
|
||||||
parser.Fetch(this->GeoLocation.LatComponents.seconds, 2);
|
parser.Fetch(GeoLocation.LatComponents.seconds, 2);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
// GPS east or west
|
// GPS east or west
|
||||||
parser.Fetch(this->GeoLocation.LonComponents.direction);
|
parser.Fetch(GeoLocation.LonComponents.direction);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
// GPS longitude
|
// GPS longitude
|
||||||
if (parser.GetFormat() == 5 && parser.GetLength() == 3) {
|
if (parser.IsRational() && parser.GetLength() == 3) {
|
||||||
parser.Fetch(this->GeoLocation.LonComponents.degrees, 0);
|
parser.Fetch(GeoLocation.LonComponents.degrees, 0);
|
||||||
parser.Fetch(this->GeoLocation.LonComponents.minutes, 1);
|
parser.Fetch(GeoLocation.LonComponents.minutes, 1);
|
||||||
parser.Fetch(this->GeoLocation.LonComponents.seconds, 2);
|
parser.Fetch(GeoLocation.LonComponents.seconds, 2);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 5:
|
case 5:
|
||||||
// GPS altitude reference (below or above sea level)
|
// GPS altitude reference (below or above sea level)
|
||||||
parser.Fetch(this->GeoLocation.AltitudeRef);
|
parser.Fetch((uint8_t&)GeoLocation.AltitudeRef);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 6:
|
case 6:
|
||||||
// GPS altitude
|
// GPS altitude
|
||||||
parser.Fetch(this->GeoLocation.Altitude);
|
parser.Fetch(GeoLocation.Altitude);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 7:
|
case 7:
|
||||||
// GPS timestamp
|
// GPS timestamp
|
||||||
if (parser.GetFormat() == 5 && parser.GetLength() == 3) {
|
if (parser.IsRational() && parser.GetLength() == 3) {
|
||||||
double h,m,s;
|
double h,m,s;
|
||||||
parser.Fetch(h, 0);
|
parser.Fetch(h, 0);
|
||||||
parser.Fetch(m, 1);
|
parser.Fetch(m, 1);
|
||||||
parser.Fetch(s, 2);
|
parser.Fetch(s, 2);
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
snprintf(buffer, 256, "%g %g %g", h, m, s);
|
snprintf(buffer, 256, "%g %g %g", h, m, s);
|
||||||
this->GeoLocation.GPSTimeStamp = buffer;
|
GeoLocation.GPSTimeStamp = buffer;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 11:
|
case 11:
|
||||||
// Indicates the GPS DOP (data degree of precision)
|
// Indicates the GPS DOP (data degree of precision)
|
||||||
parser.Fetch(this->GeoLocation.GPSDOP);
|
parser.Fetch(GeoLocation.GPSDOP);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 18:
|
case 18:
|
||||||
// GPS geodetic survey data
|
// GPS geodetic survey data
|
||||||
parser.Fetch(this->GeoLocation.GPSMapDatum);
|
parser.Fetch(GeoLocation.GPSMapDatum);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 29:
|
case 29:
|
||||||
// GPS date-stamp
|
// GPS date-stamp
|
||||||
parser.Fetch(this->GeoLocation.GPSDateStamp);
|
parser.Fetch(GeoLocation.GPSDateStamp);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 30:
|
case 30:
|
||||||
// GPS differential indicates whether differential correction is applied to the GPS receiver
|
// GPS differential indicates whether differential correction is applied to the GPS receiver
|
||||||
parser.Fetch(this->GeoLocation.GPSDifferential);
|
parser.Fetch(GeoLocation.GPSDifferential);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this->GeoLocation.parseCoords();
|
GeoLocation.parseCoords();
|
||||||
}
|
}
|
||||||
|
|
||||||
return PARSE_EXIF_SUCCESS;
|
return PARSE_EXIF_SUCCESS;
|
||||||
@@ -759,21 +786,21 @@ int EXIFInfo::parseFromXMPSegment(const uint8_t* buf, unsigned len) {
|
|||||||
tinyxml2::XMLDocument doc;
|
tinyxml2::XMLDocument doc;
|
||||||
const tinyxml2::XMLElement* document;
|
const tinyxml2::XMLElement* document;
|
||||||
if (doc.Parse(strXMP, len) != tinyxml2::XML_SUCCESS ||
|
if (doc.Parse(strXMP, len) != tinyxml2::XML_SUCCESS ||
|
||||||
((document=doc.FirstChildElement("x:xmpmeta")) == NULL && (document=doc.FirstChildElement("xmp:xmpmeta")) == NULL) ||
|
((document=doc.FirstChildElement(_T("x:xmpmeta"))) == NULL && (document=doc.FirstChildElement(_T("xmp:xmpmeta"))) == NULL) ||
|
||||||
(document=document->FirstChildElement("rdf:RDF")) == NULL ||
|
(document=document->FirstChildElement(_T("rdf:RDF"))) == NULL ||
|
||||||
(document=document->FirstChildElement("rdf:Description")) == NULL)
|
(document=document->FirstChildElement(_T("rdf:Description"))) == NULL)
|
||||||
return PARSE_EXIF_SUCCESS;
|
return PARSE_EXIF_SUCCESS;
|
||||||
|
|
||||||
// Now try parsing the XMP content for projection type.
|
// Now try parsing the XMP content for projection type.
|
||||||
{
|
{
|
||||||
const tinyxml2::XMLElement* const element(document->FirstChildElement("GPano:ProjectionType"));
|
const tinyxml2::XMLElement* const element(document->FirstChildElement(_T("GPano:ProjectionType")));
|
||||||
if (element != NULL) {
|
if (element != NULL) {
|
||||||
const char* const szProjectionType(element->GetText());
|
const char* const szProjectionType(element->GetText());
|
||||||
if (szProjectionType != NULL) {
|
if (szProjectionType != NULL) {
|
||||||
if (0 == _tcsicmp(szProjectionType, "perspective"))
|
if (0 == _tcsicmp(szProjectionType, _T("perspective")))
|
||||||
ProjectionType = 1;
|
ProjectionType = 1;
|
||||||
else if (0 == _tcsicmp(szProjectionType, "equirectangular") ||
|
else if (0 == _tcsicmp(szProjectionType, _T("equirectangular")) ||
|
||||||
0 == _tcsicmp(szProjectionType, "spherical"))
|
0 == _tcsicmp(szProjectionType, _T("spherical")))
|
||||||
ProjectionType = 2;
|
ProjectionType = 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -848,20 +875,24 @@ void EXIFInfo::clear() {
|
|||||||
|
|
||||||
// Shorts / unsigned / double
|
// Shorts / unsigned / double
|
||||||
ByteAlign = 0;
|
ByteAlign = 0;
|
||||||
|
ImageWidth = 0;
|
||||||
|
ImageHeight = 0;
|
||||||
|
RelatedImageWidth = 0;
|
||||||
|
RelatedImageHeight= 0;
|
||||||
Orientation = 0;
|
Orientation = 0;
|
||||||
BitsPerSample = 0;
|
BitsPerSample = 0;
|
||||||
ExposureTime = 0;
|
ExposureTime = 0;
|
||||||
FNumber = 0;
|
FNumber = 0;
|
||||||
ISOSpeedRatings = 0;
|
ISOSpeedRatings = 0;
|
||||||
ShutterSpeedValue = 0;
|
ShutterSpeedValue = 0;
|
||||||
|
ApertureValue = 0;
|
||||||
|
BrightnessValue = 0;
|
||||||
ExposureBiasValue = 0;
|
ExposureBiasValue = 0;
|
||||||
SubjectDistance = 0;
|
SubjectDistance = 0;
|
||||||
FocalLength = 0;
|
FocalLength = 0;
|
||||||
Flash = 0;
|
Flash = 0;
|
||||||
MeteringMode = 0;
|
MeteringMode = 0;
|
||||||
ProjectionType = 0;
|
ProjectionType = 0;
|
||||||
ImageWidth = 0;
|
|
||||||
ImageHeight = 0;
|
|
||||||
|
|
||||||
// LensInfo
|
// LensInfo
|
||||||
LensInfo.FocalLengthMax = 0;
|
LensInfo.FocalLengthMax = 0;
|
||||||
|
|||||||
16
TinyEXIF.h
16
TinyEXIF.h
@@ -94,7 +94,11 @@ public:
|
|||||||
bool alignIntel() const { return this->ByteAlign != 0; }
|
bool alignIntel() const { return this->ByteAlign != 0; }
|
||||||
|
|
||||||
// Data fields filled out by parseFrom()
|
// Data fields filled out by parseFrom()
|
||||||
int8_t ByteAlign; // 0 = Motorola byte alignment, 1 = Intel
|
uint8_t ByteAlign; // 0: Motorola byte alignment, 1: Intel
|
||||||
|
uint32_t ImageWidth; // Image width 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 RelatedImageHeight; // Original image height reported in EXIF data
|
||||||
std::string ImageDescription; // Image description
|
std::string ImageDescription; // Image description
|
||||||
std::string Make; // Camera manufacturer's name
|
std::string Make; // Camera manufacturer's name
|
||||||
std::string Model; // Camera model
|
std::string Model; // Camera model
|
||||||
@@ -122,10 +126,12 @@ public:
|
|||||||
double FNumber; // F/stop
|
double FNumber; // F/stop
|
||||||
uint16_t ISOSpeedRatings; // ISO speed
|
uint16_t ISOSpeedRatings; // ISO speed
|
||||||
double ShutterSpeedValue; // Shutter speed (reciprocal of exposure time)
|
double ShutterSpeedValue; // Shutter speed (reciprocal of exposure time)
|
||||||
|
double ApertureValue; // The lens aperture
|
||||||
|
double BrightnessValue; // The value of brightness
|
||||||
double ExposureBiasValue; // Exposure bias value in EV
|
double ExposureBiasValue; // Exposure bias value in EV
|
||||||
double SubjectDistance; // Distance to focus point in meters
|
double SubjectDistance; // Distance to focus point in meters
|
||||||
double FocalLength; // Focal length of lens in millimeters
|
double FocalLength; // Focal length of lens in millimeters
|
||||||
int8_t Flash; // 0 = no flash, 1 = flash used
|
uint16_t Flash; // 0: no flash, >0: flash used
|
||||||
uint16_t MeteringMode; // Metering mode
|
uint16_t MeteringMode; // Metering mode
|
||||||
// 1: average
|
// 1: average
|
||||||
// 2: center weighted average
|
// 2: center weighted average
|
||||||
@@ -136,8 +142,6 @@ public:
|
|||||||
// 0: unknown projection
|
// 0: unknown projection
|
||||||
// 1: perspective projection
|
// 1: perspective projection
|
||||||
// 2: equirectangular/spherical 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
|
struct LensInfo_t { // Lens information
|
||||||
double FStopMin; // Min aperture (f-stop)
|
double FStopMin; // Min aperture (f-stop)
|
||||||
double FStopMax; // Max aperture (f-stop)
|
double FStopMax; // Max aperture (f-stop)
|
||||||
@@ -158,7 +162,7 @@ public:
|
|||||||
double Latitude; // Image latitude expressed as decimal
|
double Latitude; // Image latitude expressed as decimal
|
||||||
double Longitude; // Image longitude expressed as decimal
|
double Longitude; // Image longitude expressed as decimal
|
||||||
double Altitude; // Altitude in meters, relative to sea level
|
double Altitude; // Altitude in meters, relative to sea level
|
||||||
int8_t AltitudeRef; // 0 = above sea level, -1 = below sea level
|
int8_t AltitudeRef; // 0: above sea level, -1: below sea level
|
||||||
double RelativeAltitude; // Relative altitude in meters
|
double RelativeAltitude; // Relative altitude in meters
|
||||||
double RollDegree; // Flight roll in degrees
|
double RollDegree; // Flight roll in degrees
|
||||||
double PitchDegree; // Flight pitch in degrees
|
double PitchDegree; // Flight pitch in degrees
|
||||||
@@ -174,7 +178,7 @@ public:
|
|||||||
double degrees;
|
double degrees;
|
||||||
double minutes;
|
double minutes;
|
||||||
double seconds;
|
double seconds;
|
||||||
int8_t direction;
|
uint8_t direction;
|
||||||
} LatComponents, LonComponents; // Latitude/Longitude expressed in deg/min/sec
|
} LatComponents, LonComponents; // Latitude/Longitude expressed in deg/min/sec
|
||||||
void parseCoords(); // Convert Latitude/Longitude from deg/min/sec to decimal
|
void parseCoords(); // Convert Latitude/Longitude from deg/min/sec to decimal
|
||||||
bool hasLatLon() const; // Return true if (lat,lon) is available
|
bool hasLatLon() const; // Return true if (lat,lon) is available
|
||||||
|
|||||||
Reference in New Issue
Block a user