|
@ -1,4 +1,4 @@ |
|
|
/* stb_image_write - v1.10 - public domain - http://nothings.org/stb/stb_image_write.h |
|
|
|
|
|
|
|
|
/* stb_image_write - v1.16 - public domain - http://nothings.org/stb |
|
|
writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015 |
|
|
writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015 |
|
|
no warranty implied; use at your own risk |
|
|
no warranty implied; use at your own risk |
|
|
|
|
|
|
|
@ -10,11 +10,6 @@ |
|
|
|
|
|
|
|
|
Will probably not work correctly with strict-aliasing optimizations. |
|
|
Will probably not work correctly with strict-aliasing optimizations. |
|
|
|
|
|
|
|
|
If using a modern Microsoft Compiler, non-safe versions of CRT calls may cause |
|
|
|
|
|
compilation warnings or even errors. To avoid this, also before #including, |
|
|
|
|
|
|
|
|
|
|
|
#define STBI_MSC_SECURE_CRT |
|
|
|
|
|
|
|
|
|
|
|
ABOUT: |
|
|
ABOUT: |
|
|
|
|
|
|
|
|
This header file is a library for writing images to C stdio or a callback. |
|
|
This header file is a library for writing images to C stdio or a callback. |
|
@ -110,7 +105,7 @@ USAGE: |
|
|
|
|
|
|
|
|
TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed |
|
|
TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed |
|
|
data, set the global variable 'stbi_write_tga_with_rle' to 0. |
|
|
data, set the global variable 'stbi_write_tga_with_rle' to 0. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
JPEG does ignore alpha channels in input data; quality is between 1 and 100. |
|
|
JPEG does ignore alpha channels in input data; quality is between 1 and 100. |
|
|
Higher quality looks better but results in a bigger image. |
|
|
Higher quality looks better but results in a bigger image. |
|
|
JPEG baseline (no JPEG progressive). |
|
|
JPEG baseline (no JPEG progressive). |
|
@ -118,7 +113,7 @@ USAGE: |
|
|
CREDITS: |
|
|
CREDITS: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Sean Barrett - PNG/BMP/TGA |
|
|
|
|
|
|
|
|
Sean Barrett - PNG/BMP/TGA |
|
|
Baldur Karlsson - HDR |
|
|
Baldur Karlsson - HDR |
|
|
Jean-Sebastien Guay - TGA monochrome |
|
|
Jean-Sebastien Guay - TGA monochrome |
|
|
Tim Kelsey - misc enhancements |
|
|
Tim Kelsey - misc enhancements |
|
@ -145,6 +140,7 @@ CREDITS: |
|
|
Ivan Tikhonov |
|
|
Ivan Tikhonov |
|
|
github:ignotion |
|
|
github:ignotion |
|
|
Adam Schackart |
|
|
Adam Schackart |
|
|
|
|
|
Andrew Kensler |
|
|
|
|
|
|
|
|
LICENSE |
|
|
LICENSE |
|
|
|
|
|
|
|
@ -171,9 +167,9 @@ LICENSE |
|
|
#endif |
|
|
#endif |
|
|
|
|
|
|
|
|
#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations |
|
|
#ifndef STB_IMAGE_WRITE_STATIC // C++ forbids static forward declarations |
|
|
extern int stbi_write_tga_with_rle; |
|
|
|
|
|
extern int stbi_write_png_compression_level; |
|
|
|
|
|
extern int stbi_write_force_png_filter; |
|
|
|
|
|
|
|
|
STBIWDEF int stbi_write_tga_with_rle; |
|
|
|
|
|
STBIWDEF int stbi_write_png_compression_level; |
|
|
|
|
|
STBIWDEF int stbi_write_force_png_filter; |
|
|
#endif |
|
|
#endif |
|
|
|
|
|
|
|
|
#ifndef STBI_WRITE_NO_STDIO |
|
|
#ifndef STBI_WRITE_NO_STDIO |
|
@ -183,7 +179,7 @@ STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const |
|
|
STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); |
|
|
STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); |
|
|
STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality); |
|
|
STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality); |
|
|
|
|
|
|
|
|
#ifdef STBI_WINDOWS_UTF8 |
|
|
|
|
|
|
|
|
#ifdef STBIW_WINDOWS_UTF8 |
|
|
STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); |
|
|
STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); |
|
|
#endif |
|
|
#endif |
|
|
#endif |
|
|
#endif |
|
@ -252,17 +248,17 @@ STBIWDEF void stbi_flip_vertically_on_write(int flip_boolean); |
|
|
#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) |
|
|
#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) |
|
|
|
|
|
|
|
|
#ifdef STB_IMAGE_WRITE_STATIC |
|
|
#ifdef STB_IMAGE_WRITE_STATIC |
|
|
static int stbi__flip_vertically_on_write=0; |
|
|
|
|
|
static int stbi_write_png_compression_level = 8; |
|
|
static int stbi_write_png_compression_level = 8; |
|
|
static int stbi_write_tga_with_rle = 1; |
|
|
static int stbi_write_tga_with_rle = 1; |
|
|
static int stbi_write_force_png_filter = -1; |
|
|
static int stbi_write_force_png_filter = -1; |
|
|
#else |
|
|
#else |
|
|
int stbi_write_png_compression_level = 8; |
|
|
int stbi_write_png_compression_level = 8; |
|
|
int stbi__flip_vertically_on_write=0; |
|
|
|
|
|
int stbi_write_tga_with_rle = 1; |
|
|
int stbi_write_tga_with_rle = 1; |
|
|
int stbi_write_force_png_filter = -1; |
|
|
int stbi_write_force_png_filter = -1; |
|
|
#endif |
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
static int stbi__flip_vertically_on_write = 0; |
|
|
|
|
|
|
|
|
STBIWDEF void stbi_flip_vertically_on_write(int flag) |
|
|
STBIWDEF void stbi_flip_vertically_on_write(int flag) |
|
|
{ |
|
|
{ |
|
|
stbi__flip_vertically_on_write = flag; |
|
|
stbi__flip_vertically_on_write = flag; |
|
@ -272,6 +268,8 @@ typedef struct |
|
|
{ |
|
|
{ |
|
|
stbi_write_func *func; |
|
|
stbi_write_func *func; |
|
|
void *context; |
|
|
void *context; |
|
|
|
|
|
unsigned char buffer[64]; |
|
|
|
|
|
int buf_used; |
|
|
} stbi__write_context; |
|
|
} stbi__write_context; |
|
|
|
|
|
|
|
|
// initialize a callback-based context |
|
|
// initialize a callback-based context |
|
@ -288,7 +286,7 @@ static void stbi__stdio_write(void *context, void *data, int size) |
|
|
fwrite(data,1,size,(FILE*) context); |
|
|
fwrite(data,1,size,(FILE*) context); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) |
|
|
|
|
|
|
|
|
#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8) |
|
|
#ifdef __cplusplus |
|
|
#ifdef __cplusplus |
|
|
#define STBIW_EXTERN extern "C" |
|
|
#define STBIW_EXTERN extern "C" |
|
|
#else |
|
|
#else |
|
@ -299,25 +297,25 @@ STBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned in |
|
|
|
|
|
|
|
|
STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) |
|
|
STBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) |
|
|
{ |
|
|
{ |
|
|
return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, bufferlen, NULL, NULL); |
|
|
|
|
|
|
|
|
return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); |
|
|
} |
|
|
} |
|
|
#endif |
|
|
#endif |
|
|
|
|
|
|
|
|
static FILE *stbiw__fopen(char const *filename, char const *mode) |
|
|
static FILE *stbiw__fopen(char const *filename, char const *mode) |
|
|
{ |
|
|
{ |
|
|
FILE *f; |
|
|
FILE *f; |
|
|
#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) |
|
|
|
|
|
|
|
|
#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8) |
|
|
wchar_t wMode[64]; |
|
|
wchar_t wMode[64]; |
|
|
wchar_t wFilename[1024]; |
|
|
wchar_t wFilename[1024]; |
|
|
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) |
|
|
|
|
|
|
|
|
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) |
|
|
return 0; |
|
|
return 0; |
|
|
|
|
|
|
|
|
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) |
|
|
return 0; |
|
|
return 0; |
|
|
|
|
|
|
|
|
#if _MSC_VER >= 1400 |
|
|
|
|
|
if (0 != _wfopen_s(&f, wFilename, wMode)) |
|
|
|
|
|
f = 0; |
|
|
|
|
|
|
|
|
#if defined(_MSC_VER) && _MSC_VER >= 1400 |
|
|
|
|
|
if (0 != _wfopen_s(&f, wFilename, wMode)) |
|
|
|
|
|
f = 0; |
|
|
#else |
|
|
#else |
|
|
f = _wfopen(wFilename, wMode); |
|
|
f = _wfopen(wFilename, wMode); |
|
|
#endif |
|
|
#endif |
|
@ -385,16 +383,36 @@ static void stbiw__writef(stbi__write_context *s, const char *fmt, ...) |
|
|
va_end(v); |
|
|
va_end(v); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void stbiw__write_flush(stbi__write_context *s) |
|
|
|
|
|
{ |
|
|
|
|
|
if (s->buf_used) { |
|
|
|
|
|
s->func(s->context, &s->buffer, s->buf_used); |
|
|
|
|
|
s->buf_used = 0; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
static void stbiw__putc(stbi__write_context *s, unsigned char c) |
|
|
static void stbiw__putc(stbi__write_context *s, unsigned char c) |
|
|
{ |
|
|
{ |
|
|
s->func(s->context, &c, 1); |
|
|
s->func(s->context, &c, 1); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void stbiw__write1(stbi__write_context *s, unsigned char a) |
|
|
|
|
|
{ |
|
|
|
|
|
if ((size_t)s->buf_used + 1 > sizeof(s->buffer)) |
|
|
|
|
|
stbiw__write_flush(s); |
|
|
|
|
|
s->buffer[s->buf_used++] = a; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) |
|
|
static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) |
|
|
{ |
|
|
{ |
|
|
unsigned char arr[3]; |
|
|
|
|
|
arr[0] = a, arr[1] = b, arr[2] = c; |
|
|
|
|
|
s->func(s->context, arr, 3); |
|
|
|
|
|
|
|
|
int n; |
|
|
|
|
|
if ((size_t)s->buf_used + 3 > sizeof(s->buffer)) |
|
|
|
|
|
stbiw__write_flush(s); |
|
|
|
|
|
n = s->buf_used; |
|
|
|
|
|
s->buf_used = n+3; |
|
|
|
|
|
s->buffer[n+0] = a; |
|
|
|
|
|
s->buffer[n+1] = b; |
|
|
|
|
|
s->buffer[n+2] = c; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d) |
|
|
static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d) |
|
@ -403,7 +421,7 @@ static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, in |
|
|
int k; |
|
|
int k; |
|
|
|
|
|
|
|
|
if (write_alpha < 0) |
|
|
if (write_alpha < 0) |
|
|
s->func(s->context, &d[comp - 1], 1); |
|
|
|
|
|
|
|
|
stbiw__write1(s, d[comp - 1]); |
|
|
|
|
|
|
|
|
switch (comp) { |
|
|
switch (comp) { |
|
|
case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case |
|
|
case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case |
|
@ -411,7 +429,7 @@ static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, in |
|
|
if (expand_mono) |
|
|
if (expand_mono) |
|
|
stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp |
|
|
stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp |
|
|
else |
|
|
else |
|
|
s->func(s->context, d, 1); // monochrome TGA |
|
|
|
|
|
|
|
|
stbiw__write1(s, d[0]); // monochrome TGA |
|
|
break; |
|
|
break; |
|
|
case 4: |
|
|
case 4: |
|
|
if (!write_alpha) { |
|
|
if (!write_alpha) { |
|
@ -427,7 +445,7 @@ static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, in |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
if (write_alpha > 0) |
|
|
if (write_alpha > 0) |
|
|
s->func(s->context, &d[comp - 1], 1); |
|
|
|
|
|
|
|
|
stbiw__write1(s, d[comp - 1]); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono) |
|
|
static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono) |
|
@ -441,16 +459,18 @@ static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, i |
|
|
if (stbi__flip_vertically_on_write) |
|
|
if (stbi__flip_vertically_on_write) |
|
|
vdir *= -1; |
|
|
vdir *= -1; |
|
|
|
|
|
|
|
|
if (vdir < 0) |
|
|
|
|
|
j_end = -1, j = y-1; |
|
|
|
|
|
else |
|
|
|
|
|
j_end = y, j = 0; |
|
|
|
|
|
|
|
|
if (vdir < 0) { |
|
|
|
|
|
j_end = -1; j = y-1; |
|
|
|
|
|
} else { |
|
|
|
|
|
j_end = y; j = 0; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
for (; j != j_end; j += vdir) { |
|
|
for (; j != j_end; j += vdir) { |
|
|
for (i=0; i < x; ++i) { |
|
|
for (i=0; i < x; ++i) { |
|
|
unsigned char *d = (unsigned char *) data + (j*x+i)*comp; |
|
|
unsigned char *d = (unsigned char *) data + (j*x+i)*comp; |
|
|
stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d); |
|
|
stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d); |
|
|
} |
|
|
} |
|
|
|
|
|
stbiw__write_flush(s); |
|
|
s->func(s->context, &zero, scanline_pad); |
|
|
s->func(s->context, &zero, scanline_pad); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@ -471,16 +491,27 @@ static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, |
|
|
|
|
|
|
|
|
static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data) |
|
|
static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data) |
|
|
{ |
|
|
{ |
|
|
int pad = (-x*3) & 3; |
|
|
|
|
|
return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad, |
|
|
|
|
|
"11 4 22 4" "4 44 22 444444", |
|
|
|
|
|
'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header |
|
|
|
|
|
40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header |
|
|
|
|
|
|
|
|
if (comp != 4) { |
|
|
|
|
|
// write RGB bitmap |
|
|
|
|
|
int pad = (-x*3) & 3; |
|
|
|
|
|
return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad, |
|
|
|
|
|
"11 4 22 4" "4 44 22 444444", |
|
|
|
|
|
'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header |
|
|
|
|
|
40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header |
|
|
|
|
|
} else { |
|
|
|
|
|
// RGBA bitmaps need a v4 header |
|
|
|
|
|
// use BI_BITFIELDS mode with 32bpp and alpha mask |
|
|
|
|
|
// (straight BI_RGB with alpha mask doesn't work in most readers) |
|
|
|
|
|
return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *)data,1,0, |
|
|
|
|
|
"11 4 22 4" "4 44 22 444444 4444 4 444 444 444 444", |
|
|
|
|
|
'B', 'M', 14+108+x*y*4, 0, 0, 14+108, // file header |
|
|
|
|
|
108, x,y, 1,32, 3,0,0,0,0,0, 0xff0000,0xff00,0xff,0xff000000u, 0, 0,0,0, 0,0,0, 0,0,0, 0,0,0); // bitmap V4 header |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) |
|
|
STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) |
|
|
{ |
|
|
{ |
|
|
stbi__write_context s; |
|
|
|
|
|
|
|
|
stbi__write_context s = { 0 }; |
|
|
stbi__start_write_callbacks(&s, func, context); |
|
|
stbi__start_write_callbacks(&s, func, context); |
|
|
return stbi_write_bmp_core(&s, x, y, comp, data); |
|
|
return stbi_write_bmp_core(&s, x, y, comp, data); |
|
|
} |
|
|
} |
|
@ -488,7 +519,7 @@ STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, |
|
|
#ifndef STBI_WRITE_NO_STDIO |
|
|
#ifndef STBI_WRITE_NO_STDIO |
|
|
STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) |
|
|
STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) |
|
|
{ |
|
|
{ |
|
|
stbi__write_context s; |
|
|
|
|
|
|
|
|
stbi__write_context s = { 0 }; |
|
|
if (stbi__start_write_file(&s,filename)) { |
|
|
if (stbi__start_write_file(&s,filename)) { |
|
|
int r = stbi_write_bmp_core(&s, x, y, comp, data); |
|
|
int r = stbi_write_bmp_core(&s, x, y, comp, data); |
|
|
stbi__end_write_file(&s); |
|
|
stbi__end_write_file(&s); |
|
@ -561,24 +592,25 @@ static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, v |
|
|
|
|
|
|
|
|
if (diff) { |
|
|
if (diff) { |
|
|
unsigned char header = STBIW_UCHAR(len - 1); |
|
|
unsigned char header = STBIW_UCHAR(len - 1); |
|
|
s->func(s->context, &header, 1); |
|
|
|
|
|
|
|
|
stbiw__write1(s, header); |
|
|
for (k = 0; k < len; ++k) { |
|
|
for (k = 0; k < len; ++k) { |
|
|
stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); |
|
|
stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); |
|
|
} |
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
unsigned char header = STBIW_UCHAR(len - 129); |
|
|
unsigned char header = STBIW_UCHAR(len - 129); |
|
|
s->func(s->context, &header, 1); |
|
|
|
|
|
|
|
|
stbiw__write1(s, header); |
|
|
stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); |
|
|
stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
stbiw__write_flush(s); |
|
|
} |
|
|
} |
|
|
return 1; |
|
|
return 1; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) |
|
|
STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) |
|
|
{ |
|
|
{ |
|
|
stbi__write_context s; |
|
|
|
|
|
|
|
|
stbi__write_context s = { 0 }; |
|
|
stbi__start_write_callbacks(&s, func, context); |
|
|
stbi__start_write_callbacks(&s, func, context); |
|
|
return stbi_write_tga_core(&s, x, y, comp, (void *) data); |
|
|
return stbi_write_tga_core(&s, x, y, comp, (void *) data); |
|
|
} |
|
|
} |
|
@ -586,7 +618,7 @@ STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, |
|
|
#ifndef STBI_WRITE_NO_STDIO |
|
|
#ifndef STBI_WRITE_NO_STDIO |
|
|
STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) |
|
|
STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) |
|
|
{ |
|
|
{ |
|
|
stbi__write_context s; |
|
|
|
|
|
|
|
|
stbi__write_context s = { 0 }; |
|
|
if (stbi__start_write_file(&s,filename)) { |
|
|
if (stbi__start_write_file(&s,filename)) { |
|
|
int r = stbi_write_tga_core(&s, x, y, comp, (void *) data); |
|
|
int r = stbi_write_tga_core(&s, x, y, comp, (void *) data); |
|
|
stbi__end_write_file(&s); |
|
|
stbi__end_write_file(&s); |
|
@ -602,6 +634,8 @@ STBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const |
|
|
|
|
|
|
|
|
#define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) |
|
|
#define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) |
|
|
|
|
|
|
|
|
|
|
|
#ifndef STBI_WRITE_NO_STDIO |
|
|
|
|
|
|
|
|
static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) |
|
|
static void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) |
|
|
{ |
|
|
{ |
|
|
int exponent; |
|
|
int exponent; |
|
@ -736,8 +770,8 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f |
|
|
char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; |
|
|
char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; |
|
|
s->func(s->context, header, sizeof(header)-1); |
|
|
s->func(s->context, header, sizeof(header)-1); |
|
|
|
|
|
|
|
|
#ifdef STBI_MSC_SECURE_CRT |
|
|
|
|
|
len = sprintf_s(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); |
|
|
|
|
|
|
|
|
#ifdef __STDC_LIB_EXT1__ |
|
|
|
|
|
len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); |
|
|
#else |
|
|
#else |
|
|
len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); |
|
|
len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); |
|
|
#endif |
|
|
#endif |
|
@ -752,15 +786,14 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f |
|
|
|
|
|
|
|
|
STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) |
|
|
STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) |
|
|
{ |
|
|
{ |
|
|
stbi__write_context s; |
|
|
|
|
|
|
|
|
stbi__write_context s = { 0 }; |
|
|
stbi__start_write_callbacks(&s, func, context); |
|
|
stbi__start_write_callbacks(&s, func, context); |
|
|
return stbi_write_hdr_core(&s, x, y, comp, (float *) data); |
|
|
return stbi_write_hdr_core(&s, x, y, comp, (float *) data); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
#ifndef STBI_WRITE_NO_STDIO |
|
|
|
|
|
STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) |
|
|
STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) |
|
|
{ |
|
|
{ |
|
|
stbi__write_context s; |
|
|
|
|
|
|
|
|
stbi__write_context s = { 0 }; |
|
|
if (stbi__start_write_file(&s,filename)) { |
|
|
if (stbi__start_write_file(&s,filename)) { |
|
|
int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data); |
|
|
int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data); |
|
|
stbi__end_write_file(&s); |
|
|
stbi__end_write_file(&s); |
|
@ -778,7 +811,7 @@ STBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const |
|
|
|
|
|
|
|
|
#ifndef STBIW_ZLIB_COMPRESS |
|
|
#ifndef STBIW_ZLIB_COMPRESS |
|
|
// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() |
|
|
// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() |
|
|
#define stbiw__sbraw(a) ((int *) (a) - 2) |
|
|
|
|
|
|
|
|
#define stbiw__sbraw(a) ((int *) (void *) (a) - 2) |
|
|
#define stbiw__sbm(a) stbiw__sbraw(a)[0] |
|
|
#define stbiw__sbm(a) stbiw__sbraw(a)[0] |
|
|
#define stbiw__sbn(a) stbiw__sbraw(a)[1] |
|
|
#define stbiw__sbn(a) stbiw__sbraw(a)[1] |
|
|
|
|
|
|
|
@ -872,7 +905,7 @@ STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, i |
|
|
unsigned int bitbuf=0; |
|
|
unsigned int bitbuf=0; |
|
|
int i,j, bitcount=0; |
|
|
int i,j, bitcount=0; |
|
|
unsigned char *out = NULL; |
|
|
unsigned char *out = NULL; |
|
|
unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(char**)); |
|
|
|
|
|
|
|
|
unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(unsigned char**)); |
|
|
if (hash_table == NULL) |
|
|
if (hash_table == NULL) |
|
|
return NULL; |
|
|
return NULL; |
|
|
if (quality < 5) quality = 5; |
|
|
if (quality < 5) quality = 5; |
|
@ -895,7 +928,7 @@ STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, i |
|
|
for (j=0; j < n; ++j) { |
|
|
for (j=0; j < n; ++j) { |
|
|
if (hlist[j]-data > i-32768) { // if entry lies within window |
|
|
if (hlist[j]-data > i-32768) { // if entry lies within window |
|
|
int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i); |
|
|
int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i); |
|
|
if (d >= best) best=d,bestloc=hlist[j]; |
|
|
|
|
|
|
|
|
if (d >= best) { best=d; bestloc=hlist[j]; } |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
// when hash table entry is too long, delete half the entries |
|
|
// when hash table entry is too long, delete half the entries |
|
@ -948,14 +981,31 @@ STBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, i |
|
|
(void) stbiw__sbfree(hash_table[i]); |
|
|
(void) stbiw__sbfree(hash_table[i]); |
|
|
STBIW_FREE(hash_table); |
|
|
STBIW_FREE(hash_table); |
|
|
|
|
|
|
|
|
|
|
|
// store uncompressed instead if compression was worse |
|
|
|
|
|
if (stbiw__sbn(out) > data_len + 2 + ((data_len+32766)/32767)*5) { |
|
|
|
|
|
stbiw__sbn(out) = 2; // truncate to DEFLATE 32K window and FLEVEL = 1 |
|
|
|
|
|
for (j = 0; j < data_len;) { |
|
|
|
|
|
int blocklen = data_len - j; |
|
|
|
|
|
if (blocklen > 32767) blocklen = 32767; |
|
|
|
|
|
stbiw__sbpush(out, data_len - j == blocklen); // BFINAL = ?, BTYPE = 0 -- no compression |
|
|
|
|
|
stbiw__sbpush(out, STBIW_UCHAR(blocklen)); // LEN |
|
|
|
|
|
stbiw__sbpush(out, STBIW_UCHAR(blocklen >> 8)); |
|
|
|
|
|
stbiw__sbpush(out, STBIW_UCHAR(~blocklen)); // NLEN |
|
|
|
|
|
stbiw__sbpush(out, STBIW_UCHAR(~blocklen >> 8)); |
|
|
|
|
|
memcpy(out+stbiw__sbn(out), data+j, blocklen); |
|
|
|
|
|
stbiw__sbn(out) += blocklen; |
|
|
|
|
|
j += blocklen; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
{ |
|
|
{ |
|
|
// compute adler32 on input |
|
|
// compute adler32 on input |
|
|
unsigned int s1=1, s2=0; |
|
|
unsigned int s1=1, s2=0; |
|
|
int blocklen = (int) (data_len % 5552); |
|
|
int blocklen = (int) (data_len % 5552); |
|
|
j=0; |
|
|
j=0; |
|
|
while (j < data_len) { |
|
|
while (j < data_len) { |
|
|
for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1; |
|
|
|
|
|
s1 %= 65521, s2 %= 65521; |
|
|
|
|
|
|
|
|
for (i=0; i < blocklen; ++i) { s1 += data[j+i]; s2 += s1; } |
|
|
|
|
|
s1 %= 65521; s2 %= 65521; |
|
|
j += blocklen; |
|
|
j += blocklen; |
|
|
blocklen = 5552; |
|
|
blocklen = 5552; |
|
|
} |
|
|
} |
|
@ -1048,13 +1098,13 @@ static void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int |
|
|
int type = mymap[filter_type]; |
|
|
int type = mymap[filter_type]; |
|
|
unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y); |
|
|
unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y); |
|
|
int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes; |
|
|
int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (type==0) { |
|
|
if (type==0) { |
|
|
memcpy(line_buffer, z, width*n); |
|
|
memcpy(line_buffer, z, width*n); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// first loop isn't optimized since it's just one pixel |
|
|
|
|
|
|
|
|
// first loop isn't optimized since it's just one pixel |
|
|
for (i = 0; i < n; ++i) { |
|
|
for (i = 0; i < n; ++i) { |
|
|
switch (type) { |
|
|
switch (type) { |
|
|
case 1: line_buffer[i] = z[i]; break; |
|
|
case 1: line_buffer[i] = z[i]; break; |
|
@ -1275,26 +1325,31 @@ static void stbiw__jpg_calcBits(int val, unsigned short bits[2]) { |
|
|
bits[0] = val & ((1<<bits[1])-1); |
|
|
bits[0] = val & ((1<<bits[1])-1); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static 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]) { |
|
|
|
|
|
|
|
|
static int stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt, float *CDU, int du_stride, float *fdtbl, int DC, const unsigned short HTDC[256][2], const unsigned short HTAC[256][2]) { |
|
|
const unsigned short EOB[2] = { HTAC[0x00][0], HTAC[0x00][1] }; |
|
|
const unsigned short EOB[2] = { HTAC[0x00][0], HTAC[0x00][1] }; |
|
|
const unsigned short M16zeroes[2] = { HTAC[0xF0][0], HTAC[0xF0][1] }; |
|
|
const unsigned short M16zeroes[2] = { HTAC[0xF0][0], HTAC[0xF0][1] }; |
|
|
int dataOff, i, diff, end0pos; |
|
|
|
|
|
|
|
|
int dataOff, i, j, n, diff, end0pos, x, y; |
|
|
int DU[64]; |
|
|
int DU[64]; |
|
|
|
|
|
|
|
|
// DCT rows |
|
|
// DCT rows |
|
|
for(dataOff=0; dataOff<64; dataOff+=8) { |
|
|
|
|
|
|
|
|
for(dataOff=0, n=du_stride*8; dataOff<n; dataOff+=du_stride) { |
|
|
stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+1], &CDU[dataOff+2], &CDU[dataOff+3], &CDU[dataOff+4], &CDU[dataOff+5], &CDU[dataOff+6], &CDU[dataOff+7]); |
|
|
stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+1], &CDU[dataOff+2], &CDU[dataOff+3], &CDU[dataOff+4], &CDU[dataOff+5], &CDU[dataOff+6], &CDU[dataOff+7]); |
|
|
} |
|
|
} |
|
|
// DCT columns |
|
|
// DCT columns |
|
|
for(dataOff=0; dataOff<8; ++dataOff) { |
|
|
for(dataOff=0; dataOff<8; ++dataOff) { |
|
|
stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+8], &CDU[dataOff+16], &CDU[dataOff+24], &CDU[dataOff+32], &CDU[dataOff+40], &CDU[dataOff+48], &CDU[dataOff+56]); |
|
|
|
|
|
|
|
|
stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+du_stride], &CDU[dataOff+du_stride*2], &CDU[dataOff+du_stride*3], &CDU[dataOff+du_stride*4], |
|
|
|
|
|
&CDU[dataOff+du_stride*5], &CDU[dataOff+du_stride*6], &CDU[dataOff+du_stride*7]); |
|
|
} |
|
|
} |
|
|
// Quantize/descale/zigzag the coefficients |
|
|
// Quantize/descale/zigzag the coefficients |
|
|
for(i=0; i<64; ++i) { |
|
|
|
|
|
float v = CDU[i]*fdtbl[i]; |
|
|
|
|
|
// DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f)); |
|
|
|
|
|
// ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway? |
|
|
|
|
|
DU[stbiw__jpg_ZigZag[i]] = (int)(v < 0 ? v - 0.5f : v + 0.5f); |
|
|
|
|
|
|
|
|
for(y = 0, j=0; y < 8; ++y) { |
|
|
|
|
|
for(x = 0; x < 8; ++x,++j) { |
|
|
|
|
|
float v; |
|
|
|
|
|
i = y*du_stride+x; |
|
|
|
|
|
v = CDU[i]*fdtbl[j]; |
|
|
|
|
|
// DU[stbiw__jpg_ZigZag[j]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f)); |
|
|
|
|
|
// ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway? |
|
|
|
|
|
DU[stbiw__jpg_ZigZag[j]] = (int)(v < 0 ? v - 0.5f : v + 0.5f); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Encode DC |
|
|
// Encode DC |
|
@ -1409,10 +1464,10 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in |
|
|
37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99}; |
|
|
37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99}; |
|
|
static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99, |
|
|
static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99, |
|
|
99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99}; |
|
|
99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99}; |
|
|
static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f, |
|
|
|
|
|
|
|
|
static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f, |
|
|
1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f }; |
|
|
1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f }; |
|
|
|
|
|
|
|
|
int row, col, i, k; |
|
|
|
|
|
|
|
|
int row, col, i, k, subsample; |
|
|
float fdtbl_Y[64], fdtbl_UV[64]; |
|
|
float fdtbl_Y[64], fdtbl_UV[64]; |
|
|
unsigned char YTable[64], UVTable[64]; |
|
|
unsigned char YTable[64], UVTable[64]; |
|
|
|
|
|
|
|
@ -1421,6 +1476,7 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
quality = quality ? quality : 90; |
|
|
quality = quality ? quality : 90; |
|
|
|
|
|
subsample = quality <= 90 ? 1 : 0; |
|
|
quality = quality < 1 ? 1 : quality > 100 ? 100 : quality; |
|
|
quality = quality < 1 ? 1 : quality > 100 ? 100 : quality; |
|
|
quality = quality < 50 ? 5000 / quality : 200 - quality * 2; |
|
|
quality = quality < 50 ? 5000 / quality : 200 - quality * 2; |
|
|
|
|
|
|
|
@ -1443,7 +1499,7 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in |
|
|
static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 }; |
|
|
static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 }; |
|
|
static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 }; |
|
|
static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 }; |
|
|
const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width), |
|
|
const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width), |
|
|
3,1,0x11,0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 }; |
|
|
|
|
|
|
|
|
3,1,(unsigned char)(subsample?0x22:0x11),0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 }; |
|
|
s->func(s->context, (void*)head0, sizeof(head0)); |
|
|
s->func(s->context, (void*)head0, sizeof(head0)); |
|
|
s->func(s->context, (void*)YTable, sizeof(YTable)); |
|
|
s->func(s->context, (void*)YTable, sizeof(YTable)); |
|
|
stbiw__putc(s, 1); |
|
|
stbiw__putc(s, 1); |
|
@ -1466,40 +1522,74 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in |
|
|
// Encode 8x8 macroblocks |
|
|
// Encode 8x8 macroblocks |
|
|
{ |
|
|
{ |
|
|
static const unsigned short fillBits[] = {0x7F, 7}; |
|
|
static const unsigned short fillBits[] = {0x7F, 7}; |
|
|
const unsigned char *imageData = (const unsigned char *)data; |
|
|
|
|
|
int DCY=0, DCU=0, DCV=0; |
|
|
int DCY=0, DCU=0, DCV=0; |
|
|
int bitBuf=0, bitCnt=0; |
|
|
int bitBuf=0, bitCnt=0; |
|
|
// comp == 2 is grey+alpha (alpha is ignored) |
|
|
// comp == 2 is grey+alpha (alpha is ignored) |
|
|
int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0; |
|
|
int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0; |
|
|
|
|
|
const unsigned char *dataR = (const unsigned char *)data; |
|
|
|
|
|
const unsigned char *dataG = dataR + ofsG; |
|
|
|
|
|
const unsigned char *dataB = dataR + ofsB; |
|
|
int x, y, pos; |
|
|
int x, y, pos; |
|
|
for(y = 0; y < height; y += 8) { |
|
|
|
|
|
for(x = 0; x < width; x += 8) { |
|
|
|
|
|
float YDU[64], UDU[64], VDU[64]; |
|
|
|
|
|
for(row = y, pos = 0; row < y+8; ++row) { |
|
|
|
|
|
int p; |
|
|
|
|
|
if(row < height) { |
|
|
|
|
|
p = (stbi__flip_vertically_on_write ? (height-1-row) : row)*width*comp; |
|
|
|
|
|
} else { |
|
|
|
|
|
// row >= height => use last input row (=> first if flipping) |
|
|
|
|
|
p = stbi__flip_vertically_on_write ? 0 : ((height-1)*width*comp); |
|
|
|
|
|
|
|
|
if(subsample) { |
|
|
|
|
|
for(y = 0; y < height; y += 16) { |
|
|
|
|
|
for(x = 0; x < width; x += 16) { |
|
|
|
|
|
float Y[256], U[256], V[256]; |
|
|
|
|
|
for(row = y, pos = 0; row < y+16; ++row) { |
|
|
|
|
|
// row >= height => use last input row |
|
|
|
|
|
int clamped_row = (row < height) ? row : height - 1; |
|
|
|
|
|
int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; |
|
|
|
|
|
for(col = x; col < x+16; ++col, ++pos) { |
|
|
|
|
|
// if col >= width => use pixel from last input column |
|
|
|
|
|
int p = base_p + ((col < width) ? col : (width-1))*comp; |
|
|
|
|
|
float r = dataR[p], g = dataG[p], b = dataB[p]; |
|
|
|
|
|
Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; |
|
|
|
|
|
U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; |
|
|
|
|
|
V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
for(col = x; col < x+8; ++col, ++pos) { |
|
|
|
|
|
float r, g, b; |
|
|
|
|
|
// if col >= width => use pixel from last input column |
|
|
|
|
|
p += ((col < width) ? col : (width-1))*comp; |
|
|
|
|
|
|
|
|
|
|
|
r = imageData[p+0]; |
|
|
|
|
|
g = imageData[p+ofsG]; |
|
|
|
|
|
b = imageData[p+ofsB]; |
|
|
|
|
|
YDU[pos]=+0.29900f*r+0.58700f*g+0.11400f*b-128; |
|
|
|
|
|
UDU[pos]=-0.16874f*r-0.33126f*g+0.50000f*b; |
|
|
|
|
|
VDU[pos]=+0.50000f*r-0.41869f*g-0.08131f*b; |
|
|
|
|
|
|
|
|
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+0, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); |
|
|
|
|
|
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+8, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); |
|
|
|
|
|
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+128, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); |
|
|
|
|
|
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+136, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT); |
|
|
|
|
|
|
|
|
|
|
|
// subsample U,V |
|
|
|
|
|
{ |
|
|
|
|
|
float subU[64], subV[64]; |
|
|
|
|
|
int yy, xx; |
|
|
|
|
|
for(yy = 0, pos = 0; yy < 8; ++yy) { |
|
|
|
|
|
for(xx = 0; xx < 8; ++xx, ++pos) { |
|
|
|
|
|
int j = yy*32+xx*2; |
|
|
|
|
|
subU[pos] = (U[j+0] + U[j+1] + U[j+16] + U[j+17]) * 0.25f; |
|
|
|
|
|
subV[pos] = (V[j+0] + V[j+1] + V[j+16] + V[j+17]) * 0.25f; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); |
|
|
|
|
|
DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} else { |
|
|
|
|
|
for(y = 0; y < height; y += 8) { |
|
|
|
|
|
for(x = 0; x < width; x += 8) { |
|
|
|
|
|
float Y[64], U[64], V[64]; |
|
|
|
|
|
for(row = y, pos = 0; row < y+8; ++row) { |
|
|
|
|
|
// row >= height => use last input row |
|
|
|
|
|
int clamped_row = (row < height) ? row : height - 1; |
|
|
|
|
|
int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp; |
|
|
|
|
|
for(col = x; col < x+8; ++col, ++pos) { |
|
|
|
|
|
// if col >= width => use pixel from last input column |
|
|
|
|
|
int p = base_p + ((col < width) ? col : (width-1))*comp; |
|
|
|
|
|
float r = dataR[p], g = dataG[p], b = dataB[p]; |
|
|
|
|
|
Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128; |
|
|
|
|
|
U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b; |
|
|
|
|
|
V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT); |
|
|
|
|
|
DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); |
|
|
|
|
|
DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); |
|
|
|
|
|
|
|
|
DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y, DCY, YDC_HT, YAC_HT); |
|
|
|
|
|
DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); |
|
|
|
|
|
DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -1516,7 +1606,7 @@ static int stbi_write_jpg_core(stbi__write_context *s, int width, int height, in |
|
|
|
|
|
|
|
|
STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality) |
|
|
STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality) |
|
|
{ |
|
|
{ |
|
|
stbi__write_context s; |
|
|
|
|
|
|
|
|
stbi__write_context s = { 0 }; |
|
|
stbi__start_write_callbacks(&s, func, context); |
|
|
stbi__start_write_callbacks(&s, func, context); |
|
|
return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality); |
|
|
return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality); |
|
|
} |
|
|
} |
|
@ -1525,7 +1615,7 @@ STBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, |
|
|
#ifndef STBI_WRITE_NO_STDIO |
|
|
#ifndef STBI_WRITE_NO_STDIO |
|
|
STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality) |
|
|
STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality) |
|
|
{ |
|
|
{ |
|
|
stbi__write_context s; |
|
|
|
|
|
|
|
|
stbi__write_context s = { 0 }; |
|
|
if (stbi__start_write_file(&s,filename)) { |
|
|
if (stbi__start_write_file(&s,filename)) { |
|
|
int r = stbi_write_jpg_core(&s, x, y, comp, data, quality); |
|
|
int r = stbi_write_jpg_core(&s, x, y, comp, data, quality); |
|
|
stbi__end_write_file(&s); |
|
|
stbi__end_write_file(&s); |
|
@ -1538,8 +1628,17 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const |
|
|
#endif // STB_IMAGE_WRITE_IMPLEMENTATION |
|
|
#endif // STB_IMAGE_WRITE_IMPLEMENTATION |
|
|
|
|
|
|
|
|
/* Revision history |
|
|
/* Revision history |
|
|
|
|
|
1.16 (2021-07-11) |
|
|
|
|
|
make Deflate code emit uncompressed blocks when it would otherwise expand |
|
|
|
|
|
support writing BMPs with alpha channel |
|
|
|
|
|
1.15 (2020-07-13) unknown |
|
|
|
|
|
1.14 (2020-02-02) updated JPEG writer to downsample chroma channels |
|
|
|
|
|
1.13 |
|
|
|
|
|
1.12 |
|
|
|
|
|
1.11 (2019-08-11) |
|
|
|
|
|
|
|
|
1.10 (2019-02-07) |
|
|
1.10 (2019-02-07) |
|
|
support utf8 filenames in Windows; fix warnings and platform ifdefs |
|
|
|
|
|
|
|
|
support utf8 filenames in Windows; fix warnings and platform ifdefs |
|
|
1.09 (2018-02-11) |
|
|
1.09 (2018-02-11) |
|
|
fix typo in zlib quality API, improve STB_I_W_STATIC in C++ |
|
|
fix typo in zlib quality API, improve STB_I_W_STATIC in C++ |
|
|
1.08 (2018-01-29) |
|
|
1.08 (2018-01-29) |
|
@ -1570,7 +1669,7 @@ STBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const |
|
|
add HDR output |
|
|
add HDR output |
|
|
fix monochrome BMP |
|
|
fix monochrome BMP |
|
|
0.95 (2014-08-17) |
|
|
0.95 (2014-08-17) |
|
|
add monochrome TGA output |
|
|
|
|
|
|
|
|
add monochrome TGA output |
|
|
0.94 (2014-05-31) |
|
|
0.94 (2014-05-31) |
|
|
rename private functions to avoid conflicts with stb_image.h |
|
|
rename private functions to avoid conflicts with stb_image.h |
|
|
0.93 (2014-05-27) |
|
|
0.93 (2014-05-27) |
|
@ -1588,38 +1687,38 @@ This software is available under 2 licenses -- choose whichever you prefer. |
|
|
------------------------------------------------------------------------------ |
|
|
------------------------------------------------------------------------------ |
|
|
ALTERNATIVE A - MIT License |
|
|
ALTERNATIVE A - MIT License |
|
|
Copyright (c) 2017 Sean Barrett |
|
|
Copyright (c) 2017 Sean Barrett |
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy of |
|
|
|
|
|
this software and associated documentation files (the "Software"), to deal in |
|
|
|
|
|
the Software without restriction, including without limitation the rights to |
|
|
|
|
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies |
|
|
|
|
|
of the Software, and to permit persons to whom the Software is furnished to do |
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy of |
|
|
|
|
|
this software and associated documentation files (the "Software"), to deal in |
|
|
|
|
|
the Software without restriction, including without limitation the rights to |
|
|
|
|
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies |
|
|
|
|
|
of the Software, and to permit persons to whom the Software is furnished to do |
|
|
so, subject to the following conditions: |
|
|
so, subject to the following conditions: |
|
|
The above copyright notice and this permission notice shall be included in all |
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included in all |
|
|
copies or substantial portions of the Software. |
|
|
copies or substantial portions of the Software. |
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
|
|
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
|
|
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
|
|
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
|
|
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
|
|
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
|
|
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|
|
SOFTWARE. |
|
|
SOFTWARE. |
|
|
------------------------------------------------------------------------------ |
|
|
------------------------------------------------------------------------------ |
|
|
ALTERNATIVE B - Public Domain (www.unlicense.org) |
|
|
ALTERNATIVE B - Public Domain (www.unlicense.org) |
|
|
This is free and unencumbered software released into the public domain. |
|
|
This is free and unencumbered software released into the public domain. |
|
|
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this |
|
|
|
|
|
software, either in source code form or as a compiled binary, for any purpose, |
|
|
|
|
|
|
|
|
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this |
|
|
|
|
|
software, either in source code form or as a compiled binary, for any purpose, |
|
|
commercial or non-commercial, and by any means. |
|
|
commercial or non-commercial, and by any means. |
|
|
In jurisdictions that recognize copyright laws, the author or authors of this |
|
|
|
|
|
software dedicate any and all copyright interest in the software to the public |
|
|
|
|
|
domain. We make this dedication for the benefit of the public at large and to |
|
|
|
|
|
the detriment of our heirs and successors. We intend this dedication to be an |
|
|
|
|
|
overt act of relinquishment in perpetuity of all present and future rights to |
|
|
|
|
|
|
|
|
In jurisdictions that recognize copyright laws, the author or authors of this |
|
|
|
|
|
software dedicate any and all copyright interest in the software to the public |
|
|
|
|
|
domain. We make this dedication for the benefit of the public at large and to |
|
|
|
|
|
the detriment of our heirs and successors. We intend this dedication to be an |
|
|
|
|
|
overt act of relinquishment in perpetuity of all present and future rights to |
|
|
this software under copyright law. |
|
|
this software under copyright law. |
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
|
|
|
|
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
|
|
|
|
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
|
|
|
|
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
|
|
|
|
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
|
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
|
------------------------------------------------------------------------------ |
|
|
------------------------------------------------------------------------------ |
|
|
*/ |
|
|
*/ |