29 #include "table/strings.h"
74 #if defined(_MSC_VER) || defined(__WATCOMC__)
87 #if defined(_MSC_VER) || defined(__WATCOMC__)
95 uint16 planes, bitcount;
96 uint32 compression, sizeimage, xpels, ypels, clrused, clrimp;
102 byte blue, green, red, reserved;
104 assert_compile(
sizeof(
RgbQuad) == 4);
121 switch (pixelformat) {
122 case 8: bpp = 1;
break;
124 case 32: bpp = 3;
break;
126 default:
return false;
129 FILE *f = fopen(name,
"wb");
130 if (f == NULL)
return false;
133 uint bytewidth =
Align(w * bpp, 4);
136 uint pal_size = pixelformat == 8 ?
sizeof(
RgbQuad) * 256 : 0;
140 bfh.type = TO_LE16(
'MB');
148 bih.width = TO_LE32(w);
149 bih.height = TO_LE32(h);
150 bih.planes = TO_LE16(1);
151 bih.bitcount = TO_LE16(bpp * 8);
160 if (fwrite(&bfh,
sizeof(bfh), 1, f) != 1 || fwrite(&bih,
sizeof(bih), 1, f) != 1) {
165 if (pixelformat == 8) {
168 for (uint i = 0; i < 256; i++) {
169 rq[i].red = palette[i].r;
170 rq[i].green = palette[i].g;
171 rq[i].blue = palette[i].b;
175 if (fwrite(rq,
sizeof(rq), 1, f) != 1) {
182 uint maxlines =
Clamp(65536 / (w * pixelformat / 8), 16, 128);
184 uint8 *buff = MallocT<uint8>(maxlines * w * pixelformat / 8);
185 uint8 *line =
AllocaM(uint8, bytewidth);
186 memset(line, 0, bytewidth);
190 uint n =
min(h, maxlines);
194 callb(userdata, buff, h, w, n);
198 if (pixelformat == 8) {
200 memcpy(line, buff + n * w, w);
206 for (uint i = 0; i < w; i++) {
207 dst[i * 3 ] = src[i].b;
208 dst[i * 3 + 1] = src[i].g;
209 dst[i * 3 + 2] = src[i].r;
213 if (fwrite(line, bytewidth, 1, f) != 1) {
230 #if defined(WITH_PNG)
233 #ifdef PNG_TEXT_SUPPORTED
241 static void PNGAPI
png_my_error(png_structp png_ptr, png_const_charp message)
243 DEBUG(misc, 0,
"[libpng] error: %s - %s", message, (
const char *)png_get_error_ptr(png_ptr));
244 longjmp(png_jmpbuf(png_ptr), 1);
247 static void PNGAPI
png_my_warning(png_structp png_ptr, png_const_charp message)
249 DEBUG(misc, 1,
"[libpng] warning: %s - %s", message, (
const char *)png_get_error_ptr(png_ptr));
270 uint bpp = pixelformat / 8;
275 if (pixelformat != 8 && pixelformat != 32)
return false;
277 f = fopen(name,
"wb");
278 if (f == NULL)
return false;
282 if (png_ptr == NULL) {
287 info_ptr = png_create_info_struct(png_ptr);
288 if (info_ptr == NULL) {
289 png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
294 if (setjmp(png_jmpbuf(png_ptr))) {
295 png_destroy_write_struct(&png_ptr, &info_ptr);
300 png_init_io(png_ptr, f);
302 png_set_filter(png_ptr, 0, PNG_FILTER_NONE);
304 png_set_IHDR(png_ptr, info_ptr, w, h, 8, pixelformat == 8 ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_RGB,
305 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
307 #ifdef PNG_TEXT_SUPPORTED
310 png_text_struct text[2];
311 memset(text, 0,
sizeof(text));
312 text[0].key =
const_cast<char *
>(
"Software");
313 text[0].text =
const_cast<char *
>(_openttd_revision);
314 text[0].text_length = strlen(_openttd_revision);
315 text[0].compression = PNG_TEXT_COMPRESSION_NONE;
328 FOR_ALL_COMPANIES(c) {
329 if (c->ai_info == NULL) {
335 text[1].key =
const_cast<char *
>(
"Description");
337 text[1].text_length = p - buf;
338 text[1].compression = PNG_TEXT_COMPRESSION_zTXt;
339 png_set_text(png_ptr, info_ptr, text, 2);
342 if (pixelformat == 8) {
344 for (i = 0; i != 256; i++) {
345 rq[i].red = palette[i].r;
346 rq[i].green = palette[i].g;
347 rq[i].blue = palette[i].b;
350 png_set_PLTE(png_ptr, info_ptr, rq, 256);
353 png_write_info(png_ptr, info_ptr);
354 png_set_flush(png_ptr, 512);
356 if (pixelformat == 32) {
365 png_set_sBIT(png_ptr, info_ptr, &sig_bit);
367 #if TTD_ENDIAN == TTD_LITTLE_ENDIAN
368 png_set_bgr(png_ptr);
369 png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
371 png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
376 maxlines =
Clamp(65536 / w, 16, 128);
379 void *buff = CallocT<uint8>(w * maxlines * bpp);
384 n =
min(h - y, maxlines);
387 callb(userdata, buff, y, w, n);
391 for (i = 0; i != n; i++) {
392 png_write_row(png_ptr, (png_bytep)buff + i * w * bpp);
396 png_write_end(png_ptr, info_ptr);
397 png_destroy_write_struct(&png_ptr, &info_ptr);
419 byte pal_small[16 * 3];
428 assert_compile(
sizeof(
PcxHeader) == 128);
450 if (pixelformat == 32) {
451 DEBUG(misc, 0,
"Can't convert a 32bpp screenshot to PCX format. Please pick another format.");
454 if (pixelformat != 8 || w == 0)
return false;
456 f = fopen(name,
"wb");
457 if (f == NULL)
return false;
459 memset(&pcx, 0,
sizeof(pcx));
462 pcx.manufacturer = 10;
466 pcx.xmax = TO_LE16(w - 1);
467 pcx.ymax = TO_LE16(h - 1);
468 pcx.hdpi = TO_LE16(320);
469 pcx.vdpi = TO_LE16(320);
472 pcx.cpal = TO_LE16(1);
473 pcx.width = pcx.pitch = TO_LE16(w);
474 pcx.height = TO_LE16(h);
477 if (fwrite(&pcx,
sizeof(pcx), 1, f) != 1) {
483 maxlines =
Clamp(65536 / w, 16, 128);
486 uint8 *buff = CallocT<uint8>(w * maxlines);
491 uint n =
min(h - y, maxlines);
495 callb(userdata, buff, y, w, n);
499 for (i = 0; i != n; i++) {
500 const uint8 *bufp = buff + i * w;
501 byte runchar = bufp[0];
506 for (j = 1; j < w; j++) {
509 if (ch != runchar || runcount >= 0x3f) {
510 if (runcount > 1 || (runchar & 0xC0) == 0xC0) {
511 if (fputc(0xC0 | runcount, f) == EOF) {
517 if (fputc(runchar, f) == EOF) {
529 if (runcount > 1 || (runchar & 0xC0) == 0xC0) {
530 if (fputc(0xC0 | runcount, f) == EOF) {
536 if (fputc(runchar, f) == EOF) {
547 if (fputc(12, f) == EOF) {
555 for (uint i = 0; i < 256; i++) {
556 tmp[i * 3 + 0] = palette[i].r;
557 tmp[i * 3 + 1] = palette[i].g;
558 tmp[i * 3 + 2] = palette[i].b;
560 success = fwrite(tmp,
sizeof(tmp), 1, f) == 1;
573 #if defined(WITH_PNG)
590 for (uint i = 0; i <
lengthof(_screenshot_formats); i++) {
607 void *src = blitter->
MoveTo(_screen.dst_ptr, 0, y);
629 _screen.dst_ptr = buf;
630 _screen.width = pitch;
632 _screen.pitch = pitch;
640 dpi.width = vp->
width;
648 while (vp->
width - left != 0) {
663 _screen = old_screen;
674 static const char *
MakeScreenshotName(
const char *default_fn,
const char *ext,
bool crashlog =
false)
692 for (uint serial = 1;; serial++) {
698 if (!generate)
break;
782 byte *buf = (byte *)buffer;
785 for (uint x =
MapMaxX();
true; x--) {
803 for (uint i = 0; i <
lengthof(palette); i++) {