Using std::variant, changed EndianSwap, new function StringFromTime, minor tweaks

This commit is contained in:
Vladyslav Baranovskyi
2024-09-30 15:01:00 +03:00
parent 85974069e3
commit 61043119df
2 changed files with 69 additions and 72 deletions

View File

@@ -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(&currentTime);
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);
}
}

View File

@@ -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();
};
}