Browse Source

Update to stb_image 2.19

woollybah 7 years ago
parent
commit
be5f8b9d59
3 changed files with 588 additions and 242 deletions
  1. 396 162
      stbimage.mod/stb/stb_image.h
  2. 189 79
      stbimage.mod/stb/stb_image_write.h
  3. 3 1
      stbimage.mod/stbimage.bmx

File diff suppressed because it is too large
+ 396 - 162
stbimage.mod/stb/stb_image.h


+ 189 - 79
stbimage.mod/stb/stb_image_write.h

@@ -1,4 +1,4 @@
-/* stb_image_write - v1.07 - public domain - http://nothings.org/stb/stb_image_write.h
+/* stb_image_write - v1.09 - public domain - http://nothings.org/stb/stb_image_write.h
    writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015
    writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015
                                      no warranty implied; use at your own risk
                                      no warranty implied; use at your own risk
 
 
@@ -10,34 +10,47 @@
 
 
    Will probably not work correctly with strict-aliasing optimizations.
    Will probably not work correctly with strict-aliasing optimizations.
 
 
+   If using a modern Microsoft Compiler, non-safe versions of CRT calls may cause 
+   compilation warnings or even errors. To avoid this, also before #including,
+
+       #define STBI_MSC_SECURE_CRT
+
 ABOUT:
 ABOUT:
 
 
    This header file is a library for writing images to C stdio. It could be
    This header file is a library for writing images to C stdio. It could be
    adapted to write to memory or a general streaming interface; let me know.
    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
    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:
 BUILDING:
 
 
    You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h.
    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
    You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace
    malloc,realloc,free.
    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:
 USAGE:
 
 
-   There are four functions, one for each image file format:
+   There are five functions, one for each image file format:
 
 
      int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
      int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
      int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
      int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
      int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
      int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
+     int stbi_write_jpg(char const *filename, int w, int h, int comp, const void *data, int quality);
      int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
      int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
-     int stbi_write_jpg(char const *filename, int w, int h, int comp, const float *data);
 
 
-   There are also four equivalent functions that use an arbitrary write function. You are
+     void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically
+
+   There are also five equivalent functions that use an arbitrary write function. You are
    expected to open/close your file-equivalent before and after calling these:
    expected to open/close your file-equivalent before and after calling these:
 
 
      int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data, int stride_in_bytes);
      int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data, int stride_in_bytes);
@@ -49,6 +62,12 @@ USAGE:
    where the callback is:
    where the callback is:
       void stbi_write_func(void *context, void *data, int size);
       void stbi_write_func(void *context, void *data, int size);
 
 
+   You can configure it with these global variables:
+      int stbi_write_tga_with_rle;             // defaults to true; set to 0 to disable RLE
+      int stbi_write_png_compression_level;    // defaults to 8; set to higher for more compression
+      int stbi_write_force_png_filter;         // defaults to -1; set to 0..5 to force a filter mode
+
+
    You can define STBI_WRITE_NO_STDIO to disable the file variant of these
    You can define STBI_WRITE_NO_STDIO to disable the file variant of these
    functions, so the library will not use stdio.h at all. However, this will
    functions, so the library will not use stdio.h at all. However, this will
    also disable HDR writing, because it requires stdio for formatted output.
    also disable HDR writing, because it requires stdio for formatted output.
@@ -75,6 +94,9 @@ USAGE:
    writer, both because it is in BGR order and because it may have padding
    writer, both because it is in BGR order and because it may have padding
    at the end of the line.)
    at the end of the line.)
 
 
+   PNG allows you to set the deflate compression level by setting the global
+   variable 'stbi_write_png_compression_level' (it defaults to 8).
+
    HDR expects linear float data. Since the format is always 32-bit rgb(e)
    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
    data, alpha (if provided) is discarded, and for monochrome data it is
    replicated across all three channels.
    replicated across all three channels.
@@ -88,21 +110,17 @@ USAGE:
 
 
 CREDITS:
 CREDITS:
 
 
-   PNG/BMP/TGA
-      Sean Barrett
-   HDR
-      Baldur Karlsson
-   TGA monochrome:
-      Jean-Sebastien Guay
-   misc enhancements:
-      Tim Kelsey
-   TGA RLE
-      Alan Hickman
-   initial file IO callback implementation
-      Emmanuel Julien
-   JPEG
-      Jon Olick (original jo_jpeg.cpp code)
-      Daniel Gibson
+
+   Sean Barrett           -    PNG/BMP/TGA 
+   Baldur Karlsson        -    HDR
+   Jean-Sebastien Guay    -    TGA monochrome
+   Tim Kelsey             -    misc enhancements
+   Alan Hickman           -    TGA RLE
+   Emmanuel Julien        -    initial file IO callback implementation
+   Jon Olick              -    original jo_jpeg.cpp code
+   Daniel Gibson          -    integrate JPEG, allow external zlib
+   Aarni Koskela          -    allow choosing PNG filter
+
    bugfixes:
    bugfixes:
       github:Chribba
       github:Chribba
       Guillaume Chereau
       Guillaume Chereau
@@ -114,7 +132,13 @@ CREDITS:
       Thatcher Ulrich
       Thatcher Ulrich
       github:poppolopoppo
       github:poppolopoppo
       Patrick Boettcher
       Patrick Boettcher
-      
+      github:xeekworx
+      Cap Petschulat
+      Simon Rodriguez
+      Ivan Tikhonov
+      github:ignotion
+      Adam Schackart
+
 LICENSE
 LICENSE
 
 
   See end of file for license information.
   See end of file for license information.
@@ -124,15 +148,23 @@ LICENSE
 #ifndef INCLUDE_STB_IMAGE_WRITE_H
 #ifndef INCLUDE_STB_IMAGE_WRITE_H
 #define INCLUDE_STB_IMAGE_WRITE_H
 #define INCLUDE_STB_IMAGE_WRITE_H
 
 
+// if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline'
+#ifndef STBIWDEF
+#ifdef STB_IMAGE_WRITE_STATIC
+#define STBIWDEF  static
+#else
 #ifdef __cplusplus
 #ifdef __cplusplus
-extern "C" {
+#define STBIWDEF  extern "C"
+#else
+#define STBIWDEF  extern
+#endif
+#endif
 #endif
 #endif
 
 
-#ifdef STB_IMAGE_WRITE_STATIC
-#define STBIWDEF static
-#else
-#define STBIWDEF extern
+#ifndef STB_IMAGE_WRITE_STATIC  // C++ forbids static forward declarations
 extern int stbi_write_tga_with_rle;
 extern int stbi_write_tga_with_rle;
+extern int stbi_write_png_compression_level;
+extern int stbi_write_force_png_filter;
 #endif
 #endif
 
 
 #ifndef STBI_WRITE_NO_STDIO
 #ifndef STBI_WRITE_NO_STDIO
@@ -151,9 +183,7 @@ STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w,
 STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
 STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
 STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void  *data, int quality);
 STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void  *data, int quality);
 
 
-#ifdef __cplusplus
-}
-#endif
+STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean);
 
 
 #endif//INCLUDE_STB_IMAGE_WRITE_H
 #endif//INCLUDE_STB_IMAGE_WRITE_H
 
 
@@ -208,6 +238,23 @@ STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x,
 
 
 #define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)
 #define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)
 
 
+#ifdef STB_IMAGE_WRITE_STATIC
+static int stbi__flip_vertically_on_write=0;
+static int stbi_write_png_compression_level = 8;
+static int stbi_write_tga_with_rle = 1;
+static int stbi_write_force_png_filter = -1;
+#else
+int stbi_write_png_compression_level = 8;
+int stbi__flip_vertically_on_write=0;
+int stbi_write_tga_with_rle = 1;
+int stbi_write_force_png_filter = -1;
+#endif
+
+STBIWDEF void stbi_flip_vertically_on_write(int flag)
+{
+   stbi__flip_vertically_on_write = flag;
+}
+
 typedef struct
 typedef struct
 {
 {
    stbi_write_func *func;
    stbi_write_func *func;
@@ -230,7 +277,13 @@ static void stbi__stdio_write(void *context, void *data, int size)
 
 
 static int stbi__start_write_file(stbi__write_context *s, const char *filename)
 static int stbi__start_write_file(stbi__write_context *s, const char *filename)
 {
 {
-   FILE *f = fopen(filename, "wb");
+   FILE *f;
+#ifdef STBI_MSC_SECURE_CRT
+   if (fopen_s(&f, filename, "wb"))
+      f = NULL;
+#else
+   f = fopen(filename, "wb");
+#endif
    stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f);
    stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f);
    return f != NULL;
    return f != NULL;
 }
 }
@@ -245,12 +298,6 @@ static void stbi__end_write_file(stbi__write_context *s)
 typedef unsigned int stbiw_uint32;
 typedef unsigned int stbiw_uint32;
 typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
 typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
 
 
-#ifdef STB_IMAGE_WRITE_STATIC
-static int stbi_write_tga_with_rle = 1;
-#else
-int stbi_write_tga_with_rle = 1;
-#endif
-
 static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v)
 static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v)
 {
 {
    while (*fmt) {
    while (*fmt) {
@@ -341,6 +388,9 @@ static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, i
    if (y <= 0)
    if (y <= 0)
       return;
       return;
 
 
+   if (stbi__flip_vertically_on_write)
+      vdir *= -1;
+
    if (vdir < 0)
    if (vdir < 0)
       j_end = -1, j = y-1;
       j_end = -1, j = y-1;
    else
    else
@@ -412,11 +462,21 @@ static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, v
          "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8);
          "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8);
    } else {
    } else {
       int i,j,k;
       int i,j,k;
+      int jend, jdir;
 
 
       stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8);
       stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8);
 
 
-      for (j = y - 1; j >= 0; --j) {
-          unsigned char *row = (unsigned char *) data + j * x * comp;
+      if (stbi__flip_vertically_on_write) {
+         j = 0;
+         jend = y;
+         jdir = 1;
+      } else {
+         j = y-1;
+         jend = -1;
+         jdir = -1;
+      }
+      for (; j != jend; j += jdir) {
+         unsigned char *row = (unsigned char *) data + j * x * comp;
          int len;
          int len;
 
 
          for (i = 0; i < x; i += len) {
          for (i = 0; i < x; i += len) {
@@ -626,11 +686,15 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f
       char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n";
       char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n";
       s->func(s->context, header, sizeof(header)-1);
       s->func(s->context, header, sizeof(header)-1);
 
 
+#ifdef STBI_MSC_SECURE_CRT
+      len = sprintf_s(buffer, "EXPOSURE=          1.0000000000000\n\n-Y %d +X %d\n", y, x);
+#else
       len = sprintf(buffer, "EXPOSURE=          1.0000000000000\n\n-Y %d +X %d\n", y, x);
       len = sprintf(buffer, "EXPOSURE=          1.0000000000000\n\n-Y %d +X %d\n", y, x);
+#endif
       s->func(s->context, buffer, len);
       s->func(s->context, buffer, len);
 
 
       for(i=0; i < y; i++)
       for(i=0; i < y; i++)
-         stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*i*x);
+         stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i)*x);
       STBIW_FREE(scratch);
       STBIW_FREE(scratch);
       return 1;
       return 1;
    }
    }
@@ -662,6 +726,7 @@ STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const
 // PNG writer
 // PNG writer
 //
 //
 
 
+#ifndef STBIW_ZLIB_COMPRESS
 // stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
 // stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
 #define stbiw__sbraw(a) ((int *) (a) - 2)
 #define stbiw__sbraw(a) ((int *) (a) - 2)
 #define stbiw__sbm(a)   stbiw__sbraw(a)[0]
 #define stbiw__sbm(a)   stbiw__sbraw(a)[0]
@@ -742,8 +807,14 @@ static unsigned int stbiw__zhash(unsigned char *data)
 
 
 #define stbiw__ZHASH   16384
 #define stbiw__ZHASH   16384
 
 
+#endif // STBIW_ZLIB_COMPRESS
+
 unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)
 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 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 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 };
    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 };
@@ -752,6 +823,8 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
    int i,j, bitcount=0;
    int i,j, bitcount=0;
    unsigned char *out = NULL;
    unsigned char *out = NULL;
    unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**));
    unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**));
+   if (hash_table == NULL)
+      return NULL;
    if (quality < 5) quality = 5;
    if (quality < 5) quality = 5;
 
 
    stbiw__sbpush(out, 0x78);   // DEFLATE 32K window
    stbiw__sbpush(out, 0x78);   // DEFLATE 32K window
@@ -845,6 +918,7 @@ unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_l
    // make returned pointer freeable
    // make returned pointer freeable
    STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len);
    STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len);
    return (unsigned char *) stbiw__sbraw(out);
    return (unsigned char *) stbiw__sbraw(out);
+#endif // STBIW_ZLIB_COMPRESS
 }
 }
 
 
 static unsigned int stbiw__crc32(unsigned char *buffer, int len)
 static unsigned int stbiw__crc32(unsigned char *buffer, int len)
@@ -911,61 +985,88 @@ static unsigned char stbiw__paeth(int a, int b, int c)
 }
 }
 
 
 // @OPTIMIZE: provide an option that always forces left-predict or paeth predict
 // @OPTIMIZE: provide an option that always forces left-predict or paeth predict
+static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type, signed char *line_buffer)
+{
+   static int mapping[] = { 0,1,2,3,4 };
+   static int firstmap[] = { 0,1,0,5,6 };
+   int *mymap = (y != 0) ? mapping : firstmap;
+   int i;
+   int type = mymap[filter_type];
+   unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y);
+   int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes;
+   for (i = 0; i < n; ++i) {
+      switch (type) {
+         case 0: line_buffer[i] = z[i]; break;
+         case 1: line_buffer[i] = z[i]; break;
+         case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break;
+         case 3: line_buffer[i] = z[i] - (z[i-signed_stride]>>1); break;
+         case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-signed_stride],0)); break;
+         case 5: line_buffer[i] = z[i]; break;
+         case 6: line_buffer[i] = z[i]; break;
+      }
+   }
+   for (i=n; i < width*n; ++i) {
+      switch (type) {
+         case 0: line_buffer[i] = z[i]; break;
+         case 1: line_buffer[i] = z[i] - z[i-n]; break;
+         case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break;
+         case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break;
+         case 4: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break;
+         case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break;
+         case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break;
+      }
+   }
+}
+
 unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
 unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
 {
 {
+   int force_filter = stbi_write_force_png_filter;
    int ctype[5] = { -1, 0, 4, 2, 6 };
    int ctype[5] = { -1, 0, 4, 2, 6 };
    unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
    unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
    unsigned char *out,*o, *filt, *zlib;
    unsigned char *out,*o, *filt, *zlib;
    signed char *line_buffer;
    signed char *line_buffer;
-   int i,j,k,p,zlen;
+   int j,zlen;
 
 
    if (stride_bytes == 0)
    if (stride_bytes == 0)
       stride_bytes = x * n;
       stride_bytes = x * n;
 
 
+   if (force_filter >= 5) {
+      force_filter = -1;
+   }
+
    filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0;
    filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0;
    line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; }
    line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; }
    for (j=0; j < y; ++j) {
    for (j=0; j < y; ++j) {
-      static int mapping[] = { 0,1,2,3,4 };
-      static int firstmap[] = { 0,1,0,5,6 };
-      int *mymap = (j != 0) ? mapping : firstmap;
-      int best = 0, bestval = 0x7fffffff;
-      for (p=0; p < 2; ++p) {
-         for (k= p?best:0; k < 5; ++k) { // @TODO: clarity: rewrite this to go 0..5, and 'continue' the unwanted ones during 2nd pass
-            int type = mymap[k],est=0;
-            unsigned char *z = pixels + stride_bytes*j;
-            for (i=0; i < n; ++i)
-               switch (type) {
-                  case 0: line_buffer[i] = z[i]; break;
-                  case 1: line_buffer[i] = z[i]; break;
-                  case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
-                  case 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break;
-                  case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-stride_bytes],0)); break;
-                  case 5: line_buffer[i] = z[i]; break;
-                  case 6: line_buffer[i] = z[i]; break;
-               }
-            for (i=n; i < x*n; ++i) {
-               switch (type) {
-                  case 0: line_buffer[i] = z[i]; break;
-                  case 1: line_buffer[i] = z[i] - z[i-n]; break;
-                  case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
-                  case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>1); break;
-                  case 4: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-stride_bytes], z[i-stride_bytes-n]); break;
-                  case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break;
-                  case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break;
-               }
-            }
-            if (p) break;
-            for (i=0; i < x*n; ++i)
+      int filter_type;
+      if (force_filter > -1) {
+         filter_type = force_filter;
+         stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, force_filter, line_buffer);
+      } else { // Estimate the best filter by running through all of them:
+         int best_filter = 0, best_filter_val = 0x7fffffff, est, i;
+         for (filter_type = 0; filter_type < 5; filter_type++) {
+            stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, filter_type, line_buffer);
+
+            // Estimate the entropy of the line using this filter; the less, the better.
+            est = 0;
+            for (i = 0; i < x*n; ++i) {
                est += abs((signed char) line_buffer[i]);
                est += abs((signed char) line_buffer[i]);
-            if (est < bestval) { bestval = est; best = k; }
+            }
+            if (est < best_filter_val) {
+               best_filter_val = est;
+               best_filter = filter_type;
+            }
+         }
+         if (filter_type != best_filter) {  // If the last iteration already got us the best filter, don't redo it
+            stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, best_filter, line_buffer);
+            filter_type = best_filter;
          }
          }
       }
       }
-      // when we get here, best contains the filter type, and line_buffer contains the data
-      filt[j*(x*n+1)] = (unsigned char) best;
+      // when we get here, filter_type contains the filter type, and line_buffer contains the data
+      filt[j*(x*n+1)] = (unsigned char) filter_type;
       STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n);
       STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n);
    }
    }
    STBIW_FREE(line_buffer);
    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_compression_level);
    STBIW_FREE(filt);
    STBIW_FREE(filt);
    if (!zlib) return 0;
    if (!zlib) return 0;
 
 
@@ -1010,7 +1111,12 @@ STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const
    int len;
    int len;
    unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
    unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
    if (png == NULL) return 0;
    if (png == NULL) return 0;
+#ifdef STBI_MSC_SECURE_CRT
+   if (fopen_s(&f, filename, "wb"))
+      f = NULL;
+#else
    f = fopen(filename, "wb");
    f = fopen(filename, "wb");
+#endif
    if (!f) { STBIW_FREE(png); return 0; }
    if (!f) { STBIW_FREE(png); return 0; }
    fwrite(png, 1, len, f);
    fwrite(png, 1, len, f);
    fclose(f);
    fclose(f);
@@ -1318,7 +1424,7 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in
             float YDU[64], UDU[64], VDU[64];
             float YDU[64], UDU[64], VDU[64];
             for(row = y, pos = 0; row < y+8; ++row) {
             for(row = y, pos = 0; row < y+8; ++row) {
                for(col = x; col < x+8; ++col, ++pos) {
                for(col = x; col < x+8; ++col, ++pos) {
-                  int p = row*width*comp + col*comp;
+                  int p = (stbi__flip_vertically_on_write ? height-1-row : row)*width*comp + col*comp;
                   float r, g, b;
                   float r, g, b;
                   if(row >= height) {
                   if(row >= height) {
                      p -= width*comp*(row+1 - height);
                      p -= width*comp*(row+1 - height);
@@ -1377,6 +1483,10 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const
 #endif // STB_IMAGE_WRITE_IMPLEMENTATION
 #endif // STB_IMAGE_WRITE_IMPLEMENTATION
 
 
 /* Revision history
 /* Revision history
+      1.09  (2018-02-11)
+             fix typo in zlib quality API, improve STB_I_W_STATIC in C++
+      1.08  (2018-01-29)
+             add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter
       1.07  (2017-07-24)
       1.07  (2017-07-24)
              doc fix
              doc fix
       1.06 (2017-07-23)
       1.06 (2017-07-23)

+ 3 - 1
stbimage.mod/stbimage.bmx

@@ -2,11 +2,13 @@ SuperStrict
 
 
 Module Pub.StbImage
 Module Pub.StbImage
 
 
-ModuleInfo "Version: 1.01"
+ModuleInfo "Version: 1.02"
 ModuleInfo "Author: Sean Barrett and contributers (see stb_image.h)"
 ModuleInfo "Author: Sean Barrett and contributers (see stb_image.h)"
 ModuleInfo "License: ZLib/PNG License"
 ModuleInfo "License: ZLib/PNG License"
 ModuleInfo "Credit: Adapted for BlitzMax by Bruce A Henderson"
 ModuleInfo "Credit: Adapted for BlitzMax by Bruce A Henderson"
 
 
+ModuleInfo "History: 1.02"
+ModuleInfo "History: Update to stb_image 2.19"
 ModuleInfo "History: 1.01"
 ModuleInfo "History: 1.01"
 ModuleInfo "History: Update to stb_image 2.16"
 ModuleInfo "History: Update to stb_image 2.16"
 ModuleInfo "History: 1.00"
 ModuleInfo "History: 1.00"

Some files were not shown because too many files changed in this diff