From dba0c78daf8948cc41570f878929419b59cd239b Mon Sep 17 00:00:00 2001 From: lisyarus Date: Sun, 30 Aug 2020 21:20:01 +0300 Subject: [PATCH] Support reading PBM images & fix all Netpbm readers --- libs/gfx/include/psemek/gfx/pixmap.hpp | 1 + libs/gfx/source/pixmap.cpp | 78 +++++++++++++++++++++++++- 2 files changed, 77 insertions(+), 2 deletions(-) diff --git a/libs/gfx/include/psemek/gfx/pixmap.hpp b/libs/gfx/include/psemek/gfx/pixmap.hpp index e292dee0..7ae7fffa 100644 --- a/libs/gfx/include/psemek/gfx/pixmap.hpp +++ b/libs/gfx/include/psemek/gfx/pixmap.hpp @@ -58,6 +58,7 @@ namespace psemek::gfx using pixmap_rgba = basic_pixmap; using pixmap_float = basic_pixmap; + pixmap_monochrome read_pbm(std::istream & is); pixmap_monochrome read_pgm(std::istream & is); pixmap_rgb read_ppm(std::istream & is); diff --git a/libs/gfx/source/pixmap.cpp b/libs/gfx/source/pixmap.cpp index 717438fd..a6e5cf91 100644 --- a/libs/gfx/source/pixmap.cpp +++ b/libs/gfx/source/pixmap.cpp @@ -1,10 +1,70 @@ #include #include +#include +#include namespace psemek::gfx { + pixmap_monochrome read_pbm(std::istream & is) + { + auto fail = [](std::string str) + { + throw std::runtime_error("Error loading PBM image: " + str); + }; + + std::string line; + std::getline(is, line); + + bool binary = true; + + if (line == "P1") + { + binary = false; + } + else if (line == "P4") + { + binary = true; + } + else + fail("unknown format " + line); + + if (!binary) + fail("P1 format is not supported"); + + std::getline(is, line); + std::istringstream sline(line); + + std::size_t width, height; + pixmap_monochrome pixmap; + + sline >> width >> height; + + pixmap.resize(width, height); + + std::size_t bytes = width * height; + if ((bytes % 8) == 0) + bytes = bytes / 8; + else + bytes = (bytes + 7) / 8; + std::vector data(bytes); + is.read(reinterpret_cast(data.data()), bytes); + + for (std::size_t i = 0; i < width * height; ++i) + { + std::size_t b = i / 8; + std::size_t o = 7 - (i % 8); + bool const white = (data[b] & (1 << o)) == 0; + pixmap.data()[i] = white ? 255 : 0; + } + + if (!is) + fail("stream error"); + + return pixmap; + } + pixmap_monochrome read_pgm(std::istream & is) { auto fail = [](std::string str) @@ -28,11 +88,18 @@ namespace psemek::gfx else fail("unknown format " + line); + std::getline(is, line); + std::istringstream sline(line); + std::size_t width, height; std::size_t max; pixmap_monochrome pixmap; - is >> width >> height >> max; + sline >> width >> height; + + std::getline(is, line); + sline.str(line); + sline >> max; if (max != 255) fail("max value " + std::to_string(max) + " is not supported"); @@ -73,11 +140,18 @@ namespace psemek::gfx else fail("unknown format " + line); + std::getline(is, line); + std::istringstream sline(line); + std::size_t width, height; std::size_t max; pixmap_rgb pixmap; - is >> width >> height >> max; + sline >> width >> height; + + std::getline(is, line); + sline.str(line); + sline >> max; if (max != 255) fail("max value " + std::to_string(max) + " is not supported");