zorldo

Goofing around with Ebiten
git clone git://bsandro.tech/zorldo
Log | Files | Refs | README

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 */