Huge refactor

I did my best...
This commit is contained in:
Vladyslav Baranovskyi
2024-09-27 19:49:23 +03:00
parent 0ea1c5c7db
commit 85974069e3

View File

@@ -199,6 +199,54 @@ namespace
*ptr += valueToAdd;
*ptr = EndianSwap(*ptr);
}
int AppendTagValueTypeAndString(std::vector<uint8_t>& array, IFDTag tag, std::vector<uint8_t> &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<uint8_t>& array, IFDTag tag, std::vector<uint8_t> &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<uint8_t>& 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<uint8_t>& 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<uint8_t>& 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<int> 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);