Add JpegWithTagsWriter helper
This commit is contained in:
98
openVulkanoCpp/Image/JpegWithTagsWriter.hpp
Normal file
98
openVulkanoCpp/Image/JpegWithTagsWriter.hpp
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <span>
|
||||
#include <string_view>
|
||||
|
||||
namespace OpenVulkano
|
||||
{
|
||||
class JpegWithTagsWriter final
|
||||
{
|
||||
FILE* file;
|
||||
|
||||
template<typename T> static T EndianSwap(T value)
|
||||
{
|
||||
T result;
|
||||
|
||||
char* ptr = reinterpret_cast<char*>(&value);
|
||||
std::reverse(ptr, ptr + sizeof(T));
|
||||
result = value;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Check() const
|
||||
{
|
||||
if (file == nullptr) throw std::runtime_error("Can't append to jpeg file, it has already been completed.");
|
||||
}
|
||||
|
||||
// ReSharper disable once CppDFAConstantParameter
|
||||
void WriteAppMarker(const int app = 1) const
|
||||
{
|
||||
// ReSharper disable once CppDFAConstantConditions
|
||||
if (app > 0xF) [[unlikely]] throw std::runtime_error("App marker is out of range.");
|
||||
fputc(0xFF, file);
|
||||
fputc(0xE0 + app, file);
|
||||
}
|
||||
|
||||
void Write16(uint16_t value) const
|
||||
{
|
||||
value = EndianSwap(value);
|
||||
fwrite(&value, sizeof(value), 1, file);
|
||||
}
|
||||
|
||||
void Write32(uint32_t value) const
|
||||
{
|
||||
value = EndianSwap(value);
|
||||
fwrite(&value, sizeof(value), 1, file);
|
||||
}
|
||||
|
||||
public:
|
||||
JpegWithTagsWriter(const std::filesystem::path& filePath)
|
||||
{
|
||||
file = fopen(filePath.c_str(), "wb");
|
||||
if (file == nullptr) throw std::runtime_error("Can't open file.");
|
||||
// Write soi marker
|
||||
fputc(0xFF, file);
|
||||
fputc(0xD8, file);
|
||||
}
|
||||
|
||||
void WriteExifTag(const std::span<uint8_t>& exifTag) const
|
||||
{
|
||||
WriteAppMarker();
|
||||
Write16(exifTag.size() + 2); // 2 byte extra for the size value itself
|
||||
fwrite(exifTag.data(), sizeof(uint8_t), exifTag.size(), file);
|
||||
}
|
||||
|
||||
void WriteXmpTag(const std::string& xmpTag) const
|
||||
{
|
||||
constexpr std::string_view XMP_MARKER = "http://ns.adobe.com/xap/1.0/";
|
||||
WriteAppMarker(1);
|
||||
Write16(xmpTag.size() + XMP_MARKER.size() + 3); // 1 byte extra for null termination, 2 byte extra for the size value itself
|
||||
fwrite(XMP_MARKER.data(), XMP_MARKER.size(), 1, file);
|
||||
fputc(0, file); // Null terminate string
|
||||
fwrite(xmpTag.c_str(), 1, xmpTag.size(), file);
|
||||
}
|
||||
|
||||
// Must be called as last function, as this will finalize the image writing and will close the file
|
||||
void WriteImageData(const std::span<uint8_t>& imageData)
|
||||
{
|
||||
Check();
|
||||
// write image data and skip soi marker from og data
|
||||
fwrite(imageData.data() + 2, sizeof(uint8_t), imageData.size() - 2, file);
|
||||
fclose(file);
|
||||
file = nullptr;
|
||||
}
|
||||
|
||||
operator bool() const { return file != nullptr; }
|
||||
|
||||
bool IsOpen() const { return file != nullptr; }
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user