5#define STB_IMAGE_WRITE_IMPLEMENTATION
8#if __has_include("stb/stb_image_write.h")
9#include "stb/stb_image_write.h"
10#elif __has_include("stb_image_write.h")
11#include "stb_image_write.h"
13#error "stb_image_write.h not found"
22 std::string extension_of(
const std::string& filepath)
24 auto ext = std::filesystem::path(filepath).extension().string();
25 if (!ext.empty() && ext[0] ==
'.') {
28 std::ranges::transform(ext, ext.begin(),
29 [](
unsigned char c) { return std::tolower(c); });
36 void stbi_memory_writer(
void* context,
void* data,
int size)
38 auto* buf =
static_cast<std::vector<uint8_t>*
>(context);
39 const auto* bytes =
static_cast<const uint8_t*
>(data);
40 buf->insert(buf->end(), bytes, bytes +
size);
46 bool flush_to_disk(
const std::string& filepath,
const std::vector<uint8_t>& buffer)
48 std::ofstream out(filepath, std::ios::binary | std::ios::trunc);
52 out.write(
reinterpret_cast<const char*
>(buffer.data()),
53 static_cast<std::streamsize
>(buffer.size()));
67 {
"png",
"jpg",
"jpeg",
"bmp",
"tga",
"hdr" },
68 []() -> std::unique_ptr<ImageWriter> {
69 return std::make_unique<STBImageWriter>();
73 "STBImageWriter registered for: png, jpg, jpeg, bmp, tga, hdr");
82 const auto ext = extension_of(filepath);
83 static const std::vector<std::string> supported = {
84 "png",
"jpg",
"jpeg",
"bmp",
"tga",
"hdr"
86 return std::ranges::find(supported, ext) != supported.end();
91 return {
"png",
"jpg",
"jpeg",
"bmp",
"tga",
"hdr" };
95 const std::string& filepath,
102 m_last_error =
"ImageData variant does not match declared ImageFormat";
113 const auto ext = extension_of(filepath);
116 return write_png(filepath, data, options);
117 if (ext ==
"jpg" || ext ==
"jpeg")
118 return write_jpg(filepath, data, options);
136 const std::string& filepath,
150 stbi_write_png_compression_level = compression;
153 std::vector<uint8_t> encoded;
156 const int stride =
static_cast<int>(data.
width * data.
channels);
157 const int ok = stbi_write_png_to_func(
160 static_cast<int>(data.
width),
161 static_cast<int>(data.
height),
166 if (!ok || encoded.empty()) {
172 if (!flush_to_disk(filepath, encoded)) {
179 "Wrote PNG: {} ({}x{}, {} channels, {} bytes)",
185 const std::string& filepath,
197 m_last_error =
"JPG supports only 1 or 3 channels (got "
198 + std::to_string(data.
channels) +
")";
203 const int quality = std::clamp(options.
quality, 1, 100);
206 std::vector<uint8_t> encoded;
207 const int ok = stbi_write_jpg_to_func(
210 static_cast<int>(data.
width),
211 static_cast<int>(data.
height),
216 if (!ok || encoded.empty()) {
222 if (!flush_to_disk(filepath, encoded)) {
229 "Wrote JPG: {} ({}x{}, quality {}, {} bytes)",
230 filepath, data.
width, data.
height, quality, encoded.size());
243 std::vector<uint8_t> encoded;
244 const int ok = stbi_write_bmp_to_func(
247 static_cast<int>(data.
width),
248 static_cast<int>(data.
height),
252 if (!ok || encoded.empty()) {
258 if (!flush_to_disk(filepath, encoded)) {
278 std::vector<uint8_t> encoded;
279 const int ok = stbi_write_tga_to_func(
282 static_cast<int>(data.
width),
283 static_cast<int>(data.
height),
287 if (!ok || encoded.empty()) {
293 if (!flush_to_disk(filepath, encoded)) {
314 m_last_error =
"HDR supports only 3 or 4 channels (got "
315 + std::to_string(data.
channels) +
")";
320 std::vector<uint8_t> encoded;
321 const int ok = stbi_write_hdr_to_func(
324 static_cast<int>(data.
width),
325 static_cast<int>(data.
height),
329 if (!ok || encoded.empty()) {
335 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)
@ 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.