7#define STB_IMAGE_WRITE_IMPLEMENTATION
10#if __has_include("stb/stb_image_write.h")
11#include "stb/stb_image_write.h"
12#elif __has_include("stb_image_write.h")
13#include "stb_image_write.h"
15#error "stb_image_write.h not found"
24 std::string extension_of(
const std::string& filepath)
26 auto ext = std::filesystem::path(filepath).extension().string();
27 if (!ext.empty() && ext[0] ==
'.') {
30 std::ranges::transform(ext, ext.begin(),
31 [](
unsigned char c) { return std::tolower(c); });
38 void stbi_memory_writer(
void* context,
void* data,
int size)
40 auto* buf =
static_cast<std::vector<uint8_t>*
>(context);
41 const auto* bytes =
static_cast<const uint8_t*
>(data);
42 buf->insert(buf->end(), bytes, bytes + size);
48 bool flush_to_disk(
const std::string& filepath,
const std::vector<uint8_t>& buffer)
51 std::ofstream out(resolved, std::ios::binary | std::ios::trunc);
55 out.write(
reinterpret_cast<const char*
>(buffer.data()),
56 static_cast<std::streamsize
>(buffer.size()));
70 {
"png",
"jpg",
"jpeg",
"bmp",
"tga",
"hdr" },
71 []() -> std::unique_ptr<ImageWriter> {
72 return std::make_unique<STBImageWriter>();
76 "STBImageWriter registered for: png, jpg, jpeg, bmp, tga, hdr");
85 const auto ext = extension_of(filepath);
86 static const std::vector<std::string> supported = {
87 "png",
"jpg",
"jpeg",
"bmp",
"tga",
"hdr"
89 return std::ranges::find(supported, ext) != supported.end();
94 return {
"png",
"jpg",
"jpeg",
"bmp",
"tga",
"hdr" };
98 const std::string& filepath,
105 m_last_error =
"ImageData variant does not match declared ImageFormat";
116 const auto ext = extension_of(filepath);
119 return write_png(filepath, data, options);
120 if (ext ==
"jpg" || ext ==
"jpeg")
121 return write_jpg(filepath, data, options);
139 const std::string& filepath,
153 stbi_write_png_compression_level = compression;
156 std::vector<uint8_t> encoded;
159 const int stride =
static_cast<int>(data.
width * data.
channels);
160 const int ok = stbi_write_png_to_func(
163 static_cast<int>(data.
width),
164 static_cast<int>(data.
height),
169 if (!ok || encoded.empty()) {
175 if (!flush_to_disk(filepath, encoded)) {
182 "Wrote PNG: {} ({}x{}, {} channels, {} bytes)",
188 const std::string& filepath,
200 m_last_error =
"JPG supports only 1 or 3 channels (got "
201 + std::to_string(data.
channels) +
")";
206 const int quality = std::clamp(options.
quality, 1, 100);
209 std::vector<uint8_t> encoded;
210 const int ok = stbi_write_jpg_to_func(
213 static_cast<int>(data.
width),
214 static_cast<int>(data.
height),
219 if (!ok || encoded.empty()) {
225 if (!flush_to_disk(filepath, encoded)) {
232 "Wrote JPG: {} ({}x{}, quality {}, {} bytes)",
233 filepath, data.
width, data.
height, quality, encoded.size());
246 std::vector<uint8_t> encoded;
247 const int ok = stbi_write_bmp_to_func(
250 static_cast<int>(data.
width),
251 static_cast<int>(data.
height),
255 if (!ok || encoded.empty()) {
261 if (!flush_to_disk(filepath, encoded)) {
281 std::vector<uint8_t> encoded;
282 const int ok = stbi_write_tga_to_func(
285 static_cast<int>(data.
width),
286 static_cast<int>(data.
height),
290 if (!ok || encoded.empty()) {
296 if (!flush_to_disk(filepath, encoded)) {
317 m_last_error =
"HDR supports only 3 or 4 channels (got "
318 + std::to_string(data.
channels) +
")";
323 std::vector<uint8_t> encoded;
324 const int ok = stbi_write_hdr_to_func(
327 static_cast<int>(data.
width),
328 static_cast<int>(data.
height),
332 if (!ok || encoded.empty()) {
338 if (!flush_to_disk(filepath, encoded)) {
#define MF_INFO(comp, ctx,...)
#define MF_ERROR(comp, ctx,...)
static ImageWriterRegistry & instance()
bool write_bmp(const std::string &filepath, const ImageData &data)
bool can_write(const std::string &filepath) const override
Check whether this writer handles the given filepath.
static void register_with_registry()
Register this writer with the ImageWriterRegistry.
bool write_jpg(const std::string &filepath, const ImageData &data, const ImageWriteOptions &options)
bool write_png(const std::string &filepath, const ImageData &data, const ImageWriteOptions &options)
std::vector< std::string > get_supported_extensions() const override
File extensions handled by this writer (without dot).
bool write(const std::string &filepath, const ImageData &data, const ImageWriteOptions &options={}) override
Write image data to disk.
bool write_tga(const std::string &filepath, const ImageData &data)
bool write_hdr(const std::string &filepath, const ImageData &data)
std::string resolve_write_path(const std::string &filepath)
Anchor a relative output path to Config::SOURCE_DIR.
@ FileIO
Filesystem I/O operations.
@ Init
Engine/subsystem initialization.
@ IO
Networking, file handling, streaming.
bool is_consistent() const
Check that the active variant matches the declared format.
const std::vector< float > * as_float() const
const std::vector< uint8_t > * as_uint8() const
Typed accessors.
Raw image data loaded from file.
Configuration for image writing.