From 08d646931187b30211f725a7e794a2efb1c02332 Mon Sep 17 00:00:00 2001 From: lisyarus Date: Sat, 27 Feb 2021 19:09:14 +0300 Subject: [PATCH] Support png image loading --- libs/gfx/include/psemek/gfx/pixmap.hpp | 2 + libs/gfx/source/png.cpp | 73 ++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 libs/gfx/source/png.cpp diff --git a/libs/gfx/include/psemek/gfx/pixmap.hpp b/libs/gfx/include/psemek/gfx/pixmap.hpp index c0624175..353a6e69 100644 --- a/libs/gfx/include/psemek/gfx/pixmap.hpp +++ b/libs/gfx/include/psemek/gfx/pixmap.hpp @@ -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); + } diff --git a/libs/gfx/source/png.cpp b/libs/gfx/source/png.cpp new file mode 100644 index 00000000..80199aef --- /dev/null +++ b/libs/gfx/source/png.cpp @@ -0,0 +1,73 @@ +#include + +#include +#include + +#include + +#include + +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(png_get_io_ptr(png))->read(reinterpret_cast(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(result.data() + i * width), nullptr); + + return result; + } + +}