From aa0a7822338b32e0cca2a984759cda0e8c846457 Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Mon, 25 Apr 2011 00:05:48 -0400 Subject: [PATCH] Encode the snapshots as png's. Saves between 2x and 1000x of space when passing them to the gui. It's also a huge performance win because the json parser needs to parse between 2x and 1000x less data. --- glstate.py | 15 ++++++- gui/apisurface.cpp | 61 +------------------------ image.cpp | 110 +++++++++++++++++++++++++++++++++++++++++++++ image.hpp | 5 +++ 4 files changed, 130 insertions(+), 61 deletions(-) diff --git a/glstate.py b/glstate.py index 2c18376..dee76e9 100644 --- a/glstate.py +++ b/glstate.py @@ -3019,6 +3019,7 @@ class StateDumper: print '#include ' print '#include ' print + print '#include "image.hpp"' print '#include "json.hpp"' print '#include "glimports.hpp"' print '#include "glproc.hpp"' @@ -3190,7 +3191,11 @@ writeTextureImage(JSONWriter &json, GLenum target, GLint level) glGetTexImage(target, level, GL_RGBA, GL_UNSIGNED_BYTE, pixels); json.beginMember("__data__"); - json.writeBase64(pixels, depth * width * height * 4 * sizeof *pixels); + char *pngBuffer; + int pngBufferSize; + Image::writePixelsToBuffer(pixels, width, height, 4, false, &pngBuffer, &pngBufferSize); + json.writeBase64(pngBuffer, pngBufferSize); + free(pngBuffer); json.endMember(); // __data__ delete [] pixels; @@ -3241,7 +3246,13 @@ writeDrawBufferImage(JSONWriter &json, GLenum format) glReadBuffer(readbuffer); json.beginMember("__data__"); - json.writeBase64(pixels, width * height * channels * sizeof *pixels); + char *pngBuffer; + int pngBufferSize; + Image::writePixelsToBuffer(pixels, width, height, channels, false, &pngBuffer, &pngBufferSize); + //std::cerr <<" Before = "<<(width * height * channels * sizeof *pixels) + // <<", after = "< #include +#include #include @@ -309,6 +310,115 @@ double Image::compare(Image &ref) return precision; } +struct png_tmp_buffer +{ + char *buffer; + size_t size; +}; + +static void +pngWriteCallback(png_structp png_ptr, png_bytep data, png_size_t length) +{ + struct png_tmp_buffer *buf = (struct png_tmp_buffer*) png_ptr->io_ptr; + size_t nsize = buf->size + length; + + /* allocate or grow buffer */ + if (buf->buffer) + buf->buffer = (char*)realloc(buf->buffer, nsize); + else + buf->buffer = (char*)malloc(nsize); + + if (!buf->buffer) + png_error(png_ptr, "Buffer allocation error"); + + memcpy(buf->buffer + buf->size, data, length); + buf->size += length; +} + +bool writePixelsToBuffer(unsigned char *pixels, + unsigned width, unsigned height, unsigned numChannels, + bool flipped, + char **buffer, + int *size) +{ + struct png_tmp_buffer png_mem; + png_structp png_ptr; + png_infop info_ptr; + int type; + + png_mem.buffer = NULL; + png_mem.size = 0; + + switch (numChannels) { + case 4: + type = PNG_COLOR_TYPE_RGB_ALPHA; + break; + case 3: + type = PNG_COLOR_TYPE_RGB; + break; + case 2: + type = PNG_COLOR_TYPE_GRAY_ALPHA; + break; + case 1: + type = PNG_COLOR_TYPE_GRAY; + break; + default: + goto no_png; + } + + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) + goto no_png; + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_write_struct(&png_ptr, NULL); + goto no_png; + } + + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_write_struct(&png_ptr, &info_ptr); + goto no_png; + } + + png_set_write_fn(png_ptr, &png_mem, pngWriteCallback, NULL); + + png_set_IHDR(png_ptr, info_ptr, width, height, 8, + type, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION); + + png_write_info(png_ptr, info_ptr); + + if (!flipped) { + for (unsigned y = 0; y < height; ++y) { + png_bytep row = (png_bytep)(pixels + y*width*numChannels); + png_write_rows(png_ptr, &row, 1); + } + } else { + unsigned y = height; + while (y--) { + png_bytep row = (png_bytep)(pixels + y*width*numChannels); + png_write_rows(png_ptr, &row, 1); + } + } + + png_write_end(png_ptr, info_ptr); + png_destroy_write_struct(&png_ptr, &info_ptr); + *buffer = png_mem.buffer; + *size = png_mem.size; + + return true; + +no_png: + *buffer = NULL; + *size = 0; + + if (png_mem.buffer) + free(png_mem.buffer); + return false; +} } /* namespace Image */ diff --git a/image.hpp b/image.hpp index 5a9704e..f46fb31 100644 --- a/image.hpp +++ b/image.hpp @@ -77,6 +77,11 @@ public: double compare(Image &ref); }; +bool writePixelsToBuffer(unsigned char *pixels, + unsigned w, unsigned h, unsigned numChannels, + bool flipped, + char **buffer, + int *size); Image * readPNG(const char *filename); -- 2.43.0