medfall

A super great game engine
Log | Files | Refs

stb_image_write.h (40569B)


      1 /* stb_image_write - v1.05 - 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       github:poppolopoppo
    107       Patrick Boettcher
    108       
    109 LICENSE
    110 
    111   See end of file for license information.
    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 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case
    297       case 1:
    298          if (expand_mono)
    299             stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp
    300          else
    301             s->func(s->context, d, 1);  // monochrome TGA
    302          break;
    303       case 4:
    304          if (!write_alpha) {
    305             // composite against pink background
    306             for (k = 0; k < 3; ++k)
    307                px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255;
    308             stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]);
    309             break;
    310          }
    311          /* FALLTHROUGH */
    312       case 3:
    313          stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]);
    314          break;
    315    }
    316    if (write_alpha > 0)
    317       s->func(s->context, &d[comp - 1], 1);
    318 }
    319 
    320 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)
    321 {
    322    stbiw_uint32 zero = 0;
    323    int i,j, j_end;
    324 
    325    if (y <= 0)
    326       return;
    327 
    328    if (vdir < 0)
    329       j_end = -1, j = y-1;
    330    else
    331       j_end =  y, j = 0;
    332 
    333    for (; j != j_end; j += vdir) {
    334       for (i=0; i < x; ++i) {
    335          unsigned char *d = (unsigned char *) data + (j*x+i)*comp;
    336          stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d);
    337       }
    338       s->func(s->context, &zero, scanline_pad);
    339    }
    340 }
    341 
    342 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, ...)
    343 {
    344    if (y < 0 || x < 0) {
    345       return 0;
    346    } else {
    347       va_list v;
    348       va_start(v, fmt);
    349       stbiw__writefv(s, fmt, v);
    350       va_end(v);
    351       stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono);
    352       return 1;
    353    }
    354 }
    355 
    356 static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data)
    357 {
    358    int pad = (-x*3) & 3;
    359    return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad,
    360            "11 4 22 4" "4 44 22 444444",
    361            'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40,  // file header
    362             40, x,y, 1,24, 0,0,0,0,0,0);             // bitmap header
    363 }
    364 
    365 STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
    366 {
    367    stbi__write_context s;
    368    stbi__start_write_callbacks(&s, func, context);
    369    return stbi_write_bmp_core(&s, x, y, comp, data);
    370 }
    371 
    372 #ifndef STBI_WRITE_NO_STDIO
    373 STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
    374 {
    375    stbi__write_context s;
    376    if (stbi__start_write_file(&s,filename)) {
    377       int r = stbi_write_bmp_core(&s, x, y, comp, data);
    378       stbi__end_write_file(&s);
    379       return r;
    380    } else
    381       return 0;
    382 }
    383 #endif //!STBI_WRITE_NO_STDIO
    384 
    385 static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data)
    386 {
    387    int has_alpha = (comp == 2 || comp == 4);
    388    int colorbytes = has_alpha ? comp-1 : comp;
    389    int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3
    390 
    391    if (y < 0 || x < 0)
    392       return 0;
    393 
    394    if (!stbi_write_tga_with_rle) {
    395       return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0,
    396          "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8);
    397    } else {
    398       int i,j,k;
    399 
    400       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);
    401 
    402       for (j = y - 1; j >= 0; --j) {
    403           unsigned char *row = (unsigned char *) data + j * x * comp;
    404          int len;
    405 
    406          for (i = 0; i < x; i += len) {
    407             unsigned char *begin = row + i * comp;
    408             int diff = 1;
    409             len = 1;
    410 
    411             if (i < x - 1) {
    412                ++len;
    413                diff = memcmp(begin, row + (i + 1) * comp, comp);
    414                if (diff) {
    415                   const unsigned char *prev = begin;
    416                   for (k = i + 2; k < x && len < 128; ++k) {
    417                      if (memcmp(prev, row + k * comp, comp)) {
    418                         prev += comp;
    419                         ++len;
    420                      } else {
    421                         --len;
    422                         break;
    423                      }
    424                   }
    425                } else {
    426                   for (k = i + 2; k < x && len < 128; ++k) {
    427                      if (!memcmp(begin, row + k * comp, comp)) {
    428                         ++len;
    429                      } else {
    430                         break;
    431                      }
    432                   }
    433                }
    434             }
    435 
    436             if (diff) {
    437                unsigned char header = STBIW_UCHAR(len - 1);
    438                s->func(s->context, &header, 1);
    439                for (k = 0; k < len; ++k) {
    440                   stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp);
    441                }
    442             } else {
    443                unsigned char header = STBIW_UCHAR(len - 129);
    444                s->func(s->context, &header, 1);
    445                stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin);
    446             }
    447          }
    448       }
    449    }
    450    return 1;
    451 }
    452 
    453 int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
    454 {
    455    stbi__write_context s;
    456    stbi__start_write_callbacks(&s, func, context);
    457    return stbi_write_tga_core(&s, x, y, comp, (void *) data);
    458 }
    459 
    460 #ifndef STBI_WRITE_NO_STDIO
    461 int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
    462 {
    463    stbi__write_context s;
    464    if (stbi__start_write_file(&s,filename)) {
    465       int r = stbi_write_tga_core(&s, x, y, comp, (void *) data);
    466       stbi__end_write_file(&s);
    467       return r;
    468    } else
    469       return 0;
    470 }
    471 #endif
    472 
    473 // *************************************************************************************************
    474 // Radiance RGBE HDR writer
    475 // by Baldur Karlsson
    476 
    477 #define stbiw__max(a, b)  ((a) > (b) ? (a) : (b))
    478 
    479 void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
    480 {
    481    int exponent;
    482    float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2]));
    483 
    484    if (maxcomp < 1e-32f) {
    485       rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
    486    } else {
    487       float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp;
    488 
    489       rgbe[0] = (unsigned char)(linear[0] * normalize);
    490       rgbe[1] = (unsigned char)(linear[1] * normalize);
    491       rgbe[2] = (unsigned char)(linear[2] * normalize);
    492       rgbe[3] = (unsigned char)(exponent + 128);
    493    }
    494 }
    495 
    496 void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte)
    497 {
    498    unsigned char lengthbyte = STBIW_UCHAR(length+128);
    499    STBIW_ASSERT(length+128 <= 255);
    500    s->func(s->context, &lengthbyte, 1);
    501    s->func(s->context, &databyte, 1);
    502 }
    503 
    504 void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data)
    505 {
    506    unsigned char lengthbyte = STBIW_UCHAR(length);
    507    STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code
    508    s->func(s->context, &lengthbyte, 1);
    509    s->func(s->context, data, length);
    510 }
    511 
    512 void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline)
    513 {
    514    unsigned char scanlineheader[4] = { 2, 2, 0, 0 };
    515    unsigned char rgbe[4];
    516    float linear[3];
    517    int x;
    518 
    519    scanlineheader[2] = (width&0xff00)>>8;
    520    scanlineheader[3] = (width&0x00ff);
    521 
    522    /* skip RLE for images too small or large */
    523    if (width < 8 || width >= 32768) {
    524       for (x=0; x < width; x++) {
    525          switch (ncomp) {
    526             case 4: /* fallthrough */
    527             case 3: linear[2] = scanline[x*ncomp + 2];
    528                     linear[1] = scanline[x*ncomp + 1];
    529                     linear[0] = scanline[x*ncomp + 0];
    530                     break;
    531             default:
    532                     linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];
    533                     break;
    534          }
    535          stbiw__linear_to_rgbe(rgbe, linear);
    536          s->func(s->context, rgbe, 4);
    537       }
    538    } else {
    539       int c,r;
    540       /* encode into scratch buffer */
    541       for (x=0; x < width; x++) {
    542          switch(ncomp) {
    543             case 4: /* fallthrough */
    544             case 3: linear[2] = scanline[x*ncomp + 2];
    545                     linear[1] = scanline[x*ncomp + 1];
    546                     linear[0] = scanline[x*ncomp + 0];
    547                     break;
    548             default:
    549                     linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];
    550                     break;
    551          }
    552          stbiw__linear_to_rgbe(rgbe, linear);
    553          scratch[x + width*0] = rgbe[0];
    554          scratch[x + width*1] = rgbe[1];
    555          scratch[x + width*2] = rgbe[2];
    556          scratch[x + width*3] = rgbe[3];
    557       }
    558 
    559       s->func(s->context, scanlineheader, 4);
    560 
    561       /* RLE each component separately */
    562       for (c=0; c < 4; c++) {
    563          unsigned char *comp = &scratch[width*c];
    564 
    565          x = 0;
    566          while (x < width) {
    567             // find first run
    568             r = x;
    569             while (r+2 < width) {
    570                if (comp[r] == comp[r+1] && comp[r] == comp[r+2])
    571                   break;
    572                ++r;
    573             }
    574             if (r+2 >= width)
    575                r = width;
    576             // dump up to first run
    577             while (x < r) {
    578                int len = r-x;
    579                if (len > 128) len = 128;
    580                stbiw__write_dump_data(s, len, &comp[x]);
    581                x += len;
    582             }
    583             // if there's a run, output it
    584             if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd
    585                // find next byte after run
    586                while (r < width && comp[r] == comp[x])
    587                   ++r;
    588                // output run up to r
    589                while (x < r) {
    590                   int len = r-x;
    591                   if (len > 127) len = 127;
    592                   stbiw__write_run_data(s, len, comp[x]);
    593                   x += len;
    594                }
    595             }
    596          }
    597       }
    598    }
    599 }
    600 
    601 static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data)
    602 {
    603    if (y <= 0 || x <= 0 || data == NULL)
    604       return 0;
    605    else {
    606       // Each component is stored separately. Allocate scratch space for full output scanline.
    607       unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4);
    608       int i, len;
    609       char buffer[128];
    610       char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n";
    611       s->func(s->context, header, sizeof(header)-1);
    612 
    613       len = sprintf(buffer, "EXPOSURE=          1.0000000000000\n\n-Y %d +X %d\n", y, x);
    614       s->func(s->context, buffer, len);
    615 
    616       for(i=0; i < y; i++)
    617          stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*i*x);
    618       STBIW_FREE(scratch);
    619       return 1;
    620    }
    621 }
    622 
    623 int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data)
    624 {
    625    stbi__write_context s;
    626    stbi__start_write_callbacks(&s, func, context);
    627    return stbi_write_hdr_core(&s, x, y, comp, (float *) data);
    628 }
    629 
    630 #ifndef STBI_WRITE_NO_STDIO
    631 int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
    632 {
    633    stbi__write_context s;
    634    if (stbi__start_write_file(&s,filename)) {
    635       int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data);
    636       stbi__end_write_file(&s);
    637       return r;
    638    } else
    639       return 0;
    640 }
    641 #endif // STBI_WRITE_NO_STDIO
    642 
    643 
    644 //////////////////////////////////////////////////////////////////////////////
    645 //
    646 // PNG writer
    647 //
    648 
    649 // stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
    650 #define stbiw__sbraw(a) ((int *) (a) - 2)
    651 #define stbiw__sbm(a)   stbiw__sbraw(a)[0]
    652 #define stbiw__sbn(a)   stbiw__sbraw(a)[1]
    653 
    654 #define stbiw__sbneedgrow(a,n)  ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a))
    655 #define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0)
    656 #define stbiw__sbgrow(a,n)  stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a)))
    657 
    658 #define stbiw__sbpush(a, v)      (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v))
    659 #define stbiw__sbcount(a)        ((a) ? stbiw__sbn(a) : 0)
    660 #define stbiw__sbfree(a)         ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0)
    661 
    662 static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
    663 {
    664    int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1;
    665    void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2);
    666    STBIW_ASSERT(p);
    667    if (p) {
    668       if (!*arr) ((int *) p)[1] = 0;
    669       *arr = (void *) ((int *) p + 2);
    670       stbiw__sbm(*arr) = m;
    671    }
    672    return *arr;
    673 }
    674 
    675 static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)
    676 {
    677    while (*bitcount >= 8) {
    678       stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer));
    679       *bitbuffer >>= 8;
    680       *bitcount -= 8;
    681    }
    682    return data;
    683 }
    684 
    685 static int stbiw__zlib_bitrev(int code, int codebits)
    686 {
    687    int res=0;
    688    while (codebits--) {
    689       res = (res << 1) | (code & 1);
    690       code >>= 1;
    691    }
    692    return res;
    693 }
    694 
    695 static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit)
    696 {
    697    int i;
    698    for (i=0; i < limit && i < 258; ++i)
    699       if (a[i] != b[i]) break;
    700    return i;
    701 }
    702 
    703 static unsigned int stbiw__zhash(unsigned char *data)
    704 {
    705    stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16);
    706    hash ^= hash << 3;
    707    hash += hash >> 5;
    708    hash ^= hash << 4;
    709    hash += hash >> 17;
    710    hash ^= hash << 25;
    711    hash += hash >> 6;
    712    return hash;
    713 }
    714 
    715 #define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount))
    716 #define stbiw__zlib_add(code,codebits) \
    717       (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush())
    718 #define stbiw__zlib_huffa(b,c)  stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c)
    719 // default huffman tables
    720 #define stbiw__zlib_huff1(n)  stbiw__zlib_huffa(0x30 + (n), 8)
    721 #define stbiw__zlib_huff2(n)  stbiw__zlib_huffa(0x190 + (n)-144, 9)
    722 #define stbiw__zlib_huff3(n)  stbiw__zlib_huffa(0 + (n)-256,7)
    723 #define stbiw__zlib_huff4(n)  stbiw__zlib_huffa(0xc0 + (n)-280,8)
    724 #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))
    725 #define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n))
    726 
    727 #define stbiw__ZHASH   16384
    728 
    729 unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)
    730 {
    731    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 };
    732    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 };
    733    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 };
    734    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 };
    735    unsigned int bitbuf=0;
    736    int i,j, bitcount=0;
    737    unsigned char *out = NULL;
    738    unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**));
    739    if (quality < 5) quality = 5;
    740 
    741    stbiw__sbpush(out, 0x78);   // DEFLATE 32K window
    742    stbiw__sbpush(out, 0x5e);   // FLEVEL = 1
    743    stbiw__zlib_add(1,1);  // BFINAL = 1
    744    stbiw__zlib_add(1,2);  // BTYPE = 1 -- fixed huffman
    745 
    746    for (i=0; i < stbiw__ZHASH; ++i)
    747       hash_table[i] = NULL;
    748 
    749    i=0;
    750    while (i < data_len-3) {
    751       // hash next 3 bytes of data to be compressed
    752       int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3;
    753       unsigned char *bestloc = 0;
    754       unsigned char **hlist = hash_table[h];
    755       int n = stbiw__sbcount(hlist);
    756       for (j=0; j < n; ++j) {
    757          if (hlist[j]-data > i-32768) { // if entry lies within window
    758             int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i);
    759             if (d >= best) best=d,bestloc=hlist[j];
    760          }
    761       }
    762       // when hash table entry is too long, delete half the entries
    763       if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) {
    764          STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);
    765          stbiw__sbn(hash_table[h]) = quality;
    766       }
    767       stbiw__sbpush(hash_table[h],data+i);
    768 
    769       if (bestloc) {
    770          // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal
    771          h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1);
    772          hlist = hash_table[h];
    773          n = stbiw__sbcount(hlist);
    774          for (j=0; j < n; ++j) {
    775             if (hlist[j]-data > i-32767) {
    776                int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1);
    777                if (e > best) { // if next match is better, bail on current match
    778                   bestloc = NULL;
    779                   break;
    780                }
    781             }
    782          }
    783       }
    784 
    785       if (bestloc) {
    786          int d = (int) (data+i - bestloc); // distance back
    787          STBIW_ASSERT(d <= 32767 && best <= 258);
    788          for (j=0; best > lengthc[j+1]-1; ++j);
    789          stbiw__zlib_huff(j+257);
    790          if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]);
    791          for (j=0; d > distc[j+1]-1; ++j);
    792          stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5);
    793          if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]);
    794          i += best;
    795       } else {
    796          stbiw__zlib_huffb(data[i]);
    797          ++i;
    798       }
    799    }
    800    // write out final bytes
    801    for (;i < data_len; ++i)
    802       stbiw__zlib_huffb(data[i]);
    803    stbiw__zlib_huff(256); // end of block
    804    // pad with 0 bits to byte boundary
    805    while (bitcount)
    806       stbiw__zlib_add(0,1);
    807 
    808    for (i=0; i < stbiw__ZHASH; ++i)
    809       (void) stbiw__sbfree(hash_table[i]);
    810    STBIW_FREE(hash_table);
    811 
    812    {
    813       // compute adler32 on input
    814       unsigned int s1=1, s2=0;
    815       int blocklen = (int) (data_len % 5552);
    816       j=0;
    817       while (j < data_len) {
    818          for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1;
    819          s1 %= 65521, s2 %= 65521;
    820          j += blocklen;
    821          blocklen = 5552;
    822       }
    823       stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8));
    824       stbiw__sbpush(out, STBIW_UCHAR(s2));
    825       stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8));
    826       stbiw__sbpush(out, STBIW_UCHAR(s1));
    827    }
    828    *out_len = stbiw__sbn(out);
    829    // make returned pointer freeable
    830    STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len);
    831    return (unsigned char *) stbiw__sbraw(out);
    832 }
    833 
    834 static unsigned int stbiw__crc32(unsigned char *buffer, int len)
    835 {
    836    static unsigned int crc_table[256] =
    837    {
    838       0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
    839       0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
    840       0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
    841       0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
    842       0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
    843       0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
    844       0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
    845       0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
    846       0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
    847       0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
    848       0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
    849       0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
    850       0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
    851       0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
    852       0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
    853       0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
    854       0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
    855       0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
    856       0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
    857       0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
    858       0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
    859       0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
    860       0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
    861       0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
    862       0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
    863       0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
    864       0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
    865       0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
    866       0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
    867       0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
    868       0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
    869       0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
    870    };
    871 
    872    unsigned int crc = ~0u;
    873    int i;
    874    for (i=0; i < len; ++i)
    875       crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];
    876    return ~crc;
    877 }
    878 
    879 #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)
    880 #define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));
    881 #define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3])
    882 
    883 static void stbiw__wpcrc(unsigned char **data, int len)
    884 {
    885    unsigned int crc = stbiw__crc32(*data - len - 4, len+4);
    886    stbiw__wp32(*data, crc);
    887 }
    888 
    889 static unsigned char stbiw__paeth(int a, int b, int c)
    890 {
    891    int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c);
    892    if (pa <= pb && pa <= pc) return STBIW_UCHAR(a);
    893    if (pb <= pc) return STBIW_UCHAR(b);
    894    return STBIW_UCHAR(c);
    895 }
    896 
    897 // @OPTIMIZE: provide an option that always forces left-predict or paeth predict
    898 unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
    899 {
    900    int ctype[5] = { -1, 0, 4, 2, 6 };
    901    unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
    902    unsigned char *out,*o, *filt, *zlib;
    903    signed char *line_buffer;
    904    int i,j,k,p,zlen;
    905 
    906    if (stride_bytes == 0)
    907       stride_bytes = x * n;
    908 
    909    filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0;
    910    line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; }
    911    for (j=0; j < y; ++j) {
    912       static int mapping[] = { 0,1,2,3,4 };
    913       static int firstmap[] = { 0,1,0,5,6 };
    914       int *mymap = (j != 0) ? mapping : firstmap;
    915       int best = 0, bestval = 0x7fffffff;
    916       for (p=0; p < 2; ++p) {
    917          for (k= p?best:0; k < 5; ++k) { // @TODO: clarity: rewrite this to go 0..5, and 'continue' the unwanted ones during 2nd pass
    918             int type = mymap[k],est=0;
    919             unsigned char *z = pixels + stride_bytes*j;
    920             for (i=0; i < n; ++i)
    921                switch (type) {
    922                   case 0: line_buffer[i] = z[i]; break;
    923                   case 1: line_buffer[i] = z[i]; break;
    924                   case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
    925                   case 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break;
    926                   case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-stride_bytes],0)); break;
    927                   case 5: line_buffer[i] = z[i]; break;
    928                   case 6: line_buffer[i] = z[i]; break;
    929                }
    930             for (i=n; i < x*n; ++i) {
    931                switch (type) {
    932                   case 0: line_buffer[i] = z[i]; break;
    933                   case 1: line_buffer[i] = z[i] - z[i-n]; break;
    934                   case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
    935                   case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>1); break;
    936                   case 4: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-stride_bytes], z[i-stride_bytes-n]); break;
    937                   case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break;
    938                   case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break;
    939                }
    940             }
    941             if (p) break;
    942             for (i=0; i < x*n; ++i)
    943                est += abs((signed char) line_buffer[i]);
    944             if (est < bestval) { bestval = est; best = k; }
    945          }
    946       }
    947       // when we get here, best contains the filter type, and line_buffer contains the data
    948       filt[j*(x*n+1)] = (unsigned char) best;
    949       STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n);
    950    }
    951    STBIW_FREE(line_buffer);
    952    zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory
    953    STBIW_FREE(filt);
    954    if (!zlib) return 0;
    955 
    956    // each tag requires 12 bytes of overhead
    957    out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12);
    958    if (!out) return 0;
    959    *out_len = 8 + 12+13 + 12+zlen + 12;
    960 
    961    o=out;
    962    STBIW_MEMMOVE(o,sig,8); o+= 8;
    963    stbiw__wp32(o, 13); // header length
    964    stbiw__wptag(o, "IHDR");
    965    stbiw__wp32(o, x);
    966    stbiw__wp32(o, y);
    967    *o++ = 8;
    968    *o++ = STBIW_UCHAR(ctype[n]);
    969    *o++ = 0;
    970    *o++ = 0;
    971    *o++ = 0;
    972    stbiw__wpcrc(&o,13);
    973 
    974    stbiw__wp32(o, zlen);
    975    stbiw__wptag(o, "IDAT");
    976    STBIW_MEMMOVE(o, zlib, zlen);
    977    o += zlen;
    978    STBIW_FREE(zlib);
    979    stbiw__wpcrc(&o, zlen);
    980 
    981    stbiw__wp32(o,0);
    982    stbiw__wptag(o, "IEND");
    983    stbiw__wpcrc(&o,0);
    984 
    985    STBIW_ASSERT(o == out + *out_len);
    986 
    987    return out;
    988 }
    989 
    990 #ifndef STBI_WRITE_NO_STDIO
    991 STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
    992 {
    993    FILE *f;
    994    int len;
    995    unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
    996    if (png == NULL) return 0;
    997    f = fopen(filename, "wb");
    998    if (!f) { STBIW_FREE(png); return 0; }
    999    fwrite(png, 1, len, f);
   1000    fclose(f);
   1001    STBIW_FREE(png);
   1002    return 1;
   1003 }
   1004 #endif
   1005 
   1006 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)
   1007 {
   1008    int len;
   1009    unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
   1010    if (png == NULL) return 0;
   1011    func(context, png, len);
   1012    STBIW_FREE(png);
   1013    return 1;
   1014 }
   1015 
   1016 #endif // STB_IMAGE_WRITE_IMPLEMENTATION
   1017 
   1018 /* Revision history
   1019       1.04 (2017-03-03)
   1020              monochrome BMP expansion
   1021       1.03   ???
   1022       1.02 (2016-04-02)
   1023              avoid allocating large structures on the stack
   1024       1.01 (2016-01-16)
   1025              STBIW_REALLOC_SIZED: support allocators with no realloc support
   1026              avoid race-condition in crc initialization
   1027              minor compile issues
   1028       1.00 (2015-09-14)
   1029              installable file IO function
   1030       0.99 (2015-09-13)
   1031              warning fixes; TGA rle support
   1032       0.98 (2015-04-08)
   1033              added STBIW_MALLOC, STBIW_ASSERT etc
   1034       0.97 (2015-01-18)
   1035              fixed HDR asserts, rewrote HDR rle logic
   1036       0.96 (2015-01-17)
   1037              add HDR output
   1038              fix monochrome BMP
   1039       0.95 (2014-08-17)
   1040 		       add monochrome TGA output
   1041       0.94 (2014-05-31)
   1042              rename private functions to avoid conflicts with stb_image.h
   1043       0.93 (2014-05-27)
   1044              warning fixes
   1045       0.92 (2010-08-01)
   1046              casts to unsigned char to fix warnings
   1047       0.91 (2010-07-17)
   1048              first public release
   1049       0.90   first internal release
   1050 */
   1051 
   1052 /*
   1053 ------------------------------------------------------------------------------
   1054 This software is available under 2 licenses -- choose whichever you prefer.
   1055 ------------------------------------------------------------------------------
   1056 ALTERNATIVE A - MIT License
   1057 Copyright (c) 2017 Sean Barrett
   1058 Permission is hereby granted, free of charge, to any person obtaining a copy of 
   1059 this software and associated documentation files (the "Software"), to deal in 
   1060 the Software without restriction, including without limitation the rights to 
   1061 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
   1062 of the Software, and to permit persons to whom the Software is furnished to do 
   1063 so, subject to the following conditions:
   1064 The above copyright notice and this permission notice shall be included in all 
   1065 copies or substantial portions of the Software.
   1066 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
   1067 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
   1068 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
   1069 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
   1070 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
   1071 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
   1072 SOFTWARE.
   1073 ------------------------------------------------------------------------------
   1074 ALTERNATIVE B - Public Domain (www.unlicense.org)
   1075 This is free and unencumbered software released into the public domain.
   1076 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 
   1077 software, either in source code form or as a compiled binary, for any purpose, 
   1078 commercial or non-commercial, and by any means.
   1079 In jurisdictions that recognize copyright laws, the author or authors of this 
   1080 software dedicate any and all copyright interest in the software to the public 
   1081 domain. We make this dedication for the benefit of the public at large and to 
   1082 the detriment of our heirs and successors. We intend this dedication to be an 
   1083 overt act of relinquishment in perpetuity of all present and future rights to 
   1084 this software under copyright law.
   1085 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
   1086 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
   1087 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
   1088 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 
   1089 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
   1090 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   1091 ------------------------------------------------------------------------------
   1092 */