34 bool MakeImage(std::string_view name,
const ScreenshotCallback &callb, uint w, uint h,
int pixelformat,
const Colour *palette)
override
39 uint bpp = pixelformat / 8;
44 if (pixelformat != 8 && pixelformat != 32)
return false;
47 if (!of.has_value())
return false;
50 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, &name, png_my_error, png_my_warning);
52 if (png_ptr ==
nullptr) {
56 info_ptr = png_create_info_struct(png_ptr);
57 if (info_ptr ==
nullptr) {
58 png_destroy_write_struct(&png_ptr, (png_infopp)
nullptr);
62 if (setjmp(png_jmpbuf(png_ptr))) {
63 png_destroy_write_struct(&png_ptr, &info_ptr);
67 png_init_io(png_ptr, f);
69 png_set_filter(png_ptr, 0, PNG_FILTER_NONE);
71 png_set_IHDR(png_ptr, info_ptr, w, h, 8, pixelformat == 8 ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_RGB,
72 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
74#ifdef PNG_TEXT_SUPPORTED
78 png_text_struct text[2]{};
79 text[0].key =
const_cast<char *
>(
"Software");
80 text[0].text =
const_cast<char *
>(_openttd_revision.c_str());
81 text[0].text_length = _openttd_revision.size();
82 text[0].compression = PNG_TEXT_COMPRESSION_NONE;
85 message.reserve(1024);
87 message +=
"NewGRFs:\n";
88 if (_game_mode != GM_MENU) {
90 format_append(message,
"{:08X} {} {}\n", std::byteswap(c->ident.grfid),
FormatArrayAsHex(c->ident.md5sum), c->filename);
93 message +=
"\nCompanies:\n";
95 if (c->ai_info ==
nullptr) {
96 format_append(message,
"{:2d}: Human\n", c->index);
98 format_append(message,
"{:2d}: {} (v{})\n", c->index, c->ai_info->GetName(), c->ai_info->GetVersion());
101 text[1].key =
const_cast<char *
>(
"Description");
102 text[1].text =
const_cast<char *
>(message.c_str());
103 text[1].text_length = message.size();
104 text[1].compression = PNG_TEXT_COMPRESSION_zTXt;
105 png_set_text(png_ptr, info_ptr, text, 2);
109 if (pixelformat == 8) {
111 for (i = 0; i != 256; i++) {
112 rq[i].red = palette[i].r;
113 rq[i].green = palette[i].g;
114 rq[i].blue = palette[i].b;
117 png_set_PLTE(png_ptr, info_ptr, rq, 256);
120 png_write_info(png_ptr, info_ptr);
121 png_set_flush(png_ptr, 512);
123 if (pixelformat == 32) {
132 png_set_sBIT(png_ptr, info_ptr, &sig_bit);
134 if constexpr (std::endian::native == std::endian::little) {
135 png_set_bgr(png_ptr);
136 png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
138 png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
143 maxlines =
Clamp(65536 / w, 16, 128);
146 std::vector<uint8_t> buff(
static_cast<size_t>(w) * maxlines * bpp);
151 n = std::min(h - y, maxlines);
154 callb(buff.data(), y, w, n);
158 for (i = 0; i != n; i++) {
159 png_write_row(png_ptr, (png_bytep)buff.data() + i * w * bpp);
163 png_write_end(png_ptr, info_ptr);
164 png_destroy_write_struct(&png_ptr, &info_ptr);
170 static void PNGAPI png_my_error(png_structp png_ptr, png_const_charp message)
172 Debug(misc, 0,
"[libpng] error: {} - {}", message, *
static_cast<std::string_view *
>(png_get_error_ptr(png_ptr)));
173 longjmp(png_jmpbuf(png_ptr), 1);
176 static void PNGAPI png_my_warning(png_structp png_ptr, png_const_charp message)
178 Debug(misc, 1,
"[libpng] warning: {} - {}", message, *
static_cast<std::string_view *
>(png_get_error_ptr(png_ptr)));