stb_image_write.h 33.4 KB
Newer Older
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
S
Sean Barrett 已提交
4

5
   Before #including,
S
Sean Barrett 已提交
6

7
       #define STB_IMAGE_WRITE_IMPLEMENTATION
S
Sean Barrett 已提交
8

9
   in the file that you want to have the implementation.
S
Sean Barrett 已提交
10

11
   Will probably not work correctly with strict-aliasing optimizations.
S
Sean Barrett 已提交
12 13 14 15 16 17 18 19

ABOUT:

   This header file is a library for writing images to C stdio. It could be
   adapted to write to memory or a general streaming interface; let me know.

   The PNG output is not optimal; it is 20-50% larger than the file
   written by a decent optimizing implementation. This library is designed
20
   for source code compactness and simplicity, not optimal image file size
S
Sean Barrett 已提交
21 22
   or run-time performance.

23 24 25 26 27 28 29
BUILDING:

   You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h.
   You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace
   malloc,realloc,free.
   You can define STBIW_MEMMOVE() to replace memmove()

S
Sean Barrett 已提交
30 31
USAGE:

B
baldurk 已提交
32
   There are four functions, one for each image file format:
S
Sean Barrett 已提交
33 34 35 36

     int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
     int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
     int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
B
baldurk 已提交
37
     int stbi_write_hdr(char const *filename, int w, int h, int comp, const void *data);
S
Sean Barrett 已提交
38

39 40
   There are also four equivalent functions that use an arbitrary write function. You are
   expected to open/close your file-equivalent before and after calling these:
41

42 43 44 45
     int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data, int stride_in_bytes);
     int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);
     int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);
     int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
46

47 48 49
   where the callback is:
      void stbi_write_func(void *context, void *data, int size);

50
   You can define STBI_WRITE_NO_STDIO to disable the file variant of these
51 52
   functions, so the library will not use stdio.h at all. However, this will
   also disable HDR writing, because it requires stdio for formatted output.
S
Sean Barrett 已提交
53 54

   Each function returns 0 on failure and non-0 on success.
55

S
Sean Barrett 已提交
56 57 58 59 60 61 62 63 64 65
   The functions create an image file defined by the parameters. The image
   is a rectangle of pixels stored from left-to-right, top-to-bottom.
   Each pixel contains 'comp' channels of data stored interleaved with 8-bits
   per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is
   monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall.
   The *data pointer points to the first byte of the top-left-most pixel.
   For PNG, "stride_in_bytes" is the distance in bytes from the first byte of
   a row of pixels to the first byte of the next row of pixels.

   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
S
Sean Barrett 已提交
67
   output alpha.
68

S
Sean Barrett 已提交
69 70 71 72 73 74
   PNG supports writing rectangles of data even when the bytes storing rows of
   data are not consecutive in memory (e.g. sub-rectangles of a larger image),
   by supplying the stride between the beginning of adjacent rows. The other
   formats do not. (Thus you cannot write a native-format BMP through the BMP
   writer, both because it is in BGR order and because it may have padding
   at the end of the line.)
B
baldurk 已提交
75 76 77 78

   HDR expects linear float data. Since the format is always 32-bit rgb(e)
   data, alpha (if provided) is discarded, and for monochrome data it is
   replicated across all three channels.
79

S
Sean Barrett 已提交
80 81 82
   TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed
   data, set the global variable 'stbi_write_tga_with_rle' to 0.

83 84 85 86 87 88 89 90
CREDITS:

   PNG/BMP/TGA
      Sean Barrett
   HDR
      Baldur Karlsson
   TGA monochrome:
      Jean-Sebastien Guay
91 92
   misc enhancements:
      Tim Kelsey
S
Sean Barrett 已提交
93 94
   TGA RLE
      Alan Hickman
S
Sean Barrett 已提交
95
   initial file IO callback implementation
96
      Emmanuel Julien
97 98
   bugfixes:
      github:Chribba
S
credits  
Sean Barrett 已提交
99
      Guillaume Chereau
S
Sean Barrett 已提交
100
      github:jry2
101
      github:romigrou
102 103 104 105 106 107
      
LICENSE

This software is in the public domain. Where that dedication is not
recognized, you are granted a perpetual, irrevocable license to copy,
distribute, and modify this file as you see fit.      
108

S
Sean Barrett 已提交
109 110 111 112 113 114 115 116 117
*/

#ifndef INCLUDE_STB_IMAGE_WRITE_H
#define INCLUDE_STB_IMAGE_WRITE_H

#ifdef __cplusplus
extern "C" {
#endif

118 119 120 121
#ifdef STB_IMAGE_WRITE_STATIC
#define STBIWDEF static
#else
#define STBIWDEF extern
S
Sean Barrett 已提交
122
extern int stbi_write_tga_with_rle;
123 124
#endif

125
#ifndef STBI_WRITE_NO_STDIO
126 127 128 129
STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void  *data, int stride_in_bytes);
STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void  *data);
STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void  *data);
STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
130
#endif
131

132
typedef void stbi_write_func(void *context, void *data, int size);
133

134 135 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);
STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);
STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);
STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
S
Sean Barrett 已提交
138 139 140 141 142 143 144 145 146

#ifdef __cplusplus
}
#endif

#endif//INCLUDE_STB_IMAGE_WRITE_H

#ifdef STB_IMAGE_WRITE_IMPLEMENTATION

S
Sean Barrett 已提交
147 148 149 150 151
#ifdef _WIN32
   #define _CRT_SECURE_NO_WARNINGS
   #define _CRT_NONSTDC_NO_DEPRECATE
#endif

152 153 154
#ifndef STBI_WRITE_NO_STDIO
#include <stdio.h>
#endif // STBI_WRITE_NO_STDIO
155

S
Sean Barrett 已提交
156 157 158
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
159
#include <math.h>
S
Sean Barrett 已提交
160

161
#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED))
162
// ok
163
#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED)
164 165
// ok
#else
166
#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)."
167 168
#endif

169
#ifndef STBIW_MALLOC
170 171 172
#define STBIW_MALLOC(sz)        malloc(sz)
#define STBIW_REALLOC(p,newsz)  realloc(p,newsz)
#define STBIW_FREE(p)           free(p)
173
#endif
174 175 176 177 178 179

#ifndef STBIW_REALLOC_SIZED
#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz)
#endif


180 181 182 183
#ifndef STBIW_MEMMOVE
#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz)
#endif

184

185
#ifndef STBIW_ASSERT
186
#include <assert.h>
187
#define STBIW_ASSERT(x) assert(x)
188 189
#endif

190 191
typedef struct
{
192 193
   stbi_write_func *func;
   void *context;
194 195 196
} stbi__write_context;

// initialize a callback-based context
197
static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context)
198
{
199 200
   s->func    = c;
   s->context = context;
201 202 203 204
}

#ifndef STBI_WRITE_NO_STDIO

205
static void stbi__stdio_write(void *context, void *data, int size)
206
{
207
   fwrite(data,1,size,(FILE*) context);
208 209
}

S
Sean Barrett 已提交
210
static int stbi__start_write_file(stbi__write_context *s, const char *filename)
211 212
{
   FILE *f = fopen(filename, "wb");
213
   stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f);
S
Sean Barrett 已提交
214
   return f != NULL;
215 216 217 218
}

static void stbi__end_write_file(stbi__write_context *s)
{
219
   fclose((FILE *)s->context);
220 221 222 223
}

#endif // !STBI_WRITE_NO_STDIO

S
Sean Barrett 已提交
224 225 226
typedef unsigned int stbiw_uint32;
typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];

S
Sean Barrett 已提交
227 228 229 230 231
#ifdef STB_IMAGE_WRITE_STATIC
static int stbi_write_tga_with_rle = 1;
#else
int stbi_write_tga_with_rle = 1;
#endif
F
fahickman 已提交
232

S
Sean Barrett 已提交
233
static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v)
S
Sean Barrett 已提交
234 235 236 237
{
   while (*fmt) {
      switch (*fmt++) {
         case ' ': break;
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
         case '1': { unsigned char x = (unsigned char) va_arg(v, int);
                     s->func(s->context,&x,1);
                     break; }
         case '2': { int x = va_arg(v,int);
                     unsigned char b[2];
                     b[0] = (unsigned char) x;
                     b[1] = (unsigned char) (x>>8);
                     s->func(s->context,b,2);
                     break; }
         case '4': { stbiw_uint32 x = va_arg(v,int);
                     unsigned char b[4];
                     b[0]=(unsigned char)x;
                     b[1]=(unsigned char)(x>>8);
                     b[2]=(unsigned char)(x>>16);
                     b[3]=(unsigned char)(x>>24);
                     s->func(s->context,b,4);
                     break; }
S
Sean Barrett 已提交
255
         default:
256
            STBIW_ASSERT(0);
S
Sean Barrett 已提交
257 258 259 260 261
            return;
      }
   }
}

S
Sean Barrett 已提交
262
static void stbiw__writef(stbi__write_context *s, const char *fmt, ...)
F
fahickman 已提交
263 264 265
{
   va_list v;
   va_start(v, fmt);
S
Sean Barrett 已提交
266
   stbiw__writefv(s, fmt, v);
F
fahickman 已提交
267 268 269
   va_end(v);
}

S
Sean Barrett 已提交
270
static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c)
S
Sean Barrett 已提交
271 272 273
{
   unsigned char arr[3];
   arr[0] = a, arr[1] = b, arr[2] = c;
274
   s->func(s->context, arr, 3);
S
Sean Barrett 已提交
275 276
}

S
Sean Barrett 已提交
277
static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d)
S
Sean Barrett 已提交
278 279
{
   unsigned char bg[3] = { 255, 0, 255}, px[3];
F
fahickman 已提交
280 281 282
   int k;

   if (write_alpha < 0)
283 284
      s->func(s->context, &d[comp - 1], 1);

F
fahickman 已提交
285
   switch (comp) {
286 287 288 289 290
      case 1:
         s->func(s->context,d,1);
         break;
      case 2:
         if (expand_mono)
S
Sean Barrett 已提交
291
            stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp
292 293 294 295 296 297 298 299
         else
            s->func(s->context, d, 1);  // monochrome TGA
         break;
      case 4:
         if (!write_alpha) {
            // composite against pink background
            for (k = 0; k < 3; ++k)
               px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255;
S
Sean Barrett 已提交
300
            stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]);
301 302 303 304
            break;
         }
         /* FALLTHROUGH */
      case 3:
S
Sean Barrett 已提交
305
         stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]);
F
fahickman 已提交
306 307 308
         break;
   }
   if (write_alpha > 0)
309
      s->func(s->context, &d[comp - 1], 1);
F
fahickman 已提交
310 311
}

S
Sean Barrett 已提交
312
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)
F
fahickman 已提交
313
{
S
Sean Barrett 已提交
314
   stbiw_uint32 zero = 0;
F
fahickman 已提交
315
   int i,j, j_end;
S
Sean Barrett 已提交
316 317 318 319

   if (y <= 0)
      return;

320
   if (vdir < 0)
S
Sean Barrett 已提交
321 322 323 324 325 326 327
      j_end = -1, j = y-1;
   else
      j_end =  y, j = 0;

   for (; j != j_end; j += vdir) {
      for (i=0; i < x; ++i) {
         unsigned char *d = (unsigned char *) data + (j*x+i)*comp;
S
Sean Barrett 已提交
328
         stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d);
S
Sean Barrett 已提交
329
      }
330
      s->func(s->context, &zero, scanline_pad);
S
Sean Barrett 已提交
331 332 333
   }
}

S
Sean Barrett 已提交
334
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, ...)
S
Sean Barrett 已提交
335
{
336 337 338
   if (y < 0 || x < 0) {
      return 0;
   } else {
S
Sean Barrett 已提交
339 340
      va_list v;
      va_start(v, fmt);
S
Sean Barrett 已提交
341
      stbiw__writefv(s, fmt, v);
S
Sean Barrett 已提交
342
      va_end(v);
S
Sean Barrett 已提交
343
      stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono);
344
      return 1;
S
Sean Barrett 已提交
345 346 347
   }
}

S
Sean Barrett 已提交
348
static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data)
S
Sean Barrett 已提交
349 350
{
   int pad = (-x*3) & 3;
S
Sean Barrett 已提交
351
   return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad,
S
Sean Barrett 已提交
352 353 354 355 356
           "11 4 22 4" "4 44 22 444444",
           'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40,  // file header
            40, x,y, 1,24, 0,0,0,0,0,0);             // bitmap header
}

357
STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
358 359
{
   stbi__write_context s;
360 361
   stbi__start_write_callbacks(&s, func, context);
   return stbi_write_bmp_core(&s, x, y, comp, data);
362 363 364
}

#ifndef STBI_WRITE_NO_STDIO
365
STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
366 367
{
   stbi__write_context s;
S
Sean Barrett 已提交
368 369 370 371 372 373
   if (stbi__start_write_file(&s,filename)) {
      int r = stbi_write_bmp_core(&s, x, y, comp, data);
      stbi__end_write_file(&s);
      return r;
   } else
      return 0;
374 375 376
}
#endif //!STBI_WRITE_NO_STDIO

S
Sean Barrett 已提交
377
static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data)
S
Sean Barrett 已提交
378
{
S
Sean Barrett 已提交
379 380
   int has_alpha = (comp == 2 || comp == 4);
   int colorbytes = has_alpha ? comp-1 : comp;
381
   int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3
382 383 384

   if (y < 0 || x < 0)
      return 0;
F
fahickman 已提交
385

S
Sean Barrett 已提交
386
   if (!stbi_write_tga_with_rle) {
S
Sean Barrett 已提交
387
      return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0,
F
fahickman 已提交
388
         "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8);
389
   } else {
F
fahickman 已提交
390 391
      int i,j,k;

S
Sean Barrett 已提交
392
      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);
F
fahickman 已提交
393 394

      for (j = y - 1; j >= 0; --j) {
395
          unsigned char *row = (unsigned char *) data + j * x * comp;
F
fahickman 已提交
396
         int len;
F
fahickman 已提交
397

F
fahickman 已提交
398
         for (i = 0; i < x; i += len) {
399
            unsigned char *begin = row + i * comp;
F
fahickman 已提交
400
            int diff = 1;
F
fahickman 已提交
401
            len = 1;
F
fahickman 已提交
402 403

            if (i < x - 1) {
F
fahickman 已提交
404 405
               ++len;
               diff = memcmp(begin, row + (i + 1) * comp, comp);
F
fahickman 已提交
406
               if (diff) {
F
fahickman 已提交
407 408 409 410 411
                  const unsigned char *prev = begin;
                  for (k = i + 2; k < x && len < 128; ++k) {
                     if (memcmp(prev, row + k * comp, comp)) {
                        prev += comp;
                        ++len;
F
fahickman 已提交
412
                     } else {
F
fahickman 已提交
413
                        --len;
F
fahickman 已提交
414 415 416 417
                        break;
                     }
                  }
               } else {
F
fahickman 已提交
418 419 420
                  for (k = i + 2; k < x && len < 128; ++k) {
                     if (!memcmp(begin, row + k * comp, comp)) {
                        ++len;
F
fahickman 已提交
421 422 423 424 425 426 427 428
                     } else {
                        break;
                     }
                  }
               }
            }

            if (diff) {
F
fahickman 已提交
429
               unsigned char header = (unsigned char) (len - 1);
430
               s->func(s->context, &header, 1);
F
fahickman 已提交
431
               for (k = 0; k < len; ++k) {
S
Sean Barrett 已提交
432
                  stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp);
F
fahickman 已提交
433 434
               }
            } else {
F
fahickman 已提交
435
               unsigned char header = (unsigned char) (len - 129);
436
               s->func(s->context, &header, 1);
S
Sean Barrett 已提交
437
               stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin);
F
fahickman 已提交
438 439 440 441
            }
         }
      }
   }
442
   return 1;
S
Sean Barrett 已提交
443 444
}

445
int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
446 447
{
   stbi__write_context s;
448 449
   stbi__start_write_callbacks(&s, func, context);
   return stbi_write_tga_core(&s, x, y, comp, (void *) data);
450
}
F
fahickman 已提交
451

452
#ifndef STBI_WRITE_NO_STDIO
S
Sean Barrett 已提交
453
int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
454 455
{
   stbi__write_context s;
S
Sean Barrett 已提交
456 457 458 459 460 461
   if (stbi__start_write_file(&s,filename)) {
      int r = stbi_write_tga_core(&s, x, y, comp, (void *) data);
      stbi__end_write_file(&s);
      return r;
   } else
      return 0;
S
Sean Barrett 已提交
462
}
463
#endif
S
Sean Barrett 已提交
464

B
baldurk 已提交
465 466
// *************************************************************************************************
// Radiance RGBE HDR writer
467
// by Baldur Karlsson
468 469
#ifndef STBI_WRITE_NO_STDIO

B
baldurk 已提交
470 471 472 473 474 475 476 477 478 479
#define stbiw__max(a, b)  ((a) > (b) ? (a) : (b))

void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
{
   int exponent;
   float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2]));

   if (maxcomp < 1e-32) {
      rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
   } else {
480
      float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp;
B
baldurk 已提交
481

482 483 484
      rgbe[0] = (unsigned char)(linear[0] * normalize);
      rgbe[1] = (unsigned char)(linear[1] * normalize);
      rgbe[2] = (unsigned char)(linear[2] * normalize);
B
baldurk 已提交
485 486 487 488
      rgbe[3] = (unsigned char)(exponent + 128);
   }
}

489
void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte)
B
baldurk 已提交
490
{
S
Sean Barrett 已提交
491
   unsigned char lengthbyte = (unsigned char) (length+128);
492
   STBIW_ASSERT(length+128 <= 255);
493 494
   s->func(s->context, &lengthbyte, 1);
   s->func(s->context, &databyte, 1);
B
baldurk 已提交
495 496
}

497
void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data)
B
baldurk 已提交
498 499
{
   unsigned char lengthbyte = (unsigned char )(length & 0xff);
500
   STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code
501 502
   s->func(s->context, &lengthbyte, 1);
   s->func(s->context, data, length);
B
baldurk 已提交
503 504
}

505
void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline)
B
baldurk 已提交
506 507 508 509 510 511 512 513 514 515 516 517
{
   unsigned char scanlineheader[4] = { 2, 2, 0, 0 };
   unsigned char rgbe[4];
   float linear[3];
   int x;

   scanlineheader[2] = (width&0xff00)>>8;
   scanlineheader[3] = (width&0x00ff);

   /* skip RLE for images too small or large */
   if (width < 8 || width >= 32768) {
      for (x=0; x < width; x++) {
S
Sean Barrett 已提交
518
         switch (ncomp) {
B
baldurk 已提交
519
            case 4: /* fallthrough */
S
Sean Barrett 已提交
520 521 522
            case 3: linear[2] = scanline[x*ncomp + 2];
                    linear[1] = scanline[x*ncomp + 1];
                    linear[0] = scanline[x*ncomp + 0];
B
baldurk 已提交
523
                    break;
524
            default:
S
Sean Barrett 已提交
525
                    linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];
B
baldurk 已提交
526 527 528
                    break;
         }
         stbiw__linear_to_rgbe(rgbe, linear);
529
         s->func(s->context, rgbe, 4);
B
baldurk 已提交
530 531
      }
   } else {
S
Sean Barrett 已提交
532
      int c,r;
B
baldurk 已提交
533 534
      /* encode into scratch buffer */
      for (x=0; x < width; x++) {
S
Sean Barrett 已提交
535
         switch(ncomp) {
B
baldurk 已提交
536
            case 4: /* fallthrough */
S
Sean Barrett 已提交
537 538 539
            case 3: linear[2] = scanline[x*ncomp + 2];
                    linear[1] = scanline[x*ncomp + 1];
                    linear[0] = scanline[x*ncomp + 0];
B
baldurk 已提交
540
                    break;
541
            default:
S
Sean Barrett 已提交
542
                    linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];
B
baldurk 已提交
543 544 545 546 547 548 549 550 551
                    break;
         }
         stbiw__linear_to_rgbe(rgbe, linear);
         scratch[x + width*0] = rgbe[0];
         scratch[x + width*1] = rgbe[1];
         scratch[x + width*2] = rgbe[2];
         scratch[x + width*3] = rgbe[3];
      }

552
      s->func(s->context, scanlineheader, 4);
B
baldurk 已提交
553 554

      /* RLE each component separately */
S
Sean Barrett 已提交
555 556
      for (c=0; c < 4; c++) {
         unsigned char *comp = &scratch[width*c];
B
baldurk 已提交
557

S
Sean Barrett 已提交
558 559 560 561 562 563 564 565 566 567 568 569 570 571 572
         x = 0;
         while (x < width) {
            // find first run
            r = x;
            while (r+2 < width) {
               if (comp[r] == comp[r+1] && comp[r] == comp[r+2])
                  break;
               ++r;
            }
            if (r+2 >= width)
               r = width;
            // dump up to first run
            while (x < r) {
               int len = r-x;
               if (len > 128) len = 128;
573
               stbiw__write_dump_data(s, len, &comp[x]);
S
Sean Barrett 已提交
574 575 576 577 578 579
               x += len;
            }
            // if there's a run, output it
            if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd
               // find next byte after run
               while (r < width && comp[r] == comp[x])
580
                  ++r;
S
Sean Barrett 已提交
581 582 583 584
               // output run up to r
               while (x < r) {
                  int len = r-x;
                  if (len > 127) len = 127;
585
                  stbiw__write_run_data(s, len, comp[x]);
S
Sean Barrett 已提交
586
                  x += len;
B
baldurk 已提交
587 588 589 590 591 592 593
               }
            }
         }
      }
   }
}

S
Sean Barrett 已提交
594
static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data)
B
baldurk 已提交
595
{
596 597 598 599
   if (y <= 0 || x <= 0 || data == NULL)
      return 0;
   else {
      // Each component is stored separately. Allocate scratch space for full output scanline.
600
      unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4);
601 602 603 604 605 606 607 608
      int i, len;
      char buffer[128];
      char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n";
      s->func(s->context, header, sizeof(header)-1);

      len = sprintf(buffer, "EXPOSURE=          1.0000000000000\n\n-Y %d +X %d\n", y, x);
      s->func(s->context, buffer, len);

609
      for(i=0; i < y; i++)
610
         stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*i*x);
611
      STBIW_FREE(scratch);
612
      return 1;
B
baldurk 已提交
613 614 615
   }
}

616 617 618 619 620 621 622
int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data)
{
   stbi__write_context s;
   stbi__start_write_callbacks(&s, func, context);
   return stbi_write_hdr_core(&s, x, y, comp, (float *) data);
}

S
Sean Barrett 已提交
623
int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
624 625
{
   stbi__write_context s;
S
Sean Barrett 已提交
626 627 628 629 630 631
   if (stbi__start_write_file(&s,filename)) {
      int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data);
      stbi__end_write_file(&s);
      return r;
   } else
      return 0;
632 633 634 635 636 637 638 639
}
#endif // STBI_WRITE_NO_STDIO


//////////////////////////////////////////////////////////////////////////////
//
// PNG writer
//
640

641 642 643 644
// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
#define stbiw__sbraw(a) ((int *) (a) - 2)
#define stbiw__sbm(a)   stbiw__sbraw(a)[0]
#define stbiw__sbn(a)   stbiw__sbraw(a)[1]
S
Sean Barrett 已提交
645

646 647 648
#define stbiw__sbneedgrow(a,n)  ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a))
#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0)
#define stbiw__sbgrow(a,n)  stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a)))
S
Sean Barrett 已提交
649

650 651
#define stbiw__sbpush(a, v)      (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v))
#define stbiw__sbcount(a)        ((a) ? stbiw__sbn(a) : 0)
652
#define stbiw__sbfree(a)         ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0)
S
Sean Barrett 已提交
653

654
static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
S
Sean Barrett 已提交
655
{
656
   int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1;
657
   void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2);
658
   STBIW_ASSERT(p);
S
Sean Barrett 已提交
659 660 661
   if (p) {
      if (!*arr) ((int *) p)[1] = 0;
      *arr = (void *) ((int *) p + 2);
662
      stbiw__sbm(*arr) = m;
S
Sean Barrett 已提交
663 664 665 666
   }
   return *arr;
}

667
static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)
S
Sean Barrett 已提交
668 669
{
   while (*bitcount >= 8) {
670
      stbiw__sbpush(data, (unsigned char) *bitbuffer);
S
Sean Barrett 已提交
671 672 673 674 675 676
      *bitbuffer >>= 8;
      *bitcount -= 8;
   }
   return data;
}

677
static int stbiw__zlib_bitrev(int code, int codebits)
S
Sean Barrett 已提交
678 679 680 681 682 683 684 685 686
{
   int res=0;
   while (codebits--) {
      res = (res << 1) | (code & 1);
      code >>= 1;
   }
   return res;
}

687
static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit)
S
Sean Barrett 已提交
688 689 690 691 692 693 694
{
   int i;
   for (i=0; i < limit && i < 258; ++i)
      if (a[i] != b[i]) break;
   return i;
}

695
static unsigned int stbiw__zhash(unsigned char *data)
S
Sean Barrett 已提交
696 697 698 699 700 701 702 703 704 705 706
{
   stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16);
   hash ^= hash << 3;
   hash += hash >> 5;
   hash ^= hash << 4;
   hash += hash >> 17;
   hash ^= hash << 25;
   hash += hash >> 6;
   return hash;
}

707 708 709 710
#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount))
#define stbiw__zlib_add(code,codebits) \
      (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush())
#define stbiw__zlib_huffa(b,c)  stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c)
S
Sean Barrett 已提交
711
// default huffman tables
712 713 714 715 716 717
#define stbiw__zlib_huff1(n)  stbiw__zlib_huffa(0x30 + (n), 8)
#define stbiw__zlib_huff2(n)  stbiw__zlib_huffa(0x190 + (n)-144, 9)
#define stbiw__zlib_huff3(n)  stbiw__zlib_huffa(0 + (n)-256,7)
#define stbiw__zlib_huff4(n)  stbiw__zlib_huffa(0xc0 + (n)-280,8)
#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))
#define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n))
S
Sean Barrett 已提交
718

719
#define stbiw__ZHASH   16384
S
Sean Barrett 已提交
720 721 722 723 724 725 726 727 728 729

unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)
{
   static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 };
   static unsigned char  lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4,  4,  5,  5,  5,  5,  0 };
   static unsigned short distc[]   = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 };
   static unsigned 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 };
   unsigned int bitbuf=0;
   int i,j, bitcount=0;
   unsigned char *out = NULL;
730
   unsigned char **hash_table[stbiw__ZHASH]; // 64KB on the stack!
S
Sean Barrett 已提交
731 732
   if (quality < 5) quality = 5;

733 734 735 736
   stbiw__sbpush(out, 0x78);   // DEFLATE 32K window
   stbiw__sbpush(out, 0x5e);   // FLEVEL = 1
   stbiw__zlib_add(1,1);  // BFINAL = 1
   stbiw__zlib_add(1,2);  // BTYPE = 1 -- fixed huffman
S
Sean Barrett 已提交
737

738
   for (i=0; i < stbiw__ZHASH; ++i)
S
Sean Barrett 已提交
739 740 741 742
      hash_table[i] = NULL;

   i=0;
   while (i < data_len-3) {
743
      // hash next 3 bytes of data to be compressed
744
      int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3;
S
Sean Barrett 已提交
745 746
      unsigned char *bestloc = 0;
      unsigned char **hlist = hash_table[h];
747
      int n = stbiw__sbcount(hlist);
S
Sean Barrett 已提交
748 749
      for (j=0; j < n; ++j) {
         if (hlist[j]-data > i-32768) { // if entry lies within window
750
            int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i);
S
Sean Barrett 已提交
751 752 753 754
            if (d >= best) best=d,bestloc=hlist[j];
         }
      }
      // when hash table entry is too long, delete half the entries
755
      if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) {
756
         STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);
757
         stbiw__sbn(hash_table[h]) = quality;
S
Sean Barrett 已提交
758
      }
759
      stbiw__sbpush(hash_table[h],data+i);
S
Sean Barrett 已提交
760 761 762

      if (bestloc) {
         // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal
763
         h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1);
S
Sean Barrett 已提交
764
         hlist = hash_table[h];
765
         n = stbiw__sbcount(hlist);
S
Sean Barrett 已提交
766 767
         for (j=0; j < n; ++j) {
            if (hlist[j]-data > i-32767) {
768
               int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1);
S
Sean Barrett 已提交
769 770 771 772 773 774 775 776 777
               if (e > best) { // if next match is better, bail on current match
                  bestloc = NULL;
                  break;
               }
            }
         }
      }

      if (bestloc) {
778
         int d = (int) (data+i - bestloc); // distance back
779
         STBIW_ASSERT(d <= 32767 && best <= 258);
S
Sean Barrett 已提交
780
         for (j=0; best > lengthc[j+1]-1; ++j);
781 782
         stbiw__zlib_huff(j+257);
         if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]);
S
Sean Barrett 已提交
783
         for (j=0; d > distc[j+1]-1; ++j);
784 785
         stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5);
         if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]);
S
Sean Barrett 已提交
786 787
         i += best;
      } else {
788
         stbiw__zlib_huffb(data[i]);
S
Sean Barrett 已提交
789 790 791 792 793
         ++i;
      }
   }
   // write out final bytes
   for (;i < data_len; ++i)
794 795
      stbiw__zlib_huffb(data[i]);
   stbiw__zlib_huff(256); // end of block
S
Sean Barrett 已提交
796 797
   // pad with 0 bits to byte boundary
   while (bitcount)
798
      stbiw__zlib_add(0,1);
S
Sean Barrett 已提交
799

800 801
   for (i=0; i < stbiw__ZHASH; ++i)
      (void) stbiw__sbfree(hash_table[i]);
S
Sean Barrett 已提交
802 803 804

   {
      // compute adler32 on input
S
Sean Barrett 已提交
805 806 807
      unsigned int k=0, s1=1, s2=0;
      int blocklen = (int) (data_len % 5552);
      j=0;
S
Sean Barrett 已提交
808 809 810 811 812 813
      while (j < data_len) {
         for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1;
         s1 %= 65521, s2 %= 65521;
         j += blocklen;
         blocklen = 5552;
      }
814 815 816 817
      stbiw__sbpush(out, (unsigned char) (s2 >> 8));
      stbiw__sbpush(out, (unsigned char) s2);
      stbiw__sbpush(out, (unsigned char) (s1 >> 8));
      stbiw__sbpush(out, (unsigned char) s1);
S
Sean Barrett 已提交
818
   }
819
   *out_len = stbiw__sbn(out);
S
Sean Barrett 已提交
820
   // make returned pointer freeable
821
   STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len);
822
   return (unsigned char *) stbiw__sbraw(out);
S
Sean Barrett 已提交
823 824
}

825
unsigned int stbiw__crc32(unsigned char *buffer, int len)
S
Sean Barrett 已提交
826 827 828 829 830 831 832 833 834 835 836 837 838
{
   static unsigned int crc_table[256];
   unsigned int crc = ~0u;
   int i,j;
   if (crc_table[1] == 0)
      for(i=0; i < 256; i++)
         for (crc_table[i]=i, j=0; j < 8; ++j)
            crc_table[i] = (crc_table[i] >> 1) ^ (crc_table[i] & 1 ? 0xedb88320 : 0);
   for (i=0; i < len; ++i)
      crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];
   return ~crc;
}

839 840 841
#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=(unsigned char)(a),(o)[1]=(unsigned char)(b),(o)[2]=(unsigned char)(c),(o)[3]=(unsigned char)(d),(o)+=4)
#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));
#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3])
S
Sean Barrett 已提交
842

843
static void stbiw__wpcrc(unsigned char **data, int len)
S
Sean Barrett 已提交
844
{
845 846
   unsigned int crc = stbiw__crc32(*data - len - 4, len+4);
   stbiw__wp32(*data, crc);
S
Sean Barrett 已提交
847 848
}

849
static unsigned char stbiw__paeth(int a, int b, int c)
S
Sean Barrett 已提交
850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867
{
   int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c);
   if (pa <= pb && pa <= pc) return (unsigned char) a;
   if (pb <= pc) return (unsigned char) b;
   return (unsigned char) c;
}

unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
{
   int ctype[5] = { -1, 0, 4, 2, 6 };
   unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
   unsigned char *out,*o, *filt, *zlib;
   signed char *line_buffer;
   int i,j,k,p,zlen;

   if (stride_bytes == 0)
      stride_bytes = x * n;

868 869
   filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0;
   line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; }
S
Sean Barrett 已提交
870 871 872 873 874 875 876 877 878 879 880 881 882 883 884
   for (j=0; j < y; ++j) {
      static int mapping[] = { 0,1,2,3,4 };
      static int firstmap[] = { 0,1,0,5,6 };
      int *mymap = j ? mapping : firstmap;
      int best = 0, bestval = 0x7fffffff;
      for (p=0; p < 2; ++p) {
         for (k= p?best:0; k < 5; ++k) {
            int type = mymap[k],est=0;
            unsigned char *z = pixels + stride_bytes*j;
            for (i=0; i < n; ++i)
               switch (type) {
                  case 0: line_buffer[i] = z[i]; break;
                  case 1: line_buffer[i] = z[i]; break;
                  case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
                  case 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break;
885
                  case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-stride_bytes],0)); break;
S
Sean Barrett 已提交
886 887 888 889 890 891 892 893 894
                  case 5: line_buffer[i] = z[i]; break;
                  case 6: line_buffer[i] = z[i]; break;
               }
            for (i=n; i < x*n; ++i) {
               switch (type) {
                  case 0: line_buffer[i] = z[i]; break;
                  case 1: line_buffer[i] = z[i] - z[i-n]; break;
                  case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
                  case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>1); break;
895
                  case 4: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-stride_bytes], z[i-stride_bytes-n]); break;
S
Sean Barrett 已提交
896
                  case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break;
897
                  case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break;
S
Sean Barrett 已提交
898 899 900 901 902 903 904 905 906 907
               }
            }
            if (p) break;
            for (i=0; i < x*n; ++i)
               est += abs((signed char) line_buffer[i]);
            if (est < bestval) { bestval = est; best = k; }
         }
      }
      // when we get here, best contains the filter type, and line_buffer contains the data
      filt[j*(x*n+1)] = (unsigned char) best;
908
      STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n);
S
Sean Barrett 已提交
909
   }
910
   STBIW_FREE(line_buffer);
S
Sean Barrett 已提交
911
   zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory
912
   STBIW_FREE(filt);
S
Sean Barrett 已提交
913 914 915
   if (!zlib) return 0;

   // each tag requires 12 bytes of overhead
916
   out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12);
S
Sean Barrett 已提交
917 918 919 920
   if (!out) return 0;
   *out_len = 8 + 12+13 + 12+zlen + 12;

   o=out;
921
   STBIW_MEMMOVE(o,sig,8); o+= 8;
922 923 924 925
   stbiw__wp32(o, 13); // header length
   stbiw__wptag(o, "IHDR");
   stbiw__wp32(o, x);
   stbiw__wp32(o, y);
S
Sean Barrett 已提交
926 927 928 929 930
   *o++ = 8;
   *o++ = (unsigned char) ctype[n];
   *o++ = 0;
   *o++ = 0;
   *o++ = 0;
931
   stbiw__wpcrc(&o,13);
S
Sean Barrett 已提交
932

933 934
   stbiw__wp32(o, zlen);
   stbiw__wptag(o, "IDAT");
935 936 937
   STBIW_MEMMOVE(o, zlib, zlen);
   o += zlen;
   STBIW_FREE(zlib);
938
   stbiw__wpcrc(&o, zlen);
S
Sean Barrett 已提交
939

940 941 942
   stbiw__wp32(o,0);
   stbiw__wptag(o, "IEND");
   stbiw__wpcrc(&o,0);
S
Sean Barrett 已提交
943

944
   STBIW_ASSERT(o == out + *out_len);
S
Sean Barrett 已提交
945 946 947 948

   return out;
}

949
#ifndef STBI_WRITE_NO_STDIO
950
STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
S
Sean Barrett 已提交
951 952 953 954
{
   FILE *f;
   int len;
   unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
955
   if (png == NULL) return 0;
S
Sean Barrett 已提交
956
   f = fopen(filename, "wb");
957
   if (!f) { STBIW_FREE(png); return 0; }
S
Sean Barrett 已提交
958 959
   fwrite(png, 1, len, f);
   fclose(f);
960
   STBIW_FREE(png);
S
Sean Barrett 已提交
961 962
   return 1;
}
963
#endif
964

965
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)
966
{
967 968 969 970 971 972
   int len;
   unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
   if (png == NULL) return 0;
   func(context, png, len);
   STBIW_FREE(png);
   return 1;
973 974
}

S
Sean Barrett 已提交
975 976 977
#endif // STB_IMAGE_WRITE_IMPLEMENTATION

/* Revision history
978 979
      1.01 (2016-01-16)
             STBIW_REALLOC_SIZED: support allocators with no realloc support
S
Sean Barrett 已提交
980 981
      1.00 (2015-09-14)
             installable file IO function
S
credits  
Sean Barrett 已提交
982
      0.99 (2015-09-13)
S
Sean Barrett 已提交
983
             warning fixes; TGA rle support
984
      0.98 (2015-04-08)
985
             added STBIW_MALLOC, STBIW_ASSERT etc
S
Sean Barrett 已提交
986 987
      0.97 (2015-01-18)
             fixed HDR asserts, rewrote HDR rle logic
988 989 990
      0.96 (2015-01-17)
             add HDR output
             fix monochrome BMP
S
Sean Barrett 已提交
991 992
      0.95 (2014-08-17)
		       add monochrome TGA output
S
Sean Barrett 已提交
993 994
      0.94 (2014-05-31)
             rename private functions to avoid conflicts with stb_image.h
995 996
      0.93 (2014-05-27)
             warning fixes
S
Sean Barrett 已提交
997 998 999 1000 1001 1002
      0.92 (2010-08-01)
             casts to unsigned char to fix warnings
      0.91 (2010-07-17)
             first public release
      0.90   first internal release
*/