1 /* stb_image_write - v1.15 - public domain - http://nothings.org/stb
2 writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015
3 no warranty implied; use at your own risk
7 #define STB_IMAGE_WRITE_IMPLEMENTATION
9 in the file that you want to have the implementation.
11 Will probably not work correctly with strict-aliasing optimizations.
15 This header file is a library for writing images to C stdio or a callback.
17 The PNG output is not optimal; it is 20-50% larger than the file
18 written by a decent optimizing implementation; though providing a custom
19 zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that.
20 This library is designed for source code compactness and simplicity,
21 not optimal image file size or run-time performance.
25 You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h.
26 You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace
28 You can #define STBIW_MEMMOVE() to replace memmove()
29 You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function
30 for PNG compression (instead of the builtin one), it must have the following signature:
31 unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality);
32 The returned data will be freed with STBIW_FREE() (free() by default),
33 so it must be heap allocated with STBIW_MALLOC() (malloc() by default),
37 If compiling for Windows and you wish to use Unicode filenames, compile
39 #define STBIW_WINDOWS_UTF8
40 and pass utf8-encoded filenames. Call stbiw_convert_wchar_to_utf8 to convert
41 Windows wchar_t filenames to utf8.
45 There are five functions, one for each image file format:
47 int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
48 int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
49 int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
50 int stbi_write_jpg(char const *filename, int w, int h, int comp, const void *data, int quality);
51 int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
53 void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically
55 There are also five equivalent functions that use an arbitrary write function. You are
56 expected to open/close your file-equivalent before and after calling these:
58 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);
59 int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
60 int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
61 int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
62 int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);
64 where the callback is:
65 void stbi_write_func(void *context, void *data, int size);
67 You can configure it with these global variables:
68 int stbi_write_tga_with_rle; // defaults to true; set to 0 to disable RLE
69 int stbi_write_png_compression_level; // defaults to 8; set to higher for more compression
70 int stbi_write_force_png_filter; // defaults to -1; set to 0..5 to force a filter mode
73 You can define STBI_WRITE_NO_STDIO to disable the file variant of these
74 functions, so the library will not use stdio.h at all. However, this will
75 also disable HDR writing, because it requires stdio for formatted output.
77 Each function returns 0 on failure and non-0 on success.
79 The functions create an image file defined by the parameters. The image
80 is a rectangle of pixels stored from left-to-right, top-to-bottom.
81 Each pixel contains 'comp' channels of data stored interleaved with 8-bits
82 per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is
83 monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall.
84 The *data pointer points to the first byte of the top-left-most pixel.
85 For PNG, "stride_in_bytes" is the distance in bytes from the first byte of
86 a row of pixels to the first byte of the next row of pixels.
88 PNG creates output files with the same number of components as the input.
89 The BMP format expands Y to RGB in the file format and does not
92 PNG supports writing rectangles of data even when the bytes storing rows of
93 data are not consecutive in memory (e.g. sub-rectangles of a larger image),
94 by supplying the stride between the beginning of adjacent rows. The other
95 formats do not. (Thus you cannot write a native-format BMP through the BMP
96 writer, both because it is in BGR order and because it may have padding
97 at the end of the line.)
99 PNG allows you to set the deflate compression level by setting the global
100 variable 'stbi_write_png_compression_level' (it defaults to 8).
102 HDR expects linear float data. Since the format is always 32-bit rgb(e)
103 data, alpha (if provided) is discarded, and for monochrome data it is
104 replicated across all three channels.
106 TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed
107 data, set the global variable 'stbi_write_tga_with_rle' to 0.
109 JPEG does ignore alpha channels in input data; quality is between 1 and 100.
110 Higher quality looks better but results in a bigger image.
111 JPEG baseline (no JPEG progressive).
116 Sean Barrett - PNG/BMP/TGA
117 Baldur Karlsson - HDR
118 Jean-Sebastien Guay - TGA monochrome
119 Tim Kelsey - misc enhancements
120 Alan Hickman - TGA RLE
121 Emmanuel Julien - initial file IO callback implementation
122 Jon Olick - original jo_jpeg.cpp code
123 Daniel Gibson - integrate JPEG, allow external zlib
124 Aarni Koskela - allow choosing PNG filter
146 See end of file for license information.
150 #ifndef INCLUDE_STB_IMAGE_WRITE_H
151 #define INCLUDE_STB_IMAGE_WRITE_H
155 // if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline'
157 #ifdef STB_IMAGE_WRITE_STATIC
158 #define STBIWDEF static
161 #define STBIWDEF extern "C"
163 #define STBIWDEF extern
168 #ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations
169 extern int stbi_write_tga_with_rle
;
170 extern int stbi_write_png_compression_level
;
171 extern int stbi_write_force_png_filter
;
174 #ifndef STBI_WRITE_NO_STDIO
175 STBIWDEF
int stbi_write_png(char const *filename
, int w
, int h
, int comp
, const void *data
, int stride_in_bytes
);
176 STBIWDEF
int stbi_write_bmp(char const *filename
, int w
, int h
, int comp
, const void *data
);
177 STBIWDEF
int stbi_write_tga(char const *filename
, int w
, int h
, int comp
, const void *data
);
178 STBIWDEF
int stbi_write_hdr(char const *filename
, int w
, int h
, int comp
, const float *data
);
179 STBIWDEF
int stbi_write_jpg(char const *filename
, int x
, int y
, int comp
, const void *data
, int quality
);
181 #ifdef STBI_WINDOWS_UTF8
182 STBIWDEF
int stbiw_convert_wchar_to_utf8(char *buffer
, size_t bufferlen
, const wchar_t* input
);
186 typedef void stbi_write_func(void *context
, void *data
, int size
);
188 STBIWDEF
int stbi_write_png_to_func(stbi_write_func
*func
, void *context
, int w
, int h
, int comp
, const void *data
, int stride_in_bytes
);
189 STBIWDEF
int stbi_write_bmp_to_func(stbi_write_func
*func
, void *context
, int w
, int h
, int comp
, const void *data
);
190 STBIWDEF
int stbi_write_tga_to_func(stbi_write_func
*func
, void *context
, int w
, int h
, int comp
, const void *data
);
191 STBIWDEF
int stbi_write_hdr_to_func(stbi_write_func
*func
, void *context
, int w
, int h
, int comp
, const float *data
);
192 STBIWDEF
int stbi_write_jpg_to_func(stbi_write_func
*func
, void *context
, int x
, int y
, int comp
, const void *data
, int quality
);
194 STBIWDEF
void stbi_flip_vertically_on_write(int flip_boolean
);
196 #endif//INCLUDE_STB_IMAGE_WRITE_H
198 #ifdef STB_IMAGE_WRITE_IMPLEMENTATION
201 #ifndef _CRT_SECURE_NO_WARNINGS
202 #define _CRT_SECURE_NO_WARNINGS
204 #ifndef _CRT_NONSTDC_NO_DEPRECATE
205 #define _CRT_NONSTDC_NO_DEPRECATE
209 #ifndef STBI_WRITE_NO_STDIO
211 #endif // STBI_WRITE_NO_STDIO
218 #if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED))
220 #elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED)
223 #error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)."
227 #define STBIW_MALLOC(sz) malloc(sz)
228 #define STBIW_REALLOC(p,newsz) realloc(p,newsz)
229 #define STBIW_FREE(p) free(p)
232 #ifndef STBIW_REALLOC_SIZED
233 #define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz)
237 #ifndef STBIW_MEMMOVE
238 #define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz)
244 #define STBIW_ASSERT(x) assert(x)
247 #define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)
249 #ifdef STB_IMAGE_WRITE_STATIC
250 static int stbi_write_png_compression_level
= 8;
251 static int stbi_write_tga_with_rle
= 1;
252 static int stbi_write_force_png_filter
= -1;
254 int stbi_write_png_compression_level
= 8;
255 int stbi_write_tga_with_rle
= 1;
256 int stbi_write_force_png_filter
= -1;
259 static int stbi__flip_vertically_on_write
= 0;
261 STBIWDEF
void stbi_flip_vertically_on_write(int flag
)
263 stbi__flip_vertically_on_write
= flag
;
268 stbi_write_func
*func
;
270 unsigned char buffer
[64];
272 } stbi__write_context
;
274 // initialize a callback-based context
275 static void stbi__start_write_callbacks(stbi__write_context
*s
, stbi_write_func
*c
, void *context
)
278 s
->context
= context
;
281 #ifndef STBI_WRITE_NO_STDIO
283 static void stbi__stdio_write(void *context
, void *data
, int size
)
285 fwrite(data
,1,size
,(FILE*) context
);
288 #if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8)
290 #define STBIW_EXTERN extern "C"
292 #define STBIW_EXTERN extern
294 STBIW_EXTERN
__declspec(dllimport
) int __stdcall
MultiByteToWideChar(unsigned int cp
, unsigned long flags
, const char *str
, int cbmb
, wchar_t *widestr
, int cchwide
);
295 STBIW_EXTERN
__declspec(dllimport
) int __stdcall
WideCharToMultiByte(unsigned int cp
, unsigned long flags
, const wchar_t *widestr
, int cchwide
, char *str
, int cbmb
, const char *defchar
, int *used_default
);
297 STBIWDEF
int stbiw_convert_wchar_to_utf8(char *buffer
, size_t bufferlen
, const wchar_t* input
)
299 return WideCharToMultiByte(65001 /* UTF8 */, 0, input
, -1, buffer
, (int) bufferlen
, NULL
, NULL
);
303 static FILE *stbiw__fopen(char const *filename
, char const *mode
)
306 #if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8)
308 wchar_t wFilename
[1024];
309 if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename
, -1, wFilename
, sizeof(wFilename
)))
312 if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode
, -1, wMode
, sizeof(wMode
)))
316 if (0 != _wfopen_s(&f
, wFilename
, wMode
))
319 f
= _wfopen(wFilename
, wMode
);
322 #elif defined(_MSC_VER) && _MSC_VER >= 1400
323 if (0 != fopen_s(&f
, filename
, mode
))
326 f
= fopen(filename
, mode
);
331 static int stbi__start_write_file(stbi__write_context
*s
, const char *filename
)
333 FILE *f
= stbiw__fopen(filename
, "wb");
334 stbi__start_write_callbacks(s
, stbi__stdio_write
, (void *) f
);
338 static void stbi__end_write_file(stbi__write_context
*s
)
340 fclose((FILE *)s
->context
);
343 #endif // !STBI_WRITE_NO_STDIO
345 typedef unsigned int stbiw_uint32
;
346 typedef int stb_image_write_test
[sizeof(stbiw_uint32
)==4 ? 1 : -1];
348 static void stbiw__writefv(stbi__write_context
*s
, const char *fmt
, va_list v
)
353 case '1': { unsigned char x
= STBIW_UCHAR(va_arg(v
, int));
354 s
->func(s
->context
,&x
,1);
356 case '2': { int x
= va_arg(v
,int);
358 b
[0] = STBIW_UCHAR(x
);
359 b
[1] = STBIW_UCHAR(x
>>8);
360 s
->func(s
->context
,b
,2);
362 case '4': { stbiw_uint32 x
= va_arg(v
,int);
365 b
[1]=STBIW_UCHAR(x
>>8);
366 b
[2]=STBIW_UCHAR(x
>>16);
367 b
[3]=STBIW_UCHAR(x
>>24);
368 s
->func(s
->context
,b
,4);
377 static void stbiw__writef(stbi__write_context
*s
, const char *fmt
, ...)
381 stbiw__writefv(s
, fmt
, v
);
385 static void stbiw__write_flush(stbi__write_context
*s
)
388 s
->func(s
->context
, &s
->buffer
, s
->buf_used
);
393 static void stbiw__putc(stbi__write_context
*s
, unsigned char c
)
395 s
->func(s
->context
, &c
, 1);
398 static void stbiw__write1(stbi__write_context
*s
, unsigned char a
)
400 if (s
->buf_used
+ 1 > sizeof(s
->buffer
))
401 stbiw__write_flush(s
);
402 s
->buffer
[s
->buf_used
++] = a
;
405 static void stbiw__write3(stbi__write_context
*s
, unsigned char a
, unsigned char b
, unsigned char c
)
408 if (s
->buf_used
+ 3 > sizeof(s
->buffer
))
409 stbiw__write_flush(s
);
417 static void stbiw__write_pixel(stbi__write_context
*s
, int rgb_dir
, int comp
, int write_alpha
, int expand_mono
, unsigned char *d
)
419 unsigned char bg
[3] = { 255, 0, 255}, px
[3];
423 stbiw__write1(s
, d
[comp
- 1]);
426 case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case
429 stbiw__write3(s
, d
[0], d
[0], d
[0]); // monochrome bmp
431 stbiw__write1(s
, d
[0]); // monochrome TGA
435 // composite against pink background
436 for (k
= 0; k
< 3; ++k
)
437 px
[k
] = bg
[k
] + ((d
[k
] - bg
[k
]) * d
[3]) / 255;
438 stbiw__write3(s
, px
[1 - rgb_dir
], px
[1], px
[1 + rgb_dir
]);
443 stbiw__write3(s
, d
[1 - rgb_dir
], d
[1], d
[1 + rgb_dir
]);
447 stbiw__write1(s
, d
[comp
- 1]);
450 static void stbiw__write_pixels(stbi__write_context
*s
, int rgb_dir
, int vdir
, int x
, int y
, int comp
, void *data
, int write_alpha
, int scanline_pad
, int expand_mono
)
452 stbiw_uint32 zero
= 0;
458 if (stbi__flip_vertically_on_write
)
467 for (; j
!= j_end
; j
+= vdir
) {
468 for (i
=0; i
< x
; ++i
) {
469 unsigned char *d
= (unsigned char *) data
+ (j
*x
+i
)*comp
;
470 stbiw__write_pixel(s
, rgb_dir
, comp
, write_alpha
, expand_mono
, d
);
472 stbiw__write_flush(s
);
473 s
->func(s
->context
, &zero
, scanline_pad
);
477 static int stbiw__outfile(stbi__write_context
*s
, int rgb_dir
, int vdir
, int x
, int y
, int comp
, int expand_mono
, void *data
, int alpha
, int pad
, const char *fmt
, ...)
479 if (y
< 0 || x
< 0) {
484 stbiw__writefv(s
, fmt
, v
);
486 stbiw__write_pixels(s
,rgb_dir
,vdir
,x
,y
,comp
,data
,alpha
,pad
, expand_mono
);
491 static int stbi_write_bmp_core(stbi__write_context
*s
, int x
, int y
, int comp
, const void *data
)
493 int pad
= (-x
*3) & 3;
494 return stbiw__outfile(s
,-1,-1,x
,y
,comp
,1,(void *) data
,0,pad
,
495 "11 4 22 4" "4 44 22 444444",
496 'B', 'M', 14+40+(x
*3+pad
)*y
, 0,0, 14+40, // file header
497 40, x
,y
, 1,24, 0,0,0,0,0,0); // bitmap header
500 STBIWDEF
int stbi_write_bmp_to_func(stbi_write_func
*func
, void *context
, int x
, int y
, int comp
, const void *data
)
502 stbi__write_context s
= { 0 };
503 stbi__start_write_callbacks(&s
, func
, context
);
504 return stbi_write_bmp_core(&s
, x
, y
, comp
, data
);
507 #ifndef STBI_WRITE_NO_STDIO
508 STBIWDEF
int stbi_write_bmp(char const *filename
, int x
, int y
, int comp
, const void *data
)
510 stbi__write_context s
= { 0 };
511 if (stbi__start_write_file(&s
,filename
)) {
512 int r
= stbi_write_bmp_core(&s
, x
, y
, comp
, data
);
513 stbi__end_write_file(&s
);
518 #endif //!STBI_WRITE_NO_STDIO
520 static int stbi_write_tga_core(stbi__write_context
*s
, int x
, int y
, int comp
, void *data
)
522 int has_alpha
= (comp
== 2 || comp
== 4);
523 int colorbytes
= has_alpha
? comp
-1 : comp
;
524 int format
= colorbytes
< 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3
529 if (!stbi_write_tga_with_rle
) {
530 return stbiw__outfile(s
, -1, -1, x
, y
, comp
, 0, (void *) data
, has_alpha
, 0,
531 "111 221 2222 11", 0, 0, format
, 0, 0, 0, 0, 0, x
, y
, (colorbytes
+ has_alpha
) * 8, has_alpha
* 8);
536 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);
538 if (stbi__flip_vertically_on_write
) {
547 for (; j
!= jend
; j
+= jdir
) {
548 unsigned char *row
= (unsigned char *) data
+ j
* x
* comp
;
551 for (i
= 0; i
< x
; i
+= len
) {
552 unsigned char *begin
= row
+ i
* comp
;
558 diff
= memcmp(begin
, row
+ (i
+ 1) * comp
, comp
);
560 const unsigned char *prev
= begin
;
561 for (k
= i
+ 2; k
< x
&& len
< 128; ++k
) {
562 if (memcmp(prev
, row
+ k
* comp
, comp
)) {
571 for (k
= i
+ 2; k
< x
&& len
< 128; ++k
) {
572 if (!memcmp(begin
, row
+ k
* comp
, comp
)) {
582 unsigned char header
= STBIW_UCHAR(len
- 1);
583 stbiw__write1(s
, header
);
584 for (k
= 0; k
< len
; ++k
) {
585 stbiw__write_pixel(s
, -1, comp
, has_alpha
, 0, begin
+ k
* comp
);
588 unsigned char header
= STBIW_UCHAR(len
- 129);
589 stbiw__write1(s
, header
);
590 stbiw__write_pixel(s
, -1, comp
, has_alpha
, 0, begin
);
594 stbiw__write_flush(s
);
599 STBIWDEF
int stbi_write_tga_to_func(stbi_write_func
*func
, void *context
, int x
, int y
, int comp
, const void *data
)
601 stbi__write_context s
= { 0 };
602 stbi__start_write_callbacks(&s
, func
, context
);
603 return stbi_write_tga_core(&s
, x
, y
, comp
, (void *) data
);
606 #ifndef STBI_WRITE_NO_STDIO
607 STBIWDEF
int stbi_write_tga(char const *filename
, int x
, int y
, int comp
, const void *data
)
609 stbi__write_context s
= { 0 };
610 if (stbi__start_write_file(&s
,filename
)) {
611 int r
= stbi_write_tga_core(&s
, x
, y
, comp
, (void *) data
);
612 stbi__end_write_file(&s
);
619 // *************************************************************************************************
620 // Radiance RGBE HDR writer
621 // by Baldur Karlsson
623 #define stbiw__max(a, b) ((a) > (b) ? (a) : (b))
625 static void stbiw__linear_to_rgbe(unsigned char *rgbe
, float *linear
)
628 float maxcomp
= stbiw__max(linear
[0], stbiw__max(linear
[1], linear
[2]));
630 if (maxcomp
< 1e-32f
) {
631 rgbe
[0] = rgbe
[1] = rgbe
[2] = rgbe
[3] = 0;
633 float normalize
= (float) frexp(maxcomp
, &exponent
) * 256.0f
/maxcomp
;
635 rgbe
[0] = (unsigned char)(linear
[0] * normalize
);
636 rgbe
[1] = (unsigned char)(linear
[1] * normalize
);
637 rgbe
[2] = (unsigned char)(linear
[2] * normalize
);
638 rgbe
[3] = (unsigned char)(exponent
+ 128);
642 static void stbiw__write_run_data(stbi__write_context
*s
, int length
, unsigned char databyte
)
644 unsigned char lengthbyte
= STBIW_UCHAR(length
+128);
645 STBIW_ASSERT(length
+128 <= 255);
646 s
->func(s
->context
, &lengthbyte
, 1);
647 s
->func(s
->context
, &databyte
, 1);
650 static void stbiw__write_dump_data(stbi__write_context
*s
, int length
, unsigned char *data
)
652 unsigned char lengthbyte
= STBIW_UCHAR(length
);
653 STBIW_ASSERT(length
<= 128); // inconsistent with spec but consistent with official code
654 s
->func(s
->context
, &lengthbyte
, 1);
655 s
->func(s
->context
, data
, length
);
658 static void stbiw__write_hdr_scanline(stbi__write_context
*s
, int width
, int ncomp
, unsigned char *scratch
, float *scanline
)
660 unsigned char scanlineheader
[4] = { 2, 2, 0, 0 };
661 unsigned char rgbe
[4];
665 scanlineheader
[2] = (width
&0xff00)>>8;
666 scanlineheader
[3] = (width
&0x00ff);
668 /* skip RLE for images too small or large */
669 if (width
< 8 || width
>= 32768) {
670 for (x
=0; x
< width
; x
++) {
672 case 4: /* fallthrough */
673 case 3: linear
[2] = scanline
[x
*ncomp
+ 2];
674 linear
[1] = scanline
[x
*ncomp
+ 1];
675 linear
[0] = scanline
[x
*ncomp
+ 0];
678 linear
[0] = linear
[1] = linear
[2] = scanline
[x
*ncomp
+ 0];
681 stbiw__linear_to_rgbe(rgbe
, linear
);
682 s
->func(s
->context
, rgbe
, 4);
686 /* encode into scratch buffer */
687 for (x
=0; x
< width
; x
++) {
689 case 4: /* fallthrough */
690 case 3: linear
[2] = scanline
[x
*ncomp
+ 2];
691 linear
[1] = scanline
[x
*ncomp
+ 1];
692 linear
[0] = scanline
[x
*ncomp
+ 0];
695 linear
[0] = linear
[1] = linear
[2] = scanline
[x
*ncomp
+ 0];
698 stbiw__linear_to_rgbe(rgbe
, linear
);
699 scratch
[x
+ width
*0] = rgbe
[0];
700 scratch
[x
+ width
*1] = rgbe
[1];
701 scratch
[x
+ width
*2] = rgbe
[2];
702 scratch
[x
+ width
*3] = rgbe
[3];
705 s
->func(s
->context
, scanlineheader
, 4);
707 /* RLE each component separately */
708 for (c
=0; c
< 4; c
++) {
709 unsigned char *comp
= &scratch
[width
*c
];
715 while (r
+2 < width
) {
716 if (comp
[r
] == comp
[r
+1] && comp
[r
] == comp
[r
+2])
722 // dump up to first run
725 if (len
> 128) len
= 128;
726 stbiw__write_dump_data(s
, len
, &comp
[x
]);
729 // if there's a run, output it
730 if (r
+2 < width
) { // same test as what we break out of in search loop, so only true if we break'd
731 // find next byte after run
732 while (r
< width
&& comp
[r
] == comp
[x
])
734 // output run up to r
737 if (len
> 127) len
= 127;
738 stbiw__write_run_data(s
, len
, comp
[x
]);
747 static int stbi_write_hdr_core(stbi__write_context
*s
, int x
, int y
, int comp
, float *data
)
749 if (y
<= 0 || x
<= 0 || data
== NULL
)
752 // Each component is stored separately. Allocate scratch space for full output scanline.
753 unsigned char *scratch
= (unsigned char *) STBIW_MALLOC(x
*4);
756 char header
[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n";
757 s
->func(s
->context
, header
, sizeof(header
)-1);
759 #ifdef __STDC_WANT_SECURE_LIB__
760 len
= sprintf_s(buffer
, sizeof(buffer
), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y
, x
);
762 len
= sprintf(buffer
, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y
, x
);
764 s
->func(s
->context
, buffer
, len
);
767 stbiw__write_hdr_scanline(s
, x
, comp
, scratch
, data
+ comp
*x
*(stbi__flip_vertically_on_write
? y
-1-i
: i
));
773 STBIWDEF
int stbi_write_hdr_to_func(stbi_write_func
*func
, void *context
, int x
, int y
, int comp
, const float *data
)
775 stbi__write_context s
= { 0 };
776 stbi__start_write_callbacks(&s
, func
, context
);
777 return stbi_write_hdr_core(&s
, x
, y
, comp
, (float *) data
);
780 #ifndef STBI_WRITE_NO_STDIO
781 STBIWDEF
int stbi_write_hdr(char const *filename
, int x
, int y
, int comp
, const float *data
)
783 stbi__write_context s
= { 0 };
784 if (stbi__start_write_file(&s
,filename
)) {
785 int r
= stbi_write_hdr_core(&s
, x
, y
, comp
, (float *) data
);
786 stbi__end_write_file(&s
);
791 #endif // STBI_WRITE_NO_STDIO
794 //////////////////////////////////////////////////////////////////////////////
799 #ifndef STBIW_ZLIB_COMPRESS
800 // stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
801 #define stbiw__sbraw(a) ((int *) (void *) (a) - 2)
802 #define stbiw__sbm(a) stbiw__sbraw(a)[0]
803 #define stbiw__sbn(a) stbiw__sbraw(a)[1]
805 #define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a))
806 #define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0)
807 #define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a)))
809 #define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v))
810 #define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0)
811 #define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0)
813 static void *stbiw__sbgrowf(void **arr
, int increment
, int itemsize
)
815 int m
= *arr
? 2*stbiw__sbm(*arr
)+increment
: increment
+1;
816 void *p
= STBIW_REALLOC_SIZED(*arr
? stbiw__sbraw(*arr
) : 0, *arr
? (stbiw__sbm(*arr
)*itemsize
+ sizeof(int)*2) : 0, itemsize
* m
+ sizeof(int)*2);
819 if (!*arr
) ((int *) p
)[1] = 0;
820 *arr
= (void *) ((int *) p
+ 2);
821 stbiw__sbm(*arr
) = m
;
826 static unsigned char *stbiw__zlib_flushf(unsigned char *data
, unsigned int *bitbuffer
, int *bitcount
)
828 while (*bitcount
>= 8) {
829 stbiw__sbpush(data
, STBIW_UCHAR(*bitbuffer
));
836 static int stbiw__zlib_bitrev(int code
, int codebits
)
840 res
= (res
<< 1) | (code
& 1);
846 static unsigned int stbiw__zlib_countm(unsigned char *a
, unsigned char *b
, int limit
)
849 for (i
=0; i
< limit
&& i
< 258; ++i
)
850 if (a
[i
] != b
[i
]) break;
854 static unsigned int stbiw__zhash(unsigned char *data
)
856 stbiw_uint32 hash
= data
[0] + (data
[1] << 8) + (data
[2] << 16);
866 #define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount))
867 #define stbiw__zlib_add(code,codebits) \
868 (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush())
869 #define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c)
870 // default huffman tables
871 #define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8)
872 #define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9)
873 #define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7)
874 #define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8)
875 #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))
876 #define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n))
878 #define stbiw__ZHASH 16384
880 #endif // STBIW_ZLIB_COMPRESS
882 STBIWDEF
unsigned char * stbi_zlib_compress(unsigned char *data
, int data_len
, int *out_len
, int quality
)
884 #ifdef STBIW_ZLIB_COMPRESS
885 // user provided a zlib compress implementation, use that
886 return STBIW_ZLIB_COMPRESS(data
, data_len
, out_len
, quality
);
888 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 };
889 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 };
890 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 };
891 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 };
892 unsigned int bitbuf
=0;
894 unsigned char *out
= NULL
;
895 unsigned char ***hash_table
= (unsigned char***) STBIW_MALLOC(stbiw__ZHASH
* sizeof(unsigned char**));
896 if (hash_table
== NULL
)
898 if (quality
< 5) quality
= 5;
900 stbiw__sbpush(out
, 0x78); // DEFLATE 32K window
901 stbiw__sbpush(out
, 0x5e); // FLEVEL = 1
902 stbiw__zlib_add(1,1); // BFINAL = 1
903 stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman
905 for (i
=0; i
< stbiw__ZHASH
; ++i
)
906 hash_table
[i
] = NULL
;
909 while (i
< data_len
-3) {
910 // hash next 3 bytes of data to be compressed
911 int h
= stbiw__zhash(data
+i
)&(stbiw__ZHASH
-1), best
=3;
912 unsigned char *bestloc
= 0;
913 unsigned char **hlist
= hash_table
[h
];
914 int n
= stbiw__sbcount(hlist
);
915 for (j
=0; j
< n
; ++j
) {
916 if (hlist
[j
]-data
> i
-32768) { // if entry lies within window
917 int d
= stbiw__zlib_countm(hlist
[j
], data
+i
, data_len
-i
);
918 if (d
>= best
) { best
=d
; bestloc
=hlist
[j
]; }
921 // when hash table entry is too long, delete half the entries
922 if (hash_table
[h
] && stbiw__sbn(hash_table
[h
]) == 2*quality
) {
923 STBIW_MEMMOVE(hash_table
[h
], hash_table
[h
]+quality
, sizeof(hash_table
[h
][0])*quality
);
924 stbiw__sbn(hash_table
[h
]) = quality
;
926 stbiw__sbpush(hash_table
[h
],data
+i
);
929 // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal
930 h
= stbiw__zhash(data
+i
+1)&(stbiw__ZHASH
-1);
931 hlist
= hash_table
[h
];
932 n
= stbiw__sbcount(hlist
);
933 for (j
=0; j
< n
; ++j
) {
934 if (hlist
[j
]-data
> i
-32767) {
935 int e
= stbiw__zlib_countm(hlist
[j
], data
+i
+1, data_len
-i
-1);
936 if (e
> best
) { // if next match is better, bail on current match
945 int d
= (int) (data
+i
- bestloc
); // distance back
946 STBIW_ASSERT(d
<= 32767 && best
<= 258);
947 for (j
=0; best
> lengthc
[j
+1]-1; ++j
);
948 stbiw__zlib_huff(j
+257);
949 if (lengtheb
[j
]) stbiw__zlib_add(best
- lengthc
[j
], lengtheb
[j
]);
950 for (j
=0; d
> distc
[j
+1]-1; ++j
);
951 stbiw__zlib_add(stbiw__zlib_bitrev(j
,5),5);
952 if (disteb
[j
]) stbiw__zlib_add(d
- distc
[j
], disteb
[j
]);
955 stbiw__zlib_huffb(data
[i
]);
959 // write out final bytes
960 for (;i
< data_len
; ++i
)
961 stbiw__zlib_huffb(data
[i
]);
962 stbiw__zlib_huff(256); // end of block
963 // pad with 0 bits to byte boundary
965 stbiw__zlib_add(0,1);
967 for (i
=0; i
< stbiw__ZHASH
; ++i
)
968 (void) stbiw__sbfree(hash_table
[i
]);
969 STBIW_FREE(hash_table
);
972 // compute adler32 on input
973 unsigned int s1
=1, s2
=0;
974 int blocklen
= (int) (data_len
% 5552);
976 while (j
< data_len
) {
977 for (i
=0; i
< blocklen
; ++i
) { s1
+= data
[j
+i
]; s2
+= s1
; }
978 s1
%= 65521; s2
%= 65521;
982 stbiw__sbpush(out
, STBIW_UCHAR(s2
>> 8));
983 stbiw__sbpush(out
, STBIW_UCHAR(s2
));
984 stbiw__sbpush(out
, STBIW_UCHAR(s1
>> 8));
985 stbiw__sbpush(out
, STBIW_UCHAR(s1
));
987 *out_len
= stbiw__sbn(out
);
988 // make returned pointer freeable
989 STBIW_MEMMOVE(stbiw__sbraw(out
), out
, *out_len
);
990 return (unsigned char *) stbiw__sbraw(out
);
991 #endif // STBIW_ZLIB_COMPRESS
994 static unsigned int stbiw__crc32(unsigned char *buffer
, int len
)
997 return STBIW_CRC32(buffer
, len
);
999 static unsigned int crc_table
[256] =
1001 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1002 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1003 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1004 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1005 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1006 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1007 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1008 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1009 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1010 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1011 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1012 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1013 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1014 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1015 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1016 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1017 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1018 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1019 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1020 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1021 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1022 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1023 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1024 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1025 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1026 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1027 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1028 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1029 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1030 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1031 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1032 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
1035 unsigned int crc
= ~0u;
1037 for (i
=0; i
< len
; ++i
)
1038 crc
= (crc
>> 8) ^ crc_table
[buffer
[i
] ^ (crc
& 0xff)];
1043 #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)
1044 #define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));
1045 #define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3])
1047 static void stbiw__wpcrc(unsigned char **data
, int len
)
1049 unsigned int crc
= stbiw__crc32(*data
- len
- 4, len
+4);
1050 stbiw__wp32(*data
, crc
);
1053 static unsigned char stbiw__paeth(int a
, int b
, int c
)
1055 int p
= a
+ b
- c
, pa
= abs(p
-a
), pb
= abs(p
-b
), pc
= abs(p
-c
);
1056 if (pa
<= pb
&& pa
<= pc
) return STBIW_UCHAR(a
);
1057 if (pb
<= pc
) return STBIW_UCHAR(b
);
1058 return STBIW_UCHAR(c
);
1061 // @OPTIMIZE: provide an option that always forces left-predict or paeth predict
1062 static 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
)
1064 static int mapping
[] = { 0,1,2,3,4 };
1065 static int firstmap
[] = { 0,1,0,5,6 };
1066 int *mymap
= (y
!= 0) ? mapping
: firstmap
;
1068 int type
= mymap
[filter_type
];
1069 unsigned char *z
= pixels
+ stride_bytes
* (stbi__flip_vertically_on_write
? height
-1-y
: y
);
1070 int signed_stride
= stbi__flip_vertically_on_write
? -stride_bytes
: stride_bytes
;
1073 memcpy(line_buffer
, z
, width
*n
);
1077 // first loop isn't optimized since it's just one pixel
1078 for (i
= 0; i
< n
; ++i
) {
1080 case 1: line_buffer
[i
] = z
[i
]; break;
1081 case 2: line_buffer
[i
] = z
[i
] - z
[i
-signed_stride
]; break;
1082 case 3: line_buffer
[i
] = z
[i
] - (z
[i
-signed_stride
]>>1); break;
1083 case 4: line_buffer
[i
] = (signed char) (z
[i
] - stbiw__paeth(0,z
[i
-signed_stride
],0)); break;
1084 case 5: line_buffer
[i
] = z
[i
]; break;
1085 case 6: line_buffer
[i
] = z
[i
]; break;
1089 case 1: for (i
=n
; i
< width
*n
; ++i
) line_buffer
[i
] = z
[i
] - z
[i
-n
]; break;
1090 case 2: for (i
=n
; i
< width
*n
; ++i
) line_buffer
[i
] = z
[i
] - z
[i
-signed_stride
]; break;
1091 case 3: for (i
=n
; i
< width
*n
; ++i
) line_buffer
[i
] = z
[i
] - ((z
[i
-n
] + z
[i
-signed_stride
])>>1); break;
1092 case 4: for (i
=n
; i
< width
*n
; ++i
) line_buffer
[i
] = z
[i
] - stbiw__paeth(z
[i
-n
], z
[i
-signed_stride
], z
[i
-signed_stride
-n
]); break;
1093 case 5: for (i
=n
; i
< width
*n
; ++i
) line_buffer
[i
] = z
[i
] - (z
[i
-n
]>>1); break;
1094 case 6: for (i
=n
; i
< width
*n
; ++i
) line_buffer
[i
] = z
[i
] - stbiw__paeth(z
[i
-n
], 0,0); break;
1098 STBIWDEF
unsigned char *stbi_write_png_to_mem(const unsigned char *pixels
, int stride_bytes
, int x
, int y
, int n
, int *out_len
)
1100 int force_filter
= stbi_write_force_png_filter
;
1101 int ctype
[5] = { -1, 0, 4, 2, 6 };
1102 unsigned char sig
[8] = { 137,80,78,71,13,10,26,10 };
1103 unsigned char *out
,*o
, *filt
, *zlib
;
1104 signed char *line_buffer
;
1107 if (stride_bytes
== 0)
1108 stride_bytes
= x
* n
;
1110 if (force_filter
>= 5) {
1114 filt
= (unsigned char *) STBIW_MALLOC((x
*n
+1) * y
); if (!filt
) return 0;
1115 line_buffer
= (signed char *) STBIW_MALLOC(x
* n
); if (!line_buffer
) { STBIW_FREE(filt
); return 0; }
1116 for (j
=0; j
< y
; ++j
) {
1118 if (force_filter
> -1) {
1119 filter_type
= force_filter
;
1120 stbiw__encode_png_line((unsigned char*)(pixels
), stride_bytes
, x
, y
, j
, n
, force_filter
, line_buffer
);
1121 } else { // Estimate the best filter by running through all of them:
1122 int best_filter
= 0, best_filter_val
= 0x7fffffff, est
, i
;
1123 for (filter_type
= 0; filter_type
< 5; filter_type
++) {
1124 stbiw__encode_png_line((unsigned char*)(pixels
), stride_bytes
, x
, y
, j
, n
, filter_type
, line_buffer
);
1126 // Estimate the entropy of the line using this filter; the less, the better.
1128 for (i
= 0; i
< x
*n
; ++i
) {
1129 est
+= abs((signed char) line_buffer
[i
]);
1131 if (est
< best_filter_val
) {
1132 best_filter_val
= est
;
1133 best_filter
= filter_type
;
1136 if (filter_type
!= best_filter
) { // If the last iteration already got us the best filter, don't redo it
1137 stbiw__encode_png_line((unsigned char*)(pixels
), stride_bytes
, x
, y
, j
, n
, best_filter
, line_buffer
);
1138 filter_type
= best_filter
;
1141 // when we get here, filter_type contains the filter type, and line_buffer contains the data
1142 filt
[j
*(x
*n
+1)] = (unsigned char) filter_type
;
1143 STBIW_MEMMOVE(filt
+j
*(x
*n
+1)+1, line_buffer
, x
*n
);
1145 STBIW_FREE(line_buffer
);
1146 zlib
= stbi_zlib_compress(filt
, y
*( x
*n
+1), &zlen
, stbi_write_png_compression_level
);
1148 if (!zlib
) return 0;
1150 // each tag requires 12 bytes of overhead
1151 out
= (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen
+ 12);
1153 *out_len
= 8 + 12+13 + 12+zlen
+ 12;
1156 STBIW_MEMMOVE(o
,sig
,8); o
+= 8;
1157 stbiw__wp32(o
, 13); // header length
1158 stbiw__wptag(o
, "IHDR");
1162 *o
++ = STBIW_UCHAR(ctype
[n
]);
1166 stbiw__wpcrc(&o
,13);
1168 stbiw__wp32(o
, zlen
);
1169 stbiw__wptag(o
, "IDAT");
1170 STBIW_MEMMOVE(o
, zlib
, zlen
);
1173 stbiw__wpcrc(&o
, zlen
);
1176 stbiw__wptag(o
, "IEND");
1179 STBIW_ASSERT(o
== out
+ *out_len
);
1184 #ifndef STBI_WRITE_NO_STDIO
1185 STBIWDEF
int stbi_write_png(char const *filename
, int x
, int y
, int comp
, const void *data
, int stride_bytes
)
1189 unsigned char *png
= stbi_write_png_to_mem((const unsigned char *) data
, stride_bytes
, x
, y
, comp
, &len
);
1190 if (png
== NULL
) return 0;
1192 f
= stbiw__fopen(filename
, "wb");
1193 if (!f
) { STBIW_FREE(png
); return 0; }
1194 fwrite(png
, 1, len
, f
);
1201 STBIWDEF
int stbi_write_png_to_func(stbi_write_func
*func
, void *context
, int x
, int y
, int comp
, const void *data
, int stride_bytes
)
1204 unsigned char *png
= stbi_write_png_to_mem((const unsigned char *) data
, stride_bytes
, x
, y
, comp
, &len
);
1205 if (png
== NULL
) return 0;
1206 func(context
, png
, len
);
1212 /* ***************************************************************************
1216 * This is based on Jon Olick's jo_jpeg.cpp:
1217 * public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html
1220 static 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,
1221 24,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 };
1223 static void stbiw__jpg_writeBits(stbi__write_context
*s
, int *bitBufP
, int *bitCntP
, const unsigned short *bs
) {
1224 int bitBuf
= *bitBufP
, bitCnt
= *bitCntP
;
1226 bitBuf
|= bs
[0] << (24 - bitCnt
);
1227 while(bitCnt
>= 8) {
1228 unsigned char c
= (bitBuf
>> 16) & 255;
1240 static void stbiw__jpg_DCT(float *d0p
, float *d1p
, float *d2p
, float *d3p
, float *d4p
, float *d5p
, float *d6p
, float *d7p
) {
1241 float d0
= *d0p
, d1
= *d1p
, d2
= *d2p
, d3
= *d3p
, d4
= *d4p
, d5
= *d5p
, d6
= *d6p
, d7
= *d7p
;
1242 float z1
, z2
, z3
, z4
, z5
, z11
, z13
;
1244 float tmp0
= d0
+ d7
;
1245 float tmp7
= d0
- d7
;
1246 float tmp1
= d1
+ d6
;
1247 float tmp6
= d1
- d6
;
1248 float tmp2
= d2
+ d5
;
1249 float tmp5
= d2
- d5
;
1250 float tmp3
= d3
+ d4
;
1251 float tmp4
= d3
- d4
;
1254 float tmp10
= tmp0
+ tmp3
; // phase 2
1255 float tmp13
= tmp0
- tmp3
;
1256 float tmp11
= tmp1
+ tmp2
;
1257 float tmp12
= tmp1
- tmp2
;
1259 d0
= tmp10
+ tmp11
; // phase 3
1262 z1
= (tmp12
+ tmp13
) * 0.707106781f
; // c4
1263 d2
= tmp13
+ z1
; // phase 5
1267 tmp10
= tmp4
+ tmp5
; // phase 2
1268 tmp11
= tmp5
+ tmp6
;
1269 tmp12
= tmp6
+ tmp7
;
1271 // The rotator is modified from fig 4-8 to avoid extra negations.
1272 z5
= (tmp10
- tmp12
) * 0.382683433f
; // c6
1273 z2
= tmp10
* 0.541196100f
+ z5
; // c2-c6
1274 z4
= tmp12
* 1.306562965f
+ z5
; // c2+c6
1275 z3
= tmp11
* 0.707106781f
; // c4
1277 z11
= tmp7
+ z3
; // phase 5
1280 *d5p
= z13
+ z2
; // phase 6
1285 *d0p
= d0
; *d2p
= d2
; *d4p
= d4
; *d6p
= d6
;
1288 static void stbiw__jpg_calcBits(int val
, unsigned short bits
[2]) {
1289 int tmp1
= val
< 0 ? -val
: val
;
1290 val
= val
< 0 ? val
-1 : val
;
1295 bits
[0] = val
& ((1<<bits
[1])-1);
1298 static int stbiw__jpg_processDU(stbi__write_context
*s
, int *bitBuf
, int *bitCnt
, float *CDU
, int du_stride
, float *fdtbl
, int DC
, const unsigned short HTDC
[256][2], const unsigned short HTAC
[256][2]) {
1299 const unsigned short EOB
[2] = { HTAC
[0x00][0], HTAC
[0x00][1] };
1300 const unsigned short M16zeroes
[2] = { HTAC
[0xF0][0], HTAC
[0xF0][1] };
1301 int dataOff
, i
, j
, n
, diff
, end0pos
, x
, y
;
1305 for(dataOff
=0, n
=du_stride
*8; dataOff
<n
; dataOff
+=du_stride
) {
1306 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]);
1309 for(dataOff
=0; dataOff
<8; ++dataOff
) {
1310 stbiw__jpg_DCT(&CDU
[dataOff
], &CDU
[dataOff
+du_stride
], &CDU
[dataOff
+du_stride
*2], &CDU
[dataOff
+du_stride
*3], &CDU
[dataOff
+du_stride
*4],
1311 &CDU
[dataOff
+du_stride
*5], &CDU
[dataOff
+du_stride
*6], &CDU
[dataOff
+du_stride
*7]);
1313 // Quantize/descale/zigzag the coefficients
1314 for(y
= 0, j
=0; y
< 8; ++y
) {
1315 for(x
= 0; x
< 8; ++x
,++j
) {
1318 v
= CDU
[i
]*fdtbl
[j
];
1319 // DU[stbiw__jpg_ZigZag[j]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f));
1320 // ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway?
1321 DU
[stbiw__jpg_ZigZag
[j
]] = (int)(v
< 0 ? v
- 0.5f
: v
+ 0.5f
);
1328 stbiw__jpg_writeBits(s
, bitBuf
, bitCnt
, HTDC
[0]);
1330 unsigned short bits
[2];
1331 stbiw__jpg_calcBits(diff
, bits
);
1332 stbiw__jpg_writeBits(s
, bitBuf
, bitCnt
, HTDC
[bits
[1]]);
1333 stbiw__jpg_writeBits(s
, bitBuf
, bitCnt
, bits
);
1337 for(; (end0pos
>0)&&(DU
[end0pos
]==0); --end0pos
) {
1339 // end0pos = first element in reverse order !=0
1341 stbiw__jpg_writeBits(s
, bitBuf
, bitCnt
, EOB
);
1344 for(i
= 1; i
<= end0pos
; ++i
) {
1347 unsigned short bits
[2];
1348 for (; DU
[i
]==0 && i
<=end0pos
; ++i
) {
1350 nrzeroes
= i
-startpos
;
1351 if ( nrzeroes
>= 16 ) {
1352 int lng
= nrzeroes
>>4;
1354 for (nrmarker
=1; nrmarker
<= lng
; ++nrmarker
)
1355 stbiw__jpg_writeBits(s
, bitBuf
, bitCnt
, M16zeroes
);
1358 stbiw__jpg_calcBits(DU
[i
], bits
);
1359 stbiw__jpg_writeBits(s
, bitBuf
, bitCnt
, HTAC
[(nrzeroes
<<4)+bits
[1]]);
1360 stbiw__jpg_writeBits(s
, bitBuf
, bitCnt
, bits
);
1363 stbiw__jpg_writeBits(s
, bitBuf
, bitCnt
, EOB
);
1368 static int stbi_write_jpg_core(stbi__write_context
*s
, int width
, int height
, int comp
, const void* data
, int quality
) {
1369 // Constants that don't pollute global namespace
1370 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};
1371 static const unsigned char std_dc_luminance_values
[] = {0,1,2,3,4,5,6,7,8,9,10,11};
1372 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};
1373 static const unsigned char std_ac_luminance_values
[] = {
1374 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,
1375 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,
1376 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,
1377 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,
1378 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,
1379 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,
1380 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa
1382 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};
1383 static const unsigned char std_dc_chrominance_values
[] = {0,1,2,3,4,5,6,7,8,9,10,11};
1384 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};
1385 static const unsigned char std_ac_chrominance_values
[] = {
1386 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,
1387 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,
1388 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,
1389 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87,
1390 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,
1391 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,
1392 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa
1395 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}};
1396 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}};
1397 static const unsigned short YAC_HT
[256][2] = {
1398 {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},
1399 {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},
1400 {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},
1401 {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},
1402 {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},
1403 {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},
1404 {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},
1405 {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},
1406 {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},
1407 {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},
1408 {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},
1409 {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},
1410 {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},
1411 {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},
1412 {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},
1413 {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}
1415 static const unsigned short UVAC_HT
[256][2] = {
1416 {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},
1417 {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},
1418 {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},
1419 {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},
1420 {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},
1421 {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},
1422 {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},
1423 {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},
1424 {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},
1425 {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},
1426 {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},
1427 {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},
1428 {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},
1429 {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},
1430 {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},
1431 {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}
1433 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,
1434 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};
1435 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,
1436 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};
1437 static const float aasf
[] = { 1.0f
* 2.828427125f
, 1.387039845f
* 2.828427125f
, 1.306562965f
* 2.828427125f
, 1.175875602f
* 2.828427125f
,
1438 1.0f
* 2.828427125f
, 0.785694958f
* 2.828427125f
, 0.541196100f
* 2.828427125f
, 0.275899379f
* 2.828427125f
};
1440 int row
, col
, i
, k
, subsample
;
1441 float fdtbl_Y
[64], fdtbl_UV
[64];
1442 unsigned char YTable
[64], UVTable
[64];
1444 if(!data
|| !width
|| !height
|| comp
> 4 || comp
< 1) {
1448 quality
= quality
? quality
: 90;
1449 subsample
= quality
<= 90 ? 1 : 0;
1450 quality
= quality
< 1 ? 1 : quality
> 100 ? 100 : quality
;
1451 quality
= quality
< 50 ? 5000 / quality
: 200 - quality
* 2;
1453 for(i
= 0; i
< 64; ++i
) {
1454 int uvti
, yti
= (YQT
[i
]*quality
+50)/100;
1455 YTable
[stbiw__jpg_ZigZag
[i
]] = (unsigned char) (yti
< 1 ? 1 : yti
> 255 ? 255 : yti
);
1456 uvti
= (UVQT
[i
]*quality
+50)/100;
1457 UVTable
[stbiw__jpg_ZigZag
[i
]] = (unsigned char) (uvti
< 1 ? 1 : uvti
> 255 ? 255 : uvti
);
1460 for(row
= 0, k
= 0; row
< 8; ++row
) {
1461 for(col
= 0; col
< 8; ++col
, ++k
) {
1462 fdtbl_Y
[k
] = 1 / (YTable
[stbiw__jpg_ZigZag
[k
]] * aasf
[row
] * aasf
[col
]);
1463 fdtbl_UV
[k
] = 1 / (UVTable
[stbiw__jpg_ZigZag
[k
]] * aasf
[row
] * aasf
[col
]);
1469 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 };
1470 static const unsigned char head2
[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 };
1471 const unsigned char head1
[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height
>>8),STBIW_UCHAR(height
),(unsigned char)(width
>>8),STBIW_UCHAR(width
),
1472 3,1,(unsigned char)(subsample
?0x22:0x11),0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 };
1473 s
->func(s
->context
, (void*)head0
, sizeof(head0
));
1474 s
->func(s
->context
, (void*)YTable
, sizeof(YTable
));
1476 s
->func(s
->context
, UVTable
, sizeof(UVTable
));
1477 s
->func(s
->context
, (void*)head1
, sizeof(head1
));
1478 s
->func(s
->context
, (void*)(std_dc_luminance_nrcodes
+1), sizeof(std_dc_luminance_nrcodes
)-1);
1479 s
->func(s
->context
, (void*)std_dc_luminance_values
, sizeof(std_dc_luminance_values
));
1480 stbiw__putc(s
, 0x10); // HTYACinfo
1481 s
->func(s
->context
, (void*)(std_ac_luminance_nrcodes
+1), sizeof(std_ac_luminance_nrcodes
)-1);
1482 s
->func(s
->context
, (void*)std_ac_luminance_values
, sizeof(std_ac_luminance_values
));
1483 stbiw__putc(s
, 1); // HTUDCinfo
1484 s
->func(s
->context
, (void*)(std_dc_chrominance_nrcodes
+1), sizeof(std_dc_chrominance_nrcodes
)-1);
1485 s
->func(s
->context
, (void*)std_dc_chrominance_values
, sizeof(std_dc_chrominance_values
));
1486 stbiw__putc(s
, 0x11); // HTUACinfo
1487 s
->func(s
->context
, (void*)(std_ac_chrominance_nrcodes
+1), sizeof(std_ac_chrominance_nrcodes
)-1);
1488 s
->func(s
->context
, (void*)std_ac_chrominance_values
, sizeof(std_ac_chrominance_values
));
1489 s
->func(s
->context
, (void*)head2
, sizeof(head2
));
1492 // Encode 8x8 macroblocks
1494 static const unsigned short fillBits
[] = {0x7F, 7};
1495 int DCY
=0, DCU
=0, DCV
=0;
1496 int bitBuf
=0, bitCnt
=0;
1497 // comp == 2 is grey+alpha (alpha is ignored)
1498 int ofsG
= comp
> 2 ? 1 : 0, ofsB
= comp
> 2 ? 2 : 0;
1499 const unsigned char *dataR
= (const unsigned char *)data
;
1500 const unsigned char *dataG
= dataR
+ ofsG
;
1501 const unsigned char *dataB
= dataR
+ ofsB
;
1504 for(y
= 0; y
< height
; y
+= 16) {
1505 for(x
= 0; x
< width
; x
+= 16) {
1506 float Y
[256], U
[256], V
[256];
1507 for(row
= y
, pos
= 0; row
< y
+16; ++row
) {
1508 // row >= height => use last input row
1509 int clamped_row
= (row
< height
) ? row
: height
- 1;
1510 int base_p
= (stbi__flip_vertically_on_write
? (height
-1-clamped_row
) : clamped_row
)*width
*comp
;
1511 for(col
= x
; col
< x
+16; ++col
, ++pos
) {
1512 // if col >= width => use pixel from last input column
1513 int p
= base_p
+ ((col
< width
) ? col
: (width
-1))*comp
;
1514 float r
= dataR
[p
], g
= dataG
[p
], b
= dataB
[p
];
1515 Y
[pos
]= +0.29900f
*r
+ 0.58700f
*g
+ 0.11400f
*b
- 128;
1516 U
[pos
]= -0.16874f
*r
- 0.33126f
*g
+ 0.50000f
*b
;
1517 V
[pos
]= +0.50000f
*r
- 0.41869f
*g
- 0.08131f
*b
;
1520 DCY
= stbiw__jpg_processDU(s
, &bitBuf
, &bitCnt
, Y
+0, 16, fdtbl_Y
, DCY
, YDC_HT
, YAC_HT
);
1521 DCY
= stbiw__jpg_processDU(s
, &bitBuf
, &bitCnt
, Y
+8, 16, fdtbl_Y
, DCY
, YDC_HT
, YAC_HT
);
1522 DCY
= stbiw__jpg_processDU(s
, &bitBuf
, &bitCnt
, Y
+128, 16, fdtbl_Y
, DCY
, YDC_HT
, YAC_HT
);
1523 DCY
= stbiw__jpg_processDU(s
, &bitBuf
, &bitCnt
, Y
+136, 16, fdtbl_Y
, DCY
, YDC_HT
, YAC_HT
);
1527 float subU
[64], subV
[64];
1529 for(yy
= 0, pos
= 0; yy
< 8; ++yy
) {
1530 for(xx
= 0; xx
< 8; ++xx
, ++pos
) {
1532 subU
[pos
] = (U
[j
+0] + U
[j
+1] + U
[j
+16] + U
[j
+17]) * 0.25f
;
1533 subV
[pos
] = (V
[j
+0] + V
[j
+1] + V
[j
+16] + V
[j
+17]) * 0.25f
;
1536 DCU
= stbiw__jpg_processDU(s
, &bitBuf
, &bitCnt
, subU
, 8, fdtbl_UV
, DCU
, UVDC_HT
, UVAC_HT
);
1537 DCV
= stbiw__jpg_processDU(s
, &bitBuf
, &bitCnt
, subV
, 8, fdtbl_UV
, DCV
, UVDC_HT
, UVAC_HT
);
1542 for(y
= 0; y
< height
; y
+= 8) {
1543 for(x
= 0; x
< width
; x
+= 8) {
1544 float Y
[64], U
[64], V
[64];
1545 for(row
= y
, pos
= 0; row
< y
+8; ++row
) {
1546 // row >= height => use last input row
1547 int clamped_row
= (row
< height
) ? row
: height
- 1;
1548 int base_p
= (stbi__flip_vertically_on_write
? (height
-1-clamped_row
) : clamped_row
)*width
*comp
;
1549 for(col
= x
; col
< x
+8; ++col
, ++pos
) {
1550 // if col >= width => use pixel from last input column
1551 int p
= base_p
+ ((col
< width
) ? col
: (width
-1))*comp
;
1552 float r
= dataR
[p
], g
= dataG
[p
], b
= dataB
[p
];
1553 Y
[pos
]= +0.29900f
*r
+ 0.58700f
*g
+ 0.11400f
*b
- 128;
1554 U
[pos
]= -0.16874f
*r
- 0.33126f
*g
+ 0.50000f
*b
;
1555 V
[pos
]= +0.50000f
*r
- 0.41869f
*g
- 0.08131f
*b
;
1559 DCY
= stbiw__jpg_processDU(s
, &bitBuf
, &bitCnt
, Y
, 8, fdtbl_Y
, DCY
, YDC_HT
, YAC_HT
);
1560 DCU
= stbiw__jpg_processDU(s
, &bitBuf
, &bitCnt
, U
, 8, fdtbl_UV
, DCU
, UVDC_HT
, UVAC_HT
);
1561 DCV
= stbiw__jpg_processDU(s
, &bitBuf
, &bitCnt
, V
, 8, fdtbl_UV
, DCV
, UVDC_HT
, UVAC_HT
);
1566 // Do the bit alignment of the EOI marker
1567 stbiw__jpg_writeBits(s
, &bitBuf
, &bitCnt
, fillBits
);
1571 stbiw__putc(s
, 0xFF);
1572 stbiw__putc(s
, 0xD9);
1577 STBIWDEF
int stbi_write_jpg_to_func(stbi_write_func
*func
, void *context
, int x
, int y
, int comp
, const void *data
, int quality
)
1579 stbi__write_context s
= { 0 };
1580 stbi__start_write_callbacks(&s
, func
, context
);
1581 return stbi_write_jpg_core(&s
, x
, y
, comp
, (void *) data
, quality
);
1585 #ifndef STBI_WRITE_NO_STDIO
1586 STBIWDEF
int stbi_write_jpg(char const *filename
, int x
, int y
, int comp
, const void *data
, int quality
)
1588 stbi__write_context s
= { 0 };
1589 if (stbi__start_write_file(&s
,filename
)) {
1590 int r
= stbi_write_jpg_core(&s
, x
, y
, comp
, data
, quality
);
1591 stbi__end_write_file(&s
);
1598 #endif // STB_IMAGE_WRITE_IMPLEMENTATION
1601 1.14 (2020-02-02) updated JPEG writer to downsample chroma channels
1607 support utf8 filenames in Windows; fix warnings and platform ifdefs
1609 fix typo in zlib quality API, improve STB_I_W_STATIC in C++
1611 add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter
1615 writing JPEG (using Jon Olick's code)
1618 monochrome BMP expansion
1621 avoid allocating large structures on the stack
1623 STBIW_REALLOC_SIZED: support allocators with no realloc support
1624 avoid race-condition in crc initialization
1625 minor compile issues
1627 installable file IO function
1629 warning fixes; TGA rle support
1631 added STBIW_MALLOC, STBIW_ASSERT etc
1633 fixed HDR asserts, rewrote HDR rle logic
1638 add monochrome TGA output
1640 rename private functions to avoid conflicts with stb_image.h
1644 casts to unsigned char to fix warnings
1646 first public release
1647 0.90 first internal release
1651 ------------------------------------------------------------------------------
1652 This software is available under 2 licenses -- choose whichever you prefer.
1653 ------------------------------------------------------------------------------
1654 ALTERNATIVE A - MIT License
1655 Copyright (c) 2017 Sean Barrett
1656 Permission is hereby granted, free of charge, to any person obtaining a copy of
1657 this software and associated documentation files (the "Software"), to deal in
1658 the Software without restriction, including without limitation the rights to
1659 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
1660 of the Software, and to permit persons to whom the Software is furnished to do
1661 so, subject to the following conditions:
1662 The above copyright notice and this permission notice shall be included in all
1663 copies or substantial portions of the Software.
1664 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1665 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1666 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1667 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1668 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1669 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1671 ------------------------------------------------------------------------------
1672 ALTERNATIVE B - Public Domain (www.unlicense.org)
1673 This is free and unencumbered software released into the public domain.
1674 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
1675 software, either in source code form or as a compiled binary, for any purpose,
1676 commercial or non-commercial, and by any means.
1677 In jurisdictions that recognize copyright laws, the author or authors of this
1678 software dedicate any and all copyright interest in the software to the public
1679 domain. We make this dedication for the benefit of the public at large and to
1680 the detriment of our heirs and successors. We intend this dedication to be an
1681 overt act of relinquishment in perpetuity of all present and future rights to
1682 this software under copyright law.
1683 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1684 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1685 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1686 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
1687 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
1688 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1689 ------------------------------------------------------------------------------