1 /* stb_image_write - v1.01 - 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 
106 LICENSE
107 
108 This software is in the public domain. Where that dedication is not
109 recognized, you are granted a perpetual, irrevocable license to copy,
110 distribute, and modify this file as you see fit.
111 
112 */
113 
114 #ifndef INCLUDE_STB_IMAGE_WRITE_H
115 #define INCLUDE_STB_IMAGE_WRITE_H
116 
117 #ifdef __cplusplus
118 extern "C" {
119 #endif
120 
121 #ifdef STB_IMAGE_WRITE_STATIC
122 #define STBIWDEF static
123 #else
124 #define STBIWDEF extern
125 extern int stbi_write_tga_with_rle;
126 #endif
127 
128 #ifndef STBI_WRITE_NO_STDIO
129 STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void  *data, int stride_in_bytes);
130 STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void  *data);
131 STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void  *data);
132 STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
133 #endif
134 
135 typedef void stbi_write_func(void *context, void *data, int size);
136 
137 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);
138 STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);
139 STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);
140 STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
141 
142 #ifdef __cplusplus
143 }
144 #endif
145 
146 #endif//INCLUDE_STB_IMAGE_WRITE_H
147 
148 #ifdef STB_IMAGE_WRITE_IMPLEMENTATION
149 
150 #ifdef _WIN32
151    #ifndef _CRT_SECURE_NO_WARNINGS
152    #define _CRT_SECURE_NO_WARNINGS
153    #endif
154    #ifndef _CRT_NONSTDC_NO_DEPRECATE
155    #define _CRT_NONSTDC_NO_DEPRECATE
156    #endif
157 #endif
158 
159 #ifndef STBI_WRITE_NO_STDIO
160 #include <stdio.h>
161 #endif // STBI_WRITE_NO_STDIO
162 
163 #include <stdarg.h>
164 #include <stdlib.h>
165 #include <string.h>
166 #include <math.h>
167 
168 #if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED))
169 // ok
170 #elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED)
171 // ok
172 #else
173 #error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)."
174 #endif
175 
176 #ifndef STBIW_MALLOC
177 #define STBIW_MALLOC(sz)        malloc(sz)
178 #define STBIW_REALLOC(p,newsz)  realloc(p,newsz)
179 #define STBIW_FREE(p)           free(p)
180 #endif
181 
182 #ifndef STBIW_REALLOC_SIZED
183 #define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz)
184 #endif
185 
186 
187 #ifndef STBIW_MEMMOVE
188 #define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz)
189 #endif
190 
191 
192 #ifndef STBIW_ASSERT
193 #include <assert.h>
194 #define STBIW_ASSERT(x) assert(x)
195 #endif
196 
197 #define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)
198 
199 typedef struct
200 {
201    stbi_write_func *func;
202    void *context;
203 } stbi__write_context;
204 
205 // initialize a callback-based context
stbi__start_write_callbacks(stbi__write_context * s,stbi_write_func * c,void * context)206 static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context)
207 {
208    s->func    = c;
209    s->context = context;
210 }
211 
212 #ifndef STBI_WRITE_NO_STDIO
213 
stbi__stdio_write(void * context,void * data,int size)214 static void stbi__stdio_write(void *context, void *data, int size)
215 {
216    fwrite(data,1,size,(FILE*) context);
217 }
218 
stbi__start_write_file(stbi__write_context * s,const char * filename)219 static int stbi__start_write_file(stbi__write_context *s, const char *filename)
220 {
221    FILE *f = fopen(filename, "wb");
222    stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f);
223    return f != NULL;
224 }
225 
stbi__end_write_file(stbi__write_context * s)226 static void stbi__end_write_file(stbi__write_context *s)
227 {
228    fclose((FILE *)s->context);
229 }
230 
231 #endif // !STBI_WRITE_NO_STDIO
232 
233 typedef unsigned int stbiw_uint32;
234 typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
235 
236 #ifdef STB_IMAGE_WRITE_STATIC
237 static int stbi_write_tga_with_rle = 1;
238 #else
239 int stbi_write_tga_with_rle = 1;
240 #endif
241 
stbiw__writefv(stbi__write_context * s,const char * fmt,va_list v)242 static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v)
243 {
244    while (*fmt) {
245       switch (*fmt++) {
246          case ' ': break;
247          case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int));
248                      s->func(s->context,&x,1);
249                      break; }
250          case '2': { int x = va_arg(v,int);
251                      unsigned char b[2];
252                      b[0] = STBIW_UCHAR(x);
253                      b[1] = STBIW_UCHAR(x>>8);
254                      s->func(s->context,b,2);
255                      break; }
256          case '4': { stbiw_uint32 x = va_arg(v,int);
257                      unsigned char b[4];
258                      b[0]=STBIW_UCHAR(x);
259                      b[1]=STBIW_UCHAR(x>>8);
260                      b[2]=STBIW_UCHAR(x>>16);
261                      b[3]=STBIW_UCHAR(x>>24);
262                      s->func(s->context,b,4);
263                      break; }
264          default:
265             STBIW_ASSERT(0);
266             return;
267       }
268    }
269 }
270 
stbiw__writef(stbi__write_context * s,const char * fmt,...)271 static void stbiw__writef(stbi__write_context *s, const char *fmt, ...)
272 {
273    va_list v;
274    va_start(v, fmt);
275    stbiw__writefv(s, fmt, v);
276    va_end(v);
277 }
278 
stbiw__write3(stbi__write_context * s,unsigned char a,unsigned char b,unsigned char c)279 static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c)
280 {
281    unsigned char arr[3];
282    arr[0] = a, arr[1] = b, arr[2] = c;
283    s->func(s->context, arr, 3);
284 }
285 
stbiw__write_pixel(stbi__write_context * s,int rgb_dir,int comp,int write_alpha,int expand_mono,unsigned char * d)286 static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d)
287 {
288    unsigned char bg[3] = { 255, 0, 255}, px[3];
289    int k;
290 
291    if (write_alpha < 0)
292       s->func(s->context, &d[comp - 1], 1);
293 
294    switch (comp) {
295       case 1:
296          s->func(s->context,d,1);
297          break;
298       case 2:
299          if (expand_mono)
300             stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp
301          else
302             s->func(s->context, d, 1);  // monochrome TGA
303          break;
304       case 4:
305          if (!write_alpha) {
306             // composite against pink background
307             for (k = 0; k < 3; ++k)
308                px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255;
309             stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]);
310             break;
311          }
312          /* FALLTHROUGH */
313       case 3:
314          stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]);
315          break;
316    }
317    if (write_alpha > 0)
318       s->func(s->context, &d[comp - 1], 1);
319 }
320 
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 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)
322 {
323    stbiw_uint32 zero = 0;
324    int i,j, j_end;
325 
326    if (y <= 0)
327       return;
328 
329    if (vdir < 0)
330       j_end = -1, j = y-1;
331    else
332       j_end =  y, j = 0;
333 
334    for (; j != j_end; j += vdir) {
335       for (i=0; i < x; ++i) {
336          unsigned char *d = (unsigned char *) data + (j*x+i)*comp;
337          stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d);
338       }
339       s->func(s->context, &zero, scanline_pad);
340    }
341 }
342 
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 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, ...)
344 {
345    if (y < 0 || x < 0) {
346       return 0;
347    } else {
348       va_list v;
349       va_start(v, fmt);
350       stbiw__writefv(s, fmt, v);
351       va_end(v);
352       stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono);
353       return 1;
354    }
355 }
356 
stbi_write_bmp_core(stbi__write_context * s,int x,int y,int comp,const void * data)357 static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data)
358 {
359    int pad = (-x*3) & 3;
360    return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad,
361            "11 4 22 4" "4 44 22 444444",
362            'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40,  // file header
363             40, x,y, 1,24, 0,0,0,0,0,0);             // bitmap header
364 }
365 
stbi_write_bmp_to_func(stbi_write_func * func,void * context,int x,int y,int comp,const void * data)366 STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
367 {
368    stbi__write_context s;
369    stbi__start_write_callbacks(&s, func, context);
370    return stbi_write_bmp_core(&s, x, y, comp, data);
371 }
372 
373 #ifndef STBI_WRITE_NO_STDIO
stbi_write_bmp(char const * filename,int x,int y,int comp,const void * data)374 STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
375 {
376    stbi__write_context s;
377    if (stbi__start_write_file(&s,filename)) {
378       int r = stbi_write_bmp_core(&s, x, y, comp, data);
379       stbi__end_write_file(&s);
380       return r;
381    } else
382       return 0;
383 }
384 #endif //!STBI_WRITE_NO_STDIO
385 
stbi_write_tga_core(stbi__write_context * s,int x,int y,int comp,void * data)386 static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data)
387 {
388    int has_alpha = (comp == 2 || comp == 4);
389    int colorbytes = has_alpha ? comp-1 : comp;
390    int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3
391 
392    if (y < 0 || x < 0)
393       return 0;
394 
395    if (!stbi_write_tga_with_rle) {
396       return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0,
397          "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8);
398    } else {
399       int i,j,k;
400 
401       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);
402 
403       for (j = y - 1; j >= 0; --j) {
404           unsigned char *row = (unsigned char *) data + j * x * comp;
405          int len;
406 
407          for (i = 0; i < x; i += len) {
408             unsigned char *begin = row + i * comp;
409             int diff = 1;
410             len = 1;
411 
412             if (i < x - 1) {
413                ++len;
414                diff = memcmp(begin, row + (i + 1) * comp, comp);
415                if (diff) {
416                   const unsigned char *prev = begin;
417                   for (k = i + 2; k < x && len < 128; ++k) {
418                      if (memcmp(prev, row + k * comp, comp)) {
419                         prev += comp;
420                         ++len;
421                      } else {
422                         --len;
423                         break;
424                      }
425                   }
426                } else {
427                   for (k = i + 2; k < x && len < 128; ++k) {
428                      if (!memcmp(begin, row + k * comp, comp)) {
429                         ++len;
430                      } else {
431                         break;
432                      }
433                   }
434                }
435             }
436 
437             if (diff) {
438                unsigned char header = STBIW_UCHAR(len - 1);
439                s->func(s->context, &header, 1);
440                for (k = 0; k < len; ++k) {
441                   stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp);
442                }
443             } else {
444                unsigned char header = STBIW_UCHAR(len - 129);
445                s->func(s->context, &header, 1);
446                stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin);
447             }
448          }
449       }
450    }
451    return 1;
452 }
453 
stbi_write_tga_to_func(stbi_write_func * func,void * context,int x,int y,int comp,const void * data)454 int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
455 {
456    stbi__write_context s;
457    stbi__start_write_callbacks(&s, func, context);
458    return stbi_write_tga_core(&s, x, y, comp, (void *) data);
459 }
460 
461 #ifndef STBI_WRITE_NO_STDIO
stbi_write_tga(char const * filename,int x,int y,int comp,const void * data)462 int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
463 {
464    stbi__write_context s;
465    if (stbi__start_write_file(&s,filename)) {
466       int r = stbi_write_tga_core(&s, x, y, comp, (void *) data);
467       stbi__end_write_file(&s);
468       return r;
469    } else
470       return 0;
471 }
472 #endif
473 
474 // *************************************************************************************************
475 // Radiance RGBE HDR writer
476 // by Baldur Karlsson
477 #ifndef STBI_WRITE_NO_STDIO
478 
479 #define stbiw__max(a, b)  ((a) > (b) ? (a) : (b))
480 
stbiw__linear_to_rgbe(unsigned char * rgbe,float * linear)481 void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
482 {
483    int exponent;
484    float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2]));
485 
486    if (maxcomp < 1e-32f) {
487       rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
488    } else {
489       float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp;
490 
491       rgbe[0] = (unsigned char)(linear[0] * normalize);
492       rgbe[1] = (unsigned char)(linear[1] * normalize);
493       rgbe[2] = (unsigned char)(linear[2] * normalize);
494       rgbe[3] = (unsigned char)(exponent + 128);
495    }
496 }
497 
stbiw__write_run_data(stbi__write_context * s,int length,unsigned char databyte)498 void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte)
499 {
500    unsigned char lengthbyte = STBIW_UCHAR(length+128);
501    STBIW_ASSERT(length+128 <= 255);
502    s->func(s->context, &lengthbyte, 1);
503    s->func(s->context, &databyte, 1);
504 }
505 
stbiw__write_dump_data(stbi__write_context * s,int length,unsigned char * data)506 void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data)
507 {
508    unsigned char lengthbyte = STBIW_UCHAR(length);
509    STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code
510    s->func(s->context, &lengthbyte, 1);
511    s->func(s->context, data, length);
512 }
513 
stbiw__write_hdr_scanline(stbi__write_context * s,int width,int ncomp,unsigned char * scratch,float * scanline)514 void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline)
515 {
516    unsigned char scanlineheader[4] = { 2, 2, 0, 0 };
517    unsigned char rgbe[4];
518    float linear[3];
519    int x;
520 
521    scanlineheader[2] = (width&0xff00)>>8;
522    scanlineheader[3] = (width&0x00ff);
523 
524    /* skip RLE for images too small or large */
525    if (width < 8 || width >= 32768) {
526       for (x=0; x < width; x++) {
527          switch (ncomp) {
528             case 4: /* fallthrough */
529             case 3: linear[2] = scanline[x*ncomp + 2];
530                     linear[1] = scanline[x*ncomp + 1];
531                     linear[0] = scanline[x*ncomp + 0];
532                     break;
533             default:
534                     linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];
535                     break;
536          }
537          stbiw__linear_to_rgbe(rgbe, linear);
538          s->func(s->context, rgbe, 4);
539       }
540    } else {
541       int c,r;
542       /* encode into scratch buffer */
543       for (x=0; x < width; x++) {
544          switch(ncomp) {
545             case 4: /* fallthrough */
546             case 3: linear[2] = scanline[x*ncomp + 2];
547                     linear[1] = scanline[x*ncomp + 1];
548                     linear[0] = scanline[x*ncomp + 0];
549                     break;
550             default:
551                     linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];
552                     break;
553          }
554          stbiw__linear_to_rgbe(rgbe, linear);
555          scratch[x + width*0] = rgbe[0];
556          scratch[x + width*1] = rgbe[1];
557          scratch[x + width*2] = rgbe[2];
558          scratch[x + width*3] = rgbe[3];
559       }
560 
561       s->func(s->context, scanlineheader, 4);
562 
563       /* RLE each component separately */
564       for (c=0; c < 4; c++) {
565          unsigned char *comp = &scratch[width*c];
566 
567          x = 0;
568          while (x < width) {
569             // find first run
570             r = x;
571             while (r+2 < width) {
572                if (comp[r] == comp[r+1] && comp[r] == comp[r+2])
573                   break;
574                ++r;
575             }
576             if (r+2 >= width)
577                r = width;
578             // dump up to first run
579             while (x < r) {
580                int len = r-x;
581                if (len > 128) len = 128;
582                stbiw__write_dump_data(s, len, &comp[x]);
583                x += len;
584             }
585             // if there's a run, output it
586             if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd
587                // find next byte after run
588                while (r < width && comp[r] == comp[x])
589                   ++r;
590                // output run up to r
591                while (x < r) {
592                   int len = r-x;
593                   if (len > 127) len = 127;
594                   stbiw__write_run_data(s, len, comp[x]);
595                   x += len;
596                }
597             }
598          }
599       }
600    }
601 }
602 
stbi_write_hdr_core(stbi__write_context * s,int x,int y,int comp,float * data)603 static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data)
604 {
605    if (y <= 0 || x <= 0 || data == NULL)
606       return 0;
607    else {
608       // Each component is stored separately. Allocate scratch space for full output scanline.
609       unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4);
610       int i, len;
611       char buffer[128];
612       char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n";
613       s->func(s->context, header, sizeof(header)-1);
614 
615       len = sprintf(buffer, "EXPOSURE=          1.0000000000000\n\n-Y %d +X %d\n", y, x);
616       s->func(s->context, buffer, len);
617 
618       for(i=0; i < y; i++)
619          stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*i*x);
620       STBIW_FREE(scratch);
621       return 1;
622    }
623 }
624 
stbi_write_hdr_to_func(stbi_write_func * func,void * context,int x,int y,int comp,const float * data)625 int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data)
626 {
627    stbi__write_context s;
628    stbi__start_write_callbacks(&s, func, context);
629    return stbi_write_hdr_core(&s, x, y, comp, (float *) data);
630 }
631 
stbi_write_hdr(char const * filename,int x,int y,int comp,const float * data)632 int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
633 {
634    stbi__write_context s;
635    if (stbi__start_write_file(&s,filename)) {
636       int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data);
637       stbi__end_write_file(&s);
638       return r;
639    } else
640       return 0;
641 }
642 #endif // STBI_WRITE_NO_STDIO
643 
644 
645 //////////////////////////////////////////////////////////////////////////////
646 //
647 // PNG writer
648 //
649 
650 // stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
651 #define stbiw__sbraw(a) ((int *) (a) - 2)
652 #define stbiw__sbm(a)   stbiw__sbraw(a)[0]
653 #define stbiw__sbn(a)   stbiw__sbraw(a)[1]
654 
655 #define stbiw__sbneedgrow(a,n)  ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a))
656 #define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0)
657 #define stbiw__sbgrow(a,n)  stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a)))
658 
659 #define stbiw__sbpush(a, v)      (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v))
660 #define stbiw__sbcount(a)        ((a) ? stbiw__sbn(a) : 0)
661 #define stbiw__sbfree(a)         ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0)
662 
stbiw__sbgrowf(void ** arr,int increment,int itemsize)663 static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
664 {
665    int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1;
666    void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2);
667    STBIW_ASSERT(p);
668    if (p) {
669       if (!*arr) ((int *) p)[1] = 0;
670       *arr = (void *) ((int *) p + 2);
671       stbiw__sbm(*arr) = m;
672    }
673    return *arr;
674 }
675 
stbiw__zlib_flushf(unsigned char * data,unsigned int * bitbuffer,int * bitcount)676 static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)
677 {
678    while (*bitcount >= 8) {
679       stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer));
680       *bitbuffer >>= 8;
681       *bitcount -= 8;
682    }
683    return data;
684 }
685 
stbiw__zlib_bitrev(int code,int codebits)686 static int stbiw__zlib_bitrev(int code, int codebits)
687 {
688    int res=0;
689    while (codebits--) {
690       res = (res << 1) | (code & 1);
691       code >>= 1;
692    }
693    return res;
694 }
695 
stbiw__zlib_countm(unsigned char * a,unsigned char * b,int limit)696 static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit)
697 {
698    int i;
699    for (i=0; i < limit && i < 258; ++i)
700       if (a[i] != b[i]) break;
701    return i;
702 }
703 
stbiw__zhash(unsigned char * data)704 static unsigned int stbiw__zhash(unsigned char *data)
705 {
706    stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16);
707    hash ^= hash << 3;
708    hash += hash >> 5;
709    hash ^= hash << 4;
710    hash += hash >> 17;
711    hash ^= hash << 25;
712    hash += hash >> 6;
713    return hash;
714 }
715 
716 #define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount))
717 #define stbiw__zlib_add(code,codebits) \
718       (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush())
719 #define stbiw__zlib_huffa(b,c)  stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c)
720 // default huffman tables
721 #define stbiw__zlib_huff1(n)  stbiw__zlib_huffa(0x30 + (n), 8)
722 #define stbiw__zlib_huff2(n)  stbiw__zlib_huffa(0x190 + (n)-144, 9)
723 #define stbiw__zlib_huff3(n)  stbiw__zlib_huffa(0 + (n)-256,7)
724 #define stbiw__zlib_huff4(n)  stbiw__zlib_huffa(0xc0 + (n)-280,8)
725 #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))
726 #define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n))
727 
728 #define stbiw__ZHASH   16384
729 
stbi_zlib_compress(unsigned char * data,int data_len,int * out_len,int quality)730 unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)
731 {
732    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 };
733    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 };
734    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 };
735    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 };
736    unsigned int bitbuf=0;
737    int i,j, bitcount=0;
738    unsigned char *out = NULL;
739    unsigned char **hash_table[stbiw__ZHASH]; // 64KB on the stack!
740    if (quality < 5) quality = 5;
741 
742    stbiw__sbpush(out, 0x78);   // DEFLATE 32K window
743    stbiw__sbpush(out, 0x5e);   // FLEVEL = 1
744    stbiw__zlib_add(1,1);  // BFINAL = 1
745    stbiw__zlib_add(1,2);  // BTYPE = 1 -- fixed huffman
746 
747    for (i=0; i < stbiw__ZHASH; ++i)
748       hash_table[i] = NULL;
749 
750    i=0;
751    while (i < data_len-3) {
752       // hash next 3 bytes of data to be compressed
753       int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3;
754       unsigned char *bestloc = 0;
755       unsigned char **hlist = hash_table[h];
756       int n = stbiw__sbcount(hlist);
757       for (j=0; j < n; ++j) {
758          if (hlist[j]-data > i-32768) { // if entry lies within window
759             int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i);
760             if (d >= best) best=d,bestloc=hlist[j];
761          }
762       }
763       // when hash table entry is too long, delete half the entries
764       if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) {
765          STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);
766          stbiw__sbn(hash_table[h]) = quality;
767       }
768       stbiw__sbpush(hash_table[h],data+i);
769 
770       if (bestloc) {
771          // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal
772          h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1);
773          hlist = hash_table[h];
774          n = stbiw__sbcount(hlist);
775          for (j=0; j < n; ++j) {
776             if (hlist[j]-data > i-32767) {
777                int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1);
778                if (e > best) { // if next match is better, bail on current match
779                   bestloc = NULL;
780                   break;
781                }
782             }
783          }
784       }
785 
786       if (bestloc) {
787          int d = (int) (data+i - bestloc); // distance back
788          STBIW_ASSERT(d <= 32767 && best <= 258);
789          for (j=0; best > lengthc[j+1]-1; ++j);
790          stbiw__zlib_huff(j+257);
791          if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]);
792          for (j=0; d > distc[j+1]-1; ++j);
793          stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5);
794          if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]);
795          i += best;
796       } else {
797          stbiw__zlib_huffb(data[i]);
798          ++i;
799       }
800    }
801    // write out final bytes
802    for (;i < data_len; ++i)
803       stbiw__zlib_huffb(data[i]);
804    stbiw__zlib_huff(256); // end of block
805    // pad with 0 bits to byte boundary
806    while (bitcount)
807       stbiw__zlib_add(0,1);
808 
809    for (i=0; i < stbiw__ZHASH; ++i)
810       (void) stbiw__sbfree(hash_table[i]);
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 
stbiw__crc32(unsigned char * buffer,int len)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 
stbiw__wpcrc(unsigned char ** data,int len)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 
stbiw__paeth(int a,int b,int c)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 
stbi_write_png_to_mem(unsigned char * pixels,int stride_bytes,int x,int y,int n,int * out_len)897 unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
898 {
899    int ctype[5] = { -1, 0, 4, 2, 6 };
900    unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
901    unsigned char *out,*o, *filt, *zlib;
902    signed char *line_buffer;
903    int i,j,k,p,zlen;
904 
905    if (stride_bytes == 0)
906       stride_bytes = x * n;
907 
908    filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0;
909    line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; }
910    for (j=0; j < y; ++j) {
911       static int mapping[] = { 0,1,2,3,4 };
912       static int firstmap[] = { 0,1,0,5,6 };
913       int *mymap = j ? mapping : firstmap;
914       int best = 0, bestval = 0x7fffffff;
915       for (p=0; p < 2; ++p) {
916          for (k= p?best:0; k < 5; ++k) {
917             int type = mymap[k],est=0;
918             unsigned char *z = pixels + stride_bytes*j;
919             for (i=0; i < n; ++i)
920                switch (type) {
921                   case 0: line_buffer[i] = z[i]; break;
922                   case 1: line_buffer[i] = z[i]; break;
923                   case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
924                   case 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break;
925                   case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-stride_bytes],0)); break;
926                   case 5: line_buffer[i] = z[i]; break;
927                   case 6: line_buffer[i] = z[i]; break;
928                }
929             for (i=n; i < x*n; ++i) {
930                switch (type) {
931                   case 0: line_buffer[i] = z[i]; break;
932                   case 1: line_buffer[i] = z[i] - z[i-n]; break;
933                   case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
934                   case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>1); break;
935                   case 4: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-stride_bytes], z[i-stride_bytes-n]); break;
936                   case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break;
937                   case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break;
938                }
939             }
940             if (p) break;
941             for (i=0; i < x*n; ++i)
942                est += abs((signed char) line_buffer[i]);
943             if (est < bestval) { bestval = est; best = k; }
944          }
945       }
946       // when we get here, best contains the filter type, and line_buffer contains the data
947       filt[j*(x*n+1)] = (unsigned char) best;
948       STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n);
949    }
950    STBIW_FREE(line_buffer);
951    zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory
952    STBIW_FREE(filt);
953    if (!zlib) return 0;
954 
955    // each tag requires 12 bytes of overhead
956    out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12);
957    if (!out) return 0;
958    *out_len = 8 + 12+13 + 12+zlen + 12;
959 
960    o=out;
961    STBIW_MEMMOVE(o,sig,8); o+= 8;
962    stbiw__wp32(o, 13); // header length
963    stbiw__wptag(o, "IHDR");
964    stbiw__wp32(o, x);
965    stbiw__wp32(o, y);
966    *o++ = 8;
967    *o++ = STBIW_UCHAR(ctype[n]);
968    *o++ = 0;
969    *o++ = 0;
970    *o++ = 0;
971    stbiw__wpcrc(&o,13);
972 
973    stbiw__wp32(o, zlen);
974    stbiw__wptag(o, "IDAT");
975    STBIW_MEMMOVE(o, zlib, zlen);
976    o += zlen;
977    STBIW_FREE(zlib);
978    stbiw__wpcrc(&o, zlen);
979 
980    stbiw__wp32(o,0);
981    stbiw__wptag(o, "IEND");
982    stbiw__wpcrc(&o,0);
983 
984    STBIW_ASSERT(o == out + *out_len);
985 
986    return out;
987 }
988 
989 #ifndef STBI_WRITE_NO_STDIO
stbi_write_png(char const * filename,int x,int y,int comp,const void * data,int stride_bytes)990 STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
991 {
992    FILE *f;
993    int len;
994    unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
995    if (png == NULL) return 0;
996    f = fopen(filename, "wb");
997    if (!f) { STBIW_FREE(png); return 0; }
998    fwrite(png, 1, len, f);
999    fclose(f);
1000    STBIW_FREE(png);
1001    return 1;
1002 }
1003 #endif
1004 
stbi_write_png_to_func(stbi_write_func * func,void * context,int x,int y,int comp,const void * data,int stride_bytes)1005 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)
1006 {
1007    int len;
1008    unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
1009    if (png == NULL) return 0;
1010    func(context, png, len);
1011    STBIW_FREE(png);
1012    return 1;
1013 }
1014 
1015 #endif // STB_IMAGE_WRITE_IMPLEMENTATION
1016 
1017 /* Revision history
1018       1.01 (2016-01-16)
1019              STBIW_REALLOC_SIZED: support allocators with no realloc support
1020              avoid race-condition in crc initialization
1021              minor compile issues
1022       1.00 (2015-09-14)
1023              installable file IO function
1024       0.99 (2015-09-13)
1025              warning fixes; TGA rle support
1026       0.98 (2015-04-08)
1027              added STBIW_MALLOC, STBIW_ASSERT etc
1028       0.97 (2015-01-18)
1029              fixed HDR asserts, rewrote HDR rle logic
1030       0.96 (2015-01-17)
1031              add HDR output
1032              fix monochrome BMP
1033       0.95 (2014-08-17)
1034 		       add monochrome TGA output
1035       0.94 (2014-05-31)
1036              rename private functions to avoid conflicts with stb_image.h
1037       0.93 (2014-05-27)
1038              warning fixes
1039       0.92 (2010-08-01)
1040              casts to unsigned char to fix warnings
1041       0.91 (2010-07-17)
1042              first public release
1043       0.90   first internal release
1044 */
1045