32 bool MakeImage(
const char *name,
ScreenshotCallback *callb,
void *userdata, uint w, uint h,
int pixelformat,
const Colour *palette)
override
37 uint bpp = pixelformat / 8;
42 if (pixelformat != 8 && pixelformat != 32)
return false;
45 if (!of.has_value())
return false;
48 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
const_cast<char *
>(name), png_my_error, png_my_warning);
50 if (png_ptr ==
nullptr) {
54 info_ptr = png_create_info_struct(png_ptr);
55 if (info_ptr ==
nullptr) {
56 png_destroy_write_struct(&png_ptr, (png_infopp)
nullptr);
60 if (setjmp(png_jmpbuf(png_ptr))) {
61 png_destroy_write_struct(&png_ptr, &info_ptr);
65 png_init_io(png_ptr, f);
67 png_set_filter(png_ptr, 0, PNG_FILTER_NONE);
69 png_set_IHDR(png_ptr, info_ptr, w, h, 8, pixelformat == 8 ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_RGB,
70 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
72#ifdef PNG_TEXT_SUPPORTED
76 png_text_struct text[2];
77 memset(text, 0,
sizeof(text));
78 text[0].key =
const_cast<char *
>(
"Software");
79 text[0].text =
const_cast<char *
>(_openttd_revision);
80 text[0].text_length = strlen(_openttd_revision);
81 text[0].compression = PNG_TEXT_COMPRESSION_NONE;
84 message.reserve(1024);
86 message +=
"NewGRFs:\n";
87 if (_game_mode != GM_MENU) {
89 fmt::format_to(std::back_inserter(message),
"{:08X} {} {}\n", std::byteswap(c->ident.grfid),
FormatArrayAsHex(c->ident.md5sum), c->filename);
92 message +=
"\nCompanies:\n";
94 if (c->ai_info ==
nullptr) {
95 fmt::format_to(std::back_inserter(message),
"{:2d}: Human\n", c->index);
97 fmt::format_to(std::back_inserter(message),
"{:2d}: {} (v{})\n", c->index, c->ai_info->GetName(), c->ai_info->GetVersion());
100 text[1].key =
const_cast<char *
>(
"Description");
101 text[1].text =
const_cast<char *
>(message.c_str());
102 text[1].text_length = message.size();
103 text[1].compression = PNG_TEXT_COMPRESSION_zTXt;
104 png_set_text(png_ptr, info_ptr, text, 2);
108 if (pixelformat == 8) {
110 for (i = 0; i != 256; i++) {
111 rq[i].red = palette[i].r;
112 rq[i].green = palette[i].g;
113 rq[i].blue = palette[i].b;
116 png_set_PLTE(png_ptr, info_ptr, rq, 256);
119 png_write_info(png_ptr, info_ptr);
120 png_set_flush(png_ptr, 512);
122 if (pixelformat == 32) {
131 png_set_sBIT(png_ptr, info_ptr, &sig_bit);
133 if constexpr (std::endian::native == std::endian::little) {
134 png_set_bgr(png_ptr);
135 png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
137 png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
142 maxlines =
Clamp(65536 / w, 16, 128);
145 std::vector<uint8_t> buff(
static_cast<size_t>(w) * maxlines * bpp);
150 n = std::min(h - y, maxlines);
153 callb(userdata, buff.data(), y, w, n);
157 for (i = 0; i != n; i++) {
158 png_write_row(png_ptr, (png_bytep)buff.data() + i * w * bpp);
162 png_write_end(png_ptr, info_ptr);
163 png_destroy_write_struct(&png_ptr, &info_ptr);
169 static void PNGAPI png_my_error(png_structp png_ptr, png_const_charp message)
171 Debug(misc, 0,
"[libpng] error: {} - {}", message, (
const char *)png_get_error_ptr(png_ptr));
172 longjmp(png_jmpbuf(png_ptr), 1);
175 static void PNGAPI png_my_warning(png_structp png_ptr, png_const_charp message)
177 Debug(misc, 1,
"[libpng] warning: {} - {}", message, (
const char *)png_get_error_ptr(png_ptr));