source: opengl-game/stb_image_write.h@ 972aca1

feature/imgui-sdl points-test
Last change on this file since 972aca1 was 4e0b82b, checked in by Dmitry Portnoy <dmp1488@…>, 7 years ago

Add an ImGui example project

  • Property mode set to 100644
File size: 63.3 KB
RevLine 
[4e0b82b]1/* stb_image_write - v1.09 - public domain - http://nothings.org/stb/stb_image_write.h
2writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015
3no warranty implied; use at your own risk
4
5Before #including,
6
7#define STB_IMAGE_WRITE_IMPLEMENTATION
8
9in the file that you want to have the implementation.
10
11Will probably not work correctly with strict-aliasing optimizations.
12
13If using a modern Microsoft Compiler, non-safe versions of CRT calls may cause
14compilation warnings or even errors. To avoid this, also before #including,
15
16#define STBI_MSC_SECURE_CRT
17
18ABOUT:
19
20This header file is a library for writing images to C stdio. It could be
21adapted to write to memory or a general streaming interface; let me know.
22
23The PNG output is not optimal; it is 20-50% larger than the file
24written by a decent optimizing implementation; though providing a custom
25zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that.
26This library is designed for source code compactness and simplicity,
27not optimal image file size or run-time performance.
28
29BUILDING:
30
31You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h.
32You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace
33malloc,realloc,free.
34You can #define STBIW_MEMMOVE() to replace memmove()
35You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function
36for PNG compression (instead of the builtin one), it must have the following signature:
37unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality);
38The returned data will be freed with STBIW_FREE() (free() by default),
39so it must be heap allocated with STBIW_MALLOC() (malloc() by default),
40
41USAGE:
42
43There are five functions, one for each image file format:
44
45int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
46int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
47int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
48int stbi_write_jpg(char const *filename, int w, int h, int comp, const void *data, int quality);
49int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
50
51void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically
52
53There are also five equivalent functions that use an arbitrary write function. You are
54expected to open/close your file-equivalent before and after calling these:
55
56int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes);
57int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
58int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
59int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
60int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);
61
62where the callback is:
63void stbi_write_func(void *context, void *data, int size);
64
65You can configure it with these global variables:
66int stbi_write_tga_with_rle; // defaults to true; set to 0 to disable RLE
67int stbi_write_png_compression_level; // defaults to 8; set to higher for more compression
68int stbi_write_force_png_filter; // defaults to -1; set to 0..5 to force a filter mode
69
70
71You can define STBI_WRITE_NO_STDIO to disable the file variant of these
72functions, so the library will not use stdio.h at all. However, this will
73also disable HDR writing, because it requires stdio for formatted output.
74
75Each function returns 0 on failure and non-0 on success.
76
77The functions create an image file defined by the parameters. The image
78is a rectangle of pixels stored from left-to-right, top-to-bottom.
79Each pixel contains 'comp' channels of data stored interleaved with 8-bits
80per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is
81monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall.
82The *data pointer points to the first byte of the top-left-most pixel.
83For PNG, "stride_in_bytes" is the distance in bytes from the first byte of
84a row of pixels to the first byte of the next row of pixels.
85
86PNG creates output files with the same number of components as the input.
87The BMP format expands Y to RGB in the file format and does not
88output alpha.
89
90PNG supports writing rectangles of data even when the bytes storing rows of
91data are not consecutive in memory (e.g. sub-rectangles of a larger image),
92by supplying the stride between the beginning of adjacent rows. The other
93formats do not. (Thus you cannot write a native-format BMP through the BMP
94writer, both because it is in BGR order and because it may have padding
95at the end of the line.)
96
97PNG allows you to set the deflate compression level by setting the global
98variable 'stbi_write_png_compression_level' (it defaults to 8).
99
100HDR expects linear float data. Since the format is always 32-bit rgb(e)
101data, alpha (if provided) is discarded, and for monochrome data it is
102replicated across all three channels.
103
104TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed
105data, set the global variable 'stbi_write_tga_with_rle' to 0.
106
107JPEG does ignore alpha channels in input data; quality is between 1 and 100.
108Higher quality looks better but results in a bigger image.
109JPEG baseline (no JPEG progressive).
110
111CREDITS:
112
113
114Sean Barrett - PNG/BMP/TGA
115Baldur Karlsson - HDR
116Jean-Sebastien Guay - TGA monochrome
117Tim Kelsey - misc enhancements
118Alan Hickman - TGA RLE
119Emmanuel Julien - initial file IO callback implementation
120Jon Olick - original jo_jpeg.cpp code
121Daniel Gibson - integrate JPEG, allow external zlib
122Aarni Koskela - allow choosing PNG filter
123
124bugfixes:
125github:Chribba
126Guillaume Chereau
127github:jry2
128github:romigrou
129Sergio Gonzalez
130Jonas Karlsson
131Filip Wasil
132Thatcher Ulrich
133github:poppolopoppo
134Patrick Boettcher
135github:xeekworx
136Cap Petschulat
137Simon Rodriguez
138Ivan Tikhonov
139github:ignotion
140Adam Schackart
141
142LICENSE
143
144See end of file for license information.
145
146*/
147
148#ifndef INCLUDE_STB_IMAGE_WRITE_H
149#define INCLUDE_STB_IMAGE_WRITE_H
150
151// if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline'
152#ifndef STBIWDEF
153#ifdef STB_IMAGE_WRITE_STATIC
154#define STBIWDEF static
155#else
156#ifdef __cplusplus
157#define STBIWDEF extern "C"
158#else
159#define STBIWDEF extern
160#endif
161#endif
162#endif
163
164#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations
165extern int stbi_write_tga_with_rle;
166extern int stbi_write_png_compression_level;
167extern int stbi_write_force_png_filter;
168#endif
169
170#ifndef STBI_WRITE_NO_STDIO
171STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
172STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
173STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
174STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
175STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality);
176#endif
177
178typedef void stbi_write_func(void *context, void *data, int size);
179
180STBIWDEF 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);
181STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
182STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
183STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
184STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);
185
186STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean);
187
188#endif//INCLUDE_STB_IMAGE_WRITE_H
189
190#ifdef STB_IMAGE_WRITE_IMPLEMENTATION
191
192#ifdef _WIN32
193#ifndef _CRT_SECURE_NO_WARNINGS
194#define _CRT_SECURE_NO_WARNINGS
195#endif
196#ifndef _CRT_NONSTDC_NO_DEPRECATE
197#define _CRT_NONSTDC_NO_DEPRECATE
198#endif
199#endif
200
201#ifndef STBI_WRITE_NO_STDIO
202#include <stdio.h>
203#endif // STBI_WRITE_NO_STDIO
204
205#include <stdarg.h>
206#include <stdlib.h>
207#include <string.h>
208#include <math.h>
209
210#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED))
211// ok
212#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED)
213// ok
214#else
215#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)."
216#endif
217
218#ifndef STBIW_MALLOC
219#define STBIW_MALLOC(sz) malloc(sz)
220#define STBIW_REALLOC(p,newsz) realloc(p,newsz)
221#define STBIW_FREE(p) free(p)
222#endif
223
224#ifndef STBIW_REALLOC_SIZED
225#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz)
226#endif
227
228
229#ifndef STBIW_MEMMOVE
230#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz)
231#endif
232
233
234#ifndef STBIW_ASSERT
235#include <assert.h>
236#define STBIW_ASSERT(x) assert(x)
237#endif
238
239#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)
240
241#ifdef STB_IMAGE_WRITE_STATIC
242static int stbi__flip_vertically_on_write = 0;
243static int stbi_write_png_compression_level = 8;
244static int stbi_write_tga_with_rle = 1;
245static int stbi_write_force_png_filter = -1;
246#else
247int stbi_write_png_compression_level = 8;
248int stbi__flip_vertically_on_write = 0;
249int stbi_write_tga_with_rle = 1;
250int stbi_write_force_png_filter = -1;
251#endif
252
253STBIWDEF void stbi_flip_vertically_on_write(int flag)
254{
255 stbi__flip_vertically_on_write = flag;
256}
257
258typedef struct
259{
260 stbi_write_func *func;
261 void *context;
262} stbi__write_context;
263
264// initialize a callback-based context
265static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context)
266{
267 s->func = c;
268 s->context = context;
269}
270
271#ifndef STBI_WRITE_NO_STDIO
272
273static void stbi__stdio_write(void *context, void *data, int size)
274{
275 fwrite(data, 1, size, (FILE*)context);
276}
277
278static int stbi__start_write_file(stbi__write_context *s, const char *filename)
279{
280 FILE *f;
281#ifdef STBI_MSC_SECURE_CRT
282 if (fopen_s(&f, filename, "wb"))
283 f = NULL;
284#else
285 f = fopen(filename, "wb");
286#endif
287 stbi__start_write_callbacks(s, stbi__stdio_write, (void *)f);
288 return f != NULL;
289}
290
291static void stbi__end_write_file(stbi__write_context *s)
292{
293 fclose((FILE *)s->context);
294}
295
296#endif // !STBI_WRITE_NO_STDIO
297
298typedef unsigned int stbiw_uint32;
299typedef int stb_image_write_test[sizeof(stbiw_uint32) == 4 ? 1 : -1];
300
301static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v)
302{
303 while (*fmt) {
304 switch (*fmt++) {
305 case ' ': break;
306 case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int));
307 s->func(s->context, &x, 1);
308 break; }
309 case '2': { int x = va_arg(v, int);
310 unsigned char b[2];
311 b[0] = STBIW_UCHAR(x);
312 b[1] = STBIW_UCHAR(x >> 8);
313 s->func(s->context, b, 2);
314 break; }
315 case '4': { stbiw_uint32 x = va_arg(v, int);
316 unsigned char b[4];
317 b[0] = STBIW_UCHAR(x);
318 b[1] = STBIW_UCHAR(x >> 8);
319 b[2] = STBIW_UCHAR(x >> 16);
320 b[3] = STBIW_UCHAR(x >> 24);
321 s->func(s->context, b, 4);
322 break; }
323 default:
324 STBIW_ASSERT(0);
325 return;
326 }
327 }
328}
329
330static void stbiw__writef(stbi__write_context *s, const char *fmt, ...)
331{
332 va_list v;
333 va_start(v, fmt);
334 stbiw__writefv(s, fmt, v);
335 va_end(v);
336}
337
338static void stbiw__putc(stbi__write_context *s, unsigned char c)
339{
340 s->func(s->context, &c, 1);
341}
342
343static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c)
344{
345 unsigned char arr[3];
346 arr[0] = a, arr[1] = b, arr[2] = c;
347 s->func(s->context, arr, 3);
348}
349
350static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d)
351{
352 unsigned char bg[3] = { 255, 0, 255 }, px[3];
353 int k;
354
355 if (write_alpha < 0)
356 s->func(s->context, &d[comp - 1], 1);
357
358 switch (comp) {
359 case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case
360 case 1:
361 if (expand_mono)
362 stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp
363 else
364 s->func(s->context, d, 1); // monochrome TGA
365 break;
366 case 4:
367 if (!write_alpha) {
368 // composite against pink background
369 for (k = 0; k < 3; ++k)
370 px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255;
371 stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]);
372 break;
373 }
374 /* FALLTHROUGH */
375 case 3:
376 stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]);
377 break;
378 }
379 if (write_alpha > 0)
380 s->func(s->context, &d[comp - 1], 1);
381}
382
383static 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)
384{
385 stbiw_uint32 zero = 0;
386 int i, j, j_end;
387
388 if (y <= 0)
389 return;
390
391 if (stbi__flip_vertically_on_write)
392 vdir *= -1;
393
394 if (vdir < 0)
395 j_end = -1, j = y - 1;
396 else
397 j_end = y, j = 0;
398
399 for (; j != j_end; j += vdir) {
400 for (i = 0; i < x; ++i) {
401 unsigned char *d = (unsigned char *)data + (j*x + i)*comp;
402 stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d);
403 }
404 s->func(s->context, &zero, scanline_pad);
405 }
406}
407
408static 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, ...)
409{
410 if (y < 0 || x < 0) {
411 return 0;
412 }
413 else {
414 va_list v;
415 va_start(v, fmt);
416 stbiw__writefv(s, fmt, v);
417 va_end(v);
418 stbiw__write_pixels(s, rgb_dir, vdir, x, y, comp, data, alpha, pad, expand_mono);
419 return 1;
420 }
421}
422
423static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data)
424{
425 int pad = (-x * 3) & 3;
426 return stbiw__outfile(s, -1, -1, x, y, comp, 1, (void *)data, 0, pad,
427 "11 4 22 4" "4 44 22 444444",
428 'B', 'M', 14 + 40 + (x * 3 + pad)*y, 0, 0, 14 + 40, // file header
429 40, x, y, 1, 24, 0, 0, 0, 0, 0, 0); // bitmap header
430}
431
432STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
433{
434 stbi__write_context s;
435 stbi__start_write_callbacks(&s, func, context);
436 return stbi_write_bmp_core(&s, x, y, comp, data);
437}
438
439#ifndef STBI_WRITE_NO_STDIO
440STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
441{
442 stbi__write_context s;
443 if (stbi__start_write_file(&s, filename)) {
444 int r = stbi_write_bmp_core(&s, x, y, comp, data);
445 stbi__end_write_file(&s);
446 return r;
447 }
448 else
449 return 0;
450}
451#endif //!STBI_WRITE_NO_STDIO
452
453static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data)
454{
455 int has_alpha = (comp == 2 || comp == 4);
456 int colorbytes = has_alpha ? comp - 1 : comp;
457 int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3
458
459 if (y < 0 || x < 0)
460 return 0;
461
462 if (!stbi_write_tga_with_rle) {
463 return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *)data, has_alpha, 0,
464 "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8);
465 }
466 else {
467 int i, j, k;
468 int jend, jdir;
469
470 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);
471
472 if (stbi__flip_vertically_on_write) {
473 j = 0;
474 jend = y;
475 jdir = 1;
476 }
477 else {
478 j = y - 1;
479 jend = -1;
480 jdir = -1;
481 }
482 for (; j != jend; j += jdir) {
483 unsigned char *row = (unsigned char *)data + j * x * comp;
484 int len;
485
486 for (i = 0; i < x; i += len) {
487 unsigned char *begin = row + i * comp;
488 int diff = 1;
489 len = 1;
490
491 if (i < x - 1) {
492 ++len;
493 diff = memcmp(begin, row + (i + 1) * comp, comp);
494 if (diff) {
495 const unsigned char *prev = begin;
496 for (k = i + 2; k < x && len < 128; ++k) {
497 if (memcmp(prev, row + k * comp, comp)) {
498 prev += comp;
499 ++len;
500 }
501 else {
502 --len;
503 break;
504 }
505 }
506 }
507 else {
508 for (k = i + 2; k < x && len < 128; ++k) {
509 if (!memcmp(begin, row + k * comp, comp)) {
510 ++len;
511 }
512 else {
513 break;
514 }
515 }
516 }
517 }
518
519 if (diff) {
520 unsigned char header = STBIW_UCHAR(len - 1);
521 s->func(s->context, &header, 1);
522 for (k = 0; k < len; ++k) {
523 stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp);
524 }
525 }
526 else {
527 unsigned char header = STBIW_UCHAR(len - 129);
528 s->func(s->context, &header, 1);
529 stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin);
530 }
531 }
532 }
533 }
534 return 1;
535}
536
537STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
538{
539 stbi__write_context s;
540 stbi__start_write_callbacks(&s, func, context);
541 return stbi_write_tga_core(&s, x, y, comp, (void *)data);
542}
543
544#ifndef STBI_WRITE_NO_STDIO
545STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
546{
547 stbi__write_context s;
548 if (stbi__start_write_file(&s, filename)) {
549 int r = stbi_write_tga_core(&s, x, y, comp, (void *)data);
550 stbi__end_write_file(&s);
551 return r;
552 }
553 else
554 return 0;
555}
556#endif
557
558// *************************************************************************************************
559// Radiance RGBE HDR writer
560// by Baldur Karlsson
561
562#define stbiw__max(a, b) ((a) > (b) ? (a) : (b))
563
564void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
565{
566 int exponent;
567 float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2]));
568
569 if (maxcomp < 1e-32f) {
570 rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
571 }
572 else {
573 float normalize = (float)frexp(maxcomp, &exponent) * 256.0f / maxcomp;
574
575 rgbe[0] = (unsigned char)(linear[0] * normalize);
576 rgbe[1] = (unsigned char)(linear[1] * normalize);
577 rgbe[2] = (unsigned char)(linear[2] * normalize);
578 rgbe[3] = (unsigned char)(exponent + 128);
579 }
580}
581
582void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte)
583{
584 unsigned char lengthbyte = STBIW_UCHAR(length + 128);
585 STBIW_ASSERT(length + 128 <= 255);
586 s->func(s->context, &lengthbyte, 1);
587 s->func(s->context, &databyte, 1);
588}
589
590void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data)
591{
592 unsigned char lengthbyte = STBIW_UCHAR(length);
593 STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code
594 s->func(s->context, &lengthbyte, 1);
595 s->func(s->context, data, length);
596}
597
598void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline)
599{
600 unsigned char scanlineheader[4] = { 2, 2, 0, 0 };
601 unsigned char rgbe[4];
602 float linear[3];
603 int x;
604
605 scanlineheader[2] = (width & 0xff00) >> 8;
606 scanlineheader[3] = (width & 0x00ff);
607
608 /* skip RLE for images too small or large */
609 if (width < 8 || width >= 32768) {
610 for (x = 0; x < width; x++) {
611 switch (ncomp) {
612 case 4: /* fallthrough */
613 case 3: linear[2] = scanline[x*ncomp + 2];
614 linear[1] = scanline[x*ncomp + 1];
615 linear[0] = scanline[x*ncomp + 0];
616 break;
617 default:
618 linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];
619 break;
620 }
621 stbiw__linear_to_rgbe(rgbe, linear);
622 s->func(s->context, rgbe, 4);
623 }
624 }
625 else {
626 int c, r;
627 /* encode into scratch buffer */
628 for (x = 0; x < width; x++) {
629 switch (ncomp) {
630 case 4: /* fallthrough */
631 case 3: linear[2] = scanline[x*ncomp + 2];
632 linear[1] = scanline[x*ncomp + 1];
633 linear[0] = scanline[x*ncomp + 0];
634 break;
635 default:
636 linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];
637 break;
638 }
639 stbiw__linear_to_rgbe(rgbe, linear);
640 scratch[x + width * 0] = rgbe[0];
641 scratch[x + width * 1] = rgbe[1];
642 scratch[x + width * 2] = rgbe[2];
643 scratch[x + width * 3] = rgbe[3];
644 }
645
646 s->func(s->context, scanlineheader, 4);
647
648 /* RLE each component separately */
649 for (c = 0; c < 4; c++) {
650 unsigned char *comp = &scratch[width*c];
651
652 x = 0;
653 while (x < width) {
654 // find first run
655 r = x;
656 while (r + 2 < width) {
657 if (comp[r] == comp[r + 1] && comp[r] == comp[r + 2])
658 break;
659 ++r;
660 }
661 if (r + 2 >= width)
662 r = width;
663 // dump up to first run
664 while (x < r) {
665 int len = r - x;
666 if (len > 128) len = 128;
667 stbiw__write_dump_data(s, len, &comp[x]);
668 x += len;
669 }
670 // if there's a run, output it
671 if (r + 2 < width) { // same test as what we break out of in search loop, so only true if we break'd
672 // find next byte after run
673 while (r < width && comp[r] == comp[x])
674 ++r;
675 // output run up to r
676 while (x < r) {
677 int len = r - x;
678 if (len > 127) len = 127;
679 stbiw__write_run_data(s, len, comp[x]);
680 x += len;
681 }
682 }
683 }
684 }
685 }
686}
687
688static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data)
689{
690 if (y <= 0 || x <= 0 || data == NULL)
691 return 0;
692 else {
693 // Each component is stored separately. Allocate scratch space for full output scanline.
694 unsigned char *scratch = (unsigned char *)STBIW_MALLOC(x * 4);
695 int i, len;
696 char buffer[128];
697 char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n";
698 s->func(s->context, header, sizeof(header) - 1);
699
700#ifdef STBI_MSC_SECURE_CRT
701 len = sprintf_s(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
702#else
703 len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
704#endif
705 s->func(s->context, buffer, len);
706
707 for (i = 0; i < y; i++)
708 stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y - 1 - i : i)*x);
709 STBIW_FREE(scratch);
710 return 1;
711 }
712}
713
714STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data)
715{
716 stbi__write_context s;
717 stbi__start_write_callbacks(&s, func, context);
718 return stbi_write_hdr_core(&s, x, y, comp, (float *)data);
719}
720
721#ifndef STBI_WRITE_NO_STDIO
722STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
723{
724 stbi__write_context s;
725 if (stbi__start_write_file(&s, filename)) {
726 int r = stbi_write_hdr_core(&s, x, y, comp, (float *)data);
727 stbi__end_write_file(&s);
728 return r;
729 }
730 else
731 return 0;
732}
733#endif // STBI_WRITE_NO_STDIO
734
735
736//////////////////////////////////////////////////////////////////////////////
737//
738// PNG writer
739//
740
741#ifndef STBIW_ZLIB_COMPRESS
742// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
743#define stbiw__sbraw(a) ((int *) (a) - 2)
744#define stbiw__sbm(a) stbiw__sbraw(a)[0]
745#define stbiw__sbn(a) stbiw__sbraw(a)[1]
746
747#define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a))
748#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0)
749#define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a)))
750
751#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v))
752#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0)
753#define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0)
754
755static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
756{
757 int m = *arr ? 2 * stbiw__sbm(*arr) + increment : increment + 1;
758 void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int) * 2) : 0, itemsize * m + sizeof(int) * 2);
759 STBIW_ASSERT(p);
760 if (p) {
761 if (!*arr) ((int *)p)[1] = 0;
762 *arr = (void *)((int *)p + 2);
763 stbiw__sbm(*arr) = m;
764 }
765 return *arr;
766}
767
768static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)
769{
770 while (*bitcount >= 8) {
771 stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer));
772 *bitbuffer >>= 8;
773 *bitcount -= 8;
774 }
775 return data;
776}
777
778static int stbiw__zlib_bitrev(int code, int codebits)
779{
780 int res = 0;
781 while (codebits--) {
782 res = (res << 1) | (code & 1);
783 code >>= 1;
784 }
785 return res;
786}
787
788static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit)
789{
790 int i;
791 for (i = 0; i < limit && i < 258; ++i)
792 if (a[i] != b[i]) break;
793 return i;
794}
795
796static unsigned int stbiw__zhash(unsigned char *data)
797{
798 stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16);
799 hash ^= hash << 3;
800 hash += hash >> 5;
801 hash ^= hash << 4;
802 hash += hash >> 17;
803 hash ^= hash << 25;
804 hash += hash >> 6;
805 return hash;
806}
807
808#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount))
809#define stbiw__zlib_add(code,codebits) \
810 (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush())
811#define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c)
812// default huffman tables
813#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8)
814#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9)
815#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7)
816#define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8)
817#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))
818#define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n))
819
820#define stbiw__ZHASH 16384
821
822#endif // STBIW_ZLIB_COMPRESS
823
824unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)
825{
826#ifdef STBIW_ZLIB_COMPRESS
827 // user provided a zlib compress implementation, use that
828 return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality);
829#else // use builtin
830 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 };
831 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 };
832 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 };
833 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 };
834 unsigned int bitbuf = 0;
835 int i, j, bitcount = 0;
836 unsigned char *out = NULL;
837 unsigned char ***hash_table = (unsigned char***)STBIW_MALLOC(stbiw__ZHASH * sizeof(char**));
838 if (hash_table == NULL)
839 return NULL;
840 if (quality < 5) quality = 5;
841
842 stbiw__sbpush(out, 0x78); // DEFLATE 32K window
843 stbiw__sbpush(out, 0x5e); // FLEVEL = 1
844 stbiw__zlib_add(1, 1); // BFINAL = 1
845 stbiw__zlib_add(1, 2); // BTYPE = 1 -- fixed huffman
846
847 for (i = 0; i < stbiw__ZHASH; ++i)
848 hash_table[i] = NULL;
849
850 i = 0;
851 while (i < data_len - 3) {
852 // hash next 3 bytes of data to be compressed
853 int h = stbiw__zhash(data + i)&(stbiw__ZHASH - 1), best = 3;
854 unsigned char *bestloc = 0;
855 unsigned char **hlist = hash_table[h];
856 int n = stbiw__sbcount(hlist);
857 for (j = 0; j < n; ++j) {
858 if (hlist[j] - data > i - 32768) { // if entry lies within window
859 int d = stbiw__zlib_countm(hlist[j], data + i, data_len - i);
860 if (d >= best) best = d, bestloc = hlist[j];
861 }
862 }
863 // when hash table entry is too long, delete half the entries
864 if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2 * quality) {
865 STBIW_MEMMOVE(hash_table[h], hash_table[h] + quality, sizeof(hash_table[h][0])*quality);
866 stbiw__sbn(hash_table[h]) = quality;
867 }
868 stbiw__sbpush(hash_table[h], data + i);
869
870 if (bestloc) {
871 // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal
872 h = stbiw__zhash(data + i + 1)&(stbiw__ZHASH - 1);
873 hlist = hash_table[h];
874 n = stbiw__sbcount(hlist);
875 for (j = 0; j < n; ++j) {
876 if (hlist[j] - data > i - 32767) {
877 int e = stbiw__zlib_countm(hlist[j], data + i + 1, data_len - i - 1);
878 if (e > best) { // if next match is better, bail on current match
879 bestloc = NULL;
880 break;
881 }
882 }
883 }
884 }
885
886 if (bestloc) {
887 int d = (int)(data + i - bestloc); // distance back
888 STBIW_ASSERT(d <= 32767 && best <= 258);
889 for (j = 0; best > lengthc[j + 1] - 1; ++j);
890 stbiw__zlib_huff(j + 257);
891 if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]);
892 for (j = 0; d > distc[j + 1] - 1; ++j);
893 stbiw__zlib_add(stbiw__zlib_bitrev(j, 5), 5);
894 if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]);
895 i += best;
896 }
897 else {
898 stbiw__zlib_huffb(data[i]);
899 ++i;
900 }
901 }
902 // write out final bytes
903 for (; i < data_len; ++i)
904 stbiw__zlib_huffb(data[i]);
905 stbiw__zlib_huff(256); // end of block
906 // pad with 0 bits to byte boundary
907 while (bitcount)
908 stbiw__zlib_add(0, 1);
909
910 for (i = 0; i < stbiw__ZHASH; ++i)
911 (void) stbiw__sbfree(hash_table[i]);
912 STBIW_FREE(hash_table);
913
914 {
915 // compute adler32 on input
916 unsigned int s1 = 1, s2 = 0;
917 int blocklen = (int)(data_len % 5552);
918 j = 0;
919 while (j < data_len) {
920 for (i = 0; i < blocklen; ++i) s1 += data[j + i], s2 += s1;
921 s1 %= 65521, s2 %= 65521;
922 j += blocklen;
923 blocklen = 5552;
924 }
925 stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8));
926 stbiw__sbpush(out, STBIW_UCHAR(s2));
927 stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8));
928 stbiw__sbpush(out, STBIW_UCHAR(s1));
929 }
930 *out_len = stbiw__sbn(out);
931 // make returned pointer freeable
932 STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len);
933 return (unsigned char *)stbiw__sbraw(out);
934#endif // STBIW_ZLIB_COMPRESS
935}
936
937static unsigned int stbiw__crc32(unsigned char *buffer, int len)
938{
939 static unsigned int crc_table[256] =
940 {
941 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
942 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
943 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
944 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
945 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
946 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
947 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
948 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
949 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
950 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
951 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
952 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
953 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
954 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
955 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
956 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
957 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
958 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
959 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
960 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
961 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
962 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
963 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
964 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
965 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
966 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
967 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
968 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
969 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
970 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
971 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
972 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
973 };
974
975 unsigned int crc = ~0u;
976 int i;
977 for (i = 0; i < len; ++i)
978 crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];
979 return ~crc;
980}
981
982#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)
983#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));
984#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3])
985
986static void stbiw__wpcrc(unsigned char **data, int len)
987{
988 unsigned int crc = stbiw__crc32(*data - len - 4, len + 4);
989 stbiw__wp32(*data, crc);
990}
991
992static unsigned char stbiw__paeth(int a, int b, int c)
993{
994 int p = a + b - c, pa = abs(p - a), pb = abs(p - b), pc = abs(p - c);
995 if (pa <= pb && pa <= pc) return STBIW_UCHAR(a);
996 if (pb <= pc) return STBIW_UCHAR(b);
997 return STBIW_UCHAR(c);
998}
999
1000// @OPTIMIZE: provide an option that always forces left-predict or paeth predict
1001static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type, signed char *line_buffer)
1002{
1003 static int mapping[] = { 0,1,2,3,4 };
1004 static int firstmap[] = { 0,1,0,5,6 };
1005 int *mymap = (y != 0) ? mapping : firstmap;
1006 int i;
1007 int type = mymap[filter_type];
1008 unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height - 1 - y : y);
1009 int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes;
1010 for (i = 0; i < n; ++i) {
1011 switch (type) {
1012 case 0: line_buffer[i] = z[i]; break;
1013 case 1: line_buffer[i] = z[i]; break;
1014 case 2: line_buffer[i] = z[i] - z[i - signed_stride]; break;
1015 case 3: line_buffer[i] = z[i] - (z[i - signed_stride] >> 1); break;
1016 case 4: line_buffer[i] = (signed char)(z[i] - stbiw__paeth(0, z[i - signed_stride], 0)); break;
1017 case 5: line_buffer[i] = z[i]; break;
1018 case 6: line_buffer[i] = z[i]; break;
1019 }
1020 }
1021 for (i = n; i < width*n; ++i) {
1022 switch (type) {
1023 case 0: line_buffer[i] = z[i]; break;
1024 case 1: line_buffer[i] = z[i] - z[i - n]; break;
1025 case 2: line_buffer[i] = z[i] - z[i - signed_stride]; break;
1026 case 3: line_buffer[i] = z[i] - ((z[i - n] + z[i - signed_stride]) >> 1); break;
1027 case 4: line_buffer[i] = z[i] - stbiw__paeth(z[i - n], z[i - signed_stride], z[i - signed_stride - n]); break;
1028 case 5: line_buffer[i] = z[i] - (z[i - n] >> 1); break;
1029 case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i - n], 0, 0); break;
1030 }
1031 }
1032}
1033
1034unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
1035{
1036 int force_filter = stbi_write_force_png_filter;
1037 int ctype[5] = { -1, 0, 4, 2, 6 };
1038 unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
1039 unsigned char *out, *o, *filt, *zlib;
1040 signed char *line_buffer;
1041 int j, zlen;
1042
1043 if (stride_bytes == 0)
1044 stride_bytes = x * n;
1045
1046 if (force_filter >= 5) {
1047 force_filter = -1;
1048 }
1049
1050 filt = (unsigned char *)STBIW_MALLOC((x*n + 1) * y); if (!filt) return 0;
1051 line_buffer = (signed char *)STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; }
1052 for (j = 0; j < y; ++j) {
1053 int filter_type;
1054 if (force_filter > -1) {
1055 filter_type = force_filter;
1056 stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, force_filter, line_buffer);
1057 }
1058 else { // Estimate the best filter by running through all of them:
1059 int best_filter = 0, best_filter_val = 0x7fffffff, est, i;
1060 for (filter_type = 0; filter_type < 5; filter_type++) {
1061 stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, filter_type, line_buffer);
1062
1063 // Estimate the entropy of the line using this filter; the less, the better.
1064 est = 0;
1065 for (i = 0; i < x*n; ++i) {
1066 est += abs((signed char)line_buffer[i]);
1067 }
1068 if (est < best_filter_val) {
1069 best_filter_val = est;
1070 best_filter = filter_type;
1071 }
1072 }
1073 if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it
1074 stbiw__encode_png_line(pixels, stride_bytes, x, y, j, n, best_filter, line_buffer);
1075 filter_type = best_filter;
1076 }
1077 }
1078 // when we get here, filter_type contains the filter type, and line_buffer contains the data
1079 filt[j*(x*n + 1)] = (unsigned char)filter_type;
1080 STBIW_MEMMOVE(filt + j*(x*n + 1) + 1, line_buffer, x*n);
1081 }
1082 STBIW_FREE(line_buffer);
1083 zlib = stbi_zlib_compress(filt, y*(x*n + 1), &zlen, stbi_write_png_compression_level);
1084 STBIW_FREE(filt);
1085 if (!zlib) return 0;
1086
1087 // each tag requires 12 bytes of overhead
1088 out = (unsigned char *)STBIW_MALLOC(8 + 12 + 13 + 12 + zlen + 12);
1089 if (!out) return 0;
1090 *out_len = 8 + 12 + 13 + 12 + zlen + 12;
1091
1092 o = out;
1093 STBIW_MEMMOVE(o, sig, 8); o += 8;
1094 stbiw__wp32(o, 13); // header length
1095 stbiw__wptag(o, "IHDR");
1096 stbiw__wp32(o, x);
1097 stbiw__wp32(o, y);
1098 *o++ = 8;
1099 *o++ = STBIW_UCHAR(ctype[n]);
1100 *o++ = 0;
1101 *o++ = 0;
1102 *o++ = 0;
1103 stbiw__wpcrc(&o, 13);
1104
1105 stbiw__wp32(o, zlen);
1106 stbiw__wptag(o, "IDAT");
1107 STBIW_MEMMOVE(o, zlib, zlen);
1108 o += zlen;
1109 STBIW_FREE(zlib);
1110 stbiw__wpcrc(&o, zlen);
1111
1112 stbiw__wp32(o, 0);
1113 stbiw__wptag(o, "IEND");
1114 stbiw__wpcrc(&o, 0);
1115
1116 STBIW_ASSERT(o == out + *out_len);
1117
1118 return out;
1119}
1120
1121#ifndef STBI_WRITE_NO_STDIO
1122STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
1123{
1124 FILE *f;
1125 int len;
1126 unsigned char *png = stbi_write_png_to_mem((unsigned char *)data, stride_bytes, x, y, comp, &len);
1127 if (png == NULL) return 0;
1128#ifdef STBI_MSC_SECURE_CRT
1129 if (fopen_s(&f, filename, "wb"))
1130 f = NULL;
1131#else
1132 f = fopen(filename, "wb");
1133#endif
1134 if (!f) { STBIW_FREE(png); return 0; }
1135 fwrite(png, 1, len, f);
1136 fclose(f);
1137 STBIW_FREE(png);
1138 return 1;
1139}
1140#endif
1141
1142STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes)
1143{
1144 int len;
1145 unsigned char *png = stbi_write_png_to_mem((unsigned char *)data, stride_bytes, x, y, comp, &len);
1146 if (png == NULL) return 0;
1147 func(context, png, len);
1148 STBIW_FREE(png);
1149 return 1;
1150}
1151
1152
1153/* ***************************************************************************
1154*
1155* JPEG writer
1156*
1157* This is based on Jon Olick's jo_jpeg.cpp:
1158* public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html
1159*/
1160
1161static const unsigned char stbiw__jpg_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18,
116224,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 };
1163
1164static void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) {
1165 int bitBuf = *bitBufP, bitCnt = *bitCntP;
1166 bitCnt += bs[1];
1167 bitBuf |= bs[0] << (24 - bitCnt);
1168 while (bitCnt >= 8) {
1169 unsigned char c = (bitBuf >> 16) & 255;
1170 stbiw__putc(s, c);
1171 if (c == 255) {
1172 stbiw__putc(s, 0);
1173 }
1174 bitBuf <<= 8;
1175 bitCnt -= 8;
1176 }
1177 *bitBufP = bitBuf;
1178 *bitCntP = bitCnt;
1179}
1180
1181static void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) {
1182 float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p;
1183 float z1, z2, z3, z4, z5, z11, z13;
1184
1185 float tmp0 = d0 + d7;
1186 float tmp7 = d0 - d7;
1187 float tmp1 = d1 + d6;
1188 float tmp6 = d1 - d6;
1189 float tmp2 = d2 + d5;
1190 float tmp5 = d2 - d5;
1191 float tmp3 = d3 + d4;
1192 float tmp4 = d3 - d4;
1193
1194 // Even part
1195 float tmp10 = tmp0 + tmp3; // phase 2
1196 float tmp13 = tmp0 - tmp3;
1197 float tmp11 = tmp1 + tmp2;
1198 float tmp12 = tmp1 - tmp2;
1199
1200 d0 = tmp10 + tmp11; // phase 3
1201 d4 = tmp10 - tmp11;
1202
1203 z1 = (tmp12 + tmp13) * 0.707106781f; // c4
1204 d2 = tmp13 + z1; // phase 5
1205 d6 = tmp13 - z1;
1206
1207 // Odd part
1208 tmp10 = tmp4 + tmp5; // phase 2
1209 tmp11 = tmp5 + tmp6;
1210 tmp12 = tmp6 + tmp7;
1211
1212 // The rotator is modified from fig 4-8 to avoid extra negations.
1213 z5 = (tmp10 - tmp12) * 0.382683433f; // c6
1214 z2 = tmp10 * 0.541196100f + z5; // c2-c6
1215 z4 = tmp12 * 1.306562965f + z5; // c2+c6
1216 z3 = tmp11 * 0.707106781f; // c4
1217
1218 z11 = tmp7 + z3; // phase 5
1219 z13 = tmp7 - z3;
1220
1221 *d5p = z13 + z2; // phase 6
1222 *d3p = z13 - z2;
1223 *d1p = z11 + z4;
1224 *d7p = z11 - z4;
1225
1226 *d0p = d0; *d2p = d2; *d4p = d4; *d6p = d6;
1227}
1228
1229static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) {
1230 int tmp1 = val < 0 ? -val : val;
1231 val = val < 0 ? val - 1 : val;
1232 bits[1] = 1;
1233 while (tmp1 >>= 1) {
1234 ++bits[1];
1235 }
1236 bits[0] = val & ((1 << bits[1]) - 1);
1237}
1238
1239static int stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt, float *CDU, float *fdtbl, int DC, const unsigned short HTDC[256][2], const unsigned short HTAC[256][2]) {
1240 const unsigned short EOB[2] = { HTAC[0x00][0], HTAC[0x00][1] };
1241 const unsigned short M16zeroes[2] = { HTAC[0xF0][0], HTAC[0xF0][1] };
1242 int dataOff, i, diff, end0pos;
1243 int DU[64];
1244
1245 // DCT rows
1246 for (dataOff = 0; dataOff<64; dataOff += 8) {
1247 stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff + 1], &CDU[dataOff + 2], &CDU[dataOff + 3], &CDU[dataOff + 4], &CDU[dataOff + 5], &CDU[dataOff + 6], &CDU[dataOff + 7]);
1248 }
1249 // DCT columns
1250 for (dataOff = 0; dataOff<8; ++dataOff) {
1251 stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff + 8], &CDU[dataOff + 16], &CDU[dataOff + 24], &CDU[dataOff + 32], &CDU[dataOff + 40], &CDU[dataOff + 48], &CDU[dataOff + 56]);
1252 }
1253 // Quantize/descale/zigzag the coefficients
1254 for (i = 0; i<64; ++i) {
1255 float v = CDU[i] * fdtbl[i];
1256 // DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f));
1257 // ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway?
1258 DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? v - 0.5f : v + 0.5f);
1259 }
1260
1261 // Encode DC
1262 diff = DU[0] - DC;
1263 if (diff == 0) {
1264 stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[0]);
1265 }
1266 else {
1267 unsigned short bits[2];
1268 stbiw__jpg_calcBits(diff, bits);
1269 stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[bits[1]]);
1270 stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits);
1271 }
1272 // Encode ACs
1273 end0pos = 63;
1274 for (; (end0pos>0) && (DU[end0pos] == 0); --end0pos) {
1275 }
1276 // end0pos = first element in reverse order !=0
1277 if (end0pos == 0) {
1278 stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB);
1279 return DU[0];
1280 }
1281 for (i = 1; i <= end0pos; ++i) {
1282 int startpos = i;
1283 int nrzeroes;
1284 unsigned short bits[2];
1285 for (; DU[i] == 0 && i <= end0pos; ++i) {
1286 }
1287 nrzeroes = i - startpos;
1288 if (nrzeroes >= 16) {
1289 int lng = nrzeroes >> 4;
1290 int nrmarker;
1291 for (nrmarker = 1; nrmarker <= lng; ++nrmarker)
1292 stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes);
1293 nrzeroes &= 15;
1294 }
1295 stbiw__jpg_calcBits(DU[i], bits);
1296 stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes << 4) + bits[1]]);
1297 stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits);
1298 }
1299 if (end0pos != 63) {
1300 stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB);
1301 }
1302 return DU[0];
1303}
1304
1305static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) {
1306 // Constants that don't pollute global namespace
1307 static const unsigned char std_dc_luminance_nrcodes[] = { 0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0 };
1308 static const unsigned char std_dc_luminance_values[] = { 0,1,2,3,4,5,6,7,8,9,10,11 };
1309 static const unsigned char std_ac_luminance_nrcodes[] = { 0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d };
1310 static const unsigned char std_ac_luminance_values[] = {
1311 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,
1312 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,
1313 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,
1314 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,
1315 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,
1316 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,
1317 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa
1318 };
1319 static const unsigned char std_dc_chrominance_nrcodes[] = { 0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0 };
1320 static const unsigned char std_dc_chrominance_values[] = { 0,1,2,3,4,5,6,7,8,9,10,11 };
1321 static const unsigned char std_ac_chrominance_nrcodes[] = { 0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77 };
1322 static const unsigned char std_ac_chrominance_values[] = {
1323 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,
1324 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,
1325 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,
1326 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87,
1327 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,
1328 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,
1329 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa
1330 };
1331 // Huffman tables
1332 static const unsigned short YDC_HT[256][2] = { { 0,2 },{ 2,3 },{ 3,3 },{ 4,3 },{ 5,3 },{ 6,3 },{ 14,4 },{ 30,5 },{ 62,6 },{ 126,7 },{ 254,8 },{ 510,9 } };
1333 static const unsigned short UVDC_HT[256][2] = { { 0,2 },{ 1,2 },{ 2,2 },{ 6,3 },{ 14,4 },{ 30,5 },{ 62,6 },{ 126,7 },{ 254,8 },{ 510,9 },{ 1022,10 },{ 2046,11 } };
1334 static const unsigned short YAC_HT[256][2] = {
1335 { 10,4 },{ 0,2 },{ 1,2 },{ 4,3 },{ 11,4 },{ 26,5 },{ 120,7 },{ 248,8 },{ 1014,10 },{ 65410,16 },{ 65411,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },
1336 { 12,4 },{ 27,5 },{ 121,7 },{ 502,9 },{ 2038,11 },{ 65412,16 },{ 65413,16 },{ 65414,16 },{ 65415,16 },{ 65416,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },
1337 { 28,5 },{ 249,8 },{ 1015,10 },{ 4084,12 },{ 65417,16 },{ 65418,16 },{ 65419,16 },{ 65420,16 },{ 65421,16 },{ 65422,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },
1338 { 58,6 },{ 503,9 },{ 4085,12 },{ 65423,16 },{ 65424,16 },{ 65425,16 },{ 65426,16 },{ 65427,16 },{ 65428,16 },{ 65429,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },
1339 { 59,6 },{ 1016,10 },{ 65430,16 },{ 65431,16 },{ 65432,16 },{ 65433,16 },{ 65434,16 },{ 65435,16 },{ 65436,16 },{ 65437,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },
1340 { 122,7 },{ 2039,11 },{ 65438,16 },{ 65439,16 },{ 65440,16 },{ 65441,16 },{ 65442,16 },{ 65443,16 },{ 65444,16 },{ 65445,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },
1341 { 123,7 },{ 4086,12 },{ 65446,16 },{ 65447,16 },{ 65448,16 },{ 65449,16 },{ 65450,16 },{ 65451,16 },{ 65452,16 },{ 65453,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },
1342 { 250,8 },{ 4087,12 },{ 65454,16 },{ 65455,16 },{ 65456,16 },{ 65457,16 },{ 65458,16 },{ 65459,16 },{ 65460,16 },{ 65461,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },
1343 { 504,9 },{ 32704,15 },{ 65462,16 },{ 65463,16 },{ 65464,16 },{ 65465,16 },{ 65466,16 },{ 65467,16 },{ 65468,16 },{ 65469,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },
1344 { 505,9 },{ 65470,16 },{ 65471,16 },{ 65472,16 },{ 65473,16 },{ 65474,16 },{ 65475,16 },{ 65476,16 },{ 65477,16 },{ 65478,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },
1345 { 506,9 },{ 65479,16 },{ 65480,16 },{ 65481,16 },{ 65482,16 },{ 65483,16 },{ 65484,16 },{ 65485,16 },{ 65486,16 },{ 65487,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },
1346 { 1017,10 },{ 65488,16 },{ 65489,16 },{ 65490,16 },{ 65491,16 },{ 65492,16 },{ 65493,16 },{ 65494,16 },{ 65495,16 },{ 65496,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },
1347 { 1018,10 },{ 65497,16 },{ 65498,16 },{ 65499,16 },{ 65500,16 },{ 65501,16 },{ 65502,16 },{ 65503,16 },{ 65504,16 },{ 65505,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },
1348 { 2040,11 },{ 65506,16 },{ 65507,16 },{ 65508,16 },{ 65509,16 },{ 65510,16 },{ 65511,16 },{ 65512,16 },{ 65513,16 },{ 65514,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },
1349 { 65515,16 },{ 65516,16 },{ 65517,16 },{ 65518,16 },{ 65519,16 },{ 65520,16 },{ 65521,16 },{ 65522,16 },{ 65523,16 },{ 65524,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },
1350 { 2041,11 },{ 65525,16 },{ 65526,16 },{ 65527,16 },{ 65528,16 },{ 65529,16 },{ 65530,16 },{ 65531,16 },{ 65532,16 },{ 65533,16 },{ 65534,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 }
1351 };
1352 static const unsigned short UVAC_HT[256][2] = {
1353 { 0,2 },{ 1,2 },{ 4,3 },{ 10,4 },{ 24,5 },{ 25,5 },{ 56,6 },{ 120,7 },{ 500,9 },{ 1014,10 },{ 4084,12 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },
1354 { 11,4 },{ 57,6 },{ 246,8 },{ 501,9 },{ 2038,11 },{ 4085,12 },{ 65416,16 },{ 65417,16 },{ 65418,16 },{ 65419,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },
1355 { 26,5 },{ 247,8 },{ 1015,10 },{ 4086,12 },{ 32706,15 },{ 65420,16 },{ 65421,16 },{ 65422,16 },{ 65423,16 },{ 65424,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },
1356 { 27,5 },{ 248,8 },{ 1016,10 },{ 4087,12 },{ 65425,16 },{ 65426,16 },{ 65427,16 },{ 65428,16 },{ 65429,16 },{ 65430,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },
1357 { 58,6 },{ 502,9 },{ 65431,16 },{ 65432,16 },{ 65433,16 },{ 65434,16 },{ 65435,16 },{ 65436,16 },{ 65437,16 },{ 65438,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },
1358 { 59,6 },{ 1017,10 },{ 65439,16 },{ 65440,16 },{ 65441,16 },{ 65442,16 },{ 65443,16 },{ 65444,16 },{ 65445,16 },{ 65446,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },
1359 { 121,7 },{ 2039,11 },{ 65447,16 },{ 65448,16 },{ 65449,16 },{ 65450,16 },{ 65451,16 },{ 65452,16 },{ 65453,16 },{ 65454,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },
1360 { 122,7 },{ 2040,11 },{ 65455,16 },{ 65456,16 },{ 65457,16 },{ 65458,16 },{ 65459,16 },{ 65460,16 },{ 65461,16 },{ 65462,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },
1361 { 249,8 },{ 65463,16 },{ 65464,16 },{ 65465,16 },{ 65466,16 },{ 65467,16 },{ 65468,16 },{ 65469,16 },{ 65470,16 },{ 65471,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },
1362 { 503,9 },{ 65472,16 },{ 65473,16 },{ 65474,16 },{ 65475,16 },{ 65476,16 },{ 65477,16 },{ 65478,16 },{ 65479,16 },{ 65480,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },
1363 { 504,9 },{ 65481,16 },{ 65482,16 },{ 65483,16 },{ 65484,16 },{ 65485,16 },{ 65486,16 },{ 65487,16 },{ 65488,16 },{ 65489,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },
1364 { 505,9 },{ 65490,16 },{ 65491,16 },{ 65492,16 },{ 65493,16 },{ 65494,16 },{ 65495,16 },{ 65496,16 },{ 65497,16 },{ 65498,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },
1365 { 506,9 },{ 65499,16 },{ 65500,16 },{ 65501,16 },{ 65502,16 },{ 65503,16 },{ 65504,16 },{ 65505,16 },{ 65506,16 },{ 65507,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },
1366 { 2041,11 },{ 65508,16 },{ 65509,16 },{ 65510,16 },{ 65511,16 },{ 65512,16 },{ 65513,16 },{ 65514,16 },{ 65515,16 },{ 65516,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },
1367 { 16352,14 },{ 65517,16 },{ 65518,16 },{ 65519,16 },{ 65520,16 },{ 65521,16 },{ 65522,16 },{ 65523,16 },{ 65524,16 },{ 65525,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },
1368 { 1018,10 },{ 32707,15 },{ 65526,16 },{ 65527,16 },{ 65528,16 },{ 65529,16 },{ 65530,16 },{ 65531,16 },{ 65532,16 },{ 65533,16 },{ 65534,16 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 },{ 0,0 }
1369 };
1370 static const int YQT[] = { 16,11,10,16,24,40,51,61,12,12,14,19,26,58,60,55,14,13,16,24,40,57,69,56,14,17,22,29,51,87,80,62,18,22,
1371 37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99 };
1372 static const int UVQT[] = { 17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99,
1373 99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99 };
1374 static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f,
1375 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f };
1376
1377 int row, col, i, k;
1378 float fdtbl_Y[64], fdtbl_UV[64];
1379 unsigned char YTable[64], UVTable[64];
1380
1381 if (!data || !width || !height || comp > 4 || comp < 1) {
1382 return 0;
1383 }
1384
1385 quality = quality ? quality : 90;
1386 quality = quality < 1 ? 1 : quality > 100 ? 100 : quality;
1387 quality = quality < 50 ? 5000 / quality : 200 - quality * 2;
1388
1389 for (i = 0; i < 64; ++i) {
1390 int uvti, yti = (YQT[i] * quality + 50) / 100;
1391 YTable[stbiw__jpg_ZigZag[i]] = (unsigned char)(yti < 1 ? 1 : yti > 255 ? 255 : yti);
1392 uvti = (UVQT[i] * quality + 50) / 100;
1393 UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char)(uvti < 1 ? 1 : uvti > 255 ? 255 : uvti);
1394 }
1395
1396 for (row = 0, k = 0; row < 8; ++row) {
1397 for (col = 0; col < 8; ++col, ++k) {
1398 fdtbl_Y[k] = 1 / (YTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]);
1399 fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]);
1400 }
1401 }
1402
1403 // Write Headers
1404 {
1405 static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 };
1406 static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 };
1407 const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height >> 8),STBIW_UCHAR(height),(unsigned char)(width >> 8),STBIW_UCHAR(width),
1408 3,1,0x11,0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 };
1409 s->func(s->context, (void*)head0, sizeof(head0));
1410 s->func(s->context, (void*)YTable, sizeof(YTable));
1411 stbiw__putc(s, 1);
1412 s->func(s->context, UVTable, sizeof(UVTable));
1413 s->func(s->context, (void*)head1, sizeof(head1));
1414 s->func(s->context, (void*)(std_dc_luminance_nrcodes + 1), sizeof(std_dc_luminance_nrcodes) - 1);
1415 s->func(s->context, (void*)std_dc_luminance_values, sizeof(std_dc_luminance_values));
1416 stbiw__putc(s, 0x10); // HTYACinfo
1417 s->func(s->context, (void*)(std_ac_luminance_nrcodes + 1), sizeof(std_ac_luminance_nrcodes) - 1);
1418 s->func(s->context, (void*)std_ac_luminance_values, sizeof(std_ac_luminance_values));
1419 stbiw__putc(s, 1); // HTUDCinfo
1420 s->func(s->context, (void*)(std_dc_chrominance_nrcodes + 1), sizeof(std_dc_chrominance_nrcodes) - 1);
1421 s->func(s->context, (void*)std_dc_chrominance_values, sizeof(std_dc_chrominance_values));
1422 stbiw__putc(s, 0x11); // HTUACinfo
1423 s->func(s->context, (void*)(std_ac_chrominance_nrcodes + 1), sizeof(std_ac_chrominance_nrcodes) - 1);
1424 s->func(s->context, (void*)std_ac_chrominance_values, sizeof(std_ac_chrominance_values));
1425 s->func(s->context, (void*)head2, sizeof(head2));
1426 }
1427
1428 // Encode 8x8 macroblocks
1429 {
1430 static const unsigned short fillBits[] = { 0x7F, 7 };
1431 const unsigned char *imageData = (const unsigned char *)data;
1432 int DCY = 0, DCU = 0, DCV = 0;
1433 int bitBuf = 0, bitCnt = 0;
1434 // comp == 2 is grey+alpha (alpha is ignored)
1435 int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0;
1436 int x, y, pos;
1437 for (y = 0; y < height; y += 8) {
1438 for (x = 0; x < width; x += 8) {
1439 float YDU[64], UDU[64], VDU[64];
1440 for (row = y, pos = 0; row < y + 8; ++row) {
1441 for (col = x; col < x + 8; ++col, ++pos) {
1442 int p = (stbi__flip_vertically_on_write ? height - 1 - row : row)*width*comp + col*comp;
1443 float r, g, b;
1444 if (row >= height) {
1445 p -= width*comp*(row + 1 - height);
1446 }
1447 if (col >= width) {
1448 p -= comp*(col + 1 - width);
1449 }
1450
1451 r = imageData[p + 0];
1452 g = imageData[p + ofsG];
1453 b = imageData[p + ofsB];
1454 YDU[pos] = +0.29900f*r + 0.58700f*g + 0.11400f*b - 128;
1455 UDU[pos] = -0.16874f*r - 0.33126f*g + 0.50000f*b;
1456 VDU[pos] = +0.50000f*r - 0.41869f*g - 0.08131f*b;
1457 }
1458 }
1459
1460 DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT);
1461 DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
1462 DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);
1463 }
1464 }
1465
1466 // Do the bit alignment of the EOI marker
1467 stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits);
1468 }
1469
1470 // EOI
1471 stbiw__putc(s, 0xFF);
1472 stbiw__putc(s, 0xD9);
1473
1474 return 1;
1475}
1476
1477STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality)
1478{
1479 stbi__write_context s;
1480 stbi__start_write_callbacks(&s, func, context);
1481 return stbi_write_jpg_core(&s, x, y, comp, (void *)data, quality);
1482}
1483
1484
1485#ifndef STBI_WRITE_NO_STDIO
1486STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality)
1487{
1488 stbi__write_context s;
1489 if (stbi__start_write_file(&s, filename)) {
1490 int r = stbi_write_jpg_core(&s, x, y, comp, data, quality);
1491 stbi__end_write_file(&s);
1492 return r;
1493 }
1494 else
1495 return 0;
1496}
1497#endif
1498
1499#endif // STB_IMAGE_WRITE_IMPLEMENTATION
1500
1501/* Revision history
15021.09 (2018-02-11)
1503fix typo in zlib quality API, improve STB_I_W_STATIC in C++
15041.08 (2018-01-29)
1505add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter
15061.07 (2017-07-24)
1507doc fix
15081.06 (2017-07-23)
1509writing JPEG (using Jon Olick's code)
15101.05 ???
15111.04 (2017-03-03)
1512monochrome BMP expansion
15131.03 ???
15141.02 (2016-04-02)
1515avoid allocating large structures on the stack
15161.01 (2016-01-16)
1517STBIW_REALLOC_SIZED: support allocators with no realloc support
1518avoid race-condition in crc initialization
1519minor compile issues
15201.00 (2015-09-14)
1521installable file IO function
15220.99 (2015-09-13)
1523warning fixes; TGA rle support
15240.98 (2015-04-08)
1525added STBIW_MALLOC, STBIW_ASSERT etc
15260.97 (2015-01-18)
1527fixed HDR asserts, rewrote HDR rle logic
15280.96 (2015-01-17)
1529add HDR output
1530fix monochrome BMP
15310.95 (2014-08-17)
1532add monochrome TGA output
15330.94 (2014-05-31)
1534rename private functions to avoid conflicts with stb_image.h
15350.93 (2014-05-27)
1536warning fixes
15370.92 (2010-08-01)
1538casts to unsigned char to fix warnings
15390.91 (2010-07-17)
1540first public release
15410.90 first internal release
1542*/
1543
1544/*
1545------------------------------------------------------------------------------
1546This software is available under 2 licenses -- choose whichever you prefer.
1547------------------------------------------------------------------------------
1548ALTERNATIVE A - MIT License
1549Copyright (c) 2017 Sean Barrett
1550Permission is hereby granted, free of charge, to any person obtaining a copy of
1551this software and associated documentation files (the "Software"), to deal in
1552the Software without restriction, including without limitation the rights to
1553use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
1554of the Software, and to permit persons to whom the Software is furnished to do
1555so, subject to the following conditions:
1556The above copyright notice and this permission notice shall be included in all
1557copies or substantial portions of the Software.
1558THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1559IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1560FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1561AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1562LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1563OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1564SOFTWARE.
1565------------------------------------------------------------------------------
1566ALTERNATIVE B - Public Domain (www.unlicense.org)
1567This is free and unencumbered software released into the public domain.
1568Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
1569software, either in source code form or as a compiled binary, for any purpose,
1570commercial or non-commercial, and by any means.
1571In jurisdictions that recognize copyright laws, the author or authors of this
1572software dedicate any and all copyright interest in the software to the public
1573domain. We make this dedication for the benefit of the public at large and to
1574the detriment of our heirs and successors. We intend this dedication to be an
1575overt act of relinquishment in perpetuity of all present and future rights to
1576this software under copyright law.
1577THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1578IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1579FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1580AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
1581ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
1582WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1583------------------------------------------------------------------------------
1584*/
Note: See TracBrowser for help on using the repository browser.