From ed87e1dfdb74186921760f3ad196a461d981c267 Mon Sep 17 00:00:00 2001 From: Vladyslav Baranovskyi Date: Mon, 23 Sep 2024 22:09:36 +0300 Subject: [PATCH] Summary: - Using std::array instead of c arrays - Methods and functions are now in PascalCase - Using std::reverse in EndianSwap - Using little_endian bool variable - TRUE_ is now TRUE_NORTH - Added constructors to GPSCoords class - GetCurrentTimestamp() method - Added setter for altitude variable - Minor renamings --- openVulkanoCpp/Image/ExifBuilder.cpp | 571 +++++++++++++++------------ openVulkanoCpp/Image/ExifBuilder.hpp | 24 +- 2 files changed, 326 insertions(+), 269 deletions(-) diff --git a/openVulkanoCpp/Image/ExifBuilder.cpp b/openVulkanoCpp/Image/ExifBuilder.cpp index d8e911b..3fe5436 100644 --- a/openVulkanoCpp/Image/ExifBuilder.cpp +++ b/openVulkanoCpp/Image/ExifBuilder.cpp @@ -5,16 +5,24 @@ */ #include "ExifBuilder.hpp" - -#define ARRAY_COUNT(Array) (sizeof(Array) / sizeof(*Array)) +#include +#include +#include +#include +#include +#include +#include +#include namespace { - char EXIF_HEADER_AND_PADDING[] = {'E', 'x', 'i', 'f', 0, 0}; - int const EXIF_HEADER_SIZE = ARRAY_COUNT(EXIF_HEADER_AND_PADDING); + const int EXIF_HEADER_SIZE = 6; + std::array EXIF_HEADER_AND_PADDING = { 'E', 'x', 'i', 'f', 0, 0 }; - char TIFF_HEADER[] = {0x4d, 0x4d, 0, 0x2a}; - int const TIFF_HEADER_SIZE = ARRAY_COUNT(TIFF_HEADER); + const int TIFF_HEADER_SIZE = 4; + std::array TIFF_HEADER = { 0x4d, 0x4d, 0, 0x2a }; + + constexpr bool LITTLE_ENDIAN = std::endian::native == std::endian::little; enum class IFDTag : uint16_t { @@ -22,8 +30,8 @@ namespace MAKE = 0x010f, MODEL = 0x0110, ORIENTATION = 0x0112, - XRESOLUTION = 0x011a, - YRESOLUTION = 0x011b, + X_RESOLUTION = 0x011a, + Y_RESOLUTION = 0x011b, RESOLUTION_UNIT = 0x0128, SOFTWARE_USED = 0x0131, DATE_TAKEN = 0x0132, @@ -40,143 +48,212 @@ namespace RATIONAL = 5, }; - uint32_t endianSwap(uint32_t Value) + uint32_t EndianSwap(uint32_t value) { - uint32_t Result; + uint32_t result; - char *Ptr = (char *)&Value; - char *Out = (char *)&Result; - Out[0] = Ptr[3]; - Out[1] = Ptr[2]; - Out[2] = Ptr[1]; - Out[3] = Ptr[0]; + 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; - char *Out = (char *)&Result; - Out[0] = Ptr[1]; - Out[1] = Ptr[0]; - - return Result; - } - - int appendU8(std::vector& array, uint8_t value) - { - int result = array.size(); - array.push_back(value); return result; } - int appendU16(std::vector& array, uint16_t value, bool endianSwap = false) + uint16_t EndianSwap(uint16_t value) { - int result = array.size(); + uint16_t result; - if(endianSwap) - value = ::endianSwap(value); + char *ptr = (char *) &value; + std::reverse(ptr, ptr + 2); + result = value; - char *src = (char *)&value; + return result; + } + + int AppendU8(std::vector& array, uint8_t value) + { + int offset = array.size(); + array.push_back(value); + return offset; + } + + int AppendU16(std::vector& array, uint16_t value) + { + int offset = array.size(); + + if constexpr (LITTLE_ENDIAN) + { + value = ::EndianSwap(value); + } + + char *src = (char *) &value; array.push_back(src[0]); array.push_back(src[1]); - return result; + return offset; } - int appendU32(std::vector& array, uint32_t value, bool endianSwap = false) + // no endian swap + int AppendU32NES(std::vector& array, uint32_t value) { - int result = array.size(); + int offset = array.size(); - if(endianSwap) - value = ::endianSwap(value); - - char *src = (char *)&value; + char *src = (char *) &value; array.push_back(src[0]); array.push_back(src[1]); array.push_back(src[2]); array.push_back(src[3]); - return result; + return offset; } - int appendVector(std::vector& array, std::vector values) + int AppendU32(std::vector& array, uint32_t value) { - int result = array.size(); + int offset = array.size(); - for(auto value : values) + if constexpr (LITTLE_ENDIAN) + { + value = ::EndianSwap(value); + } + + char *src = (char *) &value; + array.push_back(src[0]); + array.push_back(src[1]); + array.push_back(src[2]); + array.push_back(src[3]); + + return offset; + } + + template + int AppendVector(std::vector& array, const std::array& values) + { + int offset = array.size(); + + for (auto value: values) { array.push_back(value); } - return result; + return offset; } - int appendVector(std::vector& array, char* values, int count) + int AppendVector(std::vector& array, std::vector values) { - int result = array.size(); + int offset = array.size(); - for(int i = 0; i < count; ++i) + for (auto value: values) + { + array.push_back(value); + } + + return offset; + } + + int AppendVector(std::vector& array, char* values, int count) + { + int offset = array.size(); + + for (int i = 0; i < count; ++i) { array.push_back(values[i]); } - return result; + return offset; } - int appendRational(std::vector& array, const OpenVulkano::Image::RationalValue& rational, bool endianSwap = false) + int AppendRational(std::vector& array, const OpenVulkano::Image::RationalValue& rational) { - int result = array.size(); + int offset = array.size(); - appendU32(array, rational.nominator, endianSwap); - appendU32(array, rational.denominator, endianSwap); + AppendU32(array, rational.nominator); + AppendU32(array, rational.denominator); - return result; + return offset; } - int appendGPSCoords(std::vector& array, const OpenVulkano::Image::GPSCoords& coords, bool endianSwap = false) + int AppendGPSCoords(std::vector& array, const OpenVulkano::Image::GPSCoords& coords) { - int result = array.size(); + int offset = array.size(); - appendU32(array, coords.degrees, endianSwap); - appendU32(array, 1, endianSwap); + AppendU32(array, coords.degrees); + AppendU32(array, 1); - appendU32(array, coords.minutes, endianSwap); - appendU32(array, 1, endianSwap); + AppendU32(array, coords.minutes); + AppendU32(array, 1); - appendU32(array, coords.seconds, endianSwap); - appendU32(array, 1, endianSwap); + AppendU32(array, coords.seconds); + AppendU32(array, 1); - return result; + return offset; + } + + void AppendTagAndValueType(std::vector& array, uint16_t tag, uint16_t valueType) + { + AppendU16(array, tag); + AppendU16(array, valueType); + } + + void AddValueToU32AndEndianSwap(uint8_t *data, int valueToAdd) + { + uint32_t *ptr = (uint32_t *) data; + *ptr += valueToAdd; + *ptr = EndianSwap(*ptr); } } namespace OpenVulkano::Image { - std::vector ExifBuilder::build() + GPSCoords::GPSCoords(int32_t valueForAll) + { + this->degrees = valueForAll; + this->minutes = valueForAll; + this->seconds = valueForAll; + } + + GPSCoords::GPSCoords(int32_t degrees, int32_t minutes, int32_t seconds) + { + this->degrees = degrees; + this->minutes = minutes; + this->seconds = seconds; + } + + void ExifBuilder::SetAltitude(float level) + { + altitudeIsAboveSeaLevel = level >= 0; + if (level < 0) + { + level = -level; + } + altitude = level; + } + + std::vector ExifBuilder::Build() { std::vector result; - std::vector data; // the data that has ascii values + std::vector data; // the data that has ascii and rational values - appendVector(result, EXIF_HEADER_AND_PADDING, EXIF_HEADER_SIZE); - appendVector(result, TIFF_HEADER, TIFF_HEADER_SIZE); + if (dateTaken == "") + { + dateTaken = GetCurrentTimestamp(); + } + + AppendVector(result, EXIF_HEADER_AND_PADDING); + AppendVector(result, TIFF_HEADER); int numberOfMainTags = 1; // 1 is for GPS Info tag numberOfMainTags += orientation != 0; numberOfMainTags += make != ""; numberOfMainTags += model != ""; - numberOfMainTags += xresolution.nominator || xresolution.denominator; - numberOfMainTags += yresolution.nominator || yresolution.denominator; + numberOfMainTags += xResolution.nominator || xResolution.denominator; + numberOfMainTags += yResolution.nominator || yResolution.denominator; numberOfMainTags += resolutionUnit != 0; numberOfMainTags += exposureTime.nominator || exposureTime.denominator; numberOfMainTags += softwareUsed != ""; numberOfMainTags += dateTaken != ""; - appendU32(result, 8, true); // append offset to the ifd - appendU16(result, numberOfMainTags, true); + AppendU32(result, 8); // Append offset to the ifd + AppendU16(result, numberOfMainTags); // offsets in result array where the offset to the data should be stored int makeOffset = 0; @@ -186,96 +263,88 @@ namespace OpenVulkano::Image int gpsInfoOffset = 0; // Make - if(make != "") + if (make != "") { - appendU16(result, (uint16_t)IFDTag::MAKE, true); - appendU16(result, (uint16_t)IFDValueType::ASCII, true); - appendU32(result, make.size() + 1, true); - makeOffset = appendU32(result, data.size() + 1, true); - int offsetInData = appendVector(data, (char *)make.c_str(), make.size() + 1); + AppendTagAndValueType(result, (uint16_t) IFDTag::MAKE, (uint16_t) IFDValueType::ASCII); + AppendU32(result, make.size() + 1); + makeOffset = AppendU32(result, data.size() + 1); + int offsetInData = AppendVector(data, (char *)make.c_str(), make.size() + 1); uint32_t* ptr = (uint32_t *)(result.data() + makeOffset); *ptr = offsetInData; } // Model - if(model != "") + if (model != "") { - appendU16(result, (uint16_t)IFDTag::MODEL, true); - appendU16(result, (uint16_t)IFDValueType::ASCII, true); - appendU32(result, model.size() + 1, true); - modelOffset = appendU32(result, data.size() + 1, true); - int offsetInData = appendVector(data, (char *)model.c_str(), model.size() + 1); + AppendTagAndValueType(result, (uint16_t) IFDTag::MODEL, (uint16_t) IFDValueType::ASCII); + AppendU32(result, model.size() + 1); + modelOffset = AppendU32(result, data.size() + 1); + int offsetInData = AppendVector(data, (char *)model.c_str(), model.size() + 1); uint32_t* ptr = (uint32_t *)(result.data() + modelOffset); *ptr = offsetInData; } // Orientation - if(orientation != 0) + if (orientation != 0) { - appendU16(result, (uint16_t)IFDTag::ORIENTATION, true); - appendU16(result, (uint16_t)IFDValueType::SHORT, true); - appendU32(result, 1, true); - appendU16(result, (uint16_t)orientation, true); - appendU16(result, 0); // padding + AppendTagAndValueType(result, (uint16_t) IFDTag::ORIENTATION, (uint16_t) IFDValueType::SHORT); + AppendU32(result, 1); + AppendU16(result, (uint16_t)orientation); + AppendU16(result, 0); // padding } - // XResolution - int xresolutionOffset = 0; - if(xresolution.nominator || xresolution.denominator) + // xResolution + int xResolutionOffset = 0; + if (xResolution.nominator || xResolution.denominator) { - appendU16(result, (uint16_t)IFDTag::XRESOLUTION, true); - appendU16(result, (uint16_t)IFDValueType::RATIONAL, true); - appendU32(result, 1, true); // number of components - xresolutionOffset = appendU32(result, data.size(), true); - int offsetInData = appendRational(data, xresolution, true); - uint32_t* ptr = (uint32_t *)(result.data() + xresolutionOffset); + AppendTagAndValueType(result, (uint16_t) IFDTag::X_RESOLUTION, (uint16_t) IFDValueType::RATIONAL); + AppendU32(result, 1); // number of components + xResolutionOffset = AppendU32(result, data.size()); + int offsetInData = AppendRational(data, xResolution); + uint32_t* ptr = (uint32_t *)(result.data() + xResolutionOffset); *ptr = offsetInData; } - // YResolution - int yresolutionOffset = 0; - if(yresolution.nominator || yresolution.denominator) + // yResolution + int yResolutionOffset = 0; + if (yResolution.nominator || yResolution.denominator) { - appendU16(result, (uint16_t)IFDTag::YRESOLUTION, true); - appendU16(result, (uint16_t)IFDValueType::RATIONAL, true); - appendU32(result, 1, true); // number of components - yresolutionOffset = appendU32(result, data.size(), true); - int offsetInData = appendRational(data, yresolution, true); - uint32_t* ptr = (uint32_t *)(result.data() + yresolutionOffset); + AppendTagAndValueType(result, (uint16_t) IFDTag::Y_RESOLUTION, (uint16_t) IFDValueType::RATIONAL); + AppendU32(result, 1); // number of components + yResolutionOffset = AppendU32(result, data.size()); + int offsetInData = AppendRational(data, yResolution); + uint32_t* ptr = (uint32_t *)(result.data() + yResolutionOffset); *ptr = offsetInData; } // Exposure Time int exposureTimeOffset = 0; - if(exposureTime.nominator || exposureTime.denominator) + if (exposureTime.nominator || exposureTime.denominator) { - appendU16(result, (uint16_t)IFDTag::EXPOSURE_TIME, true); - appendU16(result, (uint16_t)IFDValueType::RATIONAL, true); - appendU32(result, 1, true); // number of components - exposureTimeOffset = appendU32(result, data.size(), true); - int offsetInData = appendRational(data, exposureTime, true); + AppendTagAndValueType(result, (uint16_t) IFDTag::EXPOSURE_TIME, (uint16_t) IFDValueType::RATIONAL); + AppendU32(result, 1); // number of components + exposureTimeOffset = AppendU32(result, data.size()); + int offsetInData = AppendRational(data, exposureTime); uint32_t* ptr = (uint32_t *)(result.data() + exposureTimeOffset); *ptr = offsetInData; } // ResolutionUnit - if(resolutionUnit != 0) + if (resolutionUnit != 0) { - appendU16(result, (uint16_t)IFDTag::RESOLUTION_UNIT, true); - appendU16(result, (uint16_t)IFDValueType::SHORT, true); - appendU32(result, 1, true); // number of components - appendU16(result, resolutionUnit, true); - appendU16(result, 0); // padding + AppendTagAndValueType(result, (uint16_t) IFDTag::RESOLUTION_UNIT, (uint16_t) IFDValueType::SHORT); + AppendU32(result, 1); // number of components + AppendU16(result, resolutionUnit); + AppendU16(result, 0); // padding } // Software Used - if(softwareUsed != "") + if (softwareUsed != "") { - appendU16(result, (uint16_t)IFDTag::SOFTWARE_USED, true); - appendU16(result, (uint16_t)IFDValueType::ASCII, true); - appendU32(result, softwareUsed.size() + 1, true); - softwareUsedOffset = appendU32(result, data.size() + 1, true); - int offsetInData = appendVector(data, (char *)softwareUsed.c_str(), softwareUsed.size() + 1); + AppendTagAndValueType(result, (uint16_t) IFDTag::SOFTWARE_USED, (uint16_t) IFDValueType::ASCII); + AppendU32(result, softwareUsed.size() + 1); + softwareUsedOffset = AppendU32(result, data.size() + 1); + int offsetInData = AppendVector(data, (char *)softwareUsed.c_str(), softwareUsed.size() + 1); uint32_t* ptr = (uint32_t *)(result.data() + softwareUsedOffset); *ptr = offsetInData; } @@ -283,192 +352,174 @@ namespace OpenVulkano::Image // 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 - if(dateTaken != "") { - appendU16(result, (uint16_t)IFDTag::DATE_TAKEN, true); - appendU16(result, (uint16_t)IFDValueType::ASCII, true); - appendU32(result, dateTaken.size() + 1, true); - dateTakenOffset = appendU32(result, data.size() + 1, true); - int offsetInData = appendVector(data, (char *)dateTaken.c_str(), dateTaken.size() + 1); + AppendTagAndValueType(result, (uint16_t) IFDTag::DATE_TAKEN, (uint16_t) IFDValueType::ASCII); + AppendU32(result, dateTaken.size() + 1); + dateTakenOffset = AppendU32(result, data.size() + 1); + int offsetInData = AppendVector(data, (char *)dateTaken.c_str(), dateTaken.size() + 1); uint32_t* ptr = (uint32_t *)(result.data() + dateTakenOffset); *ptr = offsetInData; } // GPS Info offset - appendU16(result, (uint16_t) IFDTag::GPS_INFO_OFFSET, true); - appendU16(result, (uint16_t) IFDValueType::LONG_, true); - appendU32(result, 1, true); // num components - gpsInfoOffset = appendU32(result, 0, true); // to be filled + AppendTagAndValueType(result, (uint16_t) IFDTag::GPS_INFO_OFFSET, (uint16_t) IFDValueType::LONG_); + AppendU32(result, 1); // num components + gpsInfoOffset = AppendU32(result, 0); // to be filled // next ifd offset - appendU32(result, 0); + AppendU32(result, 0); int resultSize = result.size(); - appendVector(result, data); + AppendVector(result, data); int ifdAndSubdataSize = result.size(); - if(model != "") { - uint32_t *ptr = (uint32_t *) (result.data() + modelOffset); - *ptr += resultSize - EXIF_HEADER_SIZE; - *ptr = endianSwap(*ptr); - } + const int valueToAdd = resultSize - EXIF_HEADER_SIZE; + if (model != "") + { + AddValueToU32AndEndianSwap(result.data() + modelOffset, valueToAdd); + } - if(make != "") - { - uint32_t *ptr = (uint32_t *) (result.data() + makeOffset); - *ptr += resultSize - EXIF_HEADER_SIZE; - *ptr = endianSwap(*ptr); - } + if (make != "") + { + AddValueToU32AndEndianSwap(result.data() + makeOffset, valueToAdd); + } - if(xresolutionOffset) - { - uint32_t *ptr = (uint32_t *) (result.data() + xresolutionOffset); - *ptr += resultSize - EXIF_HEADER_SIZE; - *ptr = endianSwap(*ptr); - } + if (xResolutionOffset) + { + AddValueToU32AndEndianSwap(result.data() + xResolutionOffset, valueToAdd); + } - if(yresolutionOffset) - { - uint32_t *ptr = (uint32_t *) (result.data() + yresolutionOffset); - *ptr += resultSize - EXIF_HEADER_SIZE; - *ptr = endianSwap(*ptr); - } + if (yResolutionOffset) + { + AddValueToU32AndEndianSwap(result.data() + yResolutionOffset, valueToAdd); + } - if(exposureTimeOffset) - { - uint32_t *ptr = (uint32_t *) (result.data() + exposureTimeOffset); - *ptr += resultSize - EXIF_HEADER_SIZE; - *ptr = endianSwap(*ptr); - } + if (exposureTimeOffset) + { + AddValueToU32AndEndianSwap(result.data() + exposureTimeOffset, valueToAdd); + } - if(dateTakenOffset) - { - uint32_t *ptr = (uint32_t *) (result.data() + dateTakenOffset); - *ptr += resultSize - EXIF_HEADER_SIZE; - *ptr = endianSwap(*ptr); - } + if (dateTakenOffset) + { + AddValueToU32AndEndianSwap(result.data() + dateTakenOffset, valueToAdd); + } - if(softwareUsedOffset) - { - uint32_t *ptr = (uint32_t *) (result.data() + softwareUsedOffset); - *ptr += resultSize - EXIF_HEADER_SIZE; - *ptr = endianSwap(*ptr); + if (softwareUsedOffset) + { + AddValueToU32AndEndianSwap(result.data() + softwareUsedOffset, valueToAdd); + } } { uint32_t *ptr = (uint32_t *) (result.data() + gpsInfoOffset); - *ptr = endianSwap((uint32_t)(ifdAndSubdataSize - EXIF_HEADER_SIZE)); + *ptr = EndianSwap((uint32_t)(ifdAndSubdataSize - EXIF_HEADER_SIZE)); } // Writing GPS Info structure int numberOfGPSInfoTags = 8; - appendU16(result, numberOfGPSInfoTags, true); + AppendU16(result, numberOfGPSInfoTags); // Latitude Ref - appendU16(result, 1, true); - appendU16(result, (uint16_t) IFDValueType::ASCII, true); - appendU32(result, 2, true); // 2 for N/S + \0 - appendU8(result, latitudeRef == LatitudeRef::NORTH ? 'N' : 'S'); - appendU8(result, 0); - appendU8(result, 0); // padding - appendU8(result, 0); // padding + AppendTagAndValueType(result, 1, (uint16_t) IFDValueType::ASCII); + AppendU32(result, 2); // 2 for N/S + \0 + AppendU8(result, latitudeRef == LatitudeRef::NORTH ? 'N' : 'S'); + AppendU8(result, 0); + AppendU8(result, 0); // padding + AppendU8(result, 0); // padding // Latitude - appendU16(result, 2, true); - appendU16(result, (uint16_t) IFDValueType::RATIONAL, true); - appendU32(result, 3, true); // number of components - int latitudeOffset = appendU32(result, 0); // 0 * sizeof(RationalValue) + AppendTagAndValueType(result, 2, (uint16_t) IFDValueType::RATIONAL); + AppendU32(result, 3); // number of components + int latitudeOffset = AppendU32NES(result, 0); // 0 * sizeof(RationalValue) // Longitude Ref - appendU16(result, 3, true); - appendU16(result, (uint16_t) IFDValueType::ASCII, true); - appendU32(result, 2, true); // 2 for E/W + \0 - appendU8(result, longitudeRef == LongitudeRef::EAST ? 'E' : 'W'); - appendU8(result, 0); - appendU8(result, 0); // padding - appendU8(result, 0); // padding + AppendTagAndValueType(result, 3, (uint16_t) IFDValueType::ASCII); + AppendU32(result, 2); // 2 for E/W + \0 + AppendU8(result, longitudeRef == LongitudeRef::EAST ? 'E' : 'W'); + AppendU8(result, 0); + AppendU8(result, 0); // padding + AppendU8(result, 0); // padding // Longitude - appendU16(result, 4, true); - appendU16(result, (uint16_t) IFDValueType::RATIONAL, true); - appendU32(result, 3, true); // number of components - int longitudeOffset = appendU32(result, 24); // 3 * sizeof(RationalValue) + AppendTagAndValueType(result, 4, (uint16_t) IFDValueType::RATIONAL); + AppendU32(result, 3); // number of components + int longitudeOffset = AppendU32NES(result, 24); // 3 * sizeof(RationalValue) // Altitude Ref - appendU16(result, 5, true); - appendU16(result, (uint16_t) IFDValueType::BYTE, true); - appendU32(result, 1, true); // number of components - appendU8(result, altitudeIsAboveSeaLevel ? 0 : 1); - appendU8(result, 0); // padding - appendU8(result, 0); // padding - appendU8(result, 0); // padding + AppendTagAndValueType(result, 5, (uint16_t) IFDValueType::BYTE); + AppendU32(result, 1); // number of components + AppendU8(result, altitudeIsAboveSeaLevel ? 0 : 1); + AppendU8(result, 0); // padding + AppendU8(result, 0); // padding + AppendU8(result, 0); // padding // Altitude - appendU16(result, 6, true); - appendU16(result, (uint16_t) IFDValueType::RATIONAL, true); - appendU32(result, 1, true); // number of components - int altitudeOffset = appendU32(result, 48); // 6 * sizeof(RationalValue) + AppendTagAndValueType(result, 6, (uint16_t) IFDValueType::RATIONAL); + AppendU32(result, 1); // number of components + int altitudeOffset = AppendU32NES(result, 48); // 6 * sizeof(RationalValue) // Track Ref - appendU16(result, 14, true); - appendU16(result, (uint16_t) IFDValueType::ASCII, true); - appendU32(result, 2, true); // 2 for T/M + \0 - appendU8(result, trackRef == GPSTrackRef::TRUE_ ? 'T' : 'M'); - appendU8(result, 0); - appendU8(result, 0); // padding - appendU8(result, 0); // padding + AppendTagAndValueType(result, 14, (uint16_t) IFDValueType::ASCII); + AppendU32(result, 2); // 2 for T/M + \0 + AppendU8(result, trackRef == GPSTrackRef::TRUE_NORTH ? 'T' : 'M'); + AppendU8(result, 0); + AppendU8(result, 0); // padding + AppendU8(result, 0); // padding // Track - appendU16(result, 15, true); - appendU16(result, (uint16_t) IFDValueType::RATIONAL, true); - appendU32(result, 1, true); // number of components - int trackOffset = appendU32(result, 56); // 7 * sizeof(RationalValue) + AppendTagAndValueType(result, 15, (uint16_t) IFDValueType::RATIONAL); + AppendU32(result, 1); // number of components + int trackOffset = AppendU32NES(result, 56); // 7 * sizeof(RationalValue) // - int sizeOfResultSoFar = result.size(); - - // Latitude { - uint32_t *ptr = (uint32_t *) (result.data() + latitudeOffset); - *ptr += sizeOfResultSoFar - EXIF_HEADER_SIZE; - *ptr = endianSwap(*ptr); - } + int sizeOfResultSoFar = result.size(); + const int valueToAdd = sizeOfResultSoFar - EXIF_HEADER_SIZE; + // Latitude + { + AddValueToU32AndEndianSwap(result.data() + latitudeOffset, valueToAdd); + } - // Longitude - { - uint32_t *ptr = (uint32_t *) (result.data() + longitudeOffset); - *ptr += sizeOfResultSoFar - EXIF_HEADER_SIZE; - *ptr = endianSwap(*ptr); - } + // Longitude + { + AddValueToU32AndEndianSwap(result.data() + longitudeOffset, valueToAdd); + } - // Altitude - { - uint32_t *ptr = (uint32_t *) (result.data() + altitudeOffset); - *ptr += sizeOfResultSoFar - EXIF_HEADER_SIZE; - *ptr = endianSwap(*ptr); - } + // Altitude + { + AddValueToU32AndEndianSwap(result.data() + altitudeOffset, valueToAdd); + } - // Track - { - uint32_t *ptr = (uint32_t *) (result.data() + trackOffset); - *ptr += sizeOfResultSoFar - EXIF_HEADER_SIZE; - *ptr = endianSwap(*ptr); + // Track + { + AddValueToU32AndEndianSwap(result.data() + trackOffset, valueToAdd); + } } // - appendGPSCoords(result, latitude, true); - appendGPSCoords(result, longitude, true); + AppendGPSCoords(result, latitude); + AppendGPSCoords(result, longitude); - appendU32(result, altitude, true); - appendU32(result, 1, true); // denominator for altitude + AppendU32(result, altitude); + AppendU32(result, 1); // denominator for altitude int const TRACK_PRECISION = 10000; - appendU32(result, track * TRACK_PRECISION, true); - appendU32(result, TRACK_PRECISION, true); + AppendU32(result, track * TRACK_PRECISION); + AppendU32(result, TRACK_PRECISION); return result; } + + std::string ExifBuilder::GetCurrentTimestamp() + { + 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::ostringstream oss; + oss << std::put_time(timeInfo, "%Y:%m:%d %H:%M:%S"); + return oss.str(); + } } \ No newline at end of file diff --git a/openVulkanoCpp/Image/ExifBuilder.hpp b/openVulkanoCpp/Image/ExifBuilder.hpp index b7062a4..8548dac 100644 --- a/openVulkanoCpp/Image/ExifBuilder.hpp +++ b/openVulkanoCpp/Image/ExifBuilder.hpp @@ -29,13 +29,16 @@ namespace OpenVulkano::Image }; enum class GPSTrackRef { - TRUE_, + TRUE_NORTH, MAGNETIC }; struct GPSCoords { int32_t degrees, minutes, seconds; + + GPSCoords(int32_t valueForAll = 0); + GPSCoords(int32_t degrees, int32_t minutes, int32_t seconds); }; class ExifBuilder @@ -44,26 +47,29 @@ namespace OpenVulkano::Image int orientation = 0; std::string make; std::string model; - RationalValue xresolution = {0, 0}; - RationalValue yresolution = {0, 0}; + RationalValue xResolution = { 0, 0 }; + RationalValue yResolution = { 0, 0 }; int resolutionUnit = 0; - RationalValue exposureTime = {0, 0}; + RationalValue exposureTime = { 0, 0 }; std::string dateTaken; // format: yyyy:mm:dd hh:mm:ss - std::string softwareUsed; + std::string softwareUsed = "OpenVulkano"; LatitudeRef latitudeRef = LatitudeRef::NORTH; - GPSCoords latitude = {0, 0, 0}; + GPSCoords latitude = { 0, 0, 0 }; LongitudeRef longitudeRef = LongitudeRef::EAST; - GPSCoords longitude = {0, 0, 0}; + GPSCoords longitude = { 0, 0, 0 }; bool altitudeIsAboveSeaLevel = true; uint32_t altitude = 0; - GPSTrackRef trackRef = GPSTrackRef::TRUE_; + GPSTrackRef trackRef = GPSTrackRef::TRUE_NORTH; float track = 0; // range is [0.0; 360.0) + + void SetAltitude(float level); // Typical usage is -> jpeg_write_marker(cinfo, JPEG_APP0 + 1, exif_data.data(), exif_data.size()); - std::vector build(); + std::vector Build(); + static std::string GetCurrentTimestamp(); }; } \ No newline at end of file