1 /* stbiw-0.92 - public domain - http://nothings.org/stb/stb_image_write.h
2    writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010
3                             no warranty implied; use at your own risk
4 
5 
6 Before including,
7 
8     #define STB_IMAGE_WRITE_IMPLEMENTATION
9 
10 in the file that you want to have the implementation.
11 
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 simplicitly, not optimal image file size
21    or run-time performance.
22 
23 USAGE:
24 
25    There are three functions, one for each image file format:
26 
27      int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
28      int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
29      int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
30 
31    Each function returns 0 on failure and non-0 on success.
32 
33    The functions create an image file defined by the parameters. The image
34    is a rectangle of pixels stored from left-to-right, top-to-bottom.
35    Each pixel contains 'comp' channels of data stored interleaved with 8-bits
36    per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is
37    monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall.
38    The *data pointer points to the first byte of the top-left-most pixel.
39    For PNG, "stride_in_bytes" is the distance in bytes from the first byte of
40    a row of pixels to the first byte of the next row of pixels.
41 
42    PNG creates output files with the same number of components as the input.
43    The BMP and TGA formats expand Y to RGB in the file format. BMP does not
44    output alpha.
45 
46    PNG supports writing rectangles of data even when the bytes storing rows of
47    data are not consecutive in memory (e.g. sub-rectangles of a larger image),
48    by supplying the stride between the beginning of adjacent rows. The other
49    formats do not. (Thus you cannot write a native-format BMP through the BMP
50    writer, both because it is in BGR order and because it may have padding
51    at the end of the line.)
52 */
53 
54 #ifndef INCLUDE_STB_IMAGE_WRITE_H
55 #define INCLUDE_STB_IMAGE_WRITE_H
56 
57 #ifdef __cplusplus
58 extern "C"
59 {
60 #endif
61 
62 	extern int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
63 	extern int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
64 	extern int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
65 
66 #ifdef __cplusplus
67 }
68 #endif
69 
70 #endif  //INCLUDE_STB_IMAGE_WRITE_H
71 
72 #ifdef STB_IMAGE_WRITE_IMPLEMENTATION
73 
74 #include <stdarg.h>
75 #include <stdlib.h>
76 #include <stdio.h>
77 #include <string.h>
78 #include <assert.h>
79 
80 typedef unsigned int stbiw_uint32;
81 typedef int stb_image_write_test[sizeof(stbiw_uint32) == 4 ? 1 : -1];
82 
writefv(FILE * f,const char * fmt,va_list v)83 static void writefv(FILE *f, const char *fmt, va_list v)
84 {
85 	while (*fmt)
86 	{
87 		switch (*fmt++)
88 		{
89 			case ' ':
90 				break;
91 			case '1':
92 			{
93 				unsigned char x = (unsigned char)va_arg(v, int);
94 				fputc(x, f);
95 				break;
96 			}
97 			case '2':
98 			{
99 				int x = va_arg(v, int);
100 				unsigned char b[2];
101 				b[0] = (unsigned char)x;
102 				b[1] = (unsigned char)(x >> 8);
103 				fwrite(b, 2, 1, f);
104 				break;
105 			}
106 			case '4':
107 			{
108 				stbiw_uint32 x = va_arg(v, int);
109 				unsigned char b[4];
110 				b[0] = (unsigned char)x;
111 				b[1] = (unsigned char)(x >> 8);
112 				b[2] = (unsigned char)(x >> 16);
113 				b[3] = (unsigned char)(x >> 24);
114 				fwrite(b, 4, 1, f);
115 				break;
116 			}
117 			default:
118 				assert(0);
119 				return;
120 		}
121 	}
122 }
123 
write3(FILE * f,unsigned char a,unsigned char b,unsigned char c)124 static void write3(FILE *f, unsigned char a, unsigned char b, unsigned char c)
125 {
126 	unsigned char arr[3];
127 	arr[0] = a, arr[1] = b, arr[2] = c;
128 	fwrite(arr, 3, 1, f);
129 }
130 
write_pixels(FILE * f,int rgb_dir,int vdir,int x,int y,int comp,void * data,int write_alpha,int scanline_pad)131 static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad)
132 {
133 	unsigned char bg[3] = {255, 0, 255}, px[3];
134 	stbiw_uint32 zero = 0;
135 	int i, j, k, j_end;
136 
137 	if (y <= 0)
138 		return;
139 
140 	if (vdir < 0)
141 		j_end = -1, j = y - 1;
142 	else
143 		j_end = y, j = 0;
144 
145 	for (; j != j_end; j += vdir)
146 	{
147 		for (i = 0; i < x; ++i)
148 		{
149 			unsigned char *d = (unsigned char *)data + (j * x + i) * comp;
150 			if (write_alpha < 0)
151 				fwrite(&d[comp - 1], 1, 1, f);
152 			switch (comp)
153 			{
154 				case 1:
155 				case 2:
156 					write3(f, d[0], d[0], d[0]);
157 					break;
158 				case 4:
159 					if (!write_alpha)
160 					{
161 						// composite against pink background
162 						for (k = 0; k < 3; ++k)
163 							px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255;
164 						write3(f, px[1 - rgb_dir], px[1], px[1 + rgb_dir]);
165 						break;
166 					}
167 					/* FALLTHROUGH */
168 				case 3:
169 					write3(f, d[1 - rgb_dir], d[1], d[1 + rgb_dir]);
170 					break;
171 			}
172 			if (write_alpha > 0)
173 				fwrite(&d[comp - 1], 1, 1, f);
174 		}
175 		fwrite(&zero, scanline_pad, 1, f);
176 	}
177 }
178 
outfile(char const * filename,int rgb_dir,int vdir,int x,int y,int comp,void * data,int alpha,int pad,const char * fmt,...)179 static int outfile(char const *filename, int rgb_dir, int vdir, int x, int y, int comp, void *data, int alpha, int pad, const char *fmt, ...)
180 {
181 	FILE *f;
182 	if (y < 0 || x < 0) return 0;
183 	f = fopen(filename, "wb");
184 	if (f)
185 	{
186 		va_list v;
187 		va_start(v, fmt);
188 		writefv(f, fmt, v);
189 		va_end(v);
190 		write_pixels(f, rgb_dir, vdir, x, y, comp, data, alpha, pad);
191 		fclose(f);
192 	}
193 	return f != NULL;
194 }
195 
stbi_write_bmp(char const * filename,int x,int y,int comp,const void * data)196 int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
197 {
198 	int pad = (-x * 3) & 3;
199 	return outfile(filename, -1, -1, x, y, comp, (void *)data, 0, pad,
200 				   "11 4 22 4"
201 				   "4 44 22 444444",
202 				   'B', 'M', 14 + 40 + (x * 3 + pad) * y, 0, 0, 14 + 40,  // file header
203 				   40, x, y, 1, 24, 0, 0, 0, 0, 0, 0);                    // bitmap header
204 }
205 
stbi_write_tga(char const * filename,int x,int y,int comp,const void * data)206 int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
207 {
208 	int has_alpha = !(comp & 1);
209 	return outfile(filename, -1, -1, x, y, comp, (void *)data, has_alpha, 0,
210 				   "111 221 2222 11", 0, 0, 2, 0, 0, 0, 0, 0, x, y, 24 + 8 * has_alpha, 8 * has_alpha);
211 }
212 
213 // stretchy buffer; stbi__sbpush() == vector<>::push_back() -- stbi__sbcount() == vector<>::size()
214 #define stbi__sbraw(a) ((int *)(a)-2)
215 #define stbi__sbm(a) stbi__sbraw(a)[0]
216 #define stbi__sbn(a) stbi__sbraw(a)[1]
217 
218 #define stbi__sbneedgrow(a, n) ((a) == 0 || stbi__sbn(a) + n >= stbi__sbm(a))
219 #define stbi__sbmaybegrow(a, n) (stbi__sbneedgrow(a, (n)) ? stbi__sbgrow(a, n) : 0)
220 #define stbi__sbgrow(a, n) stbi__sbgrowf((void **)&(a), (n), sizeof(*(a)))
221 
222 #define stbi__sbpush(a, v) (stbi__sbmaybegrow(a, 1), (a)[stbi__sbn(a)++] = (v))
223 #define stbi__sbcount(a) ((a) ? stbi__sbn(a) : 0)
224 #define stbi__sbfree(a) ((a) ? free(stbi__sbraw(a)), 0 : 0)
225 
stbi__sbgrowf(void ** arr,int increment,int itemsize)226 static void *stbi__sbgrowf(void **arr, int increment, int itemsize)
227 {
228 	int m = *arr ? 2 * stbi__sbm(*arr) + increment : increment + 1;
229 	void *p = realloc(*arr ? stbi__sbraw(*arr) : 0, itemsize * m + sizeof(int) * 2);
230 	assert(p);
231 	if (p)
232 	{
233 		if (!*arr) ((int *)p)[1] = 0;
234 		*arr = (void *)((int *)p + 2);
235 		stbi__sbm(*arr) = m;
236 	}
237 	return *arr;
238 }
239 
stbi__zlib_flushf(unsigned char * data,unsigned int * bitbuffer,int * bitcount)240 static unsigned char *stbi__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)
241 {
242 	while (*bitcount >= 8)
243 	{
244 		stbi__sbpush(data, (unsigned char)*bitbuffer);
245 		*bitbuffer >>= 8;
246 		*bitcount -= 8;
247 	}
248 	return data;
249 }
250 
stbi__zlib_bitrev(int code,int codebits)251 static int stbi__zlib_bitrev(int code, int codebits)
252 {
253 	int res = 0;
254 	while (codebits--)
255 	{
256 		res = (res << 1) | (code & 1);
257 		code >>= 1;
258 	}
259 	return res;
260 }
261 
stbi__zlib_countm(unsigned char * a,unsigned char * b,int limit)262 static unsigned int stbi__zlib_countm(unsigned char *a, unsigned char *b, int limit)
263 {
264 	int i;
265 	for (i = 0; i < limit && i < 258; ++i)
266 		if (a[i] != b[i]) break;
267 	return i;
268 }
269 
stbi__zhash(unsigned char * data)270 static unsigned int stbi__zhash(unsigned char *data)
271 {
272 	stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16);
273 	hash ^= hash << 3;
274 	hash += hash >> 5;
275 	hash ^= hash << 4;
276 	hash += hash >> 17;
277 	hash ^= hash << 25;
278 	hash += hash >> 6;
279 	return hash;
280 }
281 
282 #define stbi__zlib_flush() (out = stbi__zlib_flushf(out, &bitbuf, &bitcount))
283 #define stbi__zlib_add(code, codebits) \
284 	(bitbuf |= (code) << bitcount, bitcount += (codebits), stbi__zlib_flush())
285 #define stbi__zlib_huffa(b, c) stbi__zlib_add(stbi__zlib_bitrev(b, c), c)
286 // default huffman tables
287 #define stbi__zlib_huff1(n) stbi__zlib_huffa(0x30 + (n), 8)
288 #define stbi__zlib_huff2(n) stbi__zlib_huffa(0x190 + (n)-144, 9)
289 #define stbi__zlib_huff3(n) stbi__zlib_huffa(0 + (n)-256, 7)
290 #define stbi__zlib_huff4(n) stbi__zlib_huffa(0xc0 + (n)-280, 8)
291 #define stbi__zlib_huff(n) ((n) <= 143 ? stbi__zlib_huff1(n) : (n) <= 255 ? stbi__zlib_huff2(n) : (n) <= 279 ? stbi__zlib_huff3(n) : stbi__zlib_huff4(n))
292 #define stbi__zlib_huffb(n) ((n) <= 143 ? stbi__zlib_huff1(n) : stbi__zlib_huff2(n))
293 
294 #define stbi__ZHASH 16384
295 
stbi_zlib_compress(unsigned char * data,int data_len,int * out_len,int quality)296 unsigned char *stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)
297 {
298 	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};
299 	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};
300 	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};
301 	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};
302 	unsigned int bitbuf = 0;
303 	int i, j, bitcount = 0;
304 	unsigned char *out = NULL;
305 	unsigned char **hash_table[stbi__ZHASH];  // 64KB on the stack!
306 	if (quality < 5) quality = 5;
307 
308 	stbi__sbpush(out, 0x78);  // DEFLATE 32K window
309 	stbi__sbpush(out, 0x5e);  // FLEVEL = 1
310 	stbi__zlib_add(1, 1);     // BFINAL = 1
311 	stbi__zlib_add(1, 2);     // B3YPE = 1 -- fixed huffman
312 
313 	for (i = 0; i < stbi__ZHASH; ++i)
314 		hash_table[i] = NULL;
315 
316 	i = 0;
317 	while (i < data_len - 3)
318 	{
319 		// hash next 3 bytes of data to be compressed
320 		int h = stbi__zhash(data + i) & (stbi__ZHASH - 1), best = 3;
321 		unsigned char *bestloc = 0;
322 		unsigned char **hlist = hash_table[h];
323 		int n = stbi__sbcount(hlist);
324 		for (j = 0; j < n; ++j)
325 		{
326 			if (hlist[j] - data > i - 32768)
327 			{  // if entry lies within window
328 				int d = stbi__zlib_countm(hlist[j], data + i, data_len - i);
329 				if (d >= best) best = d, bestloc = hlist[j];
330 			}
331 		}
332 		// when hash table entry is too long, delete half the entries
333 		if (hash_table[h] && stbi__sbn(hash_table[h]) == 2 * quality)
334 		{
335 			memcpy(hash_table[h], hash_table[h] + quality, sizeof(hash_table[h][0]) * quality);
336 			stbi__sbn(hash_table[h]) = quality;
337 		}
338 		stbi__sbpush(hash_table[h], data + i);
339 
340 		if (bestloc)
341 		{
342 			// "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal
343 			h = stbi__zhash(data + i + 1) & (stbi__ZHASH - 1);
344 			hlist = hash_table[h];
345 			n = stbi__sbcount(hlist);
346 			for (j = 0; j < n; ++j)
347 			{
348 				if (hlist[j] - data > i - 32767)
349 				{
350 					int e = stbi__zlib_countm(hlist[j], data + i + 1, data_len - i - 1);
351 					if (e > best)
352 					{  // if next match is better, bail on current match
353 						bestloc = NULL;
354 						break;
355 					}
356 				}
357 			}
358 		}
359 
360 		if (bestloc)
361 		{
362 			int d = data + i - bestloc;  // distance back
363 			assert(d <= 32767 && best <= 258);
364 			for (j = 0; best > lengthc[j + 1] - 1; ++j)
365 				;
366 			stbi__zlib_huff(j + 257);
367 			if (lengtheb[j]) stbi__zlib_add(best - lengthc[j], lengtheb[j]);
368 			for (j = 0; d > distc[j + 1] - 1; ++j)
369 				;
370 			stbi__zlib_add(stbi__zlib_bitrev(j, 5), 5);
371 			if (disteb[j]) stbi__zlib_add(d - distc[j], disteb[j]);
372 			i += best;
373 		}
374 		else
375 		{
376 			stbi__zlib_huffb(data[i]);
377 			++i;
378 		}
379 	}
380 	// write out final bytes
381 	for (; i < data_len; ++i)
382 		stbi__zlib_huffb(data[i]);
383 	stbi__zlib_huff(256);  // end of block
384 	// pad with 0 bits to byte boundary
385 	while (bitcount)
386 		stbi__zlib_add(0, 1);
387 
388 	for (i = 0; i < stbi__ZHASH; ++i)
389 		(void)stbi__sbfree(hash_table[i]);
390 
391 	{
392 		// compute adler32 on input
393 		unsigned int i = 0, s1 = 1, s2 = 0, blocklen = data_len % 5552;
394 		int j = 0;
395 		while (j < data_len)
396 		{
397 			for (i = 0; i < blocklen; ++i) s1 += data[j + i], s2 += s1;
398 			s1 %= 65521, s2 %= 65521;
399 			j += blocklen;
400 			blocklen = 5552;
401 		}
402 		stbi__sbpush(out, (unsigned char)(s2 >> 8));
403 		stbi__sbpush(out, (unsigned char)s2);
404 		stbi__sbpush(out, (unsigned char)(s1 >> 8));
405 		stbi__sbpush(out, (unsigned char)s1);
406 	}
407 	*out_len = stbi__sbn(out);
408 	// make returned pointer freeable
409 	memmove(stbi__sbraw(out), out, *out_len);
410 	return (unsigned char *)stbi__sbraw(out);
411 }
412 
stbi__crc32(unsigned char * buffer,int len)413 unsigned int stbi__crc32(unsigned char *buffer, int len)
414 {
415 	static unsigned int crc_table[256];
416 	unsigned int crc = ~0u;
417 	int i, j;
418 	if (crc_table[1] == 0)
419 		for (i = 0; i < 256; i++)
420 			for (crc_table[i] = i, j = 0; j < 8; ++j)
421 				crc_table[i] = (crc_table[i] >> 1) ^ (crc_table[i] & 1 ? 0xedb88320 : 0);
422 	for (i = 0; i < len; ++i)
423 		crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];
424 	return ~crc;
425 }
426 
427 #define stbi__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)
428 #define stbi__wp32(data, v) stbi__wpng4(data, (v) >> 24, (v) >> 16, (v) >> 8, (v));
429 #define stbi__wptag(data, s) stbi__wpng4(data, s[0], s[1], s[2], s[3])
430 
stbi__wpcrc(unsigned char ** data,int len)431 static void stbi__wpcrc(unsigned char **data, int len)
432 {
433 	unsigned int crc = stbi__crc32(*data - len - 4, len + 4);
434 	stbi__wp32(*data, crc);
435 }
436 
stbi__paeth(int a,int b,int c)437 static unsigned char stbi__paeth(int a, int b, int c)
438 {
439 	int p = a + b - c, pa = abs(p - a), pb = abs(p - b), pc = abs(p - c);
440 	if (pa <= pb && pa <= pc) return (unsigned char)a;
441 	if (pb <= pc) return (unsigned char)b;
442 	return (unsigned char)c;
443 }
444 
stbi_write_png_to_mem(unsigned char * pixels,int stride_bytes,int x,int y,int n,int * out_len)445 unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
446 {
447 	int ctype[5] = {-1, 0, 4, 2, 6};
448 	unsigned char sig[8] = {137, 80, 78, 71, 13, 10, 26, 10};
449 	unsigned char *out, *o, *filt, *zlib;
450 	signed char *line_buffer;
451 	int i, j, k, p, zlen;
452 
453 	if (stride_bytes == 0)
454 		stride_bytes = x * n;
455 
456 	filt = (unsigned char *)malloc((x * n + 1) * y);
457 	if (!filt) return 0;
458 	line_buffer = (signed char *)malloc(x * n);
459 	if (!line_buffer)
460 	{
461 		free(filt);
462 		return 0;
463 	}
464 	for (j = 0; j < y; ++j)
465 	{
466 		static int mapping[] = {0, 1, 2, 3, 4};
467 		static int firstmap[] = {0, 1, 0, 5, 6};
468 		int *mymap = j ? mapping : firstmap;
469 		int best = 0, bestval = 0x7fffffff;
470 		for (p = 0; p < 2; ++p)
471 		{
472 			for (k = p ? best : 0; k < 5; ++k)
473 			{
474 				int type = mymap[k], est = 0;
475 				unsigned char *z = pixels + stride_bytes * j;
476 				for (i = 0; i < n; ++i)
477 					switch (type)
478 					{
479 						case 0:
480 							line_buffer[i] = z[i];
481 							break;
482 						case 1:
483 							line_buffer[i] = z[i];
484 							break;
485 						case 2:
486 							line_buffer[i] = z[i] - z[i - stride_bytes];
487 							break;
488 						case 3:
489 							line_buffer[i] = z[i] - (z[i - stride_bytes] >> 1);
490 							break;
491 						case 4:
492 							line_buffer[i] = (signed char)(z[i] - stbi__paeth(0, z[i - stride_bytes], 0));
493 							break;
494 						case 5:
495 							line_buffer[i] = z[i];
496 							break;
497 						case 6:
498 							line_buffer[i] = z[i];
499 							break;
500 					}
501 				for (i = n; i < x * n; ++i)
502 				{
503 					switch (type)
504 					{
505 						case 0:
506 							line_buffer[i] = z[i];
507 							break;
508 						case 1:
509 							line_buffer[i] = z[i] - z[i - n];
510 							break;
511 						case 2:
512 							line_buffer[i] = z[i] - z[i - stride_bytes];
513 							break;
514 						case 3:
515 							line_buffer[i] = z[i] - ((z[i - n] + z[i - stride_bytes]) >> 1);
516 							break;
517 						case 4:
518 							line_buffer[i] = z[i] - stbi__paeth(z[i - n], z[i - stride_bytes], z[i - stride_bytes - n]);
519 							break;
520 						case 5:
521 							line_buffer[i] = z[i] - (z[i - n] >> 1);
522 							break;
523 						case 6:
524 							line_buffer[i] = z[i] - stbi__paeth(z[i - n], 0, 0);
525 							break;
526 					}
527 				}
528 				if (p) break;
529 				for (i = 0; i < x * n; ++i)
530 					est += abs((signed char)line_buffer[i]);
531 				if (est < bestval)
532 				{
533 					bestval = est;
534 					best = k;
535 				}
536 			}
537 		}
538 		// when we get here, best contains the filter type, and line_buffer contains the data
539 		filt[j * (x * n + 1)] = (unsigned char)best;
540 		memcpy(filt + j * (x * n + 1) + 1, line_buffer, x * n);
541 	}
542 	free(line_buffer);
543 	zlib = stbi_zlib_compress(filt, y * (x * n + 1), &zlen, 8);  // increase 8 to get smaller but use more memory
544 	free(filt);
545 	if (!zlib) return 0;
546 
547 	// each tag requires 12 bytes of overhead
548 	out = (unsigned char *)malloc(8 + 12 + 13 + 12 + zlen + 12);
549 	if (!out) return 0;
550 	*out_len = 8 + 12 + 13 + 12 + zlen + 12;
551 
552 	o = out;
553 	memcpy(o, sig, 8);
554 	o += 8;
555 	stbi__wp32(o, 13);  // header length
556 	stbi__wptag(o, "IHDR");
557 	stbi__wp32(o, x);
558 	stbi__wp32(o, y);
559 	*o++ = 8;
560 	*o++ = (unsigned char)ctype[n];
561 	*o++ = 0;
562 	*o++ = 0;
563 	*o++ = 0;
564 	stbi__wpcrc(&o, 13);
565 
566 	stbi__wp32(o, zlen);
567 	stbi__wptag(o, "IDAT");
568 	memcpy(o, zlib, zlen);
569 	o += zlen;
570 	free(zlib);
571 	stbi__wpcrc(&o, zlen);
572 
573 	stbi__wp32(o, 0);
574 	stbi__wptag(o, "IEND");
575 	stbi__wpcrc(&o, 0);
576 
577 	assert(o == out + *out_len);
578 
579 	return out;
580 }
581 
stbi_write_png(char const * filename,int x,int y,int comp,const void * data,int stride_bytes)582 int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
583 {
584 	FILE *f;
585 	int len;
586 	unsigned char *png = stbi_write_png_to_mem((unsigned char *)data, stride_bytes, x, y, comp, &len);
587 	if (!png) return 0;
588 	f = fopen(filename, "wb");
589 	if (!f)
590 	{
591 		free(png);
592 		return 0;
593 	}
594 	fwrite(png, 1, len, f);
595 	fclose(f);
596 	free(png);
597 	return 1;
598 }
599 #endif  // STB_IMAGE_WRITE_IMPLEMENTATION
600 
601 /* Revision history
602 
603       0.92 (2010-08-01)
604              casts to unsigned char to fix warnings
605       0.91 (2010-07-17)
606              first public release
607       0.90   first internal release
608 */
609