├── .github
└── FUNDING.yml
├── CMakeLists.txt
├── LICENSE
├── README.md
├── skin_smoothing.c
├── stb_image.h
└── stb_image_write.h
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: https://www.paypal.com/paypalme/cpuimage/
13 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | CMAKE_MINIMUM_REQUIRED(VERSION 2.4)
2 | project(skin_smoothing)
3 | SET(CMAKE_BUILD_TYPE "Release")
4 | add_executable(skin_smoothing skin_smoothing.c)
5 | target_link_libraries(skin_smoothing -lm)
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2020 Zhihan Gao
2 |
3 | MIT License
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Skin Smoothing
2 | an efficient algorithm for skin smoothing implementation in c
3 |
4 | ## The algorithm steps are as follows
5 | 1. detect skin color, adapt radius according to skin color ratio
6 |
7 | 2. perform edge detection to obtain a edge map && smoothing level for apply skin denoise
8 |
9 | 3. re-detect skin color based on the denoise results, filtered non-skin areas
10 |
11 | ## Donating
12 | If you found this project useful, consider buying me a coffee
13 |
14 |
--------------------------------------------------------------------------------
/skin_smoothing.c:
--------------------------------------------------------------------------------
1 | #define STB_IMAGE_IMPLEMENTATION
2 |
3 | #include "stb_image.h"
4 |
5 | #define STB_IMAGE_WRITE_IMPLEMENTATION
6 |
7 | #include "stb_image_write.h"
8 | #include
9 | #include
10 | #include
11 |
12 | #ifndef min
13 | #define min(a, b) (((a) < (b)) ? (a) : (b))
14 | #endif
15 |
16 | #ifndef max
17 | #define max(a, b) (((a) > (b)) ? (a) : (b))
18 | #endif
19 |
20 | #ifndef ClampToByte
21 | #define ClampToByte(v) (((unsigned)(int)(v)) <(255) ? (v) : (v < 0) ? (0) : (255))
22 | #endif
23 |
24 | #include
25 |
26 | #if defined(__APPLE__)
27 | # include
28 | #elif defined(_WIN32)
29 | # define WIN32_LEAN_AND_MEAN
30 |
31 | # include
32 |
33 | #else // __linux
34 |
35 | # include
36 |
37 | # ifndef CLOCK_MONOTONIC //_RAW
38 | # define CLOCK_MONOTONIC CLOCK_REALTIME
39 | # endif
40 | #endif
41 |
42 | static
43 | uint64_t nanotimer() {
44 | static int ever = 0;
45 | #if defined(__APPLE__)
46 | static mach_timebase_info_data_t frequency;
47 | if (!ever) {
48 | if (mach_timebase_info(&frequency) != KERN_SUCCESS) {
49 | return 0;
50 | }
51 | ever = 1;
52 | }
53 | return (mach_absolute_time() * frequency.numer / frequency.denom);
54 | #elif defined(_WIN32)
55 | static LARGE_INTEGER frequency;
56 | if (!ever) {
57 | QueryPerformanceFrequency(&frequency);
58 | ever = 1;
59 | }
60 | LARGE_INTEGER t;
61 | QueryPerformanceCounter(&t);
62 | return (t.QuadPart * (uint64_t) 1e9) / frequency.QuadPart;
63 | #else // __linux
64 | struct timespec t;
65 | if (!ever) {
66 | if (clock_gettime(CLOCK_MONOTONIC, &t) != 0) {
67 | return 0;
68 | }
69 | ever = 1;
70 | }
71 | clock_gettime(CLOCK_MONOTONIC, &t);
72 | return (t.tv_sec * (uint64_t) 1e9) + t.tv_nsec;
73 | #endif
74 | }
75 |
76 |
77 | static double now() {
78 | static uint64_t epoch = 0;
79 | if (!epoch) {
80 | epoch = nanotimer();
81 | }
82 | return (nanotimer() - epoch) / 1e9;
83 | };
84 |
85 | double calcElapsed(double start, double end) {
86 | double took = -start;
87 | return took + end;
88 | }
89 |
90 | unsigned char *loadImage(const char *filename, int *width, int *height, int *channels) {
91 | return stbi_load(filename, width, height, channels, 0);
92 | }
93 |
94 | void saveImage(const char *filename, int width, int height, int channels, unsigned char *Output) {
95 | if (!stbi_write_jpg(filename, width, height, channels, Output, 100)) {
96 | fprintf(stderr, "save file fail.\n");
97 | return;
98 | }
99 | }
100 |
101 | void splitpath(const char *path, char *drv, char *dir, char *name, char *ext) {
102 | const char *end;
103 | const char *p;
104 | const char *s;
105 | if (path[0] && path[1] == ':') {
106 | if (drv) {
107 | *drv++ = *path++;
108 | *drv++ = *path++;
109 | *drv = '\0';
110 | }
111 | } else if (drv)
112 | *drv = '\0';
113 | for (end = path; *end && *end != ':';)
114 | end++;
115 | for (p = end; p > path && *--p != '\\' && *p != '/';)
116 | if (*p == '.') {
117 | end = p;
118 | break;
119 | }
120 | if (ext)
121 | for (s = end; (*ext = *s++);)
122 | ext++;
123 | for (p = end; p > path;)
124 | if (*--p == '\\' || *p == '/') {
125 | p++;
126 | break;
127 | }
128 | if (name) {
129 | for (s = p; s < end;)
130 | *name++ = *s++;
131 | *name = '\0';
132 | }
133 | if (dir) {
134 | for (s = path; s < p;)
135 | *dir++ = *s++;
136 | *dir = '\0';
137 | }
138 | }
139 |
140 |
141 | unsigned int skinDetection(unsigned char *rgb_src, int width, int height, int channels) {
142 | int stride = width * channels;
143 | int lastCol = width * channels - channels;
144 | int lastRow = height * stride - stride;
145 | unsigned int sum = 0;
146 | for (int y = 0; y < height; y++) {
147 | int cur_row = stride * y;
148 | int next_row = min(cur_row + stride, lastRow);
149 | unsigned char *next_scanLine = rgb_src + next_row;
150 | unsigned char *cur_scanLine = rgb_src + cur_row;
151 | for (int x = 0; x < width; x++) {
152 | int cur_col = x * channels;
153 | int next_col = min(cur_col + channels, lastCol);
154 | unsigned char *c00 = cur_scanLine + cur_col;
155 | unsigned char *c10 = cur_scanLine + next_col;
156 | unsigned char *c01 = next_scanLine + cur_col;
157 | unsigned char *c11 = next_scanLine + next_col;
158 | int r_avg = ((c00[0] + c10[0] + c01[0] + c11[0])) >> 2;
159 | int g_avg = ((c00[1] + c10[1] + c01[1] + c11[1])) >> 2;
160 | int b_avg = ((c00[2] + c10[2] + c01[2] + c11[2])) >> 2;
161 | if (r_avg >= 60 && g_avg >= 40 && b_avg >= 20 && r_avg >= b_avg && (r_avg - g_avg) >= 10 &&
162 | max(max(r_avg, g_avg), b_avg) - min(min(r_avg, g_avg), b_avg) >= 10) {
163 | sum++;
164 | }
165 | }
166 | }
167 | return sum;
168 | }
169 |
170 | void skinFilter(unsigned char *input, unsigned char *output, int width, int height, int channels) {
171 | int stride = width * channels;
172 | int lastCol = width * channels - channels;
173 | int lastRow = height * stride - stride;
174 | for (int y = 0; y < height; y++) {
175 | int cur_row = stride * y;
176 | int next_row = min(cur_row + stride, lastRow);
177 | unsigned char *next_scanOutLine = output + next_row;
178 | unsigned char *cur_scanOutLine = output + cur_row;
179 | unsigned char *scanOutLine = output + y * stride;
180 | unsigned char *scanInLine = input + y * stride;
181 | for (int x = 0; x < width; x++) {
182 | int cur_col = x * channels;
183 | int next_col = min(cur_col + channels, lastCol);
184 | unsigned char *c00 = cur_scanOutLine + cur_col;
185 | unsigned char *c10 = cur_scanOutLine + next_col;
186 | unsigned char *c01 = next_scanOutLine + cur_col;
187 | unsigned char *c11 = next_scanOutLine + next_col;
188 | int r_avg = ((c00[0] + c10[0] + c01[0] + c11[0])) >> 2;
189 | int g_avg = ((c00[1] + c10[1] + c01[1] + c11[1])) >> 2;
190 | int b_avg = ((c00[2] + c10[2] + c01[2] + c11[2])) >> 2;
191 | int is_skin = !(r_avg >= 60 && g_avg >= 40 && b_avg >= 20 && r_avg >= b_avg && (r_avg - g_avg) >= 10 &&
192 | max(max(r_avg, g_avg), b_avg) - min(min(r_avg, g_avg), b_avg) >= 10);
193 | if (is_skin)
194 | for (int c = 0; c < channels; ++c)
195 | scanOutLine[c] = scanInLine[c];
196 | scanOutLine += channels;
197 | scanInLine += channels;
198 | }
199 | }
200 | }
201 |
202 | void getOffsetPos(int *offsetPos, int length, int left, int right, int step) {
203 | if (offsetPos == NULL) return;
204 | if ((length < 0) || (left < 0) || (right < 0))
205 | return;
206 | for (int x = -left; x < length + right; x++) {
207 | int pos = x;
208 | int length2 = length + length;
209 | if (pos < 0) {
210 | do {
211 | pos += length2;
212 | } while (pos < 0);
213 | } else if (pos >= length2) {
214 | do {
215 | pos -= length2;
216 | } while (pos >= length2);
217 | }
218 | if (pos >= length)
219 | pos = length2 - 1 - pos;
220 | offsetPos[x + left] = pos * step;
221 | }
222 | }
223 |
224 | int Abs(int v) {
225 | return (v ^ (v >> 31)) - (v >> 31);
226 | }
227 |
228 | void skinDenoise(unsigned char *input, unsigned char *output, int width, int height, int channels, int radius,
229 | int smoothingLevel) {
230 | if ((input == NULL) || (output == NULL)) return;
231 | if ((width <= 0) || (height <= 0)) return;
232 | if ((radius <= 0) || (smoothingLevel <= 0)) return;
233 | if ((channels != 1) && (channels != 3)) return;
234 | int windowSize = (2 * radius + 1) * (2 * radius + 1);
235 | int *colPower = (int *) malloc(width * channels * sizeof(int));
236 | int *colValue = (int *) malloc(width * channels * sizeof(int));
237 | int *rowPos = (int *) malloc((width + radius + radius) * channels * sizeof(int));
238 | int *colPos = (int *) malloc((height + radius + radius) * channels * sizeof(int));
239 | if ((colPower == NULL) || (colValue == NULL) || (rowPos == NULL) || (colPos == NULL)) {
240 | if (colPower) free(colPower);
241 | if (colValue) free(colValue);
242 | if (rowPos) free(rowPos);
243 | if (colPos) free(colPos);
244 | return;
245 | }
246 | int stride = width * channels;
247 | int smoothLut[256] = {0};
248 | float ii = 0.f;
249 | for (int i = 0; i <= 255; i++, ii -= 1.) {
250 | smoothLut[i] = (int) ((expf(ii * (1.0f / (smoothingLevel * 255.0f))) + (smoothingLevel * (i + 1)) + 1) * 0.5f);
251 | smoothLut[i] = max(smoothLut[i], 1);
252 | }
253 | getOffsetPos(rowPos, width, radius, radius, channels);
254 | getOffsetPos(colPos, height, radius, radius, stride);
255 | int *rowOffset = rowPos + radius;
256 | int *colOffSet = colPos + radius;
257 | for (int y = 0; y < height; y++) {
258 | unsigned char *scanInLine = input + y * stride;
259 | unsigned char *scanOutLine = output + y * stride;
260 | if (y == 0) {
261 | for (int x = 0; x < stride; x += channels) {
262 | int colSum[3] = {0};
263 | int colSumPow[3] = {0};
264 | for (int z = -radius; z <= radius; z++) {
265 | unsigned char *sample = input + colOffSet[z] + x;
266 | for (int c = 0; c < channels; ++c) {
267 | colSum[c] += sample[c];
268 | colSumPow[c] += sample[c] * sample[c];
269 | }
270 | }
271 | for (int c = 0; c < channels; ++c) {
272 | colValue[x + c] = colSum[c];
273 | colPower[x + c] = colSumPow[c];
274 | }
275 | }
276 | } else {
277 | unsigned char *lastCol = input + colOffSet[y - radius - 1];
278 | unsigned char *nextCol = input + colOffSet[y + radius];
279 | for (int x = 0; x < stride; x += channels) {
280 | for (int c = 0; c < channels; ++c) {
281 | colValue[x + c] -= lastCol[x + c] - nextCol[x + c];
282 | colPower[x + c] -= lastCol[x + c] * lastCol[x + c] - nextCol[x + c] * nextCol[x + c];
283 | }
284 | }
285 | }
286 | int prevSum[3] = {0};
287 | int prevPowerSum[3] = {0};
288 | for (int z = -radius; z <= radius; z++) {
289 | int index = rowOffset[z];
290 | for (int c = 0; c < channels; ++c) {
291 | prevSum[c] += colValue[index + c];
292 | prevPowerSum[c] += colPower[index + c];
293 | }
294 | }
295 | for (int c = 0; c < channels; ++c) {
296 | const int mean = prevSum[c] / windowSize;
297 | const int diff = mean - scanInLine[c];
298 | const int edge = ClampToByte(diff);
299 | const int masked_edge = (edge * scanInLine[c] + (256 - edge) * mean) >> 8;
300 | const int var = Abs(prevPowerSum[c] - mean * prevSum[c]) / windowSize;
301 | const int out = masked_edge - diff * var / (var + smoothLut[scanInLine[c]]);
302 | scanOutLine[c] = ClampToByte(out);
303 | }
304 | scanInLine += channels;
305 | scanOutLine += channels;
306 | for (int x = 1; x < width; x++) {
307 | int lastRow = rowOffset[x - radius - 1];
308 | int nextRow = rowOffset[x + radius];
309 | for (int c = 0; c < channels; ++c) {
310 | prevSum[c] = prevSum[c] - colValue[lastRow + c] + colValue[nextRow + c];
311 | prevPowerSum[c] = prevPowerSum[c] - colPower[lastRow + c] + colPower[nextRow + c];
312 | const int mean = prevSum[c] / windowSize;
313 | const int diff = mean - scanInLine[c];
314 | const int edge = ClampToByte(diff);
315 | const int masked_edge = (edge * scanInLine[c] + (256 - edge) * mean) >> 8;
316 | const int var = Abs(prevPowerSum[c] - mean * prevSum[c]) / windowSize;
317 | const int out = masked_edge - diff * var / (var + smoothLut[scanInLine[c]]);
318 | scanOutLine[c] = ClampToByte(out);
319 | }
320 | scanInLine += channels;
321 | scanOutLine += channels;
322 | }
323 | }
324 | if (colPower) free(colPower);
325 | if (colValue) free(colValue);
326 | if (rowPos) free(rowPos);
327 | if (colPos) free(colPos);
328 | }
329 |
330 |
331 | void skinSmoothing(unsigned char *input, unsigned char *output, int width, int height, int channels,
332 | int smoothingLevel, int apply_skin_filter) {
333 | if (input == NULL || output == NULL || width == 0 || height == 0 || channels == 1)
334 | return;
335 | //1.detect skin color, adapt radius according to skin color ratio
336 | unsigned int skinSum = skinDetection(input, width, height, channels);
337 | float skin_rate = skinSum / (float) (width * height) * 100;
338 | int radius = min(width, height) / skin_rate + 1;
339 | //2.perform edge detection to obtain a edge map && smoothing level for apply skin denoise
340 | skinDenoise(input, output, width, height, channels, radius, smoothingLevel);
341 | //3.re-detect skin color based on the denoise results, filtered non-skin areas
342 | if (apply_skin_filter)
343 | skinFilter(input, output, width, height, channels);
344 | }
345 |
346 |
347 | int main(int argc, char **argv) {
348 | printf("Image Processing \n ");
349 | printf("blog:http://cpuimage.cnblogs.com/ \n ");
350 | printf("Skin Smoothing\n ");
351 | if (argc < 2) {
352 | printf("usage: \n ");
353 | printf("%s filename \n ", argv[0]);
354 | printf("%s image.jpg \n ", argv[0]);
355 | getchar();
356 | return 0;
357 | }
358 | char *in_file = argv[1];
359 | char drive[3];
360 | char dir[256];
361 | char fname[256];
362 | char ext[256];
363 | char out_file[1024];
364 | splitpath(in_file, drive, dir, fname, ext);
365 | sprintf(out_file, "%s%s%s_out.jpg", drive, dir, fname);
366 | int width = 0;
367 | int height = 0;
368 | int channels = 0;
369 | unsigned char *input = NULL;
370 | input = loadImage(in_file, &width, &height, &channels);
371 | if (input) {
372 | unsigned char *output = (unsigned char *) calloc(width * channels * height * sizeof(unsigned char), 1);
373 | if (output) {
374 | int smoothingLevel = 10;
375 | int apply_skin_filter = 0;
376 | double startTime = now();
377 | skinSmoothing(input, output, width, height, channels, smoothingLevel, apply_skin_filter);
378 | double elapsed = calcElapsed(startTime, now());
379 | printf("elapsed time: %d ms.\n ", (int) (elapsed * 1000));
380 | saveImage(out_file, width, height, channels, output);
381 | free(output);
382 | }
383 | free(input);
384 | } else {
385 | printf("load file: %s fail!\n", in_file);
386 | }
387 | printf("press any key to exit. \n");
388 | getchar();
389 | return 0;
390 | }
391 |
--------------------------------------------------------------------------------
/stb_image_write.h:
--------------------------------------------------------------------------------
1 | /* stb_image_write - v1.14 - public domain - http://nothings.org/stb
2 | writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015
3 | no warranty implied; use at your own risk
4 |
5 | Before #including,
6 |
7 | #define STB_IMAGE_WRITE_IMPLEMENTATION
8 |
9 | in the file that you want to have the implementation.
10 |
11 | Will probably not work correctly with strict-aliasing optimizations.
12 |
13 | ABOUT:
14 |
15 | This header file is a library for writing images to C stdio or a callback.
16 |
17 | The PNG output is not optimal; it is 20-50% larger than the file
18 | written by a decent optimizing implementation; though providing a custom
19 | zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that.
20 | This library is designed for source code compactness and simplicity,
21 | not optimal image file size or run-time performance.
22 |
23 | BUILDING:
24 |
25 | You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h.
26 | You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace
27 | malloc,realloc,free.
28 | You can #define STBIW_MEMMOVE() to replace memmove()
29 | You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function
30 | for PNG compression (instead of the builtin one), it must have the following signature:
31 | unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality);
32 | The returned data will be freed with STBIW_FREE() (free() by default),
33 | so it must be heap allocated with STBIW_MALLOC() (malloc() by default),
34 |
35 | UNICODE:
36 |
37 | If compiling for Windows and you wish to use Unicode filenames, compile
38 | with
39 | #define STBIW_WINDOWS_UTF8
40 | and pass utf8-encoded filenames. Call stbiw_convert_wchar_to_utf8 to convert
41 | Windows wchar_t filenames to utf8.
42 |
43 | USAGE:
44 |
45 | There are five functions, one for each image file format:
46 |
47 | int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
48 | int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
49 | int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
50 | int stbi_write_jpg(char const *filename, int w, int h, int comp, const void *data, int quality);
51 | int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
52 |
53 | void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically
54 |
55 | There are also five equivalent functions that use an arbitrary write function. You are
56 | expected to open/close your file-equivalent before and after calling these:
57 |
58 | int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes);
59 | int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
60 | int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
61 | int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
62 | int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);
63 |
64 | where the callback is:
65 | void stbi_write_func(void *context, void *data, int size);
66 |
67 | You can configure it with these global variables:
68 | int stbi_write_tga_with_rle; // defaults to true; set to 0 to disable RLE
69 | int stbi_write_png_compression_level; // defaults to 8; set to higher for more compression
70 | int stbi_write_force_png_filter; // defaults to -1; set to 0..5 to force a filter mode
71 |
72 |
73 | You can define STBI_WRITE_NO_STDIO to disable the file variant of these
74 | functions, so the library will not use stdio.h at all. However, this will
75 | also disable HDR writing, because it requires stdio for formatted output.
76 |
77 | Each function returns 0 on failure and non-0 on success.
78 |
79 | The functions create an image file defined by the parameters. The image
80 | is a rectangle of pixels stored from left-to-right, top-to-bottom.
81 | Each pixel contains 'comp' channels of data stored interleaved with 8-bits
82 | per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is
83 | monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall.
84 | The *data pointer points to the first byte of the top-left-most pixel.
85 | For PNG, "stride_in_bytes" is the distance in bytes from the first byte of
86 | a row of pixels to the first byte of the next row of pixels.
87 |
88 | PNG creates output files with the same number of components as the input.
89 | The BMP format expands Y to RGB in the file format and does not
90 | output alpha.
91 |
92 | PNG supports writing rectangles of data even when the bytes storing rows of
93 | data are not consecutive in memory (e.g. sub-rectangles of a larger image),
94 | by supplying the stride between the beginning of adjacent rows. The other
95 | formats do not. (Thus you cannot write a native-format BMP through the BMP
96 | writer, both because it is in BGR order and because it may have padding
97 | at the end of the line.)
98 |
99 | PNG allows you to set the deflate compression level by setting the global
100 | variable 'stbi_write_png_compression_level' (it defaults to 8).
101 |
102 | HDR expects linear float data. Since the format is always 32-bit rgb(e)
103 | data, alpha (if provided) is discarded, and for monochrome data it is
104 | replicated across all three channels.
105 |
106 | TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed
107 | data, set the global variable 'stbi_write_tga_with_rle' to 0.
108 |
109 | JPEG does ignore alpha channels in input data; quality is between 1 and 100.
110 | Higher quality looks better but results in a bigger image.
111 | JPEG baseline (no JPEG progressive).
112 |
113 | CREDITS:
114 |
115 |
116 | Sean Barrett - PNG/BMP/TGA
117 | Baldur Karlsson - HDR
118 | Jean-Sebastien Guay - TGA monochrome
119 | Tim Kelsey - misc enhancements
120 | Alan Hickman - TGA RLE
121 | Emmanuel Julien - initial file IO callback implementation
122 | Jon Olick - original jo_jpeg.cpp code
123 | Daniel Gibson - integrate JPEG, allow external zlib
124 | Aarni Koskela - allow choosing PNG filter
125 |
126 | bugfixes:
127 | github:Chribba
128 | Guillaume Chereau
129 | github:jry2
130 | github:romigrou
131 | Sergio Gonzalez
132 | Jonas Karlsson
133 | Filip Wasil
134 | Thatcher Ulrich
135 | github:poppolopoppo
136 | Patrick Boettcher
137 | github:xeekworx
138 | Cap Petschulat
139 | Simon Rodriguez
140 | Ivan Tikhonov
141 | github:ignotion
142 | Adam Schackart
143 |
144 | LICENSE
145 |
146 | See end of file for license information.
147 |
148 | */
149 |
150 | #ifndef INCLUDE_STB_IMAGE_WRITE_H
151 | #define INCLUDE_STB_IMAGE_WRITE_H
152 |
153 | #include
154 |
155 | // if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline'
156 | #ifndef STBIWDEF
157 | #ifdef STB_IMAGE_WRITE_STATIC
158 | #define STBIWDEF static
159 | #else
160 | #ifdef __cplusplus
161 | #define STBIWDEF extern "C"
162 | #else
163 | #define STBIWDEF extern
164 | #endif
165 | #endif
166 | #endif
167 |
168 | #ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations
169 | extern int stbi_write_tga_with_rle;
170 | extern int stbi_write_png_compression_level;
171 | extern int stbi_write_force_png_filter;
172 | #endif
173 |
174 | #ifndef STBI_WRITE_NO_STDIO
175 |
176 | STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);
177 |
178 | STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);
179 |
180 | STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);
181 |
182 | STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);
183 |
184 | STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality);
185 |
186 | #ifdef STBI_WINDOWS_UTF8
187 | STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);
188 | #endif
189 | #endif
190 |
191 | typedef void stbi_write_func(void *context, void *data, int size);
192 |
193 | STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data,
194 | int stride_in_bytes);
195 |
196 | STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
197 |
198 | STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);
199 |
200 | STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);
201 |
202 | STBIWDEF int
203 | stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);
204 |
205 | STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean);
206 |
207 | #endif//INCLUDE_STB_IMAGE_WRITE_H
208 |
209 | #ifdef STB_IMAGE_WRITE_IMPLEMENTATION
210 |
211 | #ifdef _WIN32
212 | #ifndef _CRT_SECURE_NO_WARNINGS
213 | #define _CRT_SECURE_NO_WARNINGS
214 | #endif
215 | #ifndef _CRT_NONSTDC_NO_DEPRECATE
216 | #define _CRT_NONSTDC_NO_DEPRECATE
217 | #endif
218 | #endif
219 |
220 | #ifndef STBI_WRITE_NO_STDIO
221 |
222 | #include
223 |
224 | #endif // STBI_WRITE_NO_STDIO
225 |
226 | #include
227 | #include
228 | #include
229 | #include
230 |
231 | #if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED))
232 | // ok
233 | #elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED)
234 | // ok
235 | #else
236 | #error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)."
237 | #endif
238 |
239 | #ifndef STBIW_MALLOC
240 | #define STBIW_MALLOC(sz) malloc(sz)
241 | #define STBIW_REALLOC(p, newsz) realloc(p,newsz)
242 | #define STBIW_FREE(p) free(p)
243 | #endif
244 |
245 | #ifndef STBIW_REALLOC_SIZED
246 | #define STBIW_REALLOC_SIZED(p, oldsz, newsz) STBIW_REALLOC(p,newsz)
247 | #endif
248 |
249 |
250 | #ifndef STBIW_MEMMOVE
251 | #define STBIW_MEMMOVE(a, b, sz) memmove(a,b,sz)
252 | #endif
253 |
254 |
255 | #ifndef STBIW_ASSERT
256 |
257 | #include
258 |
259 | #define STBIW_ASSERT(x) assert(x)
260 | #endif
261 |
262 | #define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)
263 |
264 | #ifdef STB_IMAGE_WRITE_STATIC
265 | static int stbi_write_png_compression_level = 8;
266 | static int stbi_write_tga_with_rle = 1;
267 | static int stbi_write_force_png_filter = -1;
268 | #else
269 | int stbi_write_png_compression_level = 8;
270 | int stbi_write_tga_with_rle = 1;
271 | int stbi_write_force_png_filter = -1;
272 | #endif
273 |
274 | static int stbi__flip_vertically_on_write = 0;
275 |
276 | STBIWDEF void stbi_flip_vertically_on_write(int flag) {
277 | stbi__flip_vertically_on_write = flag;
278 | }
279 |
280 | typedef struct {
281 | stbi_write_func *func;
282 | void *context;
283 | } stbi__write_context;
284 |
285 | // initialize a callback-based context
286 | static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context) {
287 | s->func = c;
288 | s->context = context;
289 | }
290 |
291 | #ifndef STBI_WRITE_NO_STDIO
292 |
293 | static void stbi__stdio_write(void *context, void *data, int size) {
294 | fwrite(data, 1, size, (FILE *) context);
295 | }
296 |
297 | #if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8)
298 | #ifdef __cplusplus
299 | #define STBIW_EXTERN extern "C"
300 | #else
301 | #define STBIW_EXTERN extern
302 | #endif
303 | STBIW_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide);
304 | STBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default);
305 |
306 | STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input)
307 | {
308 | return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL);
309 | }
310 | #endif
311 |
312 | static FILE *stbiw__fopen(char const *filename, char const *mode) {
313 | FILE *f;
314 | #if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8)
315 | wchar_t wMode[64];
316 | wchar_t wFilename[1024];
317 | if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)))
318 | return 0;
319 |
320 | if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)))
321 | return 0;
322 |
323 | #if _MSC_VER >= 1400
324 | if (0 != _wfopen_s(&f, wFilename, wMode))
325 | f = 0;
326 | #else
327 | f = _wfopen(wFilename, wMode);
328 | #endif
329 |
330 | #elif defined(_MSC_VER) && _MSC_VER >= 1400
331 | if (0 != fopen_s(&f, filename, mode))
332 | f=0;
333 | #else
334 | f = fopen(filename, mode);
335 | #endif
336 | return f;
337 | }
338 |
339 | static int stbi__start_write_file(stbi__write_context *s, const char *filename) {
340 | FILE *f = stbiw__fopen(filename, "wb");
341 | stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f);
342 | return f != NULL;
343 | }
344 |
345 | static void stbi__end_write_file(stbi__write_context *s) {
346 | fclose((FILE *) s->context);
347 | }
348 |
349 | #endif // !STBI_WRITE_NO_STDIO
350 |
351 | typedef unsigned int stbiw_uint32;
352 | typedef int stb_image_write_test[sizeof(stbiw_uint32) == 4 ? 1 : -1];
353 |
354 | static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v) {
355 | while (*fmt) {
356 | switch (*fmt++) {
357 | case ' ':
358 | break;
359 | case '1': {
360 | unsigned char x = STBIW_UCHAR(va_arg(v, int));
361 | s->func(s->context, &x, 1);
362 | break;
363 | }
364 | case '2': {
365 | int x = va_arg(v, int);
366 | unsigned char b[2];
367 | b[0] = STBIW_UCHAR(x);
368 | b[1] = STBIW_UCHAR(x >> 8);
369 | s->func(s->context, b, 2);
370 | break;
371 | }
372 | case '4': {
373 | stbiw_uint32 x = va_arg(v, int);
374 | unsigned char b[4];
375 | b[0] = STBIW_UCHAR(x);
376 | b[1] = STBIW_UCHAR(x >> 8);
377 | b[2] = STBIW_UCHAR(x >> 16);
378 | b[3] = STBIW_UCHAR(x >> 24);
379 | s->func(s->context, b, 4);
380 | break;
381 | }
382 | default:
383 | STBIW_ASSERT(0);
384 | return;
385 | }
386 | }
387 | }
388 |
389 | static void stbiw__writef(stbi__write_context *s, const char *fmt, ...) {
390 | va_list v;
391 | va_start(v, fmt);
392 | stbiw__writefv(s, fmt, v);
393 | va_end(v);
394 | }
395 |
396 | static void stbiw__putc(stbi__write_context *s, unsigned char c) {
397 | s->func(s->context, &c, 1);
398 | }
399 |
400 | static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) {
401 | unsigned char arr[3];
402 | arr[0] = a;
403 | arr[1] = b;
404 | arr[2] = c;
405 | s->func(s->context, arr, 3);
406 | }
407 |
408 | static void
409 | stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d) {
410 | unsigned char bg[3] = {255, 0, 255}, px[3];
411 | int k;
412 |
413 | if (write_alpha < 0)
414 | s->func(s->context, &d[comp - 1], 1);
415 |
416 | switch (comp) {
417 | case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case
418 | case 1:
419 | if (expand_mono)
420 | stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp
421 | else
422 | s->func(s->context, d, 1); // monochrome TGA
423 | break;
424 | case 4:
425 | if (!write_alpha) {
426 | // composite against pink background
427 | for (k = 0; k < 3; ++k)
428 | px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255;
429 | stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]);
430 | break;
431 | }
432 | /* FALLTHROUGH */
433 | case 3:
434 | stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]);
435 | break;
436 | }
437 | if (write_alpha > 0)
438 | s->func(s->context, &d[comp - 1], 1);
439 | }
440 |
441 | static void
442 | stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha,
443 | int scanline_pad, int expand_mono) {
444 | stbiw_uint32 zero = 0;
445 | int i, j, j_end;
446 |
447 | if (y <= 0)
448 | return;
449 |
450 | if (stbi__flip_vertically_on_write)
451 | vdir *= -1;
452 |
453 | if (vdir < 0) {
454 | j_end = -1;
455 | j = y - 1;
456 | } else {
457 | j_end = y;
458 | j = 0;
459 | }
460 |
461 | for (; j != j_end; j += vdir) {
462 | for (i = 0; i < x; ++i) {
463 | unsigned char *d = (unsigned char *) data + (j * x + i) * comp;
464 | stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d);
465 | }
466 | s->func(s->context, &zero, scanline_pad);
467 | }
468 | }
469 |
470 | static int
471 | stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data,
472 | int alpha, int pad, const char *fmt, ...) {
473 | if (y < 0 || x < 0) {
474 | return 0;
475 | } else {
476 | va_list v;
477 | va_start(v, fmt);
478 | stbiw__writefv(s, fmt, v);
479 | va_end(v);
480 | stbiw__write_pixels(s, rgb_dir, vdir, x, y, comp, data, alpha, pad, expand_mono);
481 | return 1;
482 | }
483 | }
484 |
485 | static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data) {
486 | int pad = (-x * 3) & 3;
487 | return stbiw__outfile(s, -1, -1, x, y, comp, 1, (void *) data, 0, pad,
488 | "11 4 22 4" "4 44 22 444444",
489 | 'B', 'M', 14 + 40 + (x * 3 + pad) * y, 0, 0, 14 + 40, // file header
490 | 40, x, y, 1, 24, 0, 0, 0, 0, 0, 0); // bitmap header
491 | }
492 |
493 | STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) {
494 | stbi__write_context s;
495 | stbi__start_write_callbacks(&s, func, context);
496 | return stbi_write_bmp_core(&s, x, y, comp, data);
497 | }
498 |
499 | #ifndef STBI_WRITE_NO_STDIO
500 |
501 | STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) {
502 | stbi__write_context s;
503 | if (stbi__start_write_file(&s, filename)) {
504 | int r = stbi_write_bmp_core(&s, x, y, comp, data);
505 | stbi__end_write_file(&s);
506 | return r;
507 | } else
508 | return 0;
509 | }
510 |
511 | #endif //!STBI_WRITE_NO_STDIO
512 |
513 | static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data) {
514 | int has_alpha = (comp == 2 || comp == 4);
515 | int colorbytes = has_alpha ? comp - 1 : comp;
516 | int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3
517 |
518 | if (y < 0 || x < 0)
519 | return 0;
520 |
521 | if (!stbi_write_tga_with_rle) {
522 | return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0,
523 | "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8,
524 | has_alpha * 8);
525 | } else {
526 | int i, j, k;
527 | int jend, jdir;
528 |
529 | stbiw__writef(s, "111 221 2222 11", 0, 0, format + 8, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8,
530 | has_alpha * 8);
531 |
532 | if (stbi__flip_vertically_on_write) {
533 | j = 0;
534 | jend = y;
535 | jdir = 1;
536 | } else {
537 | j = y - 1;
538 | jend = -1;
539 | jdir = -1;
540 | }
541 | for (; j != jend; j += jdir) {
542 | unsigned char *row = (unsigned char *) data + j * x * comp;
543 | int len;
544 |
545 | for (i = 0; i < x; i += len) {
546 | unsigned char *begin = row + i * comp;
547 | int diff = 1;
548 | len = 1;
549 |
550 | if (i < x - 1) {
551 | ++len;
552 | diff = memcmp(begin, row + (i + 1) * comp, comp);
553 | if (diff) {
554 | const unsigned char *prev = begin;
555 | for (k = i + 2; k < x && len < 128; ++k) {
556 | if (memcmp(prev, row + k * comp, comp)) {
557 | prev += comp;
558 | ++len;
559 | } else {
560 | --len;
561 | break;
562 | }
563 | }
564 | } else {
565 | for (k = i + 2; k < x && len < 128; ++k) {
566 | if (!memcmp(begin, row + k * comp, comp)) {
567 | ++len;
568 | } else {
569 | break;
570 | }
571 | }
572 | }
573 | }
574 |
575 | if (diff) {
576 | unsigned char header = STBIW_UCHAR(len - 1);
577 | s->func(s->context, &header, 1);
578 | for (k = 0; k < len; ++k) {
579 | stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp);
580 | }
581 | } else {
582 | unsigned char header = STBIW_UCHAR(len - 129);
583 | s->func(s->context, &header, 1);
584 | stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin);
585 | }
586 | }
587 | }
588 | }
589 | return 1;
590 | }
591 |
592 | STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) {
593 | stbi__write_context s;
594 | stbi__start_write_callbacks(&s, func, context);
595 | return stbi_write_tga_core(&s, x, y, comp, (void *) data);
596 | }
597 |
598 | #ifndef STBI_WRITE_NO_STDIO
599 |
600 | STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) {
601 | stbi__write_context s;
602 | if (stbi__start_write_file(&s, filename)) {
603 | int r = stbi_write_tga_core(&s, x, y, comp, (void *) data);
604 | stbi__end_write_file(&s);
605 | return r;
606 | } else
607 | return 0;
608 | }
609 |
610 | #endif
611 |
612 | // *************************************************************************************************
613 | // Radiance RGBE HDR writer
614 | // by Baldur Karlsson
615 |
616 | #define stbiw__max(a, b) ((a) > (b) ? (a) : (b))
617 |
618 | static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) {
619 | int exponent;
620 | float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2]));
621 |
622 | if (maxcomp < 1e-32f) {
623 | rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;
624 | } else {
625 | float normalize = (float) frexp(maxcomp, &exponent) * 256.0f / maxcomp;
626 |
627 | rgbe[0] = (unsigned char) (linear[0] * normalize);
628 | rgbe[1] = (unsigned char) (linear[1] * normalize);
629 | rgbe[2] = (unsigned char) (linear[2] * normalize);
630 | rgbe[3] = (unsigned char) (exponent + 128);
631 | }
632 | }
633 |
634 | static void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) {
635 | unsigned char lengthbyte = STBIW_UCHAR(length + 128);
636 | STBIW_ASSERT(length + 128 <= 255);
637 | s->func(s->context, &lengthbyte, 1);
638 | s->func(s->context, &databyte, 1);
639 | }
640 |
641 | static void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) {
642 | unsigned char lengthbyte = STBIW_UCHAR(length);
643 | STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code
644 | s->func(s->context, &lengthbyte, 1);
645 | s->func(s->context, data, length);
646 | }
647 |
648 | static void
649 | stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline) {
650 | unsigned char scanlineheader[4] = {2, 2, 0, 0};
651 | unsigned char rgbe[4];
652 | float linear[3];
653 | int x;
654 |
655 | scanlineheader[2] = (width & 0xff00) >> 8;
656 | scanlineheader[3] = (width & 0x00ff);
657 |
658 | /* skip RLE for images too small or large */
659 | if (width < 8 || width >= 32768) {
660 | for (x = 0; x < width; x++) {
661 | switch (ncomp) {
662 | case 4: /* fallthrough */
663 | case 3:
664 | linear[2] = scanline[x * ncomp + 2];
665 | linear[1] = scanline[x * ncomp + 1];
666 | linear[0] = scanline[x * ncomp + 0];
667 | break;
668 | default:
669 | linear[0] = linear[1] = linear[2] = scanline[x * ncomp + 0];
670 | break;
671 | }
672 | stbiw__linear_to_rgbe(rgbe, linear);
673 | s->func(s->context, rgbe, 4);
674 | }
675 | } else {
676 | int c, r;
677 | /* encode into scratch buffer */
678 | for (x = 0; x < width; x++) {
679 | switch (ncomp) {
680 | case 4: /* fallthrough */
681 | case 3:
682 | linear[2] = scanline[x * ncomp + 2];
683 | linear[1] = scanline[x * ncomp + 1];
684 | linear[0] = scanline[x * ncomp + 0];
685 | break;
686 | default:
687 | linear[0] = linear[1] = linear[2] = scanline[x * ncomp + 0];
688 | break;
689 | }
690 | stbiw__linear_to_rgbe(rgbe, linear);
691 | scratch[x + width * 0] = rgbe[0];
692 | scratch[x + width * 1] = rgbe[1];
693 | scratch[x + width * 2] = rgbe[2];
694 | scratch[x + width * 3] = rgbe[3];
695 | }
696 |
697 | s->func(s->context, scanlineheader, 4);
698 |
699 | /* RLE each component separately */
700 | for (c = 0; c < 4; c++) {
701 | unsigned char *comp = &scratch[width * c];
702 |
703 | x = 0;
704 | while (x < width) {
705 | // find first run
706 | r = x;
707 | while (r + 2 < width) {
708 | if (comp[r] == comp[r + 1] && comp[r] == comp[r + 2])
709 | break;
710 | ++r;
711 | }
712 | if (r + 2 >= width)
713 | r = width;
714 | // dump up to first run
715 | while (x < r) {
716 | int len = r - x;
717 | if (len > 128) len = 128;
718 | stbiw__write_dump_data(s, len, &comp[x]);
719 | x += len;
720 | }
721 | // if there's a run, output it
722 | if (r + 2 < width) { // same test as what we break out of in search loop, so only true if we break'd
723 | // find next byte after run
724 | while (r < width && comp[r] == comp[x])
725 | ++r;
726 | // output run up to r
727 | while (x < r) {
728 | int len = r - x;
729 | if (len > 127) len = 127;
730 | stbiw__write_run_data(s, len, comp[x]);
731 | x += len;
732 | }
733 | }
734 | }
735 | }
736 | }
737 | }
738 |
739 | static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data) {
740 | if (y <= 0 || x <= 0 || data == NULL)
741 | return 0;
742 | else {
743 | // Each component is stored separately. Allocate scratch space for full output scanline.
744 | unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x * 4);
745 | int i, len;
746 | char buffer[128];
747 | char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n";
748 | s->func(s->context, header, sizeof(header) - 1);
749 |
750 | #ifdef __STDC_WANT_SECURE_LIB__
751 | len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
752 | #else
753 | len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);
754 | #endif
755 | s->func(s->context, buffer, len);
756 |
757 | for (i = 0; i < y; i++)
758 | stbiw__write_hdr_scanline(s, x, comp, scratch,
759 | data + comp * x * (stbi__flip_vertically_on_write ? y - 1 - i : i));
760 | STBIW_FREE(scratch);
761 | return 1;
762 | }
763 | }
764 |
765 | STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) {
766 | stbi__write_context s;
767 | stbi__start_write_callbacks(&s, func, context);
768 | return stbi_write_hdr_core(&s, x, y, comp, (float *) data);
769 | }
770 |
771 | #ifndef STBI_WRITE_NO_STDIO
772 |
773 | STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) {
774 | stbi__write_context s;
775 | if (stbi__start_write_file(&s, filename)) {
776 | int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data);
777 | stbi__end_write_file(&s);
778 | return r;
779 | } else
780 | return 0;
781 | }
782 |
783 | #endif // STBI_WRITE_NO_STDIO
784 |
785 |
786 | //////////////////////////////////////////////////////////////////////////////
787 | //
788 | // PNG writer
789 | //
790 |
791 | #ifndef STBIW_ZLIB_COMPRESS
792 | // stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()
793 | #define stbiw__sbraw(a) ((int *) (void *) (a) - 2)
794 | #define stbiw__sbm(a) stbiw__sbraw(a)[0]
795 | #define stbiw__sbn(a) stbiw__sbraw(a)[1]
796 |
797 | #define stbiw__sbneedgrow(a, n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a))
798 | #define stbiw__sbmaybegrow(a, n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0)
799 | #define stbiw__sbgrow(a, n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a)))
800 |
801 | #define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v))
802 | #define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0)
803 | #define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0)
804 |
805 | static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) {
806 | int m = *arr ? 2 * stbiw__sbm(*arr) + increment : increment + 1;
807 | void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0,
808 | *arr ? (stbiw__sbm(*arr) * itemsize + sizeof(int) * 2) : 0,
809 | itemsize * m + sizeof(int) * 2);
810 | STBIW_ASSERT(p);
811 | if (p) {
812 | if (!*arr) ((int *) p)[1] = 0;
813 | *arr = (void *) ((int *) p + 2);
814 | stbiw__sbm(*arr) = m;
815 | }
816 | return *arr;
817 | }
818 |
819 | static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) {
820 | while (*bitcount >= 8) {
821 | stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer));
822 | *bitbuffer >>= 8;
823 | *bitcount -= 8;
824 | }
825 | return data;
826 | }
827 |
828 | static int stbiw__zlib_bitrev(int code, int codebits) {
829 | int res = 0;
830 | while (codebits--) {
831 | res = (res << 1) | (code & 1);
832 | code >>= 1;
833 | }
834 | return res;
835 | }
836 |
837 | static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit) {
838 | int i;
839 | for (i = 0; i < limit && i < 258; ++i)
840 | if (a[i] != b[i]) break;
841 | return i;
842 | }
843 |
844 | static unsigned int stbiw__zhash(unsigned char *data) {
845 | stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16);
846 | hash ^= hash << 3;
847 | hash += hash >> 5;
848 | hash ^= hash << 4;
849 | hash += hash >> 17;
850 | hash ^= hash << 25;
851 | hash += hash >> 6;
852 | return hash;
853 | }
854 |
855 | #define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount))
856 | #define stbiw__zlib_add(code, codebits) \
857 | (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush())
858 | #define stbiw__zlib_huffa(b, c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c)
859 | // default huffman tables
860 | #define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8)
861 | #define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9)
862 | #define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7)
863 | #define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8)
864 | #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))
865 | #define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n))
866 |
867 | #define stbiw__ZHASH 16384
868 |
869 | #endif // STBIW_ZLIB_COMPRESS
870 |
871 | STBIWDEF unsigned char *stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) {
872 | #ifdef STBIW_ZLIB_COMPRESS
873 | // user provided a zlib compress implementation, use that
874 | return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality);
875 | #else // use builtin
876 | 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,
877 | 99, 115, 131, 163, 195, 227, 258, 259};
878 | 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,
879 | 5, 0};
880 | static unsigned short distc[] = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769,
881 | 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 32768};
882 | 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,
883 | 12, 12, 13, 13};
884 | unsigned int bitbuf = 0;
885 | int i, j, bitcount = 0;
886 | unsigned char *out = NULL;
887 | unsigned char ***hash_table = (unsigned char ***) STBIW_MALLOC(stbiw__ZHASH * sizeof(unsigned char **));
888 | if (hash_table == NULL)
889 | return NULL;
890 | if (quality < 5) quality = 5;
891 |
892 | stbiw__sbpush(out, 0x78); // DEFLATE 32K window
893 | stbiw__sbpush(out, 0x5e); // FLEVEL = 1
894 | stbiw__zlib_add(1, 1); // BFINAL = 1
895 | stbiw__zlib_add(1, 2); // BTYPE = 1 -- fixed huffman
896 |
897 | for (i = 0; i < stbiw__ZHASH; ++i)
898 | hash_table[i] = NULL;
899 |
900 | i = 0;
901 | while (i < data_len - 3) {
902 | // hash next 3 bytes of data to be compressed
903 | int h = stbiw__zhash(data + i) & (stbiw__ZHASH - 1), best = 3;
904 | unsigned char *bestloc = 0;
905 | unsigned char **hlist = hash_table[h];
906 | int n = stbiw__sbcount(hlist);
907 | for (j = 0; j < n; ++j) {
908 | if (hlist[j] - data > i - 32768) { // if entry lies within window
909 | int d = stbiw__zlib_countm(hlist[j], data + i, data_len - i);
910 | if (d >= best) {
911 | best = d;
912 | bestloc = hlist[j];
913 | }
914 | }
915 | }
916 | // when hash table entry is too long, delete half the entries
917 | if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2 * quality) {
918 | STBIW_MEMMOVE(hash_table[h], hash_table[h] + quality, sizeof(hash_table[h][0]) * quality);
919 | stbiw__sbn(hash_table[h]) = quality;
920 | }
921 | stbiw__sbpush(hash_table[h], data + i);
922 |
923 | if (bestloc) {
924 | // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal
925 | h = stbiw__zhash(data + i + 1) & (stbiw__ZHASH - 1);
926 | hlist = hash_table[h];
927 | n = stbiw__sbcount(hlist);
928 | for (j = 0; j < n; ++j) {
929 | if (hlist[j] - data > i - 32767) {
930 | int e = stbiw__zlib_countm(hlist[j], data + i + 1, data_len - i - 1);
931 | if (e > best) { // if next match is better, bail on current match
932 | bestloc = NULL;
933 | break;
934 | }
935 | }
936 | }
937 | }
938 |
939 | if (bestloc) {
940 | int d = (int) (data + i - bestloc); // distance back
941 | STBIW_ASSERT(d <= 32767 && best <= 258);
942 | for (j = 0; best > lengthc[j + 1] - 1; ++j);
943 | stbiw__zlib_huff(j + 257);
944 | if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]);
945 | for (j = 0; d > distc[j + 1] - 1; ++j);
946 | stbiw__zlib_add(stbiw__zlib_bitrev(j, 5), 5);
947 | if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]);
948 | i += best;
949 | } else {
950 | stbiw__zlib_huffb(data[i]);
951 | ++i;
952 | }
953 | }
954 | // write out final bytes
955 | for (; i < data_len; ++i)
956 | stbiw__zlib_huffb(data[i]);
957 | stbiw__zlib_huff(256); // end of block
958 | // pad with 0 bits to byte boundary
959 | while (bitcount)
960 | stbiw__zlib_add(0, 1);
961 |
962 | for (i = 0; i < stbiw__ZHASH; ++i)
963 | (void) stbiw__sbfree(hash_table[i]);
964 | STBIW_FREE(hash_table);
965 |
966 | {
967 | // compute adler32 on input
968 | unsigned int s1 = 1, s2 = 0;
969 | int blocklen = (int) (data_len % 5552);
970 | j = 0;
971 | while (j < data_len) {
972 | for (i = 0; i < blocklen; ++i) {
973 | s1 += data[j + i];
974 | s2 += s1;
975 | }
976 | s1 %= 65521;
977 | s2 %= 65521;
978 | j += blocklen;
979 | blocklen = 5552;
980 | }
981 | stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8));
982 | stbiw__sbpush(out, STBIW_UCHAR(s2));
983 | stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8));
984 | stbiw__sbpush(out, STBIW_UCHAR(s1));
985 | }
986 | *out_len = stbiw__sbn(out);
987 | // make returned pointer freeable
988 | STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len);
989 | return (unsigned char *) stbiw__sbraw(out);
990 | #endif // STBIW_ZLIB_COMPRESS
991 | }
992 |
993 | static unsigned int stbiw__crc32(unsigned char *buffer, int len) {
994 | #ifdef STBIW_CRC32
995 | return STBIW_CRC32(buffer, len);
996 | #else
997 | static unsigned int crc_table[256] =
998 | {
999 | 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
1000 | 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
1001 | 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
1002 | 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
1003 | 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
1004 | 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
1005 | 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
1006 | 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
1007 | 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
1008 | 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
1009 | 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
1010 | 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
1011 | 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
1012 | 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
1013 | 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
1014 | 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
1015 | 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
1016 | 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
1017 | 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
1018 | 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
1019 | 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
1020 | 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
1021 | 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
1022 | 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
1023 | 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
1024 | 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
1025 | 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
1026 | 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
1027 | 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
1028 | 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
1029 | 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
1030 | 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
1031 | };
1032 |
1033 | unsigned int crc = ~0u;
1034 | int i;
1035 | for (i = 0; i < len; ++i)
1036 | crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];
1037 | return ~crc;
1038 | #endif
1039 | }
1040 |
1041 | #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)
1042 | #define stbiw__wp32(data, v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));
1043 | #define stbiw__wptag(data, s) stbiw__wpng4(data, s[0],s[1],s[2],s[3])
1044 |
1045 | static void stbiw__wpcrc(unsigned char **data, int len) {
1046 | unsigned int crc = stbiw__crc32(*data - len - 4, len + 4);
1047 | stbiw__wp32(*data, crc);
1048 | }
1049 |
1050 | static unsigned char stbiw__paeth(int a, int b, int c) {
1051 | int p = a + b - c, pa = abs(p - a), pb = abs(p - b), pc = abs(p - c);
1052 | if (pa <= pb && pa <= pc) return STBIW_UCHAR(a);
1053 | if (pb <= pc) return STBIW_UCHAR(b);
1054 | return STBIW_UCHAR(c);
1055 | }
1056 |
1057 | // @OPTIMIZE: provide an option that always forces left-predict or paeth predict
1058 | static void
1059 | stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type,
1060 | signed char *line_buffer) {
1061 | static int mapping[] = {0, 1, 2, 3, 4};
1062 | static int firstmap[] = {0, 1, 0, 5, 6};
1063 | int *mymap = (y != 0) ? mapping : firstmap;
1064 | int i;
1065 | int type = mymap[filter_type];
1066 | unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height - 1 - y : y);
1067 | int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes;
1068 |
1069 | if (type == 0) {
1070 | memcpy(line_buffer, z, width * n);
1071 | return;
1072 | }
1073 |
1074 | // first loop isn't optimized since it's just one pixel
1075 | for (i = 0; i < n; ++i) {
1076 | switch (type) {
1077 | case 1:
1078 | line_buffer[i] = z[i];
1079 | break;
1080 | case 2:
1081 | line_buffer[i] = z[i] - z[i - signed_stride];
1082 | break;
1083 | case 3:
1084 | line_buffer[i] = z[i] - (z[i - signed_stride] >> 1);
1085 | break;
1086 | case 4:
1087 | line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0, z[i - signed_stride], 0));
1088 | break;
1089 | case 5:
1090 | line_buffer[i] = z[i];
1091 | break;
1092 | case 6:
1093 | line_buffer[i] = z[i];
1094 | break;
1095 | }
1096 | }
1097 | switch (type) {
1098 | case 1:
1099 | for (i = n; i < width * n; ++i) line_buffer[i] = z[i] - z[i - n];
1100 | break;
1101 | case 2:
1102 | for (i = n; i < width * n; ++i) line_buffer[i] = z[i] - z[i - signed_stride];
1103 | break;
1104 | case 3:
1105 | for (i = n; i < width * n; ++i) line_buffer[i] = z[i] - ((z[i - n] + z[i - signed_stride]) >> 1);
1106 | break;
1107 | case 4:
1108 | for (i = n; i < width * n; ++i)
1109 | line_buffer[i] = z[i] - stbiw__paeth(z[i - n], z[i - signed_stride], z[i - signed_stride - n]);
1110 | break;
1111 | case 5:
1112 | for (i = n; i < width * n; ++i) line_buffer[i] = z[i] - (z[i - n] >> 1);
1113 | break;
1114 | case 6:
1115 | for (i = n; i < width * n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i - n], 0, 0);
1116 | break;
1117 | }
1118 | }
1119 |
1120 | STBIWDEF unsigned char *
1121 | stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) {
1122 | int force_filter = stbi_write_force_png_filter;
1123 | int ctype[5] = {-1, 0, 4, 2, 6};
1124 | unsigned char sig[8] = {137, 80, 78, 71, 13, 10, 26, 10};
1125 | unsigned char *out, *o, *filt, *zlib;
1126 | signed char *line_buffer;
1127 | int j, zlen;
1128 |
1129 | if (stride_bytes == 0)
1130 | stride_bytes = x * n;
1131 |
1132 | if (force_filter >= 5) {
1133 | force_filter = -1;
1134 | }
1135 |
1136 | filt = (unsigned char *) STBIW_MALLOC((x * n + 1) * y);
1137 | if (!filt) return 0;
1138 | line_buffer = (signed char *) STBIW_MALLOC(x * n);
1139 | if (!line_buffer) {
1140 | STBIW_FREE(filt);
1141 | return 0;
1142 | }
1143 | for (j = 0; j < y; ++j) {
1144 | int filter_type;
1145 | if (force_filter > -1) {
1146 | filter_type = force_filter;
1147 | stbiw__encode_png_line((unsigned char *) (pixels), stride_bytes, x, y, j, n, force_filter, line_buffer);
1148 | } else { // Estimate the best filter by running through all of them:
1149 | int best_filter = 0, best_filter_val = 0x7fffffff, est, i;
1150 | for (filter_type = 0; filter_type < 5; filter_type++) {
1151 | stbiw__encode_png_line((unsigned char *) (pixels), stride_bytes, x, y, j, n, filter_type, line_buffer);
1152 |
1153 | // Estimate the entropy of the line using this filter; the less, the better.
1154 | est = 0;
1155 | for (i = 0; i < x * n; ++i) {
1156 | est += abs((signed char) line_buffer[i]);
1157 | }
1158 | if (est < best_filter_val) {
1159 | best_filter_val = est;
1160 | best_filter = filter_type;
1161 | }
1162 | }
1163 | if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it
1164 | stbiw__encode_png_line((unsigned char *) (pixels), stride_bytes, x, y, j, n, best_filter, line_buffer);
1165 | filter_type = best_filter;
1166 | }
1167 | }
1168 | // when we get here, filter_type contains the filter type, and line_buffer contains the data
1169 | filt[j * (x * n + 1)] = (unsigned char) filter_type;
1170 | STBIW_MEMMOVE(filt + j * (x * n + 1) + 1, line_buffer, x * n);
1171 | }
1172 | STBIW_FREE(line_buffer);
1173 | zlib = stbi_zlib_compress(filt, y * (x * n + 1), &zlen, stbi_write_png_compression_level);
1174 | STBIW_FREE(filt);
1175 | if (!zlib) return 0;
1176 |
1177 | // each tag requires 12 bytes of overhead
1178 | out = (unsigned char *) STBIW_MALLOC(8 + 12 + 13 + 12 + zlen + 12);
1179 | if (!out) return 0;
1180 | *out_len = 8 + 12 + 13 + 12 + zlen + 12;
1181 |
1182 | o = out;
1183 | STBIW_MEMMOVE(o, sig, 8);
1184 | o += 8;
1185 | stbiw__wp32(o, 13); // header length
1186 | stbiw__wptag(o, "IHDR");
1187 | stbiw__wp32(o, x);
1188 | stbiw__wp32(o, y);
1189 | *o++ = 8;
1190 | *o++ = STBIW_UCHAR(ctype[n]);
1191 | *o++ = 0;
1192 | *o++ = 0;
1193 | *o++ = 0;
1194 | stbiw__wpcrc(&o, 13);
1195 |
1196 | stbiw__wp32(o, zlen);
1197 | stbiw__wptag(o, "IDAT");
1198 | STBIW_MEMMOVE(o, zlib, zlen);
1199 | o += zlen;
1200 | STBIW_FREE(zlib);
1201 | stbiw__wpcrc(&o, zlen);
1202 |
1203 | stbiw__wp32(o, 0);
1204 | stbiw__wptag(o, "IEND");
1205 | stbiw__wpcrc(&o, 0);
1206 |
1207 | STBIW_ASSERT(o == out + *out_len);
1208 |
1209 | return out;
1210 | }
1211 |
1212 | #ifndef STBI_WRITE_NO_STDIO
1213 |
1214 | STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes) {
1215 | FILE *f;
1216 | int len;
1217 | unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len);
1218 | if (png == NULL) return 0;
1219 |
1220 | f = stbiw__fopen(filename, "wb");
1221 | if (!f) {
1222 | STBIW_FREE(png);
1223 | return 0;
1224 | }
1225 | fwrite(png, 1, len, f);
1226 | fclose(f);
1227 | STBIW_FREE(png);
1228 | return 1;
1229 | }
1230 |
1231 | #endif
1232 |
1233 | STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data,
1234 | int stride_bytes) {
1235 | int len;
1236 | unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len);
1237 | if (png == NULL) return 0;
1238 | func(context, png, len);
1239 | STBIW_FREE(png);
1240 | return 1;
1241 | }
1242 |
1243 |
1244 | /* ***************************************************************************
1245 | *
1246 | * JPEG writer
1247 | *
1248 | * This is based on Jon Olick's jo_jpeg.cpp:
1249 | * public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html
1250 | */
1251 |
1252 | static const unsigned char stbiw__jpg_ZigZag[] = {0, 1, 5, 6, 14, 15, 27, 28, 2, 4, 7, 13, 16, 26, 29, 42, 3, 8, 12, 17,
1253 | 25, 30, 41, 43, 9, 11, 18,
1254 | 24, 31, 40, 44, 53, 10, 19, 23, 32, 39, 45, 52, 54, 20, 22, 33, 38,
1255 | 46, 51, 55, 60, 21, 34, 37, 47, 50, 56, 59, 61, 35, 36, 48, 49, 57,
1256 | 58, 62, 63};
1257 |
1258 | static void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) {
1259 | int bitBuf = *bitBufP, bitCnt = *bitCntP;
1260 | bitCnt += bs[1];
1261 | bitBuf |= bs[0] << (24 - bitCnt);
1262 | while (bitCnt >= 8) {
1263 | unsigned char c = (bitBuf >> 16) & 255;
1264 | stbiw__putc(s, c);
1265 | if (c == 255) {
1266 | stbiw__putc(s, 0);
1267 | }
1268 | bitBuf <<= 8;
1269 | bitCnt -= 8;
1270 | }
1271 | *bitBufP = bitBuf;
1272 | *bitCntP = bitCnt;
1273 | }
1274 |
1275 | static void
1276 | stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) {
1277 | float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p;
1278 | float z1, z2, z3, z4, z5, z11, z13;
1279 |
1280 | float tmp0 = d0 + d7;
1281 | float tmp7 = d0 - d7;
1282 | float tmp1 = d1 + d6;
1283 | float tmp6 = d1 - d6;
1284 | float tmp2 = d2 + d5;
1285 | float tmp5 = d2 - d5;
1286 | float tmp3 = d3 + d4;
1287 | float tmp4 = d3 - d4;
1288 |
1289 | // Even part
1290 | float tmp10 = tmp0 + tmp3; // phase 2
1291 | float tmp13 = tmp0 - tmp3;
1292 | float tmp11 = tmp1 + tmp2;
1293 | float tmp12 = tmp1 - tmp2;
1294 |
1295 | d0 = tmp10 + tmp11; // phase 3
1296 | d4 = tmp10 - tmp11;
1297 |
1298 | z1 = (tmp12 + tmp13) * 0.707106781f; // c4
1299 | d2 = tmp13 + z1; // phase 5
1300 | d6 = tmp13 - z1;
1301 |
1302 | // Odd part
1303 | tmp10 = tmp4 + tmp5; // phase 2
1304 | tmp11 = tmp5 + tmp6;
1305 | tmp12 = tmp6 + tmp7;
1306 |
1307 | // The rotator is modified from fig 4-8 to avoid extra negations.
1308 | z5 = (tmp10 - tmp12) * 0.382683433f; // c6
1309 | z2 = tmp10 * 0.541196100f + z5; // c2-c6
1310 | z4 = tmp12 * 1.306562965f + z5; // c2+c6
1311 | z3 = tmp11 * 0.707106781f; // c4
1312 |
1313 | z11 = tmp7 + z3; // phase 5
1314 | z13 = tmp7 - z3;
1315 |
1316 | *d5p = z13 + z2; // phase 6
1317 | *d3p = z13 - z2;
1318 | *d1p = z11 + z4;
1319 | *d7p = z11 - z4;
1320 |
1321 | *d0p = d0;
1322 | *d2p = d2;
1323 | *d4p = d4;
1324 | *d6p = d6;
1325 | }
1326 |
1327 | static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) {
1328 | int tmp1 = val < 0 ? -val : val;
1329 | val = val < 0 ? val - 1 : val;
1330 | bits[1] = 1;
1331 | while (tmp1 >>= 1) {
1332 | ++bits[1];
1333 | }
1334 | bits[0] = val & ((1 << bits[1]) - 1);
1335 | }
1336 |
1337 | static int
1338 | stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt, float *CDU, int du_stride, float *fdtbl, int DC,
1339 | const unsigned short HTDC[256][2], const unsigned short HTAC[256][2]) {
1340 | const unsigned short EOB[2] = {HTAC[0x00][0], HTAC[0x00][1]};
1341 | const unsigned short M16zeroes[2] = {HTAC[0xF0][0], HTAC[0xF0][1]};
1342 | int dataOff, i, j, n, diff, end0pos, x, y;
1343 | int DU[64];
1344 |
1345 | // DCT rows
1346 | for (dataOff = 0, n = du_stride * 8; dataOff < n; dataOff += du_stride) {
1347 | stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff + 1], &CDU[dataOff + 2], &CDU[dataOff + 3], &CDU[dataOff + 4],
1348 | &CDU[dataOff + 5], &CDU[dataOff + 6], &CDU[dataOff + 7]);
1349 | }
1350 | // DCT columns
1351 | for (dataOff = 0; dataOff < 8; ++dataOff) {
1352 | stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff + du_stride], &CDU[dataOff + du_stride * 2],
1353 | &CDU[dataOff + du_stride * 3], &CDU[dataOff + du_stride * 4],
1354 | &CDU[dataOff + du_stride * 5], &CDU[dataOff + du_stride * 6], &CDU[dataOff + du_stride * 7]);
1355 | }
1356 | // Quantize/descale/zigzag the coefficients
1357 | for (y = 0, j = 0; y < 8; ++y) {
1358 | for (x = 0; x < 8; ++x, ++j) {
1359 | float v;
1360 | i = y * du_stride + x;
1361 | v = CDU[i] * fdtbl[j];
1362 | // DU[stbiw__jpg_ZigZag[j]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f));
1363 | // ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway?
1364 | DU[stbiw__jpg_ZigZag[j]] = (int) (v < 0 ? v - 0.5f : v + 0.5f);
1365 | }
1366 | }
1367 |
1368 | // Encode DC
1369 | diff = DU[0] - DC;
1370 | if (diff == 0) {
1371 | stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[0]);
1372 | } else {
1373 | unsigned short bits[2];
1374 | stbiw__jpg_calcBits(diff, bits);
1375 | stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[bits[1]]);
1376 | stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits);
1377 | }
1378 | // Encode ACs
1379 | end0pos = 63;
1380 | for (; (end0pos > 0) && (DU[end0pos] == 0); --end0pos) {
1381 | }
1382 | // end0pos = first element in reverse order !=0
1383 | if (end0pos == 0) {
1384 | stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB);
1385 | return DU[0];
1386 | }
1387 | for (i = 1; i <= end0pos; ++i) {
1388 | int startpos = i;
1389 | int nrzeroes;
1390 | unsigned short bits[2];
1391 | for (; DU[i] == 0 && i <= end0pos; ++i) {
1392 | }
1393 | nrzeroes = i - startpos;
1394 | if (nrzeroes >= 16) {
1395 | int lng = nrzeroes >> 4;
1396 | int nrmarker;
1397 | for (nrmarker = 1; nrmarker <= lng; ++nrmarker)
1398 | stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes);
1399 | nrzeroes &= 15;
1400 | }
1401 | stbiw__jpg_calcBits(DU[i], bits);
1402 | stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes << 4) + bits[1]]);
1403 | stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits);
1404 | }
1405 | if (end0pos != 63) {
1406 | stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB);
1407 | }
1408 | return DU[0];
1409 | }
1410 |
1411 | static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void *data, int quality) {
1412 | // Constants that don't pollute global namespace
1413 | 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};
1414 | static const unsigned char std_dc_luminance_values[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
1415 | 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};
1416 | static const unsigned char std_ac_luminance_values[] = {
1417 | 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71,
1418 | 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
1419 | 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18,
1420 | 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
1421 | 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53,
1422 | 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
1423 | 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83,
1424 | 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
1425 | 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
1426 | 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
1427 | 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
1428 | 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
1429 | 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa
1430 | };
1431 | 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};
1432 | static const unsigned char std_dc_chrominance_values[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
1433 | 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};
1434 | static const unsigned char std_ac_chrominance_values[] = {
1435 | 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22,
1436 | 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
1437 | 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25,
1438 | 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
1439 | 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
1440 | 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
1441 | 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
1442 | 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
1443 | 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
1444 | 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
1445 | 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
1446 | 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
1447 | 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa
1448 | };
1449 | // Huffman tables
1450 | static const unsigned short YDC_HT[256][2] = {{0, 2},
1451 | {2, 3},
1452 | {3, 3},
1453 | {4, 3},
1454 | {5, 3},
1455 | {6, 3},
1456 | {14, 4},
1457 | {30, 5},
1458 | {62, 6},
1459 | {126, 7},
1460 | {254, 8},
1461 | {510, 9}};
1462 | static const unsigned short UVDC_HT[256][2] = {{0, 2},
1463 | {1, 2},
1464 | {2, 2},
1465 | {6, 3},
1466 | {14, 4},
1467 | {30, 5},
1468 | {62, 6},
1469 | {126, 7},
1470 | {254, 8},
1471 | {510, 9},
1472 | {1022, 10},
1473 | {2046, 11}};
1474 | static const unsigned short YAC_HT[256][2] = {
1475 | {10, 4},
1476 | {0, 2},
1477 | {1, 2},
1478 | {4, 3},
1479 | {11, 4},
1480 | {26, 5},
1481 | {120, 7},
1482 | {248, 8},
1483 | {1014, 10},
1484 | {65410, 16},
1485 | {65411, 16},
1486 | {0, 0},
1487 | {0, 0},
1488 | {0, 0},
1489 | {0, 0},
1490 | {0, 0},
1491 | {0, 0},
1492 | {12, 4},
1493 | {27, 5},
1494 | {121, 7},
1495 | {502, 9},
1496 | {2038, 11},
1497 | {65412, 16},
1498 | {65413, 16},
1499 | {65414, 16},
1500 | {65415, 16},
1501 | {65416, 16},
1502 | {0, 0},
1503 | {0, 0},
1504 | {0, 0},
1505 | {0, 0},
1506 | {0, 0},
1507 | {0, 0},
1508 | {28, 5},
1509 | {249, 8},
1510 | {1015, 10},
1511 | {4084, 12},
1512 | {65417, 16},
1513 | {65418, 16},
1514 | {65419, 16},
1515 | {65420, 16},
1516 | {65421, 16},
1517 | {65422, 16},
1518 | {0, 0},
1519 | {0, 0},
1520 | {0, 0},
1521 | {0, 0},
1522 | {0, 0},
1523 | {0, 0},
1524 | {58, 6},
1525 | {503, 9},
1526 | {4085, 12},
1527 | {65423, 16},
1528 | {65424, 16},
1529 | {65425, 16},
1530 | {65426, 16},
1531 | {65427, 16},
1532 | {65428, 16},
1533 | {65429, 16},
1534 | {0, 0},
1535 | {0, 0},
1536 | {0, 0},
1537 | {0, 0},
1538 | {0, 0},
1539 | {0, 0},
1540 | {59, 6},
1541 | {1016, 10},
1542 | {65430, 16},
1543 | {65431, 16},
1544 | {65432, 16},
1545 | {65433, 16},
1546 | {65434, 16},
1547 | {65435, 16},
1548 | {65436, 16},
1549 | {65437, 16},
1550 | {0, 0},
1551 | {0, 0},
1552 | {0, 0},
1553 | {0, 0},
1554 | {0, 0},
1555 | {0, 0},
1556 | {122, 7},
1557 | {2039, 11},
1558 | {65438, 16},
1559 | {65439, 16},
1560 | {65440, 16},
1561 | {65441, 16},
1562 | {65442, 16},
1563 | {65443, 16},
1564 | {65444, 16},
1565 | {65445, 16},
1566 | {0, 0},
1567 | {0, 0},
1568 | {0, 0},
1569 | {0, 0},
1570 | {0, 0},
1571 | {0, 0},
1572 | {123, 7},
1573 | {4086, 12},
1574 | {65446, 16},
1575 | {65447, 16},
1576 | {65448, 16},
1577 | {65449, 16},
1578 | {65450, 16},
1579 | {65451, 16},
1580 | {65452, 16},
1581 | {65453, 16},
1582 | {0, 0},
1583 | {0, 0},
1584 | {0, 0},
1585 | {0, 0},
1586 | {0, 0},
1587 | {0, 0},
1588 | {250, 8},
1589 | {4087, 12},
1590 | {65454, 16},
1591 | {65455, 16},
1592 | {65456, 16},
1593 | {65457, 16},
1594 | {65458, 16},
1595 | {65459, 16},
1596 | {65460, 16},
1597 | {65461, 16},
1598 | {0, 0},
1599 | {0, 0},
1600 | {0, 0},
1601 | {0, 0},
1602 | {0, 0},
1603 | {0, 0},
1604 | {504, 9},
1605 | {32704, 15},
1606 | {65462, 16},
1607 | {65463, 16},
1608 | {65464, 16},
1609 | {65465, 16},
1610 | {65466, 16},
1611 | {65467, 16},
1612 | {65468, 16},
1613 | {65469, 16},
1614 | {0, 0},
1615 | {0, 0},
1616 | {0, 0},
1617 | {0, 0},
1618 | {0, 0},
1619 | {0, 0},
1620 | {505, 9},
1621 | {65470, 16},
1622 | {65471, 16},
1623 | {65472, 16},
1624 | {65473, 16},
1625 | {65474, 16},
1626 | {65475, 16},
1627 | {65476, 16},
1628 | {65477, 16},
1629 | {65478, 16},
1630 | {0, 0},
1631 | {0, 0},
1632 | {0, 0},
1633 | {0, 0},
1634 | {0, 0},
1635 | {0, 0},
1636 | {506, 9},
1637 | {65479, 16},
1638 | {65480, 16},
1639 | {65481, 16},
1640 | {65482, 16},
1641 | {65483, 16},
1642 | {65484, 16},
1643 | {65485, 16},
1644 | {65486, 16},
1645 | {65487, 16},
1646 | {0, 0},
1647 | {0, 0},
1648 | {0, 0},
1649 | {0, 0},
1650 | {0, 0},
1651 | {0, 0},
1652 | {1017, 10},
1653 | {65488, 16},
1654 | {65489, 16},
1655 | {65490, 16},
1656 | {65491, 16},
1657 | {65492, 16},
1658 | {65493, 16},
1659 | {65494, 16},
1660 | {65495, 16},
1661 | {65496, 16},
1662 | {0, 0},
1663 | {0, 0},
1664 | {0, 0},
1665 | {0, 0},
1666 | {0, 0},
1667 | {0, 0},
1668 | {1018, 10},
1669 | {65497, 16},
1670 | {65498, 16},
1671 | {65499, 16},
1672 | {65500, 16},
1673 | {65501, 16},
1674 | {65502, 16},
1675 | {65503, 16},
1676 | {65504, 16},
1677 | {65505, 16},
1678 | {0, 0},
1679 | {0, 0},
1680 | {0, 0},
1681 | {0, 0},
1682 | {0, 0},
1683 | {0, 0},
1684 | {2040, 11},
1685 | {65506, 16},
1686 | {65507, 16},
1687 | {65508, 16},
1688 | {65509, 16},
1689 | {65510, 16},
1690 | {65511, 16},
1691 | {65512, 16},
1692 | {65513, 16},
1693 | {65514, 16},
1694 | {0, 0},
1695 | {0, 0},
1696 | {0, 0},
1697 | {0, 0},
1698 | {0, 0},
1699 | {0, 0},
1700 | {65515, 16},
1701 | {65516, 16},
1702 | {65517, 16},
1703 | {65518, 16},
1704 | {65519, 16},
1705 | {65520, 16},
1706 | {65521, 16},
1707 | {65522, 16},
1708 | {65523, 16},
1709 | {65524, 16},
1710 | {0, 0},
1711 | {0, 0},
1712 | {0, 0},
1713 | {0, 0},
1714 | {0, 0},
1715 | {2041, 11},
1716 | {65525, 16},
1717 | {65526, 16},
1718 | {65527, 16},
1719 | {65528, 16},
1720 | {65529, 16},
1721 | {65530, 16},
1722 | {65531, 16},
1723 | {65532, 16},
1724 | {65533, 16},
1725 | {65534, 16},
1726 | {0, 0},
1727 | {0, 0},
1728 | {0, 0},
1729 | {0, 0},
1730 | {0, 0}
1731 | };
1732 | static const unsigned short UVAC_HT[256][2] = {
1733 | {0, 2},
1734 | {1, 2},
1735 | {4, 3},
1736 | {10, 4},
1737 | {24, 5},
1738 | {25, 5},
1739 | {56, 6},
1740 | {120, 7},
1741 | {500, 9},
1742 | {1014, 10},
1743 | {4084, 12},
1744 | {0, 0},
1745 | {0, 0},
1746 | {0, 0},
1747 | {0, 0},
1748 | {0, 0},
1749 | {0, 0},
1750 | {11, 4},
1751 | {57, 6},
1752 | {246, 8},
1753 | {501, 9},
1754 | {2038, 11},
1755 | {4085, 12},
1756 | {65416, 16},
1757 | {65417, 16},
1758 | {65418, 16},
1759 | {65419, 16},
1760 | {0, 0},
1761 | {0, 0},
1762 | {0, 0},
1763 | {0, 0},
1764 | {0, 0},
1765 | {0, 0},
1766 | {26, 5},
1767 | {247, 8},
1768 | {1015, 10},
1769 | {4086, 12},
1770 | {32706, 15},
1771 | {65420, 16},
1772 | {65421, 16},
1773 | {65422, 16},
1774 | {65423, 16},
1775 | {65424, 16},
1776 | {0, 0},
1777 | {0, 0},
1778 | {0, 0},
1779 | {0, 0},
1780 | {0, 0},
1781 | {0, 0},
1782 | {27, 5},
1783 | {248, 8},
1784 | {1016, 10},
1785 | {4087, 12},
1786 | {65425, 16},
1787 | {65426, 16},
1788 | {65427, 16},
1789 | {65428, 16},
1790 | {65429, 16},
1791 | {65430, 16},
1792 | {0, 0},
1793 | {0, 0},
1794 | {0, 0},
1795 | {0, 0},
1796 | {0, 0},
1797 | {0, 0},
1798 | {58, 6},
1799 | {502, 9},
1800 | {65431, 16},
1801 | {65432, 16},
1802 | {65433, 16},
1803 | {65434, 16},
1804 | {65435, 16},
1805 | {65436, 16},
1806 | {65437, 16},
1807 | {65438, 16},
1808 | {0, 0},
1809 | {0, 0},
1810 | {0, 0},
1811 | {0, 0},
1812 | {0, 0},
1813 | {0, 0},
1814 | {59, 6},
1815 | {1017, 10},
1816 | {65439, 16},
1817 | {65440, 16},
1818 | {65441, 16},
1819 | {65442, 16},
1820 | {65443, 16},
1821 | {65444, 16},
1822 | {65445, 16},
1823 | {65446, 16},
1824 | {0, 0},
1825 | {0, 0},
1826 | {0, 0},
1827 | {0, 0},
1828 | {0, 0},
1829 | {0, 0},
1830 | {121, 7},
1831 | {2039, 11},
1832 | {65447, 16},
1833 | {65448, 16},
1834 | {65449, 16},
1835 | {65450, 16},
1836 | {65451, 16},
1837 | {65452, 16},
1838 | {65453, 16},
1839 | {65454, 16},
1840 | {0, 0},
1841 | {0, 0},
1842 | {0, 0},
1843 | {0, 0},
1844 | {0, 0},
1845 | {0, 0},
1846 | {122, 7},
1847 | {2040, 11},
1848 | {65455, 16},
1849 | {65456, 16},
1850 | {65457, 16},
1851 | {65458, 16},
1852 | {65459, 16},
1853 | {65460, 16},
1854 | {65461, 16},
1855 | {65462, 16},
1856 | {0, 0},
1857 | {0, 0},
1858 | {0, 0},
1859 | {0, 0},
1860 | {0, 0},
1861 | {0, 0},
1862 | {249, 8},
1863 | {65463, 16},
1864 | {65464, 16},
1865 | {65465, 16},
1866 | {65466, 16},
1867 | {65467, 16},
1868 | {65468, 16},
1869 | {65469, 16},
1870 | {65470, 16},
1871 | {65471, 16},
1872 | {0, 0},
1873 | {0, 0},
1874 | {0, 0},
1875 | {0, 0},
1876 | {0, 0},
1877 | {0, 0},
1878 | {503, 9},
1879 | {65472, 16},
1880 | {65473, 16},
1881 | {65474, 16},
1882 | {65475, 16},
1883 | {65476, 16},
1884 | {65477, 16},
1885 | {65478, 16},
1886 | {65479, 16},
1887 | {65480, 16},
1888 | {0, 0},
1889 | {0, 0},
1890 | {0, 0},
1891 | {0, 0},
1892 | {0, 0},
1893 | {0, 0},
1894 | {504, 9},
1895 | {65481, 16},
1896 | {65482, 16},
1897 | {65483, 16},
1898 | {65484, 16},
1899 | {65485, 16},
1900 | {65486, 16},
1901 | {65487, 16},
1902 | {65488, 16},
1903 | {65489, 16},
1904 | {0, 0},
1905 | {0, 0},
1906 | {0, 0},
1907 | {0, 0},
1908 | {0, 0},
1909 | {0, 0},
1910 | {505, 9},
1911 | {65490, 16},
1912 | {65491, 16},
1913 | {65492, 16},
1914 | {65493, 16},
1915 | {65494, 16},
1916 | {65495, 16},
1917 | {65496, 16},
1918 | {65497, 16},
1919 | {65498, 16},
1920 | {0, 0},
1921 | {0, 0},
1922 | {0, 0},
1923 | {0, 0},
1924 | {0, 0},
1925 | {0, 0},
1926 | {506, 9},
1927 | {65499, 16},
1928 | {65500, 16},
1929 | {65501, 16},
1930 | {65502, 16},
1931 | {65503, 16},
1932 | {65504, 16},
1933 | {65505, 16},
1934 | {65506, 16},
1935 | {65507, 16},
1936 | {0, 0},
1937 | {0, 0},
1938 | {0, 0},
1939 | {0, 0},
1940 | {0, 0},
1941 | {0, 0},
1942 | {2041, 11},
1943 | {65508, 16},
1944 | {65509, 16},
1945 | {65510, 16},
1946 | {65511, 16},
1947 | {65512, 16},
1948 | {65513, 16},
1949 | {65514, 16},
1950 | {65515, 16},
1951 | {65516, 16},
1952 | {0, 0},
1953 | {0, 0},
1954 | {0, 0},
1955 | {0, 0},
1956 | {0, 0},
1957 | {0, 0},
1958 | {16352, 14},
1959 | {65517, 16},
1960 | {65518, 16},
1961 | {65519, 16},
1962 | {65520, 16},
1963 | {65521, 16},
1964 | {65522, 16},
1965 | {65523, 16},
1966 | {65524, 16},
1967 | {65525, 16},
1968 | {0, 0},
1969 | {0, 0},
1970 | {0, 0},
1971 | {0, 0},
1972 | {0, 0},
1973 | {1018, 10},
1974 | {32707, 15},
1975 | {65526, 16},
1976 | {65527, 16},
1977 | {65528, 16},
1978 | {65529, 16},
1979 | {65530, 16},
1980 | {65531, 16},
1981 | {65532, 16},
1982 | {65533, 16},
1983 | {65534, 16},
1984 | {0, 0},
1985 | {0, 0},
1986 | {0, 0},
1987 | {0, 0},
1988 | {0, 0}
1989 | };
1990 | 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,
1991 | 69, 56, 14, 17, 22, 29, 51, 87, 80, 62, 18, 22,
1992 | 37, 56, 68, 109, 103, 77, 24, 35, 55, 64, 81, 104, 113, 92, 49, 64, 78, 87, 103, 121, 120,
1993 | 101, 72, 92, 95, 98, 112, 100, 103, 99};
1994 | 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,
1995 | 99, 99, 47, 66, 99, 99, 99, 99, 99, 99,
1996 | 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
1997 | 99, 99, 99, 99, 99, 99, 99, 99, 99, 99};
1998 | static const float aasf[] = {1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f,
1999 | 1.175875602f * 2.828427125f,
2000 | 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f,
2001 | 0.275899379f * 2.828427125f};
2002 |
2003 | int row, col, i, k, subsample;
2004 | float fdtbl_Y[64], fdtbl_UV[64];
2005 | unsigned char YTable[64], UVTable[64];
2006 |
2007 | if (!data || !width || !height || comp > 4 || comp < 1) {
2008 | return 0;
2009 | }
2010 |
2011 | quality = quality ? quality : 90;
2012 | subsample = quality <= 90 ? 1 : 0;
2013 | quality = quality < 1 ? 1 : quality > 100 ? 100 : quality;
2014 | quality = quality < 50 ? 5000 / quality : 200 - quality * 2;
2015 |
2016 | for (i = 0; i < 64; ++i) {
2017 | int uvti, yti = (YQT[i] * quality + 50) / 100;
2018 | YTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (yti < 1 ? 1 : yti > 255 ? 255 : yti);
2019 | uvti = (UVQT[i] * quality + 50) / 100;
2020 | UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti);
2021 | }
2022 |
2023 | for (row = 0, k = 0; row < 8; ++row) {
2024 | for (col = 0; col < 8; ++col, ++k) {
2025 | fdtbl_Y[k] = 1 / (YTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]);
2026 | fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]);
2027 | }
2028 | }
2029 |
2030 | // Write Headers
2031 | {
2032 | static const unsigned char head0[] = {0xFF, 0xD8, 0xFF, 0xE0, 0, 0x10, 'J', 'F', 'I', 'F', 0, 1, 1, 0, 0, 1, 0,
2033 | 1, 0, 0, 0xFF, 0xDB, 0, 0x84, 0};
2034 | static const unsigned char head2[] = {0xFF, 0xDA, 0, 0xC, 3, 1, 0, 2, 0x11, 3, 0x11, 0, 0x3F, 0};
2035 | const unsigned char head1[] = {0xFF, 0xC0, 0, 0x11, 8, (unsigned char) (height >> 8), STBIW_UCHAR(height),
2036 | (unsigned char) (width >> 8), STBIW_UCHAR(width),
2037 | 3, 1, (unsigned char) (subsample ? 0x22 : 0x11), 0, 2, 0x11, 1, 3, 0x11, 1, 0xFF,
2038 | 0xC4, 0x01, 0xA2, 0};
2039 | s->func(s->context, (void *) head0, sizeof(head0));
2040 | s->func(s->context, (void *) YTable, sizeof(YTable));
2041 | stbiw__putc(s, 1);
2042 | s->func(s->context, UVTable, sizeof(UVTable));
2043 | s->func(s->context, (void *) head1, sizeof(head1));
2044 | s->func(s->context, (void *) (std_dc_luminance_nrcodes + 1), sizeof(std_dc_luminance_nrcodes) - 1);
2045 | s->func(s->context, (void *) std_dc_luminance_values, sizeof(std_dc_luminance_values));
2046 | stbiw__putc(s, 0x10); // HTYACinfo
2047 | s->func(s->context, (void *) (std_ac_luminance_nrcodes + 1), sizeof(std_ac_luminance_nrcodes) - 1);
2048 | s->func(s->context, (void *) std_ac_luminance_values, sizeof(std_ac_luminance_values));
2049 | stbiw__putc(s, 1); // HTUDCinfo
2050 | s->func(s->context, (void *) (std_dc_chrominance_nrcodes + 1), sizeof(std_dc_chrominance_nrcodes) - 1);
2051 | s->func(s->context, (void *) std_dc_chrominance_values, sizeof(std_dc_chrominance_values));
2052 | stbiw__putc(s, 0x11); // HTUACinfo
2053 | s->func(s->context, (void *) (std_ac_chrominance_nrcodes + 1), sizeof(std_ac_chrominance_nrcodes) - 1);
2054 | s->func(s->context, (void *) std_ac_chrominance_values, sizeof(std_ac_chrominance_values));
2055 | s->func(s->context, (void *) head2, sizeof(head2));
2056 | }
2057 |
2058 | // Encode 8x8 macroblocks
2059 | {
2060 | static const unsigned short fillBits[] = {0x7F, 7};
2061 | int DCY = 0, DCU = 0, DCV = 0;
2062 | int bitBuf = 0, bitCnt = 0;
2063 | // comp == 2 is grey+alpha (alpha is ignored)
2064 | int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0;
2065 | const unsigned char *dataR = (const unsigned char *) data;
2066 | const unsigned char *dataG = dataR + ofsG;
2067 | const unsigned char *dataB = dataR + ofsB;
2068 | int x, y, pos;
2069 | if (subsample) {
2070 | for (y = 0; y < height; y += 16) {
2071 | for (x = 0; x < width; x += 16) {
2072 | float Y[256], U[256], V[256];
2073 | for (row = y, pos = 0; row < y + 16; ++row) {
2074 | // row >= height => use last input row
2075 | int clamped_row = (row < height) ? row : height - 1;
2076 | int base_p =
2077 | (stbi__flip_vertically_on_write ? (height - 1 - clamped_row) : clamped_row) * width *
2078 | comp;
2079 | for (col = x; col < x + 16; ++col, ++pos) {
2080 | // if col >= width => use pixel from last input column
2081 | int p = base_p + ((col < width) ? col : (width - 1)) * comp;
2082 | float r = dataR[p], g = dataG[p], b = dataB[p];
2083 | Y[pos] = +0.29900f * r + 0.58700f * g + 0.11400f * b - 128;
2084 | U[pos] = -0.16874f * r - 0.33126f * g + 0.50000f * b;
2085 | V[pos] = +0.50000f * r - 0.41869f * g - 0.08131f * b;
2086 | }
2087 | }
2088 | DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y + 0, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);
2089 | DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y + 8, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);
2090 | DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y + 128, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);
2091 | DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y + 136, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);
2092 |
2093 | // subsample U,V
2094 | {
2095 | float subU[64], subV[64];
2096 | int yy, xx;
2097 | for (yy = 0, pos = 0; yy < 8; ++yy) {
2098 | for (xx = 0; xx < 8; ++xx, ++pos) {
2099 | int j = yy * 32 + xx * 2;
2100 | subU[pos] = (U[j + 0] + U[j + 1] + U[j + 16] + U[j + 17]) * 0.25f;
2101 | subV[pos] = (V[j + 0] + V[j + 1] + V[j + 16] + V[j + 17]) * 0.25f;
2102 | }
2103 | }
2104 | DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
2105 | DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);
2106 | }
2107 | }
2108 | }
2109 | } else {
2110 | for (y = 0; y < height; y += 8) {
2111 | for (x = 0; x < width; x += 8) {
2112 | float Y[64], U[64], V[64];
2113 | for (row = y, pos = 0; row < y + 8; ++row) {
2114 | // row >= height => use last input row
2115 | int clamped_row = (row < height) ? row : height - 1;
2116 | int base_p =
2117 | (stbi__flip_vertically_on_write ? (height - 1 - clamped_row) : clamped_row) * width *
2118 | comp;
2119 | for (col = x; col < x + 8; ++col, ++pos) {
2120 | // if col >= width => use pixel from last input column
2121 | int p = base_p + ((col < width) ? col : (width - 1)) * comp;
2122 | float r = dataR[p], g = dataG[p], b = dataB[p];
2123 | Y[pos] = +0.29900f * r + 0.58700f * g + 0.11400f * b - 128;
2124 | U[pos] = -0.16874f * r - 0.33126f * g + 0.50000f * b;
2125 | V[pos] = +0.50000f * r - 0.41869f * g - 0.08131f * b;
2126 | }
2127 | }
2128 |
2129 | DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y, DCY, YDC_HT, YAC_HT);
2130 | DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
2131 | DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);
2132 | }
2133 | }
2134 | }
2135 |
2136 | // Do the bit alignment of the EOI marker
2137 | stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits);
2138 | }
2139 |
2140 | // EOI
2141 | stbiw__putc(s, 0xFF);
2142 | stbiw__putc(s, 0xD9);
2143 |
2144 | return 1;
2145 | }
2146 |
2147 | STBIWDEF int
2148 | stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality) {
2149 | stbi__write_context s;
2150 | stbi__start_write_callbacks(&s, func, context);
2151 | return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality);
2152 | }
2153 |
2154 |
2155 | #ifndef STBI_WRITE_NO_STDIO
2156 |
2157 | STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality) {
2158 | stbi__write_context s;
2159 | if (stbi__start_write_file(&s, filename)) {
2160 | int r = stbi_write_jpg_core(&s, x, y, comp, data, quality);
2161 | stbi__end_write_file(&s);
2162 | return r;
2163 | } else
2164 | return 0;
2165 | }
2166 |
2167 | #endif
2168 |
2169 | #endif // STB_IMAGE_WRITE_IMPLEMENTATION
2170 |
2171 | /* Revision history
2172 | 1.14 (2020-02-02) updated JPEG writer to downsample chroma channels
2173 | 1.13
2174 | 1.12
2175 | 1.11 (2019-08-11)
2176 |
2177 | 1.10 (2019-02-07)
2178 | support utf8 filenames in Windows; fix warnings and platform ifdefs
2179 | 1.09 (2018-02-11)
2180 | fix typo in zlib quality API, improve STB_I_W_STATIC in C++
2181 | 1.08 (2018-01-29)
2182 | add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter
2183 | 1.07 (2017-07-24)
2184 | doc fix
2185 | 1.06 (2017-07-23)
2186 | writing JPEG (using Jon Olick's code)
2187 | 1.05 ???
2188 | 1.04 (2017-03-03)
2189 | monochrome BMP expansion
2190 | 1.03 ???
2191 | 1.02 (2016-04-02)
2192 | avoid allocating large structures on the stack
2193 | 1.01 (2016-01-16)
2194 | STBIW_REALLOC_SIZED: support allocators with no realloc support
2195 | avoid race-condition in crc initialization
2196 | minor compile issues
2197 | 1.00 (2015-09-14)
2198 | installable file IO function
2199 | 0.99 (2015-09-13)
2200 | warning fixes; TGA rle support
2201 | 0.98 (2015-04-08)
2202 | added STBIW_MALLOC, STBIW_ASSERT etc
2203 | 0.97 (2015-01-18)
2204 | fixed HDR asserts, rewrote HDR rle logic
2205 | 0.96 (2015-01-17)
2206 | add HDR output
2207 | fix monochrome BMP
2208 | 0.95 (2014-08-17)
2209 | add monochrome TGA output
2210 | 0.94 (2014-05-31)
2211 | rename private functions to avoid conflicts with stb_image.h
2212 | 0.93 (2014-05-27)
2213 | warning fixes
2214 | 0.92 (2010-08-01)
2215 | casts to unsigned char to fix warnings
2216 | 0.91 (2010-07-17)
2217 | first public release
2218 | 0.90 first internal release
2219 | */
2220 |
2221 | /*
2222 | ------------------------------------------------------------------------------
2223 | This software is available under 2 licenses -- choose whichever you prefer.
2224 | ------------------------------------------------------------------------------
2225 | ALTERNATIVE A - MIT License
2226 | Copyright (c) 2017 Sean Barrett
2227 | Permission is hereby granted, free of charge, to any person obtaining a copy of
2228 | this software and associated documentation files (the "Software"), to deal in
2229 | the Software without restriction, including without limitation the rights to
2230 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
2231 | of the Software, and to permit persons to whom the Software is furnished to do
2232 | so, subject to the following conditions:
2233 | The above copyright notice and this permission notice shall be included in all
2234 | copies or substantial portions of the Software.
2235 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2236 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2237 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2238 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2239 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2240 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2241 | SOFTWARE.
2242 | ------------------------------------------------------------------------------
2243 | ALTERNATIVE B - Public Domain (www.unlicense.org)
2244 | This is free and unencumbered software released into the public domain.
2245 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
2246 | software, either in source code form or as a compiled binary, for any purpose,
2247 | commercial or non-commercial, and by any means.
2248 | In jurisdictions that recognize copyright laws, the author or authors of this
2249 | software dedicate any and all copyright interest in the software to the public
2250 | domain. We make this dedication for the benefit of the public at large and to
2251 | the detriment of our heirs and successors. We intend this dedication to be an
2252 | overt act of relinquishment in perpetuity of all present and future rights to
2253 | this software under copyright law.
2254 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2255 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2256 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2257 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2258 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
2259 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2260 | ------------------------------------------------------------------------------
2261 | */
--------------------------------------------------------------------------------