summaryrefslogtreecommitdiff
path: root/ThirdParty/stb/stb_image.h
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2021-10-25 23:29:21 +0800
committerchai <chaifix@163.com>2021-10-25 23:29:21 +0800
commit7ecf913256fb396e3027aac3318d996a716a52ef (patch)
tree4540835c881a63b665e2a692bf30115fd29e8bb0 /ThirdParty/stb/stb_image.h
parent0816cd70ca1a213b6ed872bcf3c0bf0912473722 (diff)
+ job system
Diffstat (limited to 'ThirdParty/stb/stb_image.h')
-rw-r--r--ThirdParty/stb/stb_image.h1461
1 files changed, 1091 insertions, 370 deletions
diff --git a/ThirdParty/stb/stb_image.h b/ThirdParty/stb/stb_image.h
index 4df317a..d60371b 100644
--- a/ThirdParty/stb/stb_image.h
+++ b/ThirdParty/stb/stb_image.h
@@ -1,5 +1,5 @@
-/* stb_image - v2.15 - public domain image loader - http://nothings.org/stb_image.h
- no warranty implied; use at your own risk
+/* stb_image - v2.27 - public domain image loader - http://nothings.org/stb
+ no warranty implied; use at your own risk
Do this:
#define STB_IMAGE_IMPLEMENTATION
@@ -22,7 +22,7 @@
JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib)
PNG 1/2/4/8/16-bit-per-channel
-
+
TGA (not sure what subset, if a subset)
BMP non-1bpp, non-RLE
PSD (composited view only, no extra channels, 8/16 bit-per-channel)
@@ -48,6 +48,18 @@ LICENSE
RECENT REVISION HISTORY:
+ 2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes
+ 2.26 (2020-07-13) many minor fixes
+ 2.25 (2020-02-02) fix warnings
+ 2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically
+ 2.23 (2019-08-11) fix clang static analysis warning
+ 2.22 (2019-03-04) gif fixes, fix warnings
+ 2.21 (2019-02-25) fix typo in comment
+ 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs
+ 2.19 (2018-02-11) fix warning
+ 2.18 (2018-01-30) fix warnings
+ 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings
+ 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes
2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC
2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs
2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes
@@ -58,10 +70,6 @@ RECENT REVISION HISTORY:
correct channel count for PNG & BMP
2.10 (2016-01-22) avoid warning introduced in 2.09
2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED
- 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA
- 2.07 (2015-09-13) partial animated GIF support
- limited 16-bit PSD support
- minor bugs, code cleanup, and compiler warnings
See end of file for full revision history.
@@ -77,39 +85,52 @@ RECENT REVISION HISTORY:
Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip)
Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD)
github:urraka (animated gif) Junggon Kim (PNM comments)
- Daniel Gibson (16-bit TGA)
+ Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA)
socks-the-fox (16-bit PNG)
- Jeremy Sawicki (handle all ImageNetManager JPGs)
- Optimizations & bugfixes
- Fabian "ryg" Giesen
- Arseny Kapoulkine
+ Jeremy Sawicki (handle all ImageNet JPGs)
+ Optimizations & bugfixes Mikhail Morozov (1-bit BMP)
+ Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query)
+ Arseny Kapoulkine Simon Breuss (16-bit PNM)
+ John-Mark Allen
+ Carmelo J Fdez-Aguera
Bug & warning fixes
- Marc LeBlanc David Woo Guillaume George Martins Mozeiko
- Christpher Lloyd Jerry Jansson Joseph Thomson Phil Jordan
- Dave Moore Roy Eltham Hayaki Saito Nathan Reed
- Won Chun Luke Graham Johan Duparc Nick Verigakis
- the Horde3D community Thomas Ruf Ronny Chevalier Baldur Karlsson
- Janez Zemva John Bartholomew Michal Cichon github:rlyeh
- Jonathan Blow Ken Hamada Tero Hanninen github:romigrou
- Laurent Gomila Cort Stratton Sergio Gonzalez github:svdijk
- Aruelien Pocheville Thibault Reuille Cass Everitt github:snagar
- Ryamond Barbiero Paul Du Bois Engin Manap github:Zelex
- Michaelangel007@github Philipp Wiesemann Dale Weiler github:grim210
- Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:sammyhw
- Blazej Dariusz Roszkowski Gregory Mullen github:phprus
-
+ Marc LeBlanc David Woo Guillaume George Martins Mozeiko
+ Christpher Lloyd Jerry Jansson Joseph Thomson Blazej Dariusz Roszkowski
+ Phil Jordan Dave Moore Roy Eltham
+ Hayaki Saito Nathan Reed Won Chun
+ Luke Graham Johan Duparc Nick Verigakis the Horde3D community
+ Thomas Ruf Ronny Chevalier github:rlyeh
+ Janez Zemva John Bartholomew Michal Cichon github:romigrou
+ Jonathan Blow Ken Hamada Tero Hanninen github:svdijk
+ Eugene Golushkov Laurent Gomila Cort Stratton github:snagar
+ Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex
+ Cass Everitt Ryamond Barbiero github:grim210
+ Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw
+ Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus
+ Josh Tobin Matthew Gregan github:poppolopoppo
+ Julian Raschke Gregory Mullen Christian Floisand github:darealshinji
+ Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007
+ Brad Weinberger Matvey Cherevko github:mosra
+ Luca Sas Alexander Veselov Zack Middleton [reserved]
+ Ryan C. Gordon [reserved] [reserved]
+ DO NOT ADD YOUR NAME HERE
+
+ Jacko Dirks
+
+ To add your name to the credits, pick a random blank space in the middle and fill it.
+ 80% of merge conflicts on stb PRs are due to people adding their name at the end
+ of the credits.
*/
+
#ifndef STBI_INCLUDE_STB_IMAGE_H
#define STBI_INCLUDE_STB_IMAGE_H
// DOCUMENTATION
//
// Limitations:
-// - no 16-bit-per-channel PNG
// - no 12-bit-per-channel JPEG
// - no JPEGs with arithmetic coding
-// - no 1-bit BMP
// - GIF always returns *comp=4
//
// Basic usage (see HDR discussion below for HDR usage):
@@ -133,11 +154,12 @@ RECENT REVISION HISTORY:
// 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 see if it's trivially opaque
-// because e.g. there were only 3 channels in the source image.
+// components N is 'desired_channels' if desired_channels is non-zero, or
+// *channels_in_file otherwise. If desired_channels is non-zero,
+// *channels_in_file has the number of components that _would_ have been
+// output otherwise. E.g. if you set desired_channels to 4, you will always
+// get RGBA output, but you can check *channels_in_file 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:
@@ -149,14 +171,50 @@ RECENT REVISION HISTORY:
// 4 red, green, blue, alpha
//
// If image loading fails for any reason, the return value will be NULL,
-// and *x, *y, *comp will be unchanged. The function stbi_failure_reason()
-// can be queried for an extremely brief, end-user unfriendly explanation
-// of why the load failed. Define STBI_NO_FAILURE_STRINGS to avoid
-// compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly
+// and *x, *y, *channels_in_file will be unchanged. The function
+// stbi_failure_reason() can be queried for an extremely brief, end-user
+// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS
+// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly
// more user-friendly ones.
//
// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized.
//
+// To query the width, height and component count of an image without having to
+// decode the full file, you can use the stbi_info family of functions:
+//
+// int x,y,n,ok;
+// ok = stbi_info(filename, &x, &y, &n);
+// // returns ok=1 and sets x, y, n if image is a supported format,
+// // 0 otherwise.
+//
+// Note that stb_image pervasively uses ints in its public API for sizes,
+// including sizes of memory buffers. This is now part of the API and thus
+// hard to change without causing breakage. As a result, the various image
+// loaders all have certain limits on image size; these differ somewhat
+// by format but generally boil down to either just under 2GB or just under
+// 1GB. When the decoded image would be larger than this, stb_image decoding
+// will fail.
+//
+// Additionally, stb_image will reject image files that have any of their
+// dimensions set to a larger value than the configurable STBI_MAX_DIMENSIONS,
+// which defaults to 2**24 = 16777216 pixels. Due to the above memory limit,
+// the only way to have an image with such dimensions load correctly
+// is for it to have a rather extreme aspect ratio. Either way, the
+// assumption here is that such larger images are likely to be malformed
+// or malicious. If you do need to load an image with individual dimensions
+// larger than that, and it still fits in the overall size limit, you can
+// #define STBI_MAX_DIMENSIONS on your own to be something larger.
+//
+// ===========================================================================
+//
+// UNICODE:
+//
+// If compiling for Windows and you wish to use Unicode filenames, compile
+// with
+// #define STBI_WINDOWS_UTF8
+// and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert
+// Windows wchar_t filenames to utf8.
+//
// ===========================================================================
//
// Philosophy
@@ -169,12 +227,12 @@ RECENT REVISION HISTORY:
//
// Sometimes I let "good performance" creep up in priority over "easy to maintain",
// and for best performance I may provide less-easy-to-use APIs that give higher
-// performance, in addition to the easy to use ones. Nevertheless, it's important
+// performance, in addition to the easy-to-use ones. Nevertheless, it's important
// to keep in mind that from the standpoint of you, a client of this library,
// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all.
//
// Some secondary priorities arise directly from the first two, some of which
-// make more explicit reasons why performance can't be emphasized.
+// provide more explicit reasons why performance can't be emphasized.
//
// - Portable ("ease of use")
// - Small source code footprint ("easy to maintain")
@@ -217,11 +275,10 @@ RECENT REVISION HISTORY:
//
// HDR image support (disable by defining STBI_NO_HDR)
//
-// stb_image now supports loading HDR images in general, and currently
-// the Radiance .HDR file format, although the support is provided
-// generically. You can still load any file through the existing interface;
-// if you attempt to load an HDR file, it will be automatically remapped to
-// LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1;
+// stb_image supports loading HDR images in general, and currently the Radiance
+// .HDR file format specifically. You can still load any file through the existing
+// interface; if you attempt to load an HDR file, it will be automatically remapped
+// to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1;
// both of these constants can be reconfigured through this interface:
//
// stbi_hdr_to_ldr_gamma(2.2f);
@@ -253,11 +310,10 @@ RECENT REVISION HISTORY:
//
// iPhone PNG support:
//
-// 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).
+// We optionally support converting iPhone-formatted PNGs (which store
+// premultiplied BGRA) back to RGB, even though they're internally encoded
+// differently. To enable this conversion, call
+// stbi_convert_iphone_png_to_rgb(1).
//
// 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
@@ -299,7 +355,14 @@ RECENT REVISION HISTORY:
// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still
// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB
//
-
+// - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater
+// than that size (in either width or height) without further processing.
+// This is to let programs in the wild set an upper bound to prevent
+// denial-of-service attacks on untrusted data, as one could generate a
+// valid image of gigantic dimensions and force stb_image to allocate a
+// huge block of memory and spend disproportionate time decoding it. By
+// default this is set to (1 << 24), which is 16777216, but that's still
+// very big.
#ifndef STBI_NO_STDIO
#include <stdio.h>
@@ -309,7 +372,7 @@ RECENT REVISION HISTORY:
enum
{
- STBI_default = 0, // only used for req_comp
+ STBI_default = 0, // only used for desired_channels
STBI_grey = 1,
STBI_grey_alpha = 2,
@@ -317,6 +380,7 @@ enum
STBI_rgb_alpha = 4
};
+#include <stdlib.h>
typedef unsigned char stbi_uc;
typedef unsigned short stbi_us;
@@ -324,11 +388,13 @@ typedef unsigned short stbi_us;
extern "C" {
#endif
+#ifndef STBIDEF
#ifdef STB_IMAGE_STATIC
#define STBIDEF static
#else
#define STBIDEF extern
#endif
+#endif
//////////////////////////////////////////////////////////////////////////////
//
@@ -351,36 +417,46 @@ typedef struct
// 8-bits-per-channel interface
//
-STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels);
STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels);
#ifndef STBI_NO_STDIO
-STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
+STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
+STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
// for stbi_load_from_file, file pointer is left pointing immediately after image
#endif
+#ifndef STBI_NO_GIF
+STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp);
+#endif
+
+#ifdef STBI_WINDOWS_UTF8
+STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);
+#endif
+
////////////////////////////////////
//
// 16-bits-per-channel interface
//
-STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
+STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);
+STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels);
+
#ifndef STBI_NO_STDIO
+STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
#endif
-// @TODO the other variants
////////////////////////////////////
//
// float-per-channel interface
//
#ifndef STBI_NO_LINEAR
- STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);
STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels);
#ifndef STBI_NO_STDIO
+ STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
#endif
#endif
@@ -405,7 +481,7 @@ STBIDEF int stbi_is_hdr_from_file(FILE *f);
// get a VERY brief reason for failure
-// NOT THREADSAFE
+// on most compilers (and ALL modern mainstream compilers) this is threadsafe
STBIDEF const char *stbi_failure_reason (void);
// free the loaded image -- this is just free()
@@ -414,11 +490,14 @@ STBIDEF void stbi_image_free (void *retval_from_stbi_load);
// get image dimensions & components without fully decoding
STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);
STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);
+STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len);
+STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user);
#ifndef STBI_NO_STDIO
-STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp);
-STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp);
-
+STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp);
+STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp);
+STBIDEF int stbi_is_16_bit (char const *filename);
+STBIDEF int stbi_is_16_bit_from_file(FILE *f);
#endif
@@ -435,6 +514,13 @@ STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert);
// flip the image vertically, so the first pixel in the output array is the bottom left
STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip);
+// as above, but only applies to images loaded on the thread that calls the function
+// this function is only available if your compiler supports thread-local variables;
+// calling it will fail to link if your compiler doesn't
+STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply);
+STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert);
+STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip);
+
// ZLIB client - used by PNG, available for other purposes
STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen);
@@ -502,7 +588,7 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch
#include <limits.h>
#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
-#include <math.h> // ldexp
+#include <math.h> // ldexp, pow
#endif
#ifndef STBI_NO_STDIO
@@ -514,6 +600,12 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch
#define STBI_ASSERT(x) assert(x)
#endif
+#ifdef __cplusplus
+#define STBI_EXTERN extern "C"
+#else
+#define STBI_EXTERN extern
+#endif
+
#ifndef _MSC_VER
#ifdef __cplusplus
@@ -525,6 +617,23 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch
#define stbi_inline __forceinline
#endif
+#ifndef STBI_NO_THREAD_LOCALS
+ #if defined(__cplusplus) && __cplusplus >= 201103L
+ #define STBI_THREAD_LOCAL thread_local
+ #elif defined(__GNUC__) && __GNUC__ < 5
+ #define STBI_THREAD_LOCAL __thread
+ #elif defined(_MSC_VER)
+ #define STBI_THREAD_LOCAL __declspec(thread)
+ #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__)
+ #define STBI_THREAD_LOCAL _Thread_local
+ #endif
+
+ #ifndef STBI_THREAD_LOCAL
+ #if defined(__GNUC__)
+ #define STBI_THREAD_LOCAL __thread
+ #endif
+ #endif
+#endif
#ifdef _MSC_VER
typedef unsigned short stbi__uint16;
@@ -555,7 +664,7 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];
#ifdef STBI_HAS_LROTL
#define stbi_lrot(x,y) _lrotl(x,y)
#else
- #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y))))
+ #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (-(y) & 31)))
#endif
#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED))
@@ -638,15 +747,19 @@ static int stbi__cpuid3(void)
#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name
-static int stbi__sse2_available()
+#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2)
+static int stbi__sse2_available(void)
{
int info3 = stbi__cpuid3();
return ((info3 >> 26) & 1) != 0;
}
+#endif
+
#else // assume GCC-style if not VC++
#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
-static int stbi__sse2_available()
+#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2)
+static int stbi__sse2_available(void)
{
// If we're even attempting to compile this on GCC/Clang, that means
// -msse2 is on, which means the compiler is allowed to use SSE2
@@ -654,6 +767,8 @@ static int stbi__sse2_available()
return 1;
}
#endif
+
+#endif
#endif
// ARM NEON
@@ -663,14 +778,21 @@ static int stbi__sse2_available()
#ifdef STBI_NEON
#include <arm_neon.h>
-// assume GCC or Clang on ARM targets
+#ifdef _MSC_VER
+#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name
+#else
#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
#endif
+#endif
#ifndef STBI_SIMD_ALIGN
#define STBI_SIMD_ALIGN(type, name) type name
#endif
+#ifndef STBI_MAX_DIMENSIONS
+#define STBI_MAX_DIMENSIONS (1 << 24)
+#endif
+
///////////////////////////////////////////////
//
// stbi__context struct and start_xxx functions
@@ -688,6 +810,7 @@ typedef struct
int read_from_callbacks;
int buflen;
stbi_uc buffer_start[128];
+ int callback_already_read;
stbi_uc *img_buffer, *img_buffer_end;
stbi_uc *img_buffer_original, *img_buffer_original_end;
@@ -701,6 +824,7 @@ static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len)
{
s->io.read = NULL;
s->read_from_callbacks = 0;
+ s->callback_already_read = 0;
s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer;
s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len;
}
@@ -712,7 +836,8 @@ static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *
s->io_user_data = user;
s->buflen = sizeof(s->buffer_start);
s->read_from_callbacks = 1;
- s->img_buffer_original = s->buffer_start;
+ s->callback_already_read = 0;
+ s->img_buffer = s->img_buffer_original = s->buffer_start;
stbi__refill_buffer(s);
s->img_buffer_original_end = s->img_buffer_end;
}
@@ -726,12 +851,17 @@ static int stbi__stdio_read(void *user, char *data, int size)
static void stbi__stdio_skip(void *user, int n)
{
+ int ch;
fseek((FILE*) user, n, SEEK_CUR);
+ ch = fgetc((FILE*) user); /* have to read a byte to reset feof()'s flag */
+ if (ch != EOF) {
+ ungetc(ch, (FILE *) user); /* push byte back onto stream if valid. */
+ }
}
static int stbi__stdio_eof(void *user)
{
- return feof((FILE*) user);
+ return feof((FILE*) user) || ferror((FILE *) user);
}
static stbi_io_callbacks stbi__stdio_callbacks =
@@ -782,6 +912,7 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp);
static int stbi__png_test(stbi__context *s);
static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp);
+static int stbi__png_is16(stbi__context *s);
#endif
#ifndef STBI_NO_BMP
@@ -800,6 +931,7 @@ static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp);
static int stbi__psd_test(stbi__context *s);
static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc);
static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp);
+static int stbi__psd_is16(stbi__context *s);
#endif
#ifndef STBI_NO_HDR
@@ -817,6 +949,7 @@ static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp);
#ifndef STBI_NO_GIF
static int stbi__gif_test(stbi__context *s);
static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
+static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp);
static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp);
#endif
@@ -824,21 +957,27 @@ static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp);
static int stbi__pnm_test(stbi__context *s);
static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp);
+static int stbi__pnm_is16(stbi__context *s);
#endif
-// this is not threadsafe
-static const char *stbi__g_failure_reason;
+static
+#ifdef STBI_THREAD_LOCAL
+STBI_THREAD_LOCAL
+#endif
+const char *stbi__g_failure_reason;
STBIDEF const char *stbi_failure_reason(void)
{
return stbi__g_failure_reason;
}
+#ifndef STBI_NO_FAILURE_STRINGS
static int stbi__err(const char *str)
{
stbi__g_failure_reason = str;
return 0;
}
+#endif
static void *stbi__malloc(size_t size)
{
@@ -877,11 +1016,13 @@ static int stbi__mul2sizes_valid(int a, int b)
return a <= INT_MAX/b;
}
+#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR)
// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow
static int stbi__mad2sizes_valid(int a, int b, int add)
{
return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add);
}
+#endif
// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow
static int stbi__mad3sizes_valid(int a, int b, int c, int add)
@@ -891,18 +1032,22 @@ static int stbi__mad3sizes_valid(int a, int b, int c, int add)
}
// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow
+#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM)
static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add)
{
return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&
stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add);
}
+#endif
+#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR)
// mallocs with size overflow checking
static void *stbi__malloc_mad2(int a, int b, int add)
{
if (!stbi__mad2sizes_valid(a, b, add)) return NULL;
return stbi__malloc(a*b + add);
}
+#endif
static void *stbi__malloc_mad3(int a, int b, int c, int add)
{
@@ -910,11 +1055,13 @@ static void *stbi__malloc_mad3(int a, int b, int c, int add)
return stbi__malloc(a*b*c + add);
}
+#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM)
static void *stbi__malloc_mad4(int a, int b, int c, int d, int add)
{
if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL;
return stbi__malloc(a*b*c*d + add);
}
+#endif
// stbi__err - error
// stbi__errpf - error returning pointer to float
@@ -944,13 +1091,29 @@ static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp);
static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp);
#endif
-static int stbi__vertically_flip_on_load = 0;
+static int stbi__vertically_flip_on_load_global = 0;
STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip)
{
- stbi__vertically_flip_on_load = flag_true_if_should_flip;
+ stbi__vertically_flip_on_load_global = flag_true_if_should_flip;
+}
+
+#ifndef STBI_THREAD_LOCAL
+#define stbi__vertically_flip_on_load stbi__vertically_flip_on_load_global
+#else
+static STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set;
+
+STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip)
+{
+ stbi__vertically_flip_on_load_local = flag_true_if_should_flip;
+ stbi__vertically_flip_on_load_set = 1;
}
+#define stbi__vertically_flip_on_load (stbi__vertically_flip_on_load_set \
+ ? stbi__vertically_flip_on_load_local \
+ : stbi__vertically_flip_on_load_global)
+#endif // STBI_THREAD_LOCAL
+
static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc)
{
memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields
@@ -958,9 +1121,8 @@ static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int re
ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order
ri->num_channels = 0;
- #ifndef STBI_NO_JPEG
- if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri);
- #endif
+ // test the formats with a very explicit header first (at least a FOURCC
+ // or distinctive magic number first)
#ifndef STBI_NO_PNG
if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri);
#endif
@@ -972,10 +1134,19 @@ static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int re
#endif
#ifndef STBI_NO_PSD
if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc);
+ #else
+ STBI_NOTUSED(bpc);
#endif
#ifndef STBI_NO_PIC
if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri);
#endif
+
+ // then the formats that can end up attempting to load with just 1 or 2
+ // bytes matching expectations; these are prone to false positives, so
+ // try them later
+ #ifndef STBI_NO_JPEG
+ if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri);
+ #endif
#ifndef STBI_NO_PNM
if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri);
#endif
@@ -1028,6 +1199,44 @@ static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int chan
return enlarged;
}
+static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel)
+{
+ int row;
+ size_t bytes_per_row = (size_t)w * bytes_per_pixel;
+ stbi_uc temp[2048];
+ stbi_uc *bytes = (stbi_uc *)image;
+
+ for (row = 0; row < (h>>1); row++) {
+ stbi_uc *row0 = bytes + row*bytes_per_row;
+ stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row;
+ // swap row0 with row1
+ size_t bytes_left = bytes_per_row;
+ while (bytes_left) {
+ size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp);
+ memcpy(temp, row0, bytes_copy);
+ memcpy(row0, row1, bytes_copy);
+ memcpy(row1, temp, bytes_copy);
+ row0 += bytes_copy;
+ row1 += bytes_copy;
+ bytes_left -= bytes_copy;
+ }
+ }
+}
+
+#ifndef STBI_NO_GIF
+static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel)
+{
+ int slice;
+ int slice_size = w * h * bytes_per_pixel;
+
+ stbi_uc *bytes = (stbi_uc *)image;
+ for (slice = 0; slice < z; ++slice) {
+ stbi__vertical_flip(bytes, w, h, bytes_per_pixel);
+ bytes += slice_size;
+ }
+}
+#endif
+
static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)
{
stbi__result_info ri;
@@ -1036,8 +1245,10 @@ static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x,
if (result == NULL)
return NULL;
+ // it is the responsibility of the loaders to make sure we get either 8 or 16 bit.
+ STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16);
+
if (ri.bits_per_channel != 8) {
- STBI_ASSERT(ri.bits_per_channel == 16);
result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp);
ri.bits_per_channel = 8;
}
@@ -1045,21 +1256,8 @@ static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x,
// @TODO: move stbi__convert_format to here
if (stbi__vertically_flip_on_load) {
- int w = *x, h = *y;
int channels = req_comp ? req_comp : *comp;
- int row,col,z;
- stbi_uc *image = (stbi_uc *) result;
-
- // @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once
- for (row = 0; row < (h>>1); row++) {
- for (col = 0; col < w; col++) {
- for (z = 0; z < channels; z++) {
- stbi_uc temp = image[(row * w + col) * channels + z];
- image[(row * w + col) * channels + z] = image[((h - row - 1) * w + col) * channels + z];
- image[((h - row - 1) * w + col) * channels + z] = temp;
- }
- }
- }
+ stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc));
}
return (unsigned char *) result;
@@ -1073,8 +1271,10 @@ static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x,
if (result == NULL)
return NULL;
+ // it is the responsibility of the loaders to make sure we get either 8 or 16 bit.
+ STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16);
+
if (ri.bits_per_channel != 16) {
- STBI_ASSERT(ri.bits_per_channel == 8);
result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp);
ri.bits_per_channel = 16;
}
@@ -1083,55 +1283,57 @@ static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x,
// @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision
if (stbi__vertically_flip_on_load) {
- int w = *x, h = *y;
int channels = req_comp ? req_comp : *comp;
- int row,col,z;
- stbi__uint16 *image = (stbi__uint16 *) result;
-
- // @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once
- for (row = 0; row < (h>>1); row++) {
- for (col = 0; col < w; col++) {
- for (z = 0; z < channels; z++) {
- stbi__uint16 temp = image[(row * w + col) * channels + z];
- image[(row * w + col) * channels + z] = image[((h - row - 1) * w + col) * channels + z];
- image[((h - row - 1) * w + col) * channels + z] = temp;
- }
- }
- }
+ stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16));
}
return (stbi__uint16 *) result;
}
-#ifndef STBI_NO_HDR
+#if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR)
static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp)
{
if (stbi__vertically_flip_on_load && result != NULL) {
- int w = *x, h = *y;
- int depth = req_comp ? req_comp : *comp;
- int row,col,z;
- float temp;
-
- // @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once
- for (row = 0; row < (h>>1); row++) {
- for (col = 0; col < w; col++) {
- for (z = 0; z < depth; z++) {
- temp = result[(row * w + col) * depth + z];
- result[(row * w + col) * depth + z] = result[((h - row - 1) * w + col) * depth + z];
- result[((h - row - 1) * w + col) * depth + z] = temp;
- }
- }
- }
+ int channels = req_comp ? req_comp : *comp;
+ stbi__vertical_flip(result, *x, *y, channels * sizeof(float));
}
}
#endif
#ifndef STBI_NO_STDIO
+#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8)
+STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide);
+STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default);
+#endif
+
+#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8)
+STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input)
+{
+ return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL);
+}
+#endif
+
static FILE *stbi__fopen(char const *filename, char const *mode)
{
FILE *f;
+#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8)
+ wchar_t wMode[64];
+ wchar_t wFilename[1024];
+ if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename)))
+ return 0;
+
+ if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode)))
+ return 0;
+
#if defined(_MSC_VER) && _MSC_VER >= 1400
+ if (0 != _wfopen_s(&f, wFilename, wMode))
+ f = 0;
+#else
+ f = _wfopen(wFilename, wMode);
+#endif
+
+#elif defined(_MSC_VER) && _MSC_VER >= 1400
if (0 != fopen_s(&f, filename, mode))
f=0;
#else
@@ -1190,6 +1392,20 @@ STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, i
#endif //!STBI_NO_STDIO
+STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels)
+{
+ stbi__context s;
+ stbi__start_mem(&s,buffer,len);
+ return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels);
+}
+
+STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels)
+{
+ stbi__context s;
+ stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user);
+ return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels);
+}
+
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;
@@ -1204,6 +1420,22 @@ STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *u
return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
}
+#ifndef STBI_NO_GIF
+STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp)
+{
+ unsigned char *result;
+ stbi__context s;
+ stbi__start_mem(&s,buffer,len);
+
+ result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp);
+ if (stbi__vertically_flip_on_load) {
+ stbi__vertical_flip_slices( result, *x, *y, *z, *comp );
+ }
+
+ return result;
+}
+#endif
+
#ifndef STBI_NO_LINEAR
static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)
{
@@ -1287,12 +1519,16 @@ STBIDEF int stbi_is_hdr (char const *filename)
return result;
}
-STBIDEF int stbi_is_hdr_from_file(FILE *f)
+STBIDEF int stbi_is_hdr_from_file(FILE *f)
{
#ifndef STBI_NO_HDR
+ long pos = ftell(f);
+ int res;
stbi__context s;
stbi__start_file(&s,f);
- return stbi__hdr_test(&s);
+ res = stbi__hdr_test(&s);
+ fseek(f, pos, SEEK_SET);
+ return res;
#else
STBI_NOTUSED(f);
return 0;
@@ -1341,6 +1577,7 @@ enum
static void stbi__refill_buffer(stbi__context *s)
{
int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen);
+ s->callback_already_read += (int) (s->img_buffer - s->img_buffer_original);
if (n == 0) {
// at end of file, treat same as if from memory, but need to handle case
// where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file
@@ -1365,6 +1602,9 @@ stbi_inline static stbi_uc stbi__get8(stbi__context *s)
return 0;
}
+#if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM)
+// nothing
+#else
stbi_inline static int stbi__at_eof(stbi__context *s)
{
if (s->io.read) {
@@ -1376,9 +1616,14 @@ stbi_inline static int stbi__at_eof(stbi__context *s)
return s->img_buffer >= s->img_buffer_end;
}
+#endif
+#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC)
+// nothing
+#else
static void stbi__skip(stbi__context *s, int n)
{
+ if (n == 0) return; // already there!
if (n < 0) {
s->img_buffer = s->img_buffer_end;
return;
@@ -1393,7 +1638,11 @@ static void stbi__skip(stbi__context *s, int n)
}
s->img_buffer += n;
}
+#endif
+#if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM)
+// nothing
+#else
static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n)
{
if (s->io.read) {
@@ -1417,18 +1666,27 @@ static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n)
} else
return 0;
}
+#endif
+#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC)
+// nothing
+#else
static int stbi__get16be(stbi__context *s)
{
int z = stbi__get8(s);
return (z << 8) + stbi__get8(s);
}
+#endif
+#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC)
+// nothing
+#else
static stbi__uint32 stbi__get32be(stbi__context *s)
{
stbi__uint32 z = stbi__get16be(s);
return (z << 16) + stbi__get16be(s);
}
+#endif
#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF)
// nothing
@@ -1444,13 +1702,16 @@ static int stbi__get16le(stbi__context *s)
static stbi__uint32 stbi__get32le(stbi__context *s)
{
stbi__uint32 z = stbi__get16le(s);
- return z + (stbi__get16le(s) << 16);
+ z += (stbi__uint32)stbi__get16le(s) << 16;
+ return z;
}
#endif
#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings
-
+#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM)
+// nothing
+#else
//////////////////////////////////////////////////////////////////////////////
//
// generic converter from built-in img_n to req_comp
@@ -1466,7 +1727,11 @@ static stbi_uc stbi__compute_y(int r, int g, int b)
{
return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8);
}
+#endif
+#if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM)
+// nothing
+#else
static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y)
{
int i,j;
@@ -1490,19 +1755,19 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r
// convert source image with img_n components to one with req_comp components;
// avoid switch per pixel, so use switch per scanline and massive macros
switch (STBI__COMBO(img_n, req_comp)) {
- STBI__CASE(1,2) { dest[0]=src[0], dest[1]=255; } break;
+ STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=255; } break;
STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
- STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; } break;
+ STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=255; } break;
STBI__CASE(2,1) { dest[0]=src[0]; } break;
STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
- STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break;
- STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; } break;
+ STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break;
+ STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=255; } break;
STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break;
- STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; } break;
+ STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255; } break;
STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break;
- STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; } break;
- STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break;
- default: STBI_ASSERT(0);
+ STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break;
+ STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break;
+ default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return stbi__errpuc("unsupported", "Unsupported format conversion");
}
#undef STBI__CASE
}
@@ -1510,12 +1775,20 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r
STBI_FREE(data);
return good;
}
+#endif
+#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD)
+// nothing
+#else
static stbi__uint16 stbi__compute_y_16(int r, int g, int b)
{
return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8);
}
+#endif
+#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD)
+// nothing
+#else
static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y)
{
int i,j;
@@ -1539,19 +1812,19 @@ static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int r
// convert source image with img_n components to one with req_comp components;
// avoid switch per pixel, so use switch per scanline and massive macros
switch (STBI__COMBO(img_n, req_comp)) {
- STBI__CASE(1,2) { dest[0]=src[0], dest[1]=0xffff; } break;
+ STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=0xffff; } break;
STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
- STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=0xffff; } break;
+ STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=0xffff; } break;
STBI__CASE(2,1) { dest[0]=src[0]; } break;
STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
- STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break;
- STBI__CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=0xffff; } break;
+ STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break;
+ STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=0xffff; } break;
STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break;
- STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = 0xffff; } break;
+ STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = 0xffff; } break;
STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break;
- STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]), dest[1] = src[3]; } break;
- STBI__CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break;
- default: STBI_ASSERT(0);
+ STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break;
+ STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break;
+ default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return (stbi__uint16*) stbi__errpuc("unsupported", "Unsupported format conversion");
}
#undef STBI__CASE
}
@@ -1559,6 +1832,7 @@ static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int r
STBI_FREE(data);
return good;
}
+#endif
#ifndef STBI_NO_LINEAR
static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp)
@@ -1574,7 +1848,11 @@ static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp)
for (k=0; k < n; ++k) {
output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale);
}
- if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f;
+ }
+ if (n < comp) {
+ for (i=0; i < x*y; ++i) {
+ output[i*comp + n] = data[i*comp + n]/255.0f;
+ }
}
STBI_FREE(data);
return output;
@@ -1704,7 +1982,8 @@ typedef struct
static int stbi__build_huffman(stbi__huffman *h, int *count)
{
- int i,j,k=0,code;
+ int i,j,k=0;
+ unsigned int code;
// build size list for each symbol (from JPEG spec)
for (i=0; i < 16; ++i)
for (j=0; j < count[i]; ++j)
@@ -1720,7 +1999,7 @@ static int stbi__build_huffman(stbi__huffman *h, int *count)
if (h->size[k] == j) {
while (h->size[k] == j)
h->code[k++] = (stbi__uint16) (code++);
- if (code-1 >= (1 << j)) return stbi__err("bad code lengths","Corrupt JPEG");
+ if (code-1 >= (1u << j)) return stbi__err("bad code lengths","Corrupt JPEG");
}
// compute largest code + 1 for this size, preshifted as needed later
h->maxcode[j] = code << (16-j);
@@ -1764,7 +2043,7 @@ static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h)
if (k < m) k += (~0U << magbits) + 1;
// if the result is small enough, we can fit it in fast_ac table
if (k >= -128 && k <= 127)
- fast_ac[i] = (stbi__int16) ((k << 8) + (run << 4) + (len + magbits));
+ fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits));
}
}
}
@@ -1773,7 +2052,7 @@ static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h)
static void stbi__grow_buffer_unsafe(stbi__jpeg *j)
{
do {
- int b = j->nomore ? 0 : stbi__get8(j->s);
+ unsigned int b = j->nomore ? 0 : stbi__get8(j->s);
if (b == 0xff) {
int c = stbi__get8(j->s);
while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes
@@ -1789,7 +2068,7 @@ static void stbi__grow_buffer_unsafe(stbi__jpeg *j)
}
// (1 << n) - 1
-static stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535};
+static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535};
// decode a jpeg huffman value from the bitstream
stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h)
@@ -1842,7 +2121,7 @@ stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h)
}
// bias[n] = (-1<<n) + 1
-static int const stbi__jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767};
+static const int stbi__jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767};
// combined JPEG 'receive' and JPEG 'extend', since baseline
// always extends everything it receives.
@@ -1852,13 +2131,12 @@ stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n)
int sgn;
if (j->code_bits < n) stbi__grow_buffer_unsafe(j);
- sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB
+ sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative)
k = stbi_lrot(j->code_buffer, n);
- STBI_ASSERT(n >= 0 && n < (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask)));
j->code_buffer = k & ~stbi__bmask[n];
k &= stbi__bmask[n];
j->code_bits -= n;
- return k + (stbi__jbias[n] & ~sgn);
+ return k + (stbi__jbias[n] & (sgn - 1));
}
// get some unsigned bits
@@ -1885,7 +2163,7 @@ stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j)
// 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] =
+static const stbi_uc stbi__jpeg_dezigzag[64+15] =
{
0, 1, 8, 16, 9, 2, 3, 10,
17, 24, 32, 25, 18, 11, 4, 5,
@@ -1908,7 +2186,7 @@ static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman
if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
t = stbi__jpeg_huff_decode(j, hdc);
- if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+ if (t < 0 || t > 15) return stbi__err("bad huffman code","Corrupt JPEG");
// 0 all the ac values now so we can do it 32-bits at a time
memset(data,0,64*sizeof(data[0]));
@@ -1965,11 +2243,12 @@ static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__
// 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);
+ if (t < 0 || t > 15) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
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);
+ data[0] = (short) (dc * (1 << j->succ_low));
} else {
// refinement scan for DC coefficient
if (stbi__jpeg_get_bit(j))
@@ -2006,7 +2285,7 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__
j->code_buffer <<= s;
j->code_bits -= s;
zig = stbi__jpeg_dezigzag[k++];
- data[zig] = (short) ((r >> 8) << shift);
+ data[zig] = (short) ((r >> 8) * (1 << shift));
} else {
int rs = stbi__jpeg_huff_decode(j, hac);
if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG");
@@ -2024,7 +2303,7 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__
} else {
k += r;
zig = stbi__jpeg_dezigzag[k++];
- data[zig] = (short) (stbi__extend_receive(j,s) << shift);
+ data[zig] = (short) (stbi__extend_receive(j,s) * (1 << shift));
}
}
} while (k <= j->spec_end);
@@ -2111,7 +2390,7 @@ stbi_inline static stbi_uc stbi__clamp(int x)
}
#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5)))
-#define stbi__fsh(x) ((x) << 12)
+#define stbi__fsh(x) ((x) * 4096)
// derived from jidctint -- DCT_ISLOW
#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \
@@ -2166,7 +2445,7 @@ static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64])
// (1|2|3|4|5|6|7)==0 0 seconds
// all separate -0.047 seconds
// 1 && 2|3 && 4|5 && 6|7: -0.047 seconds
- int dcterm = d[0] << 2;
+ int dcterm = d[0]*4;
v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm;
} else {
STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56])
@@ -2805,7 +3084,7 @@ static int stbi__process_marker(stbi__jpeg *z, int m)
if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG");
for (i=0; i < 64; ++i)
- z->dequant[t][stbi__jpeg_dezigzag[i]] = sixteen ? stbi__get16be(z->s) : stbi__get8(z->s);
+ z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s));
L -= (sixteen ? 129 : 65);
}
return L==0;
@@ -2955,6 +3234,8 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan)
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
+ if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
+ if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
c = stbi__get8(s);
if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG");
s->img_n = c;
@@ -2967,7 +3248,7 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan)
z->rgb = 0;
for (i=0; i < s->img_n; ++i) {
- static unsigned char rgb[3] = { 'R', 'G', 'B' };
+ static const unsigned char rgb[3] = { 'R', 'G', 'B' };
z->img_comp[i].id = stbi__get8(s);
if (s->img_n == 3 && z->img_comp[i].id == rgb[i])
++z->rgb;
@@ -2986,6 +3267,13 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan)
if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v;
}
+ // check that plane subsampling factors are integer ratios; our resamplers can't deal with fractional ratios
+ // and I've never seen a non-corrupted JPEG file actually use them
+ for (i=0; i < s->img_n; ++i) {
+ if (h_max % z->img_comp[i].h != 0) return stbi__err("bad H","Corrupt JPEG");
+ if (v_max % z->img_comp[i].v != 0) return stbi__err("bad V","Corrupt JPEG");
+ }
+
// compute interleaved mcu info
z->img_h_max = h_max;
z->img_v_max = v_max;
@@ -3092,8 +3380,8 @@ static int stbi__decode_jpeg_image(stbi__jpeg *j)
} else if (stbi__DNL(m)) {
int Ld = stbi__get16be(j->s);
stbi__uint32 NL = stbi__get16be(j->s);
- if (Ld != 4) stbi__err("bad DNL len", "Corrupt JPEG");
- if (NL != j->s->img_y) stbi__err("bad DNL height", "Corrupt JPEG");
+ if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG");
+ if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG");
} else {
if (!stbi__process_marker(j, m)) return 0;
}
@@ -3541,12 +3829,16 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp
else
decode_n = z->s->img_n;
+ // nothing to do if no components requested; check this now to avoid
+ // accessing uninitialized coutput[0] later
+ if (decode_n <= 0) { stbi__cleanup_jpeg(z); return NULL; }
+
// resample and color-convert
{
int k;
unsigned int i,j;
stbi_uc *output;
- stbi_uc *coutput[4];
+ stbi_uc *coutput[4] = { NULL, NULL, NULL, NULL };
stbi__resample res_comp[4];
@@ -3610,20 +3902,20 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp
} else if (z->s->img_n == 4) {
if (z->app14_color_transform == 0) { // CMYK
for (i=0; i < z->s->img_x; ++i) {
- stbi_uc k = coutput[3][i];
- out[0] = stbi__blinn_8x8(coutput[0][i], k);
- out[1] = stbi__blinn_8x8(coutput[1][i], k);
- out[2] = stbi__blinn_8x8(coutput[2][i], k);
+ stbi_uc m = coutput[3][i];
+ out[0] = stbi__blinn_8x8(coutput[0][i], m);
+ out[1] = stbi__blinn_8x8(coutput[1][i], m);
+ out[2] = stbi__blinn_8x8(coutput[2][i], m);
out[3] = 255;
out += n;
}
} else if (z->app14_color_transform == 2) { // YCCK
z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);
for (i=0; i < z->s->img_x; ++i) {
- stbi_uc k = coutput[3][i];
- out[0] = stbi__blinn_8x8(255 - out[0], k);
- out[1] = stbi__blinn_8x8(255 - out[1], k);
- out[2] = stbi__blinn_8x8(255 - out[2], k);
+ stbi_uc m = coutput[3][i];
+ out[0] = stbi__blinn_8x8(255 - out[0], m);
+ out[1] = stbi__blinn_8x8(255 - out[1], m);
+ out[2] = stbi__blinn_8x8(255 - out[2], m);
out += n;
}
} else { // YCbCr + alpha? Ignore the fourth channel for now
@@ -3648,10 +3940,10 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp
}
} else if (z->s->img_n == 4 && z->app14_color_transform == 0) {
for (i=0; i < z->s->img_x; ++i) {
- stbi_uc k = coutput[3][i];
- stbi_uc r = stbi__blinn_8x8(coutput[0][i], k);
- stbi_uc g = stbi__blinn_8x8(coutput[1][i], k);
- stbi_uc b = stbi__blinn_8x8(coutput[2][i], k);
+ stbi_uc m = coutput[3][i];
+ stbi_uc r = stbi__blinn_8x8(coutput[0][i], m);
+ stbi_uc g = stbi__blinn_8x8(coutput[1][i], m);
+ stbi_uc b = stbi__blinn_8x8(coutput[2][i], m);
out[0] = stbi__compute_y(r, g, b);
out[1] = 255;
out += n;
@@ -3667,7 +3959,7 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp
if (n == 1)
for (i=0; i < z->s->img_x; ++i) out[i] = y[i];
else
- for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255;
+ for (i=0; i < z->s->img_x; ++i) { *out++ = y[i]; *out++ = 255; }
}
}
}
@@ -3683,6 +3975,7 @@ static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int re
{
unsigned char* result;
stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg));
+ if (!j) return stbi__errpuc("outofmem", "Out of memory");
STBI_NOTUSED(ri);
j->s = s;
stbi__setup_jpeg(j);
@@ -3695,6 +3988,7 @@ static int stbi__jpeg_test(stbi__context *s)
{
int r;
stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg));
+ if (!j) return stbi__err("outofmem", "Out of memory");
j->s = s;
stbi__setup_jpeg(j);
r = stbi__decode_jpeg_header(j, STBI__SCAN_type);
@@ -3719,6 +4013,7 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp)
{
int result;
stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg)));
+ if (!j) return stbi__err("outofmem", "Out of memory");
j->s = s;
result = stbi__jpeg_info_raw(j, x, y, comp);
STBI_FREE(j);
@@ -3738,6 +4033,7 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp)
// fast-way is faster to check than jpeg huffman, but slow way is slower
#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables
#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1)
+#define STBI__ZNSYMS 288 // number of symbols in literal/length alphabet
// zlib-style huffman encoding
// (jpegs packs from left, zlib from right, so can't share code)
@@ -3747,8 +4043,8 @@ typedef struct
stbi__uint16 firstcode[16];
int maxcode[17];
stbi__uint16 firstsymbol[16];
- stbi_uc size[288];
- stbi__uint16 value[288];
+ stbi_uc size[STBI__ZNSYMS];
+ stbi__uint16 value[STBI__ZNSYMS];
} stbi__zhuffman;
stbi_inline static int stbi__bitreverse16(int n)
@@ -3835,16 +4131,23 @@ typedef struct
stbi__zhuffman z_length, z_distance;
} stbi__zbuf;
+stbi_inline static int stbi__zeof(stbi__zbuf *z)
+{
+ return (z->zbuffer >= z->zbuffer_end);
+}
+
stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z)
{
- if (z->zbuffer >= z->zbuffer_end) return 0;
- return *z->zbuffer++;
+ return stbi__zeof(z) ? 0 : *z->zbuffer++;
}
static void stbi__fill_bits(stbi__zbuf *z)
{
do {
- STBI_ASSERT(z->code_buffer < (1U << z->num_bits));
+ if (z->code_buffer >= (1U << z->num_bits)) {
+ z->zbuffer = z->zbuffer_end; /* treat this as EOF so we fail. */
+ return;
+ }
z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits;
z->num_bits += 8;
} while (z->num_bits <= 24);
@@ -3869,10 +4172,11 @@ static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z)
for (s=STBI__ZFAST_BITS+1; ; ++s)
if (k < z->maxcode[s])
break;
- if (s == 16) return -1; // invalid code!
+ if (s >= 16) return -1; // invalid code!
// code size is s, so:
b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s];
- STBI_ASSERT(z->size[b] == s);
+ if (b >= STBI__ZNSYMS) return -1; // some data was corrupt somewhere!
+ if (z->size[b] != s) return -1; // was originally an assert, but report failure instead.
a->code_buffer >>= s;
a->num_bits -= s;
return z->value[b];
@@ -3881,7 +4185,12 @@ static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z)
stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z)
{
int b,s;
- if (a->num_bits < 16) stbi__fill_bits(a);
+ if (a->num_bits < 16) {
+ if (stbi__zeof(a)) {
+ return -1; /* report error for unexpected end of data. */
+ }
+ stbi__fill_bits(a);
+ }
b = z->fast[a->code_buffer & STBI__ZFAST_MASK];
if (b) {
s = b >> 9;
@@ -3895,13 +4204,16 @@ stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z)
static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes
{
char *q;
- int cur, limit, old_limit;
+ unsigned int cur, limit, old_limit;
z->zout = zout;
if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG");
- cur = (int) (z->zout - z->zout_start);
- limit = old_limit = (int) (z->zout_end - z->zout_start);
- while (cur + n > limit)
+ cur = (unsigned int) (z->zout - z->zout_start);
+ limit = old_limit = (unsigned) (z->zout_end - z->zout_start);
+ if (UINT_MAX - cur < (unsigned) n) return stbi__err("outofmem", "Out of memory");
+ while (cur + n > limit) {
+ if(limit > UINT_MAX / 2) return stbi__err("outofmem", "Out of memory");
limit *= 2;
+ }
q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit);
STBI_NOTUSED(old_limit);
if (q == NULL) return stbi__err("outofmem", "Out of memory");
@@ -3911,18 +4223,18 @@ static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room
return 1;
}
-static int stbi__zlength_base[31] = {
+static const int stbi__zlength_base[31] = {
3,4,5,6,7,8,9,10,11,13,
15,17,19,23,27,31,35,43,51,59,
67,83,99,115,131,163,195,227,258,0,0 };
-static int stbi__zlength_extra[31]=
+static const 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,
+static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,
257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
-static int stbi__zdist_extra[32] =
+static const int stbi__zdist_extra[32] =
{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
static int stbi__parse_huffman_block(stbi__zbuf *a)
@@ -3969,7 +4281,7 @@ static int stbi__parse_huffman_block(stbi__zbuf *a)
static int stbi__compute_huffman_codes(stbi__zbuf *a)
{
- static stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
+ static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
stbi__zhuffman z_codelength;
stbi_uc lencodes[286+32+137];//padding for maximum single op
stbi_uc codelength_sizes[19];
@@ -3999,11 +4311,12 @@ static int stbi__compute_huffman_codes(stbi__zbuf *a)
c = stbi__zreceive(a,2)+3;
if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG");
fill = lencodes[n-1];
- } else if (c == 17)
+ } else if (c == 17) {
c = stbi__zreceive(a,3)+3;
- else {
- STBI_ASSERT(c == 18);
+ } else if (c == 18) {
c = stbi__zreceive(a,7)+11;
+ } else {
+ return stbi__err("bad codelengths", "Corrupt PNG");
}
if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG");
memset(lencodes+n, fill, c);
@@ -4029,7 +4342,7 @@ static int stbi__parse_uncompressed_block(stbi__zbuf *a)
a->code_buffer >>= 8;
a->num_bits -= 8;
}
- STBI_ASSERT(a->num_bits == 0);
+ if (a->num_bits < 0) return stbi__err("zlib corrupt","Corrupt PNG");
// now fill header the normal way
while (k < 4)
header[k++] = stbi__zget8(a);
@@ -4051,6 +4364,7 @@ static int stbi__parse_zlib_header(stbi__zbuf *a)
int cm = cmf & 15;
/* int cinfo = cmf >> 4; */
int flg = stbi__zget8(a);
+ if (stbi__zeof(a)) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec
if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec
if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png
if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png
@@ -4058,7 +4372,7 @@ static int stbi__parse_zlib_header(stbi__zbuf *a)
return 1;
}
-static const stbi_uc stbi__zdefault_length[288] =
+static const stbi_uc stbi__zdefault_length[STBI__ZNSYMS] =
{
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
@@ -4104,7 +4418,7 @@ static int stbi__parse_zlib(stbi__zbuf *a, int parse_header)
} else {
if (type == 1) {
// use fixed code lengths
- if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0;
+ if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , STBI__ZNSYMS)) return 0;
if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0;
} else {
if (!stbi__compute_huffman_codes(a)) return 0;
@@ -4228,7 +4542,7 @@ static stbi__pngchunk stbi__get_chunk_header(stbi__context *s)
static int stbi__check_png_header(stbi__context *s)
{
- static stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 };
+ static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 };
int i;
for (i=0; i < 8; ++i)
if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG");
@@ -4274,7 +4588,7 @@ static int stbi__paeth(int a, int b, int c)
return c;
}
-static stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };
+static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };
// create the png data from post-deflated data
static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color)
@@ -4294,13 +4608,14 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into
if (!a->out) return stbi__err("outofmem", "Out of memory");
+ if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG");
img_width_bytes = (((img_n * x * depth) + 7) >> 3);
img_len = (img_width_bytes + 1) * y;
- if (s->img_x == x && s->img_y == y) {
- if (raw_len != img_len) return stbi__err("not enough pixels","Corrupt PNG");
- } else { // interlaced:
- if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG");
- }
+
+ // we used to check for exact match between raw_len and img_len on non-interlaced PNGs,
+ // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros),
+ // so just check for raw_len < img_len always.
+ if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG");
for (j=0; j < y; ++j) {
stbi_uc *cur = a->out + stride*j;
@@ -4311,7 +4626,7 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r
return stbi__err("invalid filter","Corrupt PNG");
if (depth < 8) {
- STBI_ASSERT(img_width_bytes <= x);
+ if (img_width_bytes > x) return stbi__err("invalid width","Corrupt PNG");
cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place
filter_bytes = 1;
width = img_width_bytes;
@@ -4499,6 +4814,7 @@ static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint3
// de-interlacing
final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0);
+ if (!final) return stbi__err("outofmem", "Out of memory");
for (p=0; p < 7; ++p) {
int xorig[] = { 0,4,0,2,0,1,0 };
int yorig[] = { 0,0,4,0,2,0,1 };
@@ -4619,19 +4935,46 @@ static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int
return 1;
}
-static int stbi__unpremultiply_on_load = 0;
-static int stbi__de_iphone_flag = 0;
+static int stbi__unpremultiply_on_load_global = 0;
+static int stbi__de_iphone_flag_global = 0;
STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply)
{
- stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply;
+ stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply;
}
STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert)
{
- stbi__de_iphone_flag = flag_true_if_should_convert;
+ stbi__de_iphone_flag_global = flag_true_if_should_convert;
+}
+
+#ifndef STBI_THREAD_LOCAL
+#define stbi__unpremultiply_on_load stbi__unpremultiply_on_load_global
+#define stbi__de_iphone_flag stbi__de_iphone_flag_global
+#else
+static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set;
+static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set;
+
+STBIDEF void stbi__unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply)
+{
+ stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply;
+ stbi__unpremultiply_on_load_set = 1;
}
+STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert)
+{
+ stbi__de_iphone_flag_local = flag_true_if_should_convert;
+ stbi__de_iphone_flag_set = 1;
+}
+
+#define stbi__unpremultiply_on_load (stbi__unpremultiply_on_load_set \
+ ? stbi__unpremultiply_on_load_local \
+ : stbi__unpremultiply_on_load_global)
+#define stbi__de_iphone_flag (stbi__de_iphone_flag_set \
+ ? stbi__de_iphone_flag_local \
+ : stbi__de_iphone_flag_global)
+#endif // STBI_THREAD_LOCAL
+
static void stbi__de_iphone(stbi__png *z)
{
stbi__context *s = z->s;
@@ -4653,9 +4996,10 @@ static void stbi__de_iphone(stbi__png *z)
stbi_uc a = p[3];
stbi_uc t = p[0];
if (a) {
- p[0] = p[2] * 255 / a;
- p[1] = p[1] * 255 / a;
- p[2] = t * 255 / a;
+ stbi_uc half = a / 2;
+ p[0] = (p[2] * 255 + half) / a;
+ p[1] = (p[1] * 255 + half) / a;
+ p[2] = ( t * 255 + half) / a;
} else {
p[0] = p[2];
p[2] = t;
@@ -4674,12 +5018,12 @@ static void stbi__de_iphone(stbi__png *z)
}
}
-#define STBI__PNG_TYPE(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d))
+#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d))
static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
{
stbi_uc palette[1024], pal_img_n=0;
- stbi_uc has_trans=0, tc[3];
+ stbi_uc has_trans=0, tc[3]={0};
stbi__uint16 tc16[3];
stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0;
int first=1,k,interlace=0, color=0, is_iphone=0;
@@ -4705,8 +5049,10 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
if (!first) return stbi__err("multiple IHDR","Corrupt PNG");
first = 0;
if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG");
- s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)");
- s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)");
+ s->img_x = stbi__get32be(s);
+ s->img_y = stbi__get32be(s);
+ if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
+ if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only");
color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG");
if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG");
@@ -4818,8 +5164,13 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
if (req_comp >= 3) s->img_out_n = req_comp;
if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n))
return 0;
+ } else if (has_trans) {
+ // non-paletted image with tRNS -> source image has (constant) alpha
+ ++s->img_n;
}
STBI_FREE(z->expanded); z->expanded = NULL;
+ // end of PNG chunk, read and skip CRC
+ stbi__get32be(s);
return 1;
}
@@ -4850,10 +5201,12 @@ static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, st
void *result=NULL;
if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error");
if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) {
- if (p->depth < 8)
+ if (p->depth <= 8)
ri->bits_per_channel = 8;
+ else if (p->depth == 16)
+ ri->bits_per_channel = 16;
else
- ri->bits_per_channel = p->depth;
+ return stbi__errpuc("bad bits_per_channel", "PNG not supported: unsupported color depth");
result = p->out;
p->out = NULL;
if (req_comp && req_comp != p->s->img_out_n) {
@@ -4908,6 +5261,19 @@ static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp)
p.s = s;
return stbi__png_info_raw(&p, x, y, comp);
}
+
+static int stbi__png_is16(stbi__context *s)
+{
+ stbi__png p;
+ p.s = s;
+ if (!stbi__png_info_raw(&p, NULL, NULL, NULL))
+ return 0;
+ if (p.depth != 16) {
+ stbi__rewind(p.s);
+ return 0;
+ }
+ return 1;
+}
#endif
// Microsoft/Windows BMP image
@@ -4941,11 +5307,11 @@ static int stbi__high_bit(unsigned int z)
{
int n=0;
if (z == 0) return -1;
- if (z >= 0x10000) n += 16, z >>= 16;
- if (z >= 0x00100) n += 8, z >>= 8;
- if (z >= 0x00010) n += 4, z >>= 4;
- if (z >= 0x00004) n += 2, z >>= 2;
- if (z >= 0x00002) n += 1, z >>= 1;
+ if (z >= 0x10000) { n += 16; z >>= 16; }
+ if (z >= 0x00100) { n += 8; z >>= 8; }
+ if (z >= 0x00010) { n += 4; z >>= 4; }
+ if (z >= 0x00004) { n += 2; z >>= 2; }
+ if (z >= 0x00002) { n += 1;/* >>= 1;*/ }
return n;
}
@@ -4959,29 +5325,62 @@ static int stbi__bitcount(unsigned int a)
return a & 0xff;
}
-static int stbi__shiftsigned(int v, int shift, int bits)
-{
- int result;
- int z=0;
-
- if (shift < 0) v <<= -shift;
- else v >>= shift;
- result = v;
-
- z = bits;
- while (z < 8) {
- result += v >> z;
- z += bits;
- }
- return result;
+// extract an arbitrarily-aligned N-bit value (N=bits)
+// from v, and then make it 8-bits long and fractionally
+// extend it to full full range.
+static int stbi__shiftsigned(unsigned int v, int shift, int bits)
+{
+ static unsigned int mul_table[9] = {
+ 0,
+ 0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/,
+ 0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/,
+ };
+ static unsigned int shift_table[9] = {
+ 0, 0,0,1,0,2,4,6,0,
+ };
+ if (shift < 0)
+ v <<= -shift;
+ else
+ v >>= shift;
+ STBI_ASSERT(v < 256);
+ v >>= (8-bits);
+ STBI_ASSERT(bits >= 0 && bits <= 8);
+ return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits];
}
typedef struct
{
int bpp, offset, hsz;
unsigned int mr,mg,mb,ma, all_a;
+ int extra_read;
} stbi__bmp_data;
+static int stbi__bmp_set_mask_defaults(stbi__bmp_data *info, int compress)
+{
+ // BI_BITFIELDS specifies masks explicitly, don't override
+ if (compress == 3)
+ return 1;
+
+ if (compress == 0) {
+ if (info->bpp == 16) {
+ info->mr = 31u << 10;
+ info->mg = 31u << 5;
+ info->mb = 31u << 0;
+ } else if (info->bpp == 32) {
+ info->mr = 0xffu << 16;
+ info->mg = 0xffu << 8;
+ info->mb = 0xffu << 0;
+ info->ma = 0xffu << 24;
+ info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0
+ } else {
+ // otherwise, use defaults, which is all-0
+ info->mr = info->mg = info->mb = info->ma = 0;
+ }
+ return 1;
+ }
+ return 0; // error
+}
+
static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
{
int hsz;
@@ -4992,6 +5391,9 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
info->offset = stbi__get32le(s);
info->hsz = hsz = stbi__get32le(s);
info->mr = info->mg = info->mb = info->ma = 0;
+ info->extra_read = 14;
+
+ if (info->offset < 0) return stbi__errpuc("bad BMP", "bad BMP");
if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown");
if (hsz == 12) {
@@ -5003,10 +5405,11 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
}
if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP");
info->bpp = stbi__get16le(s);
- if (info->bpp == 1) return stbi__errpuc("monochrome", "BMP type not supported: 1-bit");
if (hsz != 12) {
int compress = stbi__get32le(s);
if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE");
+ if (compress >= 4) return stbi__errpuc("BMP JPEG/PNG", "BMP type not supported: unsupported compression"); // this includes PNG/JPEG modes
+ if (compress == 3 && info->bpp != 16 && info->bpp != 32) return stbi__errpuc("bad BMP", "bad BMP"); // bitfields requires 16 or 32 bits/pixel
stbi__get32le(s); // discard sizeof
stbi__get32le(s); // discard hres
stbi__get32le(s); // discard vres
@@ -5021,21 +5424,12 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
}
if (info->bpp == 16 || info->bpp == 32) {
if (compress == 0) {
- if (info->bpp == 32) {
- info->mr = 0xffu << 16;
- info->mg = 0xffu << 8;
- info->mb = 0xffu << 0;
- info->ma = 0xffu << 24;
- info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0
- } else {
- info->mr = 31u << 10;
- info->mg = 31u << 5;
- info->mb = 31u << 0;
- }
+ stbi__bmp_set_mask_defaults(info, compress);
} else if (compress == 3) {
info->mr = stbi__get32le(s);
info->mg = stbi__get32le(s);
info->mb = stbi__get32le(s);
+ info->extra_read += 12;
// not documented, but generated by photoshop and handled by mspaint
if (info->mr == info->mg && info->mg == info->mb) {
// ?!?!?
@@ -5045,6 +5439,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
return stbi__errpuc("bad BMP", "bad BMP");
}
} else {
+ // V4/V5 header
int i;
if (hsz != 108 && hsz != 124)
return stbi__errpuc("bad BMP", "bad BMP");
@@ -5052,6 +5447,8 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
info->mg = stbi__get32le(s);
info->mb = stbi__get32le(s);
info->ma = stbi__get32le(s);
+ if (compress != 3) // override mr/mg/mb unless in BI_BITFIELDS mode, as per docs
+ stbi__bmp_set_mask_defaults(info, compress);
stbi__get32le(s); // discard color space
for (i=0; i < 12; ++i)
stbi__get32le(s); // discard color space parameters
@@ -5084,6 +5481,9 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
flip_vertically = ((int) s->img_y) > 0;
s->img_y = abs((int) s->img_y);
+ if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+ if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+
mr = info.mr;
mg = info.mg;
mb = info.mb;
@@ -5092,13 +5492,21 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
if (info.hsz == 12) {
if (info.bpp < 24)
- psize = (info.offset - 14 - 24) / 3;
+ psize = (info.offset - info.extra_read - 24) / 3;
} else {
if (info.bpp < 16)
- psize = (info.offset - 14 - info.hsz) >> 2;
+ psize = (info.offset - info.extra_read - info.hsz) >> 2;
+ }
+ if (psize == 0) {
+ if (info.offset != s->callback_already_read + (s->img_buffer - s->img_buffer_original)) {
+ return stbi__errpuc("bad offset", "Corrupt BMP");
+ }
}
- s->img_n = ma ? 4 : 3;
+ if (info.bpp == 24 && ma == 0xff000000)
+ s->img_n = 3;
+ else
+ s->img_n = ma ? 4 : 3;
if (req_comp && req_comp >= 3) // we can directly decode 3 or 4
target = req_comp;
else
@@ -5120,36 +5528,56 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
if (info.hsz != 12) stbi__get8(s);
pal[i][3] = 255;
}
- stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4));
- if (info.bpp == 4) width = (s->img_x + 1) >> 1;
+ stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4));
+ if (info.bpp == 1) width = (s->img_x + 7) >> 3;
+ else if (info.bpp == 4) width = (s->img_x + 1) >> 1;
else if (info.bpp == 8) width = s->img_x;
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) {
- int v=stbi__get8(s),v2=0;
- if (info.bpp == 4) {
- v2 = v & 15;
- v >>= 4;
+ if (info.bpp == 1) {
+ for (j=0; j < (int) s->img_y; ++j) {
+ int bit_offset = 7, v = stbi__get8(s);
+ for (i=0; i < (int) s->img_x; ++i) {
+ int color = (v>>bit_offset)&0x1;
+ out[z++] = pal[color][0];
+ out[z++] = pal[color][1];
+ out[z++] = pal[color][2];
+ if (target == 4) out[z++] = 255;
+ if (i+1 == (int) s->img_x) break;
+ if((--bit_offset) < 0) {
+ bit_offset = 7;
+ v = stbi__get8(s);
+ }
}
- out[z++] = pal[v][0];
- out[z++] = pal[v][1];
- out[z++] = pal[v][2];
- if (target == 4) out[z++] = 255;
- if (i+1 == (int) s->img_x) break;
- v = (info.bpp == 8) ? stbi__get8(s) : v2;
- out[z++] = pal[v][0];
- out[z++] = pal[v][1];
- out[z++] = pal[v][2];
- if (target == 4) out[z++] = 255;
+ stbi__skip(s, pad);
+ }
+ } else {
+ for (j=0; j < (int) s->img_y; ++j) {
+ for (i=0; i < (int) s->img_x; i += 2) {
+ int v=stbi__get8(s),v2=0;
+ if (info.bpp == 4) {
+ v2 = v & 15;
+ v >>= 4;
+ }
+ out[z++] = pal[v][0];
+ out[z++] = pal[v][1];
+ out[z++] = pal[v][2];
+ if (target == 4) out[z++] = 255;
+ if (i+1 == (int) s->img_x) break;
+ v = (info.bpp == 8) ? stbi__get8(s) : v2;
+ out[z++] = pal[v][0];
+ out[z++] = pal[v][1];
+ out[z++] = pal[v][2];
+ if (target == 4) out[z++] = 255;
+ }
+ stbi__skip(s, pad);
}
- stbi__skip(s, pad);
}
} else {
int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0;
int z = 0;
int easy=0;
- stbi__skip(s, info.offset - 14 - info.hsz);
+ stbi__skip(s, info.offset - info.extra_read - info.hsz);
if (info.bpp == 24) width = 3 * s->img_x;
else if (info.bpp == 16) width = 2*s->img_x;
else /* bpp = 32 and pad = 0 */ width=0;
@@ -5167,6 +5595,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg);
bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb);
ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma);
+ if (rcount > 8 || gcount > 8 || bcount > 8 || acount > 8) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); }
}
for (j=0; j < (int) s->img_y; ++j) {
if (easy) {
@@ -5184,7 +5613,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
int bpp = info.bpp;
for (i=0; i < (int) s->img_x; ++i) {
stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s));
- int a;
+ unsigned int a;
out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount));
out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount));
out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount));
@@ -5208,7 +5637,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
stbi_uc *p1 = out + j *s->img_x*target;
stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target;
for (i=0; i < (int) s->img_x*target; ++i) {
- t = p1[i], p1[i] = p2[i], p2[i] = t;
+ t = p1[i]; p1[i] = p2[i]; p2[i] = t;
}
}
}
@@ -5232,14 +5661,14 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req
static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16)
{
// only RGB or RGBA (incl. 16bit) or grey allowed
- if(is_rgb16) *is_rgb16 = 0;
+ if (is_rgb16) *is_rgb16 = 0;
switch(bits_per_pixel) {
case 8: return STBI_grey;
case 16: if(is_grey) return STBI_grey_alpha;
- // else: fall-through
+ // fallthrough
case 15: if(is_rgb16) *is_rgb16 = 1;
- return STBI_rgb;
- case 24: // fall-through
+ return STBI_rgb;
+ case 24: // fallthrough
case 32: return bits_per_pixel/8;
default: return 0;
}
@@ -5388,6 +5817,11 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req
int RLE_repeating = 0;
int read_next_pixel = 1;
STBI_NOTUSED(ri);
+ STBI_NOTUSED(tga_x_origin); // @TODO
+ STBI_NOTUSED(tga_y_origin); // @TODO
+
+ if (tga_height > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+ if (tga_width > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
// do a tiny bit of precessing
if ( tga_image_type >= 8 )
@@ -5428,6 +5862,11 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req
// do I need to load a palette?
if ( tga_indexed)
{
+ if (tga_palette_len == 0) { /* you have to have at least one entry! */
+ STBI_FREE(tga_data);
+ return stbi__errpuc("bad palette", "Corrupt TGA");
+ }
+
// any data to skip? (offset usually = 0)
stbi__skip(s, tga_palette_start );
// load the palette
@@ -5551,6 +5990,7 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req
// Microsoft's C compilers happy... [8^(
tga_palette_start = tga_palette_len = tga_palette_bits =
tga_x_origin = tga_y_origin = 0;
+ STBI_NOTUSED(tga_palette_start);
// OK, done
return tga_data;
}
@@ -5635,6 +6075,9 @@ static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req
h = stbi__get32be(s);
w = stbi__get32be(s);
+ if (h > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+ if (w > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+
// Make sure the depth is 8 bits.
bitdepth = stbi__get16be(s);
if (bitdepth != 8 && bitdepth != 16)
@@ -5698,7 +6141,7 @@ static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req
// Else if n is 128, noop.
// Endloop
- // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data,
+ // The RLE-compressed data is preceded by a 2-byte data count for each row in the data,
// which we're going to just skip.
stbi__skip(s, h * channelCount * 2 );
@@ -5989,6 +6432,10 @@ static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_c
x = stbi__get16be(s);
y = stbi__get16be(s);
+
+ if (y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+ if (x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+
if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)");
if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode");
@@ -5998,6 +6445,7 @@ static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_c
// intermediate buffer is RGBA
result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0);
+ if (!result) return stbi__errpuc("outofmem", "Out of memory");
memset(result, 0xff, x*y*4);
if (!stbi__pic_load_core(s,x,y,comp, result)) {
@@ -6034,11 +6482,13 @@ typedef struct
typedef struct
{
int w,h;
- stbi_uc *out, *old_out; // output buffer (always 4 components)
- int flags, bgindex, ratio, transparent, eflags, delay;
+ stbi_uc *out; // output buffer (always 4 components)
+ stbi_uc *background; // The current "background" as far as a gif is concerned
+ stbi_uc *history;
+ int flags, bgindex, ratio, transparent, eflags;
stbi_uc pal[256][4];
stbi_uc lpal[256][4];
- stbi__gif_lzw codes[4096];
+ stbi__gif_lzw codes[8192];
stbi_uc *color_table;
int parse, step;
int lflags;
@@ -6046,6 +6496,7 @@ typedef struct
int max_x, max_y;
int cur_x, cur_y;
int line_size;
+ int delay;
} stbi__gif;
static int stbi__gif_test_raw(stbi__context *s)
@@ -6094,6 +6545,9 @@ static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_in
g->ratio = stbi__get8(s);
g->transparent = -1;
+ if (g->w > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
+ if (g->h > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
+
if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments
if (is_info) return 1;
@@ -6107,6 +6561,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*) stbi__malloc(sizeof(stbi__gif));
+ if (!g) return stbi__err("outofmem", "Out of memory");
if (!stbi__gif_header(s, g, comp, 1)) {
STBI_FREE(g);
stbi__rewind( s );
@@ -6121,6 +6576,7 @@ static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp)
static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)
{
stbi_uc *p, *c;
+ int idx;
// recurse to decode the prefixes, since the linked-list is backwards,
// and working backwards through an interleaved image would be nasty
@@ -6129,10 +6585,12 @@ static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)
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];
+ idx = g->cur_x + g->cur_y;
+ p = &g->out[idx];
+ g->history[idx / 4] = 1;
- if (c[3] >= 128) {
+ c = &g->color_table[g->codes[code].suffix * 4];
+ if (c[3] > 128) { // don't render transparent pixels;
p[0] = c[2];
p[1] = c[1];
p[2] = c[0];
@@ -6206,11 +6664,16 @@ static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)
stbi__skip(s,len);
return g->out;
} else if (code <= avail) {
- if (first) return stbi__errpuc("no clear code", "Corrupt GIF");
+ if (first) {
+ return stbi__errpuc("no clear code", "Corrupt GIF");
+ }
if (oldcode >= 0) {
p = &g->codes[avail++];
- if (avail > 4096) return stbi__errpuc("too many codes", "Corrupt GIF");
+ if (avail > 8192) {
+ return stbi__errpuc("too many codes", "Corrupt GIF");
+ }
+
p->prefix = (stbi__int16) oldcode;
p->first = g->codes[oldcode].first;
p->suffix = (code == avail) ? p->first : g->codes[code].first;
@@ -6232,62 +6695,77 @@ static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)
}
}
-static void stbi__fill_gif_background(stbi__gif *g, int x0, int y0, int x1, int y1)
-{
- int x, y;
- stbi_uc *c = g->pal[g->bgindex];
- for (y = y0; y < y1; y += 4 * g->w) {
- for (x = x0; x < x1; x += 4) {
- stbi_uc *p = &g->out[y + x];
- p[0] = c[2];
- p[1] = c[1];
- p[2] = c[0];
- p[3] = 0;
- }
- }
-}
-
// this function is designed to support animated gifs, although stb_image doesn't support it
-static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp)
+// two back is the image from two frames ago, used for a very specific disposal format
+static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back)
{
- int i;
- stbi_uc *prev_out = 0;
-
- if (g->out == 0 && !stbi__gif_header(s, g, comp,0))
- return 0; // stbi__g_failure_reason set by stbi__gif_header
+ int dispose;
+ int first_frame;
+ int pi;
+ int pcount;
+ STBI_NOTUSED(req_comp);
- if (!stbi__mad3sizes_valid(g->w, g->h, 4, 0))
- return stbi__errpuc("too large", "GIF too large");
+ // on first frame, any non-written pixels get the background colour (non-transparent)
+ first_frame = 0;
+ if (g->out == 0) {
+ if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header
+ if (!stbi__mad3sizes_valid(4, g->w, g->h, 0))
+ return stbi__errpuc("too large", "GIF image is too large");
+ pcount = g->w * g->h;
+ g->out = (stbi_uc *) stbi__malloc(4 * pcount);
+ g->background = (stbi_uc *) stbi__malloc(4 * pcount);
+ g->history = (stbi_uc *) stbi__malloc(pcount);
+ if (!g->out || !g->background || !g->history)
+ return stbi__errpuc("outofmem", "Out of memory");
+
+ // image is treated as "transparent" at the start - ie, nothing overwrites the current background;
+ // background colour is only used for pixels that are not rendered first frame, after that "background"
+ // color refers to the color that was there the previous frame.
+ memset(g->out, 0x00, 4 * pcount);
+ memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent)
+ memset(g->history, 0x00, pcount); // pixels that were affected previous frame
+ first_frame = 1;
+ } else {
+ // second frame - how do we dispose of the previous one?
+ dispose = (g->eflags & 0x1C) >> 2;
+ pcount = g->w * g->h;
- prev_out = g->out;
- g->out = (stbi_uc *) stbi__malloc_mad3(4, g->w, g->h, 0);
- if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory");
+ if ((dispose == 3) && (two_back == 0)) {
+ dispose = 2; // if I don't have an image to revert back to, default to the old background
+ }
- switch ((g->eflags & 0x1C) >> 2) {
- case 0: // unspecified (also always used on 1st frame)
- stbi__fill_gif_background(g, 0, 0, 4 * g->w, 4 * g->w * g->h);
- break;
- case 1: // do not dispose
- if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h);
- g->old_out = prev_out;
- break;
- case 2: // dispose to background
- if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h);
- stbi__fill_gif_background(g, g->start_x, g->start_y, g->max_x, g->max_y);
- break;
- case 3: // dispose to previous
- if (g->old_out) {
- for (i = g->start_y; i < g->max_y; i += 4 * g->w)
- memcpy(&g->out[i + g->start_x], &g->old_out[i + g->start_x], g->max_x - g->start_x);
+ if (dispose == 3) { // use previous graphic
+ for (pi = 0; pi < pcount; ++pi) {
+ if (g->history[pi]) {
+ memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 );
+ }
}
- break;
+ } else if (dispose == 2) {
+ // restore what was changed last frame to background before that frame;
+ for (pi = 0; pi < pcount; ++pi) {
+ if (g->history[pi]) {
+ memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 );
+ }
+ }
+ } else {
+ // This is a non-disposal case eithe way, so just
+ // leave the pixels as is, and they will become the new background
+ // 1: do not dispose
+ // 0: not specified.
+ }
+
+ // background is what out is after the undoing of the previou frame;
+ memcpy( g->background, g->out, 4 * g->w * g->h );
}
+ // clear my history;
+ memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame
+
for (;;) {
- switch (stbi__get8(s)) {
+ int tag = stbi__get8(s);
+ switch (tag) {
case 0x2C: /* Image Descriptor */
{
- int prev_trans = -1;
stbi__int32 x, y, w, h;
stbi_uc *o;
@@ -6306,6 +6784,13 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
g->cur_x = g->start_x;
g->cur_y = g->start_y;
+ // if the width of the specified rectangle is 0, that means
+ // we may not see *any* pixels or the image is malformed;
+ // to make sure this is caught, move the current y down to
+ // max_y (which is what out_gif_code checks).
+ if (w == 0)
+ g->cur_y = g->max_y;
+
g->lflags = stbi__get8(s);
if (g->lflags & 0x40) {
@@ -6320,19 +6805,24 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1);
g->color_table = (stbi_uc *) g->lpal;
} else if (g->flags & 0x80) {
- if (g->transparent >= 0 && (g->eflags & 0x01)) {
- prev_trans = g->pal[g->transparent][3];
- 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;
-
- if (prev_trans != -1)
- g->pal[g->transparent][3] = (stbi_uc) prev_trans;
+ if (!o) return NULL;
+
+ // if this was the first frame,
+ pcount = g->w * g->h;
+ if (first_frame && (g->bgindex > 0)) {
+ // if first frame, any pixel not drawn to gets the background color
+ for (pi = 0; pi < pcount; ++pi) {
+ if (g->history[pi] == 0) {
+ g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be;
+ memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 );
+ }
+ }
+ }
return o;
}
@@ -6340,19 +6830,35 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
case 0x21: // Comment Extension.
{
int len;
- if (stbi__get8(s) == 0xF9) { // Graphic Control Extension.
+ int ext = stbi__get8(s);
+ if (ext == 0xF9) { // Graphic Control Extension.
len = stbi__get8(s);
if (len == 4) {
g->eflags = stbi__get8(s);
- g->delay = stbi__get16le(s);
- g->transparent = stbi__get8(s);
+ g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths.
+
+ // unset old transparent
+ if (g->transparent >= 0) {
+ g->pal[g->transparent][3] = 255;
+ }
+ if (g->eflags & 0x01) {
+ g->transparent = stbi__get8(s);
+ if (g->transparent >= 0) {
+ g->pal[g->transparent][3] = 0;
+ }
+ } else {
+ // don't need transparent
+ stbi__skip(s, 1);
+ g->transparent = -1;
+ }
} else {
stbi__skip(s, len);
break;
}
}
- while ((len = stbi__get8(s)) != 0)
+ while ((len = stbi__get8(s)) != 0) {
stbi__skip(s, len);
+ }
break;
}
@@ -6363,28 +6869,130 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i
return stbi__errpuc("unknown code", "Corrupt GIF");
}
}
+}
- STBI_NOTUSED(req_comp);
+static void *stbi__load_gif_main_outofmem(stbi__gif *g, stbi_uc *out, int **delays)
+{
+ STBI_FREE(g->out);
+ STBI_FREE(g->history);
+ STBI_FREE(g->background);
+
+ if (out) STBI_FREE(out);
+ if (delays && *delays) STBI_FREE(*delays);
+ return stbi__errpuc("outofmem", "Out of memory");
+}
+
+static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp)
+{
+ if (stbi__gif_test(s)) {
+ int layers = 0;
+ stbi_uc *u = 0;
+ stbi_uc *out = 0;
+ stbi_uc *two_back = 0;
+ stbi__gif g;
+ int stride;
+ int out_size = 0;
+ int delays_size = 0;
+
+ STBI_NOTUSED(out_size);
+ STBI_NOTUSED(delays_size);
+
+ memset(&g, 0, sizeof(g));
+ if (delays) {
+ *delays = 0;
+ }
+
+ do {
+ u = stbi__gif_load_next(s, &g, comp, req_comp, two_back);
+ if (u == (stbi_uc *) s) u = 0; // end of animated gif marker
+
+ if (u) {
+ *x = g.w;
+ *y = g.h;
+ ++layers;
+ stride = g.w * g.h * 4;
+
+ if (out) {
+ void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride );
+ if (!tmp)
+ return stbi__load_gif_main_outofmem(&g, out, delays);
+ else {
+ out = (stbi_uc*) tmp;
+ out_size = layers * stride;
+ }
+
+ if (delays) {
+ int *new_delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers );
+ if (!new_delays)
+ return stbi__load_gif_main_outofmem(&g, out, delays);
+ *delays = new_delays;
+ delays_size = layers * sizeof(int);
+ }
+ } else {
+ out = (stbi_uc*)stbi__malloc( layers * stride );
+ if (!out)
+ return stbi__load_gif_main_outofmem(&g, out, delays);
+ out_size = layers * stride;
+ if (delays) {
+ *delays = (int*) stbi__malloc( layers * sizeof(int) );
+ if (!*delays)
+ return stbi__load_gif_main_outofmem(&g, out, delays);
+ delays_size = layers * sizeof(int);
+ }
+ }
+ memcpy( out + ((layers - 1) * stride), u, stride );
+ if (layers >= 2) {
+ two_back = out - 2 * stride;
+ }
+
+ if (delays) {
+ (*delays)[layers - 1U] = g.delay;
+ }
+ }
+ } while (u != 0);
+
+ // free temp buffer;
+ STBI_FREE(g.out);
+ STBI_FREE(g.history);
+ STBI_FREE(g.background);
+
+ // do the final conversion after loading everything;
+ if (req_comp && req_comp != 4)
+ out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h);
+
+ *z = layers;
+ return out;
+ } else {
+ return stbi__errpuc("not GIF", "Image was not as a gif type.");
+ }
}
static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
{
stbi_uc *u = 0;
- stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif));
- memset(g, 0, sizeof(*g));
+ stbi__gif g;
+ memset(&g, 0, sizeof(g));
STBI_NOTUSED(ri);
- u = stbi__gif_load_next(s, g, comp, req_comp);
+ u = stbi__gif_load_next(s, &g, comp, req_comp, 0);
if (u == (stbi_uc *) s) u = 0; // end of animated gif marker
if (u) {
- *x = g->w;
- *y = g->h;
+ *x = g.w;
+ *y = g.h;
+
+ // moved conversion to after successful load so that the same
+ // can be done for multiple frames.
if (req_comp && req_comp != 4)
- u = stbi__convert_format(u, 4, req_comp, g->w, g->h);
+ u = stbi__convert_format(u, 4, req_comp, g.w, g.h);
+ } else if (g.out) {
+ // if there was an error and we allocated an image buffer, free it!
+ STBI_FREE(g.out);
}
- else if (g->out)
- STBI_FREE(g->out);
- STBI_FREE(g);
+
+ // free buffers needed for multiple frame loading;
+ STBI_FREE(g.history);
+ STBI_FREE(g.background);
+
return u;
}
@@ -6508,6 +7116,9 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re
token += 3;
width = (int) strtol(token, NULL, 10);
+ if (height > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)");
+ if (width > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)");
+
*x = width;
*y = height;
@@ -6650,12 +7261,18 @@ static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp)
info.all_a = 255;
p = stbi__bmp_parse_header(s, &info);
- stbi__rewind( s );
- if (p == NULL)
+ if (p == NULL) {
+ stbi__rewind( s );
return 0;
+ }
if (x) *x = s->img_x;
if (y) *y = s->img_y;
- if (comp) *comp = info.ma ? 4 : 3;
+ if (comp) {
+ if (info.bpp == 24 && info.ma == 0xff000000)
+ *comp = 3;
+ else
+ *comp = info.ma ? 4 : 3;
+ }
return 1;
}
#endif
@@ -6663,7 +7280,7 @@ static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp)
#ifndef STBI_NO_PSD
static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp)
{
- int channelCount, dummy;
+ int channelCount, dummy, depth;
if (!x) x = &dummy;
if (!y) y = &dummy;
if (!comp) comp = &dummy;
@@ -6683,7 +7300,8 @@ static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp)
}
*y = stbi__get32be(s);
*x = stbi__get32be(s);
- if (stbi__get16be(s) != 8) {
+ depth = stbi__get16be(s);
+ if (depth != 8 && depth != 16) {
stbi__rewind( s );
return 0;
}
@@ -6694,6 +7312,33 @@ static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp)
*comp = 4;
return 1;
}
+
+static int stbi__psd_is16(stbi__context *s)
+{
+ int channelCount, depth;
+ if (stbi__get32be(s) != 0x38425053) {
+ stbi__rewind( s );
+ return 0;
+ }
+ if (stbi__get16be(s) != 1) {
+ stbi__rewind( s );
+ return 0;
+ }
+ stbi__skip(s, 6);
+ channelCount = stbi__get16be(s);
+ if (channelCount < 0 || channelCount > 16) {
+ stbi__rewind( s );
+ return 0;
+ }
+ STBI_NOTUSED(stbi__get32be(s));
+ STBI_NOTUSED(stbi__get32be(s));
+ depth = stbi__get16be(s);
+ if (depth != 16) {
+ stbi__rewind( s );
+ return 0;
+ }
+ return 1;
+}
#endif
#ifndef STBI_NO_PIC
@@ -6765,7 +7410,6 @@ 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
#ifndef STBI_NO_PNM
@@ -6786,19 +7430,23 @@ static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req
stbi_uc *out;
STBI_NOTUSED(ri);
- if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n))
+ ri->bits_per_channel = stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n);
+ if (ri->bits_per_channel == 0)
return 0;
+ if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+ if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)");
+
*x = s->img_x;
*y = s->img_y;
if (comp) *comp = s->img_n;
- if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0))
+ if (!stbi__mad4sizes_valid(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0))
return stbi__errpuc("too large", "PNM too large");
- out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0);
+ out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0);
if (!out) return stbi__errpuc("outofmem", "Out of memory");
- stbi__getn(s, out, s->img_n * s->img_x * s->img_y);
+ stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8));
if (req_comp && req_comp != s->img_n) {
out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y);
@@ -6874,11 +7522,19 @@ static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp)
stbi__pnm_skip_whitespace(s, &c);
maxv = stbi__pnm_getinteger(s, &c); // read max value
-
- if (maxv > 255)
- return stbi__err("max value > 255", "PPM image not 8-bit");
+ if (maxv > 65535)
+ return stbi__err("max value > 65535", "PPM image supports only 8-bit and 16-bit images");
+ else if (maxv > 255)
+ return 16;
else
- return 1;
+ return 8;
+}
+
+static int stbi__pnm_is16(stbi__context *s)
+{
+ if (stbi__pnm_info(s, NULL, NULL, NULL) == 16)
+ return 1;
+ return 0;
}
#endif
@@ -6924,6 +7580,22 @@ static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp)
return stbi__err("unknown image type", "Image not of any known type, or corrupt");
}
+static int stbi__is_16_main(stbi__context *s)
+{
+ #ifndef STBI_NO_PNG
+ if (stbi__png_is16(s)) return 1;
+ #endif
+
+ #ifndef STBI_NO_PSD
+ if (stbi__psd_is16(s)) return 1;
+ #endif
+
+ #ifndef STBI_NO_PNM
+ if (stbi__pnm_is16(s)) return 1;
+ #endif
+ return 0;
+}
+
#ifndef STBI_NO_STDIO
STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp)
{
@@ -6945,6 +7617,27 @@ STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp)
fseek(f,pos,SEEK_SET);
return r;
}
+
+STBIDEF int stbi_is_16_bit(char const *filename)
+{
+ FILE *f = stbi__fopen(filename, "rb");
+ int result;
+ if (!f) return stbi__err("can't fopen", "Unable to open file");
+ result = stbi_is_16_bit_from_file(f);
+ fclose(f);
+ return result;
+}
+
+STBIDEF int stbi_is_16_bit_from_file(FILE *f)
+{
+ int r;
+ stbi__context s;
+ long pos = ftell(f);
+ stbi__start_file(&s, f);
+ r = stbi__is_16_main(&s);
+ fseek(f,pos,SEEK_SET);
+ return r;
+}
#endif // !STBI_NO_STDIO
STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp)
@@ -6961,10 +7654,38 @@ STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int
return stbi__info_main(&s,x,y,comp);
}
+STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len)
+{
+ stbi__context s;
+ stbi__start_mem(&s,buffer,len);
+ return stbi__is_16_main(&s);
+}
+
+STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user)
+{
+ stbi__context s;
+ stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user);
+ return stbi__is_16_main(&s);
+}
+
#endif // STB_IMAGE_IMPLEMENTATION
/*
revision history:
+ 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs
+ 2.19 (2018-02-11) fix warning
+ 2.18 (2018-01-30) fix warnings
+ 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug
+ 1-bit BMP
+ *_is_16_bit api
+ avoid warnings
+ 2.16 (2017-07-23) all functions have 16-bit variants;
+ STBI_NO_STDIO works again;
+ compilation fixes;
+ fix rounding in unpremultiply;
+ optimize vertical flip;
+ disable raw_len validation;
+ documentation fixes
2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode;
warning fixes; disable run-time SSE detection on gcc;
uniform handling of optional "return" values;