Using std::variant, changed EndianSwap, new function StringFromTime, minor tweaks
This commit is contained in:
@@ -9,7 +9,6 @@
|
||||
#include <algorithm>
|
||||
#include <bit>
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <iterator>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
@@ -60,23 +59,13 @@ namespace
|
||||
RATIONAL = 5,
|
||||
};
|
||||
|
||||
uint32_t EndianSwap(uint32_t value)
|
||||
template<typename T>
|
||||
T EndianSwap(T value)
|
||||
{
|
||||
uint32_t result;
|
||||
T result;
|
||||
|
||||
char *ptr = (char *) &value;
|
||||
std::reverse(ptr, ptr + 4);
|
||||
result = value;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint16_t EndianSwap(uint16_t value)
|
||||
{
|
||||
uint16_t result;
|
||||
|
||||
char *ptr = (char *) &value;
|
||||
std::reverse(ptr, ptr + 2);
|
||||
char* ptr = reinterpret_cast<char*>(&value);
|
||||
std::reverse(ptr, ptr + sizeof(T));
|
||||
result = value;
|
||||
|
||||
return result;
|
||||
@@ -247,6 +236,26 @@ namespace
|
||||
int offset = AppendU32NES(array, initialOffsetValue);
|
||||
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
|
||||
@@ -263,45 +272,35 @@ namespace OpenVulkano::Image
|
||||
|
||||
if (isLatitude)
|
||||
{
|
||||
if (decimalDegrees < 0)
|
||||
{
|
||||
latitudeRef = LatitudeRef::SOUTH;
|
||||
ref = (decimalDegrees < 0) ? LatitudeRef::SOUTH : LatitudeRef::NORTH;
|
||||
}
|
||||
else
|
||||
{
|
||||
latitudeRef = LatitudeRef::NORTH;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (decimalDegrees < 0)
|
||||
{
|
||||
longitudeRef = LongitudeRef::WEST;
|
||||
}
|
||||
else
|
||||
{
|
||||
longitudeRef = LongitudeRef::EAST;
|
||||
}
|
||||
ref = (decimalDegrees < 0) ? LongitudeRef::WEST : LongitudeRef::EAST;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
altitudeIsAboveSeaLevel = level >= 0;
|
||||
if (level < 0)
|
||||
{
|
||||
level = -level;
|
||||
altitude = std::abs(level);
|
||||
}
|
||||
altitude = level;
|
||||
|
||||
void ExifBuilder::SetTime(std::time_t timestamp)
|
||||
{
|
||||
dateTaken = StringFromTime(timestamp);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> ExifBuilder::Build()
|
||||
@@ -334,67 +333,54 @@ namespace OpenVulkano::Image
|
||||
std::vector<int> offsets;
|
||||
int gpsInfoOffset = 0;
|
||||
|
||||
// Make
|
||||
if (!make.empty())
|
||||
{
|
||||
offsets.push_back(AppendTagValueTypeAndString(result, IFDTag::MAKE, data, make));
|
||||
}
|
||||
|
||||
// Model
|
||||
if (!model.empty())
|
||||
{
|
||||
offsets.push_back(AppendTagValueTypeAndString(result, IFDTag::MODEL, data, model));
|
||||
}
|
||||
|
||||
// Orientation
|
||||
if (orientation != 0)
|
||||
{
|
||||
AppendTagValueTypeAndShort(result, IFDTag::ORIENTATION, orientation);
|
||||
}
|
||||
|
||||
// xResolution
|
||||
if (xResolution.nominator || xResolution.denominator)
|
||||
{
|
||||
offsets.push_back(AppendTagValueTypeAndRational(result, IFDTag::X_RESOLUTION, data, xResolution));
|
||||
}
|
||||
|
||||
// yResolution
|
||||
if (yResolution.nominator || yResolution.denominator)
|
||||
{
|
||||
offsets.push_back(AppendTagValueTypeAndRational(result, IFDTag::Y_RESOLUTION, data, yResolution));
|
||||
}
|
||||
|
||||
// Exposure Time
|
||||
if (exposureTime.nominator || exposureTime.denominator)
|
||||
{
|
||||
offsets.push_back(AppendTagValueTypeAndRational(result, IFDTag::EXPOSURE_TIME, data, exposureTime));
|
||||
}
|
||||
|
||||
// ResolutionUnit
|
||||
if (resolutionUnit != 0)
|
||||
{
|
||||
AppendTagValueTypeAndShort(result, IFDTag::RESOLUTION_UNIT, resolutionUnit);
|
||||
}
|
||||
|
||||
// Software Used
|
||||
if (!softwareUsed.empty())
|
||||
{
|
||||
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!
|
||||
// Even though other software does provide this information without a problem
|
||||
{
|
||||
offsets.push_back(AppendTagValueTypeAndString(result, IFDTag::DATE_TAKEN, data, dateTaken));
|
||||
}
|
||||
|
||||
// GPS Info offset
|
||||
{
|
||||
AppendTagAndValueType(result, (uint16_t) IFDTag::GPS_INFO_OFFSET, (uint16_t) IFDValueType::LONG_);
|
||||
AppendU32(result, 1); // num components
|
||||
gpsInfoOffset = AppendU32(result, 0);
|
||||
}
|
||||
|
||||
// next ifd offset
|
||||
AppendU32(result, 0);
|
||||
@@ -424,13 +410,15 @@ namespace OpenVulkano::Image
|
||||
offsets.resize(0);
|
||||
|
||||
// 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
|
||||
offsets.push_back(AppendTagValueTypeAndGPSRational(result, IFDGPSTag::LATITUDE, 3, 0)); // 0 * sizeof(RationalValue)
|
||||
|
||||
// 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
|
||||
offsets.push_back(AppendTagValueTypeAndGPSRational(result, IFDGPSTag::LONGITUDE, 3, 24)); // 3 * sizeof(RationalValue)
|
||||
@@ -466,20 +454,25 @@ namespace OpenVulkano::Image
|
||||
AppendU32(result, 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_PRECISION);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string ExifBuilder::GetCurrentTimestamp()
|
||||
std::string ExifBuilder::StringFromTime(std::time_t time)
|
||||
{
|
||||
auto now = std::chrono::system_clock::now();
|
||||
std::time_t currentTime = std::chrono::system_clock::to_time_t(now);
|
||||
std::tm* timeInfo = std::localtime(¤tTime);
|
||||
std::tm* timeInfo = std::localtime(&time);
|
||||
std::ostringstream oss;
|
||||
oss << std::put_time(timeInfo, "%Y:%m:%d %H:%M:%S");
|
||||
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 <string>
|
||||
#include <stdint.h>
|
||||
#include <ctime>
|
||||
#include <variant>
|
||||
|
||||
namespace OpenVulkano::Image
|
||||
{
|
||||
@@ -36,11 +38,11 @@ namespace OpenVulkano::Image
|
||||
struct GPSCoords
|
||||
{
|
||||
int32_t degrees, minutes, seconds;
|
||||
LatitudeRef latitudeRef = LatitudeRef::NORTH;
|
||||
LongitudeRef longitudeRef = LongitudeRef::EAST;
|
||||
std::variant<LatitudeRef, LongitudeRef> ref;
|
||||
|
||||
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
|
||||
@@ -56,8 +58,8 @@ namespace OpenVulkano::Image
|
||||
std::string dateTaken; // format: yyyy:mm:dd hh:mm:ss
|
||||
std::string softwareUsed = "OpenVulkano";
|
||||
|
||||
GPSCoords latitude = { 0, 0, 0 };
|
||||
GPSCoords longitude = { 0, 0, 0 };
|
||||
GPSCoords latitude = { 0, 0, 0, LatitudeRef::NORTH };
|
||||
GPSCoords longitude = { 0, 0, 0, LongitudeRef::EAST };
|
||||
|
||||
bool altitudeIsAboveSeaLevel = true;
|
||||
uint32_t altitude = 0;
|
||||
@@ -67,8 +69,10 @@ namespace OpenVulkano::Image
|
||||
|
||||
|
||||
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());
|
||||
std::vector<uint8_t> Build();
|
||||
static std::string GetCurrentTimestamp();
|
||||
[[nodiscard]] std::vector<uint8_t> Build();
|
||||
[[nodiscard]] static std::string StringFromTime(std::time_t time);
|
||||
[[nodiscard]] static std::string GetCurrentTimestamp();
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user