Open Source Tomb Raider Engine
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

stb_image_write.h 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. /* stb_image_write - v0.95 - 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. Before including,
  5. #define STB_IMAGE_WRITE_IMPLEMENTATION
  6. in the file that you want to have the implementation.
  7. Will probably not work correctly with strict-aliasing optimizations.
  8. ABOUT:
  9. This header file is a library for writing images to C stdio. It could be
  10. adapted to write to memory or a general streaming interface; let me know.
  11. The PNG output is not optimal; it is 20-50% larger than the file
  12. written by a decent optimizing implementation. This library is designed
  13. for source code compactness and simplicitly, not optimal image file size
  14. or run-time performance.
  15. USAGE:
  16. There are three functions, one for each image file format:
  17. int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
  18. int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
  19. int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
  20. Each function returns 0 on failure and non-0 on success.
  21. The functions create an image file defined by the parameters. The image
  22. is a rectangle of pixels stored from left-to-right, top-to-bottom.
  23. Each pixel contains 'comp' channels of data stored interleaved with 8-bits
  24. per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is
  25. monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall.
  26. The *data pointer points to the first byte of the top-left-most pixel.
  27. For PNG, "stride_in_bytes" is the distance in bytes from the first byte of
  28. a row of pixels to the first byte of the next row of pixels.
  29. PNG creates output files with the same number of components as the input.
  30. The BMP format expands Y to RGB in the file format and does not
  31. output alpha.
  32. PNG supports writing rectangles of data even when the bytes storing rows of
  33. data are not consecutive in memory (e.g. sub-rectangles of a larger image),
  34. by supplying the stride between the beginning of adjacent rows. The other
  35. formats do not. (Thus you cannot write a native-format BMP through the BMP
  36. writer, both because it is in BGR order and because it may have padding
  37. at the end of the line.)
  38. */
  39. #ifndef INCLUDE_STB_IMAGE_WRITE_H
  40. #define INCLUDE_STB_IMAGE_WRITE_H
  41. #ifdef __cplusplus
  42. extern "C" {
  43. #endif
  44. extern int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
  45. extern int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
  46. extern int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
  47. #ifdef __cplusplus
  48. }
  49. #endif
  50. #endif//INCLUDE_STB_IMAGE_WRITE_H
  51. #ifdef STB_IMAGE_WRITE_IMPLEMENTATION
  52. #include <stdarg.h>
  53. #include <stdlib.h>
  54. #include <stdio.h>
  55. #include <string.h>
  56. #ifndef STBI_ASSERT
  57. #include <assert.h>
  58. #define STBI_ASSERT(x) assert(x)
  59. #endif
  60. typedef unsigned int stbiw_uint32;
  61. typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
  62. static void writefv(FILE *f, const char *fmt, va_list v)
  63. {
  64. while (*fmt) {
  65. switch (*fmt++) {
  66. case ' ': break;
  67. case '1': { unsigned char x = (unsigned char) va_arg(v, int); fputc(x,f); break; }
  68. case '2': { int x = va_arg(v,int); unsigned char b[2];
  69. b[0] = (unsigned char) x; b[1] = (unsigned char) (x>>8);
  70. fwrite(b,2,1,f); break; }
  71. case '4': { stbiw_uint32 x = va_arg(v,int); unsigned char b[4];
  72. b[0]=(unsigned char)x; b[1]=(unsigned char)(x>>8);
  73. b[2]=(unsigned char)(x>>16); b[3]=(unsigned char)(x>>24);
  74. fwrite(b,4,1,f); break; }
  75. default:
  76. STBI_ASSERT(0);
  77. return;
  78. }
  79. }
  80. }
  81. static void write3(FILE *f, unsigned char a, unsigned char b, unsigned char c)
  82. {
  83. unsigned char arr[3];
  84. arr[0] = a, arr[1] = b, arr[2] = c;
  85. fwrite(arr, 3, 1, f);
  86. }
  87. 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)
  88. {
  89. unsigned char bg[3] = { 255, 0, 255}, px[3];
  90. stbiw_uint32 zero = 0;
  91. int i,j,k, j_end;
  92. if (y <= 0)
  93. return;
  94. if (vdir < 0)
  95. j_end = -1, j = y-1;
  96. else
  97. j_end = y, j = 0;
  98. for (; j != j_end; j += vdir) {
  99. for (i=0; i < x; ++i) {
  100. unsigned char *d = (unsigned char *) data + (j*x+i)*comp;
  101. if (write_alpha < 0)
  102. fwrite(&d[comp-1], 1, 1, f);
  103. switch (comp) {
  104. case 1:
  105. case 2: fwrite(d, 1, 1, f);
  106. break;
  107. case 4:
  108. if (!write_alpha) {
  109. // composite against pink background
  110. for (k=0; k < 3; ++k)
  111. px[k] = bg[k] + ((d[k] - bg[k]) * d[3])/255;
  112. write3(f, px[1-rgb_dir],px[1],px[1+rgb_dir]);
  113. break;
  114. }
  115. /* FALLTHROUGH */
  116. case 3:
  117. write3(f, d[1-rgb_dir],d[1],d[1+rgb_dir]);
  118. break;
  119. }
  120. if (write_alpha > 0)
  121. fwrite(&d[comp-1], 1, 1, f);
  122. }
  123. fwrite(&zero,scanline_pad,1,f);
  124. }
  125. }
  126. 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, ...)
  127. {
  128. FILE *f;
  129. if (y < 0 || x < 0) return 0;
  130. f = fopen(filename, "wb");
  131. if (f) {
  132. va_list v;
  133. va_start(v, fmt);
  134. writefv(f, fmt, v);
  135. va_end(v);
  136. write_pixels(f,rgb_dir,vdir,x,y,comp,data,alpha,pad);
  137. fclose(f);
  138. }
  139. return f != NULL;
  140. }
  141. int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
  142. {
  143. int pad = (-x*3) & 3;
  144. return outfile(filename,-1,-1,x,y,comp,(void *) data,0,pad,
  145. "11 4 22 4" "4 44 22 444444",
  146. 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header
  147. 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header
  148. }
  149. int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
  150. {
  151. int has_alpha = (comp == 2 || comp == 4);
  152. int colorbytes = has_alpha ? comp-1 : comp;
  153. int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3
  154. return outfile(filename, -1,-1, x, y, comp, (void *) data, has_alpha, 0,
  155. "111 221 2222 11", 0,0,format, 0,0,0, 0,0,x,y, (colorbytes+has_alpha)*8, has_alpha*8);
  156. }
  157. // stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
  158. #define stbiw__sbraw(a) ((int *) (a) - 2)
  159. #define stbiw__sbm(a) stbiw__sbraw(a)[0]
  160. #define stbiw__sbn(a) stbiw__sbraw(a)[1]
  161. #define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a))
  162. #define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0)
  163. #define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a)))
  164. #define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v))
  165. #define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0)
  166. #define stbiw__sbfree(a) ((a) ? free(stbiw__sbraw(a)),0 : 0)
  167. static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
  168. {
  169. int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1;
  170. void *p = realloc(*arr ? stbiw__sbraw(*arr) : 0, itemsize * m + sizeof(int)*2);
  171. STBI_ASSERT(p);
  172. if (p) {
  173. if (!*arr) ((int *) p)[1] = 0;
  174. *arr = (void *) ((int *) p + 2);
  175. stbiw__sbm(*arr) = m;
  176. }
  177. return *arr;
  178. }
  179. static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)
  180. {
  181. while (*bitcount >= 8) {
  182. stbiw__sbpush(data, (unsigned char) *bitbuffer);
  183. *bitbuffer >>= 8;
  184. *bitcount -= 8;
  185. }
  186. return data;
  187. }
  188. static int stbiw__zlib_bitrev(int code, int codebits)
  189. {
  190. int res=0;
  191. while (codebits--) {
  192. res = (res << 1) | (code & 1);
  193. code >>= 1;
  194. }
  195. return res;
  196. }
  197. static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit)
  198. {
  199. int i;
  200. for (i=0; i < limit && i < 258; ++i)
  201. if (a[i] != b[i]) break;
  202. return i;
  203. }
  204. static unsigned int stbiw__zhash(unsigned char *data)
  205. {
  206. stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16);
  207. hash ^= hash << 3;
  208. hash += hash >> 5;
  209. hash ^= hash << 4;
  210. hash += hash >> 17;
  211. hash ^= hash << 25;
  212. hash += hash >> 6;
  213. return hash;
  214. }
  215. #define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount))
  216. #define stbiw__zlib_add(code,codebits) \
  217. (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush())
  218. #define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c)
  219. // default huffman tables
  220. #define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8)
  221. #define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9)
  222. #define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7)
  223. #define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8)
  224. #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))
  225. #define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n))
  226. #define stbiw__ZHASH 16384
  227. unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)
  228. {
  229. 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 };
  230. 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 };
  231. 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 };
  232. 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 };
  233. unsigned int bitbuf=0;
  234. int i,j, bitcount=0;
  235. unsigned char *out = NULL;
  236. unsigned char **hash_table[stbiw__ZHASH]; // 64KB on the stack!
  237. if (quality < 5) quality = 5;
  238. stbiw__sbpush(out, 0x78); // DEFLATE 32K window
  239. stbiw__sbpush(out, 0x5e); // FLEVEL = 1
  240. stbiw__zlib_add(1,1); // BFINAL = 1
  241. stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman
  242. for (i=0; i < stbiw__ZHASH; ++i)
  243. hash_table[i] = NULL;
  244. i=0;
  245. while (i < data_len-3) {
  246. // hash next 3 bytes of data to be compressed
  247. int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3;
  248. unsigned char *bestloc = 0;
  249. unsigned char **hlist = hash_table[h];
  250. int n = stbiw__sbcount(hlist);
  251. for (j=0; j < n; ++j) {
  252. if (hlist[j]-data > i-32768) { // if entry lies within window
  253. int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i);
  254. if (d >= best) best=d,bestloc=hlist[j];
  255. }
  256. }
  257. // when hash table entry is too long, delete half the entries
  258. if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) {
  259. memcpy(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);
  260. stbiw__sbn(hash_table[h]) = quality;
  261. }
  262. stbiw__sbpush(hash_table[h],data+i);
  263. if (bestloc) {
  264. // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal
  265. h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1);
  266. hlist = hash_table[h];
  267. n = stbiw__sbcount(hlist);
  268. for (j=0; j < n; ++j) {
  269. if (hlist[j]-data > i-32767) {
  270. int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1);
  271. if (e > best) { // if next match is better, bail on current match
  272. bestloc = NULL;
  273. break;
  274. }
  275. }
  276. }
  277. }
  278. if (bestloc) {
  279. int d = (int) (data+i - bestloc); // distance back
  280. STBI_ASSERT(d <= 32767 && best <= 258);
  281. for (j=0; best > lengthc[j+1]-1; ++j);
  282. stbiw__zlib_huff(j+257);
  283. if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]);
  284. for (j=0; d > distc[j+1]-1; ++j);
  285. stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5);
  286. if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]);
  287. i += best;
  288. } else {
  289. stbiw__zlib_huffb(data[i]);
  290. ++i;
  291. }
  292. }
  293. // write out final bytes
  294. for (;i < data_len; ++i)
  295. stbiw__zlib_huffb(data[i]);
  296. stbiw__zlib_huff(256); // end of block
  297. // pad with 0 bits to byte boundary
  298. while (bitcount)
  299. stbiw__zlib_add(0,1);
  300. for (i=0; i < stbiw__ZHASH; ++i)
  301. (void) stbiw__sbfree(hash_table[i]);
  302. {
  303. // compute adler32 on input
  304. unsigned int i=0, s1=1, s2=0, blocklen = data_len % 5552;
  305. int j=0;
  306. while (j < data_len) {
  307. for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1;
  308. s1 %= 65521, s2 %= 65521;
  309. j += blocklen;
  310. blocklen = 5552;
  311. }
  312. stbiw__sbpush(out, (unsigned char) (s2 >> 8));
  313. stbiw__sbpush(out, (unsigned char) s2);
  314. stbiw__sbpush(out, (unsigned char) (s1 >> 8));
  315. stbiw__sbpush(out, (unsigned char) s1);
  316. }
  317. *out_len = stbiw__sbn(out);
  318. // make returned pointer freeable
  319. memmove(stbiw__sbraw(out), out, *out_len);
  320. return (unsigned char *) stbiw__sbraw(out);
  321. }
  322. unsigned int stbiw__crc32(unsigned char *buffer, int len)
  323. {
  324. static unsigned int crc_table[256];
  325. unsigned int crc = ~0u;
  326. int i,j;
  327. if (crc_table[1] == 0)
  328. for(i=0; i < 256; i++)
  329. for (crc_table[i]=i, j=0; j < 8; ++j)
  330. crc_table[i] = (crc_table[i] >> 1) ^ (crc_table[i] & 1 ? 0xedb88320 : 0);
  331. for (i=0; i < len; ++i)
  332. crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];
  333. return ~crc;
  334. }
  335. #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)
  336. #define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));
  337. #define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3])
  338. static void stbiw__wpcrc(unsigned char **data, int len)
  339. {
  340. unsigned int crc = stbiw__crc32(*data - len - 4, len+4);
  341. stbiw__wp32(*data, crc);
  342. }
  343. static unsigned char stbiw__paeth(int a, int b, int c)
  344. {
  345. int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c);
  346. if (pa <= pb && pa <= pc) return (unsigned char) a;
  347. if (pb <= pc) return (unsigned char) b;
  348. return (unsigned char) c;
  349. }
  350. unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
  351. {
  352. int ctype[5] = { -1, 0, 4, 2, 6 };
  353. unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
  354. unsigned char *out,*o, *filt, *zlib;
  355. signed char *line_buffer;
  356. int i,j,k,p,zlen;
  357. if (stride_bytes == 0)
  358. stride_bytes = x * n;
  359. filt = (unsigned char *) malloc((x*n+1) * y); if (!filt) return 0;
  360. line_buffer = (signed char *) malloc(x * n); if (!line_buffer) { free(filt); return 0; }
  361. for (j=0; j < y; ++j) {
  362. static int mapping[] = { 0,1,2,3,4 };
  363. static int firstmap[] = { 0,1,0,5,6 };
  364. int *mymap = j ? mapping : firstmap;
  365. int best = 0, bestval = 0x7fffffff;
  366. for (p=0; p < 2; ++p) {
  367. for (k= p?best:0; k < 5; ++k) {
  368. int type = mymap[k],est=0;
  369. unsigned char *z = pixels + stride_bytes*j;
  370. for (i=0; i < n; ++i)
  371. switch (type) {
  372. case 0: line_buffer[i] = z[i]; break;
  373. case 1: line_buffer[i] = z[i]; break;
  374. case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
  375. case 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break;
  376. case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-stride_bytes],0)); break;
  377. case 5: line_buffer[i] = z[i]; break;
  378. case 6: line_buffer[i] = z[i]; break;
  379. }
  380. for (i=n; i < x*n; ++i) {
  381. switch (type) {
  382. case 0: line_buffer[i] = z[i]; break;
  383. case 1: line_buffer[i] = z[i] - z[i-n]; break;
  384. case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break;
  385. case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>1); break;
  386. case 4: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-stride_bytes], z[i-stride_bytes-n]); break;
  387. case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break;
  388. case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break;
  389. }
  390. }
  391. if (p) break;
  392. for (i=0; i < x*n; ++i)
  393. est += abs((signed char) line_buffer[i]);
  394. if (est < bestval) { bestval = est; best = k; }
  395. }
  396. }
  397. // when we get here, best contains the filter type, and line_buffer contains the data
  398. filt[j*(x*n+1)] = (unsigned char) best;
  399. memcpy(filt+j*(x*n+1)+1, line_buffer, x*n);
  400. }
  401. free(line_buffer);
  402. zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory
  403. free(filt);
  404. if (!zlib) return 0;
  405. // each tag requires 12 bytes of overhead
  406. out = (unsigned char *) malloc(8 + 12+13 + 12+zlen + 12);
  407. if (!out) return 0;
  408. *out_len = 8 + 12+13 + 12+zlen + 12;
  409. o=out;
  410. memcpy(o,sig,8); o+= 8;
  411. stbiw__wp32(o, 13); // header length
  412. stbiw__wptag(o, "IHDR");
  413. stbiw__wp32(o, x);
  414. stbiw__wp32(o, y);
  415. *o++ = 8;
  416. *o++ = (unsigned char) ctype[n];
  417. *o++ = 0;
  418. *o++ = 0;
  419. *o++ = 0;
  420. stbiw__wpcrc(&o,13);
  421. stbiw__wp32(o, zlen);
  422. stbiw__wptag(o, "IDAT");
  423. memcpy(o, zlib, zlen); o += zlen; free(zlib);
  424. stbiw__wpcrc(&o, zlen);
  425. stbiw__wp32(o,0);
  426. stbiw__wptag(o, "IEND");
  427. stbiw__wpcrc(&o,0);
  428. STBI_ASSERT(o == out + *out_len);
  429. return out;
  430. }
  431. int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
  432. {
  433. FILE *f;
  434. int len;
  435. unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len);
  436. if (!png) return 0;
  437. f = fopen(filename, "wb");
  438. if (!f) { free(png); return 0; }
  439. fwrite(png, 1, len, f);
  440. fclose(f);
  441. free(png);
  442. return 1;
  443. }
  444. #endif // STB_IMAGE_WRITE_IMPLEMENTATION
  445. /* Revision history
  446. 0.95 (2014-08-17)
  447. add monochrome TGA output
  448. 0.94 (2014-05-31)
  449. rename private functions to avoid conflicts with stb_image.h
  450. 0.93 (2014-05-27)
  451. warning fixes
  452. 0.92 (2010-08-01)
  453. casts to unsigned char to fix warnings
  454. 0.91 (2010-07-17)
  455. first public release
  456. 0.90 first internal release
  457. */