# HG changeset patch # User Michael Pavone # Date 1521945651 25200 # Node ID b505083dcd877cd00b2930ee010a25e88973784b # Parent 092675db4f372e2f6dcbdab6b07ecc277d4104b7 Added png screenshot support diff -r 092675db4f37 -r b505083dcd87 Makefile --- a/Makefile Sat Mar 24 15:33:44 2018 -0700 +++ b/Makefile Sat Mar 24 19:40:51 2018 -0700 @@ -136,7 +136,7 @@ ifdef NOZLIB CFLAGS+= -DDISABLE_ZLIB else -MAINOBJS+= $(LIBZOBJS) +MAINOBJS+= $(LIBZOBJS) png.o endif ifeq ($(CPU),x86_64) diff -r 092675db4f37 -r b505083dcd87 png.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/png.c Sat Mar 24 19:40:51 2018 -0700 @@ -0,0 +1,138 @@ +#include +#include +#include +#include "zlib/zlib.h" + +static const char png_magic[] = {0x89, 'P', 'N', 'G', '\r', '\n', 0x1A, '\n'}; +static const char ihdr[] = {'I', 'H', 'D', 'R'}; +static const char plte[] = {'P', 'L', 'T', 'E'}; +static const char idat[] = {'I', 'D', 'A', 'T'}; +static const char iend[] = {'I', 'E', 'N', 'D'}; + +enum { + COLOR_TRUE = 2, + COLOR_INDEXED +}; + +static void write_chunk(FILE *f, const char*id, uint8_t *buffer, uint32_t size) +{ + uint8_t tmp[4] = {size >> 24, size >> 16, size >> 8, size}; + uint8_t warn = 0; + warn = warn || (sizeof(tmp) != fwrite(tmp, 1, sizeof(tmp), f)); + warn = warn || (4 != fwrite(id, 1, 4, f)); + if (size) { + warn = warn || (size != fwrite(buffer, 1, size, f)); + } + + uint32_t crc = crc32(0, NULL, 0); + crc = crc32(crc, id, 4); + if (size) { + crc = crc32(crc, buffer, size); + } + tmp[0] = crc >> 24; + tmp[1] = crc >> 16; + tmp[2] = crc >> 8; + tmp[3] = crc; + warn = warn || (sizeof(tmp) != fwrite(tmp, 1, sizeof(tmp), f)); + if (warn) { + fprintf(stderr, "Failure during write of %c%c%c%c chunk\n", id[0], id[1], id[2], id[3]); + } +} + +static void write_header(FILE *f, uint32_t width, uint32_t height, uint8_t color_type) +{ + uint8_t chunk[13] = { + width >> 24, width >> 16, width >> 8, width, + height >> 24, height >> 16, height >> 8, height, + 8, color_type, 0, 0, 0 + }; + if (sizeof(png_magic) != fwrite(png_magic, 1, sizeof(png_magic), f)) { + fputs("Error writing PNG magic\n", stderr); + } + write_chunk(f, ihdr, chunk, sizeof(chunk)); +} + +void save_png24(FILE *f, uint32_t *buffer, uint32_t width, uint32_t height, uint32_t pitch) +{ + uint32_t idat_size = (1 + width*3) * height; + uint8_t *idat_buffer = malloc(idat_size); + uint32_t *pixel = buffer; + uint8_t *cur = idat_buffer; + for (uint32_t y = 0; y < height; y++) + { + //save filter type + *(cur++) = 0; + uint32_t *start = pixel; + for (uint32_t x = 0; x < width; x++, pixel++) + { + uint32_t value = *pixel; + *(cur++) = value >> 16; + *(cur++) = value >> 8; + *(cur++) = value; + } + pixel = start + pitch / sizeof(uint32_t); + } + write_header(f, width, height, COLOR_TRUE); + uLongf compress_buffer_size = idat_size + 5 * (idat_size/16383 + 1) + 3; + uint8_t *compressed = malloc(compress_buffer_size); + compress(compressed, &compress_buffer_size, idat_buffer, idat_size); + free(idat_buffer); + write_chunk(f, idat, compressed, compress_buffer_size); + write_chunk(f, iend, NULL, 0); + free(compressed); +} + +void save_png(FILE *f, uint32_t *buffer, uint32_t width, uint32_t height, uint32_t pitch) +{ + uint32_t palette[256]; + uint8_t pal_buffer[256*3]; + uint32_t num_pal = 0; + uint32_t index_size = (1 + width) * height; + uint8_t *index_buffer = malloc(index_size); + uint8_t *cur = index_buffer; + uint32_t *pixel = buffer; + for (uint32_t y = 0; y < height; y++) + { + //save filter type + *(cur++) = 0; + uint32_t *start = pixel; + for (uint32_t x = 0; x < width; x++, pixel++, cur++) + { + uint32_t value = (*pixel) & 0xFFFFFF; + uint32_t i; + for (i = 0; i < num_pal; i++) + { + if (palette[i] == value) { + break; + } + } + if (i == num_pal) { + if (num_pal == 256) { + free(index_buffer); + save_png24(f, buffer, width, height, pitch); + return; + } + palette[i] = value; + num_pal++; + } + *cur = i; + } + pixel = start + pitch / sizeof(uint32_t); + } + write_header(f, width, height, COLOR_INDEXED); + cur = pal_buffer; + for (uint32_t i = 0; i < num_pal; i++) + { + *(cur++) = palette[i] >> 16; + *(cur++) = palette[i] >> 8; + *(cur++) = palette[i]; + } + write_chunk(f, plte, pal_buffer, num_pal * 3); + uLongf compress_buffer_size = index_size + 5 * (index_size/16383 + 1) + 3; + uint8_t *compressed = malloc(compress_buffer_size); + compress(compressed, &compress_buffer_size, index_buffer, index_size); + free(index_buffer); + write_chunk(f, idat, compressed, compress_buffer_size); + write_chunk(f, iend, NULL, 0); + free(compressed); +} diff -r 092675db4f37 -r b505083dcd87 png.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/png.h Sat Mar 24 19:40:51 2018 -0700 @@ -0,0 +1,7 @@ +#ifndef PNG_H_ +#define PNG_H_ + +void save_png24(FILE *f, uint32_t *buffer, uint32_t width, uint32_t height, uint32_t pitch); +void save_png(FILE *f, uint32_t *buffer, uint32_t width, uint32_t height, uint32_t pitch); + +#endif //PNG_H_ diff -r 092675db4f37 -r b505083dcd87 render_sdl.c --- a/render_sdl.c Sat Mar 24 15:33:44 2018 -0700 +++ b/render_sdl.c Sat Mar 24 19:40:51 2018 -0700 @@ -13,6 +13,7 @@ #include "io.h" #include "util.h" #include "ppm.h" +#include "png.h" #ifndef DISABLE_OPENGL #include @@ -597,9 +598,13 @@ : 240; FILE *screenshot_file = NULL; uint32_t shot_height, shot_width; + char *ext; if (screenshot_path && which == FRAMEBUFFER_ODD) { screenshot_file = fopen(screenshot_path, "wb"); if (screenshot_file) { +#ifndef DISABLE_ZLIB + ext = path_extension(screenshot_path); +#endif info_message("Saving screenshot to %s\n", screenshot_path); } else { warning("Failed to open screenshot file %s for writing\n", screenshot_path); @@ -643,7 +648,17 @@ if (screenshot_file) { //properly supporting interlaced modes here is non-trivial, so only save the odd field for now - save_ppm(screenshot_file, texture_buf, shot_width, shot_height, LINEBUF_SIZE*sizeof(uint32_t)); +#ifndef DISABLE_ZLIB + if (!strcasecmp(ext, "png")) { + free(ext); + save_png(screenshot_file, texture_buf, shot_width, shot_height, LINEBUF_SIZE*sizeof(uint32_t)); + } else { + free(ext); +#endif + save_ppm(screenshot_file, texture_buf, shot_width, shot_height, LINEBUF_SIZE*sizeof(uint32_t)); +#ifndef DISABLE_ZLIB + } +#endif } } else { #endif @@ -670,7 +685,17 @@ } else { shot_pitch *= 2; } - save_ppm(screenshot_file, locked_pixels, shot_width, shot_height, shot_pitch); +#ifndef DISABLE_ZLIB + if (!strcasecmp(ext, "png")) { + free(ext); + save_png(screenshot_file, locked_pixels, shot_width, shot_height, shot_pitch); + } else { + free(ext); +#endif + save_ppm(screenshot_file, locked_pixels, shot_width, shot_height, shot_pitch); +#ifndef DISABLE_ZLIB + } +#endif } SDL_UnlockTexture(sdl_textures[which]); SDL_Rect src_clip = {