Skip to content

Commit

Permalink
stb_image_write.h: Allow setting custom zlib compress function for PNG
Browse files Browse the repository at this point in the history
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 nothings#113.

Example for zlib:

#include <zlib.h>
unsigned char* compress_for_stbiw(unsigned char *data, int data_len,
                                  int *out_len, int quality)
{
  uLongf bufSize = compressBound(data_len);
  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"
// ...
  • Loading branch information
DanielGibson committed Jul 4, 2017
1 parent e6bbecd commit 1dae231
Showing 1 changed file with 16 additions and 4 deletions.
20 changes: 16 additions & 4 deletions stb_image_write.h
Expand Up @@ -16,16 +16,20 @@
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);
USAGE:
Expand Down Expand Up @@ -650,6 +654,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]
Expand Down Expand Up @@ -730,8 +735,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 };
Expand Down Expand Up @@ -833,6 +844,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)
Expand Down

0 comments on commit 1dae231

Please sign in to comment.