URI:
       stb_image_write.h - ltkx - GUI toolkit for X11 (old)
  HTML git clone git://lumidify.org/ltkx.git (fast, but not encrypted)
  HTML git clone https://lumidify.org/git/ltkx.git (encrypted, but very slow)
  HTML git clone git://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/ltkx.git (over tor)
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       stb_image_write.h (37685B)
       ---
            1 /* stb_image_write - v1.02 - public domain - http://nothings.org/stb/stb_image_write.h
            2    writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010-2015
            3                                      no warranty implied; use at your own risk
            4 
            5    Before #including,
            6 
            7        #define STB_IMAGE_WRITE_IMPLEMENTATION
            8 
            9    in the file that you want to have the implementation.
           10 
           11    Will probably not work correctly with strict-aliasing optimizations.
           12 
           13 ABOUT:
           14 
           15    This header file is a library for writing images to C stdio. It could be
           16    adapted to write to memory or a general streaming interface; let me know.
           17 
           18    The PNG output is not optimal; it is 20-50% larger than the file
           19    written by a decent optimizing implementation. This library is designed
           20    for source code compactness and simplicity, not optimal image file size
           21    or run-time performance.
           22 
           23 BUILDING:
           24 
           25    You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h.
           26    You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace
           27    malloc,realloc,free.
           28    You can define STBIW_MEMMOVE() to replace memmove()
           29 
           30 USAGE:
           31 
           32    There are four functions, one for each image file format:
           33 
           34      int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
           35      int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
           36      int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
           37      int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
           38 
           39    There are also four equivalent functions that use an arbitrary write function. You are
           40    expected to open/close your file-equivalent before and after calling these:
           41 
           42      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);
           43      int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);
           44      int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);
           45      int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
           46 
           47    where the callback is:
           48       void stbi_write_func(void *context, void *data, int size);
           49 
           50    You can define STBI_WRITE_NO_STDIO to disable the file variant of these
           51    functions, so the library will not use stdio.h at all. However, this will
           52    also disable HDR writing, because it requires stdio for formatted output.
           53 
           54    Each function returns 0 on failure and non-0 on success.
           55 
           56    The functions create an image file defined by the parameters. The image
           57    is a rectangle of pixels stored from left-to-right, top-to-bottom.
           58    Each pixel contains 'comp' channels of data stored interleaved with 8-bits
           59    per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is
           60    monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall.
           61    The *data pointer points to the first byte of the top-left-most pixel.
           62    For PNG, "stride_in_bytes" is the distance in bytes from the first byte of
           63    a row of pixels to the first byte of the next row of pixels.
           64 
           65    PNG creates output files with the same number of components as the input.
           66    The BMP format expands Y to RGB in the file format and does not
           67    output alpha.
           68 
           69    PNG supports writing rectangles of data even when the bytes storing rows of
           70    data are not consecutive in memory (e.g. sub-rectangles of a larger image),
           71    by supplying the stride between the beginning of adjacent rows. The other
           72    formats do not. (Thus you cannot write a native-format BMP through the BMP
           73    writer, both because it is in BGR order and because it may have padding
           74    at the end of the line.)
           75 
           76    HDR expects linear float data. Since the format is always 32-bit rgb(e)
           77    data, alpha (if provided) is discarded, and for monochrome data it is
           78    replicated across all three channels.
           79 
           80    TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed
           81    data, set the global variable 'stbi_write_tga_with_rle' to 0.
           82 
           83 CREDITS:
           84 
           85    PNG/BMP/TGA
           86       Sean Barrett
           87    HDR
           88       Baldur Karlsson
           89    TGA monochrome:
           90       Jean-Sebastien Guay
           91    misc enhancements:
           92       Tim Kelsey
           93    TGA RLE
           94       Alan Hickman
           95    initial file IO callback implementation
           96       Emmanuel Julien
           97    bugfixes:
           98       github:Chribba
           99       Guillaume Chereau
          100       github:jry2
          101       github:romigrou
          102       Sergio Gonzalez
          103       Jonas Karlsson
          104       Filip Wasil
          105       Thatcher Ulrich
          106       
          107 LICENSE
          108 
          109 This software is dual-licensed to the public domain and under the following
          110 license: you are granted a perpetual, irrevocable license to copy, modify,
          111 publish, and distribute this file as you see fit.
          112 
          113 */
          114 
          115 #ifndef INCLUDE_STB_IMAGE_WRITE_H
          116 #define INCLUDE_STB_IMAGE_WRITE_H
          117 
          118 #ifdef __cplusplus
          119 extern "C" {
          120 #endif
          121 
          122 #ifdef STB_IMAGE_WRITE_STATIC
          123 #define STBIWDEF static
          124 #else
          125 #define STBIWDEF extern
          126 extern int stbi_write_tga_with_rle;
          127 #endif
          128 
          129 #ifndef STBI_WRITE_NO_STDIO
          130 STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void  *data, int stride_in_bytes);
          131 STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void  *data);
          132 STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void  *data);
          133 STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
          134 #endif
          135 
          136 typedef void stbi_write_func(void *context, void *data, int size);
          137 
          138 STBIWDEF 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);
          139 STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);
          140 STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);
          141 STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
          142 
          143 #ifdef __cplusplus
          144 }
          145 #endif
          146 
          147 #endif//INCLUDE_STB_IMAGE_WRITE_H
          148 
          149 #ifdef STB_IMAGE_WRITE_IMPLEMENTATION
          150 
          151 #ifdef _WIN32
          152    #ifndef _CRT_SECURE_NO_WARNINGS
          153    #define _CRT_SECURE_NO_WARNINGS
          154    #endif
          155    #ifndef _CRT_NONSTDC_NO_DEPRECATE
          156    #define _CRT_NONSTDC_NO_DEPRECATE
          157    #endif
          158 #endif
          159 
          160 #ifndef STBI_WRITE_NO_STDIO
          161 #include <stdio.h>
          162 #endif // STBI_WRITE_NO_STDIO
          163 
          164 #include <stdarg.h>
          165 #include <stdlib.h>
          166 #include <string.h>
          167 #include <math.h>
          168 
          169 #if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED))
          170 // ok
          171 #elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED)
          172 // ok
          173 #else
          174 #error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)."
          175 #endif
          176 
          177 #ifndef STBIW_MALLOC
          178 #define STBIW_MALLOC(sz)        malloc(sz)
          179 #define STBIW_REALLOC(p,newsz)  realloc(p,newsz)
          180 #define STBIW_FREE(p)           free(p)
          181 #endif
          182 
          183 #ifndef STBIW_REALLOC_SIZED
          184 #define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz)
          185 #endif
          186 
          187 
          188 #ifndef STBIW_MEMMOVE
          189 #define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz)
          190 #endif
          191 
          192 
          193 #ifndef STBIW_ASSERT
          194 #include <assert.h>
          195 #define STBIW_ASSERT(x) assert(x)
          196 #endif
          197 
          198 #define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)
          199 
          200 typedef struct
          201 {
          202    stbi_write_func *func;
          203    void *context;
          204 } stbi__write_context;
          205 
          206 // initialize a callback-based context
          207 static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context)
          208 {
          209    s->func    = c;
          210    s->context = context;
          211 }
          212 
          213 #ifndef STBI_WRITE_NO_STDIO
          214 
          215 static void stbi__stdio_write(void *context, void *data, int size)
          216 {
          217    fwrite(data,1,size,(FILE*) context);
          218 }
          219 
          220 static int stbi__start_write_file(stbi__write_context *s, const char *filename)
          221 {
          222    FILE *f = fopen(filename, "wb");
          223    stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f);
          224    return f != NULL;
          225 }
          226 
          227 static void stbi__end_write_file(stbi__write_context *s)
          228 {
          229    fclose((FILE *)s->context);
          230 }
          231 
          232 #endif // !STBI_WRITE_NO_STDIO
          233 
          234 typedef unsigned int stbiw_uint32;
          235 typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
          236 
          237 #ifdef STB_IMAGE_WRITE_STATIC
          238 static int stbi_write_tga_with_rle = 1;
          239 #else
          240 int stbi_write_tga_with_rle = 1;
          241 #endif
          242 
          243 static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v)
          244 {
          245    while (*fmt) {
          246       switch (*fmt++) {
          247          case ' ': break;
          248          case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int));
          249                      s->func(s->context,&x,1);
          250                      break; }
          251          case '2': { int x = va_arg(v,int);
          252                      unsigned char b[2];
          253                      b[0] = STBIW_UCHAR(x);
          254                      b[1] = STBIW_UCHAR(x>>8);
          255                      s->func(s->context,b,2);
          256                      break; }
          257          case '4': { stbiw_uint32 x = va_arg(v,int);
          258                      unsigned char b[4];
          259                      b[0]=STBIW_UCHAR(x);
          260                      b[1]=STBIW_UCHAR(x>>8);
          261                      b[2]=STBIW_UCHAR(x>>16);
          262                      b[3]=STBIW_UCHAR(x>>24);
          263                      s->func(s->context,b,4);
          264                      break; }
          265          default:
          266             STBIW_ASSERT(0);
          267             return;
          268       }
          269    }
          270 }
          271 
          272 static void stbiw__writef(stbi__write_context *s, const char *fmt, ...)
          273 {
          274    va_list v;
          275    va_start(v, fmt);
          276    stbiw__writefv(s, fmt, v);
          277    va_end(v);
          278 }
          279 
          280 static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c)
          281 {
          282    unsigned char arr[3];
          283    arr[0] = a, arr[1] = b, arr[2] = c;
          284    s->func(s->context, arr, 3);
          285 }
          286 
          287 static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d)
          288 {
          289    unsigned char bg[3] = { 255, 0, 255}, px[3];
          290    int k;
          291 
          292    if (write_alpha < 0)
          293       s->func(s->context, &d[comp - 1], 1);
          294 
          295    switch (comp) {
          296       case 1:
          297          s->func(s->context,d,1);
          298          break;
          299       case 2:
          300          if (expand_mono)
          301             stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp
          302          else
          303             s->func(s->context, d, 1);  // monochrome TGA
          304          break;
          305       case 4:
          306          if (!write_alpha) {
          307             // composite against pink background
          308             for (k = 0; k < 3; ++k)
          309                px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255;
          310             stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]);
          311             break;
          312          }
          313          /* FALLTHROUGH */
          314       case 3:
          315          stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]);
          316          break;
          317    }
          318    if (write_alpha > 0)
          319       s->func(s->context, &d[comp - 1], 1);
          320 }
          321 
          322 static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono)
          323 {
          324    stbiw_uint32 zero = 0;
          325    int i,j, j_end;
          326 
          327    if (y <= 0)
          328       return;
          329 
          330    if (vdir < 0)
          331       j_end = -1, j = y-1;
          332    else
          333       j_end =  y, j = 0;
          334 
          335    for (; j != j_end; j += vdir) {
          336       for (i=0; i < x; ++i) {
          337          unsigned char *d = (unsigned char *) data + (j*x+i)*comp;
          338          stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d);
          339       }
          340       s->func(s->context, &zero, scanline_pad);
          341    }
          342 }
          343 
          344 static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...)
          345 {
          346    if (y < 0 || x < 0) {
          347       return 0;
          348    } else {
          349       va_list v;
          350       va_start(v, fmt);
          351       stbiw__writefv(s, fmt, v);
          352       va_end(v);
          353       stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono);
          354       return 1;
          355    }
          356 }
          357 
          358 static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data)
          359 {
          360    int pad = (-x*3) & 3;
          361    return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad,
          362            "11 4 22 4" "4 44 22 444444",
          363            'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40,  // file header
          364             40, x,y, 1,24, 0,0,0,0,0,0);             // bitmap header
          365 }
          366 
          367 STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
          368 {
          369    stbi__write_context s;
          370    stbi__start_write_callbacks(&s, func, context);
          371    return stbi_write_bmp_core(&s, x, y, comp, data);
          372 }
          373 
          374 #ifndef STBI_WRITE_NO_STDIO
          375 STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
          376 {
          377    stbi__write_context s;
          378    if (stbi__start_write_file(&s,filename)) {
          379       int r = stbi_write_bmp_core(&s, x, y, comp, data);
          380       stbi__end_write_file(&s);
          381       return r;
          382    } else
          383       return 0;
          384 }
          385 #endif //!STBI_WRITE_NO_STDIO
          386 
          387 static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data)
          388 {
          389    int has_alpha = (comp == 2 || comp == 4);
          390    int colorbytes = has_alpha ? comp-1 : comp;
          391    int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3
          392 
          393    if (y < 0 || x < 0)
          394       return 0;
          395 
          396    if (!stbi_write_tga_with_rle) {
          397       return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0,
          398          "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8);
          399    } else {
          400       int i,j,k;
          401 
          402       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);
          403 
          404       for (j = y - 1; j >= 0; --j) {
          405           unsigned char *row = (unsigned char *) data + j * x * comp;
          406          int len;
          407 
          408          for (i = 0; i < x; i += len) {
          409             unsigned char *begin = row + i * comp;
          410             int diff = 1;
          411             len = 1;
          412 
          413             if (i < x - 1) {
          414                ++len;
          415                diff = memcmp(begin, row + (i + 1) * comp, comp);
          416                if (diff) {
          417                   const unsigned char *prev = begin;
          418                   for (k = i + 2; k < x && len < 128; ++k) {
          419                      if (memcmp(prev, row + k * comp, comp)) {
          420                         prev += comp;
          421                         ++len;
          422                      } else {
          423                         --len;
          424                         break;
          425                      }
          426                   }
          427                } else {
          428                   for (k = i + 2; k < x && len < 128; ++k) {
          429                      if (!memcmp(begin, row + k * comp, comp)) {
          430                         ++len;
          431                      } else {
          432                         break;
          433                      }
          434                   }
          435                }
          436             }
          437 
          438             if (diff) {
          439                unsigned char header = STBIW_UCHAR(len - 1);
          440                s->func(s->context, &header, 1);
          441                for (k = 0; k < len; ++k) {
          442                   stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp);
          443                }
          444             } else {
          445                unsigned char header = STBIW_UCHAR(len - 129);
          446                s->func(s->context, &header, 1);
          447                stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin);
          448             }
          449          }
          450       }
          451    }
          452    return 1;
          453 }
          454 
          455 int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
          456 {
          457    stbi__write_context s;
          458    stbi__start_write_callbacks(&s, func, context);
          459    return stbi_write_tga_core(&s, x, y, comp, (void *) data);
          460 }
          461 
          462 #ifndef STBI_WRITE_NO_STDIO
          463 int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
          464 {
          465    stbi__write_context s;
          466    if (stbi__start_write_file(&s,filename)) {
          467       int r = stbi_write_tga_core(&s, x, y, comp, (void *) data);
          468       stbi__end_write_file(&s);
          469       return r;
          470    } else
          471       return 0;
          472 }
          473 #endif
          474 
          475 // *************************************************************************************************
          476 // Radiance RGBE HDR writer
          477 // by Baldur Karlsson
          478 #ifndef STBI_WRITE_NO_STDIO
          479 
          480 #define stbiw__max(a, b)  ((a) > (b) ? (a) : (b))
          481 
          482 void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
          483 {
          484    int exponent;
          485    float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2]));
          486 
          487    if (maxcomp < 1e-32f) {
          488       rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
          489    } else {
          490       float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp;
          491 
          492       rgbe[0] = (unsigned char)(linear[0] * normalize);
          493       rgbe[1] = (unsigned char)(linear[1] * normalize);
          494       rgbe[2] = (unsigned char)(linear[2] * normalize);
          495       rgbe[3] = (unsigned char)(exponent + 128);
          496    }
          497 }
          498 
          499 void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte)
          500 {
          501    unsigned char lengthbyte = STBIW_UCHAR(length+128);
          502    STBIW_ASSERT(length+128 <= 255);
          503    s->func(s->context, &lengthbyte, 1);
          504    s->func(s->context, &databyte, 1);
          505 }
          506 
          507 void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data)
          508 {
          509    unsigned char lengthbyte = STBIW_UCHAR(length);
          510    STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code
          511    s->func(s->context, &lengthbyte, 1);
          512    s->func(s->context, data, length);
          513 }
          514 
          515 void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline)
          516 {
          517    unsigned char scanlineheader[4] = { 2, 2, 0, 0 };
          518    unsigned char rgbe[4];
          519    float linear[3];
          520    int x;
          521 
          522    scanlineheader[2] = (width&0xff00)>>8;
          523    scanlineheader[3] = (width&0x00ff);
          524 
          525    /* skip RLE for images too small or large */
          526    if (width < 8 || width >= 32768) {
          527       for (x=0; x < width; x++) {
          528          switch (ncomp) {
          529             case 4: /* fallthrough */
          530             case 3: linear[2] = scanline[x*ncomp + 2];
          531                     linear[1] = scanline[x*ncomp + 1];
          532                     linear[0] = scanline[x*ncomp + 0];
          533                     break;
          534             default:
          535                     linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];
          536                     break;
          537          }
          538          stbiw__linear_to_rgbe(rgbe, linear);
          539          s->func(s->context, rgbe, 4);
          540       }
          541    } else {
          542       int c,r;
          543       /* encode into scratch buffer */
          544       for (x=0; x < width; x++) {
          545          switch(ncomp) {
          546             case 4: /* fallthrough */
          547             case 3: linear[2] = scanline[x*ncomp + 2];
          548                     linear[1] = scanline[x*ncomp + 1];
          549                     linear[0] = scanline[x*ncomp + 0];
          550                     break;
          551             default:
          552                     linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];
          553                     break;
          554          }
          555          stbiw__linear_to_rgbe(rgbe, linear);
          556          scratch[x + width*0] = rgbe[0];
          557          scratch[x + width*1] = rgbe[1];
          558          scratch[x + width*2] = rgbe[2];
          559          scratch[x + width*3] = rgbe[3];
          560       }
          561 
          562       s->func(s->context, scanlineheader, 4);
          563 
          564       /* RLE each component separately */
          565       for (c=0; c < 4; c++) {
          566          unsigned char *comp = &scratch[width*c];
          567 
          568          x = 0;
          569          while (x < width) {
          570             // find first run
          571             r = x;
          572             while (r+2 < width) {
          573                if (comp[r] == comp[r+1] && comp[r] == comp[r+2])
          574                   break;
          575                ++r;
          576             }
          577             if (r+2 >= width)
          578                r = width;
          579             // dump up to first run
          580             while (x < r) {
          581                int len = r-x;
          582                if (len > 128) len = 128;
          583                stbiw__write_dump_data(s, len, &comp[x]);
          584                x += len;
          585             }
          586             // if there's a run, output it
          587             if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd
          588                // find next byte after run
          589                while (r < width && comp[r] == comp[x])
          590                   ++r;
          591                // output run up to r
          592                while (x < r) {
          593                   int len = r-x;
          594                   if (len > 127) len = 127;
          595                   stbiw__write_run_data(s, len, comp[x]);
          596                   x += len;
          597                }
          598             }
          599          }
          600       }
          601    }
          602 }
          603 
          604 static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data)
          605 {
          606    if (y <= 0 || x <= 0 || data == NULL)
          607       return 0;
          608    else {
          609       // Each component is stored separately. Allocate scratch space for full output scanline.
          610       unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4);
          611       int i, len;
          612       char buffer[128];
          613       char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n";
          614       s->func(s->context, header, sizeof(header)-1);
          615 
          616       len = sprintf(buffer, "EXPOSURE=          1.0000000000000\n\n-Y %d +X %d\n", y, x);
          617       s->func(s->context, buffer, len);
          618 
          619       for(i=0; i < y; i++)
          620          stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*i*x);
          621       STBIW_FREE(scratch);
          622       return 1;
          623    }
          624 }
          625 
          626 int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data)
          627 {
          628    stbi__write_context s;
          629    stbi__start_write_callbacks(&s, func, context);
          630    return stbi_write_hdr_core(&s, x, y, comp, (float *) data);
          631 }
          632 
          633 int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
          634 {
          635    stbi__write_context s;
          636    if (stbi__start_write_file(&s,filename)) {
          637       int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data);
          638       stbi__end_write_file(&s);
          639       return r;
          640    } else
          641       return 0;
          642 }
          643 #endif // STBI_WRITE_NO_STDIO
          644 
          645 
          646 //////////////////////////////////////////////////////////////////////////////
          647 //
          648 // PNG writer
          649 //
          650 
          651 // stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
          652 #define stbiw__sbraw(a) ((int *) (a) - 2)
          653 #define stbiw__sbm(a)   stbiw__sbraw(a)[0]
          654 #define stbiw__sbn(a)   stbiw__sbraw(a)[1]
          655 
          656 #define stbiw__sbneedgrow(a,n)  ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a))
          657 #define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0)
          658 #define stbiw__sbgrow(a,n)  stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a)))
          659 
          660 #define stbiw__sbpush(a, v)      (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v))
          661 #define stbiw__sbcount(a)        ((a) ? stbiw__sbn(a) : 0)
          662 #define stbiw__sbfree(a)         ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0)
          663 
          664 static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
          665 {
          666    int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1;
          667    void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2);
          668    STBIW_ASSERT(p);
          669    if (p) {
          670       if (!*arr) ((int *) p)[1] = 0;
          671       *arr = (void *) ((int *) p + 2);
          672       stbiw__sbm(*arr) = m;
          673    }
          674    return *arr;
          675 }
          676 
          677 static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)
          678 {
          679    while (*bitcount >= 8) {
          680       stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer));
          681       *bitbuffer >>= 8;
          682       *bitcount -= 8;
          683    }
          684    return data;
          685 }
          686 
          687 static int stbiw__zlib_bitrev(int code, int codebits)
          688 {
          689    int res=0;
          690    while (codebits--) {
          691       res = (res << 1) | (code & 1);
          692       code >>= 1;
          693    }
          694    return res;
          695 }
          696 
          697 static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit)
          698 {
          699    int i;
          700    for (i=0; i < limit && i < 258; ++i)
          701       if (a[i] != b[i]) break;
          702    return i;
          703 }
          704 
          705 static unsigned int stbiw__zhash(unsigned char *data)
          706 {
          707    stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16);
          708    hash ^= hash << 3;
          709    hash += hash >> 5;
          710    hash ^= hash << 4;
          711    hash += hash >> 17;
          712    hash ^= hash << 25;
          713    hash += hash >> 6;
          714    return hash;
          715 }
          716 
          717 #define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount))
          718 #define stbiw__zlib_add(code,codebits) \
          719       (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush())
          720 #define stbiw__zlib_huffa(b,c)  stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c)
          721 // default huffman tables
          722 #define stbiw__zlib_huff1(n)  stbiw__zlib_huffa(0x30 + (n), 8)
          723 #define stbiw__zlib_huff2(n)  stbiw__zlib_huffa(0x190 + (n)-144, 9)
          724 #define stbiw__zlib_huff3(n)  stbiw__zlib_huffa(0 + (n)-256,7)
          725 #define stbiw__zlib_huff4(n)  stbiw__zlib_huffa(0xc0 + (n)-280,8)
          726 #define stbiw__zlib_huff(n)  ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n))
          727 #define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n))
          728 
          729 #define stbiw__ZHASH   16384
          730 
          731 unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)
          732 {
          733    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 };
          734    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 };
          735    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 };
          736    static unsigned char  disteb[]  = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 };
          737    unsigned int bitbuf=0;
          738    int i,j, bitcount=0;
          739    unsigned char *out = NULL;
          740    unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**));
          741    if (quality < 5) quality = 5;
          742 
          743    stbiw__sbpush(out, 0x78);   // DEFLATE 32K window
          744    stbiw__sbpush(out, 0x5e);   // FLEVEL = 1
          745    stbiw__zlib_add(1,1);  // BFINAL = 1
          746    stbiw__zlib_add(1,2);  // BTYPE = 1 -- fixed huffman
          747 
          748    for (i=0; i < stbiw__ZHASH; ++i)
          749       hash_table[i] = NULL;
          750 
          751    i=0;
          752    while (i < data_len-3) {
          753       // hash next 3 bytes of data to be compressed
          754       int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3;
          755       unsigned char *bestloc = 0;
          756       unsigned char **hlist = hash_table[h];
          757       int n = stbiw__sbcount(hlist);
          758       for (j=0; j < n; ++j) {
          759          if (hlist[j]-data > i-32768) { // if entry lies within window
          760             int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i);
          761             if (d >= best) best=d,bestloc=hlist[j];
          762          }
          763       }
          764       // when hash table entry is too long, delete half the entries
          765       if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) {
          766          STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);
          767          stbiw__sbn(hash_table[h]) = quality;
          768       }
          769       stbiw__sbpush(hash_table[h],data+i);
          770 
          771       if (bestloc) {
          772          // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal
          773          h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1);
          774          hlist = hash_table[h];
          775          n = stbiw__sbcount(hlist);
          776          for (j=0; j < n; ++j) {
          777             if (hlist[j]-data > i-32767) {
          778                int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1);
          779                if (e > best) { // if next match is better, bail on current match
          780                   bestloc = NULL;
          781                   break;
          782                }
          783             }
          784          }
          785       }
          786 
          787       if (bestloc) {
          788          int d = (int) (data+i - bestloc); // distance back
          789          STBIW_ASSERT(d <= 32767 && best <= 258);
          790          for (j=0; best > lengthc[j+1]-1; ++j);
          791          stbiw__zlib_huff(j+257);
          792          if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]);
          793          for (j=0; d > distc[j+1]-1; ++j);
          794          stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5);
          795          if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]);
          796          i += best;
          797       } else {
          798          stbiw__zlib_huffb(data[i]);
          799          ++i;
          800       }
          801    }
          802    // write out final bytes
          803    for (;i < data_len; ++i)
          804       stbiw__zlib_huffb(data[i]);
          805    stbiw__zlib_huff(256); // end of block
          806    // pad with 0 bits to byte boundary
          807    while (bitcount)
          808       stbiw__zlib_add(0,1);
          809 
          810    for (i=0; i < stbiw__ZHASH; ++i)
          811       (void) stbiw__sbfree(hash_table[i]);
          812    STBIW_FREE(hash_table);
          813 
          814    {
          815       // compute adler32 on input
          816       unsigned int s1=1, s2=0;
          817       int blocklen = (int) (data_len % 5552);
          818       j=0;
          819       while (j < data_len) {
          820          for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1;
          821          s1 %= 65521, s2 %= 65521;
          822          j += blocklen;
          823          blocklen = 5552;
          824       }
          825       stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8));
          826       stbiw__sbpush(out, STBIW_UCHAR(s2));
          827       stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8));
          828       stbiw__sbpush(out, STBIW_UCHAR(s1));
          829    }
          830    *out_len = stbiw__sbn(out);
          831    // make returned pointer freeable
          832    STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len);
          833    return (unsigned char *) stbiw__sbraw(out);
          834 }
          835 
          836 static unsigned int stbiw__crc32(unsigned char *buffer, int len)
          837 {
          838    static unsigned int crc_table[256] =
          839    {
          840       0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
          841       0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
          842       0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
          843       0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
          844       0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
          845       0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
          846       0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
          847       0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
          848       0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
          849       0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
          850       0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
          851       0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
          852       0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
          853       0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
          854       0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
          855       0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
          856       0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
          857       0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
          858       0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
          859       0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
          860       0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
          861       0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
          862       0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
          863       0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
          864       0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
          865       0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
          866       0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
          867       0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
          868       0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
          869       0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
          870       0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
          871       0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
          872    };
          873 
          874    unsigned int crc = ~0u;
          875    int i;
          876    for (i=0; i < len; ++i)
          877       crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];
          878    return ~crc;
          879 }
          880 
          881 #define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4)
          882 #define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));
          883 #define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3])
          884 
          885 static void stbiw__wpcrc(unsigned char **data, int len)
          886 {
          887    unsigned int crc = stbiw__crc32(*data - len - 4, len+4);
          888    stbiw__wp32(*data, crc);
          889 }
          890 
          891 static unsigned char stbiw__paeth(int a, int b, int c)
          892 {
          893    int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c);
          894    if (pa <= pb && pa <= pc) return STBIW_UCHAR(a);
          895    if (pb <= pc) return STBIW_UCHAR(b);
          896    return STBIW_UCHAR(c);
          897 }
          898 
          899 unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
          900 {
          901    int ctype[5] = { -1, 0, 4, 2, 6 };
          902    unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
          903    unsigned char *out,*o, *filt, *zlib;
          904    signed char *line_buffer;
          905    int i,j,k,p,zlen;
          906 
          907    if (stride_bytes == 0)
          908       stride_bytes = x * n;
          909 
          910    filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0;
          911    line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; }
          912    for (j=0; j < y; ++j) {
          913       static int mapping[] = { 0,1,2,3,4 };
          914       static int firstmap[] = { 0,1,0,5,6 };
          915       int *mymap = j ? mapping : firstmap;
          916       int best = 0, bestval = 0x7fffffff;
          917       for (p=0; p < 2; ++p) {
          918          for (k= p?best:0; k < 5; ++k) {
          919             int type = mymap[k],est=0;
          920             unsigned char *z = pixels + stride_bytes*j;
          921             for (i=0; i < n; ++i)
          922                switch (type) {
          923                   case 0: line_buffer[i] = z[i]; break;
          924                   case 1: line_buffer[i] = z[i]; break;
          925                   case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
          926                   case 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break;
          927                   case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-stride_bytes],0)); break;
          928                   case 5: line_buffer[i] = z[i]; break;
          929                   case 6: line_buffer[i] = z[i]; break;
          930                }
          931             for (i=n; i < x*n; ++i) {
          932                switch (type) {
          933                   case 0: line_buffer[i] = z[i]; break;
          934                   case 1: line_buffer[i] = z[i] - z[i-n]; break;
          935                   case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
          936                   case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>1); break;
          937                   case 4: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-stride_bytes], z[i-stride_bytes-n]); break;
          938                   case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break;
          939                   case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break;
          940                }
          941             }
          942             if (p) break;
          943             for (i=0; i < x*n; ++i)
          944                est += abs((signed char) line_buffer[i]);
          945             if (est < bestval) { bestval = est; best = k; }
          946          }
          947       }
          948       // when we get here, best contains the filter type, and line_buffer contains the data
          949       filt[j*(x*n+1)] = (unsigned char) best;
          950       STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n);
          951    }
          952    STBIW_FREE(line_buffer);
          953    zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory
          954    STBIW_FREE(filt);
          955    if (!zlib) return 0;
          956 
          957    // each tag requires 12 bytes of overhead
          958    out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12);
          959    if (!out) return 0;
          960    *out_len = 8 + 12+13 + 12+zlen + 12;
          961 
          962    o=out;
          963    STBIW_MEMMOVE(o,sig,8); o+= 8;
          964    stbiw__wp32(o, 13); // header length
          965    stbiw__wptag(o, "IHDR");
          966    stbiw__wp32(o, x);
          967    stbiw__wp32(o, y);
          968    *o++ = 8;
          969    *o++ = STBIW_UCHAR(ctype[n]);
          970    *o++ = 0;
          971    *o++ = 0;
          972    *o++ = 0;
          973    stbiw__wpcrc(&o,13);
          974 
          975    stbiw__wp32(o, zlen);
          976    stbiw__wptag(o, "IDAT");
          977    STBIW_MEMMOVE(o, zlib, zlen);
          978    o += zlen;
          979    STBIW_FREE(zlib);
          980    stbiw__wpcrc(&o, zlen);
          981 
          982    stbiw__wp32(o,0);
          983    stbiw__wptag(o, "IEND");
          984    stbiw__wpcrc(&o,0);
          985 
          986    STBIW_ASSERT(o == out + *out_len);
          987 
          988    return out;
          989 }
          990 
          991 #ifndef STBI_WRITE_NO_STDIO
          992 STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
          993 {
          994    FILE *f;
          995    int len;
          996    unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
          997    if (png == NULL) return 0;
          998    f = fopen(filename, "wb");
          999    if (!f) { STBIW_FREE(png); return 0; }
         1000    fwrite(png, 1, len, f);
         1001    fclose(f);
         1002    STBIW_FREE(png);
         1003    return 1;
         1004 }
         1005 #endif
         1006 
         1007 STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes)
         1008 {
         1009    int len;
         1010    unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
         1011    if (png == NULL) return 0;
         1012    func(context, png, len);
         1013    STBIW_FREE(png);
         1014    return 1;
         1015 }
         1016 
         1017 #endif // STB_IMAGE_WRITE_IMPLEMENTATION
         1018 
         1019 /* Revision history
         1020       1.02 (2016-04-02)
         1021              avoid allocating large structures on the stack
         1022       1.01 (2016-01-16)
         1023              STBIW_REALLOC_SIZED: support allocators with no realloc support
         1024              avoid race-condition in crc initialization
         1025              minor compile issues
         1026       1.00 (2015-09-14)
         1027              installable file IO function
         1028       0.99 (2015-09-13)
         1029              warning fixes; TGA rle support
         1030       0.98 (2015-04-08)
         1031              added STBIW_MALLOC, STBIW_ASSERT etc
         1032       0.97 (2015-01-18)
         1033              fixed HDR asserts, rewrote HDR rle logic
         1034       0.96 (2015-01-17)
         1035              add HDR output
         1036              fix monochrome BMP
         1037       0.95 (2014-08-17)
         1038                        add monochrome TGA output
         1039       0.94 (2014-05-31)
         1040              rename private functions to avoid conflicts with stb_image.h
         1041       0.93 (2014-05-27)
         1042              warning fixes
         1043       0.92 (2010-08-01)
         1044              casts to unsigned char to fix warnings
         1045       0.91 (2010-07-17)
         1046              first public release
         1047       0.90   first internal release
         1048 */