Support png image loading

This commit is contained in:
Nikita Lisitsa 2021-02-27 19:09:14 +03:00
parent de4a661009
commit 08d6469311
2 changed files with 75 additions and 0 deletions

View file

@ -23,4 +23,6 @@ namespace psemek::gfx
void write_pgm(pixmap_monochrome const & p, std::ostream & os);
void write_ppm(pixmap_rgb const & p, std::ostream & os);
pixmap_rgba read_png(std::istream & is);
}

73
libs/gfx/source/png.cpp Normal file
View file

@ -0,0 +1,73 @@
#include <psemek/gfx/pixmap.hpp>
#include <psemek/log/log.hpp>
#include <psemek/util/at_scope_exit.hpp>
#include <vector>
#include <png.h>
namespace psemek::gfx
{
pixmap_rgba read_png(std::istream & is)
{
png_error_ptr error = [](png_structp, png_const_charp str)
{
throw std::runtime_error(str);
};
png_error_ptr warn = [](png_structp, png_const_charp str)
{
log::warning() << str;
};
auto png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, error, warn);
if (!png) throw std::runtime_error("png_create_read_struct returned null");
png_set_error_fn(png, nullptr, error, warn);
png_infop info = nullptr;
png_infop end_info = nullptr;
[[maybe_unused]] auto png_dtor = util::at_scope_exit([&]{
png_destroy_read_struct(&png, &info, &end_info);
});
info = png_create_info_struct(png);
if (!info) throw std::runtime_error("png_create_info_struct returned null");
end_info = png_create_info_struct(png);
if (!end_info) throw std::runtime_error("png_create_info_struct returned null");
png_rw_ptr read = [](png_structp png, png_bytep ptr, size_t count){
reinterpret_cast<std::istream *>(png_get_io_ptr(png))->read(reinterpret_cast<char *>(ptr), count);
};
png_set_read_fn(png, &is, read);
png_read_info(png, info);
auto const width = png_get_image_width(png, info);
auto const height = png_get_image_height(png, info);
auto const color_type = png_get_color_type(png, info);
auto const bit_depth = png_get_bit_depth(png, info);
if (color_type != PNG_COLOR_TYPE_RGBA)
throw std::runtime_error("PNG color types other than RGBA are not supported");
if (bit_depth != 8)
throw std::runtime_error("PNG bit depths other than 8 are not supported");
pixmap_rgba result({width, height});
auto const row_bytes = png_get_rowbytes(png, info);
if (row_bytes != width * 4)
throw std::runtime_error("PNG row bytes is wrong");
for (std::uint32_t i = 0; i < height; ++i)
png_read_row(png, reinterpret_cast<png_bytep>(result.data() + i * width), nullptr);
return result;
}
}