stb_image_write.h 36.8 KB
Newer Older
1
/* stb_image_write - v1.02 - public domain - http://nothings.org/stb/stb_image_write.h
2
   writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010-2015
3
                                     no warranty implied; use at your own risk
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);
J
Jonas Karlsson 已提交
37
     int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *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
      Sergio Gonzalez
S
Sean Barrett 已提交
103
      Jonas Karlsson
S
Sean Barrett 已提交
104
      Filip Wasil
105
      Thatcher Ulrich
106 107 108
      
LICENSE

109 110 111
This software is dual-licensed to the public domain and under the following
license: you are granted a perpetual, irrevocable license to copy, modify,
publish, and distribute this file as you see fit.
112

S
Sean Barrett 已提交
113 114 115 116 117 118 119 120 121
*/

#ifndef INCLUDE_STB_IMAGE_WRITE_H
#define INCLUDE_STB_IMAGE_WRITE_H

#ifdef __cplusplus
extern "C" {
#endif

122 123 124 125
#ifdef STB_IMAGE_WRITE_STATIC
#define STBIWDEF static
#else
#define STBIWDEF extern
S
Sean Barrett 已提交
126
extern int stbi_write_tga_with_rle;
127 128
#endif

129
#ifndef STBI_WRITE_NO_STDIO
130 131 132 133
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);
134
#endif
135

136
typedef void stbi_write_func(void *context, void *data, int size);
137

138 139 140 141
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 已提交
142 143 144 145 146 147 148 149 150

#ifdef __cplusplus
}
#endif

#endif//INCLUDE_STB_IMAGE_WRITE_H

#ifdef STB_IMAGE_WRITE_IMPLEMENTATION

S
Sean Barrett 已提交
151
#ifdef _WIN32
152
   #ifndef _CRT_SECURE_NO_WARNINGS
S
Sean Barrett 已提交
153
   #define _CRT_SECURE_NO_WARNINGS
154 155
   #endif
   #ifndef _CRT_NONSTDC_NO_DEPRECATE
S
Sean Barrett 已提交
156
   #define _CRT_NONSTDC_NO_DEPRECATE
157
   #endif
S
Sean Barrett 已提交
158 159
#endif

160 161 162
#ifndef STBI_WRITE_NO_STDIO
#include <stdio.h>
#endif // STBI_WRITE_NO_STDIO
163

S
Sean Barrett 已提交
164 165 166
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
167
#include <math.h>
S
Sean Barrett 已提交
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 173
// ok
#else
174
#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)."
175 176
#endif

177
#ifndef STBIW_MALLOC
178 179 180
#define STBIW_MALLOC(sz)        malloc(sz)
#define STBIW_REALLOC(p,newsz)  realloc(p,newsz)
#define STBIW_FREE(p)           free(p)
181
#endif
182 183 184 185 186 187

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


188 189 190 191
#ifndef STBIW_MEMMOVE
#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz)
#endif

192

193
#ifndef STBIW_ASSERT
194
#include <assert.h>
195
#define STBIW_ASSERT(x) assert(x)
196 197
#endif

198 199
#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)

200 201
typedef struct
{
202 203
   stbi_write_func *func;
   void *context;
204 205 206
} stbi__write_context;

// initialize a callback-based context
207
static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context)
208
{
209 210
   s->func    = c;
   s->context = context;
211 212 213 214
}

#ifndef STBI_WRITE_NO_STDIO

215
static void stbi__stdio_write(void *context, void *data, int size)
216
{
217
   fwrite(data,1,size,(FILE*) context);
218 219
}

S
Sean Barrett 已提交
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);
S
Sean Barrett 已提交
224
   return f != NULL;
225 226 227 228
}

static void stbi__end_write_file(stbi__write_context *s)
{
229
   fclose((FILE *)s->context);
230 231 232 233
}

#endif // !STBI_WRITE_NO_STDIO

S
Sean Barrett 已提交
234 235 236
typedef unsigned int stbiw_uint32;
typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];

S
Sean Barrett 已提交
237 238 239 240 241
#ifdef STB_IMAGE_WRITE_STATIC
static int stbi_write_tga_with_rle = 1;
#else
int stbi_write_tga_with_rle = 1;
#endif
F
fahickman 已提交
242

S
Sean Barrett 已提交
243
static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v)
S
Sean Barrett 已提交
244 245 246 247
{
   while (*fmt) {
      switch (*fmt++) {
         case ' ': break;
248
         case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int));
249 250 251 252
                     s->func(s->context,&x,1);
                     break; }
         case '2': { int x = va_arg(v,int);
                     unsigned char b[2];
253 254
                     b[0] = STBIW_UCHAR(x);
                     b[1] = STBIW_UCHAR(x>>8);
255 256 257 258
                     s->func(s->context,b,2);
                     break; }
         case '4': { stbiw_uint32 x = va_arg(v,int);
                     unsigned char b[4];
259 260 261 262
                     b[0]=STBIW_UCHAR(x);
                     b[1]=STBIW_UCHAR(x>>8);
                     b[2]=STBIW_UCHAR(x>>16);
                     b[3]=STBIW_UCHAR(x>>24);
263 264
                     s->func(s->context,b,4);
                     break; }
S
Sean Barrett 已提交
265
         default:
266
            STBIW_ASSERT(0);
S
Sean Barrett 已提交
267 268 269 270 271
            return;
      }
   }
}

S
Sean Barrett 已提交
272
static void stbiw__writef(stbi__write_context *s, const char *fmt, ...)
F
fahickman 已提交
273 274 275
{
   va_list v;
   va_start(v, fmt);
S
Sean Barrett 已提交
276
   stbiw__writefv(s, fmt, v);
F
fahickman 已提交
277 278 279
   va_end(v);
}

S
Sean Barrett 已提交
280
static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c)
S
Sean Barrett 已提交
281 282 283
{
   unsigned char arr[3];
   arr[0] = a, arr[1] = b, arr[2] = c;
284
   s->func(s->context, arr, 3);
S
Sean Barrett 已提交
285 286
}

S
Sean Barrett 已提交
287
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 已提交
288 289
{
   unsigned char bg[3] = { 255, 0, 255}, px[3];
F
fahickman 已提交
290 291 292
   int k;

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

F
fahickman 已提交
295
   switch (comp) {
296 297 298 299 300
      case 1:
         s->func(s->context,d,1);
         break;
      case 2:
         if (expand_mono)
S
Sean Barrett 已提交
301
            stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp
302 303 304 305 306 307 308 309
         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 已提交
310
            stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]);
311 312 313 314
            break;
         }
         /* FALLTHROUGH */
      case 3:
S
Sean Barrett 已提交
315
         stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]);
F
fahickman 已提交
316 317 318
         break;
   }
   if (write_alpha > 0)
319
      s->func(s->context, &d[comp - 1], 1);
F
fahickman 已提交
320 321
}

S
Sean Barrett 已提交
322
static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono)
F
fahickman 已提交
323
{
S
Sean Barrett 已提交
324
   stbiw_uint32 zero = 0;
F
fahickman 已提交
325
   int i,j, j_end;
S
Sean Barrett 已提交
326 327 328 329

   if (y <= 0)
      return;

330
   if (vdir < 0)
S
Sean Barrett 已提交
331 332 333 334 335 336 337
      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 已提交
338
         stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d);
S
Sean Barrett 已提交
339
      }
340
      s->func(s->context, &zero, scanline_pad);
S
Sean Barrett 已提交
341 342 343
   }
}

S
Sean Barrett 已提交
344
static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...)
S
Sean Barrett 已提交
345
{
346 347 348
   if (y < 0 || x < 0) {
      return 0;
   } else {
S
Sean Barrett 已提交
349 350
      va_list v;
      va_start(v, fmt);
S
Sean Barrett 已提交
351
      stbiw__writefv(s, fmt, v);
S
Sean Barrett 已提交
352
      va_end(v);
S
Sean Barrett 已提交
353
      stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono);
354
      return 1;
S
Sean Barrett 已提交
355 356 357
   }
}

S
Sean Barrett 已提交
358
static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data)
S
Sean Barrett 已提交
359 360
{
   int pad = (-x*3) & 3;
S
Sean Barrett 已提交
361
   return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad,
S
Sean Barrett 已提交
362 363 364 365 366
           "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
}

367
STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
368 369
{
   stbi__write_context s;
370 371
   stbi__start_write_callbacks(&s, func, context);
   return stbi_write_bmp_core(&s, x, y, comp, data);
372 373 374
}

#ifndef STBI_WRITE_NO_STDIO
375
STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
376 377
{
   stbi__write_context s;
S
Sean Barrett 已提交
378 379 380 381 382 383
   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;
384 385 386
}
#endif //!STBI_WRITE_NO_STDIO

S
Sean Barrett 已提交
387
static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data)
S
Sean Barrett 已提交
388
{
S
Sean Barrett 已提交
389 390
   int has_alpha = (comp == 2 || comp == 4);
   int colorbytes = has_alpha ? comp-1 : comp;
391
   int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3
392 393 394

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

S
Sean Barrett 已提交
396
   if (!stbi_write_tga_with_rle) {
S
Sean Barrett 已提交
397
      return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0,
F
fahickman 已提交
398
         "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8);
399
   } else {
F
fahickman 已提交
400 401
      int i,j,k;

S
Sean Barrett 已提交
402
      stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8);
F
fahickman 已提交
403 404

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

F
fahickman 已提交
408
         for (i = 0; i < x; i += len) {
409
            unsigned char *begin = row + i * comp;
F
fahickman 已提交
410
            int diff = 1;
F
fahickman 已提交
411
            len = 1;
F
fahickman 已提交
412 413

            if (i < x - 1) {
F
fahickman 已提交
414 415
               ++len;
               diff = memcmp(begin, row + (i + 1) * comp, comp);
F
fahickman 已提交
416
               if (diff) {
F
fahickman 已提交
417 418 419 420 421
                  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 已提交
422
                     } else {
F
fahickman 已提交
423
                        --len;
F
fahickman 已提交
424 425 426 427
                        break;
                     }
                  }
               } else {
F
fahickman 已提交
428 429 430
                  for (k = i + 2; k < x && len < 128; ++k) {
                     if (!memcmp(begin, row + k * comp, comp)) {
                        ++len;
F
fahickman 已提交
431 432 433 434 435 436 437 438
                     } else {
                        break;
                     }
                  }
               }
            }

            if (diff) {
439
               unsigned char header = STBIW_UCHAR(len - 1);
440
               s->func(s->context, &header, 1);
F
fahickman 已提交
441
               for (k = 0; k < len; ++k) {
S
Sean Barrett 已提交
442
                  stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp);
F
fahickman 已提交
443 444
               }
            } else {
445
               unsigned char header = STBIW_UCHAR(len - 129);
446
               s->func(s->context, &header, 1);
S
Sean Barrett 已提交
447
               stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin);
F
fahickman 已提交
448 449 450 451
            }
         }
      }
   }
452
   return 1;
S
Sean Barrett 已提交
453 454
}

455
int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
456 457
{
   stbi__write_context s;
458 459
   stbi__start_write_callbacks(&s, func, context);
   return stbi_write_tga_core(&s, x, y, comp, (void *) data);
460
}
F
fahickman 已提交
461

462
#ifndef STBI_WRITE_NO_STDIO
S
Sean Barrett 已提交
463
int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
464 465
{
   stbi__write_context s;
S
Sean Barrett 已提交
466 467 468 469 470 471
   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 已提交
472
}
473
#endif
S
Sean Barrett 已提交
474

B
baldurk 已提交
475 476
// *************************************************************************************************
// Radiance RGBE HDR writer
477
// by Baldur Karlsson
478 479
#ifndef STBI_WRITE_NO_STDIO

B
baldurk 已提交
480 481 482 483 484 485 486
#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]));

F
Filip Wasil 已提交
487
   if (maxcomp < 1e-32f) {
B
baldurk 已提交
488 489
      rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
   } else {
490
      float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp;
B
baldurk 已提交
491

492 493 494
      rgbe[0] = (unsigned char)(linear[0] * normalize);
      rgbe[1] = (unsigned char)(linear[1] * normalize);
      rgbe[2] = (unsigned char)(linear[2] * normalize);
B
baldurk 已提交
495 496 497 498
      rgbe[3] = (unsigned char)(exponent + 128);
   }
}

499
void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte)
B
baldurk 已提交
500
{
501
   unsigned char lengthbyte = STBIW_UCHAR(length+128);
502
   STBIW_ASSERT(length+128 <= 255);
503 504
   s->func(s->context, &lengthbyte, 1);
   s->func(s->context, &databyte, 1);
B
baldurk 已提交
505 506
}

507
void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data)
B
baldurk 已提交
508
{
509
   unsigned char lengthbyte = STBIW_UCHAR(length);
510
   STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code
511 512
   s->func(s->context, &lengthbyte, 1);
   s->func(s->context, data, length);
B
baldurk 已提交
513 514
}

515
void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline)
B
baldurk 已提交
516 517 518 519 520 521 522 523 524 525 526 527
{
   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 已提交
528
         switch (ncomp) {
B
baldurk 已提交
529
            case 4: /* fallthrough */
S
Sean Barrett 已提交
530 531 532
            case 3: linear[2] = scanline[x*ncomp + 2];
                    linear[1] = scanline[x*ncomp + 1];
                    linear[0] = scanline[x*ncomp + 0];
B
baldurk 已提交
533
                    break;
534
            default:
S
Sean Barrett 已提交
535
                    linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];
B
baldurk 已提交
536 537 538
                    break;
         }
         stbiw__linear_to_rgbe(rgbe, linear);
539
         s->func(s->context, rgbe, 4);
B
baldurk 已提交
540 541
      }
   } else {
S
Sean Barrett 已提交
542
      int c,r;
B
baldurk 已提交
543 544
      /* encode into scratch buffer */
      for (x=0; x < width; x++) {
S
Sean Barrett 已提交
545
         switch(ncomp) {
B
baldurk 已提交
546
            case 4: /* fallthrough */
S
Sean Barrett 已提交
547 548 549
            case 3: linear[2] = scanline[x*ncomp + 2];
                    linear[1] = scanline[x*ncomp + 1];
                    linear[0] = scanline[x*ncomp + 0];
B
baldurk 已提交
550
                    break;
551
            default:
S
Sean Barrett 已提交
552
                    linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];
B
baldurk 已提交
553 554 555 556 557 558 559 560 561
                    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];
      }

562
      s->func(s->context, scanlineheader, 4);
B
baldurk 已提交
563 564

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

S
Sean Barrett 已提交
568 569 570 571 572 573 574 575 576 577 578 579 580 581 582
         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;
583
               stbiw__write_dump_data(s, len, &comp[x]);
S
Sean Barrett 已提交
584 585 586 587 588 589
               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])
590
                  ++r;
S
Sean Barrett 已提交
591 592 593 594
               // output run up to r
               while (x < r) {
                  int len = r-x;
                  if (len > 127) len = 127;
595
                  stbiw__write_run_data(s, len, comp[x]);
S
Sean Barrett 已提交
596
                  x += len;
B
baldurk 已提交
597 598 599 600 601 602 603
               }
            }
         }
      }
   }
}

S
Sean Barrett 已提交
604
static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data)
B
baldurk 已提交
605
{
606 607 608 609
   if (y <= 0 || x <= 0 || data == NULL)
      return 0;
   else {
      // Each component is stored separately. Allocate scratch space for full output scanline.
610
      unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4);
611 612 613 614 615 616 617 618
      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);

619
      for(i=0; i < y; i++)
620
         stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*i*x);
621
      STBIW_FREE(scratch);
622
      return 1;
B
baldurk 已提交
623 624 625
   }
}

626 627 628 629 630 631 632
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 已提交
633
int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
634 635
{
   stbi__write_context s;
S
Sean Barrett 已提交
636 637 638 639 640 641
   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;
642 643 644 645 646 647 648 649
}
#endif // STBI_WRITE_NO_STDIO


//////////////////////////////////////////////////////////////////////////////
//
// PNG writer
//
650

651 652 653 654
// 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 已提交
655

656 657 658
#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 已提交
659

660 661
#define stbiw__sbpush(a, v)      (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v))
#define stbiw__sbcount(a)        ((a) ? stbiw__sbn(a) : 0)
662
#define stbiw__sbfree(a)         ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0)
S
Sean Barrett 已提交
663

664
static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
S
Sean Barrett 已提交
665
{
666
   int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1;
667
   void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2);
668
   STBIW_ASSERT(p);
S
Sean Barrett 已提交
669 670 671
   if (p) {
      if (!*arr) ((int *) p)[1] = 0;
      *arr = (void *) ((int *) p + 2);
672
      stbiw__sbm(*arr) = m;
S
Sean Barrett 已提交
673 674 675 676
   }
   return *arr;
}

677
static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)
S
Sean Barrett 已提交
678 679
{
   while (*bitcount >= 8) {
680
      stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer));
S
Sean Barrett 已提交
681 682 683 684 685 686
      *bitbuffer >>= 8;
      *bitcount -= 8;
   }
   return data;
}

687
static int stbiw__zlib_bitrev(int code, int codebits)
S
Sean Barrett 已提交
688 689 690 691 692 693 694 695 696
{
   int res=0;
   while (codebits--) {
      res = (res << 1) | (code & 1);
      code >>= 1;
   }
   return res;
}

697
static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit)
S
Sean Barrett 已提交
698 699 700 701 702 703 704
{
   int i;
   for (i=0; i < limit && i < 258; ++i)
      if (a[i] != b[i]) break;
   return i;
}

705
static unsigned int stbiw__zhash(unsigned char *data)
S
Sean Barrett 已提交
706 707 708 709 710 711 712 713 714 715 716
{
   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;
}

717 718 719 720
#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 已提交
721
// default huffman tables
722 723 724 725 726 727
#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 已提交
728

729
#define stbiw__ZHASH   16384
S
Sean Barrett 已提交
730 731 732 733 734 735 736 737 738 739

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;
740
   unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**));
S
Sean Barrett 已提交
741 742
   if (quality < 5) quality = 5;

743 744 745 746
   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 已提交
747

748
   for (i=0; i < stbiw__ZHASH; ++i)
S
Sean Barrett 已提交
749 750 751 752
      hash_table[i] = NULL;

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

      if (bestloc) {
         // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal
773
         h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1);
S
Sean Barrett 已提交
774
         hlist = hash_table[h];
775
         n = stbiw__sbcount(hlist);
S
Sean Barrett 已提交
776 777
         for (j=0; j < n; ++j) {
            if (hlist[j]-data > i-32767) {
778
               int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1);
S
Sean Barrett 已提交
779 780 781 782 783 784 785 786 787
               if (e > best) { // if next match is better, bail on current match
                  bestloc = NULL;
                  break;
               }
            }
         }
      }

      if (bestloc) {
788
         int d = (int) (data+i - bestloc); // distance back
789
         STBIW_ASSERT(d <= 32767 && best <= 258);
S
Sean Barrett 已提交
790
         for (j=0; best > lengthc[j+1]-1; ++j);
791 792
         stbiw__zlib_huff(j+257);
         if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]);
S
Sean Barrett 已提交
793
         for (j=0; d > distc[j+1]-1; ++j);
794 795
         stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5);
         if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]);
S
Sean Barrett 已提交
796 797
         i += best;
      } else {
798
         stbiw__zlib_huffb(data[i]);
S
Sean Barrett 已提交
799 800 801 802 803
         ++i;
      }
   }
   // write out final bytes
   for (;i < data_len; ++i)
804 805
      stbiw__zlib_huffb(data[i]);
   stbiw__zlib_huff(256); // end of block
S
Sean Barrett 已提交
806 807
   // pad with 0 bits to byte boundary
   while (bitcount)
808
      stbiw__zlib_add(0,1);
S
Sean Barrett 已提交
809

810 811
   for (i=0; i < stbiw__ZHASH; ++i)
      (void) stbiw__sbfree(hash_table[i]);
812
   STBIW_FREE(hash_table);
S
Sean Barrett 已提交
813 814 815

   {
      // compute adler32 on input
816
      unsigned int s1=1, s2=0;
S
Sean Barrett 已提交
817 818
      int blocklen = (int) (data_len % 5552);
      j=0;
S
Sean Barrett 已提交
819 820 821 822 823 824
      while (j < data_len) {
         for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1;
         s1 %= 65521, s2 %= 65521;
         j += blocklen;
         blocklen = 5552;
      }
825 826 827 828
      stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8));
      stbiw__sbpush(out, STBIW_UCHAR(s2));
      stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8));
      stbiw__sbpush(out, STBIW_UCHAR(s1));
S
Sean Barrett 已提交
829
   }
830
   *out_len = stbiw__sbn(out);
S
Sean Barrett 已提交
831
   // make returned pointer freeable
832
   STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len);
833
   return (unsigned char *) stbiw__sbraw(out);
S
Sean Barrett 已提交
834 835
}

S
Sean Barrett 已提交
836
static unsigned int stbiw__crc32(unsigned char *buffer, int len)
S
Sean Barrett 已提交
837
{
838 839
   static unsigned int crc_table[256] =
   {
S
Sean Barrett 已提交
840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871
      0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
      0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
      0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
      0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
      0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
      0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
      0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
      0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
      0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
      0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
      0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
      0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
      0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
      0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
      0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
      0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
      0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
      0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
      0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
      0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
      0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
      0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
      0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
      0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
      0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
      0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
      0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
      0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
      0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
      0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
      0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
      0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
872 873
   };

S
Sean Barrett 已提交
874
   unsigned int crc = ~0u;
S
Sean Barrett 已提交
875 876
   int i;
   for (i=0; i < len; ++i)
S
Sean Barrett 已提交
877 878 879 880
      crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];
   return ~crc;
}

881
#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4)
882 883
#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 已提交
884

885
static void stbiw__wpcrc(unsigned char **data, int len)
S
Sean Barrett 已提交
886
{
887 888
   unsigned int crc = stbiw__crc32(*data - len - 4, len+4);
   stbiw__wp32(*data, crc);
S
Sean Barrett 已提交
889 890
}

891
static unsigned char stbiw__paeth(int a, int b, int c)
S
Sean Barrett 已提交
892 893
{
   int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c);
894 895 896
   if (pa <= pb && pa <= pc) return STBIW_UCHAR(a);
   if (pb <= pc) return STBIW_UCHAR(b);
   return STBIW_UCHAR(c);
S
Sean Barrett 已提交
897 898 899 900 901 902 903 904 905 906 907 908 909
}

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;

910 911
   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 已提交
912 913 914 915 916 917 918 919 920 921 922 923 924 925 926
   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;
927
                  case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-stride_bytes],0)); break;
S
Sean Barrett 已提交
928 929 930 931 932 933 934 935 936
                  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;
937
                  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 已提交
938
                  case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break;
939
                  case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break;
S
Sean Barrett 已提交
940 941 942 943 944 945 946 947 948 949
               }
            }
            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;
950
      STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n);
S
Sean Barrett 已提交
951
   }
952
   STBIW_FREE(line_buffer);
S
Sean Barrett 已提交
953
   zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory
954
   STBIW_FREE(filt);
S
Sean Barrett 已提交
955 956 957
   if (!zlib) return 0;

   // each tag requires 12 bytes of overhead
958
   out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12);
S
Sean Barrett 已提交
959 960 961 962
   if (!out) return 0;
   *out_len = 8 + 12+13 + 12+zlen + 12;

   o=out;
963
   STBIW_MEMMOVE(o,sig,8); o+= 8;
964 965 966 967
   stbiw__wp32(o, 13); // header length
   stbiw__wptag(o, "IHDR");
   stbiw__wp32(o, x);
   stbiw__wp32(o, y);
S
Sean Barrett 已提交
968
   *o++ = 8;
969
   *o++ = STBIW_UCHAR(ctype[n]);
S
Sean Barrett 已提交
970 971 972
   *o++ = 0;
   *o++ = 0;
   *o++ = 0;
973
   stbiw__wpcrc(&o,13);
S
Sean Barrett 已提交
974

975 976
   stbiw__wp32(o, zlen);
   stbiw__wptag(o, "IDAT");
977 978 979
   STBIW_MEMMOVE(o, zlib, zlen);
   o += zlen;
   STBIW_FREE(zlib);
980
   stbiw__wpcrc(&o, zlen);
S
Sean Barrett 已提交
981

982 983 984
   stbiw__wp32(o,0);
   stbiw__wptag(o, "IEND");
   stbiw__wpcrc(&o,0);
S
Sean Barrett 已提交
985

986
   STBIW_ASSERT(o == out + *out_len);
S
Sean Barrett 已提交
987 988 989 990

   return out;
}

991
#ifndef STBI_WRITE_NO_STDIO
992
STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
S
Sean Barrett 已提交
993 994 995 996
{
   FILE *f;
   int len;
   unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
997
   if (png == NULL) return 0;
S
Sean Barrett 已提交
998
   f = fopen(filename, "wb");
999
   if (!f) { STBIW_FREE(png); return 0; }
S
Sean Barrett 已提交
1000 1001
   fwrite(png, 1, len, f);
   fclose(f);
1002
   STBIW_FREE(png);
S
Sean Barrett 已提交
1003 1004
   return 1;
}
1005
#endif
1006

1007
STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes)
1008
{
1009 1010 1011 1012 1013 1014
   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;
1015 1016
}

S
Sean Barrett 已提交
1017 1018 1019
#endif // STB_IMAGE_WRITE_IMPLEMENTATION

/* Revision history
1020 1021
      1.02 (2016-04-02)
             avoid allocating large structures on the stack
1022 1023
      1.01 (2016-01-16)
             STBIW_REALLOC_SIZED: support allocators with no realloc support
S
Sean Barrett 已提交
1024 1025
             avoid race-condition in crc initialization
             minor compile issues
S
Sean Barrett 已提交
1026 1027
      1.00 (2015-09-14)
             installable file IO function
S
credits  
Sean Barrett 已提交
1028
      0.99 (2015-09-13)
S
Sean Barrett 已提交
1029
             warning fixes; TGA rle support
1030
      0.98 (2015-04-08)
1031
             added STBIW_MALLOC, STBIW_ASSERT etc
S
Sean Barrett 已提交
1032 1033
      0.97 (2015-01-18)
             fixed HDR asserts, rewrote HDR rle logic
1034 1035 1036
      0.96 (2015-01-17)
             add HDR output
             fix monochrome BMP
S
Sean Barrett 已提交
1037 1038
      0.95 (2014-08-17)
		       add monochrome TGA output
S
Sean Barrett 已提交
1039 1040
      0.94 (2014-05-31)
             rename private functions to avoid conflicts with stb_image.h
1041 1042
      0.93 (2014-05-27)
             warning fixes
S
Sean Barrett 已提交
1043 1044 1045 1046 1047 1048
      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
*/