Using std::variant, changed EndianSwap, new function StringFromTime, minor tweaks
This commit is contained in:
@@ -9,7 +9,6 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <bit>
|
#include <bit>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <ctime>
|
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@@ -60,23 +59,13 @@ namespace
|
|||||||
RATIONAL = 5,
|
RATIONAL = 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t EndianSwap(uint32_t value)
|
template<typename T>
|
||||||
|
T EndianSwap(T value)
|
||||||
{
|
{
|
||||||
uint32_t result;
|
T result;
|
||||||
|
|
||||||
char *ptr = (char *) &value;
|
char* ptr = reinterpret_cast<char*>(&value);
|
||||||
std::reverse(ptr, ptr + 4);
|
std::reverse(ptr, ptr + sizeof(T));
|
||||||
result = value;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t EndianSwap(uint16_t value)
|
|
||||||
{
|
|
||||||
uint16_t result;
|
|
||||||
|
|
||||||
char *ptr = (char *) &value;
|
|
||||||
std::reverse(ptr, ptr + 2);
|
|
||||||
result = value;
|
result = value;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -247,6 +236,26 @@ namespace
|
|||||||
int offset = AppendU32NES(array, initialOffsetValue);
|
int offset = AppendU32NES(array, initialOffsetValue);
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char CoordRefToChar(const std::variant<OpenVulkano::Image::LatitudeRef, OpenVulkano::Image::LongitudeRef>& ref)
|
||||||
|
{
|
||||||
|
char c = 0;
|
||||||
|
if (std::holds_alternative<OpenVulkano::Image::LatitudeRef>(ref))
|
||||||
|
{
|
||||||
|
auto lat = std::get<OpenVulkano::Image::LatitudeRef>(ref);
|
||||||
|
c = (lat == OpenVulkano::Image::LatitudeRef::NORTH ? 'N' : 'S');
|
||||||
|
}
|
||||||
|
else if (std::holds_alternative<OpenVulkano::Image::LongitudeRef>(ref))
|
||||||
|
{
|
||||||
|
auto lon = std::get<OpenVulkano::Image::LongitudeRef>(ref);
|
||||||
|
c = (lon == OpenVulkano::Image::LongitudeRef::EAST ? 'E' : 'W');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("An alternative does not contain neither LatitudeRef nor LongitudeRef!");
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace OpenVulkano::Image
|
namespace OpenVulkano::Image
|
||||||
@@ -263,45 +272,35 @@ namespace OpenVulkano::Image
|
|||||||
|
|
||||||
if (isLatitude)
|
if (isLatitude)
|
||||||
{
|
{
|
||||||
if (decimalDegrees < 0)
|
ref = (decimalDegrees < 0) ? LatitudeRef::SOUTH : LatitudeRef::NORTH;
|
||||||
{
|
|
||||||
latitudeRef = LatitudeRef::SOUTH;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
latitudeRef = LatitudeRef::NORTH;
|
ref = (decimalDegrees < 0) ? LongitudeRef::WEST : LongitudeRef::EAST;
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (decimalDegrees < 0)
|
|
||||||
{
|
|
||||||
longitudeRef = LongitudeRef::WEST;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
longitudeRef = LongitudeRef::EAST;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
degrees = std::abs(degrees);
|
degrees = std::abs(degrees);
|
||||||
}
|
}
|
||||||
|
|
||||||
GPSCoords::GPSCoords(int32_t degrees, int32_t minutes, int32_t seconds)
|
GPSCoords::GPSCoords(int32_t degrees, int32_t minutes, int32_t seconds, LatitudeRef ref)
|
||||||
|
: degrees(degrees), minutes(minutes), seconds(seconds), ref(ref)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
GPSCoords::GPSCoords(int32_t degrees, int32_t minutes, int32_t seconds, LongitudeRef ref)
|
||||||
|
: degrees(degrees), minutes(minutes), seconds(seconds), ref(ref)
|
||||||
{
|
{
|
||||||
this->degrees = degrees;
|
|
||||||
this->minutes = minutes;
|
|
||||||
this->seconds = seconds;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExifBuilder::SetAltitude(float level)
|
void ExifBuilder::SetAltitude(float level)
|
||||||
{
|
{
|
||||||
altitudeIsAboveSeaLevel = level >= 0;
|
altitudeIsAboveSeaLevel = level >= 0;
|
||||||
if (level < 0)
|
altitude = std::abs(level);
|
||||||
{
|
|
||||||
level = -level;
|
|
||||||
}
|
}
|
||||||
altitude = level;
|
|
||||||
|
void ExifBuilder::SetTime(std::time_t timestamp)
|
||||||
|
{
|
||||||
|
dateTaken = StringFromTime(timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> ExifBuilder::Build()
|
std::vector<uint8_t> ExifBuilder::Build()
|
||||||
@@ -334,67 +333,54 @@ namespace OpenVulkano::Image
|
|||||||
std::vector<int> offsets;
|
std::vector<int> offsets;
|
||||||
int gpsInfoOffset = 0;
|
int gpsInfoOffset = 0;
|
||||||
|
|
||||||
// Make
|
|
||||||
if (!make.empty())
|
if (!make.empty())
|
||||||
{
|
{
|
||||||
offsets.push_back(AppendTagValueTypeAndString(result, IFDTag::MAKE, data, make));
|
offsets.push_back(AppendTagValueTypeAndString(result, IFDTag::MAKE, data, make));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Model
|
|
||||||
if (!model.empty())
|
if (!model.empty())
|
||||||
{
|
{
|
||||||
offsets.push_back(AppendTagValueTypeAndString(result, IFDTag::MODEL, data, model));
|
offsets.push_back(AppendTagValueTypeAndString(result, IFDTag::MODEL, data, model));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Orientation
|
|
||||||
if (orientation != 0)
|
if (orientation != 0)
|
||||||
{
|
{
|
||||||
AppendTagValueTypeAndShort(result, IFDTag::ORIENTATION, orientation);
|
AppendTagValueTypeAndShort(result, IFDTag::ORIENTATION, orientation);
|
||||||
}
|
}
|
||||||
|
|
||||||
// xResolution
|
|
||||||
if (xResolution.nominator || xResolution.denominator)
|
if (xResolution.nominator || xResolution.denominator)
|
||||||
{
|
{
|
||||||
offsets.push_back(AppendTagValueTypeAndRational(result, IFDTag::X_RESOLUTION, data, xResolution));
|
offsets.push_back(AppendTagValueTypeAndRational(result, IFDTag::X_RESOLUTION, data, xResolution));
|
||||||
}
|
}
|
||||||
|
|
||||||
// yResolution
|
|
||||||
if (yResolution.nominator || yResolution.denominator)
|
if (yResolution.nominator || yResolution.denominator)
|
||||||
{
|
{
|
||||||
offsets.push_back(AppendTagValueTypeAndRational(result, IFDTag::Y_RESOLUTION, data, yResolution));
|
offsets.push_back(AppendTagValueTypeAndRational(result, IFDTag::Y_RESOLUTION, data, yResolution));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exposure Time
|
|
||||||
if (exposureTime.nominator || exposureTime.denominator)
|
if (exposureTime.nominator || exposureTime.denominator)
|
||||||
{
|
{
|
||||||
offsets.push_back(AppendTagValueTypeAndRational(result, IFDTag::EXPOSURE_TIME, data, exposureTime));
|
offsets.push_back(AppendTagValueTypeAndRational(result, IFDTag::EXPOSURE_TIME, data, exposureTime));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResolutionUnit
|
|
||||||
if (resolutionUnit != 0)
|
if (resolutionUnit != 0)
|
||||||
{
|
{
|
||||||
AppendTagValueTypeAndShort(result, IFDTag::RESOLUTION_UNIT, resolutionUnit);
|
AppendTagValueTypeAndShort(result, IFDTag::RESOLUTION_UNIT, resolutionUnit);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Software Used
|
|
||||||
if (!softwareUsed.empty())
|
if (!softwareUsed.empty())
|
||||||
{
|
{
|
||||||
offsets.push_back(AppendTagValueTypeAndString(result, IFDTag::SOFTWARE_USED, data, softwareUsed));
|
offsets.push_back(AppendTagValueTypeAndString(result, IFDTag::SOFTWARE_USED, data, softwareUsed));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Date Taken
|
|
||||||
// NOTE(vb): For some reason windows file properties doesn't print date taken field!
|
// NOTE(vb): For some reason windows file properties doesn't print date taken field!
|
||||||
// Even though other software does provide this information without a problem
|
// Even though other software does provide this information without a problem
|
||||||
{
|
|
||||||
offsets.push_back(AppendTagValueTypeAndString(result, IFDTag::DATE_TAKEN, data, dateTaken));
|
offsets.push_back(AppendTagValueTypeAndString(result, IFDTag::DATE_TAKEN, data, dateTaken));
|
||||||
}
|
|
||||||
|
|
||||||
// GPS Info offset
|
// GPS Info offset
|
||||||
{
|
|
||||||
AppendTagAndValueType(result, (uint16_t) IFDTag::GPS_INFO_OFFSET, (uint16_t) IFDValueType::LONG_);
|
AppendTagAndValueType(result, (uint16_t) IFDTag::GPS_INFO_OFFSET, (uint16_t) IFDValueType::LONG_);
|
||||||
AppendU32(result, 1); // num components
|
AppendU32(result, 1); // num components
|
||||||
gpsInfoOffset = AppendU32(result, 0);
|
gpsInfoOffset = AppendU32(result, 0);
|
||||||
}
|
|
||||||
|
|
||||||
// next ifd offset
|
// next ifd offset
|
||||||
AppendU32(result, 0);
|
AppendU32(result, 0);
|
||||||
@@ -424,13 +410,15 @@ namespace OpenVulkano::Image
|
|||||||
offsets.resize(0);
|
offsets.resize(0);
|
||||||
|
|
||||||
// Latitude Ref
|
// Latitude Ref
|
||||||
AppendTagValueTypeAndByte(result, IFDGPSTag::LATITUDE_REF, IFDValueType::ASCII, (latitude.latitudeRef == LatitudeRef::NORTH) ? 'N' : 'S');
|
char latitudeRef = CoordRefToChar(latitude.ref);
|
||||||
|
AppendTagValueTypeAndByte(result, IFDGPSTag::LATITUDE_REF, IFDValueType::ASCII, latitudeRef);
|
||||||
|
|
||||||
// Latitude
|
// Latitude
|
||||||
offsets.push_back(AppendTagValueTypeAndGPSRational(result, IFDGPSTag::LATITUDE, 3, 0)); // 0 * sizeof(RationalValue)
|
offsets.push_back(AppendTagValueTypeAndGPSRational(result, IFDGPSTag::LATITUDE, 3, 0)); // 0 * sizeof(RationalValue)
|
||||||
|
|
||||||
// Longitude Ref
|
// Longitude Ref
|
||||||
AppendTagValueTypeAndByte(result, IFDGPSTag::LONGITUDE_REF, IFDValueType::ASCII, (longitude.longitudeRef == LongitudeRef::EAST) ? 'E' : 'W');
|
char longitudeRef = CoordRefToChar(longitude.ref);
|
||||||
|
AppendTagValueTypeAndByte(result, IFDGPSTag::LONGITUDE_REF, IFDValueType::ASCII, longitudeRef);
|
||||||
|
|
||||||
// Longitude
|
// Longitude
|
||||||
offsets.push_back(AppendTagValueTypeAndGPSRational(result, IFDGPSTag::LONGITUDE, 3, 24)); // 3 * sizeof(RationalValue)
|
offsets.push_back(AppendTagValueTypeAndGPSRational(result, IFDGPSTag::LONGITUDE, 3, 24)); // 3 * sizeof(RationalValue)
|
||||||
@@ -466,20 +454,25 @@ namespace OpenVulkano::Image
|
|||||||
AppendU32(result, altitude);
|
AppendU32(result, altitude);
|
||||||
AppendU32(result, 1); // denominator for altitude
|
AppendU32(result, 1); // denominator for altitude
|
||||||
|
|
||||||
const int TRACK_PRECISION = 10000;
|
constexpr int TRACK_PRECISION = 10000;
|
||||||
AppendU32(result, track * TRACK_PRECISION);
|
AppendU32(result, track * TRACK_PRECISION);
|
||||||
AppendU32(result, TRACK_PRECISION);
|
AppendU32(result, TRACK_PRECISION);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ExifBuilder::GetCurrentTimestamp()
|
std::string ExifBuilder::StringFromTime(std::time_t time)
|
||||||
{
|
{
|
||||||
auto now = std::chrono::system_clock::now();
|
std::tm* timeInfo = std::localtime(&time);
|
||||||
std::time_t currentTime = std::chrono::system_clock::to_time_t(now);
|
|
||||||
std::tm* timeInfo = std::localtime(¤tTime);
|
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << std::put_time(timeInfo, "%Y:%m:%d %H:%M:%S");
|
oss << std::put_time(timeInfo, "%Y:%m:%d %H:%M:%S");
|
||||||
return oss.str();
|
return oss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string ExifBuilder::GetCurrentTimestamp()
|
||||||
|
{
|
||||||
|
auto now = std::chrono::system_clock::now();
|
||||||
|
std::time_t currentTime = std::chrono::system_clock::to_time_t(now);
|
||||||
|
return StringFromTime(currentTime);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,8 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <ctime>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
namespace OpenVulkano::Image
|
namespace OpenVulkano::Image
|
||||||
{
|
{
|
||||||
@@ -36,11 +38,11 @@ namespace OpenVulkano::Image
|
|||||||
struct GPSCoords
|
struct GPSCoords
|
||||||
{
|
{
|
||||||
int32_t degrees, minutes, seconds;
|
int32_t degrees, minutes, seconds;
|
||||||
LatitudeRef latitudeRef = LatitudeRef::NORTH;
|
std::variant<LatitudeRef, LongitudeRef> ref;
|
||||||
LongitudeRef longitudeRef = LongitudeRef::EAST;
|
|
||||||
|
|
||||||
GPSCoords(float decimalDegrees, bool isLatitude);
|
GPSCoords(float decimalDegrees, bool isLatitude);
|
||||||
GPSCoords(int32_t degrees, int32_t minutes, int32_t seconds);
|
GPSCoords(int32_t degrees, int32_t minutes, int32_t seconds, LatitudeRef ref);
|
||||||
|
GPSCoords(int32_t degrees, int32_t minutes, int32_t seconds, LongitudeRef ref);
|
||||||
};
|
};
|
||||||
|
|
||||||
class ExifBuilder
|
class ExifBuilder
|
||||||
@@ -56,8 +58,8 @@ namespace OpenVulkano::Image
|
|||||||
std::string dateTaken; // format: yyyy:mm:dd hh:mm:ss
|
std::string dateTaken; // format: yyyy:mm:dd hh:mm:ss
|
||||||
std::string softwareUsed = "OpenVulkano";
|
std::string softwareUsed = "OpenVulkano";
|
||||||
|
|
||||||
GPSCoords latitude = { 0, 0, 0 };
|
GPSCoords latitude = { 0, 0, 0, LatitudeRef::NORTH };
|
||||||
GPSCoords longitude = { 0, 0, 0 };
|
GPSCoords longitude = { 0, 0, 0, LongitudeRef::EAST };
|
||||||
|
|
||||||
bool altitudeIsAboveSeaLevel = true;
|
bool altitudeIsAboveSeaLevel = true;
|
||||||
uint32_t altitude = 0;
|
uint32_t altitude = 0;
|
||||||
@@ -67,8 +69,10 @@ namespace OpenVulkano::Image
|
|||||||
|
|
||||||
|
|
||||||
void SetAltitude(float level);
|
void SetAltitude(float level);
|
||||||
|
void SetTime(std::time_t timestamp);
|
||||||
// Typical usage is -> jpeg_write_marker(cinfo, JPEG_APP0 + 1, exif_data.data(), exif_data.size());
|
// Typical usage is -> jpeg_write_marker(cinfo, JPEG_APP0 + 1, exif_data.data(), exif_data.size());
|
||||||
std::vector<uint8_t> Build();
|
[[nodiscard]] std::vector<uint8_t> Build();
|
||||||
static std::string GetCurrentTimestamp();
|
[[nodiscard]] static std::string StringFromTime(std::time_t time);
|
||||||
|
[[nodiscard]] static std::string GetCurrentTimestamp();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user