Add SaveImageResource implementation for libpng
This commit is contained in:
parent
7bdeb96649
commit
84cedb4fed
@ -4255,6 +4255,102 @@ namespace olc
|
|||||||
|
|
||||||
olc::rcode SaveImageResource(const olc::Sprite* spr, const std::string& sImageFile) override
|
olc::rcode SaveImageResource(const olc::Sprite* spr, const std::string& sImageFile) override
|
||||||
{
|
{
|
||||||
|
if (spr == nullptr)
|
||||||
|
return olc::rcode::FAIL;
|
||||||
|
|
||||||
|
// RAII wrapper for FILE pointer
|
||||||
|
struct FileWrapper
|
||||||
|
{
|
||||||
|
FILE* f = nullptr;
|
||||||
|
|
||||||
|
FileWrapper(const std::string& sImageFile)
|
||||||
|
{
|
||||||
|
f = fopen(sImageFile.c_str(), "wb");
|
||||||
|
}
|
||||||
|
|
||||||
|
FileWrapper(const FileWrapper&) = delete;
|
||||||
|
FileWrapper(FileWrapper&&) = delete;
|
||||||
|
FileWrapper& operator=(const FileWrapper&) = delete;
|
||||||
|
FileWrapper& operator=(FileWrapper&&) = delete;
|
||||||
|
|
||||||
|
~FileWrapper()
|
||||||
|
{
|
||||||
|
if (f != nullptr)
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Good() const
|
||||||
|
{
|
||||||
|
return f != nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// RAII wrapper for png_struct and png_info pointers
|
||||||
|
struct PNGStructWrapper
|
||||||
|
{
|
||||||
|
struct PNGError
|
||||||
|
{};
|
||||||
|
|
||||||
|
png_structp png_ptr = nullptr;
|
||||||
|
png_infop info_ptr = nullptr;
|
||||||
|
|
||||||
|
PNGStructWrapper()
|
||||||
|
{
|
||||||
|
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, PNGStructWrapper::user_error_handling_func, PNGStructWrapper::user_warn_func);
|
||||||
|
if (png_ptr != nullptr)
|
||||||
|
info_ptr = png_create_info_struct(png_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
PNGStructWrapper(const PNGStructWrapper&) = delete;
|
||||||
|
PNGStructWrapper(PNGStructWrapper&&) = delete;
|
||||||
|
PNGStructWrapper& operator=(const PNGStructWrapper&) = delete;
|
||||||
|
PNGStructWrapper& operator=(PNGStructWrapper&&) = delete;
|
||||||
|
|
||||||
|
~PNGStructWrapper()
|
||||||
|
{
|
||||||
|
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Good() const
|
||||||
|
{
|
||||||
|
return png_ptr != nullptr && info_ptr != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void user_error_handling_func(png_structp, png_const_charp error_msg) {
|
||||||
|
fprintf(stderr, "%s\n", error_msg);
|
||||||
|
throw PNGError{}; // Function must not return control to caller
|
||||||
|
}
|
||||||
|
static void user_warn_func(png_structp, png_const_charp warning_msg) {
|
||||||
|
fprintf(stderr, "%s\n", warning_msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
FileWrapper file(sImageFile);
|
||||||
|
if (!file.Good())
|
||||||
|
{
|
||||||
|
return olc::rcode::FAIL;
|
||||||
|
}
|
||||||
|
PNGStructWrapper png;
|
||||||
|
if (!png.Good())
|
||||||
|
{
|
||||||
|
return olc::rcode::FAIL;
|
||||||
|
}
|
||||||
|
png_init_io(png.png_ptr, file.f);
|
||||||
|
png_set_IHDR(png.png_ptr, png.info_ptr, spr->width, spr->height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
||||||
|
std::unique_ptr<png_bytep[]> png_rows = std::make_unique<png_bytep[]>(spr->height);
|
||||||
|
for (int y = 0; y < spr->height; y++)
|
||||||
|
png_rows[y] = (png_bytep)(spr->pColData.data() + std::ptrdiff_t(y) * spr->width);
|
||||||
|
|
||||||
|
png_set_rows(png.png_ptr, png.info_ptr, png_rows.get());
|
||||||
|
png_write_png(png.png_ptr, png.info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
|
||||||
|
}
|
||||||
|
catch (PNGStructWrapper::PNGError&)
|
||||||
|
{
|
||||||
|
return olc::rcode::FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
return olc::rcode::OK;
|
return olc::rcode::OK;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user