#include #include #include #include namespace psemek::gfx { template basic_pixmap read_image(io::istream && is) { stbi_io_callbacks callbacks; callbacks.read = [](void * user, char * data, int size) -> int { return reinterpret_cast(user)->read(data, size); }; callbacks.skip = [](void * user, int count) { if (count < 0) throw util::exception("unget is not supported in stb_image skip callback"); char buffer[1024]; while (count > 0) { int read_count = std::min(1024, count); count -= reinterpret_cast(user)->read(buffer, read_count); } }; callbacks.eof = [](void * user) { return reinterpret_cast(user)->finished() ? 1 : 0; }; int width, height, channels; auto data = stbi_load_from_callbacks(&callbacks, &is, &width, &height, &channels, sizeof(Pixel)); if (!data) throw util::exception(stbi_failure_reason()); basic_pixmap result({width, height}); std::copy(data, data + width * height * sizeof(Pixel), reinterpret_cast(result.data())); stbi_image_free(data); return result; } template pixmap_monochrome read_image(io::istream && is); template pixmap_rgb read_image(io::istream && is); template pixmap_rgba read_image(io::istream && is); namespace { void write_func(void * context, void * data, int size) { reinterpret_cast(context)->write(reinterpret_cast(data), size); } } void write_image_png(pixmap_monochrome const & p, io::ostream && os) { if (stbi_write_png_to_func(write_func, &os, p.width(), p.height(), 1, p.data(), p.width() * 1) == 0) throw util::exception("Failed to write monochrome png"); } void write_image_png(pixmap_rgb const & p, io::ostream && os) { if (stbi_write_png_to_func(write_func, &os, p.width(), p.height(), 3, p.data(), p.width() * 3) == 0) throw util::exception("Failed to write rgb png"); } void write_image_png(pixmap_rgba const & p, io::ostream && os) { if (stbi_write_png_to_func(write_func, &os, p.width(), p.height(), 4, p.data(), p.width() * 4) == 0) throw util::exception("Failed to write rgba png"); } void write_image_tga(pixmap_monochrome const & p, io::ostream && os) { if (stbi_write_tga_to_func(write_func, &os, p.width(), p.height(), 1, p.data()) == 0) throw util::exception("Failed to write monochrome tga"); } void write_image_tga(pixmap_rgb const & p, io::ostream && os) { if (stbi_write_tga_to_func(write_func, &os, p.width(), p.height(), 3, p.data()) == 0) throw util::exception("Failed to write rgb tga"); } void write_image_tga(pixmap_rgba const & p, io::ostream && os) { if (stbi_write_tga_to_func(write_func, &os, p.width(), p.height(), 4, p.data()) == 0) throw util::exception("Failed to write rgba tga"); } void write_image_bmp(pixmap_rgb const & p, io::ostream && os) { if (stbi_write_bmp_to_func(write_func, &os, p.width(), p.height(), 3, p.data()) == 0) throw util::exception("Failed to write rgb bmp"); } void write_image_jpg(pixmap_rgb const & p, io::ostream && os, int quality) { if (stbi_write_jpg_to_func(write_func, &os, p.width(), p.height(), 3, p.data(), quality) == 0) throw util::exception("Failed to write rgb jpg"); } void write_image_hdr(basic_pixmap const & p, io::ostream && os) { if (stbi_write_hdr_to_func(write_func, &os, p.width(), p.height(), 1, reinterpret_cast(p.data())) == 0) throw util::exception("Failed to write rgb hdr"); } void write_image_pgm(pixmap_monochrome const & p, io::ostream && os) { char header_buffer[256]; int header_size = std::snprintf(header_buffer, 256, "P5\n%lu %lu\n255\n", (unsigned long)p.width(), (unsigned long)p.height()); os.write(header_buffer, header_size); os.write(reinterpret_cast(p.data()), p.width() * p.height()); } void write_image_ppm(pixmap_rgb const & p, io::ostream && os) { char header_buffer[256]; int header_size = std::snprintf(header_buffer, 256, "P6\n%lu %lu\n255\n", (unsigned long)p.width(), (unsigned long)p.height()); os.write(header_buffer, header_size); os.write(reinterpret_cast(p.data()), p.width() * p.height() * 3); } }