From e6bbecd3a9c73be061aeb51d6e4fe19317bc4d89 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Tue, 4 Jul 2017 18:07:33 +0200 Subject: [PATCH 1/2] stb_image_write.h: Set PNG compress lvl via stbi_write_png_level This allows the user to change the deflate/zlib compress level used for PNG compression by changing a global variable. --- stb_image_write.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/stb_image_write.h b/stb_image_write.h index df62339..44c8943 100644 --- a/stb_image_write.h +++ b/stb_image_write.h @@ -73,6 +73,9 @@ USAGE: writer, both because it is in BGR order and because it may have padding at the end of the line.) + PNG allows you to set the deflate compression level by setting the global + variable 'stbi_write_png_level' (it defaults to 8). + HDR expects linear float data. Since the format is always 32-bit rgb(e) data, alpha (if provided) is discarded, and for monochrome data it is replicated across all three channels. @@ -124,6 +127,7 @@ extern "C" { #else #define STBIWDEF extern extern int stbi_write_tga_with_rle; +extern int stbi_write_png_level; #endif #ifndef STBI_WRITE_NO_STDIO @@ -894,6 +898,12 @@ static unsigned char stbiw__paeth(int a, int b, int c) return STBIW_UCHAR(c); } +#ifdef STB_IMAGE_WRITE_STATIC +static int stbi_write_png_level = 8; +#else +int stbi_write_png_level = 8; +#endif + // @OPTIMIZE: provide an option that always forces left-predict or paeth predict unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) { @@ -949,7 +959,7 @@ unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, in STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n); } STBIW_FREE(line_buffer); - zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory + zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_level); STBIW_FREE(filt); if (!zlib) return 0; From be21113512b4c1ab8a9fce23d5ad9ca4184bc25e Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Tue, 4 Jul 2017 19:34:31 +0200 Subject: [PATCH 2/2] stb_image_write.h: Allow setting custom zlib compress function for PNG The builtin stbi_zlib_compress does not compress as well as zlib or miniz (which is not too surprising as it's <200 LOC), thus PNGs created by stb_image_write are about 20-50% bigger than PNGs compressed with libpng. This change lets the user supply a custom deflate/zlib-style compress function, which improves compression a lot. This was requested in #113. Example for zlib: #include unsigned char* compress_for_stbiw(unsigned char *data, int data_len, int *out_len, int quality) { uLongf bufSize = compressBound(data_len); // note that buf will be free'd by stb_image_write.h // with STBIW_FREE() (plain free() by default) unsigned char* buf = malloc(bufSize); if(buf == NULL) return NULL; if(compress2(buf, &bufSize, data, data_len, quality) != Z_OK) { free(buf); return NULL; } *out_len = bufSize; return buf; } #define STBIW_ZLIB_COMPRESS compress_for_stbiw #define STB_IMAGE_WRITE_IMPLEMENTATION #include "stb_image_write.h" // ... --- stb_image_write.h | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/stb_image_write.h b/stb_image_write.h index 44c8943..a084364 100644 --- a/stb_image_write.h +++ b/stb_image_write.h @@ -16,16 +16,22 @@ ABOUT: adapted to write to memory or a general streaming interface; let me know. The PNG output is not optimal; it is 20-50% larger than the file - written by a decent optimizing implementation. This library is designed - for source code compactness and simplicity, not optimal image file size - or run-time performance. + written by a decent optimizing implementation; though providing a custom + zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that. + This library is designed for source code compactness and simplicity, + not optimal image file size or run-time performance. BUILDING: You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h. You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace malloc,realloc,free. - You can define STBIW_MEMMOVE() to replace memmove() + You can #define STBIW_MEMMOVE() to replace memmove() + You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function + for PNG compression (instead of the builtin one), it must have the following signature: + unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality); + The returned data will be freed with STBIW_FREE() (free() by default), + so it must be heap allocated with STBIW_MALLOC() (malloc() by default), USAGE: @@ -650,6 +656,7 @@ int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *da // PNG writer // +#ifndef STBIW_ZLIB_COMPRESS // stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() #define stbiw__sbraw(a) ((int *) (a) - 2) #define stbiw__sbm(a) stbiw__sbraw(a)[0] @@ -730,8 +737,14 @@ static unsigned int stbiw__zhash(unsigned char *data) #define stbiw__ZHASH 16384 +#endif // STBIW_ZLIB_COMPRESS + unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) { +#ifdef STBIW_ZLIB_COMPRESS + // user provided a zlib compress implementation, use that + return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality); +#else // use builtin static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 }; @@ -833,6 +846,7 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l // make returned pointer freeable STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); return (unsigned char *) stbiw__sbraw(out); +#endif // STBIW_ZLIB_COMPRESS } static unsigned int stbiw__crc32(unsigned char *buffer, int len)