1#ifndef INCLUDE_STB_IMAGE_WRITE_H
2#define INCLUDE_STB_IMAGE_WRITE_H
3
4#include <stdlib.h>
5
6#ifndef STBIWDEF
7#ifdef STB_IMAGE_WRITE_STATIC
8#define STBIWDEF static
9#else
10#ifdef __cplusplus
11#define STBIWDEF extern "C"
12#else
13#define STBIWDEF extern
14#endif
15#endif
16#endif
17
18#ifndef STB_IMAGE_WRITE_STATIC
19STBIWDEF int stbi_write_tga_with_rle;
20STBIWDEF int stbi_write_png_compression_level;
21STBIWDEF int stbi_write_force_png_filter;
22#endif
23
24#ifndef STBI_WRITE_NO_STDIO
25STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
26STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
27STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
28STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
29STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality);
30
31#ifdef STBIW_WINDOWS_UTF8
32STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);
33#endif
34#endif
35
36typedef void stbi_write_func(void *context, void *data, int size);
37
38STBIWDEF 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);
39STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
40STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
41STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
42STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);
43
44STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean);
45
46#endif
47
48#ifdef STB_IMAGE_WRITE_IMPLEMENTATION
49
50#ifdef _WIN32
51 #ifndef _CRT_SECURE_NO_WARNINGS
52 #define _CRT_SECURE_NO_WARNINGS
53 #endif
54 #ifndef _CRT_NONSTDC_NO_DEPRECATE
55 #define _CRT_NONSTDC_NO_DEPRECATE
56 #endif
57#endif
58
59#ifndef STBI_WRITE_NO_STDIO
60#include <stdio.h>
61#endif
62
63#include <stdarg.h>
64#include <stdlib.h>
65#include <string.h>
66#include <math.h>
67
68#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED))
69
70#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED)
71
72#else
73#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)."
74#endif
75
76#ifndef STBIW_MALLOC
77#define STBIW_MALLOC(sz) malloc(sz)
78#define STBIW_REALLOC(p,newsz) realloc(p,newsz)
79#define STBIW_FREE(p) free(p)
80#endif
81
82#ifndef STBIW_REALLOC_SIZED
83#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz)
84#endif
85
86#ifndef STBIW_MEMMOVE
87#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz)
88#endif
89
90#ifndef STBIW_ASSERT
91#include <assert.h>
92#define STBIW_ASSERT(x) assert(x)
93#endif
94
95#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)
96
97#ifdef STB_IMAGE_WRITE_STATIC
98static int stbi_write_png_compression_level = 8;
99static int stbi_write_tga_with_rle = 1;
100static int stbi_write_force_png_filter = -1;
101#else
102int stbi_write_png_compression_level = 8;
103int stbi_write_tga_with_rle = 1;
104int stbi_write_force_png_filter = -1;
105#endif
106
107static int stbi__flip_vertically_on_write = 0;
108
109STBIWDEF void stbi_flip_vertically_on_write(int flag)
110{
111 stbi__flip_vertically_on_write = flag;
112}
113
114typedef struct
115{
116 stbi_write_func *func;
117 void *context;
118 unsigned char buffer[64];
119 int buf_used;
120} stbi__write_context;
121
122static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context)
123{
124 s->func = c;
125 s->context = context;
126}
127
128#ifndef STBI_WRITE_NO_STDIO
129
130static void stbi__stdio_write(void *context, void *data, int size)
131{
132 fwrite(data,1,size,(FILE*) context);
133}
134
135#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8)
136#ifdef __cplusplus
137#define STBIW_EXTERN extern "C"
138#else
139#define STBIW_EXTERN extern
140#endif
141STBIW_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide);
142STBIW_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);
143
144STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input)
145{
146 return WideCharToMultiByte(65001 , 0, input, -1, buffer, (int) bufferlen, NULL, NULL);
147}
148#endif
149
150static FILE *stbiw__fopen(char const *filename, char const *mode)
151{
152 FILE *f;
153#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8)
154 wchar_t wMode[64];
155 wchar_t wFilename[1024];
156 if (0 == MultiByteToWideChar(65001 , 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename)))
157 return 0;
158
159 if (0 == MultiByteToWideChar(65001 , 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode)))
160 return 0;
161
162#if defined(_MSC_VER) && _MSC_VER >= 1400
163 if (0 != _wfopen_s(&f, wFilename, wMode))
164 f = 0;
165#else
166 f = _wfopen(wFilename, wMode);
167#endif
168
169#elif defined(_MSC_VER) && _MSC_VER >= 1400
170 if (0 != fopen_s(&f, filename, mode))
171 f=0;
172#else
173 f = fopen(filename, mode);
174#endif
175 return f;
176}
177
178static int stbi__start_write_file(stbi__write_context *s, const char *filename)
179{
180 FILE *f = stbiw__fopen(filename, "wb");
181 stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f);
182 return f != NULL;
183}
184
185static void stbi__end_write_file(stbi__write_context *s)
186{
187 fclose((FILE *)s->context);
188}
189
190#endif
191
192typedef unsigned int stbiw_uint32;
193typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];
194
195static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v)
196{
197 while (*fmt) {
198 switch (*fmt++) {
199 case ' ': break;
200 case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int));
201 s->func(s->context,&x,1);
202 break; }
203 case '2': { int x = va_arg(v,int);
204 unsigned char b[2];
205 b[0] = STBIW_UCHAR(x);
206 b[1] = STBIW_UCHAR(x>>8);
207 s->func(s->context,b,2);
208 break; }
209 case '4': { stbiw_uint32 x = va_arg(v,int);
210 unsigned char b[4];
211 b[0]=STBIW_UCHAR(x);
212 b[1]=STBIW_UCHAR(x>>8);
213 b[2]=STBIW_UCHAR(x>>16);
214 b[3]=STBIW_UCHAR(x>>24);
215 s->func(s->context,b,4);
216 break; }
217 default:
218 STBIW_ASSERT(0);
219 return;
220 }
221 }
222}
223
224static void stbiw__writef(stbi__write_context *s, const char *fmt, ...)
225{
226 va_list v;
227 va_start(v, fmt);
228 stbiw__writefv(s, fmt, v);
229 va_end(v);
230}
231
232static void stbiw__write_flush(stbi__write_context *s)
233{
234 if (s->buf_used) {
235 s->func(s->context, &s->buffer, s->buf_used);
236 s->buf_used = 0;
237 }
238}
239
240static void stbiw__putc(stbi__write_context *s, unsigned char c)
241{
242 s->func(s->context, &c, 1);
243}
244
245static void stbiw__write1(stbi__write_context *s, unsigned char a)
246{
247 if ((size_t)s->buf_used + 1 > sizeof(s->buffer))
248 stbiw__write_flush(s);
249 s->buffer[s->buf_used++] = a;
250}
251
252static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c)
253{
254 int n;
255 if ((size_t)s->buf_used + 3 > sizeof(s->buffer))
256 stbiw__write_flush(s);
257 n = s->buf_used;
258 s->buf_used = n+3;
259 s->buffer[n+0] = a;
260 s->buffer[n+1] = b;
261 s->buffer[n+2] = c;
262}
263
264static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d)
265{
266 unsigned char bg[3] = { 255, 0, 255}, px[3];
267 int k;
268
269 if (write_alpha < 0)
270 stbiw__write1(s, d[comp - 1]);
271
272 switch (comp) {
273 case 2:
274 case 1:
275 if (expand_mono)
276 stbiw__write3(s, d[0], d[0], d[0]);
277 else
278 stbiw__write1(s, d[0]);
279 break;
280 case 4:
281 if (!write_alpha) {
282
283 for (k = 0; k < 3; ++k)
284 px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255;
285 stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]);
286 break;
287 }
288
289 case 3:
290 stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]);
291 break;
292 }
293 if (write_alpha > 0)
294 stbiw__write1(s, d[comp - 1]);
295}
296
297static 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)
298{
299 stbiw_uint32 zero = 0;
300 int i,j, j_end;
301
302 if (y <= 0)
303 return;
304
305 if (stbi__flip_vertically_on_write)
306 vdir *= -1;
307
308 if (vdir < 0) {
309 j_end = -1; j = y-1;
310 } else {
311 j_end = y; j = 0;
312 }
313
314 for (; j != j_end; j += vdir) {
315 for (i=0; i < x; ++i) {
316 unsigned char *d = (unsigned char *) data + (j*x+i)*comp;
317 stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d);
318 }
319 stbiw__write_flush(s);
320 s->func(s->context, &zero, scanline_pad);
321 }
322}
323
324static 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, ...)
325{
326 if (y < 0 || x < 0) {
327 return 0;
328 } else {
329 va_list v;
330 va_start(v, fmt);
331 stbiw__writefv(s, fmt, v);
332 va_end(v);
333 stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono);
334 return 1;
335 }
336}
337
338static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data)
339{
340 if (comp != 4) {
341
342 int pad = (-x*3) & 3;
343 return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad,
344 "11 4 22 4" "4 44 22 444444",
345 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40,
346 40, x,y, 1,24, 0,0,0,0,0,0);
347 } else {
348
349 return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *)data,1,0,
350 "11 4 22 4" "4 44 22 444444 4444 4 444 444 444 444",
351 'B', 'M', 14+108+x*y*4, 0, 0, 14+108,
352 108, x,y, 1,32, 3,0,0,0,0,0, 0xff0000,0xff00,0xff,0xff000000u, 0, 0,0,0, 0,0,0, 0,0,0, 0,0,0);
353 }
354}
355
356STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
357{
358 stbi__write_context s = { 0 };
359 stbi__start_write_callbacks(&s, func, context);
360 return stbi_write_bmp_core(&s, x, y, comp, data);
361}
362
363#ifndef STBI_WRITE_NO_STDIO
364STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)
365{
366 stbi__write_context s = { 0 };
367 if (stbi__start_write_file(&s,filename)) {
368 int r = stbi_write_bmp_core(&s, x, y, comp, data);
369 stbi__end_write_file(&s);
370 return r;
371 } else
372 return 0;
373}
374#endif
375
376static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data)
377{
378 int has_alpha = (comp == 2 || comp == 4);
379 int colorbytes = has_alpha ? comp-1 : comp;
380 int format = colorbytes < 2 ? 3 : 2;
381
382 if (y < 0 || x < 0)
383 return 0;
384
385 if (!stbi_write_tga_with_rle) {
386 return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0,
387 "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8);
388 } else {
389 int i,j,k;
390 int jend, jdir;
391
392 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);
393
394 if (stbi__flip_vertically_on_write) {
395 j = 0;
396 jend = y;
397 jdir = 1;
398 } else {
399 j = y-1;
400 jend = -1;
401 jdir = -1;
402 }
403 for (; j != jend; j += jdir) {
404 unsigned char *row = (unsigned char *) data + j * x * comp;
405 int len;
406
407 for (i = 0; i < x; i += len) {
408 unsigned char *begin = row + i * comp;
409 int diff = 1;
410 len = 1;
411
412 if (i < x - 1) {
413 ++len;
414 diff = memcmp(begin, row + (i + 1) * comp, comp);
415 if (diff) {
416 const unsigned char *prev = begin;
417 for (k = i + 2; k < x && len < 128; ++k) {
418 if (memcmp(prev, row + k * comp, comp)) {
419 prev += comp;
420 ++len;
421 } else {
422 --len;
423 break;
424 }
425 }
426 } else {
427 for (k = i + 2; k < x && len < 128; ++k) {
428 if (!memcmp(begin, row + k * comp, comp)) {
429 ++len;
430 } else {
431 break;
432 }
433 }
434 }
435 }
436
437 if (diff) {
438 unsigned char header = STBIW_UCHAR(len - 1);
439 stbiw__write1(s, header);
440 for (k = 0; k < len; ++k) {
441 stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp);
442 }
443 } else {
444 unsigned char header = STBIW_UCHAR(len - 129);
445 stbiw__write1(s, header);
446 stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin);
447 }
448 }
449 }
450 stbiw__write_flush(s);
451 }
452 return 1;
453}
454
455STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)
456{
457 stbi__write_context s = { 0 };
458 stbi__start_write_callbacks(&s, func, context);
459 return stbi_write_tga_core(&s, x, y, comp, (void *) data);
460}
461
462#ifndef STBI_WRITE_NO_STDIO
463STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)
464{
465 stbi__write_context s = { 0 };
466 if (stbi__start_write_file(&s,filename)) {
467 int r = stbi_write_tga_core(&s, x, y, comp, (void *) data);
468 stbi__end_write_file(&s);
469 return r;
470 } else
471 return 0;
472}
473#endif
474
475#define stbiw__max(a, b) ((a) > (b) ? (a) : (b))
476
477#ifndef STBI_WRITE_NO_STDIO
478
479static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)
480{
481 int exponent;
482 float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2]));
483
484 if (maxcomp < 1e-32f) {
485 rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
486 } else {
487 float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp;
488
489 rgbe[0] = (unsigned char)(linear[0] * normalize);
490 rgbe[1] = (unsigned char)(linear[1] * normalize);
491 rgbe[2] = (unsigned char)(linear[2] * normalize);
492 rgbe[3] = (unsigned char)(exponent + 128);
493 }
494}
495
496static void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte)
497{
498 unsigned char lengthbyte = STBIW_UCHAR(length+128);
499 STBIW_ASSERT(length+128 <= 255);
500 s->func(s->context, &lengthbyte, 1);
501 s->func(s->context, &databyte, 1);
502}
503
504static void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data)
505{
506 unsigned char lengthbyte = STBIW_UCHAR(length);
507 STBIW_ASSERT(length <= 128);
508 s->func(s->context, &lengthbyte, 1);
509 s->func(s->context, data, length);
510}
511
512static void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline)
513{
514 unsigned char scanlineheader[4] = { 2, 2, 0, 0 };
515 unsigned char rgbe[4];
516 float linear[3];
517 int x;
518
519 scanlineheader[2] = (width&0xff00)>>8;
520 scanlineheader[3] = (width&0x00ff);
521
522 if (width < 8 || width >= 32768) {
523 for (x=0; x < width; x++) {
524 switch (ncomp) {
525 case 4:
526 case 3: linear[2] = scanline[x*ncomp + 2];
527 linear[1] = scanline[x*ncomp + 1];
528 linear[0] = scanline[x*ncomp + 0];
529 break;
530 default:
531 linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];
532 break;
533 }
534 stbiw__linear_to_rgbe(rgbe, linear);
535 s->func(s->context, rgbe, 4);
536 }
537 } else {
538 int c,r;
539
540 for (x=0; x < width; x++) {
541 switch(ncomp) {
542 case 4:
543 case 3: linear[2] = scanline[x*ncomp + 2];
544 linear[1] = scanline[x*ncomp + 1];
545 linear[0] = scanline[x*ncomp + 0];
546 break;
547 default:
548 linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];
549 break;
550 }
551 stbiw__linear_to_rgbe(rgbe, linear);
552 scratch[x + width*0] = rgbe[0];
553 scratch[x + width*1] = rgbe[1];
554 scratch[x + width*2] = rgbe[2];
555 scratch[x + width*3] = rgbe[3];
556 }
557
558 s->func(s->context, scanlineheader, 4);
559
560 for (c=0; c < 4; c++) {
561 unsigned char *comp = &scratch[width*c];
562
563 x = 0;
564 while (x < width) {
565
566 r = x;
567 while (r+2 < width) {
568 if (comp[r] == comp[r+1] && comp[r] == comp[r+2])
569 break;
570 ++r;
571 }
572 if (r+2 >= width)
573 r = width;
574
575 while (x < r) {
576 int len = r-x;
577 if (len > 128) len = 128;
578 stbiw__write_dump_data(s, len, &comp[x]);
579 x += len;
580 }
581
582 if (r+2 < width) {
583
584 while (r < width && comp[r] == comp[x])
585 ++r;
586
587 while (x < r) {
588 int len = r-x;
589 if (len > 127) len = 127;
590 stbiw__write_run_data(s, len, comp[x]);
591 x += len;
592 }
593 }
594 }
595 }
596 }
597}
598
599static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data)
600{
601 if (y <= 0 || x <= 0 || data == NULL)
602 return 0;
603 else {
604
605 unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4);
606 int i, len;
607 char buffer[128];
608 char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n";
609 s->func(s->context, header, sizeof(header)-1);
610
611#ifdef __STDC_LIB_EXT1__
612 len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
613#else
614 len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
615#endif
616 s->func(s->context, buffer, len);
617
618 for(i=0; i < y; i++)
619 stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i));
620 STBIW_FREE(scratch);
621 return 1;
622 }
623}
624
625STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data)
626{
627 stbi__write_context s = { 0 };
628 stbi__start_write_callbacks(&s, func, context);
629 return stbi_write_hdr_core(&s, x, y, comp, (float *) data);
630}
631
632STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)
633{
634 stbi__write_context s = { 0 };
635 if (stbi__start_write_file(&s,filename)) {
636 int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data);
637 stbi__end_write_file(&s);
638 return r;
639 } else
640 return 0;
641}
642#endif
643
644#ifndef STBIW_ZLIB_COMPRESS
645
646#define stbiw__sbraw(a) ((int *) (void *) (a) - 2)
647#define stbiw__sbm(a) stbiw__sbraw(a)[0]
648#define stbiw__sbn(a) stbiw__sbraw(a)[1]
649
650#define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a))
651#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0)
652#define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a)))
653
654#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v))
655#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0)
656#define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0)
657
658static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)
659{
660 int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1;
661 void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2);
662 STBIW_ASSERT(p);
663 if (p) {
664 if (!*arr) ((int *) p)[1] = 0;
665 *arr = (void *) ((int *) p + 2);
666 stbiw__sbm(*arr) = m;
667 }
668 return *arr;
669}
670
671static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)
672{
673 while (*bitcount >= 8) {
674 stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer));
675 *bitbuffer >>= 8;
676 *bitcount -= 8;
677 }
678 return data;
679}
680
681static int stbiw__zlib_bitrev(int code, int codebits)
682{
683 int res=0;
684 while (codebits--) {
685 res = (res << 1) | (code & 1);
686 code >>= 1;
687 }
688 return res;
689}
690
691static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit)
692{
693 int i;
694 for (i=0; i < limit && i < 258; ++i)
695 if (a[i] != b[i]) break;
696 return i;
697}
698
699static unsigned int stbiw__zhash(unsigned char *data)
700{
701 stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16);
702 hash ^= hash << 3;
703 hash += hash >> 5;
704 hash ^= hash << 4;
705 hash += hash >> 17;
706 hash ^= hash << 25;
707 hash += hash >> 6;
708 return hash;
709}
710
711#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount))
712#define stbiw__zlib_add(code,codebits) \
713 (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush())
714#define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c)
715
716#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8)
717#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9)
718#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7)
719#define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8)
720#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))
721#define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n))
722
723#define stbiw__ZHASH 16384
724
725#endif
726
727STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)
728{
729#ifdef STBIW_ZLIB_COMPRESS
730
731 return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality);
732#else
733 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 };
734 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 };
735 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 };
736 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 };
737 unsigned int bitbuf=0;
738 int i,j, bitcount=0;
739 unsigned char *out = NULL;
740 unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(unsigned char**));
741 if (hash_table == NULL)
742 return NULL;
743 if (quality < 5) quality = 5;
744
745 stbiw__sbpush(out, 0x78);
746 stbiw__sbpush(out, 0x5e);
747 stbiw__zlib_add(1,1);
748 stbiw__zlib_add(1,2);
749
750 for (i=0; i < stbiw__ZHASH; ++i)
751 hash_table[i] = NULL;
752
753 i=0;
754 while (i < data_len-3) {
755
756 int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3;
757 unsigned char *bestloc = 0;
758 unsigned char **hlist = hash_table[h];
759 int n = stbiw__sbcount(hlist);
760 for (j=0; j < n; ++j) {
761 if (hlist[j]-data > i-32768) {
762 int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i);
763 if (d >= best) { best=d; bestloc=hlist[j]; }
764 }
765 }
766
767 if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) {
768 STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);
769 stbiw__sbn(hash_table[h]) = quality;
770 }
771 stbiw__sbpush(hash_table[h],data+i);
772
773 if (bestloc) {
774
775 h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1);
776 hlist = hash_table[h];
777 n = stbiw__sbcount(hlist);
778 for (j=0; j < n; ++j) {
779 if (hlist[j]-data > i-32767) {
780 int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1);
781 if (e > best) {
782 bestloc = NULL;
783 break;
784 }
785 }
786 }
787 }
788
789 if (bestloc) {
790 int d = (int) (data+i - bestloc);
791 STBIW_ASSERT(d <= 32767 && best <= 258);
792 for (j=0; best > lengthc[j+1]-1; ++j);
793 stbiw__zlib_huff(j+257);
794 if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]);
795 for (j=0; d > distc[j+1]-1; ++j);
796 stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5);
797 if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]);
798 i += best;
799 } else {
800 stbiw__zlib_huffb(data[i]);
801 ++i;
802 }
803 }
804
805 for (;i < data_len; ++i)
806 stbiw__zlib_huffb(data[i]);
807 stbiw__zlib_huff(256);
808
809 while (bitcount)
810 stbiw__zlib_add(0,1);
811
812 for (i=0; i < stbiw__ZHASH; ++i)
813 (void) stbiw__sbfree(hash_table[i]);
814 STBIW_FREE(hash_table);
815
816 if (stbiw__sbn(out) > data_len + 2 + ((data_len+32766)/32767)*5) {
817 stbiw__sbn(out) = 2;
818 for (j = 0; j < data_len;) {
819 int blocklen = data_len - j;
820 if (blocklen > 32767) blocklen = 32767;
821 stbiw__sbpush(out, data_len - j == blocklen);
822 stbiw__sbpush(out, STBIW_UCHAR(blocklen));
823 stbiw__sbpush(out, STBIW_UCHAR(blocklen >> 8));
824 stbiw__sbpush(out, STBIW_UCHAR(~blocklen));
825 stbiw__sbpush(out, STBIW_UCHAR(~blocklen >> 8));
826 memcpy(out+stbiw__sbn(out), data+j, blocklen);
827 stbiw__sbn(out) += blocklen;
828 j += blocklen;
829 }
830 }
831
832 {
833
834 unsigned int s1=1, s2=0;
835 int blocklen = (int) (data_len % 5552);
836 j=0;
837 while (j < data_len) {
838 for (i=0; i < blocklen; ++i) { s1 += data[j+i]; s2 += s1; }
839 s1 %= 65521; s2 %= 65521;
840 j += blocklen;
841 blocklen = 5552;
842 }
843 stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8));
844 stbiw__sbpush(out, STBIW_UCHAR(s2));
845 stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8));
846 stbiw__sbpush(out, STBIW_UCHAR(s1));
847 }
848 *out_len = stbiw__sbn(out);
849
850 STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len);
851 return (unsigned char *) stbiw__sbraw(out);
852#endif
853}
854
855static unsigned int stbiw__crc32(unsigned char *buffer, int len)
856{
857#ifdef STBIW_CRC32
858 return STBIW_CRC32(buffer, len);
859#else
860 static unsigned int crc_table[256] =
861 {
862 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
863 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
864 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
865 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
866 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
867 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
868 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
869 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
870 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
871 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
872 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
873 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
874 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
875 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
876 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
877 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
878 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
879 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
880 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
881 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
882 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
883 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
884 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
885 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
886 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
887 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
888 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
889 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
890 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
891 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
892 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
893 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
894 };
895
896 unsigned int crc = ~0u;
897 int i;
898 for (i=0; i < len; ++i)
899 crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];
900 return ~crc;
901#endif
902}
903
904#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)
905#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));
906#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3])
907
908static void stbiw__wpcrc(unsigned char **data, int len)
909{
910 unsigned int crc = stbiw__crc32(*data - len - 4, len+4);
911 stbiw__wp32(*data, crc);
912}
913
914static unsigned char stbiw__paeth(int a, int b, int c)
915{
916 int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c);
917 if (pa <= pb && pa <= pc) return STBIW_UCHAR(a);
918 if (pb <= pc) return STBIW_UCHAR(b);
919 return STBIW_UCHAR(c);
920}
921
922static 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)
923{
924 static int mapping[] = { 0,1,2,3,4 };
925 static int firstmap[] = { 0,1,0,5,6 };
926 int *mymap = (y != 0) ? mapping : firstmap;
927 int i;
928 int type = mymap[filter_type];
929 unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y);
930 int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes;
931
932 if (type==0) {
933 memcpy(line_buffer, z, width*n);
934 return;
935 }
936
937 for (i = 0; i < n; ++i) {
938 switch (type) {
939 case 1: line_buffer[i] = z[i]; break;
940 case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break;
941 case 3: line_buffer[i] = z[i] - (z[i-signed_stride]>>1); break;
942 case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-signed_stride],0)); break;
943 case 5: line_buffer[i] = z[i]; break;
944 case 6: line_buffer[i] = z[i]; break;
945 }
946 }
947 switch (type) {
948 case 1: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-n]; break;
949 case 2: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-signed_stride]; break;
950 case 3: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break;
951 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;
952 case 5: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - (z[i-n]>>1); break;
953 case 6: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break;
954 }
955}
956
957STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)
958{
959 int force_filter = stbi_write_force_png_filter;
960 int ctype[5] = { -1, 0, 4, 2, 6 };
961 unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };
962 unsigned char *out,*o, *filt, *zlib;
963 signed char *line_buffer;
964 int j,zlen;
965
966 if (stride_bytes == 0)
967 stride_bytes = x * n;
968
969 if (force_filter >= 5) {
970 force_filter = -1;
971 }
972
973 filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0;
974 line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; }
975 for (j=0; j < y; ++j) {
976 int filter_type;
977 if (force_filter > -1) {
978 filter_type = force_filter;
979 stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer);
980 } else {
981 int best_filter = 0, best_filter_val = 0x7fffffff, est, i;
982 for (filter_type = 0; filter_type < 5; filter_type++) {
983 stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer);
984
985 est = 0;
986 for (i = 0; i < x*n; ++i) {
987 est += abs((signed char) line_buffer[i]);
988 }
989 if (est < best_filter_val) {
990 best_filter_val = est;
991 best_filter = filter_type;
992 }
993 }
994 if (filter_type != best_filter) {
995 stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer);
996 filter_type = best_filter;
997 }
998 }
999
1000 filt[j*(x*n+1)] = (unsigned char) filter_type;
1001 STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n);
1002 }
1003 STBIW_FREE(line_buffer);
1004 zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_compression_level);
1005 STBIW_FREE(filt);
1006 if (!zlib) return 0;
1007
1008 out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12);
1009 if (!out) return 0;
1010 *out_len = 8 + 12+13 + 12+zlen + 12;
1011
1012 o=out;
1013 STBIW_MEMMOVE(o,sig,8); o+= 8;
1014 stbiw__wp32(o, 13);
1015 stbiw__wptag(o, "IHDR");
1016 stbiw__wp32(o, x);
1017 stbiw__wp32(o, y);
1018 *o++ = 8;
1019 *o++ = STBIW_UCHAR(ctype[n]);
1020 *o++ = 0;
1021 *o++ = 0;
1022 *o++ = 0;
1023 stbiw__wpcrc(&o,13);
1024
1025 stbiw__wp32(o, zlen);
1026 stbiw__wptag(o, "IDAT");
1027 STBIW_MEMMOVE(o, zlib, zlen);
1028 o += zlen;
1029 STBIW_FREE(zlib);
1030 stbiw__wpcrc(&o, zlen);
1031
1032 stbiw__wp32(o,0);
1033 stbiw__wptag(o, "IEND");
1034 stbiw__wpcrc(&o,0);
1035
1036 STBIW_ASSERT(o == out + *out_len);
1037
1038 return out;
1039}
1040
1041#ifndef STBI_WRITE_NO_STDIO
1042STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)
1043{
1044 FILE *f;
1045 int len;
1046 unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len);
1047 if (png == NULL) return 0;
1048
1049 f = stbiw__fopen(filename, "wb");
1050 if (!f) { STBIW_FREE(png); return 0; }
1051 fwrite(png, 1, len, f);
1052 fclose(f);
1053 STBIW_FREE(png);
1054 return 1;
1055}
1056#endif
1057
1058STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes)
1059{
1060 int len;
1061 unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len);
1062 if (png == NULL) return 0;
1063 func(context, png, len);
1064 STBIW_FREE(png);
1065 return 1;
1066}
1067
1068static 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,
1069 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 };
1070
1071static void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) {
1072 int bitBuf = *bitBufP, bitCnt = *bitCntP;
1073 bitCnt += bs[1];
1074 bitBuf |= bs[0] << (24 - bitCnt);
1075 while(bitCnt >= 8) {
1076 unsigned char c = (bitBuf >> 16) & 255;
1077 stbiw__putc(s, c);
1078 if(c == 255) {
1079 stbiw__putc(s, 0);
1080 }
1081 bitBuf <<= 8;
1082 bitCnt -= 8;
1083 }
1084 *bitBufP = bitBuf;
1085 *bitCntP = bitCnt;
1086}
1087
1088static void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) {
1089 float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p;
1090 float z1, z2, z3, z4, z5, z11, z13;
1091
1092 float tmp0 = d0 + d7;
1093 float tmp7 = d0 - d7;
1094 float tmp1 = d1 + d6;
1095 float tmp6 = d1 - d6;
1096 float tmp2 = d2 + d5;
1097 float tmp5 = d2 - d5;
1098 float tmp3 = d3 + d4;
1099 float tmp4 = d3 - d4;
1100
1101 float tmp10 = tmp0 + tmp3;
1102 float tmp13 = tmp0 - tmp3;
1103 float tmp11 = tmp1 + tmp2;
1104 float tmp12 = tmp1 - tmp2;
1105
1106 d0 = tmp10 + tmp11;
1107 d4 = tmp10 - tmp11;
1108
1109 z1 = (tmp12 + tmp13) * 0.707106781f;
1110 d2 = tmp13 + z1;
1111 d6 = tmp13 - z1;
1112
1113 tmp10 = tmp4 + tmp5;
1114 tmp11 = tmp5 + tmp6;
1115 tmp12 = tmp6 + tmp7;
1116
1117 z5 = (tmp10 - tmp12) * 0.382683433f;
1118 z2 = tmp10 * 0.541196100f + z5;
1119 z4 = tmp12 * 1.306562965f + z5;
1120 z3 = tmp11 * 0.707106781f;
1121
1122 z11 = tmp7 + z3;
1123 z13 = tmp7 - z3;
1124
1125 *d5p = z13 + z2;
1126 *d3p = z13 - z2;
1127 *d1p = z11 + z4;
1128 *d7p = z11 - z4;
1129
1130 *d0p = d0; *d2p = d2; *d4p = d4; *d6p = d6;
1131}
1132
1133static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) {
1134 int tmp1 = val < 0 ? -val : val;
1135 val = val < 0 ? val-1 : val;
1136 bits[1] = 1;
1137 while(tmp1 >>= 1) {
1138 ++bits[1];
1139 }
1140 bits[0] = val & ((1<<bits[1])-1);
1141}
1142
1143static 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]) {
1144 const unsigned short EOB[2] = { HTAC[0x00][0], HTAC[0x00][1] };
1145 const unsigned short M16zeroes[2] = { HTAC[0xF0][0], HTAC[0xF0][1] };
1146 int dataOff, i, j, n, diff, end0pos, x, y;
1147 int DU[64];
1148
1149 for(dataOff=0, n=du_stride*8; dataOff<n; dataOff+=du_stride) {
1150 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]);
1151 }
1152
1153 for(dataOff=0; dataOff<8; ++dataOff) {
1154 stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+du_stride], &CDU[dataOff+du_stride*2], &CDU[dataOff+du_stride*3], &CDU[dataOff+du_stride*4],
1155 &CDU[dataOff+du_stride*5], &CDU[dataOff+du_stride*6], &CDU[dataOff+du_stride*7]);
1156 }
1157
1158 for(y = 0, j=0; y < 8; ++y) {
1159 for(x = 0; x < 8; ++x,++j) {
1160 float v;
1161 i = y*du_stride+x;
1162 v = CDU[i]*fdtbl[j];
1163
1164 DU[stbiw__jpg_ZigZag[j]] = (int)(v < 0 ? v - 0.5f : v + 0.5f);
1165 }
1166 }
1167
1168 diff = DU[0] - DC;
1169 if (diff == 0) {
1170 stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[0]);
1171 } else {
1172 unsigned short bits[2];
1173 stbiw__jpg_calcBits(diff, bits);
1174 stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[bits[1]]);
1175 stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits);
1176 }
1177
1178 end0pos = 63;
1179 for(; (end0pos>0)&&(DU[end0pos]==0); --end0pos) {
1180 }
1181
1182 if(end0pos == 0) {
1183 stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB);
1184 return DU[0];
1185 }
1186 for(i = 1; i <= end0pos; ++i) {
1187 int startpos = i;
1188 int nrzeroes;
1189 unsigned short bits[2];
1190 for (; DU[i]==0 && i<=end0pos; ++i) {
1191 }
1192 nrzeroes = i-startpos;
1193 if ( nrzeroes >= 16 ) {
1194 int lng = nrzeroes>>4;
1195 int nrmarker;
1196 for (nrmarker=1; nrmarker <= lng; ++nrmarker)
1197 stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes);
1198 nrzeroes &= 15;
1199 }
1200 stbiw__jpg_calcBits(DU[i], bits);
1201 stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]]);
1202 stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits);
1203 }
1204 if(end0pos != 63) {
1205 stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB);
1206 }
1207 return DU[0];
1208}
1209
1210static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) {
1211
1212 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};
1213 static const unsigned char std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11};
1214 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};
1215 static const unsigned char std_ac_luminance_values[] = {
1216 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,
1217 0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,
1218 0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,
1219 0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,
1220 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,
1221 0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,
1222 0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa
1223 };
1224 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};
1225 static const unsigned char std_dc_chrominance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11};
1226 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};
1227 static const unsigned char std_ac_chrominance_values[] = {
1228 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,
1229 0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,
1230 0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,
1231 0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87,
1232 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,
1233 0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,
1234 0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa
1235 };
1236
1237 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}};
1238 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}};
1239 static const unsigned short YAC_HT[256][2] = {
1240 {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},
1241 {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},
1242 {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},
1243 {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},
1244 {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},
1245 {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},
1246 {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},
1247 {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},
1248 {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},
1249 {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},
1250 {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},
1251 {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},
1252 {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},
1253 {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},
1254 {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},
1255 {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}
1256 };
1257 static const unsigned short UVAC_HT[256][2] = {
1258 {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},
1259 {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},
1260 {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},
1261 {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},
1262 {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},
1263 {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},
1264 {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},
1265 {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},
1266 {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},
1267 {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},
1268 {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},
1269 {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},
1270 {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},
1271 {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},
1272 {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},
1273 {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}
1274 };
1275 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,
1276 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};
1277 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,
1278 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};
1279 static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f,
1280 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f };
1281
1282 int row, col, i, k, subsample;
1283 float fdtbl_Y[64], fdtbl_UV[64];
1284 unsigned char YTable[64], UVTable[64];
1285
1286 if(!data || !width || !height || comp > 4 || comp < 1) {
1287 return 0;
1288 }
1289
1290 quality = quality ? quality : 90;
1291 subsample = quality <= 90 ? 1 : 0;
1292 quality = quality < 1 ? 1 : quality > 100 ? 100 : quality;
1293 quality = quality < 50 ? 5000 / quality : 200 - quality * 2;
1294
1295 for(i = 0; i < 64; ++i) {
1296 int uvti, yti = (YQT[i]*quality+50)/100;
1297 YTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (yti < 1 ? 1 : yti > 255 ? 255 : yti);
1298 uvti = (UVQT[i]*quality+50)/100;
1299 UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti);
1300 }
1301
1302 for(row = 0, k = 0; row < 8; ++row) {
1303 for(col = 0; col < 8; ++col, ++k) {
1304 fdtbl_Y[k] = 1 / (YTable [stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]);
1305 fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]);
1306 }
1307 }
1308
1309 {
1310 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 };
1311 static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 };
1312 const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width),
1313 3,1,(unsigned char)(subsample?0x22:0x11),0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 };
1314 s->func(s->context, (void*)head0, sizeof(head0));
1315 s->func(s->context, (void*)YTable, sizeof(YTable));
1316 stbiw__putc(s, 1);
1317 s->func(s->context, UVTable, sizeof(UVTable));
1318 s->func(s->context, (void*)head1, sizeof(head1));
1319 s->func(s->context, (void*)(std_dc_luminance_nrcodes+1), sizeof(std_dc_luminance_nrcodes)-1);
1320 s->func(s->context, (void*)std_dc_luminance_values, sizeof(std_dc_luminance_values));
1321 stbiw__putc(s, 0x10);
1322 s->func(s->context, (void*)(std_ac_luminance_nrcodes+1), sizeof(std_ac_luminance_nrcodes)-1);
1323 s->func(s->context, (void*)std_ac_luminance_values, sizeof(std_ac_luminance_values));
1324 stbiw__putc(s, 1);
1325 s->func(s->context, (void*)(std_dc_chrominance_nrcodes+1), sizeof(std_dc_chrominance_nrcodes)-1);
1326 s->func(s->context, (void*)std_dc_chrominance_values, sizeof(std_dc_chrominance_values));
1327 stbiw__putc(s, 0x11);
1328 s->func(s->context, (void*)(std_ac_chrominance_nrcodes+1), sizeof(std_ac_chrominance_nrcodes)-1);
1329 s->func(s->context, (void*)std_ac_chrominance_values, sizeof(std_ac_chrominance_values));
1330 s->func(s->context, (void*)head2, sizeof(head2));
1331 }
1332
1333 {
1334 static const unsigned short fillBits[] = {0x7F, 7};
1335 int DCY=0, DCU=0, DCV=0;
1336 int bitBuf=0, bitCnt=0;
1337
1338 int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0;
1339 const unsigned char *dataR = (const unsigned char *)data;
1340 const unsigned char *dataG = dataR + ofsG;
1341 const unsigned char *dataB = dataR + ofsB;
1342 int x, y, pos;
1343 if(subsample) {
1344 for(y = 0; y < height; y += 16) {
1345 for(x = 0; x < width; x += 16) {
1346 float Y[256], U[256], V[256];
1347 for(row = y, pos = 0; row < y+16; ++row) {
1348
1349 int clamped_row = (row < height) ? row : height - 1;
1350 int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp;
1351 for(col = x; col < x+16; ++col, ++pos) {
1352
1353 int p = base_p + ((col < width) ? col : (width-1))*comp;
1354 float r = dataR[p], g = dataG[p], b = dataB[p];
1355 Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128;
1356 U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b;
1357 V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b;
1358 }
1359 }
1360 DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+0, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);
1361 DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+8, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);
1362 DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+128, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);
1363 DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+136, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);
1364
1365 {
1366 float subU[64], subV[64];
1367 int yy, xx;
1368 for(yy = 0, pos = 0; yy < 8; ++yy) {
1369 for(xx = 0; xx < 8; ++xx, ++pos) {
1370 int j = yy*32+xx*2;
1371 subU[pos] = (U[j+0] + U[j+1] + U[j+16] + U[j+17]) * 0.25f;
1372 subV[pos] = (V[j+0] + V[j+1] + V[j+16] + V[j+17]) * 0.25f;
1373 }
1374 }
1375 DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
1376 DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);
1377 }
1378 }
1379 }
1380 } else {
1381 for(y = 0; y < height; y += 8) {
1382 for(x = 0; x < width; x += 8) {
1383 float Y[64], U[64], V[64];
1384 for(row = y, pos = 0; row < y+8; ++row) {
1385
1386 int clamped_row = (row < height) ? row : height - 1;
1387 int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp;
1388 for(col = x; col < x+8; ++col, ++pos) {
1389
1390 int p = base_p + ((col < width) ? col : (width-1))*comp;
1391 float r = dataR[p], g = dataG[p], b = dataB[p];
1392 Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128;
1393 U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b;
1394 V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b;
1395 }
1396 }
1397
1398 DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y, DCY, YDC_HT, YAC_HT);
1399 DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
1400 DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);
1401 }
1402 }
1403 }
1404
1405 stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits);
1406 }
1407
1408 stbiw__putc(s, 0xFF);
1409 stbiw__putc(s, 0xD9);
1410
1411 return 1;
1412}
1413
1414STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality)
1415{
1416 stbi__write_context s = { 0 };
1417 stbi__start_write_callbacks(&s, func, context);
1418 return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality);
1419}
1420
1421#ifndef STBI_WRITE_NO_STDIO
1422STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality)
1423{
1424 stbi__write_context s = { 0 };
1425 if (stbi__start_write_file(&s,filename)) {
1426 int r = stbi_write_jpg_core(&s, x, y, comp, data, quality);
1427 stbi__end_write_file(&s);
1428 return r;
1429 } else
1430 return 0;
1431}
1432#endif
1433
1434#endif