From 85974069e3b1942a925385c01e9d199d6770b608 Mon Sep 17 00:00:00 2001 From: Vladyslav Baranovskyi Date: Fri, 27 Sep 2024 19:49:23 +0300 Subject: [PATCH] Huge refactor I did my best... --- openVulkanoCpp/Image/ExifBuilder.cpp | 228 ++++++++++----------------- 1 file changed, 80 insertions(+), 148 deletions(-) diff --git a/openVulkanoCpp/Image/ExifBuilder.cpp b/openVulkanoCpp/Image/ExifBuilder.cpp index a67d970..ed0c005 100644 --- a/openVulkanoCpp/Image/ExifBuilder.cpp +++ b/openVulkanoCpp/Image/ExifBuilder.cpp @@ -199,6 +199,54 @@ namespace *ptr += valueToAdd; *ptr = EndianSwap(*ptr); } + + int AppendTagValueTypeAndString(std::vector& array, IFDTag tag, std::vector &otherArray, const std::string& str) + { + AppendTagAndValueType(array, (uint16_t) tag, (uint16_t) IFDValueType::ASCII); + AppendU32(array, str.size() + 1); + int offset = AppendU32(array, otherArray.size() + 1); + int offsetInData = AppendVector(otherArray, (char*) str.c_str(), str.size() + 1); + uint32_t* ptr = (uint32_t*) (array.data() + offset); + *ptr = offsetInData; + return offset; + } + + int AppendTagValueTypeAndRational(std::vector& array, IFDTag tag, std::vector &otherArray, const OpenVulkano::Image::RationalValue& value) + { + AppendTagAndValueType(array, (uint16_t) tag, (uint16_t) IFDValueType::RATIONAL); + AppendU32(array, 1); // number of components + int offset = AppendU32(array, otherArray.size()); + int offsetInData = AppendRational(otherArray, value); + uint32_t* ptr = (uint32_t*) (array.data() + offset); + *ptr = offsetInData; + return offset; + } + + void AppendTagValueTypeAndShort(std::vector& array, IFDTag tag, uint16_t value) + { + AppendTagAndValueType(array, (uint16_t ) tag, (uint16_t) IFDValueType::SHORT); + AppendU32(array, 1); + AppendU16(array, value); + AppendU16(array, 0); // padding + } + + void AppendTagValueTypeAndByte(std::vector& array, IFDGPSTag tag, IFDValueType valueType, uint16_t byte) + { + AppendTagAndValueType(array, (uint16_t) tag, (uint16_t) valueType); + AppendU32(array, (valueType == IFDValueType::BYTE) ? 1 : 2); // 2 for N/S/E/W + \0, 1 for a single byte + AppendU8(array, byte); + AppendU8(array, 0); // padding + AppendU8(array, 0); // padding + AppendU8(array, 0); // padding + } + + int AppendTagValueTypeAndGPSRational(std::vector& array, IFDGPSTag tag, int numberOfComponents, int initialOffsetValue) + { + AppendTagAndValueType(array, (uint16_t) tag, (uint16_t) IFDValueType::RATIONAL); + AppendU32(array, numberOfComponents); // number of components + int offset = AppendU32NES(array, initialOffsetValue); + return offset; + } } namespace OpenVulkano::Image @@ -283,163 +331,89 @@ namespace OpenVulkano::Image 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; - int modelOffset = 0; - int dateTakenOffset = 0; - int softwareUsedOffset = 0; + std::vector offsets; int gpsInfoOffset = 0; // Make if (!make.empty()) { - 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; + offsets.push_back(AppendTagValueTypeAndString(result, IFDTag::MAKE, data, make)); } // Model if (!model.empty()) { - 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; + offsets.push_back(AppendTagValueTypeAndString(result, IFDTag::MODEL, data, model)); } // Orientation if (orientation != 0) { - AppendTagAndValueType(result, (uint16_t) IFDTag::ORIENTATION, (uint16_t) IFDValueType::SHORT); - AppendU32(result, 1); - AppendU16(result, (uint16_t)orientation); - AppendU16(result, 0); // padding + AppendTagValueTypeAndShort(result, IFDTag::ORIENTATION, orientation); } // xResolution - int xResolutionOffset = 0; if (xResolution.nominator || xResolution.denominator) { - 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; + offsets.push_back(AppendTagValueTypeAndRational(result, IFDTag::X_RESOLUTION, data, xResolution)); } // yResolution - int yResolutionOffset = 0; if (yResolution.nominator || yResolution.denominator) { - 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; + offsets.push_back(AppendTagValueTypeAndRational(result, IFDTag::Y_RESOLUTION, data, yResolution)); } // Exposure Time - int exposureTimeOffset = 0; if (exposureTime.nominator || exposureTime.denominator) { - 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; + offsets.push_back(AppendTagValueTypeAndRational(result, IFDTag::EXPOSURE_TIME, data, exposureTime)); } // ResolutionUnit if (resolutionUnit != 0) { - AppendTagAndValueType(result, (uint16_t) IFDTag::RESOLUTION_UNIT, (uint16_t) IFDValueType::SHORT); - AppendU32(result, 1); // number of components - AppendU16(result, resolutionUnit); - AppendU16(result, 0); // padding + AppendTagValueTypeAndShort(result, IFDTag::RESOLUTION_UNIT, resolutionUnit); } // Software Used if (!softwareUsed.empty()) { - 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; + 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 { - 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; + 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); // to be filled + { + 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); int resultSize = result.size(); AppendVector(result, data); - int ifdAndSubdataSize = result.size(); + // Resolve offsets { const int valueToAdd = resultSize - EXIF_HEADER_SIZE; - if (!model.empty()) + for (const auto& offset: offsets) { - AddValueToU32AndEndianSwap(result.data() + modelOffset, valueToAdd); - } - - if (!make.empty()) - { - AddValueToU32AndEndianSwap(result.data() + makeOffset, valueToAdd); - } - - if (xResolutionOffset) - { - AddValueToU32AndEndianSwap(result.data() + xResolutionOffset, valueToAdd); - } - - if (yResolutionOffset) - { - AddValueToU32AndEndianSwap(result.data() + yResolutionOffset, valueToAdd); - } - - if (exposureTimeOffset) - { - AddValueToU32AndEndianSwap(result.data() + exposureTimeOffset, valueToAdd); - } - - if (dateTakenOffset) - { - AddValueToU32AndEndianSwap(result.data() + dateTakenOffset, valueToAdd); - } - - if (softwareUsedOffset) - { - AddValueToU32AndEndianSwap(result.data() + softwareUsedOffset, valueToAdd); + AddValueToU32AndEndianSwap(result.data() + offset, valueToAdd); } } + // Resolve GPS info offset { + int ifdAndSubdataSize = result.size(); uint32_t *ptr = (uint32_t *) (result.data() + gpsInfoOffset); *ptr = EndianSwap((uint32_t)(ifdAndSubdataSize - EXIF_HEADER_SIZE)); } @@ -447,82 +421,40 @@ namespace OpenVulkano::Image // Writing GPS Info structure int numberOfGPSInfoTags = 8; AppendU16(result, numberOfGPSInfoTags); + offsets.resize(0); // Latitude Ref - AppendTagAndValueType(result, (uint16_t) IFDGPSTag::LATITUDE_REF, (uint16_t) IFDValueType::ASCII); - AppendU32(result, 2); // 2 for N/S + \0 - AppendU8(result, latitude.latitudeRef == LatitudeRef::NORTH ? 'N' : 'S'); - AppendU8(result, 0); - AppendU8(result, 0); // padding - AppendU8(result, 0); // padding + AppendTagValueTypeAndByte(result, IFDGPSTag::LATITUDE_REF, IFDValueType::ASCII, (latitude.latitudeRef == LatitudeRef::NORTH) ? 'N' : 'S'); // Latitude - AppendTagAndValueType(result, (uint16_t) IFDGPSTag::LATITUDE, (uint16_t) IFDValueType::RATIONAL); - AppendU32(result, 3); // number of components - int latitudeOffset = AppendU32NES(result, 0); // 0 * sizeof(RationalValue) + offsets.push_back(AppendTagValueTypeAndGPSRational(result, IFDGPSTag::LATITUDE, 3, 0)); // 0 * sizeof(RationalValue) // Longitude Ref - AppendTagAndValueType(result, (uint16_t) IFDGPSTag::LONGITUDE_REF, (uint16_t) IFDValueType::ASCII); - AppendU32(result, 2); // 2 for E/W + \0 - AppendU8(result, longitude.longitudeRef == LongitudeRef::EAST ? 'E' : 'W'); - AppendU8(result, 0); - AppendU8(result, 0); // padding - AppendU8(result, 0); // padding + AppendTagValueTypeAndByte(result, IFDGPSTag::LONGITUDE_REF, IFDValueType::ASCII, (longitude.longitudeRef == LongitudeRef::EAST) ? 'E' : 'W'); // Longitude - AppendTagAndValueType(result, (uint16_t) IFDGPSTag::LONGITUDE, (uint16_t) IFDValueType::RATIONAL); - AppendU32(result, 3); // number of components - int longitudeOffset = AppendU32NES(result, 24); // 3 * sizeof(RationalValue) + offsets.push_back(AppendTagValueTypeAndGPSRational(result, IFDGPSTag::LONGITUDE, 3, 24)); // 3 * sizeof(RationalValue) // Altitude Ref - AppendTagAndValueType(result, (uint16_t) IFDGPSTag::ALTITUDE_REF, (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 + AppendTagValueTypeAndByte(result, IFDGPSTag::ALTITUDE_REF, IFDValueType::BYTE, altitudeIsAboveSeaLevel ? 0 : 1); // Altitude - AppendTagAndValueType(result, (uint16_t) IFDGPSTag::ALTITUDE, (uint16_t) IFDValueType::RATIONAL); - AppendU32(result, 1); // number of components - int altitudeOffset = AppendU32NES(result, 48); // 6 * sizeof(RationalValue) + offsets.push_back(AppendTagValueTypeAndGPSRational(result, IFDGPSTag::ALTITUDE, 1, 48)); // 6 * sizeof(RationalValue) // Track Ref - AppendTagAndValueType(result, (uint16_t) IFDGPSTag::TRACK_REF, (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 + AppendTagValueTypeAndByte(result, IFDGPSTag::TRACK_REF, IFDValueType::ASCII, (trackRef == GPSTrackRef::TRUE_NORTH) ? 'T' : 'M'); // Track - AppendTagAndValueType(result, (uint16_t) IFDGPSTag::TRACK, (uint16_t) IFDValueType::RATIONAL); - AppendU32(result, 1); // number of components - int trackOffset = AppendU32NES(result, 56); // 7 * sizeof(RationalValue) + offsets.push_back(AppendTagValueTypeAndGPSRational(result, IFDGPSTag::TRACK, 1, 56)); // 7 * sizeof(RationalValue) // { int sizeOfResultSoFar = result.size(); const int valueToAdd = sizeOfResultSoFar - EXIF_HEADER_SIZE; - // Latitude + for(const auto &offset : offsets) { - AddValueToU32AndEndianSwap(result.data() + latitudeOffset, valueToAdd); - } - - // Longitude - { - AddValueToU32AndEndianSwap(result.data() + longitudeOffset, valueToAdd); - } - - // Altitude - { - AddValueToU32AndEndianSwap(result.data() + altitudeOffset, valueToAdd); - } - - // Track - { - AddValueToU32AndEndianSwap(result.data() + trackOffset, valueToAdd); + AddValueToU32AndEndianSwap(result.data() + offset, valueToAdd); } } @@ -534,7 +466,7 @@ namespace OpenVulkano::Image AppendU32(result, altitude); AppendU32(result, 1); // denominator for altitude - int const TRACK_PRECISION = 10000; + const int TRACK_PRECISION = 10000; AppendU32(result, track * TRACK_PRECISION); AppendU32(result, TRACK_PRECISION);