From e003c66498c7929032d185448fd92719abc1792c Mon Sep 17 00:00:00 2001 From: Ken Miller Date: Sun, 7 Sep 2014 00:38:18 -0500 Subject: [PATCH 01/11] support PGM and PPM formats --- stb_image.h | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 121 insertions(+), 1 deletion(-) diff --git a/stb_image.h b/stb_image.h index 90d0d15..862f961 100644 --- a/stb_image.h +++ b/stb_image.h @@ -56,7 +56,7 @@ Jean-Marc Lienher (gif) Won Chun Tom Seddon (pic) the Horde3D community Thatcher Ulrich (psd) Janez Zemva - Jonathan Blow + Ken Miller (pgm, ppm) Jonathan Blow Laurent Gomila Extensions, features Aruelien Pocheville Jetro Lauha (stbi_info) Ryamond Barbiero @@ -514,6 +514,9 @@ static stbi_uc *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int static int stbi__gif_test(stbi__context *s); static stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__pnm_test(stbi__context *s); +static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp); +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); // this is not threadsafe @@ -568,6 +571,7 @@ static unsigned char *stbi_load_main(stbi__context *s, int *x, int *y, int *comp if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp); if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp); if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp); + if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp); #ifndef STBI_NO_HDR if (stbi__hdr_test(s)) { @@ -4500,6 +4504,120 @@ static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) return 1; } +// ************************************************************************************************* +// Portable Gray Map and Portable Pixel Map loader +// by Ken Miller +// +// PGM: http://netpbm.sourceforge.net/doc/pgm.html +// PPM: http://netpbm.sourceforge.net/doc/ppm.html +// +// Known limitations: +// Does not support comments in the header section +// Does not support ASCII image data (formats P2 and P3) + +static int stbi__pnm_test(stbi__context *s) +{ + char p, t; + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind( s ); + return 0; + } + return 1; +} + +static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi_uc *out; + if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) { + return 0; + } + *x = s->img_x; + *y = s->img_y; + *comp = s->img_n; + + out = stbi__malloc(s->img_n * s->img_x * s->img_y); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + stbi__getn(s, out, s->img_n * s->img_x * s->img_y); + + if (req_comp && req_comp != s->img_n) { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + return out; +} + +static int stbi__pnm_isspace(char c) +{ + return c == ' ' || c == '\t' || c == '\n' || c == '\r'; +} + +static void stbi__pnm_skipspace(stbi__context *s, char *c) +{ + while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) { + *c = (char) stbi__get8(s); + } +} + +static int stbi__pnm_isdigit(char c) +{ + return c >= '0' && c <= '9'; +} + +static int stbi__pnm_getinteger(stbi__context *s, char *c) +{ + int value = 0; + + while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { + value *= 10; + value += *c - '0'; + *c = (char) stbi__get8(s); + } + + return value; +} + +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) +{ + char c, p, t; + + stbi__rewind( s ); + + // Get identifier + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind( s ); + return 0; + } + + // '5' is 1-component .pgm; '6' is 3-component .ppm + *comp = (t == '6') ? 3 : 1; + + c = (char) stbi__get8(s); + + // skip whitespace + stbi__pnm_skipspace(s, &c); + + // read width + *x = stbi__pnm_getinteger(s, &c); + + // skip whitespace + stbi__pnm_skipspace(s, &c); + + // read height + *y = stbi__pnm_getinteger(s, &c); + + // skip whitespace + stbi__pnm_skipspace(s, &c); + + // read max value + stbi__pnm_getinteger(s, &c); + + return 1; +} + static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) { if (stbi__jpeg_info(s, x, y, comp)) @@ -4514,6 +4632,8 @@ static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) return 1; if (stbi__pic_info(s, x, y, comp)) return 1; + if (stbi__pnm_info(s, x, y, comp)) + return 1; #ifndef STBI_NO_HDR if (stbi__hdr_info(s, x, y, comp)) return 1; From 8e91cb2b7df2ab3ee6f2be97fbde1433e2c6ac0c Mon Sep 17 00:00:00 2001 From: Ken Miller Date: Sun, 7 Sep 2014 00:48:48 -0500 Subject: [PATCH 02/11] treat vertical tab and form feed characters as whitespace --- stb_image.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stb_image.h b/stb_image.h index 862f961..287eca9 100644 --- a/stb_image.h +++ b/stb_image.h @@ -4550,7 +4550,7 @@ static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int static int stbi__pnm_isspace(char c) { - return c == ' ' || c == '\t' || c == '\n' || c == '\r'; + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; } static void stbi__pnm_skipspace(stbi__context *s, char *c) From bd6b78f2680dd95320a6658851586164d7b0ff7b Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Sat, 20 Dec 2014 05:13:25 -0800 Subject: [PATCH 03/11] finalize scalar YCbCr conversion back-ported from SSE version; add missing STBIDEFs to a few functions; update documentation with full 1.49 info even though most isn't implemented yet --- stb_image.h | 152 ++++++++++++++++++++++++++++++--------------- tests/image_test.c | 10 +-- 2 files changed, 107 insertions(+), 55 deletions(-) diff --git a/stb_image.h b/stb_image.h index ef01a26..c701e3f 100644 --- a/stb_image.h +++ b/stb_image.h @@ -7,6 +7,8 @@ before you include this file in *one* C or C++ file to create the implementation. #define STBI_ASSERT(x) to avoid using assert.h. + #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free + QUICK NOTES: Primarily of interest to game developers and other people who can @@ -27,7 +29,56 @@ - decode from arbitrary I/O callbacks - SIMD acceleration on x86/x64 - Latest revisions: + Full documentation under "DOCUMENTATION" below. + + + Revision 1.49 release notes: + + - The old STBI_SIMD system which allowed installing a user-defined + IDCT etc. has been removed. If you need this, don't upgrade. My + assumption is that almost nobody was doing this, and those who + were will find the next bullet item more satisfactory anyway. + + - x86 platforms now make use of SSE2 SIMD instructions if available. + This release is 2x faster on our test JPEGs, mostly due to SIMD. + This work was done by Fabian "ryg" Giesen. + + - Compilation of SIMD code can be suppressed with + #define STBI_NO_SIMD + It should not be necessary to disable it unless you have issues + compiling (e.g. using an x86 compiler which doesn't support SSE + intrinsics or that doesn't support the method used to detect + SSE2 support at run-time), and even those can be reported as + bugs so I can refine the built-in compile-time checking to be + smarter. + + - RGB values computed for JPEG images are slightly different from + previous versions of stb_image. (This is due to using less + integer precision in SIMD.) The C code has been adjusted so + that the same RGB values will be computed regardless of whether + SIMD support is available, so your app should always produce + consistent results. But these results are slightly different from + previous versions. (Specifically, about 3% of available YCbCr values + will compute different RGB results from pre-1.49 versions by +-1; + most of the deviating values are one smaller in the G channel.) + + - If you must produce consistent results with previous versions of + stb_image, #define STBI_JPEG_OLD and you will get the same results + you used to; however, you will not get the SIMD speedups for + the YCbCr-to-RGB conversion step (although you should still see + significant JPEG speedup from the other changes). + + Please note that STBI_JPEG_OLD is a temporary feature; it will be + removed in future versions of the library. It is only intended for + back-compatibility use. + + + Latest revision history: + 1.49 (2014-12-25) optimize JPG, incl. x86 SIMD + PGM/PPM support + allocation macros + stbi_load_into() -- load into pre-defined memory + STBI_MALLOC,STBI_REALLOC,STBI_FREE 1.48 (2014-12-14) fix incorrectly-named assert() 1.47 (2014-12-14) 1/2/4-bit PNG support (both grayscale and paletted) optimize PNG @@ -41,9 +92,6 @@ See end of file for full revision history. - TODO: - stbi_info support for BMP,PSD,HDR,PIC - ============================ Contributors ========================= @@ -79,6 +127,8 @@ #ifndef STBI_INCLUDE_STB_IMAGE_H #define STBI_INCLUDE_STB_IMAGE_H +// DOCUMENTATION +// // Limitations: // - no jpeg progressive support // - no 16-bit-per-channel PNG @@ -248,14 +298,6 @@ extern "C" { // load image by filename, open file, or memory buffer // -STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); - -#ifndef STBI_NO_STDIO -STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *comp, int req_comp); -STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); -// for stbi_load_from_file, file pointer is left pointing immediately after image -#endif - typedef struct { int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read @@ -263,18 +305,26 @@ typedef struct int (*eof) (void *user); // returns nonzero if we are at end of file/data } stbi_io_callbacks; -STBIDEF stbi_uc *stbi_load_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp); +STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *comp, int req_comp); +STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *comp, int req_comp); +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *comp, int req_comp); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +// for stbi_load_from_file, file pointer is left pointing immediately after image +#endif #ifndef STBI_NO_HDR - STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); - - #ifndef STBI_NO_STDIO - STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *comp, int req_comp); - STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); - #endif - + STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *comp, int req_comp); + STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp); + #ifndef STBI_NO_STDIO + STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); + #endif +#endif + +#ifndef STBI_NO_HDR STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); STBIDEF void stbi_hdr_to_ldr_scale(float scale); @@ -282,7 +332,7 @@ STBIDEF stbi_uc *stbi_load_from_callbacks (stbi_io_callbacks const *clbk, void STBIDEF void stbi_ldr_to_hdr_scale(float scale); #endif // STBI_NO_HDR -// stbi_is_hdr is always defined +// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); #ifndef STBI_NO_STDIO @@ -648,7 +698,7 @@ static FILE *stbi__fopen(char const *filename, char const *mode) } -STBIDEF unsigned char *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) +STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) { FILE *f = stbi__fopen(filename, "rb"); unsigned char *result; @@ -658,7 +708,7 @@ STBIDEF unsigned char *stbi_load(char const *filename, int *x, int *y, int *comp return result; } -STBIDEF unsigned char *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) { unsigned char *result; stbi__context s; @@ -672,14 +722,14 @@ STBIDEF unsigned char *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, i } #endif //!STBI_NO_STDIO -STBIDEF unsigned char *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) { stbi__context s; stbi__start_mem(&s,buffer,len); return stbi_load_main(&s,x,y,comp,req_comp); } -STBIDEF unsigned char *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) { stbi__context s; stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); @@ -740,7 +790,7 @@ STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_ // defined, for API simplicity; if STBI_NO_HDR is defined, it always // reports false! -int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) { #ifndef STBI_NO_HDR stbi__context s; @@ -792,11 +842,11 @@ STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; -void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } -void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } +STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } +STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } -void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } -void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } +STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } +STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } #endif @@ -2112,10 +2162,10 @@ static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_ return out; } +#ifdef STBI_JPEG_OLD +// this is the same YCbCr-to-RGB calculation that stb_image has used +// historically before the algorithm changes in 1.49 #define float2fixed(x) ((int) ((x) * 65536 + 0.5)) - -// 0.38 seconds on 3*anemones.jpg (0.25 with processor = Pro) -// VC6 without processor=Pro is generating multiple LEAs per multiply! static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) { int i; @@ -2140,10 +2190,11 @@ static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc out += step; } } - -#define float2fixed2(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) - -static void stbi__YCbCr_to_RGB_backport(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) +#else +// this is a reduced-precision calculation of YCbCr-to-RGB introduced +// to make sure the code produces the same results in both SIMD and scalar +#define float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) +static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) { int i; for (i=0; i < count; ++i) { @@ -2151,11 +2202,9 @@ static void stbi__YCbCr_to_RGB_backport(stbi_uc *out, const stbi_uc *y, const st int r,g,b; int cr = pcr[i] - 128; int cb = pcb[i] - 128; - r = y_fixed + cr*float2fixed2(1.40200f); - g = y_fixed; - g += (cr*-float2fixed2(0.71414f)) & 0xffff0000; - g += (cb*-float2fixed2(0.34414f)) & 0xffff0000; - b = y_fixed + cb*float2fixed2(1.77200f); + r = y_fixed + cr* float2fixed(1.40200f); + g = y_fixed + (cr*-float2fixed(0.71414f)) + ((cb*-float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* float2fixed(1.77200f); r >>= 20; g >>= 20; b >>= 20; @@ -2169,6 +2218,7 @@ static void stbi__YCbCr_to_RGB_backport(stbi_uc *out, const stbi_uc *y, const st out += step; } } +#endif #ifdef STBI_SSE2 static void stbi__YCbCr_to_RGB_sse2(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) @@ -2182,7 +2232,7 @@ static void stbi__YCbCr_to_RGB_sse2(stbi_uc *out, stbi_uc const *y, stbi_uc cons // note: unlike the IDCT, this isn't bit-identical to the integer version. if (step == 4) { // this is a fairly straightforward implementation and not super-optimized. - __m128i signflip = _mm_set1_epi8(-0x80); + __m128i signflip = _mm_set1_epi8(-0x80); __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); @@ -2237,16 +2287,16 @@ static void stbi__YCbCr_to_RGB_sse2(stbi_uc *out, stbi_uc const *y, stbi_uc cons } for (; i < count; ++i) { - int y_fixed = (y[i] << 16) + 32768; // rounding + int y_fixed = (y[i] << 20) + (1<<19); // rounding int r,g,b; int cr = pcr[i] - 128; int cb = pcb[i] - 128; - r = y_fixed + cr*float2fixed(1.40200f); - g = y_fixed - cr*float2fixed(0.71414f) - cb*float2fixed(0.34414f); - b = y_fixed + cb*float2fixed(1.77200f); - r >>= 16; - g >>= 16; - b >>= 16; + r = y_fixed + cr* float2fixed(1.40200f); + g = y_fixed + cr*-float2fixed(0.71414f) + ((cb*-float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } @@ -2269,7 +2319,9 @@ static void stbi__setup_jpeg(stbi__jpeg *j) #ifdef STBI_SSE2 if (stbi__sse2_available()) { j->idct_block_kernel = stbi__idct_sse2; + #ifndef STBI_JPEG_OLD j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_sse2; + #endif j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_sse2; } #endif diff --git a/tests/image_test.c b/tests/image_test.c index b3c8e1d..8f35150 100644 --- a/tests/image_test.c +++ b/tests/image_test.c @@ -9,7 +9,7 @@ #define PNGSUITE_PRIMARY -#if 1 +#if 0 void test_ycbcr(void) { STBI_SIMD_ALIGN(unsigned char, y[256]); @@ -28,15 +28,15 @@ void test_ycbcr(void) cb[k] = j; cr[k] = i; } - stbi__YCbCr_to_RGB_sse2(out1[0], y, cb, cr, 256, 4); - stbi__YCbCr_to_RGB_backport(out2[0], y, cb, cr, 256, 4); + stbi__YCbCr_to_RGB_row(out1[0], y, cb, cr, 256, 4); + stbi__YCbCr_to_RGB_sse2(out2[0], y, cb, cr, 256, 4); for (k=0; k < 256; ++k) { if (out1[k][0] != out2[k][0] || out1[k][1] != out2[k][1] || out1[k][2] != out2[k][2]) { int dist1 = abs(out1[k][0] - out2[k][0]); int dist2 = abs(out1[k][1] - out2[k][1]); int dist3 = abs(out1[k][2] - out2[k][2]); ++count; - if (dist2) + if (out1[k][1] > out2[k][1]) ++bigcount; } } @@ -50,7 +50,7 @@ void test_ycbcr(void) int main(int argc, char **argv) { int w,h; - test_ycbcr(); + //test_ycbcr(); if (argc > 1) { int i; for (i=1; i < argc; ++i) { From ba5e333fafdbff36feacf1ff5ac41833d8f37677 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Sat, 20 Dec 2014 05:46:13 -0800 Subject: [PATCH 04/11] STBI_MALLOC etc. some documentation cleanup --- stb_image.h | 181 +++++++++++++++++++-------------- tests/test_cpp_compilation.cpp | 8 ++ 2 files changed, 111 insertions(+), 78 deletions(-) diff --git a/stb_image.h b/stb_image.h index c701e3f..76f78c7 100644 --- a/stb_image.h +++ b/stb_image.h @@ -132,12 +132,11 @@ // Limitations: // - no jpeg progressive support // - no 16-bit-per-channel PNG -// - no 12-bit-per-channel jpeg -// - no delayed line count (jpeg) -- IJG doesn't support either +// - no 12-bit-per-channel JPEG // - no 1-bit BMP // - GIF always returns *comp=4 // -// Basic usage (see HDR discussion below): +// Basic usage (see HDR discussion below for HDR usage): // int x,y,n; // unsigned char *data = stbi_load(filename, &x, &y, &n, 0); // // ... process data if not NULL ... @@ -153,14 +152,16 @@ // int req_comp -- if non-zero, # of image components requested in result // // The return value from an image loader is an 'unsigned char *' which points -// to the pixel data. The pixel data consists of *y scanlines of *x pixels, +// to the pixel data, or NULL on an allocation failure or if the image is +// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels, // with each pixel consisting of N interleaved 8-bit components; the first // pixel pointed to is top-left-most in the image. There is no padding between // image scanlines or between pixels, regardless of format. The number of // components N is 'req_comp' if req_comp is non-zero, or *comp otherwise. // If req_comp is non-zero, *comp has the number of components that _would_ // have been output otherwise. E.g. if you set req_comp to 4, you will always -// get RGBA output, but you can check *comp to easily see if it's opaque. +// get RGBA output, but you can check *comp to see if it's trivially opaque +// because e.g. there were only 3 channels in the source image. // // An output image with N components has the following components interleaved // in this order in each pixel: @@ -182,18 +183,39 @@ // // =========================================================================== // -// iPhone PNG support: +// I/O callbacks // -// By default we convert iphone-formatted PNGs back to RGB; nominally they -// would silently load as BGR, except the existing code should have just -// failed on such iPhone PNGs. But you can disable this conversion by -// by calling stbi_convert_iphone_png_to_rgb(0), in which case -// you will always just get the native iphone "format" through. +// I/O callbacks allow you to read from arbitrary sources, like packaged +// files or some other source. Data read from callbacks are processed +// through a small internal buffer (currently 128 bytes) to try to reduce +// overhead. // -// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per -// pixel to remove any premultiplied alpha *only* if the image file explicitly -// says there's premultiplied data (currently only happens in iPhone images, -// and only if iPhone convert-to-rgb processing is on). +// The three functions you must define are "read" (reads some bytes of data), +// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). +// +// =========================================================================== +// +// SIMD support +// +// The JPEG decoder will automatically use SIMD kernels on x86 platforms +// where supported. +// +// (The old do-it-yourself SIMD API is no longer supported in the current +// code.) +// +// The code will automatically detect if the required SIMD instructions are +// available, and fall back to the generic C version where they're not. +// +// The output of the JPEG decoder is slightly different from versions where +// SIMD support was introduced (that is, for versions before 1.49). The +// difference is only +-1 in the 8-bit RGB channels, and only on a small +// fraction of pixels. You can force the pre-1.49 behavior by defining +// STBI_JPEG_OLD, but this will disable some of the SIMD decoding path +// and hence cost some performance. +// +// If for some reason you do not want to use any of SIMD code, or if +// you have issues compiling it, you can disable it entirely by +// defining STBI_NO_SIMD. // // =========================================================================== // @@ -233,32 +255,19 @@ // // =========================================================================== // -// I/O callbacks +// iPhone PNG support: // -// I/O callbacks allow you to read from arbitrary sources, like packaged -// files or some other source. Data read from callbacks are processed -// through a small internal buffer (currently 128 bytes) to try to reduce -// overhead. +// By default we convert iphone-formatted PNGs back to RGB, even though +// they are internally encoded differently. You can disable this conversion +// by by calling stbi_convert_iphone_png_to_rgb(0), in which case +// you will always just get the native iphone "format" through (which +// is BGR stored in RGB). // -// The three functions you must define are "read" (reads some bytes of data), -// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). +// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per +// pixel to remove any premultiplied alpha *only* if the image file explicitly +// says there's premultiplied data (currently only happens in iPhone images, +// and only if iPhone convert-to-rgb processing is on). // -// =========================================================================== -// -// SIMD support -// -// The JPEG decoder will automatically use SIMD kernels on x86 platforms -// where supported. -// -// (The old do-it-yourself SIMD API is no longer supported in the current -// code.) -// -// The code will automatically detect if the required SIMD instructions are -// available, and fall back to the generic C version where they're not. -// -// The supplied kernels are designed to produce results that are bit-identical -// to the C versions. Nevertheless, if you want to disable this functionality, -// define STBI_NO_SIMD. #ifndef STBI_NO_STDIO @@ -392,22 +401,24 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch #ifdef STB_IMAGE_IMPLEMENTATION +#include +#include // ptrdiff_t on osx +#include +#include + #ifndef STBI_NO_HDR #include // ldexp -#include // strcmp, strtok #endif #ifndef STBI_NO_STDIO #include #endif -#include -#include + #ifndef STBI_ASSERT #include #define STBI_ASSERT(x) assert(x) #endif -#include -#include // ptrdiff_t on osx + #ifndef _MSC_VER #ifdef __cplusplus @@ -452,6 +463,20 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) #endif +#if defined(STBI_MALLOC) && defined(STBI_FREE) && defined(STBI_REALLOC) +// ok +#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) +// ok +#else +#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC." +#endif + +#ifndef STBI_MALLOC +#define STBI_MALLOC(sz) malloc(sz) +#define STBI_REALLOC(p,sz) realloc(p,sz) +#define STBI_FREE(p) free(p) +#endif + #if !defined(STBI_NO_SIMD) && (defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86)) #define STBI_SSE2 #include @@ -633,7 +658,7 @@ static int stbi__err(const char *str) static void *stbi__malloc(size_t size) { - return malloc(size); + return STBI_MALLOC(size); } // stbi__err - error @@ -653,7 +678,7 @@ static void *stbi__malloc(size_t size) STBIDEF void stbi_image_free(void *retval_from_stbi_load) { - free(retval_from_stbi_load); + STBI_FREE(retval_from_stbi_load); } #ifndef STBI_NO_HDR @@ -988,7 +1013,7 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r good = (unsigned char *) stbi__malloc(req_comp * x * y); if (good == NULL) { - free(data); + STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } @@ -1018,7 +1043,7 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r #undef CASE } - free(data); + STBI_FREE(data); return good; } @@ -1027,7 +1052,7 @@ static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) { int i,k,n; float *output = (float *) stbi__malloc(x * y * comp * sizeof(float)); - if (output == NULL) { free(data); return stbi__errpf("outofmem", "Out of memory"); } + if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } // compute number of non-alpha components if (comp & 1) n = comp; else n = comp-1; for (i=0; i < x*y; ++i) { @@ -1036,7 +1061,7 @@ static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) } if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f; } - free(data); + STBI_FREE(data); return output; } @@ -1045,7 +1070,7 @@ static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) { int i,k,n; stbi_uc *output = (stbi_uc *) stbi__malloc(x * y * comp); - if (output == NULL) { free(data); return stbi__errpuc("outofmem", "Out of memory"); } + if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } // compute number of non-alpha components if (comp & 1) n = comp; else n = comp-1; for (i=0; i < x*y; ++i) { @@ -1062,7 +1087,7 @@ static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) output[i*comp + k] = (stbi_uc) stbi__float2int(z); } } - free(data); + STBI_FREE(data); return output; } #endif @@ -1918,7 +1943,7 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) z->img_comp[i].raw_data = stbi__malloc(z->img_comp[i].w2 * z->img_comp[i].h2+15); if (z->img_comp[i].raw_data == NULL) { for(--i; i >= 0; --i) { - free(z->img_comp[i].raw_data); + STBI_FREE(z->img_comp[i].raw_data); z->img_comp[i].data = NULL; } return stbi__err("outofmem", "Out of memory"); @@ -2333,12 +2358,12 @@ static void stbi__cleanup_jpeg(stbi__jpeg *j) int i; for (i=0; i < j->s->img_n; ++i) { if (j->img_comp[i].raw_data) { - free(j->img_comp[i].raw_data); + STBI_FREE(j->img_comp[i].raw_data); j->img_comp[i].raw_data = NULL; j->img_comp[i].data = NULL; } if (j->img_comp[i].linebuf) { - free(j->img_comp[i].linebuf); + STBI_FREE(j->img_comp[i].linebuf); j->img_comp[i].linebuf = NULL; } } @@ -2662,7 +2687,7 @@ static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room limit = (int) (z->zout_end - z->zout_start); while (cur + n > limit) limit *= 2; - q = (char *) realloc(z->zout_start, limit); + q = (char *) STBI_REALLOC(z->zout_start, limit); if (q == NULL) return stbi__err("outofmem", "Out of memory"); z->zout_start = q; z->zout = q + cur; @@ -2877,7 +2902,7 @@ STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int if (outlen) *outlen = (int) (a.zout - a.zout_start); return a.zout_start; } else { - free(a.zout_start); + STBI_FREE(a.zout_start); return NULL; } } @@ -2898,7 +2923,7 @@ STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, i if (outlen) *outlen = (int) (a.zout - a.zout_start); return a.zout_start; } else { - free(a.zout_start); + STBI_FREE(a.zout_start); return NULL; } } @@ -2925,7 +2950,7 @@ STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int if (outlen) *outlen = (int) (a.zout - a.zout_start); return a.zout_start; } else { - free(a.zout_start); + STBI_FREE(a.zout_start); return NULL; } } @@ -3217,7 +3242,7 @@ static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint3 if (x && y) { stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { - free(final); + STBI_FREE(final); return 0; } for (j=0; j < y; ++j) { @@ -3228,7 +3253,7 @@ static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint3 a->out + (j*x+i)*out_n, out_n); } } - free(a->out); + STBI_FREE(a->out); image_data += img_len; image_data_len -= img_len; } @@ -3292,7 +3317,7 @@ static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int p += 4; } } - free(a->out); + STBI_FREE(a->out); a->out = temp_out; STBI_NOTUSED(len); @@ -3451,7 +3476,7 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; while (ioff + c.length > idata_limit) idata_limit *= 2; - p = (stbi_uc *) realloc(z->idata, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); + p = (stbi_uc *) STBI_REALLOC(z->idata, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); z->idata = p; } if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); @@ -3468,7 +3493,7 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) raw_len = s->img_x * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); if (z->expanded == NULL) return 0; // zlib should set error - free(z->idata); z->idata = NULL; + STBI_FREE(z->idata); z->idata = NULL; if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) s->img_out_n = s->img_n+1; else @@ -3486,7 +3511,7 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) return 0; } - free(z->expanded); z->expanded = NULL; + STBI_FREE(z->expanded); z->expanded = NULL; return 1; } @@ -3528,9 +3553,9 @@ static unsigned char *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req *y = p->s->img_y; if (n) *n = p->s->img_out_n; } - free(p->out); p->out = NULL; - free(p->expanded); p->expanded = NULL; - free(p->idata); p->idata = NULL; + STBI_FREE(p->out); p->out = NULL; + STBI_FREE(p->expanded); p->expanded = NULL; + STBI_FREE(p->idata); p->idata = NULL; return result; } @@ -3732,7 +3757,7 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int if (!out) return stbi__errpuc("outofmem", "Out of memory"); if (bpp < 16) { int z=0; - if (psize == 0 || psize > 256) { free(out); return stbi__errpuc("invalid", "Corrupt BMP"); } + if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } for (i=0; i < psize; ++i) { pal[i][2] = stbi__get8(s); pal[i][1] = stbi__get8(s); @@ -3743,7 +3768,7 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int stbi__skip(s, offset - 14 - hsz - psize * (hsz == 12 ? 3 : 4)); if (bpp == 4) width = (s->img_x + 1) >> 1; else if (bpp == 8) width = s->img_x; - else { free(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } + else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } pad = (-width)&3; for (j=0; j < (int) s->img_y; ++j) { for (i=0; i < (int) s->img_x; i += 2) { @@ -3781,7 +3806,7 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int easy = 2; } if (!easy) { - if (!mr || !mg || !mb) { free(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } // right shift amt to put high bit in position #7 rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); @@ -3978,12 +4003,12 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int // load the palette tga_palette = (unsigned char*)stbi__malloc( tga_palette_len * tga_palette_bits / 8 ); if (!tga_palette) { - free(tga_data); + STBI_FREE(tga_data); return stbi__errpuc("outofmem", "Out of memory"); } if (!stbi__getn(s, tga_palette, tga_palette_len * tga_palette_bits / 8 )) { - free(tga_data); - free(tga_palette); + STBI_FREE(tga_data); + STBI_FREE(tga_palette); return stbi__errpuc("bad palette", "Corrupt TGA"); } } @@ -4065,7 +4090,7 @@ static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int // clear my palette, if I had one if ( tga_palette != NULL ) { - free( tga_palette ); + STBI_FREE( tga_palette ); } } @@ -4456,7 +4481,7 @@ static stbi_uc *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int re memset(result, 0xff, x*y*4); if (!stbi__pic_load_core(s,x,y,comp, result)) { - free(result); + STBI_FREE(result); result=0; } *px = x; @@ -4966,12 +4991,12 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re stbi__hdr_convert(hdr_data, rgbe, req_comp); i = 1; j = 0; - free(scanline); + STBI_FREE(scanline); goto main_decode_loop; // yes, this makes no sense } len <<= 8; len |= stbi__get8(s); - if (len != width) { free(hdr_data); free(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } + if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } if (scanline == NULL) scanline = (stbi_uc *) stbi__malloc(width * 4); for (k = 0; k < 4; ++k) { @@ -4994,7 +5019,7 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re for (i=0; i < width; ++i) stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); } - free(scanline); + STBI_FREE(scanline); } return hdr_data; diff --git a/tests/test_cpp_compilation.cpp b/tests/test_cpp_compilation.cpp index 44262fb..f97c06b 100644 --- a/tests/test_cpp_compilation.cpp +++ b/tests/test_cpp_compilation.cpp @@ -8,6 +8,14 @@ #define STB_HERRINGBONE_WANG_TILE_IMPLEMENTATION #define STB_RECT_PACK_IMPLEMENTATION +#define STBI_MALLOC my_malloc +#define STBI_FREE my_free +#define STBI_REALLOC my_realloc + +void *my_malloc(size_t) { return 0; } +void *my_realloc(void *, size_t) { return 0; } +void my_free(void *) { } + #include "stb_image.h" #include "stb_rect_pack.h" #include "stb_truetype.h" From b4e526d7cff9dc8471038a30838f722a6d097711 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Sat, 20 Dec 2014 06:09:23 -0800 Subject: [PATCH 05/11] PNM cleanup fix a few old error messages --- stb_image.h | 57 +++++++++++++++++++++++------------------------------ 1 file changed, 25 insertions(+), 32 deletions(-) diff --git a/stb_image.h b/stb_image.h index 7a03c1d..32328ac 100644 --- a/stb_image.h +++ b/stb_image.h @@ -1,4 +1,4 @@ -/* stb_image - v1.48 - public domain JPEG/PNG reader - http://nothings.org/stb_image.c +/* stb_image - v1.49 - public domain JPEG/PNG reader - http://nothings.org/stb_image.c when you control the images you're loading no warranty implied; use at your own risk @@ -24,6 +24,7 @@ GIF (*comp always reports as 4-channel) HDR (radiance rgbE format) PIC (Softimage PIC) + PNM (PPM and PGM binary only) - decode from memory or through FILE (define STBI_NO_STDIO to remove code) - decode from arbitrary I/O callbacks @@ -1972,7 +1973,7 @@ static int decode_jpeg_header(stbi__jpeg *z, int scan) int m; z->marker = STBI__MARKER_none; // initialize cached marker to empty m = stbi__get_marker(z); - if (!stbi__SOI(m)) return stbi__err("no stbi__SOI","Corrupt JPEG"); + if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); if (scan == SCAN_type) return 1; m = stbi__get_marker(z); while (!stbi__SOF(m)) { @@ -1980,7 +1981,7 @@ static int decode_jpeg_header(stbi__jpeg *z, int scan) m = stbi__get_marker(z); while (m == STBI__MARKER_none) { // some files have extra padding after their blocks, so ok, we'll scan - if (stbi__at_eof(z->s)) return stbi__err("no stbi__SOF", "Corrupt JPEG"); + if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); m = stbi__get_marker(z); } } @@ -4565,7 +4566,7 @@ static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_in version = stbi__get8(s); if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); - if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); + if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); stbi__g_failure_reason = ""; g->w = stbi__get16le(s); @@ -5183,6 +5184,7 @@ static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) // Known limitations: // Does not support comments in the header section // Does not support ASCII image data (formats P2 and P3) +// Does not support 16-bit-per-channel static int stbi__pnm_test(stbi__context *s) { @@ -5199,14 +5201,13 @@ static int stbi__pnm_test(stbi__context *s) static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp) { stbi_uc *out; - if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) { - return 0; - } + if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) + return 0; *x = s->img_x; *y = s->img_y; *comp = s->img_n; - out = stbi__malloc(s->img_n * s->img_x * s->img_y); + out = (stbi_uc *) stbi__malloc(s->img_n * s->img_x * s->img_y); if (!out) return stbi__errpuc("outofmem", "Out of memory"); stbi__getn(s, out, s->img_n * s->img_x * s->img_y); @@ -5222,11 +5223,10 @@ static int stbi__pnm_isspace(char c) return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; } -static void stbi__pnm_skipspace(stbi__context *s, char *c) +static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) { - while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) { + while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) *c = (char) stbi__get8(s); - } } static int stbi__pnm_isdigit(char c) @@ -5239,8 +5239,7 @@ static int stbi__pnm_getinteger(stbi__context *s, char *c) int value = 0; while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { - value *= 10; - value += *c - '0'; + value = value*10 + (*c - '0'); *c = (char) stbi__get8(s); } @@ -5249,6 +5248,7 @@ static int stbi__pnm_getinteger(stbi__context *s, char *c) static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) { + int maxv; char c, p, t; stbi__rewind( s ); @@ -5261,30 +5261,23 @@ static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) return 0; } - // '5' is 1-component .pgm; '6' is 3-component .ppm - *comp = (t == '6') ? 3 : 1; + *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm - c = (char) stbi__get8(s); + c = (char) stbi__get8(s); + stbi__pnm_skip_whitespace(s, &c); - // skip whitespace - stbi__pnm_skipspace(s, &c); + *x = stbi__pnm_getinteger(s, &c); // read width + stbi__pnm_skip_whitespace(s, &c); - // read width - *x = stbi__pnm_getinteger(s, &c); + *y = stbi__pnm_getinteger(s, &c); // read height + stbi__pnm_skip_whitespace(s, &c); - // skip whitespace - stbi__pnm_skipspace(s, &c); + maxv = stbi__pnm_getinteger(s, &c); // read max value - // read height - *y = stbi__pnm_getinteger(s, &c); - - // skip whitespace - stbi__pnm_skipspace(s, &c); - - // read max value - stbi__pnm_getinteger(s, &c); - - return 1; + if (maxv > 255) + return stbi__err("max value > 255", "PPM image not 8-bit"); + else + return 1; } static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) From 9ad85cc8d2f7ecf7b7afb331248e7e821df3fadc Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Sat, 20 Dec 2014 06:22:17 -0800 Subject: [PATCH 06/11] tweak release docs tweak credits tweak revision history remove trailing whitespace --- stb_image.h | 130 +++++++++++++++++++++++++++++----------------------- 1 file changed, 72 insertions(+), 58 deletions(-) diff --git a/stb_image.h b/stb_image.h index 32328ac..9b936f7 100644 --- a/stb_image.h +++ b/stb_image.h @@ -51,7 +51,7 @@ intrinsics or that doesn't support the method used to detect SSE2 support at run-time), and even those can be reported as bugs so I can refine the built-in compile-time checking to be - smarter. + smarter. - RGB values computed for JPEG images are slightly different from previous versions of stb_image. (This is due to using less @@ -73,12 +73,18 @@ removed in future versions of the library. It is only intended for back-compatibility use. + - Added support for PNM images. + + - Added STBI_MALLOC, STBI_REALLOC, and STBI_FREE macros for replacing + the memory allocator. Unlike other STBI libraries, these macros don't + support a context parameter, so if you need to pass a context in to + the allocator, you'll have to store it in a global or a thread-local + variable. + Latest revision history: 1.49 (2014-12-25) optimize JPG, incl. x86 SIMD PGM/PPM support - allocation macros - stbi_load_into() -- load into pre-defined memory STBI_MALLOC,STBI_REALLOC,STBI_FREE 1.48 (2014-12-14) fix incorrectly-named assert() 1.47 (2014-12-14) 1/2/4-bit PNG support (both grayscale and paletted) @@ -86,16 +92,12 @@ fix bug in interlaced PNG with user-specified channel count 1.46 (2014-08-26) fix broken tRNS chunk in non-paletted PNG 1.45 (2014-08-16) workaround MSVC-ARM internal compiler error by wrapping malloc - 1.44 (2014-08-07) warnings - 1.43 (2014-07-15) fix MSVC-only bug in 1.42 - 1.42 (2014-07-09) no _CRT_SECURE_NO_WARNINGS; error-path fixes; STBI_ASSERT - 1.41 (2014-06-25) fix search&replace that messed up comments/error messages See end of file for full revision history. ============================ Contributors ========================= - + Image formats Bug fixes & warning fixes Sean Barrett (jpeg, png, bmp) Marc LeBlanc Nicolas Schulz (hdr, psd) Christpher Lloyd @@ -105,24 +107,32 @@ Thatcher Ulrich (psd) Janez Zemva Ken Miller (pgm, ppm) Jonathan Blow Laurent Gomila - Extensions, features Aruelien Pocheville - Jetro Lauha (stbi_info) Ryamond Barbiero - James "moose2000" Brown (iPhone PNG) David Woo - Ben "Disch" Wenger (io callbacks) Roy Eltham - Martin "SpartanJ" Golini Luke Graham - Omar Cornut (1/2/4-bit png) Thomas Ruf + Aruelien Pocheville + Extensions, features Ryamond Barbiero + Jetro Lauha (stbi_info) David Woo + Martin "SpartanJ" Golini (stbi_info) Martin Golini + James "moose2000" Brown (iPhone PNG) Roy Eltham + Ben "Disch" Wenger (io callbacks) Luke Graham + Omar Cornut (1/2/4-bit PNG) Thomas Ruf John Bartholomew - Optimizations & bugfixes Ken Hamada - Fabian "ryg" Giesen Cort Stratton - Arseny Kapoulkine Blazej Dariusz Roszkowski - Thibault Reuille + Ken Hamada + Optimizations & bugfixes Cort Stratton + Fabian "ryg" Giesen Blazej Dariusz Roszkowski + Arseny Kapoulkine Thibault Reuille Paul Du Bois Guillaume George - Jerry Jansson - If your name should be here but Hayaki Saito - isn't, let Sean know. Johan Duparc + If your name should be here but Jerry Jansson + isn't, let Sean know. Hayaki Saito + Johan Duparc Ronny Chevalier Michal Cichon + Tero Hanninen + +License: + This software is in the public domain. Where that dedication is not + recognized, you are granted a perpetual, irrevocable license to copy + and modify this file as you see fit. + */ #ifndef STBI_INCLUDE_STB_IMAGE_H @@ -140,7 +150,7 @@ // Basic usage (see HDR discussion below for HDR usage): // int x,y,n; // unsigned char *data = stbi_load(filename, &x, &y, &n, 0); -// // ... process data if not NULL ... +// // ... process data if not NULL ... // // ... x = width, y = height, n = # 8-bit components per pixel ... // // ... replace '0' with '1'..'4' to force that many components per pixel // // ... but 'n' will always be the number that it would have been if you said 0 @@ -189,7 +199,7 @@ // I/O callbacks allow you to read from arbitrary sources, like packaged // files or some other source. Data read from callbacks are processed // through a small internal buffer (currently 128 bytes) to try to reduce -// overhead. +// overhead. // // The three functions you must define are "read" (reads some bytes of data), // "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). @@ -239,7 +249,7 @@ // (linear) floats to preserve the full dynamic range: // // float *data = stbi_loadf(filename, &x, &y, &n, 0); -// +// // If you load LDR images through this interface, those images will // be promoted to floating point values, run through the inverse of // constants corresponding to the above: @@ -310,7 +320,7 @@ extern "C" { typedef struct { - int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read + int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative int (*eof) (void *user); // returns nonzero if we are at end of file/data } stbi_io_callbacks; @@ -353,7 +363,7 @@ STBIDEF int stbi_is_hdr_from_file(FILE *f); // get a VERY brief reason for failure // NOT THREADSAFE -STBIDEF const char *stbi_failure_reason (void); +STBIDEF const char *stbi_failure_reason (void); // free the loaded image -- this is just free() STBIDEF void stbi_image_free (void *retval_from_stbi_load); @@ -543,7 +553,7 @@ typedef struct { stbi__uint32 img_x, img_y; int img_n, img_out_n; - + stbi_io_callbacks io; void *io_user_data; @@ -928,7 +938,7 @@ stbi_inline static int stbi__at_eof(stbi__context *s) if (s->read_from_callbacks == 0) return 1; } - return s->img_buffer >= s->img_buffer_end; + return s->img_buffer >= s->img_buffer_end; } static void stbi__skip(stbi__context *s, int n) @@ -952,7 +962,7 @@ static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) int res, count; memcpy(buffer, s->img_buffer, blen); - + count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); res = (count == (n-blen)); s->img_buffer = s->img_buffer_end; @@ -2379,7 +2389,7 @@ typedef struct resample_row_func resample; stbi_uc *line0,*line1; int hs,vs; // expansion factor in each axis - int w_lores; // horizontal pixels pre-expansion + int w_lores; // horizontal pixels pre-expansion int ystep; // how far through vertical expansion we are int ypos; // which pre-expansion row we're on } stbi__resample; @@ -2539,7 +2549,7 @@ typedef struct int maxcode[17]; stbi__uint16 firstsymbol[16]; stbi_uc size[288]; - stbi__uint16 value[288]; + stbi__uint16 value[288]; } stbi__zhuffman; stbi_inline static int stbi__bitreverse16(int n) @@ -2567,7 +2577,7 @@ static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num) // DEFLATE spec for generating codes memset(sizes, 0, sizeof(sizes)); memset(z->fast, 0, sizeof(z->fast)); - for (i=0; i < num; ++i) + for (i=0; i < num; ++i) ++sizes[sizelist[i]]; sizes[0] = 0; for (i=1; i < 16; ++i) @@ -2647,7 +2657,7 @@ stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) k = z->code_buffer & ((1 << n) - 1); z->code_buffer >>= n; z->num_bits -= n; - return k; + return k; } static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) @@ -2705,7 +2715,7 @@ static int stbi__zlength_base[31] = { 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 }; -static int stbi__zlength_extra[31]= +static int stbi__zlength_extra[31]= { 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,0,0 }; static int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, @@ -3370,7 +3380,7 @@ static void stbi__de_iphone(stbi__png *z) } else { p[0] = p[2]; p[2] = t; - } + } p += 4; } } else { @@ -3837,7 +3847,7 @@ static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); - if (target == 4) out[z++] = STBI__BYTECAST(a); + if (target == 4) out[z++] = STBI__BYTECAST(a); } } stbi__skip(s, pad); @@ -4161,7 +4171,7 @@ static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int // Read the rows and columns of the image. h = stbi__get32be(s); w = stbi__get32be(s); - + // Make sure the depth is 8 bits. if (stbi__get16be(s) != 8) return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 bit"); @@ -4203,7 +4213,7 @@ static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int // Initialize the data to zero. //memset( out, 0, pixelCount * 4 ); - + // Finally, the image data. if (compression) { // RLE as used by .PSD and .TIFF @@ -4221,7 +4231,7 @@ static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int // Read the RLE data by channel. for (channel = 0; channel < 4; channel++) { stbi_uc *p; - + p = out+channel; if (channel >= channelCount) { // Fill this channel with default data. @@ -4259,15 +4269,15 @@ static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int } } } - + } else { // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) // where each channel consists of an 8-bit value for each pixel in the image. - + // Read the data by channel. for (channel = 0; channel < 4; channel++) { stbi_uc *p; - + p = out + channel; if (channel > channelCount) { // Fill this channel with default data. @@ -4288,7 +4298,7 @@ static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int if (comp) *comp = channelCount; *y = h; *x = w; - + return out; } @@ -4506,7 +4516,7 @@ static int stbi__pic_test(stbi__context *s) // ************************************************************************************************* // GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb -typedef struct +typedef struct { stbi__int16 prefix; stbi_uc first; @@ -4555,7 +4565,7 @@ static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], in pal[i][1] = stbi__get8(s); pal[i][0] = stbi__get8(s); pal[i][3] = transp ? 0 : 255; - } + } } static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) @@ -4567,7 +4577,7 @@ static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_in version = stbi__get8(s); if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); - + stbi__g_failure_reason = ""; g->w = stbi__get16le(s); g->h = stbi__get16le(s); @@ -4588,7 +4598,7 @@ static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_in static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) { - stbi__gif g; + stbi__gif g; if (!stbi__gif_header(s, &g, comp, 1)) { stbi__rewind( s ); return 0; @@ -4608,7 +4618,7 @@ static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) stbi__out_gif_code(g, g->codes[code].prefix); if (g->cur_y >= g->max_y) return; - + p = &g->out[g->cur_x + g->cur_y]; c = &g->color_table[g->codes[code].suffix * 4]; @@ -4662,7 +4672,7 @@ static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) if (valid_bits < codesize) { if (len == 0) { len = stbi__get8(s); // start new block - if (len == 0) + if (len == 0) return g->out; } --len; @@ -4707,7 +4717,7 @@ static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) } else { return stbi__errpuc("illegal code in raster", "Corrupt GIF"); } - } + } } } @@ -4745,7 +4755,7 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i memcpy(g->out, old_out, g->w*g->h*4); } } - + for (;;) { switch (stbi__get8(s)) { case 0x2C: /* Image Descriptor */ @@ -4780,16 +4790,16 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i if (g->lflags & 0x80) { stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); - g->color_table = (stbi_uc *) g->lpal; + g->color_table = (stbi_uc *) g->lpal; } else if (g->flags & 0x80) { for (i=0; i < 256; ++i) // @OPTIMIZE: stbi__jpeg_reset only the previous transparent - g->pal[i][3] = 255; + g->pal[i][3] = 255; if (g->transparent >= 0 && (g->eflags & 0x01)) g->pal[g->transparent][3] = 0; g->color_table = (stbi_uc *) g->pal; } else return stbi__errpuc("missing color table", "Corrupt GIF"); - + o = stbi__process_gif_raster(s, g); if (o == NULL) return NULL; @@ -4935,7 +4945,7 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re // Check identifier if (strcmp(stbi__hdr_gettoken(s,buffer), "#?RADIANCE") != 0) return stbi__errpf("not HDR", "Corrupt HDR image"); - + // Parse header for(;;) { token = stbi__hdr_gettoken(s,buffer); @@ -5003,7 +5013,7 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re len |= stbi__get8(s); if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } if (scanline == NULL) scanline = (stbi_uc *) stbi__malloc(width * 4); - + for (k = 0; k < 4; ++k) { i = 0; while (i < width) { @@ -5263,7 +5273,7 @@ static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm - c = (char) stbi__get8(s); + c = (char) stbi__get8(s); stbi__pnm_skip_whitespace(s, &c); *x = stbi__pnm_getinteger(s, &c); // read width @@ -5347,6 +5357,10 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int /* revision history: + 1.49 (2014-12-25) optimize JPG, incl. x86 SIMD (ryg) + PGM/PPM support (Ken Miller) + STBI_MALLOC,STBI_REALLOC,STBI_FREE + stbi_load_into() -- load into pre-defined memory 1.48 (2014-12-14) fix incorrectly-named assert() 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) optimize PNG (ryg) @@ -5400,7 +5414,7 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) fix inefficiency in decoding 32-bit BMP (David Woo) 1.29 (2010-08-16) - various warning fixes from Aurelien Pocheville + various warning fixes from Aurelien Pocheville 1.28 (2010-08-01) fix bug in GIF palette transparency (SpartanJ) 1.27 (2010-08-01) From 33e24eafa0c6465390428af6a9b5d905996e3ba3 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Sun, 21 Dec 2014 07:53:05 -0800 Subject: [PATCH 07/11] in progress progressive stuff --- stb_image.h | 492 ++++++++++++++++++++++++++++++++++++--------- tests/image_test.c | 6 +- 2 files changed, 405 insertions(+), 93 deletions(-) diff --git a/stb_image.h b/stb_image.h index 76f78c7..3ece66b 100644 --- a/stb_image.h +++ b/stb_image.h @@ -652,6 +652,7 @@ STBIDEF const char *stbi_failure_reason(void) static int stbi__err(const char *str) { + fclose(stdout); stbi__g_failure_reason = str; return 0; } @@ -1157,15 +1158,24 @@ typedef struct int x,y,w2,h2; stbi_uc *data; - void *raw_data; + void *raw_data, *raw_coeff; stbi_uc *linebuf; + short *coeff; // progressive only + int coeff_w, coeff_h; // number of 8x8 coefficient blocks } img_comp[4]; - stbi__uint32 code_buffer; // jpeg entropy-coded buffer + stbi__uint32 code_buffer; // jpeg entropy-coded buffer int code_bits; // number of valid bits unsigned char marker; // marker seen while filling entropy buffer int nomore; // flag if we saw a marker so must stop + int progressive; + int spec_start; + int spec_end; + int succ_high; + int succ_low; + int eob_run; + int scan_n, order[4]; int restart_interval, todo; @@ -1332,6 +1342,28 @@ stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n) return k + (stbi__jbias[n] & ~sgn); } +// get some unsigned bits +stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) +{ + unsigned int k; + if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k; +} + +stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) +{ + unsigned int k; + if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); + k = j->code_buffer; + j->code_buffer <<= 1; + --j->code_bits; + return k & 0x80000000; +} + // given a value that's at position X in the zigzag stream, // where does it appear in the 8x8 matrix coded as row-major? static stbi_uc stbi__jpeg_dezigzag[64+15] = @@ -1402,6 +1434,159 @@ static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman return 1; } +static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi_uc *dequant) +{ + int diff,dc; + int t; + if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + if (j->succ_high == 0) { + // first scan for DC coefficient, must be first + memset(data,0,64*sizeof(data[0])); // 0 all the ac values now + t = stbi__jpeg_huff_decode(j, hdc); + diff = t ? stbi__extend_receive(j, t) : 0; + + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) ((dc << j->succ_low)); + } else { + // refinement scan for DC coefficient + if (stbi__jpeg_get_bit(j)) + data[0] += 1 << j->succ_low; + } + return 1; +} + +// @OPTIMIZE: store non-zigzagged during the decode passes, +// and only de-zigzag when dequantizing +static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi_uc *dequant) +{ + int k; + if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->succ_high == 0) { + int shift = j->succ_low; + + if (j->eob_run) { + --j->eob_run; + return 1; + } + + k = j->spec_start; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (0 && r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) << shift); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r); + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + --j->eob_run; + break; + } + k += 16; + } else { + k += r; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) << shift); + } + } + } while (k <= j->spec_end); + } else { + // refinement scan for these AC coefficients + + int bit = 1 << j->succ_low; + k = j->spec_start; + + if (j->eob_run == 0) { + do { + int r,s; + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r); + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + break; // fall through to j->eob_run != 0 case below, which continues k + } + r = 16; // r=15 is the code for 16 0s + } else { + if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); + // sign bit + if (stbi__jpeg_get_bit(j)) + s = bit; + else + s = -bit; + } + + // advance by r + while (k <= j->spec_end) { + short *p = &data[stbi__jpeg_dezigzag[k]]; + if (*p != 0) { + if (stbi__jpeg_get_bit(j)) { + if ((*p & bit) == 0) + if (*p > 0) + *p += bit; + else + *p -= bit; + } + ++k; + } else { + if (r == 0) + break; + --r; + ++k; + } + } + + if (s && k <= j->spec_end) { + data[stbi__jpeg_dezigzag[k++]] = s; + } + } while (k <= j->spec_end); + } + + // catch case where a previous block had an eob run OR this block + // has an eob_run (in the previous if) + if (j->eob_run) { + --j->eob_run; + for (; k <= j->spec_end; ++k) { + short *p = &data[stbi__jpeg_dezigzag[k]]; + if (*p != 0) + // if we already have a history for this, get a bit of it + if (stbi__jpeg_get_bit(j)) { + if ((*p & bit) == 0) // not sure about this, it's in Rich's code, it would mean some bits get sent more than once + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } + } + } + + return 1; +} + // take a -128..127 value and stbi__clamp it and convert to 0..255 stbi_inline static stbi_uc stbi__clamp(int x) { @@ -1417,17 +1602,17 @@ stbi_inline static stbi_uc stbi__clamp(int x) #define stbi__fsh(x) ((x) << 12) // derived from jidctint -- DCT_ISLOW -#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ +#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ p2 = s2; \ p3 = s6; \ - p1 = (p2+p3) * stbi__f2f(0.5411961f); \ - t2 = p1 + p3*stbi__f2f(-1.847759065f); \ - t3 = p1 + p2*stbi__f2f( 0.765366865f); \ + p1 = (p2+p3) * stbi__f2f(0.5411961f); \ + t2 = p1 + p3*stbi__f2f(-1.847759065f); \ + t3 = p1 + p2*stbi__f2f( 0.765366865f); \ p2 = s0; \ p3 = s4; \ - t0 = stbi__fsh(p2+p3); \ - t1 = stbi__fsh(p2-p3); \ + t0 = stbi__fsh(p2+p3); \ + t1 = stbi__fsh(p2-p3); \ x0 = t0+t3; \ x3 = t0-t3; \ x1 = t1+t2; \ @@ -1440,21 +1625,20 @@ stbi_inline static stbi_uc stbi__clamp(int x) p4 = t1+t3; \ p1 = t0+t3; \ p2 = t1+t2; \ - p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ - t0 = t0*stbi__f2f( 0.298631336f); \ - t1 = t1*stbi__f2f( 2.053119869f); \ - t2 = t2*stbi__f2f( 3.072711026f); \ - t3 = t3*stbi__f2f( 1.501321110f); \ - p1 = p5 + p1*stbi__f2f(-0.899976223f); \ - p2 = p5 + p2*stbi__f2f(-2.562915447f); \ - p3 = p3*stbi__f2f(-1.961570560f); \ - p4 = p4*stbi__f2f(-0.390180644f); \ + p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ + t0 = t0*stbi__f2f( 0.298631336f); \ + t1 = t1*stbi__f2f( 2.053119869f); \ + t2 = t2*stbi__f2f( 3.072711026f); \ + t3 = t3*stbi__f2f( 1.501321110f); \ + p1 = p5 + p1*stbi__f2f(-0.899976223f); \ + p2 = p5 + p2*stbi__f2f(-2.562915447f); \ + p3 = p3*stbi__f2f(-1.961570560f); \ + p4 = p4*stbi__f2f(-0.390180644f); \ t3 += p1+p4; \ t2 += p2+p3; \ t1 += p2+p4; \ t0 += p1+p3; -// .344 seconds on 3*anemones.jpg static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) { int i,val[64],*v=val; @@ -1725,6 +1909,7 @@ static void stbi__jpeg_reset(stbi__jpeg *j) j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = 0; j->marker = STBI__MARKER_none; j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; + j->eob_run = 0; // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, // since we don't even allow 1<<30 pixels } @@ -1732,66 +1917,161 @@ static void stbi__jpeg_reset(stbi__jpeg *j) static int stbi__parse_entropy_coded_data(stbi__jpeg *z) { stbi__jpeg_reset(z); - if (z->scan_n == 1) { - int i,j; - STBI_SIMD_ALIGN(short, data[64]); - int n = z->order[0]; - // non-interleaved data, we just need to process one block at a time, - // in trivial scanline order - // number of blocks to do just depends on how many actual "pixels" this - // component has, independent of interleaved MCU blocking and such - int w = (z->img_comp[n].x+7) >> 3; - int h = (z->img_comp[n].y+7) >> 3; - for (j=0; j < h; ++j) { - for (i=0; i < w; ++i) { - int ha = z->img_comp[n].ha; - if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; - z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); - // every data block is an MCU, so countdown the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - // if it's NOT a restart, then just bail, so we get corrupt data - // rather than no data - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); - } - } - } - } else { // interleaved! - int i,j,k,x,y; - STBI_SIMD_ALIGN(short, data[64]); - for (j=0; j < z->img_mcu_y; ++j) { - for (i=0; i < z->img_mcu_x; ++i) { - // scan an interleaved mcu... process scan_n components in order - for (k=0; k < z->scan_n; ++k) { - int n = z->order[k]; - // scan out an mcu's worth of this component; that's just determined - // by the basic H and V specified for the component - for (y=0; y < z->img_comp[n].v; ++y) { - for (x=0; x < z->img_comp[n].h; ++x) { - int x2 = (i*z->img_comp[n].h + x)*8; - int y2 = (j*z->img_comp[n].v + y)*8; - int ha = z->img_comp[n].ha; - if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; - z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); - } + if (!z->progressive) { + if (z->scan_n == 1) { + int i,j; + STBI_SIMD_ALIGN(short, data[64]); + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); } } - // after all interleaved components, that's an interleaved MCU, - // so now count down the restart interval - if (--z->todo <= 0) { - if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); - // if it's NOT a restart, then just bail, so we get corrupt data - // rather than no data - if (!STBI__RESTART(z->marker)) return 1; - stbi__jpeg_reset(z); + } + return 1; + } else { // interleaved! + int i,j,k,x,y; + STBI_SIMD_ALIGN(short, data[64]); + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x)*8; + int y2 = (j*z->img_comp[n].v + y)*8; + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + //z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } else { + if (z->scan_n == 1) { + int i,j; + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + int ha = z->img_comp[n].ha; + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + if (z->spec_start == 0) { + if (!stbi__jpeg_decode_block_prog_dc(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) + return 0; + } else { + if (!stbi__jpeg_decode_block_prog_ac(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) + return 0; + } + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved! + int i,j,k,x,y; + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x); + int y2 = (j*z->img_comp[n].v + y); + int ha = z->img_comp[n].ha; + short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); + if (!stbi__jpeg_decode_block_prog_dc(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) + return 0; + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } +} + +static void stbi__jpeg_dequantize(short *data, stbi_uc *dequant) +{ + int i; + for (i=0; i < 64; ++i) + data[i] *= dequant[i]; +} + +static void stbi__jpeg_finish(stbi__jpeg *z) +{ + if (z->progressive) { + // dequantize and idct the data + int i,j,n; + for (n=0; n < z->s->img_n; ++n) { + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); } } } } - return 1; } + static int stbi__process_marker(stbi__jpeg *z, int m) { int L; @@ -1799,9 +2079,6 @@ static int stbi__process_marker(stbi__jpeg *z, int m) case STBI__MARKER_none: // no marker found return stbi__err("expected marker","Corrupt JPEG"); - case 0xC2: // stbi__SOF - progressive - return stbi__err("progressive jpeg","JPEG format not supported (progressive)"); - case 0xDD: // DRI - specify restart interval if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); z->restart_interval = stbi__get16be(z->s); @@ -1858,28 +2135,42 @@ static int stbi__process_marker(stbi__jpeg *z, int m) return 0; } -// after we see stbi__SOS +// after we see SOS static int stbi__process_scan_header(stbi__jpeg *z) { int i; int Ls = stbi__get16be(z->s); z->scan_n = stbi__get8(z->s); - if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad stbi__SOS component count","Corrupt JPEG"); - if (Ls != 6+2*z->scan_n) return stbi__err("bad stbi__SOS len","Corrupt JPEG"); + if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); + if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); for (i=0; i < z->scan_n; ++i) { int id = stbi__get8(z->s), which; int q = stbi__get8(z->s); for (which = 0; which < z->s->img_n; ++which) if (z->img_comp[which].id == id) break; - if (which == z->s->img_n) return 0; + if (which == z->s->img_n) return 0; // no match z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); z->order[i] = which; } - if (stbi__get8(z->s) != 0) return stbi__err("bad stbi__SOS","Corrupt JPEG"); - stbi__get8(z->s); // should be 63, but might be 0 - if (stbi__get8(z->s) != 0) return stbi__err("bad stbi__SOS","Corrupt JPEG"); + + { + int aa; + z->spec_start = stbi__get8(z->s); + z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 + aa = stbi__get8(z->s); + z->succ_high = (aa >> 4); + z->succ_low = (aa & 15); + if (z->progressive) { + if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) + return stbi__err("bad SOS", "Corrupt JPEG"); + } else { + if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); + if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); + z->spec_end = 63; + } + } return 1; } @@ -1888,8 +2179,8 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) { stbi__context *s = z->s; int Lf,p,i,q, h_max=1,v_max=1,c; - Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad stbi__SOF len","Corrupt JPEG"); // JPEG - p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline + Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG + p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires c = stbi__get8(s); @@ -1900,7 +2191,7 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) z->img_comp[i].linebuf = NULL; } - if (Lf != 8+3*s->img_n) return stbi__err("bad stbi__SOF len","Corrupt JPEG"); + if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); for (i=0; i < s->img_n; ++i) { z->img_comp[i].id = stbi__get8(s); @@ -1941,6 +2232,7 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; z->img_comp[i].raw_data = stbi__malloc(z->img_comp[i].w2 * z->img_comp[i].h2+15); + if (z->img_comp[i].raw_data == NULL) { for(--i; i >= 0; --i) { STBI_FREE(z->img_comp[i].raw_data); @@ -1948,27 +2240,38 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) } return stbi__err("outofmem", "Out of memory"); } - // align blocks for installable-idct using mmx/sse + // align blocks for idct using mmx/sse z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); z->img_comp[i].linebuf = NULL; + if (z->progressive) { + z->img_comp[i].coeff_w = (z->img_comp[i].w2 + 7) >> 3; + z->img_comp[i].coeff_h = (z->img_comp[i].h2 + 7) >> 3; + z->img_comp[i].raw_coeff = malloc(z->img_comp[i].coeff_w * z->img_comp[i].coeff_h * 64 * sizeof(short) + 15); + z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); + } else { + z->img_comp[i].coeff = 0; + z->img_comp[i].raw_coeff = 0; + } } return 1; } -// use comparisons since in some cases we handle more than one case (e.g. stbi__SOF) +// use comparisons since in some cases we handle more than one case (e.g. SOF) #define stbi__DNL(x) ((x) == 0xdc) #define stbi__SOI(x) ((x) == 0xd8) #define stbi__EOI(x) ((x) == 0xd9) -#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1) +#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) #define stbi__SOS(x) ((x) == 0xda) +#define stbi__SOF_progressive(x) ((x) == 0xc2) + static int decode_jpeg_header(stbi__jpeg *z, int scan) { int m; z->marker = STBI__MARKER_none; // initialize cached marker to empty m = stbi__get_marker(z); - if (!stbi__SOI(m)) return stbi__err("no stbi__SOI","Corrupt JPEG"); + if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); if (scan == SCAN_type) return 1; m = stbi__get_marker(z); while (!stbi__SOF(m)) { @@ -1976,14 +2279,16 @@ static int decode_jpeg_header(stbi__jpeg *z, int scan) m = stbi__get_marker(z); while (m == STBI__MARKER_none) { // some files have extra padding after their blocks, so ok, we'll scan - if (stbi__at_eof(z->s)) return stbi__err("no stbi__SOF", "Corrupt JPEG"); + if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); m = stbi__get_marker(z); } } + z->progressive = stbi__SOF_progressive(m); if (!stbi__process_frame_header(z, scan)) return 0; return 1; } +// decode image to YCbCr format static int decode_jpeg_image(stbi__jpeg *j) { int m; @@ -2002,7 +2307,7 @@ static int decode_jpeg_image(stbi__jpeg *j) j->marker = stbi__get8(j->s); break; } else if (x != 0) { - return 0; + return stbi__err("junk before marker", "Corrupt JPEG"); } } // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 @@ -2012,6 +2317,8 @@ static int decode_jpeg_image(stbi__jpeg *j) } m = stbi__get_marker(j); } + if (j->progressive) + stbi__jpeg_finish(j); return 1; } @@ -2362,6 +2669,11 @@ static void stbi__cleanup_jpeg(stbi__jpeg *j) j->img_comp[i].raw_data = NULL; j->img_comp[i].data = NULL; } + if (j->img_comp[i].raw_coeff) { + STBI_FREE(j->img_comp[i].raw_coeff); + j->img_comp[i].raw_coeff = 0; + j->img_comp[i].coeff = 0; + } if (j->img_comp[i].linebuf) { STBI_FREE(j->img_comp[i].linebuf); j->img_comp[i].linebuf = NULL; @@ -2387,7 +2699,7 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp // validate req_comp if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); - // load a jpeg image from whichever source + // load a jpeg image from whichever source, but leave in YCbCr format if (!decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } // determine actual number of components to generate diff --git a/tests/image_test.c b/tests/image_test.c index 8f35150..e15049a 100644 --- a/tests/image_test.c +++ b/tests/image_test.c @@ -7,7 +7,7 @@ #define STB_DEFINE #include "stb.h" -#define PNGSUITE_PRIMARY +//#define PNGSUITE_PRIMARY #if 0 void test_ycbcr(void) @@ -52,10 +52,10 @@ int main(int argc, char **argv) int w,h; //test_ycbcr(); if (argc > 1) { - int i; + int i, n; + for (i=1; i < argc; ++i) { unsigned char *data; - int n; printf("%s\n", argv[i]); data = stbi_load(argv[i], &w, &h, &n, 4); if (data) free(data); else printf("Failed &n\n"); data = stbi_load(argv[i], &w, &h, 0, 1); if (data) free(data); else printf("Failed 1\n"); From 49d4d3193f54525b177d75d62560c6cf4b7302a7 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Sun, 21 Dec 2014 08:21:17 -0800 Subject: [PATCH 08/11] fix non-progressive jpegs (had commented out a line accidentally); fix long-standing bug where gifs were just broken AFAICT --- stb_image.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/stb_image.h b/stb_image.h index 3ece66b..fdb554d 100644 --- a/stb_image.h +++ b/stb_image.h @@ -652,7 +652,6 @@ STBIDEF const char *stbi_failure_reason(void) static int stbi__err(const char *str) { - fclose(stdout); stbi__g_failure_reason = str; return 0; } @@ -1960,7 +1959,7 @@ static int stbi__parse_entropy_coded_data(stbi__jpeg *z) int y2 = (j*z->img_comp[n].v + y)*8; int ha = z->img_comp[n].ha; if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; - //z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); } } } @@ -4861,7 +4860,7 @@ static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], in pal[i][2] = stbi__get8(s); pal[i][1] = stbi__get8(s); pal[i][0] = stbi__get8(s); - pal[i][3] = transp ? 0 : 255; + pal[i][3] = transp == i ? 0 : 255; } } From 53008c0922f17026ed65ac7b1cf569b78e24dca5 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Sun, 21 Dec 2014 08:25:13 -0800 Subject: [PATCH 09/11] default tests --- tests/image_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/image_test.c b/tests/image_test.c index e15049a..5cf3d54 100644 --- a/tests/image_test.c +++ b/tests/image_test.c @@ -7,7 +7,7 @@ #define STB_DEFINE #include "stb.h" -//#define PNGSUITE_PRIMARY +#define PNGSUITE_PRIMARY #if 0 void test_ycbcr(void) From 6403f319f79fef0e9eccbcc079e7dfb4416fe02c Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Sun, 21 Dec 2014 08:30:27 -0800 Subject: [PATCH 10/11] tweak documentation stbi__ prefix on two functions that were missing it --- stb_image.h | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/stb_image.h b/stb_image.h index 9b0c5b5..db43022 100644 --- a/stb_image.h +++ b/stb_image.h @@ -33,17 +33,18 @@ Full documentation under "DOCUMENTATION" below. - Revision 1.49 release notes: + Revision 2.00 release notes: - - The old STBI_SIMD system which allowed installing a user-defined - IDCT etc. has been removed. If you need this, don't upgrade. My - assumption is that almost nobody was doing this, and those who - were will find the next bullet item more satisfactory anyway. + - Progressive JPEG is now supported. + + - PPM and PGM binary formats are now supported. - x86 platforms now make use of SSE2 SIMD instructions if available. This release is 2x faster on our test JPEGs, mostly due to SIMD. This work was done by Fabian "ryg" Giesen. + - ARM platforms now make use of NEON SIMD instructions if available. + - Compilation of SIMD code can be suppressed with #define STBI_NO_SIMD It should not be necessary to disable it unless you have issues @@ -53,6 +54,11 @@ bugs so I can refine the built-in compile-time checking to be smarter. + - The old STBI_SIMD system which allowed installing a user-defined + IDCT etc. has been removed. If you need this, don't upgrade. My + assumption is that almost nobody was doing this, and those who + were will find the next bullet item more satisfactory anyway. + - RGB values computed for JPEG images are slightly different from previous versions of stb_image. (This is due to using less integer precision in SIMD.) The C code has been adjusted so @@ -73,8 +79,6 @@ removed in future versions of the library. It is only intended for back-compatibility use. - - Added support for PNM images. - - Added STBI_MALLOC, STBI_REALLOC, and STBI_FREE macros for replacing the memory allocator. Unlike other STBI libraries, these macros don't support a context parameter, so if you need to pass a context in to @@ -83,9 +87,11 @@ Latest revision history: - 1.49 (2014-12-25) optimize JPG, incl. x86 SIMD + 2.00 (2014-12-25) optimize JPG, incl. x86 & NEON SIMD + progressive JPEG PGM/PPM support STBI_MALLOC,STBI_REALLOC,STBI_FREE + GIF bugfix 1.48 (2014-12-14) fix incorrectly-named assert() 1.47 (2014-12-14) 1/2/4-bit PNG support (both grayscale and paletted) optimize PNG @@ -2280,7 +2286,7 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) #define stbi__SOF_progressive(x) ((x) == 0xc2) -static int decode_jpeg_header(stbi__jpeg *z, int scan) +static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) { int m; z->marker = STBI__MARKER_none; // initialize cached marker to empty @@ -2303,11 +2309,11 @@ static int decode_jpeg_header(stbi__jpeg *z, int scan) } // decode image to YCbCr format -static int decode_jpeg_image(stbi__jpeg *j) +static int stbi__decode_jpeg_image(stbi__jpeg *j) { int m; j->restart_interval = 0; - if (!decode_jpeg_header(j, SCAN_load)) return 0; + if (!stbi__decode_jpeg_header(j, SCAN_load)) return 0; m = stbi__get_marker(j); while (!stbi__EOI(m)) { if (stbi__SOS(m)) { @@ -2714,7 +2720,7 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); // load a jpeg image from whichever source, but leave in YCbCr format - if (!decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } + if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } // determine actual number of components to generate n = req_comp ? req_comp : z->s->img_n; @@ -2816,14 +2822,14 @@ static int stbi__jpeg_test(stbi__context *s) stbi__jpeg j; j.s = s; stbi__setup_jpeg(&j); - r = decode_jpeg_header(&j, SCAN_type); + r = stbi__decode_jpeg_header(&j, SCAN_type); stbi__rewind(s); return r; } static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) { - if (!decode_jpeg_header(j, SCAN_header)) { + if (!stbi__decode_jpeg_header(j, SCAN_header)) { stbi__rewind( j->s ); return 0; } @@ -5668,10 +5674,11 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int /* revision history: - 1.49 (2014-12-25) optimize JPG, incl. x86 SIMD (ryg) + 2.00 (2014-12-25) optimize JPG, incl. x86 & NEON SIMD (ryg) + progressive JPEG (stb) PGM/PPM support (Ken Miller) STBI_MALLOC,STBI_REALLOC,STBI_FREE - stbi_load_into() -- load into pre-defined memory + GIF bugfix -- seemingly never worked 1.48 (2014-12-14) fix incorrectly-named assert() 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) optimize PNG (ryg) From 16d9ed721161338f0f701d044fbdb0efcc600f56 Mon Sep 17 00:00:00 2001 From: Sean Barrett Date: Sun, 21 Dec 2014 08:32:09 -0800 Subject: [PATCH 11/11] return truetype test code to old path --- tests/test_truetype.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_truetype.c b/tests/test_truetype.c index c151533..1ace8b2 100644 --- a/tests/test_truetype.c +++ b/tests/test_truetype.c @@ -35,6 +35,7 @@ int main(int argc, char **argv) // @TODO: why is minglui.ttc failing? fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : "c:/windows/fonts/mingliu.ttc", "rb")); +#if 0 stbtt_BakeFontBitmap(ttf_buffer,stbtt_GetFontOffsetForIndex(ttf_buffer,0), 40.0, temp_bitmap[0],BITMAP_W,BITMAP_H, 32,96, cdata); // no guarantee this fits! stbi_write_png("fonttest1.png", BITMAP_W, BITMAP_H, 1, temp_bitmap, 0); @@ -67,6 +68,7 @@ int main(int argc, char **argv) stbi_write_png("fonttest3.png", BITMAP_W, BITMAP_H, 1, temp_bitmap, 0); } return 0; +#endif stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0)); bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, (float)s), c, &w, &h, 0,0);