Path: blob/a-new-beginning/SharedDependencies/Sources/stb/include/stb_image_write.h
2 views
/* stb_image_write - v1.13 - public domain - http://nothings.org/stb1writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-20152no warranty implied; use at your own risk34Before #including,56#define STB_IMAGE_WRITE_IMPLEMENTATION78in the file that you want to have the implementation.910Will probably not work correctly with strict-aliasing optimizations.1112ABOUT:1314This header file is a library for writing images to C stdio or a callback.1516The PNG output is not optimal; it is 20-50% larger than the file17written by a decent optimizing implementation; though providing a custom18zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that.19This library is designed for source code compactness and simplicity,20not optimal image file size or run-time performance.2122BUILDING:2324You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h.25You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace26malloc,realloc,free.27You can #define STBIW_MEMMOVE() to replace memmove()28You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function29for PNG compression (instead of the builtin one), it must have the following signature:30unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality);31The returned data will be freed with STBIW_FREE() (free() by default),32so it must be heap allocated with STBIW_MALLOC() (malloc() by default),3334UNICODE:3536If compiling for Windows and you wish to use Unicode filenames, compile37with38#define STBIW_WINDOWS_UTF839and pass utf8-encoded filenames. Call stbiw_convert_wchar_to_utf8 to convert40Windows wchar_t filenames to utf8.4142USAGE:4344There are five functions, one for each image file format:4546int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);47int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);48int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);49int stbi_write_jpg(char const *filename, int w, int h, int comp, const void *data, int quality);50int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);5152void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically5354There are also five equivalent functions that use an arbitrary write function. You are55expected to open/close your file-equivalent before and after calling these:5657int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes);58int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);59int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);60int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);61int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);6263where the callback is:64void stbi_write_func(void *context, void *data, int size);6566You can configure it with these global variables:67int stbi_write_tga_with_rle; // defaults to true; set to 0 to disable RLE68int stbi_write_png_compression_level; // defaults to 8; set to higher for more compression69int stbi_write_force_png_filter; // defaults to -1; set to 0..5 to force a filter mode707172You can define STBI_WRITE_NO_STDIO to disable the file variant of these73functions, so the library will not use stdio.h at all. However, this will74also disable HDR writing, because it requires stdio for formatted output.7576Each function returns 0 on failure and non-0 on success.7778The functions create an image file defined by the parameters. The image79is a rectangle of pixels stored from left-to-right, top-to-bottom.80Each pixel contains 'comp' channels of data stored interleaved with 8-bits81per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is82monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall.83The *data pointer points to the first byte of the top-left-most pixel.84For PNG, "stride_in_bytes" is the distance in bytes from the first byte of85a row of pixels to the first byte of the next row of pixels.8687PNG creates output files with the same number of components as the input.88The BMP format expands Y to RGB in the file format and does not89output alpha.9091PNG supports writing rectangles of data even when the bytes storing rows of92data are not consecutive in memory (e.g. sub-rectangles of a larger image),93by supplying the stride between the beginning of adjacent rows. The other94formats do not. (Thus you cannot write a native-format BMP through the BMP95writer, both because it is in BGR order and because it may have padding96at the end of the line.)9798PNG allows you to set the deflate compression level by setting the global99variable 'stbi_write_png_compression_level' (it defaults to 8).100101HDR expects linear float data. Since the format is always 32-bit rgb(e)102data, alpha (if provided) is discarded, and for monochrome data it is103replicated across all three channels.104105TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed106data, set the global variable 'stbi_write_tga_with_rle' to 0.107108JPEG does ignore alpha channels in input data; quality is between 1 and 100.109Higher quality looks better but results in a bigger image.110JPEG baseline (no JPEG progressive).111112CREDITS:113114115Sean Barrett - PNG/BMP/TGA116Baldur Karlsson - HDR117Jean-Sebastien Guay - TGA monochrome118Tim Kelsey - misc enhancements119Alan Hickman - TGA RLE120Emmanuel Julien - initial file IO callback implementation121Jon Olick - original jo_jpeg.cpp code122Daniel Gibson - integrate JPEG, allow external zlib123Aarni Koskela - allow choosing PNG filter124125bugfixes:126github:Chribba127Guillaume Chereau128github:jry2129github:romigrou130Sergio Gonzalez131Jonas Karlsson132Filip Wasil133Thatcher Ulrich134github:poppolopoppo135Patrick Boettcher136github:xeekworx137Cap Petschulat138Simon Rodriguez139Ivan Tikhonov140github:ignotion141Adam Schackart142143LICENSE144145See end of file for license information.146147*/148149#ifndef INCLUDE_STB_IMAGE_WRITE_H150#define INCLUDE_STB_IMAGE_WRITE_H151152#include <stdlib.h>153154// if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline'155#ifndef STBIWDEF156#ifdef STB_IMAGE_WRITE_STATIC157#define STBIWDEF static158#else159#ifdef __cplusplus160#define STBIWDEF extern "C"161#else162#define STBIWDEF extern163#endif164#endif165#endif166167#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations168extern int stbi_write_tga_with_rle;169extern int stbi_write_png_compression_level;170extern int stbi_write_force_png_filter;171#endif172173#ifndef STBI_WRITE_NO_STDIO174STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);175STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);176STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);177STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);178STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality);179180#ifdef STBI_WINDOWS_UTF8181STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);182#endif183#endif184185typedef void stbi_write_func(void *context, void *data, int size);186187STBIWDEF 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);188STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);189STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data);190STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);191STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);192193STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean);194195#endif//INCLUDE_STB_IMAGE_WRITE_H196197#ifdef STB_IMAGE_WRITE_IMPLEMENTATION198199#ifdef _WIN32200#ifndef _CRT_SECURE_NO_WARNINGS201#define _CRT_SECURE_NO_WARNINGS202#endif203#ifndef _CRT_NONSTDC_NO_DEPRECATE204#define _CRT_NONSTDC_NO_DEPRECATE205#endif206#endif207208#ifndef STBI_WRITE_NO_STDIO209#include <stdio.h>210#endif // STBI_WRITE_NO_STDIO211212#include <stdarg.h>213#include <stdlib.h>214#include <string.h>215#include <math.h>216217#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED))218// ok219#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED)220// ok221#else222#error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)."223#endif224225#ifndef STBIW_MALLOC226#define STBIW_MALLOC(sz) malloc(sz)227#define STBIW_REALLOC(p,newsz) realloc(p,newsz)228#define STBIW_FREE(p) free(p)229#endif230231#ifndef STBIW_REALLOC_SIZED232#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz)233#endif234235236#ifndef STBIW_MEMMOVE237#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz)238#endif239240241#ifndef STBIW_ASSERT242#include <assert.h>243#define STBIW_ASSERT(x) assert(x)244#endif245246#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)247248#ifdef STB_IMAGE_WRITE_STATIC249static int stbi__flip_vertically_on_write=0;250static int stbi_write_png_compression_level = 8;251static int stbi_write_tga_with_rle = 1;252static int stbi_write_force_png_filter = -1;253#else254int stbi_write_png_compression_level = 8;255int stbi__flip_vertically_on_write=0;256int stbi_write_tga_with_rle = 1;257int stbi_write_force_png_filter = -1;258#endif259260STBIWDEF void stbi_flip_vertically_on_write(int flag)261{262stbi__flip_vertically_on_write = flag;263}264265typedef struct266{267stbi_write_func *func;268void *context;269} stbi__write_context;270271// initialize a callback-based context272static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context)273{274s->func = c;275s->context = context;276}277278#ifndef STBI_WRITE_NO_STDIO279280static void stbi__stdio_write(void *context, void *data, int size)281{282fwrite(data,1,size,(FILE*) context);283}284285#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8)286#ifdef __cplusplus287#define STBIW_EXTERN extern "C"288#else289#define STBIW_EXTERN extern290#endif291STBIW_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide);292STBIW_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);293294STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input)295{296return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL);297}298#endif299300static FILE *stbiw__fopen(char const *filename, char const *mode)301{302FILE *f;303#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8)304wchar_t wMode[64];305wchar_t wFilename[1024];306if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)))307return 0;308309if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)))310return 0;311312#if _MSC_VER >= 1400313if (0 != _wfopen_s(&f, wFilename, wMode))314f = 0;315#else316f = _wfopen(wFilename, wMode);317#endif318319#elif defined(_MSC_VER) && _MSC_VER >= 1400320if (0 != fopen_s(&f, filename, mode))321f=0;322#else323f = fopen(filename, mode);324#endif325return f;326}327328static int stbi__start_write_file(stbi__write_context *s, const char *filename)329{330FILE *f = stbiw__fopen(filename, "wb");331stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f);332return f != NULL;333}334335static void stbi__end_write_file(stbi__write_context *s)336{337fclose((FILE *)s->context);338}339340#endif // !STBI_WRITE_NO_STDIO341342typedef unsigned int stbiw_uint32;343typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];344345static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v)346{347while (*fmt) {348switch (*fmt++) {349case ' ': break;350case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int));351s->func(s->context,&x,1);352break; }353case '2': { int x = va_arg(v,int);354unsigned char b[2];355b[0] = STBIW_UCHAR(x);356b[1] = STBIW_UCHAR(x>>8);357s->func(s->context,b,2);358break; }359case '4': { stbiw_uint32 x = va_arg(v,int);360unsigned char b[4];361b[0]=STBIW_UCHAR(x);362b[1]=STBIW_UCHAR(x>>8);363b[2]=STBIW_UCHAR(x>>16);364b[3]=STBIW_UCHAR(x>>24);365s->func(s->context,b,4);366break; }367default:368STBIW_ASSERT(0);369return;370}371}372}373374static void stbiw__writef(stbi__write_context *s, const char *fmt, ...)375{376va_list v;377va_start(v, fmt);378stbiw__writefv(s, fmt, v);379va_end(v);380}381382static void stbiw__putc(stbi__write_context *s, unsigned char c)383{384s->func(s->context, &c, 1);385}386387static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c)388{389unsigned char arr[3];390arr[0] = a; arr[1] = b; arr[2] = c;391s->func(s->context, arr, 3);392}393394static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d)395{396unsigned char bg[3] = { 255, 0, 255}, px[3];397int k;398399if (write_alpha < 0)400s->func(s->context, &d[comp - 1], 1);401402switch (comp) {403case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case404case 1:405if (expand_mono)406stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp407else408s->func(s->context, d, 1); // monochrome TGA409break;410case 4:411if (!write_alpha) {412// composite against pink background413for (k = 0; k < 3; ++k)414px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255;415stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]);416break;417}418/* FALLTHROUGH */419case 3:420stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]);421break;422}423if (write_alpha > 0)424s->func(s->context, &d[comp - 1], 1);425}426427static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono)428{429stbiw_uint32 zero = 0;430int i,j, j_end;431432if (y <= 0)433return;434435if (stbi__flip_vertically_on_write)436vdir *= -1;437438if (vdir < 0) {439j_end = -1; j = y-1;440} else {441j_end = y; j = 0;442}443444for (; j != j_end; j += vdir) {445for (i=0; i < x; ++i) {446unsigned char *d = (unsigned char *) data + (j*x+i)*comp;447stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d);448}449s->func(s->context, &zero, scanline_pad);450}451}452453static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...)454{455if (y < 0 || x < 0) {456return 0;457} else {458va_list v;459va_start(v, fmt);460stbiw__writefv(s, fmt, v);461va_end(v);462stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono);463return 1;464}465}466467static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data)468{469int pad = (-x*3) & 3;470return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad,471"11 4 22 4" "4 44 22 444444",472'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header47340, x,y, 1,24, 0,0,0,0,0,0); // bitmap header474}475476STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)477{478stbi__write_context s;479stbi__start_write_callbacks(&s, func, context);480return stbi_write_bmp_core(&s, x, y, comp, data);481}482483#ifndef STBI_WRITE_NO_STDIO484STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)485{486stbi__write_context s;487if (stbi__start_write_file(&s,filename)) {488int r = stbi_write_bmp_core(&s, x, y, comp, data);489stbi__end_write_file(&s);490return r;491} else492return 0;493}494#endif //!STBI_WRITE_NO_STDIO495496static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data)497{498int has_alpha = (comp == 2 || comp == 4);499int colorbytes = has_alpha ? comp-1 : comp;500int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3501502if (y < 0 || x < 0)503return 0;504505if (!stbi_write_tga_with_rle) {506return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0,507"111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8);508} else {509int i,j,k;510int jend, jdir;511512stbiw__writef(s, "111 221 2222 11", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8);513514if (stbi__flip_vertically_on_write) {515j = 0;516jend = y;517jdir = 1;518} else {519j = y-1;520jend = -1;521jdir = -1;522}523for (; j != jend; j += jdir) {524unsigned char *row = (unsigned char *) data + j * x * comp;525int len;526527for (i = 0; i < x; i += len) {528unsigned char *begin = row + i * comp;529int diff = 1;530len = 1;531532if (i < x - 1) {533++len;534diff = memcmp(begin, row + (i + 1) * comp, comp);535if (diff) {536const unsigned char *prev = begin;537for (k = i + 2; k < x && len < 128; ++k) {538if (memcmp(prev, row + k * comp, comp)) {539prev += comp;540++len;541} else {542--len;543break;544}545}546} else {547for (k = i + 2; k < x && len < 128; ++k) {548if (!memcmp(begin, row + k * comp, comp)) {549++len;550} else {551break;552}553}554}555}556557if (diff) {558unsigned char header = STBIW_UCHAR(len - 1);559s->func(s->context, &header, 1);560for (k = 0; k < len; ++k) {561stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp);562}563} else {564unsigned char header = STBIW_UCHAR(len - 129);565s->func(s->context, &header, 1);566stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin);567}568}569}570}571return 1;572}573574STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)575{576stbi__write_context s;577stbi__start_write_callbacks(&s, func, context);578return stbi_write_tga_core(&s, x, y, comp, (void *) data);579}580581#ifndef STBI_WRITE_NO_STDIO582STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)583{584stbi__write_context s;585if (stbi__start_write_file(&s,filename)) {586int r = stbi_write_tga_core(&s, x, y, comp, (void *) data);587stbi__end_write_file(&s);588return r;589} else590return 0;591}592#endif593594// *************************************************************************************************595// Radiance RGBE HDR writer596// by Baldur Karlsson597598#define stbiw__max(a, b) ((a) > (b) ? (a) : (b))599600static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)601{602int exponent;603float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2]));604605if (maxcomp < 1e-32f) {606rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;607} else {608float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp;609610rgbe[0] = (unsigned char)(linear[0] * normalize);611rgbe[1] = (unsigned char)(linear[1] * normalize);612rgbe[2] = (unsigned char)(linear[2] * normalize);613rgbe[3] = (unsigned char)(exponent + 128);614}615}616617static void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte)618{619unsigned char lengthbyte = STBIW_UCHAR(length+128);620STBIW_ASSERT(length+128 <= 255);621s->func(s->context, &lengthbyte, 1);622s->func(s->context, &databyte, 1);623}624625static void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data)626{627unsigned char lengthbyte = STBIW_UCHAR(length);628STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code629s->func(s->context, &lengthbyte, 1);630s->func(s->context, data, length);631}632633static void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline)634{635unsigned char scanlineheader[4] = { 2, 2, 0, 0 };636unsigned char rgbe[4];637float linear[3];638int x;639640scanlineheader[2] = (width&0xff00)>>8;641scanlineheader[3] = (width&0x00ff);642643/* skip RLE for images too small or large */644if (width < 8 || width >= 32768) {645for (x=0; x < width; x++) {646switch (ncomp) {647case 4: /* fallthrough */648case 3: linear[2] = scanline[x*ncomp + 2];649linear[1] = scanline[x*ncomp + 1];650linear[0] = scanline[x*ncomp + 0];651break;652default:653linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];654break;655}656stbiw__linear_to_rgbe(rgbe, linear);657s->func(s->context, rgbe, 4);658}659} else {660int c,r;661/* encode into scratch buffer */662for (x=0; x < width; x++) {663switch(ncomp) {664case 4: /* fallthrough */665case 3: linear[2] = scanline[x*ncomp + 2];666linear[1] = scanline[x*ncomp + 1];667linear[0] = scanline[x*ncomp + 0];668break;669default:670linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];671break;672}673stbiw__linear_to_rgbe(rgbe, linear);674scratch[x + width*0] = rgbe[0];675scratch[x + width*1] = rgbe[1];676scratch[x + width*2] = rgbe[2];677scratch[x + width*3] = rgbe[3];678}679680s->func(s->context, scanlineheader, 4);681682/* RLE each component separately */683for (c=0; c < 4; c++) {684unsigned char *comp = &scratch[width*c];685686x = 0;687while (x < width) {688// find first run689r = x;690while (r+2 < width) {691if (comp[r] == comp[r+1] && comp[r] == comp[r+2])692break;693++r;694}695if (r+2 >= width)696r = width;697// dump up to first run698while (x < r) {699int len = r-x;700if (len > 128) len = 128;701stbiw__write_dump_data(s, len, &comp[x]);702x += len;703}704// if there's a run, output it705if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd706// find next byte after run707while (r < width && comp[r] == comp[x])708++r;709// output run up to r710while (x < r) {711int len = r-x;712if (len > 127) len = 127;713stbiw__write_run_data(s, len, comp[x]);714x += len;715}716}717}718}719}720}721722static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data)723{724if (y <= 0 || x <= 0 || data == NULL)725return 0;726else {727// Each component is stored separately. Allocate scratch space for full output scanline.728unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4);729int i, len;730char buffer[128];731char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n";732s->func(s->context, header, sizeof(header)-1);733734#ifdef __STDC_WANT_SECURE_LIB__735len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);736#else737len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x);738#endif739s->func(s->context, buffer, len);740741for(i=0; i < y; i++)742stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i));743STBIW_FREE(scratch);744return 1;745}746}747748STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data)749{750stbi__write_context s;751stbi__start_write_callbacks(&s, func, context);752return stbi_write_hdr_core(&s, x, y, comp, (float *) data);753}754755#ifndef STBI_WRITE_NO_STDIO756STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)757{758stbi__write_context s;759if (stbi__start_write_file(&s,filename)) {760int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data);761stbi__end_write_file(&s);762return r;763} else764return 0;765}766#endif // STBI_WRITE_NO_STDIO767768769//////////////////////////////////////////////////////////////////////////////770//771// PNG writer772//773774#ifndef STBIW_ZLIB_COMPRESS775// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()776#define stbiw__sbraw(a) ((int *) (a) - 2)777#define stbiw__sbm(a) stbiw__sbraw(a)[0]778#define stbiw__sbn(a) stbiw__sbraw(a)[1]779780#define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a))781#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0)782#define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a)))783784#define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v))785#define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0)786#define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0)787788static void *stbiw__sbgrowf(void **arr, int increment, int itemsize)789{790int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1;791void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2);792STBIW_ASSERT(p);793if (p) {794if (!*arr) ((int *) p)[1] = 0;795*arr = (void *) ((int *) p + 2);796stbiw__sbm(*arr) = m;797}798return *arr;799}800801static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)802{803while (*bitcount >= 8) {804stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer));805*bitbuffer >>= 8;806*bitcount -= 8;807}808return data;809}810811static int stbiw__zlib_bitrev(int code, int codebits)812{813int res=0;814while (codebits--) {815res = (res << 1) | (code & 1);816code >>= 1;817}818return res;819}820821static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit)822{823int i;824for (i=0; i < limit && i < 258; ++i)825if (a[i] != b[i]) break;826return i;827}828829static unsigned int stbiw__zhash(unsigned char *data)830{831stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16);832hash ^= hash << 3;833hash += hash >> 5;834hash ^= hash << 4;835hash += hash >> 17;836hash ^= hash << 25;837hash += hash >> 6;838return hash;839}840841#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount))842#define stbiw__zlib_add(code,codebits) \843(bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush())844#define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c)845// default huffman tables846#define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8)847#define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9)848#define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7)849#define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8)850#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))851#define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n))852853#define stbiw__ZHASH 16384854855#endif // STBIW_ZLIB_COMPRESS856857STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)858{859#ifdef STBIW_ZLIB_COMPRESS860// user provided a zlib compress implementation, use that861return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality);862#else // use builtin863static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 };864static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 };865static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 };866static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 };867unsigned int bitbuf=0;868int i,j, bitcount=0;869unsigned char *out = NULL;870unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(unsigned char**));871if (hash_table == NULL)872return NULL;873if (quality < 5) quality = 5;874875stbiw__sbpush(out, 0x78); // DEFLATE 32K window876stbiw__sbpush(out, 0x5e); // FLEVEL = 1877stbiw__zlib_add(1,1); // BFINAL = 1878stbiw__zlib_add(1,2); // BTYPE = 1 -- fixed huffman879880for (i=0; i < stbiw__ZHASH; ++i)881hash_table[i] = NULL;882883i=0;884while (i < data_len-3) {885// hash next 3 bytes of data to be compressed886int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3;887unsigned char *bestloc = 0;888unsigned char **hlist = hash_table[h];889int n = stbiw__sbcount(hlist);890for (j=0; j < n; ++j) {891if (hlist[j]-data > i-32768) { // if entry lies within window892int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i);893if (d >= best) { best=d; bestloc=hlist[j]; }894}895}896// when hash table entry is too long, delete half the entries897if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) {898STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);899stbiw__sbn(hash_table[h]) = quality;900}901stbiw__sbpush(hash_table[h],data+i);902903if (bestloc) {904// "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal905h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1);906hlist = hash_table[h];907n = stbiw__sbcount(hlist);908for (j=0; j < n; ++j) {909if (hlist[j]-data > i-32767) {910int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1);911if (e > best) { // if next match is better, bail on current match912bestloc = NULL;913break;914}915}916}917}918919if (bestloc) {920int d = (int) (data+i - bestloc); // distance back921STBIW_ASSERT(d <= 32767 && best <= 258);922for (j=0; best > lengthc[j+1]-1; ++j);923stbiw__zlib_huff(j+257);924if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]);925for (j=0; d > distc[j+1]-1; ++j);926stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5);927if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]);928i += best;929} else {930stbiw__zlib_huffb(data[i]);931++i;932}933}934// write out final bytes935for (;i < data_len; ++i)936stbiw__zlib_huffb(data[i]);937stbiw__zlib_huff(256); // end of block938// pad with 0 bits to byte boundary939while (bitcount)940stbiw__zlib_add(0,1);941942for (i=0; i < stbiw__ZHASH; ++i)943(void) stbiw__sbfree(hash_table[i]);944STBIW_FREE(hash_table);945946{947// compute adler32 on input948unsigned int s1=1, s2=0;949int blocklen = (int) (data_len % 5552);950j=0;951while (j < data_len) {952for (i=0; i < blocklen; ++i) { s1 += data[j+i]; s2 += s1; }953s1 %= 65521; s2 %= 65521;954j += blocklen;955blocklen = 5552;956}957stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8));958stbiw__sbpush(out, STBIW_UCHAR(s2));959stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8));960stbiw__sbpush(out, STBIW_UCHAR(s1));961}962*out_len = stbiw__sbn(out);963// make returned pointer freeable964STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len);965return (unsigned char *) stbiw__sbraw(out);966#endif // STBIW_ZLIB_COMPRESS967}968969static unsigned int stbiw__crc32(unsigned char *buffer, int len)970{971#ifdef STBIW_CRC32972return STBIW_CRC32(buffer, len);973#else974static unsigned int crc_table[256] =975{9760x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,9770x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,9780x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,9790x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,9800x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,9810x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,9820x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,9830x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,9840x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,9850x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,9860x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,9870x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,9880x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,9890x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,9900x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,9910x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,9920xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,9930xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,9940xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,9950xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,9960xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,9970xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,9980xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,9990xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,10000x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,10010x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,10020x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,10030x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,10040xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,10050xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,10060xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,10070xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D1008};10091010unsigned int crc = ~0u;1011int i;1012for (i=0; i < len; ++i)1013crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];1014return ~crc;1015#endif1016}10171018#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)1019#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));1020#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3])10211022static void stbiw__wpcrc(unsigned char **data, int len)1023{1024unsigned int crc = stbiw__crc32(*data - len - 4, len+4);1025stbiw__wp32(*data, crc);1026}10271028static unsigned char stbiw__paeth(int a, int b, int c)1029{1030int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c);1031if (pa <= pb && pa <= pc) return STBIW_UCHAR(a);1032if (pb <= pc) return STBIW_UCHAR(b);1033return STBIW_UCHAR(c);1034}10351036// @OPTIMIZE: provide an option that always forces left-predict or paeth predict1037static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type, signed char *line_buffer)1038{1039static int mapping[] = { 0,1,2,3,4 };1040static int firstmap[] = { 0,1,0,5,6 };1041int *mymap = (y != 0) ? mapping : firstmap;1042int i;1043int type = mymap[filter_type];1044unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y);1045int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes;10461047if (type==0) {1048memcpy(line_buffer, z, width*n);1049return;1050}10511052// first loop isn't optimized since it's just one pixel1053for (i = 0; i < n; ++i) {1054switch (type) {1055case 1: line_buffer[i] = z[i]; break;1056case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break;1057case 3: line_buffer[i] = z[i] - (z[i-signed_stride]>>1); break;1058case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-signed_stride],0)); break;1059case 5: line_buffer[i] = z[i]; break;1060case 6: line_buffer[i] = z[i]; break;1061}1062}1063switch (type) {1064case 1: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-n]; break;1065case 2: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-signed_stride]; break;1066case 3: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break;1067case 4: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break;1068case 5: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - (z[i-n]>>1); break;1069case 6: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break;1070}1071}10721073STBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)1074{1075int force_filter = stbi_write_force_png_filter;1076int ctype[5] = { -1, 0, 4, 2, 6 };1077unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };1078unsigned char *out,*o, *filt, *zlib;1079signed char *line_buffer;1080int j,zlen;10811082if (stride_bytes == 0)1083stride_bytes = x * n;10841085if (force_filter >= 5) {1086force_filter = -1;1087}10881089filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0;1090line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; }1091for (j=0; j < y; ++j) {1092int filter_type;1093if (force_filter > -1) {1094filter_type = force_filter;1095stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer);1096} else { // Estimate the best filter by running through all of them:1097int best_filter = 0, best_filter_val = 0x7fffffff, est, i;1098for (filter_type = 0; filter_type < 5; filter_type++) {1099stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer);11001101// Estimate the entropy of the line using this filter; the less, the better.1102est = 0;1103for (i = 0; i < x*n; ++i) {1104est += abs((signed char) line_buffer[i]);1105}1106if (est < best_filter_val) {1107best_filter_val = est;1108best_filter = filter_type;1109}1110}1111if (filter_type != best_filter) { // If the last iteration already got us the best filter, don't redo it1112stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer);1113filter_type = best_filter;1114}1115}1116// when we get here, filter_type contains the filter type, and line_buffer contains the data1117filt[j*(x*n+1)] = (unsigned char) filter_type;1118STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n);1119}1120STBIW_FREE(line_buffer);1121zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_compression_level);1122STBIW_FREE(filt);1123if (!zlib) return 0;11241125// each tag requires 12 bytes of overhead1126out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12);1127if (!out) return 0;1128*out_len = 8 + 12+13 + 12+zlen + 12;11291130o=out;1131STBIW_MEMMOVE(o,sig,8); o+= 8;1132stbiw__wp32(o, 13); // header length1133stbiw__wptag(o, "IHDR");1134stbiw__wp32(o, x);1135stbiw__wp32(o, y);1136*o++ = 8;1137*o++ = STBIW_UCHAR(ctype[n]);1138*o++ = 0;1139*o++ = 0;1140*o++ = 0;1141stbiw__wpcrc(&o,13);11421143stbiw__wp32(o, zlen);1144stbiw__wptag(o, "IDAT");1145STBIW_MEMMOVE(o, zlib, zlen);1146o += zlen;1147STBIW_FREE(zlib);1148stbiw__wpcrc(&o, zlen);11491150stbiw__wp32(o,0);1151stbiw__wptag(o, "IEND");1152stbiw__wpcrc(&o,0);11531154STBIW_ASSERT(o == out + *out_len);11551156return out;1157}11581159#ifndef STBI_WRITE_NO_STDIO1160STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)1161{1162FILE *f;1163int len;1164unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len);1165if (png == NULL) return 0;11661167f = stbiw__fopen(filename, "wb");1168if (!f) { STBIW_FREE(png); return 0; }1169fwrite(png, 1, len, f);1170fclose(f);1171STBIW_FREE(png);1172return 1;1173}1174#endif11751176STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes)1177{1178int len;1179unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len);1180if (png == NULL) return 0;1181func(context, png, len);1182STBIW_FREE(png);1183return 1;1184}118511861187/* ***************************************************************************1188*1189* JPEG writer1190*1191* This is based on Jon Olick's jo_jpeg.cpp:1192* public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html1193*/11941195static const unsigned char stbiw__jpg_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18,119624,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 };11971198static void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) {1199int bitBuf = *bitBufP, bitCnt = *bitCntP;1200bitCnt += bs[1];1201bitBuf |= bs[0] << (24 - bitCnt);1202while(bitCnt >= 8) {1203unsigned char c = (bitBuf >> 16) & 255;1204stbiw__putc(s, c);1205if(c == 255) {1206stbiw__putc(s, 0);1207}1208bitBuf <<= 8;1209bitCnt -= 8;1210}1211*bitBufP = bitBuf;1212*bitCntP = bitCnt;1213}12141215static void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) {1216float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p;1217float z1, z2, z3, z4, z5, z11, z13;12181219float tmp0 = d0 + d7;1220float tmp7 = d0 - d7;1221float tmp1 = d1 + d6;1222float tmp6 = d1 - d6;1223float tmp2 = d2 + d5;1224float tmp5 = d2 - d5;1225float tmp3 = d3 + d4;1226float tmp4 = d3 - d4;12271228// Even part1229float tmp10 = tmp0 + tmp3; // phase 21230float tmp13 = tmp0 - tmp3;1231float tmp11 = tmp1 + tmp2;1232float tmp12 = tmp1 - tmp2;12331234d0 = tmp10 + tmp11; // phase 31235d4 = tmp10 - tmp11;12361237z1 = (tmp12 + tmp13) * 0.707106781f; // c41238d2 = tmp13 + z1; // phase 51239d6 = tmp13 - z1;12401241// Odd part1242tmp10 = tmp4 + tmp5; // phase 21243tmp11 = tmp5 + tmp6;1244tmp12 = tmp6 + tmp7;12451246// The rotator is modified from fig 4-8 to avoid extra negations.1247z5 = (tmp10 - tmp12) * 0.382683433f; // c61248z2 = tmp10 * 0.541196100f + z5; // c2-c61249z4 = tmp12 * 1.306562965f + z5; // c2+c61250z3 = tmp11 * 0.707106781f; // c412511252z11 = tmp7 + z3; // phase 51253z13 = tmp7 - z3;12541255*d5p = z13 + z2; // phase 61256*d3p = z13 - z2;1257*d1p = z11 + z4;1258*d7p = z11 - z4;12591260*d0p = d0; *d2p = d2; *d4p = d4; *d6p = d6;1261}12621263static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) {1264int tmp1 = val < 0 ? -val : val;1265val = val < 0 ? val-1 : val;1266bits[1] = 1;1267while(tmp1 >>= 1) {1268++bits[1];1269}1270bits[0] = val & ((1<<bits[1])-1);1271}12721273static int stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt, float *CDU, float *fdtbl, int DC, const unsigned short HTDC[256][2], const unsigned short HTAC[256][2]) {1274const unsigned short EOB[2] = { HTAC[0x00][0], HTAC[0x00][1] };1275const unsigned short M16zeroes[2] = { HTAC[0xF0][0], HTAC[0xF0][1] };1276int dataOff, i, diff, end0pos;1277int DU[64];12781279// DCT rows1280for(dataOff=0; dataOff<64; dataOff+=8) {1281stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+1], &CDU[dataOff+2], &CDU[dataOff+3], &CDU[dataOff+4], &CDU[dataOff+5], &CDU[dataOff+6], &CDU[dataOff+7]);1282}1283// DCT columns1284for(dataOff=0; dataOff<8; ++dataOff) {1285stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+8], &CDU[dataOff+16], &CDU[dataOff+24], &CDU[dataOff+32], &CDU[dataOff+40], &CDU[dataOff+48], &CDU[dataOff+56]);1286}1287// Quantize/descale/zigzag the coefficients1288for(i=0; i<64; ++i) {1289float v = CDU[i]*fdtbl[i];1290// DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f));1291// ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway?1292DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? v - 0.5f : v + 0.5f);1293}12941295// Encode DC1296diff = DU[0] - DC;1297if (diff == 0) {1298stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[0]);1299} else {1300unsigned short bits[2];1301stbiw__jpg_calcBits(diff, bits);1302stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[bits[1]]);1303stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits);1304}1305// Encode ACs1306end0pos = 63;1307for(; (end0pos>0)&&(DU[end0pos]==0); --end0pos) {1308}1309// end0pos = first element in reverse order !=01310if(end0pos == 0) {1311stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB);1312return DU[0];1313}1314for(i = 1; i <= end0pos; ++i) {1315int startpos = i;1316int nrzeroes;1317unsigned short bits[2];1318for (; DU[i]==0 && i<=end0pos; ++i) {1319}1320nrzeroes = i-startpos;1321if ( nrzeroes >= 16 ) {1322int lng = nrzeroes>>4;1323int nrmarker;1324for (nrmarker=1; nrmarker <= lng; ++nrmarker)1325stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes);1326nrzeroes &= 15;1327}1328stbiw__jpg_calcBits(DU[i], bits);1329stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]]);1330stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits);1331}1332if(end0pos != 63) {1333stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB);1334}1335return DU[0];1336}13371338static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) {1339// Constants that don't pollute global namespace1340static const unsigned char std_dc_luminance_nrcodes[] = {0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0};1341static const unsigned char std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11};1342static const unsigned char std_ac_luminance_nrcodes[] = {0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d};1343static const unsigned char std_ac_luminance_values[] = {13440x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,13450x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,13460x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,13470x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,13480x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,13490xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,13500xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa1351};1352static const unsigned char std_dc_chrominance_nrcodes[] = {0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0};1353static const unsigned char std_dc_chrominance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11};1354static const unsigned char std_ac_chrominance_nrcodes[] = {0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77};1355static const unsigned char std_ac_chrominance_values[] = {13560x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,13570xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,13580x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,13590x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87,13600x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,13610xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,13620xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa1363};1364// Huffman tables1365static const unsigned short YDC_HT[256][2] = { {0,2},{2,3},{3,3},{4,3},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9}};1366static const unsigned short UVDC_HT[256][2] = { {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9},{1022,10},{2046,11}};1367static const unsigned short YAC_HT[256][2] = {1368{10,4},{0,2},{1,2},{4,3},{11,4},{26,5},{120,7},{248,8},{1014,10},{65410,16},{65411,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},1369{12,4},{27,5},{121,7},{502,9},{2038,11},{65412,16},{65413,16},{65414,16},{65415,16},{65416,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},1370{28,5},{249,8},{1015,10},{4084,12},{65417,16},{65418,16},{65419,16},{65420,16},{65421,16},{65422,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},1371{58,6},{503,9},{4085,12},{65423,16},{65424,16},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},1372{59,6},{1016,10},{65430,16},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},1373{122,7},{2039,11},{65438,16},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},1374{123,7},{4086,12},{65446,16},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},1375{250,8},{4087,12},{65454,16},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},1376{504,9},{32704,15},{65462,16},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},1377{505,9},{65470,16},{65471,16},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},1378{506,9},{65479,16},{65480,16},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},1379{1017,10},{65488,16},{65489,16},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},1380{1018,10},{65497,16},{65498,16},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},1381{2040,11},{65506,16},{65507,16},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},1382{65515,16},{65516,16},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{0,0},{0,0},{0,0},{0,0},{0,0},1383{2041,11},{65525,16},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0}1384};1385static const unsigned short UVAC_HT[256][2] = {1386{0,2},{1,2},{4,3},{10,4},{24,5},{25,5},{56,6},{120,7},{500,9},{1014,10},{4084,12},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},1387{11,4},{57,6},{246,8},{501,9},{2038,11},{4085,12},{65416,16},{65417,16},{65418,16},{65419,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},1388{26,5},{247,8},{1015,10},{4086,12},{32706,15},{65420,16},{65421,16},{65422,16},{65423,16},{65424,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},1389{27,5},{248,8},{1016,10},{4087,12},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{65430,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},1390{58,6},{502,9},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{65438,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},1391{59,6},{1017,10},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{65446,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},1392{121,7},{2039,11},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{65454,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},1393{122,7},{2040,11},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{65462,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},1394{249,8},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{65470,16},{65471,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},1395{503,9},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{65479,16},{65480,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},1396{504,9},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{65488,16},{65489,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},1397{505,9},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{65497,16},{65498,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},1398{506,9},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{65506,16},{65507,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},1399{2041,11},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{65515,16},{65516,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},1400{16352,14},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{65525,16},{0,0},{0,0},{0,0},{0,0},{0,0},1401{1018,10},{32707,15},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0}1402};1403static const int YQT[] = {16,11,10,16,24,40,51,61,12,12,14,19,26,58,60,55,14,13,16,24,40,57,69,56,14,17,22,29,51,87,80,62,18,22,140437,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99};1405static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99,140699,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99};1407static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f,14081.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f };14091410int row, col, i, k;1411float fdtbl_Y[64], fdtbl_UV[64];1412unsigned char YTable[64], UVTable[64];14131414if(!data || !width || !height || comp > 4 || comp < 1) {1415return 0;1416}14171418quality = quality ? quality : 90;1419quality = quality < 1 ? 1 : quality > 100 ? 100 : quality;1420quality = quality < 50 ? 5000 / quality : 200 - quality * 2;14211422for(i = 0; i < 64; ++i) {1423int uvti, yti = (YQT[i]*quality+50)/100;1424YTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (yti < 1 ? 1 : yti > 255 ? 255 : yti);1425uvti = (UVQT[i]*quality+50)/100;1426UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti);1427}14281429for(row = 0, k = 0; row < 8; ++row) {1430for(col = 0; col < 8; ++col, ++k) {1431fdtbl_Y[k] = 1 / (YTable [stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]);1432fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]);1433}1434}14351436// Write Headers1437{1438static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 };1439static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 };1440const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width),14413,1,0x11,0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 };1442s->func(s->context, (void*)head0, sizeof(head0));1443s->func(s->context, (void*)YTable, sizeof(YTable));1444stbiw__putc(s, 1);1445s->func(s->context, UVTable, sizeof(UVTable));1446s->func(s->context, (void*)head1, sizeof(head1));1447s->func(s->context, (void*)(std_dc_luminance_nrcodes+1), sizeof(std_dc_luminance_nrcodes)-1);1448s->func(s->context, (void*)std_dc_luminance_values, sizeof(std_dc_luminance_values));1449stbiw__putc(s, 0x10); // HTYACinfo1450s->func(s->context, (void*)(std_ac_luminance_nrcodes+1), sizeof(std_ac_luminance_nrcodes)-1);1451s->func(s->context, (void*)std_ac_luminance_values, sizeof(std_ac_luminance_values));1452stbiw__putc(s, 1); // HTUDCinfo1453s->func(s->context, (void*)(std_dc_chrominance_nrcodes+1), sizeof(std_dc_chrominance_nrcodes)-1);1454s->func(s->context, (void*)std_dc_chrominance_values, sizeof(std_dc_chrominance_values));1455stbiw__putc(s, 0x11); // HTUACinfo1456s->func(s->context, (void*)(std_ac_chrominance_nrcodes+1), sizeof(std_ac_chrominance_nrcodes)-1);1457s->func(s->context, (void*)std_ac_chrominance_values, sizeof(std_ac_chrominance_values));1458s->func(s->context, (void*)head2, sizeof(head2));1459}14601461// Encode 8x8 macroblocks1462{1463static const unsigned short fillBits[] = {0x7F, 7};1464const unsigned char *imageData = (const unsigned char *)data;1465int DCY=0, DCU=0, DCV=0;1466int bitBuf=0, bitCnt=0;1467// comp == 2 is grey+alpha (alpha is ignored)1468int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0;1469int x, y, pos;1470for(y = 0; y < height; y += 8) {1471for(x = 0; x < width; x += 8) {1472float YDU[64], UDU[64], VDU[64];1473for(row = y, pos = 0; row < y+8; ++row) {1474// row >= height => use last input row1475int clamped_row = (row < height) ? row : height - 1;1476int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp;1477for(col = x; col < x+8; ++col, ++pos) {1478float r, g, b;1479// if col >= width => use pixel from last input column1480int p = base_p + ((col < width) ? col : (width-1))*comp;14811482r = imageData[p+0];1483g = imageData[p+ofsG];1484b = imageData[p+ofsB];1485YDU[pos]=+0.29900f*r+0.58700f*g+0.11400f*b-128;1486UDU[pos]=-0.16874f*r-0.33126f*g+0.50000f*b;1487VDU[pos]=+0.50000f*r-0.41869f*g-0.08131f*b;1488}1489}14901491DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT);1492DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);1493DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);1494}1495}14961497// Do the bit alignment of the EOI marker1498stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits);1499}15001501// EOI1502stbiw__putc(s, 0xFF);1503stbiw__putc(s, 0xD9);15041505return 1;1506}15071508STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality)1509{1510stbi__write_context s;1511stbi__start_write_callbacks(&s, func, context);1512return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality);1513}151415151516#ifndef STBI_WRITE_NO_STDIO1517STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality)1518{1519stbi__write_context s;1520if (stbi__start_write_file(&s,filename)) {1521int r = stbi_write_jpg_core(&s, x, y, comp, data, quality);1522stbi__end_write_file(&s);1523return r;1524} else1525return 0;1526}1527#endif15281529#endif // STB_IMAGE_WRITE_IMPLEMENTATION15301531/* Revision history15321.11 (2019-08-11)153315341.10 (2019-02-07)1535support utf8 filenames in Windows; fix warnings and platform ifdefs15361.09 (2018-02-11)1537fix typo in zlib quality API, improve STB_I_W_STATIC in C++15381.08 (2018-01-29)1539add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter15401.07 (2017-07-24)1541doc fix15421.06 (2017-07-23)1543writing JPEG (using Jon Olick's code)15441.05 ???15451.04 (2017-03-03)1546monochrome BMP expansion15471.03 ???15481.02 (2016-04-02)1549avoid allocating large structures on the stack15501.01 (2016-01-16)1551STBIW_REALLOC_SIZED: support allocators with no realloc support1552avoid race-condition in crc initialization1553minor compile issues15541.00 (2015-09-14)1555installable file IO function15560.99 (2015-09-13)1557warning fixes; TGA rle support15580.98 (2015-04-08)1559added STBIW_MALLOC, STBIW_ASSERT etc15600.97 (2015-01-18)1561fixed HDR asserts, rewrote HDR rle logic15620.96 (2015-01-17)1563add HDR output1564fix monochrome BMP15650.95 (2014-08-17)1566add monochrome TGA output15670.94 (2014-05-31)1568rename private functions to avoid conflicts with stb_image.h15690.93 (2014-05-27)1570warning fixes15710.92 (2010-08-01)1572casts to unsigned char to fix warnings15730.91 (2010-07-17)1574first public release15750.90 first internal release1576*/15771578/*1579------------------------------------------------------------------------------1580This software is available under 2 licenses -- choose whichever you prefer.1581------------------------------------------------------------------------------1582ALTERNATIVE A - MIT License1583Copyright (c) 2017 Sean Barrett1584Permission is hereby granted, free of charge, to any person obtaining a copy of1585this software and associated documentation files (the "Software"), to deal in1586the Software without restriction, including without limitation the rights to1587use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies1588of the Software, and to permit persons to whom the Software is furnished to do1589so, subject to the following conditions:1590The above copyright notice and this permission notice shall be included in all1591copies or substantial portions of the Software.1592THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR1593IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,1594FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE1595AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER1596LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,1597OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE1598SOFTWARE.1599------------------------------------------------------------------------------1600ALTERNATIVE B - Public Domain (www.unlicense.org)1601This is free and unencumbered software released into the public domain.1602Anyone is free to copy, modify, publish, use, compile, sell, or distribute this1603software, either in source code form or as a compiled binary, for any purpose,1604commercial or non-commercial, and by any means.1605In jurisdictions that recognize copyright laws, the author or authors of this1606software dedicate any and all copyright interest in the software to the public1607domain. We make this dedication for the benefit of the public at large and to1608the detriment of our heirs and successors. We intend this dedication to be an1609overt act of relinquishment in perpetuity of all present and future rights to1610this software under copyright law.1611THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR1612IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,1613FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE1614AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN1615ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION1616WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.1617------------------------------------------------------------------------------1618*/161916201621