diff --git a/openVulkanoCpp/Image/ExifBuilder.cpp b/openVulkanoCpp/Image/ExifBuilder.cpp index ed0c005..1ec4361 100644 --- a/openVulkanoCpp/Image/ExifBuilder.cpp +++ b/openVulkanoCpp/Image/ExifBuilder.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -60,23 +59,13 @@ namespace RATIONAL = 5, }; - uint32_t EndianSwap(uint32_t value) + template + 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(&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& ref) + { + char c = 0; + if (std::holds_alternative(ref)) + { + auto lat = std::get(ref); + c = (lat == OpenVulkano::Image::LatitudeRef::NORTH ? 'N' : 'S'); + } + else if (std::holds_alternative(ref)) + { + auto lon = std::get(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; - } - else - { - latitudeRef = LatitudeRef::NORTH; - } + ref = (decimalDegrees < 0) ? LatitudeRef::SOUTH : 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 = level; + altitude = std::abs(level); + } + + void ExifBuilder::SetTime(std::time_t timestamp) + { + dateTaken = StringFromTime(timestamp); } std::vector ExifBuilder::Build() @@ -334,67 +333,54 @@ namespace OpenVulkano::Image std::vector 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)); - } + 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); - } + 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); + } } \ No newline at end of file diff --git a/openVulkanoCpp/Image/ExifBuilder.hpp b/openVulkanoCpp/Image/ExifBuilder.hpp index 4bc238b..2f13771 100644 --- a/openVulkanoCpp/Image/ExifBuilder.hpp +++ b/openVulkanoCpp/Image/ExifBuilder.hpp @@ -8,6 +8,8 @@ #include #include #include +#include +#include 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 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 Build(); - static std::string GetCurrentTimestamp(); + [[nodiscard]] std::vector Build(); + [[nodiscard]] static std::string StringFromTime(std::time_t time); + [[nodiscard]] static std::string GetCurrentTimestamp(); }; } \ No newline at end of file