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