208 lines
3.9 KiB
C++
208 lines
3.9 KiB
C++
#include <psemek/gfx/pixmap.hpp>
|
|
#include <psemek/util/exception.hpp>
|
|
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <vector>
|
|
|
|
namespace psemek::gfx
|
|
{
|
|
|
|
pixmap_monochrome read_pbm(std::istream & is)
|
|
{
|
|
auto fail = [](std::string str)
|
|
{
|
|
throw util::exception("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);
|
|
if (!is)
|
|
fail("stream error");
|
|
std::istringstream sline(line);
|
|
|
|
std::size_t width, height;
|
|
pixmap_monochrome pixmap;
|
|
|
|
sline >> width >> height;
|
|
if (!sline)
|
|
fail("stream error");
|
|
|
|
pixmap.resize({width, height});
|
|
|
|
std::size_t bytes = width * height;
|
|
if ((bytes % 8) == 0)
|
|
bytes = bytes / 8;
|
|
else
|
|
bytes = (bytes + 7) / 8;
|
|
std::vector<std::uint8_t> data(bytes);
|
|
is.read(reinterpret_cast<char *>(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)
|
|
{
|
|
throw util::exception("Error loading PGM image: " + str);
|
|
};
|
|
|
|
std::string line;
|
|
std::getline(is, line);
|
|
|
|
bool binary = true;
|
|
|
|
if (line == "P2")
|
|
{
|
|
binary = false;
|
|
}
|
|
else if (line == "P5")
|
|
{
|
|
binary = true;
|
|
}
|
|
else
|
|
fail("unknown format " + line);
|
|
|
|
std::getline(is, line);
|
|
if (!is)
|
|
fail("stream error");
|
|
std::istringstream sline(line);
|
|
|
|
std::size_t width, height;
|
|
std::size_t max;
|
|
pixmap_monochrome pixmap;
|
|
|
|
sline >> width >> height;
|
|
if (!sline)
|
|
fail("stream error");
|
|
|
|
std::getline(is, line);
|
|
if (!is)
|
|
fail("stream error");
|
|
sline.clear();
|
|
sline.str(line);
|
|
sline >> max;
|
|
if (!sline)
|
|
fail("stream error");
|
|
|
|
if (max != 255)
|
|
fail("max value " + std::to_string(max) + " is not supported");
|
|
|
|
pixmap.resize({width, height});
|
|
|
|
if (binary)
|
|
is.read(reinterpret_cast<char *>(pixmap.data()), width * height * sizeof(pixmap.data()[0]));
|
|
else
|
|
fail("P2 format is not supported");
|
|
|
|
if (!is)
|
|
fail("stream error");
|
|
|
|
return pixmap;
|
|
}
|
|
|
|
pixmap_rgb read_ppm(std::istream & is)
|
|
{
|
|
auto fail = [](std::string str)
|
|
{
|
|
throw util::exception("Error loading PPM image: " + str);
|
|
};
|
|
|
|
std::string line;
|
|
std::getline(is, line);
|
|
|
|
bool binary = true;
|
|
|
|
if (line == "P3")
|
|
{
|
|
binary = false;
|
|
}
|
|
else if (line == "P6")
|
|
{
|
|
binary = true;
|
|
}
|
|
else
|
|
fail("unknown format " + line);
|
|
|
|
std::getline(is, line);
|
|
if (!is)
|
|
fail("stream error");
|
|
std::istringstream sline(line);
|
|
|
|
std::size_t width, height;
|
|
std::size_t max;
|
|
pixmap_rgb pixmap;
|
|
|
|
sline >> width >> height;
|
|
|
|
if (!sline)
|
|
fail("stream error");
|
|
|
|
std::getline(is, line);
|
|
if (!is)
|
|
fail("stream error");
|
|
sline.clear();
|
|
sline.str(line);
|
|
sline >> max;
|
|
if (!sline)
|
|
fail("stream error");
|
|
|
|
if (max != 255)
|
|
fail("max value " + std::to_string(max) + " is not supported");
|
|
|
|
pixmap.resize({width, height});
|
|
|
|
if (binary)
|
|
is.read(reinterpret_cast<char *>(pixmap.data()), width * height * sizeof(pixmap.data()[0]));
|
|
else
|
|
fail("P3 format is not supported");
|
|
|
|
if (!is)
|
|
fail("stream error");
|
|
|
|
return pixmap;
|
|
}
|
|
|
|
void write_pgm(pixmap_monochrome const & p, std::ostream & os)
|
|
{
|
|
os << "P5\n" << p.width() << " " << p.height() << "\n255\n";
|
|
os.write(reinterpret_cast<char const *>(p.data()), p.width() * p.height() * sizeof(p.data()[0]));
|
|
}
|
|
|
|
void write_ppm(pixmap_rgb const & p, std::ostream & os)
|
|
{
|
|
os << "P6\n" << p.width() << " " << p.height() << "\n255\n";
|
|
os.write(reinterpret_cast<char const *>(p.data()), p.width() * p.height() * sizeof(p.data()[0]));
|
|
}
|
|
|
|
}
|