From ff367bdb577dcd04dbe5803fb28056de8fa869dc Mon Sep 17 00:00:00 2001 From: LaurentGom Date: Sat, 31 Jul 2010 14:06:30 +0000 Subject: [PATCH] Now using stb_image directly for loading image files, instead of SOIL (which is not maintained anymore) git-svn-id: https://sfml.svn.sourceforge.net/svnroot/sfml/branches/sfml2@1542 4e206d99-4929-0410-ac5d-dfc041789085 --- build/codeblocks/SFML.workspace | 4 +- build/codeblocks/batch-build/build.bat | 2 - build/codeblocks/sfml-graphics.cbp | 5 - build/make/Makefile.graphics | 8 +- build/vc2005/sfml-graphics.vcproj | 20 +- build/vc2008/sfml-graphics.vcproj | 20 +- extlibs/headers/SOIL/SOIL.h | 151 - extlibs/libs-mingw/libsoil.a | Bin 85500 -> 0 bytes extlibs/libs-vc2005/soil.lib | Bin 90964 -> 0 bytes include/SFML/Graphics/Image.hpp | 14 +- src/SFML/Graphics/ImageLoader.cpp | 154 +- src/SFML/Graphics/ImageLoader.hpp | 13 - src/SFML/Graphics/stb_image/stb_image.h | 4918 +++++++++++++++++ src/SFML/Graphics/stb_image/stb_image_write.h | 504 ++ 14 files changed, 5502 insertions(+), 311 deletions(-) delete mode 100644 extlibs/headers/SOIL/SOIL.h delete mode 100644 extlibs/libs-mingw/libsoil.a delete mode 100644 extlibs/libs-vc2005/soil.lib create mode 100644 src/SFML/Graphics/stb_image/stb_image.h create mode 100644 src/SFML/Graphics/stb_image/stb_image_write.h diff --git a/build/codeblocks/SFML.workspace b/build/codeblocks/SFML.workspace index e60f353a..49c0814b 100644 --- a/build/codeblocks/SFML.workspace +++ b/build/codeblocks/SFML.workspace @@ -1,10 +1,10 @@ - + - + diff --git a/build/codeblocks/batch-build/build.bat b/build/codeblocks/batch-build/build.bat index fbbeaff7..9873e45e 100644 --- a/build/codeblocks/batch-build/build.bat +++ b/build/codeblocks/batch-build/build.bat @@ -63,8 +63,6 @@ echo Adding external libraries to libsfml-graphics-s... ar x %SFML%\extlibs\libs-mingw\libfreetype.a ar x %SFML%\extlibs\libs-mingw\libglew.a ar x %SFML%\extlibs\libs-mingw\libjpeg.a -ar x %SFML%\extlibs\libs-mingw\libpng.a -ar x %SFML%\extlibs\libs-mingw\libsoil.a ar rs libsfml-graphics-s.a *.o ar rs libsfml-graphics-s-d.a *.o del *.o /f /q diff --git a/build/codeblocks/sfml-graphics.cbp b/build/codeblocks/sfml-graphics.cbp index ffdaee78..91899112 100644 --- a/build/codeblocks/sfml-graphics.cbp +++ b/build/codeblocks/sfml-graphics.cbp @@ -33,8 +33,6 @@ - - @@ -67,8 +65,6 @@ - - @@ -124,7 +120,6 @@ - diff --git a/build/make/Makefile.graphics b/build/make/Makefile.graphics index 679d4fb1..dc5af67e 100644 --- a/build/make/Makefile.graphics +++ b/build/make/Makefile.graphics @@ -1,6 +1,6 @@ SRC = $(wildcard $(SRCROOT)/Graphics/*.cpp $(SRCROOT)/Graphics/Linux/*.cpp) OBJ = $(SRC:.cpp=.o) -LIB = libsfml-graphics.so +LIB = libsfml-graphics.so LIBNAME = $(LIB).$(VERSION) FULLLIBNAME = $(LIBPATH)/$(LIBNAME) LINK = $(LN) $(LNFLAGS) $(LIBNAME) $(DESTLIBDIR)/$(LIB) @@ -8,7 +8,7 @@ LINK = $(LN) $(LNFLAGS) $(LIBNAME) $(DESTLIBDIR)/$(LIB) all: $(LIB) libsfml-graphics.so: $(OBJ) - $(CPP) $(LDFLAGS) -Wl,-soname,$(LIBNAME) -o $(FULLLIBNAME) $(OBJ) -lGLEW -ljpeg -lpng -lSOIL -lfreetype -lX11 -lGL + $(CPP) $(LDFLAGS) -Wl,-soname,$(LIBNAME) -o $(FULLLIBNAME) $(OBJ) -lGLEW -ljpeg -lfreetype -lX11 -lGL $(OBJ): %.o: %.cpp $(CPP) -o $@ -c $< $(CFLAGS) -I/usr/include/freetype2 @@ -21,7 +21,7 @@ clean: mrproper: clean rm -rf $(FULLLIBNAME) -install: - objcopy --only-keep-debug $(FULLLIBNAME) $(DESTDBGDIR)/$(LIBNAME) +install: + objcopy --only-keep-debug $(FULLLIBNAME) $(DESTDBGDIR)/$(LIBNAME) objcopy --strip-unneeded $(FULLLIBNAME) $(DESTLIBDIR)/$(LIBNAME) $(LINK) diff --git a/build/vc2005/sfml-graphics.vcproj b/build/vc2005/sfml-graphics.vcproj index 5f0e7acf..4bc2e1bc 100644 --- a/build/vc2005/sfml-graphics.vcproj +++ b/build/vc2005/sfml-graphics.vcproj @@ -49,7 +49,7 @@ @@ -315,7 +315,7 @@ EnableIntrinsicFunctions="true" FavorSizeOrSpeed="1" WholeProgramOptimization="false" - AdditionalIncludeDirectories=""$(SolutionDir)..\..\include";"$(SolutionDir)..\..\src";"$(SolutionDir)..\..\extlibs\headers";"$(SolutionDir)..\..\extlibs\headers\jpeg";"$(SolutionDir)..\..\extlibs\headers\png"" + AdditionalIncludeDirectories=""$(SolutionDir)..\..\include";"$(SolutionDir)..\..\src";"$(SolutionDir)..\..\extlibs\headers";"$(SolutionDir)..\..\extlibs\headers\jpeg"" PreprocessorDefinitions="NDEBUG;WIN32;_LIB;SFML_EXPORTS;GLEW_STATIC;STBI_FAILURE_USERMSG" StringPooling="true" MinimalRebuild="false" @@ -340,7 +340,7 @@ /> @@ -488,6 +488,7 @@ > @@ -496,6 +497,7 @@ > @@ -504,6 +506,7 @@ > @@ -512,6 +515,7 @@ > diff --git a/build/vc2008/sfml-graphics.vcproj b/build/vc2008/sfml-graphics.vcproj index 16f0a0a0..926121b8 100644 --- a/build/vc2008/sfml-graphics.vcproj +++ b/build/vc2008/sfml-graphics.vcproj @@ -51,7 +51,7 @@ Name="VCCLCompilerTool" AdditionalOptions="/MP" Optimization="0" - AdditionalIncludeDirectories=""$(SolutionDir)..\..\src";"$(SolutionDir)..\..\include";"$(SolutionDir)..\..\extlibs\headers";"$(SolutionDir)..\..\extlibs\headers\jpeg";"$(SolutionDir)..\..\extlibs\headers\png"" + AdditionalIncludeDirectories=""$(SolutionDir)..\..\src";"$(SolutionDir)..\..\include";"$(SolutionDir)..\..\extlibs\headers";"$(SolutionDir)..\..\extlibs\headers\jpeg"" PreprocessorDefinitions="WIN32;_DEBUG;_LIB;SFML_EXPORTS;SFML_DYNAMIC;GLEW_STATIC" MinimalRebuild="false" BasicRuntimeChecks="3" @@ -72,7 +72,7 @@ /> @@ -316,7 +316,7 @@ EnableIntrinsicFunctions="true" FavorSizeOrSpeed="1" WholeProgramOptimization="false" - AdditionalIncludeDirectories=""$(SolutionDir)..\..\src";"$(SolutionDir)..\..\include";"$(SolutionDir)..\..\extlibs\headers";"$(SolutionDir)..\..\extlibs\headers\jpeg";"$(SolutionDir)..\..\extlibs\headers\png"" + AdditionalIncludeDirectories=""$(SolutionDir)..\..\src";"$(SolutionDir)..\..\include";"$(SolutionDir)..\..\extlibs\headers";"$(SolutionDir)..\..\extlibs\headers\jpeg"" PreprocessorDefinitions="NDEBUG;WIN32;_LIB;SFML_EXPORTS;GLEW_STATIC;STBI_FAILURE_USERMSG" StringPooling="true" RuntimeLibrary="2" @@ -340,7 +340,7 @@ /> @@ -488,6 +488,7 @@ > @@ -496,6 +497,7 @@ > @@ -504,6 +506,7 @@ > @@ -512,6 +515,7 @@ > diff --git a/extlibs/headers/SOIL/SOIL.h b/extlibs/headers/SOIL/SOIL.h deleted file mode 100644 index 4e049d35..00000000 --- a/extlibs/headers/SOIL/SOIL.h +++ /dev/null @@ -1,151 +0,0 @@ -/** - @mainpage SOIL - - Jonathan Dummer - 2007-07-26-10.36 - - Simple OpenGL Image Library - - A tiny c library for uploading images as - textures into OpenGL. Also saving and - loading of images is supported. - - I'm using Sean's Tool Box image loader as a base: - http://www.nothings.org/ - - I'm upgrading it to load TGA and DDS files, and a direct - path for loading DDS files straight into OpenGL textures, - when applicable. - - Image Formats: - - BMP load & save - - TGA load & save - - DDS load & save - - PNG load - - JPG load - - OpenGL Texture Features: - - resample to power-of-two sizes - - MIPmap generation - - compressed texture S3TC formats (if supported) - - can pre-multiply alpha for you, for better compositing - - can flip image about the y-axis (except pre-compressed DDS files) - - Thanks to: - * Sean Barret - for the awesome stb_image - * Dan Venkitachalam - for finding some non-compliant DDS files, and patching some explicit casts - * everybody at gamedev.net -**/ - -#ifndef HEADER_SIMPLE_OPENGL_IMAGE_LIBRARY -#define HEADER_SIMPLE_OPENGL_IMAGE_LIBRARY - -#ifdef __cplusplus -extern "C" { -#endif - -/** - The format of images that may be loaded (force_channels). - SOIL_LOAD_AUTO leaves the image in whatever format it was found. - SOIL_LOAD_L forces the image to load as Luminous (greyscale) - SOIL_LOAD_LA forces the image to load as Luminous with Alpha - SOIL_LOAD_RGB forces the image to load as Red Green Blue - SOIL_LOAD_RGBA forces the image to load as Red Green Blue Alpha -**/ -enum -{ - SOIL_LOAD_AUTO = 0, - SOIL_LOAD_L = 1, - SOIL_LOAD_LA = 2, - SOIL_LOAD_RGB = 3, - SOIL_LOAD_RGBA = 4 -}; - -/** - The types of images that may be saved. - (TGA supports uncompressed RGB / RGBA) - (BMP supports uncompressed RGB) - (DDS supports DXT1 and DXT5) -**/ -enum -{ - SOIL_SAVE_TYPE_TGA = 0, - SOIL_SAVE_TYPE_BMP = 1, - SOIL_SAVE_TYPE_DDS = 2 -}; -/** - Loads an image from disk into an array of unsigned chars. - Note that *channels return the original channel count of the - image. If force_channels was other than SOIL_LOAD_AUTO, - the resulting image has force_channels, but *channels may be - different (if the original image had a different channel - count). - \return 0 if failed, otherwise returns 1 -**/ -unsigned char* - SOIL_load_image - ( - const char *filename, - int *width, int *height, int *channels, - int force_channels - ); - -/** - Loads an image from memory into an array of unsigned chars. - Note that *channels return the original channel count of the - image. If force_channels was other than SOIL_LOAD_AUTO, - the resulting image has force_channels, but *channels may be - different (if the original image had a different channel - count). - \return 0 if failed, otherwise returns 1 -**/ -unsigned char* - SOIL_load_image_from_memory - ( - const unsigned char *const buffer, - int buffer_length, - int *width, int *height, int *channels, - int force_channels - ); - -/** - Saves an image from an array of unsigned chars (RGBA) to disk - \return 0 if failed, otherwise returns 1 -**/ -int - SOIL_save_image - ( - const char *filename, - int image_type, - int width, int height, int channels, - const unsigned char *const data - ); - -/** - Frees the image data (note, this is just C's "free()"...this function is - present mostly so C++ programmers don't forget to use "free()" and call - "delete []" instead [8^) -**/ -void - SOIL_free_image_data - ( - unsigned char *img_data - ); - -/** - This function resturn a pointer to a string describing the last thing - that happened inside SOIL. It can be used to determine why an image - failed to load. -**/ -const char* - SOIL_last_result - ( - void - ); - - -#ifdef __cplusplus -} -#endif - -#endif /* HEADER_SIMPLE_OPENGL_IMAGE_LIBRARY */ diff --git a/extlibs/libs-mingw/libsoil.a b/extlibs/libs-mingw/libsoil.a deleted file mode 100644 index a93ed88b43319553b85490ceb55dc5847ca5e16d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 85500 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 F{@*~-B6|P; diff --git a/include/SFML/Graphics/Image.hpp b/include/SFML/Graphics/Image.hpp index 2ec14a9d..55bb70bc 100644 --- a/include/SFML/Graphics/Image.hpp +++ b/include/SFML/Graphics/Image.hpp @@ -74,9 +74,9 @@ public : //////////////////////////////////////////////////////////// /// \brief Load the image from a file on disk /// - /// The supported image formats are bmp, png, tga, jpg, dds - /// and psd. Some format options are not supported, like - /// progressive jpeg. + /// The supported image formats are bmp, png, tga, jpg, gif, + /// psd, hdr and pic. Some format options are not supported, + /// like progressive jpeg. /// The maximum size for an image depends on the graphics /// driver and can be retrieve with the GetMaximumSize function. /// @@ -92,9 +92,9 @@ public : //////////////////////////////////////////////////////////// /// \brief Load the image from a file in memory /// - /// The supported image formats are bmp, png, tga, jpg, dds - /// and psd. Some format options are not supported, like - /// progressive jpeg. + /// The supported image formats are bmp, png, tga, jpg, gif, + /// psd, hdr and pic. Some format options are not supported, + /// like progressive jpeg. /// The maximum size for an image depends on the graphics /// driver and can be retrieve with the GetMaximumSize function. /// @@ -133,7 +133,7 @@ public : /// /// The format of the image is automatically deduced from /// the extension. The supported image formats are bmp, png, - /// tga, jpg, dds and psd. The destination file is overwritten + /// tga and jpg. The destination file is overwritten /// if it already exists. /// /// \param filename Path of the file to save diff --git a/src/SFML/Graphics/ImageLoader.cpp b/src/SFML/Graphics/ImageLoader.cpp index c8149ec9..6d5cd1be 100644 --- a/src/SFML/Graphics/ImageLoader.cpp +++ b/src/SFML/Graphics/ImageLoader.cpp @@ -27,26 +27,27 @@ //////////////////////////////////////////////////////////// #include #include +#include +#define STB_IMAGE_WRITE_IMPLEMENTATION +#include extern "C" { #include #include } -#include -#include +#include -// For compatibility with versions of libpng < 1.4.0 -#ifndef png_jmpbuf - #define png_jmpbuf(png) png->jmpbuf -#endif namespace { //////////////////////////////////////////////////////////// - void PngErrorHandler(png_structp png, png_const_charp message) + std::string ToLower(const std::string& str) { - sf::Err() << "Failed to write PNG image. Reason : " << message << std::endl; - longjmp(png_jmpbuf(png), 1); + std::string lower = str; + for (std::string::iterator it = lower.begin(); it != lower.end(); ++it) + *it = static_cast(tolower(*it)); + + return str; } } @@ -86,7 +87,7 @@ bool ImageLoader::LoadImageFromFile(const std::string& filename, std::vector(data); - unsigned char* ptr = SOIL_load_image_from_memory(buffer, static_cast(size), &imgWidth, &imgHeight, &imgChannels, SOIL_LOAD_RGBA); + unsigned char* ptr = stbi_load_from_memory(buffer, static_cast(size), &imgWidth, &imgHeight, &imgChannels, STBI_rgb_alpha); if (ptr) { @@ -135,14 +136,14 @@ bool ImageLoader::LoadImageFromMemory(const void* data, std::size_t size, std::v memcpy(&pixels[0], ptr, pixels.size()); // Free the loaded pixels (they are now in our own pixel buffer) - SOIL_free_image_data(ptr); + stbi_image_free(ptr); return true; } else { // Error, failed to load the image - Err() << "Failed to load image from memory. Reason : " << SOIL_last_result() << std::endl; + Err() << "Failed to load image from memory. Reason : " << stbi_failure_reason() << std::endl; return false; } @@ -153,35 +154,39 @@ bool ImageLoader::LoadImageFromMemory(const void* data, std::size_t size, std::v bool ImageLoader::SaveImageToFile(const std::string& filename, const std::vector& pixels, unsigned int width, unsigned int height) { // Deduce the image type from its extension - int type = -1; if (filename.size() > 3) { + // Extract the extension std::string extension = filename.substr(filename.size() - 3); - if (extension == "bmp" || extension == "BMP") type = SOIL_SAVE_TYPE_BMP; - else if (extension == "tga" || extension == "TGA") type = SOIL_SAVE_TYPE_TGA; - else if (extension == "dds" || extension == "DDS") type = SOIL_SAVE_TYPE_DDS; - // Special handling for PNG and JPG -- not handled by SOIL - else if (extension == "png" || extension == "PNG") return WritePng(filename, pixels, width, height); - else if (extension == "jpg" || extension == "JPG") return WriteJpg(filename, pixels, width, height); + if (ToLower(extension) == "bmp") + { + // BMP format + if (stbi_write_bmp(filename.c_str(), width, height, 4, &pixels[0])) + return true; + } + else if (ToLower(extension) == "tga") + { + // TGA format + if (stbi_write_tga(filename.c_str(), width, height, 4, &pixels[0])) + return true; + } + else if(ToLower(extension) == "png") + { + // PNG format + if (stbi_write_png(filename.c_str(), width, height, 4, &pixels[0], 0)) + return true; + } + else if (ToLower(extension) == "jpg") + { + // JPG format + if (WriteJpg(filename, pixels, width, height)) + return true; + } } - if (type == -1) - { - // Error, incompatible type - Err() << "Failed to save image \"" << filename << "\". Reason: this image format is not supported" << std::endl; - return false; - } - - // Finally save the image - if (!SOIL_save_image(filename.c_str(), type, static_cast(width), static_cast(height), 4, &pixels[0])) - { - // Error, failed to save the image - Err() << "Failed to save image \"" << filename << "\". Reason: " << SOIL_last_result() << std::endl; - return false; - } - - return true; + Err() << "Failed to save image \"" << filename << "\"" << std::endl; + return false; } @@ -191,10 +196,7 @@ bool ImageLoader::WriteJpg(const std::string& filename, const std::vector // Open the file to write in FILE* file = fopen(filename.c_str(), "wb"); if (!file) - { - Err() << "Failed to save image file \"" << filename << "\". Reason : cannot open file" << std::endl; return false; - } // Initialize the error handler jpeg_compress_struct compressInfos; @@ -241,76 +243,6 @@ bool ImageLoader::WriteJpg(const std::string& filename, const std::vector return true; } - -//////////////////////////////////////////////////////////// -bool ImageLoader::WritePng(const std::string& filename, const std::vector& pixels, unsigned int width, unsigned int height) -{ - // Open the file to write in - FILE* file = fopen(filename.c_str(), "wb"); - if (!file) - { - Err() << "Failed to save image file \"" << filename << "\". Reason : cannot open file" << std::endl; - return false; - } - - // Create the main PNG structure - png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, &PngErrorHandler, NULL); - if (!png) - { - fclose(file); - Err() << "Failed to save image file \"" << filename << "\". Reason : cannot allocate PNG write structure" << std::endl; - return false; - } - - // Initialize the image informations - png_infop pngInfos = png_create_info_struct(png); - if (!pngInfos) - { - fclose(file); - png_destroy_write_struct(&png, NULL); - Err() << "Failed to save image file \"" << filename << "\". Reason : cannot allocate PNG info structure" << std::endl; - return false; - } - - // For proper error handling... - if (setjmp(png_jmpbuf(png))) - { - png_destroy_write_struct(&png, &pngInfos); - return false; - } - - // Link the file to the PNG structure - png_init_io(png, file); - - // Set the image informations - png_set_IHDR(png, pngInfos, width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - - // Write the header - png_write_info(png, pngInfos); - - // Get the pointers to the pixels rows into an array - png_byte* ptr = (png_byte*)&pixels[0]; - std::vector rawPointers(height); - for (unsigned int i = 0; i < height; ++i) - { - rawPointers[i] = ptr; - ptr += width * 4; - } - - // Write pixels row by row - png_set_rows(png, pngInfos, &rawPointers[0]); - png_write_png(png, pngInfos, PNG_TRANSFORM_IDENTITY, NULL); - - // Finish writing the file - png_write_end(png, pngInfos); - - // Cleanup resources - png_destroy_write_struct(&png, &pngInfos); - fclose(file); - - return true; -} - } // namespace priv } // namespace sf diff --git a/src/SFML/Graphics/ImageLoader.hpp b/src/SFML/Graphics/ImageLoader.hpp index f1b75e0f..581437ef 100644 --- a/src/SFML/Graphics/ImageLoader.hpp +++ b/src/SFML/Graphics/ImageLoader.hpp @@ -119,19 +119,6 @@ private : /// //////////////////////////////////////////////////////////// bool WriteJpg(const std::string& filename, const std::vector& pixels, unsigned int width, unsigned int height); - - //////////////////////////////////////////////////////////// - /// \brief Save an image file in PNG format - /// - /// \param filename Path of image file to save - /// \param pixels Array of pixels to save to image - /// \param width Width of image to save, in pixels - /// \param height Height of image to save, in pixels - /// - /// \return True if saving was successful - /// - //////////////////////////////////////////////////////////// - bool WritePng(const std::string& filename, const std::vector& pixels, unsigned int width, unsigned int height); }; } // namespace priv diff --git a/src/SFML/Graphics/stb_image/stb_image.h b/src/SFML/Graphics/stb_image/stb_image.h new file mode 100644 index 00000000..37d52698 --- /dev/null +++ b/src/SFML/Graphics/stb_image/stb_image.h @@ -0,0 +1,4918 @@ +/* stbi-1.26 - public domain JPEG/PNG reader - http://nothings.org/stb_image.c + when you control the images you're loading + no warranty implied; use at your own risk + + QUICK NOTES: + Primarily of interest to game developers and other people who can + avoid problematic images and only need the trivial interface + + JPEG baseline (no JPEG progressive) + PNG 8-bit only + + TGA (not sure what subset, if a subset) + BMP non-1bpp, non-RLE + PSD (composited view only, no extra channels) + + GIF (*comp always reports as 4-channel) + HDR (radiance rgbE format) + PIC (Softimage PIC) + + - decoded from memory or through stdio FILE (define STBI_NO_STDIO to remove code) + - supports installable dequantizing-IDCT, YCbCr-to-RGB conversion (define STBI_SIMD) + + Latest revisions: + 1.26 (2010-07-24) + fix bug in file buffering for PNG reported by SpartanJ + 1.25 (2010-07-17) + refix trans_data warning (Won Chun) + 1.24 (2010-07-12) + perf improvements reading from files on platforms with lock-heavy fgetc() + minor perf improvements for jpeg + deprecated type-specific functions so we'll get feedback if they're needed + attempt to fix trans_data warning (Won Chun) + 1.23 fixed bug in iPhone support + 1.22 (2010-07-10) + removed image *writing* support, moved to stb_image_write.h + stbi_info support from Jetro Lauha + GIF support from Jean-Marc Lienher + iPhone PNG-extensions from James Brown + warning-fixes from Nicolas Schulz and Janez Zemva (aka Janez U+017D;emva) + 1.21 fix use of 'uint8' in header (reported by jon blow) + 1.20 added support for Softimage PIC, by Tom Seddon + + See end of file for full revision history. + + TODO: + stbi_info support for BMP,PSD,HDR,PIC + rewrite stbi_info and load_file variations to share file handling code + (current system allows individual functions to be called directly, + since each does all the work, but I doubt anyone uses this in practice) + + + ============================ Contributors ========================= + + Image formats Optimizations & bugfixes + Sean Barrett (jpeg, png, bmp) Fabian "ryg" Giesen + Nicolas Schulz (hdr, psd) + Jonathan Dummer (tga) Bug fixes & warning fixes + Jean-Marc Lienher (gif) Marc LeBlanc + Tom Seddon (pic) Christpher Lloyd + Thatcher Ulrich (psd) Dave Moore + Won Chun + the Horde3D community + Extensions, features Janez Zemva + Jetro Lauha (stbi_info) Jonathan Blow + James "moose2000" Brown (iPhone PNG) + + If your name should be here but isn't, let Sean know. + +*/ + +#ifndef STBI_INCLUDE_STB_IMAGE_H +#define STBI_INCLUDE_STB_IMAGE_H + +// To get a header file for this, either cut and paste the header, +// or create stb_image.h, #define STBI_HEADER_FILE_ONLY, and +// then include stb_image.c from it. + +//// begin header file //////////////////////////////////////////////////// +// +// Limitations: +// - no jpeg progressive support +// - non-HDR formats support 8-bit samples only (jpeg, png) +// - no delayed line count (jpeg) -- IJG doesn't support either +// - no 1-bit BMP +// - GIF always returns *comp=4 +// +// Basic usage (see HDR discussion below): +// int x,y,n; +// unsigned char *data = stbi_load(filename, &x, &y, &n, 0); +// // ... process data if not NULL ... +// // ... x = width, y = height, n = # 8-bit components per pixel ... +// // ... replace '0' with '1'..'4' to force that many components per pixel +// stbi_image_free(data) +// +// Standard parameters: +// int *x -- outputs image width in pixels +// int *y -- outputs image height in pixels +// int *comp -- outputs # of image components in image file +// int req_comp -- if non-zero, # of image components requested in result +// +// The return value from an image loader is an 'unsigned char *' which points +// to the pixel data. The pixel data consists of *y scanlines of *x pixels, +// with each pixel consisting of N interleaved 8-bit components; the first +// pixel pointed to is top-left-most in the image. There is no padding between +// image scanlines or between pixels, regardless of format. The number of +// components N is 'req_comp' if req_comp is non-zero, or *comp otherwise. +// If req_comp is non-zero, *comp has the number of components that _would_ +// have been output otherwise. E.g. if you set req_comp to 4, you will always +// get RGBA output, but you can check *comp to easily see if it's opaque. +// +// An output image with N components has the following components interleaved +// in this order in each pixel: +// +// N=#comp components +// 1 grey +// 2 grey, alpha +// 3 red, green, blue +// 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 +// more user-friendly ones. +// +// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. +// +// =========================================================================== +// +// iPhone PNG support: +// +// By default we convert iphone-formatted PNGs back to RGB; nominally they +// would silently load as BGR, except the existing code should have just +// failed on such iPhone PNGs. But you can disable this conversion by +// by calling stbi_convert_iphone_png_to_rgb(0), in which case +// you will always just get the native iphone "format" through. +// +// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per +// pixel to remove any premultiplied alpha *only* if the image file explicitly +// says there's premultiplied data (currently only happens in iPhone images, +// and only if iPhone convert-to-rgb processing is on). +// +// =========================================================================== +// +// 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; +// both of these constants can be reconfigured through this interface: +// +// stbi_hdr_to_ldr_gamma(2.2f); +// stbi_hdr_to_ldr_scale(1.0f); +// +// (note, do not use _inverse_ constants; stbi_image will invert them +// appropriately). +// +// Additionally, there is a new, parallel interface for loading files as +// (linear) floats to preserve the full dynamic range: +// +// float *data = stbi_loadf(filename, &x, &y, &n, 0); +// +// If you load LDR images through this interface, those images will +// be promoted to floating point values, run through the inverse of +// constants corresponding to the above: +// +// stbi_ldr_to_hdr_scale(1.0f); +// stbi_ldr_to_hdr_gamma(2.2f); +// +// Finally, given a filename (or an open file or memory block--see header +// file for details) containing image data, you can query for the "most +// appropriate" interface to use (that is, whether the image is HDR or +// not), using: +// +// stbi_is_hdr(char *filename); + +#ifndef STBI_NO_STDIO +#include +#endif + +#define STBI_VERSION 1 + +enum +{ + STBI_default = 0, // only used for req_comp + + STBI_grey = 1, + STBI_grey_alpha = 2, + STBI_rgb = 3, + STBI_rgb_alpha = 4, +}; + +typedef unsigned char stbi_uc; + +#ifdef __cplusplus +extern "C" { +#endif + +// PRIMARY API - works on images of any type + +// load image by filename, open file, or memory buffer +extern stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); + +#ifndef STBI_NO_STDIO +extern stbi_uc *stbi_load (char const *filename, int *x, int *y, int *comp, int req_comp); +extern stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +// for stbi_load_from_file, file pointer is left pointing immediately after image +#endif + +#ifndef STBI_NO_HDR + extern float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); + + #ifndef STBI_NO_STDIO + extern float *stbi_loadf (char const *filename, int *x, int *y, int *comp, int req_comp); + extern float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); + #endif + + extern void stbi_hdr_to_ldr_gamma(float gamma); + extern void stbi_hdr_to_ldr_scale(float scale); + + extern void stbi_ldr_to_hdr_gamma(float gamma); + extern void stbi_ldr_to_hdr_scale(float scale); +#endif // STBI_NO_HDR + +// get a VERY brief reason for failure +// NOT THREADSAFE +extern const char *stbi_failure_reason (void); + +// free the loaded image -- this is just free() +extern void stbi_image_free (void *retval_from_stbi_load); + +// get image dimensions & components without fully decoding +extern int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); +extern int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); + +#ifndef STBI_NO_STDIO +extern int stbi_info (char const *filename, int *x, int *y, int *comp); +extern int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); + +extern int stbi_is_hdr (char const *filename); +extern int stbi_is_hdr_from_file(FILE *f); +#endif + +// for image formats that explicitly notate that they have premultiplied alpha, +// we just return the colors as stored in the file. set this flag to force +// unpremultiplication. results are undefined if the unpremultiply overflow. +extern void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); + +// indicate whether we should process iphone images back to canonical format, +// or just pass them through "as-is" +extern void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); + + +// ZLIB client - used by PNG, available for other purposes + +extern char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); +extern char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); +extern int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + +extern char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); +extern int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + +// define new loaders +typedef struct +{ + int (*test_memory)(stbi_uc const *buffer, int len); + stbi_uc * (*load_from_memory)(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); + #ifndef STBI_NO_STDIO + int (*test_file)(FILE *f); + stbi_uc * (*load_from_file)(FILE *f, int *x, int *y, int *comp, int req_comp); + #endif +} stbi_loader; + +// register a loader by filling out the above structure (you must define ALL functions) +// returns 1 if added or already added, 0 if not added (too many loaders) +// NOT THREADSAFE +extern int stbi_register_loader(stbi_loader *loader); + +// define faster low-level operations (typically SIMD support) +#if STBI_SIMD +typedef void (*stbi_idct_8x8)(stbi_uc *out, int out_stride, short data[64], unsigned short *dequantize); +// compute an integer IDCT on "input" +// input[x] = data[x] * dequantize[x] +// write results to 'out': 64 samples, each run of 8 spaced by 'out_stride' +// CLAMP results to 0..255 +typedef void (*stbi_YCbCr_to_RGB_run)(stbi_uc *output, stbi_uc const *y, stbi_uc const *cb, stbi_uc const *cr, int count, int step); +// compute a conversion from YCbCr to RGB +// 'count' pixels +// write pixels to 'output'; each pixel is 'step' bytes (either 3 or 4; if 4, write '255' as 4th), order R,G,B +// y: Y input channel +// cb: Cb input channel; scale/biased to be 0..255 +// cr: Cr input channel; scale/biased to be 0..255 + +extern void stbi_install_idct(stbi_idct_8x8 func); +extern void stbi_install_YCbCr_to_RGB(stbi_YCbCr_to_RGB_run func); +#endif // STBI_SIMD + + + + +// TYPE-SPECIFIC ACCESS + +#ifdef STBI_TYPE_SPECIFIC_FUNCTIONS + +// is it a jpeg? +extern int stbi_jpeg_test_memory (stbi_uc const *buffer, int len); +extern stbi_uc *stbi_jpeg_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +extern int stbi_jpeg_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); + +#ifndef STBI_NO_STDIO +extern stbi_uc *stbi_jpeg_load (char const *filename, int *x, int *y, int *comp, int req_comp); +extern int stbi_jpeg_test_file (FILE *f); +extern stbi_uc *stbi_jpeg_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); + +extern int stbi_jpeg_info (char const *filename, int *x, int *y, int *comp); +extern int stbi_jpeg_info_from_file (FILE *f, int *x, int *y, int *comp); +#endif + +// is it a png? +extern int stbi_png_test_memory (stbi_uc const *buffer, int len); +extern stbi_uc *stbi_png_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +extern int stbi_png_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp); + +#ifndef STBI_NO_STDIO +extern stbi_uc *stbi_png_load (char const *filename, int *x, int *y, int *comp, int req_comp); +extern int stbi_png_info (char const *filename, int *x, int *y, int *comp); +extern int stbi_png_test_file (FILE *f); +extern stbi_uc *stbi_png_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +extern int stbi_png_info_from_file (FILE *f, int *x, int *y, int *comp); +#endif + +// is it a bmp? +extern int stbi_bmp_test_memory (stbi_uc const *buffer, int len); + +extern stbi_uc *stbi_bmp_load (char const *filename, int *x, int *y, int *comp, int req_comp); +extern stbi_uc *stbi_bmp_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +#ifndef STBI_NO_STDIO +extern int stbi_bmp_test_file (FILE *f); +extern stbi_uc *stbi_bmp_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +#endif + +// is it a tga? +extern int stbi_tga_test_memory (stbi_uc const *buffer, int len); + +extern stbi_uc *stbi_tga_load (char const *filename, int *x, int *y, int *comp, int req_comp); +extern stbi_uc *stbi_tga_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +#ifndef STBI_NO_STDIO +extern int stbi_tga_test_file (FILE *f); +extern stbi_uc *stbi_tga_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +#endif + +// is it a psd? +extern int stbi_psd_test_memory (stbi_uc const *buffer, int len); + +extern stbi_uc *stbi_psd_load (char const *filename, int *x, int *y, int *comp, int req_comp); +extern stbi_uc *stbi_psd_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +#ifndef STBI_NO_STDIO +extern int stbi_psd_test_file (FILE *f); +extern stbi_uc *stbi_psd_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +#endif + +// is it an hdr? +extern int stbi_hdr_test_memory (stbi_uc const *buffer, int len); + +extern float * stbi_hdr_load (char const *filename, int *x, int *y, int *comp, int req_comp); +extern float * stbi_hdr_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +#ifndef STBI_NO_STDIO +extern int stbi_hdr_test_file (FILE *f); +extern float * stbi_hdr_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +#endif + +// is it a pic? +extern int stbi_pic_test_memory (stbi_uc const *buffer, int len); + +extern stbi_uc *stbi_pic_load (char const *filename, int *x, int *y, int *comp, int req_comp); +extern stbi_uc *stbi_pic_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +#ifndef STBI_NO_STDIO +extern int stbi_pic_test_file (FILE *f); +extern stbi_uc *stbi_pic_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +#endif + +// is it a gif? +extern int stbi_gif_test_memory (stbi_uc const *buffer, int len); + +extern stbi_uc *stbi_gif_load (char const *filename, int *x, int *y, int *comp, int req_comp); +extern stbi_uc *stbi_gif_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +extern int stbi_gif_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp); + +#ifndef STBI_NO_STDIO +extern int stbi_gif_test_file (FILE *f); +extern stbi_uc *stbi_gif_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +extern int stbi_gif_info (char const *filename, int *x, int *y, int *comp); +extern int stbi_gif_info_from_file (FILE *f, int *x, int *y, int *comp); +#endif + +#endif//STBI_TYPE_SPECIFIC_FUNCTIONS + + + + +#ifdef __cplusplus +} +#endif + +// +// +//// end header file ///////////////////////////////////////////////////// +#endif // STBI_INCLUDE_STB_IMAGE_H + +#ifndef STBI_HEADER_FILE_ONLY + +#ifndef STBI_NO_HDR +#include // ldexp +#include // strcmp +#endif + +#ifndef STBI_NO_STDIO +#include +#endif +#include +#include +#include +#include + +#ifndef _MSC_VER + #ifdef __cplusplus + #define __forceinline inline + #else + #define __forceinline + #endif +#endif + + +// implementation: +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef signed short int16; +typedef unsigned int uint32; +typedef signed int int32; +typedef unsigned int uint; + +// should produce compiler error if size is wrong +typedef unsigned char validate_uint32[sizeof(uint32)==4 ? 1 : -1]; + +#if defined(STBI_NO_STDIO) && !defined(STBI_NO_WRITE) +#define STBI_NO_WRITE +#endif + +#define STBI_NOTUSED(v) v=v + +#ifdef _MSC_VER +#define STBI_HAS_LRTOL +#endif + +#ifdef STBI_HAS_LRTOL + #define stbi_lrot(x,y) _lrotl(x,y) +#else + #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// Generic API that works on all image types +// + +// deprecated functions + +// is it a jpeg? +extern int stbi_jpeg_test_memory (stbi_uc const *buffer, int len); +extern stbi_uc *stbi_jpeg_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +extern int stbi_jpeg_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); + +#ifndef STBI_NO_STDIO +extern stbi_uc *stbi_jpeg_load (char const *filename, int *x, int *y, int *comp, int req_comp); +extern int stbi_jpeg_test_file (FILE *f); +extern stbi_uc *stbi_jpeg_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); + +extern int stbi_jpeg_info (char const *filename, int *x, int *y, int *comp); +extern int stbi_jpeg_info_from_file (FILE *f, int *x, int *y, int *comp); +#endif + +// is it a png? +extern int stbi_png_test_memory (stbi_uc const *buffer, int len); +extern stbi_uc *stbi_png_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +extern int stbi_png_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp); + +#ifndef STBI_NO_STDIO +extern stbi_uc *stbi_png_load (char const *filename, int *x, int *y, int *comp, int req_comp); +extern int stbi_png_info (char const *filename, int *x, int *y, int *comp); +extern int stbi_png_test_file (FILE *f); +extern stbi_uc *stbi_png_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +extern int stbi_png_info_from_file (FILE *f, int *x, int *y, int *comp); +#endif + +// is it a bmp? +extern int stbi_bmp_test_memory (stbi_uc const *buffer, int len); + +extern stbi_uc *stbi_bmp_load (char const *filename, int *x, int *y, int *comp, int req_comp); +extern stbi_uc *stbi_bmp_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +#ifndef STBI_NO_STDIO +extern int stbi_bmp_test_file (FILE *f); +extern stbi_uc *stbi_bmp_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +#endif + +// is it a tga? +extern int stbi_tga_test_memory (stbi_uc const *buffer, int len); + +extern stbi_uc *stbi_tga_load (char const *filename, int *x, int *y, int *comp, int req_comp); +extern stbi_uc *stbi_tga_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +#ifndef STBI_NO_STDIO +extern int stbi_tga_test_file (FILE *f); +extern stbi_uc *stbi_tga_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +#endif + +// is it a psd? +extern int stbi_psd_test_memory (stbi_uc const *buffer, int len); + +extern stbi_uc *stbi_psd_load (char const *filename, int *x, int *y, int *comp, int req_comp); +extern stbi_uc *stbi_psd_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +#ifndef STBI_NO_STDIO +extern int stbi_psd_test_file (FILE *f); +extern stbi_uc *stbi_psd_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +#endif + +// is it an hdr? +extern int stbi_hdr_test_memory (stbi_uc const *buffer, int len); + +extern float * stbi_hdr_load (char const *filename, int *x, int *y, int *comp, int req_comp); +extern float * stbi_hdr_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +#ifndef STBI_NO_STDIO +extern int stbi_hdr_test_file (FILE *f); +extern float * stbi_hdr_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +#endif + +// is it a pic? +extern int stbi_pic_test_memory (stbi_uc const *buffer, int len); + +extern stbi_uc *stbi_pic_load (char const *filename, int *x, int *y, int *comp, int req_comp); +extern stbi_uc *stbi_pic_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +#ifndef STBI_NO_STDIO +extern int stbi_pic_test_file (FILE *f); +extern stbi_uc *stbi_pic_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +#endif + +// is it a gif? +extern int stbi_gif_test_memory (stbi_uc const *buffer, int len); + +extern stbi_uc *stbi_gif_load (char const *filename, int *x, int *y, int *comp, int req_comp); +extern stbi_uc *stbi_gif_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp); +extern int stbi_gif_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp); + +#ifndef STBI_NO_STDIO +extern int stbi_gif_test_file (FILE *f); +extern stbi_uc *stbi_gif_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp); +extern int stbi_gif_info (char const *filename, int *x, int *y, int *comp); +extern int stbi_gif_info_from_file (FILE *f, int *x, int *y, int *comp); +#endif + + +// this is not threadsafe +static const char *failure_reason; + +const char *stbi_failure_reason(void) +{ + return failure_reason; +} + +static int e(const char *str) +{ + failure_reason = str; + return 0; +} + +#ifdef STBI_NO_FAILURE_STRINGS + #define e(x,y) 0 +#elif defined(STBI_FAILURE_USERMSG) + #define e(x,y) e(y) +#else + #define e(x,y) e(x) +#endif + +#define epf(x,y) ((float *) (e(x,y)?NULL:NULL)) +#define epuc(x,y) ((unsigned char *) (e(x,y)?NULL:NULL)) + +void stbi_image_free(void *retval_from_stbi_load) +{ + free(retval_from_stbi_load); +} + +#define MAX_LOADERS 32 +stbi_loader *loaders[MAX_LOADERS]; +static int max_loaders = 0; + +int stbi_register_loader(stbi_loader *loader) +{ + int i; + for (i=0; i < MAX_LOADERS; ++i) { + // already present? + if (loaders[i] == loader) + return 1; + // end of the list? + if (loaders[i] == NULL) { + loaders[i] = loader; + max_loaders = i+1; + return 1; + } + } + // no room for it + return 0; +} + +#ifndef STBI_NO_HDR +static float *ldr_to_hdr(stbi_uc *data, int x, int y, int comp); +static stbi_uc *hdr_to_ldr(float *data, int x, int y, int comp); +#endif + +#ifndef STBI_NO_STDIO +unsigned char *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = fopen(filename, "rb"); + unsigned char *result; + if (!f) return epuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +unsigned char *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + int i; + if (stbi_jpeg_test_file(f)) return stbi_jpeg_load_from_file(f,x,y,comp,req_comp); + if (stbi_png_test_file(f)) return stbi_png_load_from_file(f,x,y,comp,req_comp); + if (stbi_bmp_test_file(f)) return stbi_bmp_load_from_file(f,x,y,comp,req_comp); + if (stbi_gif_test_file(f)) return stbi_gif_load_from_file(f,x,y,comp,req_comp); + if (stbi_psd_test_file(f)) return stbi_psd_load_from_file(f,x,y,comp,req_comp); + if (stbi_pic_test_file(f)) return stbi_pic_load_from_file(f,x,y,comp,req_comp); + + #ifndef STBI_NO_HDR + if (stbi_hdr_test_file(f)) { + float *hdr = stbi_hdr_load_from_file(f, x,y,comp,req_comp); + return hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); + } + #endif + + for (i=0; i < max_loaders; ++i) + if (loaders[i]->test_file(f)) + return loaders[i]->load_from_file(f,x,y,comp,req_comp); + // test tga last because it's a crappy test! + if (stbi_tga_test_file(f)) + return stbi_tga_load_from_file(f,x,y,comp,req_comp); + return epuc("unknown image type", "Image not of any known type, or corrupt"); +} +#endif + +unsigned char *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + int i; + if (stbi_jpeg_test_memory(buffer,len)) return stbi_jpeg_load_from_memory(buffer,len,x,y,comp,req_comp); + if (stbi_png_test_memory(buffer,len)) return stbi_png_load_from_memory(buffer,len,x,y,comp,req_comp); + if (stbi_bmp_test_memory(buffer,len)) return stbi_bmp_load_from_memory(buffer,len,x,y,comp,req_comp); + if (stbi_gif_test_memory(buffer,len)) return stbi_gif_load_from_memory(buffer,len,x,y,comp,req_comp); + if (stbi_psd_test_memory(buffer,len)) return stbi_psd_load_from_memory(buffer,len,x,y,comp,req_comp); + if (stbi_pic_test_memory(buffer,len)) return stbi_pic_load_from_memory(buffer,len,x,y,comp,req_comp); + + #ifndef STBI_NO_HDR + if (stbi_hdr_test_memory(buffer, len)) { + float *hdr = stbi_hdr_load_from_memory(buffer, len,x,y,comp,req_comp); + return hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); + } + #endif + + for (i=0; i < max_loaders; ++i) + if (loaders[i]->test_memory(buffer,len)) + return loaders[i]->load_from_memory(buffer,len,x,y,comp,req_comp); + // test tga last because it's a crappy test! + if (stbi_tga_test_memory(buffer,len)) + return stbi_tga_load_from_memory(buffer,len,x,y,comp,req_comp); + return epuc("unknown image type", "Image not of any known type, or corrupt"); +} + +#ifndef STBI_NO_HDR + +#ifndef STBI_NO_STDIO +float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = fopen(filename, "rb"); + float *result; + if (!f) return epf("can't fopen", "Unable to open file"); + result = stbi_loadf_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *data; + #ifndef STBI_NO_HDR + if (stbi_hdr_test_file(f)) + return stbi_hdr_load_from_file(f,x,y,comp,req_comp); + #endif + data = stbi_load_from_file(f, x, y, comp, req_comp); + if (data) + return ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); + return epf("unknown image type", "Image not of any known type, or corrupt"); +} +#endif + +float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi_uc *data; + #ifndef STBI_NO_HDR + if (stbi_hdr_test_memory(buffer, len)) + return stbi_hdr_load_from_memory(buffer, len,x,y,comp,req_comp); + #endif + data = stbi_load_from_memory(buffer, len, x, y, comp, req_comp); + if (data) + return ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); + return epf("unknown image type", "Image not of any known type, or corrupt"); +} +#endif + +// these is-hdr-or-not is defined independent of whether STBI_NO_HDR is +// defined, for API simplicity; if STBI_NO_HDR is defined, it always +// reports false! + +int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) +{ + #ifndef STBI_NO_HDR + return stbi_hdr_test_memory(buffer, len); + #else + return 0; + #endif +} + +#ifndef STBI_NO_STDIO +extern int stbi_is_hdr (char const *filename) +{ + FILE *f = fopen(filename, "rb"); + int result=0; + if (f) { + result = stbi_is_hdr_from_file(f); + fclose(f); + } + return result; +} + +extern int stbi_is_hdr_from_file(FILE *f) +{ + #ifndef STBI_NO_HDR + return stbi_hdr_test_file(f); + #else + return 0; + #endif +} + +#endif + +#ifndef STBI_NO_HDR +static float h2l_gamma_i=1.0f/2.2f, h2l_scale_i=1.0f; +static float l2h_gamma=2.2f, l2h_scale=1.0f; + +void stbi_hdr_to_ldr_gamma(float gamma) { h2l_gamma_i = 1/gamma; } +void stbi_hdr_to_ldr_scale(float scale) { h2l_scale_i = 1/scale; } + +void stbi_ldr_to_hdr_gamma(float gamma) { l2h_gamma = gamma; } +void stbi_ldr_to_hdr_scale(float scale) { l2h_scale = scale; } +#endif + + +////////////////////////////////////////////////////////////////////////////// +// +// Common code used by all image loaders +// + +enum +{ + SCAN_load=0, + SCAN_type, + SCAN_header, +}; + +typedef struct +{ + uint32 img_x, img_y; + int img_n, img_out_n; + + #ifndef STBI_NO_STDIO + FILE *img_file; + int buflen; + uint8 buffer_start[128]; + int from_file; + #endif + uint8 *img_buffer, *img_buffer_end; +} stbi; + +#ifndef STBI_NO_STDIO +static void start_file(stbi *s, FILE *f) +{ + s->img_file = f; + s->buflen = sizeof(s->buffer_start); + s->img_buffer_end = s->buffer_start + s->buflen; + s->img_buffer = s->img_buffer_end; + s->from_file = 1; +} +#endif + +static void start_mem(stbi *s, uint8 const *buffer, int len) +{ +#ifndef STBI_NO_STDIO + s->img_file = NULL; + s->from_file = 0; +#endif + s->img_buffer = (uint8 *) buffer; + s->img_buffer_end = (uint8 *) buffer+len; +} + +#ifndef STBI_NO_STDIO +static void refill_buffer(stbi *s) +{ + int n = fread(s->buffer_start, 1, s->buflen, s->img_file); + if (n == 0) { + s->from_file = 0; + s->img_buffer = s->img_buffer_end-1; + *s->img_buffer = 0; + } else { + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start + n; + } +} +#endif + +__forceinline static int get8(stbi *s) +{ + if (s->img_buffer < s->img_buffer_end) + return *s->img_buffer++; +#ifndef STBI_NO_STDIO + if (s->from_file) { + refill_buffer(s); + return *s->img_buffer++; + } +#endif + return 0; +} + +__forceinline static int at_eof(stbi *s) +{ +#ifndef STBI_NO_STDIO + if (s->img_file) { + if (!feof(s->img_file)) return 0; + // if feof() is true, check if buffer = end + // special case: we've got the one extra character at the end + if (s->from_file == 0) return 1; + } +#endif + return s->img_buffer >= s->img_buffer_end; +} + +__forceinline static uint8 get8u(stbi *s) +{ + return (uint8) get8(s); +} + +static void skip(stbi *s, int n) +{ +#ifndef STBI_NO_STDIO + if (s->img_file) { + int blen = s->img_buffer_end - s->img_buffer; + if (blen < n) { + s->img_buffer = s->img_buffer_end; + fseek(s->img_file, n - blen, SEEK_CUR); + return; + } + } +#endif + s->img_buffer += n; +} + +static int getn(stbi *s, stbi_uc *buffer, int n) +{ +#ifndef STBI_NO_STDIO + if (s->img_file) { + int blen = s->img_buffer_end - s->img_buffer; + if (blen < n) { + int res; + memcpy(buffer, s->img_buffer, blen); + res = ((int) fread(buffer + blen, 1, n - blen, s->img_file) == (n-blen)); + s->img_buffer = s->img_buffer_end; + return res; + } + } +#endif + if (s->img_buffer+n <= s->img_buffer_end) { + memcpy(buffer, s->img_buffer, n); + s->img_buffer += n; + return 1; + } else + return 0; +} + +static int get16(stbi *s) +{ + int z = get8(s); + return (z << 8) + get8(s); +} + +static uint32 get32(stbi *s) +{ + uint32 z = get16(s); + return (z << 16) + get16(s); +} + +static int get16le(stbi *s) +{ + int z = get8(s); + return z + (get8(s) << 8); +} + +static uint32 get32le(stbi *s) +{ + uint32 z = get16le(s); + return z + (get16le(s) << 16); +} + +////////////////////////////////////////////////////////////////////////////// +// +// generic converter from built-in img_n to req_comp +// individual types do this automatically as much as possible (e.g. jpeg +// does all cases internally since it needs to colorspace convert anyway, +// and it never has alpha, so very few cases ). png can automatically +// interleave an alpha=255 channel, but falls back to this for other cases +// +// assume data buffer is malloced, so malloc a new one and free that one +// only failure mode is malloc failing + +static uint8 compute_y(int r, int g, int b) +{ + return (uint8) (((r*77) + (g*150) + (29*b)) >> 8); +} + +static unsigned char *convert_format(unsigned char *data, int img_n, int req_comp, uint x, uint y) +{ + int i,j; + unsigned char *good; + + if (req_comp == img_n) return data; + assert(req_comp >= 1 && req_comp <= 4); + + good = (unsigned char *) malloc(req_comp * x * y); + if (good == NULL) { + free(data); + return epuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + unsigned char *src = data + j * x * img_n ; + unsigned char *dest = good + j * x * req_comp; + + #define COMBO(a,b) ((a)*8+(b)) + #define CASE(a,b) case COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // 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 (COMBO(img_n, req_comp)) { + CASE(1,2) dest[0]=src[0], dest[1]=255; break; + CASE(1,3) dest[0]=dest[1]=dest[2]=src[0]; break; + CASE(1,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; break; + CASE(2,1) dest[0]=src[0]; break; + CASE(2,3) dest[0]=dest[1]=dest[2]=src[0]; break; + CASE(2,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; break; + CASE(3,4) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; break; + CASE(3,1) dest[0]=compute_y(src[0],src[1],src[2]); break; + CASE(3,2) dest[0]=compute_y(src[0],src[1],src[2]), dest[1] = 255; break; + CASE(4,1) dest[0]=compute_y(src[0],src[1],src[2]); break; + CASE(4,2) dest[0]=compute_y(src[0],src[1],src[2]), dest[1] = src[3]; break; + CASE(4,3) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; break; + default: assert(0); + } + #undef CASE + } + + free(data); + return good; +} + +#ifndef STBI_NO_HDR +static float *ldr_to_hdr(stbi_uc *data, int x, int y, int comp) +{ + int i,k,n; + float *output = (float *) malloc(x * y * comp * sizeof(float)); + if (output == NULL) { free(data); return epf("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + output[i*comp + k] = (float) pow(data[i*comp+k]/255.0f, l2h_gamma) * l2h_scale; + } + if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f; + } + free(data); + return output; +} + +#define float2int(x) ((int) (x)) +static stbi_uc *hdr_to_ldr(float *data, int x, int y, int comp) +{ + int i,k,n; + stbi_uc *output = (stbi_uc *) malloc(x * y * comp); + if (output == NULL) { free(data); return epuc("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + float z = (float) pow(data[i*comp+k]*h2l_scale_i, h2l_gamma_i) * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = float2int(z); + } + if (k < comp) { + float z = data[i*comp+k] * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = float2int(z); + } + } + free(data); + return output; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// "baseline" JPEG/JFIF decoder (not actually fully baseline implementation) +// +// simple implementation +// - channel subsampling of at most 2 in each dimension +// - doesn't support delayed output of y-dimension +// - simple interface (only one output format: 8-bit interleaved RGB) +// - doesn't try to recover corrupt jpegs +// - doesn't allow partial loading, loading multiple at once +// - still fast on x86 (copying globals into locals doesn't help x86) +// - allocates lots of intermediate memory (full size of all components) +// - non-interleaved case requires this anyway +// - allows good upsampling (see next) +// high-quality +// - upsampled channels are bilinearly interpolated, even across blocks +// - quality integer IDCT derived from IJG's 'slow' +// performance +// - fast huffman; reasonable integer IDCT +// - uses a lot of intermediate memory, could cache poorly +// - load http://nothings.org/remote/anemones.jpg 3 times on 2.8Ghz P4 +// stb_jpeg: 1.34 seconds (MSVC6, default release build) +// stb_jpeg: 1.06 seconds (MSVC6, processor = Pentium Pro) +// IJL11.dll: 1.08 seconds (compiled by intel) +// IJG 1998: 0.98 seconds (MSVC6, makefile provided by IJG) +// IJG 1998: 0.95 seconds (MSVC6, makefile + proc=PPro) + +// huffman decoding acceleration +#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache + +typedef struct +{ + uint8 fast[1 << FAST_BITS]; + // weirdly, repacking this into AoS is a 10% speed loss, instead of a win + uint16 code[256]; + uint8 values[256]; + uint8 size[257]; + unsigned int maxcode[18]; + int delta[17]; // old 'firstsymbol' - old 'firstcode' +} huffman; + +typedef struct +{ + #if STBI_SIMD + unsigned short dequant2[4][64]; + #endif + stbi s; + huffman huff_dc[4]; + huffman huff_ac[4]; + uint8 dequant[4][64]; + +// sizes for components, interleaved MCUs + int img_h_max, img_v_max; + int img_mcu_x, img_mcu_y; + int img_mcu_w, img_mcu_h; + +// definition of jpeg image component + struct + { + int id; + int h,v; + int tq; + int hd,ha; + int dc_pred; + + int x,y,w2,h2; + uint8 *data; + void *raw_data; + uint8 *linebuf; + } img_comp[4]; + + uint32 code_buffer; // jpeg entropy-coded buffer + int code_bits; // number of valid bits + unsigned char marker; // marker seen while filling entropy buffer + int nomore; // flag if we saw a marker so must stop + + int scan_n, order[4]; + int restart_interval, todo; +} jpeg; + +static int build_huffman(huffman *h, int *count) +{ + int i,j,k=0,code; + // build size list for each symbol (from JPEG spec) + for (i=0; i < 16; ++i) + for (j=0; j < count[i]; ++j) + h->size[k++] = (uint8) (i+1); + h->size[k] = 0; + + // compute actual symbols (from jpeg spec) + code = 0; + k = 0; + for(j=1; j <= 16; ++j) { + // compute delta to add to code to compute symbol id + h->delta[j] = k - code; + if (h->size[k] == j) { + while (h->size[k] == j) + h->code[k++] = (uint16) (code++); + if (code-1 >= (1 << j)) return e("bad code lengths","Corrupt JPEG"); + } + // compute largest code + 1 for this size, preshifted as needed later + h->maxcode[j] = code << (16-j); + code <<= 1; + } + h->maxcode[j] = 0xffffffff; + + // build non-spec acceleration table; 255 is flag for not-accelerated + memset(h->fast, 255, 1 << FAST_BITS); + for (i=0; i < k; ++i) { + int s = h->size[i]; + if (s <= FAST_BITS) { + int c = h->code[i] << (FAST_BITS-s); + int m = 1 << (FAST_BITS-s); + for (j=0; j < m; ++j) { + h->fast[c+j] = (uint8) i; + } + } + } + return 1; +} + +static void grow_buffer_unsafe(jpeg *j) +{ + do { + int b = j->nomore ? 0 : get8(&j->s); + if (b == 0xff) { + int c = get8(&j->s); + if (c != 0) { + j->marker = (unsigned char) c; + j->nomore = 1; + return; + } + } + j->code_buffer |= b << (24 - j->code_bits); + j->code_bits += 8; + } while (j->code_bits <= 24); +} + +// (1 << n) - 1 +static uint32 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 +__forceinline static int decode(jpeg *j, huffman *h) +{ + unsigned int temp; + int c,k; + + if (j->code_bits < 16) grow_buffer_unsafe(j); + + // look at the top FAST_BITS and determine what symbol ID it is, + // if the code is <= FAST_BITS + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + k = h->fast[c]; + if (k < 255) { + int s = h->size[k]; + if (s > j->code_bits) + return -1; + j->code_buffer <<= s; + j->code_bits -= s; + return h->values[k]; + } + + // naive test is to shift the code_buffer down so k bits are + // valid, then test against maxcode. To speed this up, we've + // preshifted maxcode left so that it has (16-k) 0s at the + // end; in other words, regardless of the number of bits, it + // wants to be compared against something shifted to have 16; + // that way we don't need to shift inside the loop. + temp = j->code_buffer >> 16; + for (k=FAST_BITS+1 ; ; ++k) + if (temp < h->maxcode[k]) + break; + if (k == 17) { + // error! code not found + j->code_bits -= 16; + return -1; + } + + if (k > j->code_bits) + return -1; + + // convert the huffman code to the symbol id + c = ((j->code_buffer >> (32 - k)) & bmask[k]) + h->delta[k]; + assert((((j->code_buffer) >> (32 - h->size[c])) & bmask[h->size[c]]) == h->code[c]); + + // convert the id to a symbol + j->code_bits -= k; + j->code_buffer <<= k; + return h->values[c]; +} + +// combined JPEG 'receive' and JPEG 'extend', since baseline +// always extends everything it receives. +__forceinline static int extend_receive(jpeg *j, int n) +{ + unsigned int m = 1 << (n-1); + unsigned int k; + if (j->code_bits < n) grow_buffer_unsafe(j); + + #if 1 + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~bmask[n]; + k &= bmask[n]; + j->code_bits -= n; + #else + k = (j->code_buffer >> (32 - n)) & bmask[n]; + j->code_bits -= n; + j->code_buffer <<= n; + #endif + // the following test is probably a random branch that won't + // predict well. I tried to table accelerate it but failed. + // maybe it's compiling as a conditional move? + if (k < m) + return (-1 << n) + k + 1; + else + return k; +} + +// 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 uint8 dezigzag[64+15] = +{ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + // let corrupt input sample past end + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63 +}; + +// decode one 64-entry block-- +static int decode_block(jpeg *j, short data[64], huffman *hdc, huffman *hac, int b) +{ + int diff,dc,k; + int t = decode(j, hdc); + if (t < 0) return e("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])); + + diff = t ? extend_receive(j, t) : 0; + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) dc; + + // decode AC components, see JPEG spec + k = 1; + do { + int r,s; + int rs = decode(j, hac); + if (rs < 0) return e("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (rs != 0xf0) break; // end block + k += 16; + } else { + k += r; + // decode into unzigzag'd location + data[dezigzag[k++]] = (short) extend_receive(j,s); + } + } while (k < 64); + return 1; +} + +// take a -128..127 value and clamp it and convert to 0..255 +__forceinline static uint8 clamp(int x) +{ + // trick to use a single test to catch both cases + if ((unsigned int) x > 255) { + if (x < 0) return 0; + if (x > 255) return 255; + } + return (uint8) x; +} + +#define f2f(x) (int) (((x) * 4096 + 0.5)) +#define fsh(x) ((x) << 12) + +// derived from jidctint -- DCT_ISLOW +#define IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ + int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ + p2 = s2; \ + p3 = s6; \ + p1 = (p2+p3) * f2f(0.5411961f); \ + t2 = p1 + p3*f2f(-1.847759065f); \ + t3 = p1 + p2*f2f( 0.765366865f); \ + p2 = s0; \ + p3 = s4; \ + t0 = fsh(p2+p3); \ + t1 = fsh(p2-p3); \ + x0 = t0+t3; \ + x3 = t0-t3; \ + x1 = t1+t2; \ + x2 = t1-t2; \ + t0 = s7; \ + t1 = s5; \ + t2 = s3; \ + t3 = s1; \ + p3 = t0+t2; \ + p4 = t1+t3; \ + p1 = t0+t3; \ + p2 = t1+t2; \ + p5 = (p3+p4)*f2f( 1.175875602f); \ + t0 = t0*f2f( 0.298631336f); \ + t1 = t1*f2f( 2.053119869f); \ + t2 = t2*f2f( 3.072711026f); \ + t3 = t3*f2f( 1.501321110f); \ + p1 = p5 + p1*f2f(-0.899976223f); \ + p2 = p5 + p2*f2f(-2.562915447f); \ + p3 = p3*f2f(-1.961570560f); \ + p4 = p4*f2f(-0.390180644f); \ + t3 += p1+p4; \ + t2 += p2+p3; \ + t1 += p2+p4; \ + t0 += p1+p3; + +#if STBI_SIMD +typedef unsigned short stbi_dequantize_t; +#else +typedef uint8 stbi_dequantize_t; +#endif + +// .344 seconds on 3*anemones.jpg +static void idct_block(uint8 *out, int out_stride, short data[64], stbi_dequantize_t *dequantize) +{ + int i,val[64],*v=val; + stbi_dequantize_t *dq = dequantize; + uint8 *o; + short *d = data; + + // columns + for (i=0; i < 8; ++i,++d,++dq, ++v) { + // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing + if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 + && d[40]==0 && d[48]==0 && d[56]==0) { + // no shortcut 0 seconds + // (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] * dq[0] << 2; + v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; + } else { + IDCT_1D(d[ 0]*dq[ 0],d[ 8]*dq[ 8],d[16]*dq[16],d[24]*dq[24], + d[32]*dq[32],d[40]*dq[40],d[48]*dq[48],d[56]*dq[56]) + // constants scaled things up by 1<<12; let's bring them back + // down, but keep 2 extra bits of precision + x0 += 512; x1 += 512; x2 += 512; x3 += 512; + v[ 0] = (x0+t3) >> 10; + v[56] = (x0-t3) >> 10; + v[ 8] = (x1+t2) >> 10; + v[48] = (x1-t2) >> 10; + v[16] = (x2+t1) >> 10; + v[40] = (x2-t1) >> 10; + v[24] = (x3+t0) >> 10; + v[32] = (x3-t0) >> 10; + } + } + + for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { + // no fast case since the first 1D IDCT spread components out + IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) + // constants scaled things up by 1<<12, plus we had 1<<2 from first + // loop, plus horizontal and vertical each scale by sqrt(8) so together + // we've got an extra 1<<3, so 1<<17 total we need to remove. + // so we want to round that, which means adding 0.5 * 1<<17, + // aka 65536. Also, we'll end up with -128 to 127 that we want + // to encode as 0..255 by adding 128, so we'll add that before the shift + x0 += 65536 + (128<<17); + x1 += 65536 + (128<<17); + x2 += 65536 + (128<<17); + x3 += 65536 + (128<<17); + // tried computing the shifts into temps, or'ing the temps to see + // if any were out of range, but that was slower + o[0] = clamp((x0+t3) >> 17); + o[7] = clamp((x0-t3) >> 17); + o[1] = clamp((x1+t2) >> 17); + o[6] = clamp((x1-t2) >> 17); + o[2] = clamp((x2+t1) >> 17); + o[5] = clamp((x2-t1) >> 17); + o[3] = clamp((x3+t0) >> 17); + o[4] = clamp((x3-t0) >> 17); + } +} + +#ifdef STBI_SIMD +static stbi_idct_8x8 stbi_idct_installed = idct_block; + +extern void stbi_install_idct(stbi_idct_8x8 func) +{ + stbi_idct_installed = func; +} +#endif + +#define MARKER_none 0xff +// if there's a pending marker from the entropy stream, return that +// otherwise, fetch from the stream and get a marker. if there's no +// marker, return 0xff, which is never a valid marker value +static uint8 get_marker(jpeg *j) +{ + uint8 x; + if (j->marker != MARKER_none) { x = j->marker; j->marker = MARKER_none; return x; } + x = get8u(&j->s); + if (x != 0xff) return MARKER_none; + while (x == 0xff) + x = get8u(&j->s); + return x; +} + +// in each scan, we'll have scan_n components, and the order +// of the components is specified by order[] +#define RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) + +// after a restart interval, reset the entropy decoder and +// the dc prediction +static void reset(jpeg *j) +{ + j->code_bits = 0; + j->code_buffer = 0; + j->nomore = 0; + j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = 0; + j->marker = MARKER_none; + j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; + // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, + // since we don't even allow 1<<30 pixels +} + +static int parse_entropy_coded_data(jpeg *z) +{ + reset(z); + if (z->scan_n == 1) { + int i,j; + #if STBI_SIMD + __declspec(align(16)) + #endif + short data[64]; + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + if (!decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+z->img_comp[n].ha, n)) return 0; + #if STBI_SIMD + stbi_idct_installed(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data, z->dequant2[z->img_comp[n].tq]); + #else + idct_block(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data, z->dequant[z->img_comp[n].tq]); + #endif + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!RESTART(z->marker)) return 1; + reset(z); + } + } + } + } else { // interleaved! + int i,j,k,x,y; + short data[64]; + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x)*8; + int y2 = (j*z->img_comp[n].v + y)*8; + if (!decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+z->img_comp[n].ha, n)) return 0; + #if STBI_SIMD + stbi_idct_installed(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data, z->dequant2[z->img_comp[n].tq]); + #else + idct_block(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data, z->dequant[z->img_comp[n].tq]); + #endif + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!RESTART(z->marker)) return 1; + reset(z); + } + } + } + } + return 1; +} + +static int process_marker(jpeg *z, int m) +{ + int L; + switch (m) { + case MARKER_none: // no marker found + return e("expected marker","Corrupt JPEG"); + + case 0xC2: // SOF - progressive + return e("progressive jpeg","JPEG format not supported (progressive)"); + + case 0xDD: // DRI - specify restart interval + if (get16(&z->s) != 4) return e("bad DRI len","Corrupt JPEG"); + z->restart_interval = get16(&z->s); + return 1; + + case 0xDB: // DQT - define quantization table + L = get16(&z->s)-2; + while (L > 0) { + int q = get8(&z->s); + int p = q >> 4; + int t = q & 15,i; + if (p != 0) return e("bad DQT type","Corrupt JPEG"); + if (t > 3) return e("bad DQT table","Corrupt JPEG"); + for (i=0; i < 64; ++i) + z->dequant[t][dezigzag[i]] = get8u(&z->s); + #if STBI_SIMD + for (i=0; i < 64; ++i) + z->dequant2[t][i] = z->dequant[t][i]; + #endif + L -= 65; + } + return L==0; + + case 0xC4: // DHT - define huffman table + L = get16(&z->s)-2; + while (L > 0) { + uint8 *v; + int sizes[16],i,m=0; + int q = get8(&z->s); + int tc = q >> 4; + int th = q & 15; + if (tc > 1 || th > 3) return e("bad DHT header","Corrupt JPEG"); + for (i=0; i < 16; ++i) { + sizes[i] = get8(&z->s); + m += sizes[i]; + } + L -= 17; + if (tc == 0) { + if (!build_huffman(z->huff_dc+th, sizes)) return 0; + v = z->huff_dc[th].values; + } else { + if (!build_huffman(z->huff_ac+th, sizes)) return 0; + v = z->huff_ac[th].values; + } + for (i=0; i < m; ++i) + v[i] = get8u(&z->s); + L -= m; + } + return L==0; + } + // check for comment block or APP blocks + if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { + skip(&z->s, get16(&z->s)-2); + return 1; + } + return 0; +} + +// after we see SOS +static int process_scan_header(jpeg *z) +{ + int i; + int Ls = get16(&z->s); + z->scan_n = get8(&z->s); + if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s.img_n) return e("bad SOS component count","Corrupt JPEG"); + if (Ls != 6+2*z->scan_n) return e("bad SOS len","Corrupt JPEG"); + for (i=0; i < z->scan_n; ++i) { + int id = get8(&z->s), which; + int q = get8(&z->s); + for (which = 0; which < z->s.img_n; ++which) + if (z->img_comp[which].id == id) + break; + if (which == z->s.img_n) return 0; + z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return e("bad DC huff","Corrupt JPEG"); + z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return e("bad AC huff","Corrupt JPEG"); + z->order[i] = which; + } + if (get8(&z->s) != 0) return e("bad SOS","Corrupt JPEG"); + get8(&z->s); // should be 63, but might be 0 + if (get8(&z->s) != 0) return e("bad SOS","Corrupt JPEG"); + + return 1; +} + +static int process_frame_header(jpeg *z, int scan) +{ + stbi *s = &z->s; + int Lf,p,i,q, h_max=1,v_max=1,c; + Lf = get16(s); if (Lf < 11) return e("bad SOF len","Corrupt JPEG"); // JPEG + p = get8(s); if (p != 8) return e("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline + s->img_y = get16(s); if (s->img_y == 0) return e("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG + s->img_x = get16(s); if (s->img_x == 0) return e("0 width","Corrupt JPEG"); // JPEG requires + c = get8(s); + if (c != 3 && c != 1) return e("bad component count","Corrupt JPEG"); // JFIF requires + s->img_n = c; + for (i=0; i < c; ++i) { + z->img_comp[i].data = NULL; + z->img_comp[i].linebuf = NULL; + } + + if (Lf != 8+3*s->img_n) return e("bad SOF len","Corrupt JPEG"); + + for (i=0; i < s->img_n; ++i) { + z->img_comp[i].id = get8(s); + if (z->img_comp[i].id != i+1) // JFIF requires + if (z->img_comp[i].id != i) // some version of jpegtran outputs non-JFIF-compliant files! + return e("bad component ID","Corrupt JPEG"); + q = get8(s); + z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return e("bad H","Corrupt JPEG"); + z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return e("bad V","Corrupt JPEG"); + z->img_comp[i].tq = get8(s); if (z->img_comp[i].tq > 3) return e("bad TQ","Corrupt JPEG"); + } + + if (scan != SCAN_load) return 1; + + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return e("too large", "Image too large to decode"); + + for (i=0; i < s->img_n; ++i) { + if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; + if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; + } + + // compute interleaved mcu info + z->img_h_max = h_max; + z->img_v_max = v_max; + z->img_mcu_w = h_max * 8; + z->img_mcu_h = v_max * 8; + z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; + z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; + + for (i=0; i < s->img_n; ++i) { + // number of effective pixels (e.g. for non-interleaved MCU) + z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; + z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; + // to simplify generation, we'll allocate enough memory to decode + // the bogus oversized data from using interleaved MCUs and their + // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't + // discard the extra data until colorspace conversion + z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; + z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; + z->img_comp[i].raw_data = malloc(z->img_comp[i].w2 * z->img_comp[i].h2+15); + if (z->img_comp[i].raw_data == NULL) { + for(--i; i >= 0; --i) { + free(z->img_comp[i].raw_data); + z->img_comp[i].data = NULL; + } + return e("outofmem", "Out of memory"); + } + // align blocks for installable-idct using mmx/sse + z->img_comp[i].data = (uint8*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); + z->img_comp[i].linebuf = NULL; + } + + return 1; +} + +// use comparisons since in some cases we handle more than one case (e.g. SOF) +#define DNL(x) ((x) == 0xdc) +#define SOI(x) ((x) == 0xd8) +#define EOI(x) ((x) == 0xd9) +#define SOF(x) ((x) == 0xc0 || (x) == 0xc1) +#define SOS(x) ((x) == 0xda) + +static int decode_jpeg_header(jpeg *z, int scan) +{ + int m; + z->marker = MARKER_none; // initialize cached marker to empty + m = get_marker(z); + if (!SOI(m)) return e("no SOI","Corrupt JPEG"); + if (scan == SCAN_type) return 1; + m = get_marker(z); + while (!SOF(m)) { + if (!process_marker(z,m)) return 0; + m = get_marker(z); + while (m == MARKER_none) { + // some files have extra padding after their blocks, so ok, we'll scan + if (at_eof(&z->s)) return e("no SOF", "Corrupt JPEG"); + m = get_marker(z); + } + } + if (!process_frame_header(z, scan)) return 0; + return 1; +} + +static int decode_jpeg_image(jpeg *j) +{ + int m; + j->restart_interval = 0; + if (!decode_jpeg_header(j, SCAN_load)) return 0; + m = get_marker(j); + while (!EOI(m)) { + if (SOS(m)) { + if (!process_scan_header(j)) return 0; + if (!parse_entropy_coded_data(j)) return 0; + } else { + if (!process_marker(j, m)) return 0; + } + m = get_marker(j); + } + return 1; +} + +// static jfif-centered resampling (across block boundaries) + +typedef uint8 *(*resample_row_func)(uint8 *out, uint8 *in0, uint8 *in1, + int w, int hs); + +#define div4(x) ((uint8) ((x) >> 2)) + +static uint8 *resample_row_1(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs) +{ + STBI_NOTUSED(out); + STBI_NOTUSED(in_far); + STBI_NOTUSED(w); + STBI_NOTUSED(hs); + return in_near; +} + +static uint8* resample_row_v_2(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs) +{ + // need to generate two samples vertically for every one in input + int i; + STBI_NOTUSED(hs); + for (i=0; i < w; ++i) + out[i] = div4(3*in_near[i] + in_far[i] + 2); + return out; +} + +static uint8* resample_row_h_2(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs) +{ + // need to generate two samples horizontally for every one in input + int i; + uint8 *input = in_near; + + if (w == 1) { + // if only one sample, can't do any interpolation + out[0] = out[1] = input[0]; + return out; + } + + out[0] = input[0]; + out[1] = div4(input[0]*3 + input[1] + 2); + for (i=1; i < w-1; ++i) { + int n = 3*input[i]+2; + out[i*2+0] = div4(n+input[i-1]); + out[i*2+1] = div4(n+input[i+1]); + } + out[i*2+0] = div4(input[w-2]*3 + input[w-1] + 2); + out[i*2+1] = input[w-1]; + + STBI_NOTUSED(in_far); + STBI_NOTUSED(hs); + + return out; +} + +#define div16(x) ((uint8) ((x) >> 4)) + +static uint8 *resample_row_hv_2(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i,t0,t1; + if (w == 1) { + out[0] = out[1] = div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + out[0] = div4(t1+2); + for (i=1; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = div16(3*t0 + t1 + 8); + out[i*2 ] = div16(3*t1 + t0 + 8); + } + out[w*2-1] = div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} + +static uint8 *resample_row_generic(uint8 *out, uint8 *in_near, uint8 *in_far, int w, int hs) +{ + // resample with nearest-neighbor + int i,j; + for (i=0; i < w; ++i) + for (j=0; j < hs; ++j) + out[i*hs+j] = in_near[i]; + return out; +} + +#define float2fixed(x) ((int) ((x) * 65536 + 0.5)) + +// 0.38 seconds on 3*anemones.jpg (0.25 with processor = Pro) +// VC6 without processor=Pro is generating multiple LEAs per multiply! +static void YCbCr_to_RGB_row(uint8 *out, const uint8 *y, const uint8 *pcb, const uint8 *pcr, int count, int step) +{ + int i; + for (i=0; i < count; ++i) { + int y_fixed = (y[i] << 16) + 32768; // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr*float2fixed(1.40200f); + g = y_fixed - cr*float2fixed(0.71414f) - cb*float2fixed(0.34414f); + b = y_fixed + cb*float2fixed(1.77200f); + r >>= 16; + g >>= 16; + b >>= 16; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (uint8)r; + out[1] = (uint8)g; + out[2] = (uint8)b; + out[3] = 255; + out += step; + } +} + +#if STBI_SIMD +static stbi_YCbCr_to_RGB_run stbi_YCbCr_installed = YCbCr_to_RGB_row; + +void stbi_install_YCbCr_to_RGB(stbi_YCbCr_to_RGB_run func) +{ + stbi_YCbCr_installed = func; +} +#endif + + +// clean up the temporary component buffers +static void cleanup_jpeg(jpeg *j) +{ + int i; + for (i=0; i < j->s.img_n; ++i) { + if (j->img_comp[i].data) { + free(j->img_comp[i].raw_data); + j->img_comp[i].data = NULL; + } + if (j->img_comp[i].linebuf) { + free(j->img_comp[i].linebuf); + j->img_comp[i].linebuf = NULL; + } + } +} + +typedef struct +{ + resample_row_func resample; + uint8 *line0,*line1; + int hs,vs; // expansion factor in each axis + int w_lores; // horizontal pixels pre-expansion + int ystep; // how far through vertical expansion we are + int ypos; // which pre-expansion row we're on +} stbi_resample; + +static uint8 *load_jpeg_image(jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) +{ + int n, decode_n; + // validate req_comp + if (req_comp < 0 || req_comp > 4) return epuc("bad req_comp", "Internal error"); + z->s.img_n = 0; + + // load a jpeg image from whichever source + if (!decode_jpeg_image(z)) { cleanup_jpeg(z); return NULL; } + + // determine actual number of components to generate + n = req_comp ? req_comp : z->s.img_n; + + if (z->s.img_n == 3 && n < 3) + decode_n = 1; + else + decode_n = z->s.img_n; + + // resample and color-convert + { + int k; + uint i,j; + uint8 *output; + uint8 *coutput[4]; + + stbi_resample res_comp[4]; + + for (k=0; k < decode_n; ++k) { + stbi_resample *r = &res_comp[k]; + + // allocate line buffer big enough for upsampling off the edges + // with upsample factor of 4 + z->img_comp[k].linebuf = (uint8 *) malloc(z->s.img_x + 3); + if (!z->img_comp[k].linebuf) { cleanup_jpeg(z); return epuc("outofmem", "Out of memory"); } + + r->hs = z->img_h_max / z->img_comp[k].h; + r->vs = z->img_v_max / z->img_comp[k].v; + r->ystep = r->vs >> 1; + r->w_lores = (z->s.img_x + r->hs-1) / r->hs; + r->ypos = 0; + r->line0 = r->line1 = z->img_comp[k].data; + + if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; + else if (r->hs == 1 && r->vs == 2) r->resample = resample_row_v_2; + else if (r->hs == 2 && r->vs == 1) r->resample = resample_row_h_2; + else if (r->hs == 2 && r->vs == 2) r->resample = resample_row_hv_2; + else r->resample = resample_row_generic; + } + + // can't error after this so, this is safe + output = (uint8 *) malloc(n * z->s.img_x * z->s.img_y + 1); + if (!output) { cleanup_jpeg(z); return epuc("outofmem", "Out of memory"); } + + // now go ahead and resample + for (j=0; j < z->s.img_y; ++j) { + uint8 *out = output + n * z->s.img_x * j; + for (k=0; k < decode_n; ++k) { + stbi_resample *r = &res_comp[k]; + int y_bot = r->ystep >= (r->vs >> 1); + coutput[k] = r->resample(z->img_comp[k].linebuf, + y_bot ? r->line1 : r->line0, + y_bot ? r->line0 : r->line1, + r->w_lores, r->hs); + if (++r->ystep >= r->vs) { + r->ystep = 0; + r->line0 = r->line1; + if (++r->ypos < z->img_comp[k].y) + r->line1 += z->img_comp[k].w2; + } + } + if (n >= 3) { + uint8 *y = coutput[0]; + if (z->s.img_n == 3) { + #if STBI_SIMD + stbi_YCbCr_installed(out, y, coutput[1], coutput[2], z->s.img_x, n); + #else + YCbCr_to_RGB_row(out, y, coutput[1], coutput[2], z->s.img_x, n); + #endif + } else + for (i=0; i < z->s.img_x; ++i) { + out[0] = out[1] = out[2] = y[i]; + out[3] = 255; // not used if n==3 + out += n; + } + } else { + uint8 *y = coutput[0]; + 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; + } + } + cleanup_jpeg(z); + *out_x = z->s.img_x; + *out_y = z->s.img_y; + if (comp) *comp = z->s.img_n; // report original components, not output + return output; + } +} + +#ifndef STBI_NO_STDIO +unsigned char *stbi_jpeg_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + jpeg j; + start_file(&j.s, f); + return load_jpeg_image(&j, x,y,comp,req_comp); +} + +unsigned char *stbi_jpeg_load(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *data; + FILE *f = fopen(filename, "rb"); + if (!f) return NULL; + data = stbi_jpeg_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return data; +} +#endif + +unsigned char *stbi_jpeg_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + jpeg j; + start_mem(&j.s, buffer,len); + return load_jpeg_image(&j, x,y,comp,req_comp); +} + +static int stbi_jpeg_info_raw(jpeg *j, int *x, int *y, int *comp) +{ + if (!decode_jpeg_header(j, SCAN_header)) + return 0; + if (x) *x = j->s.img_x; + if (y) *y = j->s.img_y; + if (comp) *comp = j->s.img_n; + return 1; +} + +#ifndef STBI_NO_STDIO +int stbi_jpeg_test_file(FILE *f) +{ + int n,r; + jpeg j; + n = ftell(f); + start_file(&j.s, f); + r = decode_jpeg_header(&j, SCAN_type); + fseek(f,n,SEEK_SET); + return r; +} + +int stbi_jpeg_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + jpeg j; + long n = ftell(f); + int res; + start_file(&j.s, f); + res = stbi_jpeg_info_raw(&j, x, y, comp); + fseek(f, n, SEEK_SET); + return res; +} + +int stbi_jpeg_info(char const *filename, int *x, int *y, int *comp) +{ + FILE *f = fopen(filename, "rb"); + int result; + if (!f) return e("can't fopen", "Unable to open file"); + result = stbi_jpeg_info_from_file(f, x, y, comp); + fclose(f); + return result; +} +#endif + +int stbi_jpeg_test_memory(stbi_uc const *buffer, int len) +{ + jpeg j; + start_mem(&j.s, buffer,len); + return decode_jpeg_header(&j, SCAN_type); +} + +int stbi_jpeg_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + jpeg j; + start_mem(&j.s, buffer, len); + return stbi_jpeg_info_raw(&j, x, y, comp); +} + +#ifndef STBI_NO_STDIO +extern int stbi_jpeg_info (char const *filename, int *x, int *y, int *comp); +extern int stbi_jpeg_info_from_file (FILE *f, int *x, int *y, int *comp); +#endif +extern int stbi_jpeg_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); + +// public domain zlib decode v0.2 Sean Barrett 2006-11-18 +// simple implementation +// - all input must be provided in an upfront buffer +// - all output is written to a single output buffer (can malloc/realloc) +// performance +// - fast huffman + +// fast-way is faster to check than jpeg huffman, but slow way is slower +#define ZFAST_BITS 9 // accelerate all cases in default tables +#define ZFAST_MASK ((1 << ZFAST_BITS) - 1) + +// zlib-style huffman encoding +// (jpegs packs from left, zlib from right, so can't share code) +typedef struct +{ + uint16 fast[1 << ZFAST_BITS]; + uint16 firstcode[16]; + int maxcode[17]; + uint16 firstsymbol[16]; + uint8 size[288]; + uint16 value[288]; +} zhuffman; + +__forceinline static int bitreverse16(int n) +{ + n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); + n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); + n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); + n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); + return n; +} + +__forceinline static int bit_reverse(int v, int bits) +{ + assert(bits <= 16); + // to bit reverse n bits, reverse 16 and shift + // e.g. 11 bits, bit reverse and shift away 5 + return bitreverse16(v) >> (16-bits); +} + +static int zbuild_huffman(zhuffman *z, uint8 *sizelist, int num) +{ + int i,k=0; + int code, next_code[16], sizes[17]; + + // DEFLATE spec for generating codes + memset(sizes, 0, sizeof(sizes)); + memset(z->fast, 255, sizeof(z->fast)); + for (i=0; i < num; ++i) + ++sizes[sizelist[i]]; + sizes[0] = 0; + for (i=1; i < 16; ++i) + assert(sizes[i] <= (1 << i)); + code = 0; + for (i=1; i < 16; ++i) { + next_code[i] = code; + z->firstcode[i] = (uint16) code; + z->firstsymbol[i] = (uint16) k; + code = (code + sizes[i]); + if (sizes[i]) + if (code-1 >= (1 << i)) return e("bad codelengths","Corrupt JPEG"); + z->maxcode[i] = code << (16-i); // preshift for inner loop + code <<= 1; + k += sizes[i]; + } + z->maxcode[16] = 0x10000; // sentinel + for (i=0; i < num; ++i) { + int s = sizelist[i]; + if (s) { + int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; + z->size[c] = (uint8)s; + z->value[c] = (uint16)i; + if (s <= ZFAST_BITS) { + int k = bit_reverse(next_code[s],s); + while (k < (1 << ZFAST_BITS)) { + z->fast[k] = (uint16) c; + k += (1 << s); + } + } + ++next_code[s]; + } + } + return 1; +} + +// zlib-from-memory implementation for PNG reading +// because PNG allows splitting the zlib stream arbitrarily, +// and it's annoying structurally to have PNG call ZLIB call PNG, +// we require PNG read all the IDATs and combine them into a single +// memory buffer + +typedef struct +{ + uint8 *zbuffer, *zbuffer_end; + int num_bits; + uint32 code_buffer; + + char *zout; + char *zout_start; + char *zout_end; + int z_expandable; + + zhuffman z_length, z_distance; +} zbuf; + +__forceinline static int zget8(zbuf *z) +{ + if (z->zbuffer >= z->zbuffer_end) return 0; + return *z->zbuffer++; +} + +static void fill_bits(zbuf *z) +{ + do { + assert(z->code_buffer < (1U << z->num_bits)); + z->code_buffer |= zget8(z) << z->num_bits; + z->num_bits += 8; + } while (z->num_bits <= 24); +} + +__forceinline static unsigned int zreceive(zbuf *z, int n) +{ + unsigned int k; + if (z->num_bits < n) fill_bits(z); + k = z->code_buffer & ((1 << n) - 1); + z->code_buffer >>= n; + z->num_bits -= n; + return k; +} + +__forceinline static int zhuffman_decode(zbuf *a, zhuffman *z) +{ + int b,s,k; + if (a->num_bits < 16) fill_bits(a); + b = z->fast[a->code_buffer & ZFAST_MASK]; + if (b < 0xffff) { + s = z->size[b]; + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; + } + + // not resolved by fast table, so compute it the slow way + // use jpeg approach, which requires MSbits at top + k = bit_reverse(a->code_buffer, 16); + for (s=ZFAST_BITS+1; ; ++s) + if (k < z->maxcode[s]) + break; + if (s == 16) return -1; // invalid code! + // code size is s, so: + b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; + assert(z->size[b] == s); + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; +} + +static int expand(zbuf *z, int n) // need to make room for n bytes +{ + char *q; + int cur, limit; + if (!z->z_expandable) return e("output buffer limit","Corrupt PNG"); + cur = (int) (z->zout - z->zout_start); + limit = (int) (z->zout_end - z->zout_start); + while (cur + n > limit) + limit *= 2; + q = (char *) realloc(z->zout_start, limit); + if (q == NULL) return e("outofmem", "Out of memory"); + z->zout_start = q; + z->zout = q + cur; + z->zout_end = q + limit; + return 1; +} + +static int length_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 length_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 dist_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 dist_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 parse_huffman_block(zbuf *a) +{ + for(;;) { + int z = zhuffman_decode(a, &a->z_length); + if (z < 256) { + if (z < 0) return e("bad huffman code","Corrupt PNG"); // error in huffman codes + if (a->zout >= a->zout_end) if (!expand(a, 1)) return 0; + *a->zout++ = (char) z; + } else { + uint8 *p; + int len,dist; + if (z == 256) return 1; + z -= 257; + len = length_base[z]; + if (length_extra[z]) len += zreceive(a, length_extra[z]); + z = zhuffman_decode(a, &a->z_distance); + if (z < 0) return e("bad huffman code","Corrupt PNG"); + dist = dist_base[z]; + if (dist_extra[z]) dist += zreceive(a, dist_extra[z]); + if (a->zout - a->zout_start < dist) return e("bad dist","Corrupt PNG"); + if (a->zout + len > a->zout_end) if (!expand(a, len)) return 0; + p = (uint8 *) (a->zout - dist); + while (len--) + *a->zout++ = *p++; + } + } +} + +static int compute_huffman_codes(zbuf *a) +{ + static uint8 length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + zhuffman z_codelength; + uint8 lencodes[286+32+137];//padding for maximum single op + uint8 codelength_sizes[19]; + int i,n; + + int hlit = zreceive(a,5) + 257; + int hdist = zreceive(a,5) + 1; + int hclen = zreceive(a,4) + 4; + + memset(codelength_sizes, 0, sizeof(codelength_sizes)); + for (i=0; i < hclen; ++i) { + int s = zreceive(a,3); + codelength_sizes[length_dezigzag[i]] = (uint8) s; + } + if (!zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; + + n = 0; + while (n < hlit + hdist) { + int c = zhuffman_decode(a, &z_codelength); + assert(c >= 0 && c < 19); + if (c < 16) + lencodes[n++] = (uint8) c; + else if (c == 16) { + c = zreceive(a,2)+3; + memset(lencodes+n, lencodes[n-1], c); + n += c; + } else if (c == 17) { + c = zreceive(a,3)+3; + memset(lencodes+n, 0, c); + n += c; + } else { + assert(c == 18); + c = zreceive(a,7)+11; + memset(lencodes+n, 0, c); + n += c; + } + } + if (n != hlit+hdist) return e("bad codelengths","Corrupt PNG"); + if (!zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; + if (!zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; + return 1; +} + +static int parse_uncompressed_block(zbuf *a) +{ + uint8 header[4]; + int len,nlen,k; + if (a->num_bits & 7) + zreceive(a, a->num_bits & 7); // discard + // drain the bit-packed data into header + k = 0; + while (a->num_bits > 0) { + header[k++] = (uint8) (a->code_buffer & 255); // wtf this warns? + a->code_buffer >>= 8; + a->num_bits -= 8; + } + assert(a->num_bits == 0); + // now fill header the normal way + while (k < 4) + header[k++] = (uint8) zget8(a); + len = header[1] * 256 + header[0]; + nlen = header[3] * 256 + header[2]; + if (nlen != (len ^ 0xffff)) return e("zlib corrupt","Corrupt PNG"); + if (a->zbuffer + len > a->zbuffer_end) return e("read past buffer","Corrupt PNG"); + if (a->zout + len > a->zout_end) + if (!expand(a, len)) return 0; + memcpy(a->zout, a->zbuffer, len); + a->zbuffer += len; + a->zout += len; + return 1; +} + +static int parse_zlib_header(zbuf *a) +{ + int cmf = zget8(a); + int cm = cmf & 15; + /* int cinfo = cmf >> 4; */ + int flg = zget8(a); + if ((cmf*256+flg) % 31 != 0) return e("bad zlib header","Corrupt PNG"); // zlib spec + if (flg & 32) return e("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png + if (cm != 8) return e("bad compression","Corrupt PNG"); // DEFLATE required for png + // window = 1 << (8 + cinfo)... but who cares, we fully buffer output + return 1; +} + +// @TODO: should statically initialize these for optimal thread safety +static uint8 default_length[288], default_distance[32]; +static void init_defaults(void) +{ + int i; // use <= to match clearly with spec + for (i=0; i <= 143; ++i) default_length[i] = 8; + for ( ; i <= 255; ++i) default_length[i] = 9; + for ( ; i <= 279; ++i) default_length[i] = 7; + for ( ; i <= 287; ++i) default_length[i] = 8; + + for (i=0; i <= 31; ++i) default_distance[i] = 5; +} + +int stbi_png_partial; // a quick hack to only allow decoding some of a PNG... I should implement real streaming support instead +static int parse_zlib(zbuf *a, int parse_header) +{ + int final, type; + if (parse_header) + if (!parse_zlib_header(a)) return 0; + a->num_bits = 0; + a->code_buffer = 0; + do { + final = zreceive(a,1); + type = zreceive(a,2); + if (type == 0) { + if (!parse_uncompressed_block(a)) return 0; + } else if (type == 3) { + return 0; + } else { + if (type == 1) { + // use fixed code lengths + if (!default_distance[31]) init_defaults(); + if (!zbuild_huffman(&a->z_length , default_length , 288)) return 0; + if (!zbuild_huffman(&a->z_distance, default_distance, 32)) return 0; + } else { + if (!compute_huffman_codes(a)) return 0; + } + if (!parse_huffman_block(a)) return 0; + } + if (stbi_png_partial && a->zout - a->zout_start > 65536) + break; + } while (!final); + return 1; +} + +static int do_zlib(zbuf *a, char *obuf, int olen, int exp, int parse_header) +{ + a->zout_start = obuf; + a->zout = obuf; + a->zout_end = obuf + olen; + a->z_expandable = exp; + + return parse_zlib(a, parse_header); +} + +char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) +{ + zbuf a; + char *p = (char *) malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (uint8 *) buffer; + a.zbuffer_end = (uint8 *) buffer + len; + if (do_zlib(&a, p, initial_size, 1, 1)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + free(a.zout_start); + return NULL; + } +} + +char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) +{ + return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); +} + +char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) +{ + zbuf a; + char *p = (char *) malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (uint8 *) buffer; + a.zbuffer_end = (uint8 *) buffer + len; + if (do_zlib(&a, p, initial_size, 1, parse_header)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + free(a.zout_start); + return NULL; + } +} + +int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) +{ + zbuf a; + a.zbuffer = (uint8 *) ibuffer; + a.zbuffer_end = (uint8 *) ibuffer + ilen; + if (do_zlib(&a, obuffer, olen, 0, 1)) + return (int) (a.zout - a.zout_start); + else + return -1; +} + +char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) +{ + zbuf a; + char *p = (char *) malloc(16384); + if (p == NULL) return NULL; + a.zbuffer = (uint8 *) buffer; + a.zbuffer_end = (uint8 *) buffer+len; + if (do_zlib(&a, p, 16384, 1, 0)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + free(a.zout_start); + return NULL; + } +} + +int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) +{ + zbuf a; + a.zbuffer = (uint8 *) ibuffer; + a.zbuffer_end = (uint8 *) ibuffer + ilen; + if (do_zlib(&a, obuffer, olen, 0, 0)) + return (int) (a.zout - a.zout_start); + else + return -1; +} + +// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 +// simple implementation +// - only 8-bit samples +// - no CRC checking +// - allocates lots of intermediate memory +// - avoids problem of streaming data between subsystems +// - avoids explicit window management +// performance +// - uses stb_zlib, a PD zlib implementation with fast huffman decoding + + +typedef struct +{ + uint32 length; + uint32 type; +} chunk; + +#define PNG_TYPE(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) + +static chunk get_chunk_header(stbi *s) +{ + chunk c; + c.length = get32(s); + c.type = get32(s); + return c; +} + +static int check_png_header(stbi *s) +{ + static uint8 png_sig[8] = { 137,80,78,71,13,10,26,10 }; + int i; + for (i=0; i < 8; ++i) + if (get8(s) != png_sig[i]) return e("bad png sig","Not a PNG"); + return 1; +} + +typedef struct +{ + stbi s; + uint8 *idata, *expanded, *out; +} png; + + +enum { + F_none=0, F_sub=1, F_up=2, F_avg=3, F_paeth=4, + F_avg_first, F_paeth_first, +}; + +static uint8 first_row_filter[5] = +{ + F_none, F_sub, F_none, F_avg_first, F_paeth_first +}; + +static int paeth(int a, int b, int c) +{ + int p = a + b - c; + int pa = abs(p-a); + int pb = abs(p-b); + int pc = abs(p-c); + if (pa <= pb && pa <= pc) return a; + if (pb <= pc) return b; + return c; +} + +// create the png data from post-deflated data +static int create_png_image_raw(png *a, uint8 *raw, uint32 raw_len, int out_n, uint32 x, uint32 y) +{ + stbi *s = &a->s; + uint32 i,j,stride = x*out_n; + int k; + int img_n = s->img_n; // copy it into a local for later + assert(out_n == s->img_n || out_n == s->img_n+1); + if (stbi_png_partial) y = 1; + a->out = (uint8 *) malloc(x * y * out_n); + if (!a->out) return e("outofmem", "Out of memory"); + if (!stbi_png_partial) { + if (s->img_x == x && s->img_y == y) { + if (raw_len != (img_n * x + 1) * y) return e("not enough pixels","Corrupt PNG"); + } else { // interlaced: + if (raw_len < (img_n * x + 1) * y) return e("not enough pixels","Corrupt PNG"); + } + } + for (j=0; j < y; ++j) { + uint8 *cur = a->out + stride*j; + uint8 *prior = cur - stride; + int filter = *raw++; + if (filter > 4) return e("invalid filter","Corrupt PNG"); + // if first row, use special filter that doesn't sample previous row + if (j == 0) filter = first_row_filter[filter]; + // handle first pixel explicitly + for (k=0; k < img_n; ++k) { + switch (filter) { + case F_none : cur[k] = raw[k]; break; + case F_sub : cur[k] = raw[k]; break; + case F_up : cur[k] = raw[k] + prior[k]; break; + case F_avg : cur[k] = raw[k] + (prior[k]>>1); break; + case F_paeth : cur[k] = (uint8) (raw[k] + paeth(0,prior[k],0)); break; + case F_avg_first : cur[k] = raw[k]; break; + case F_paeth_first: cur[k] = raw[k]; break; + } + } + if (img_n != out_n) cur[img_n] = 255; + raw += img_n; + cur += out_n; + prior += out_n; + // this is a little gross, so that we don't switch per-pixel or per-component + if (img_n == out_n) { + #define CASE(f) \ + case f: \ + for (i=x-1; i >= 1; --i, raw+=img_n,cur+=img_n,prior+=img_n) \ + for (k=0; k < img_n; ++k) + switch (filter) { + CASE(F_none) cur[k] = raw[k]; break; + CASE(F_sub) cur[k] = raw[k] + cur[k-img_n]; break; + CASE(F_up) cur[k] = raw[k] + prior[k]; break; + CASE(F_avg) cur[k] = raw[k] + ((prior[k] + cur[k-img_n])>>1); break; + CASE(F_paeth) cur[k] = (uint8) (raw[k] + paeth(cur[k-img_n],prior[k],prior[k-img_n])); break; + CASE(F_avg_first) cur[k] = raw[k] + (cur[k-img_n] >> 1); break; + CASE(F_paeth_first) cur[k] = (uint8) (raw[k] + paeth(cur[k-img_n],0,0)); break; + } + #undef CASE + } else { + assert(img_n+1 == out_n); + #define CASE(f) \ + case f: \ + for (i=x-1; i >= 1; --i, cur[img_n]=255,raw+=img_n,cur+=out_n,prior+=out_n) \ + for (k=0; k < img_n; ++k) + switch (filter) { + CASE(F_none) cur[k] = raw[k]; break; + CASE(F_sub) cur[k] = raw[k] + cur[k-out_n]; break; + CASE(F_up) cur[k] = raw[k] + prior[k]; break; + CASE(F_avg) cur[k] = raw[k] + ((prior[k] + cur[k-out_n])>>1); break; + CASE(F_paeth) cur[k] = (uint8) (raw[k] + paeth(cur[k-out_n],prior[k],prior[k-out_n])); break; + CASE(F_avg_first) cur[k] = raw[k] + (cur[k-out_n] >> 1); break; + CASE(F_paeth_first) cur[k] = (uint8) (raw[k] + paeth(cur[k-out_n],0,0)); break; + } + #undef CASE + } + } + return 1; +} + +static int create_png_image(png *a, uint8 *raw, uint32 raw_len, int out_n, int interlaced) +{ + uint8 *final; + int p; + int save; + if (!interlaced) + return create_png_image_raw(a, raw, raw_len, out_n, a->s.img_x, a->s.img_y); + save = stbi_png_partial; + stbi_png_partial = 0; + + // de-interlacing + final = (uint8 *) malloc(a->s.img_x * a->s.img_y * out_n); + for (p=0; p < 7; ++p) { + int xorig[] = { 0,4,0,2,0,1,0 }; + int yorig[] = { 0,0,4,0,2,0,1 }; + int xspc[] = { 8,8,4,4,2,2,1 }; + int yspc[] = { 8,8,8,4,4,2,2 }; + int i,j,x,y; + // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 + x = (a->s.img_x - xorig[p] + xspc[p]-1) / xspc[p]; + y = (a->s.img_y - yorig[p] + yspc[p]-1) / yspc[p]; + if (x && y) { + if (!create_png_image_raw(a, raw, raw_len, out_n, x, y)) { + free(final); + return 0; + } + for (j=0; j < y; ++j) + for (i=0; i < x; ++i) + memcpy(final + (j*yspc[p]+yorig[p])*a->s.img_x*out_n + (i*xspc[p]+xorig[p])*out_n, + a->out + (j*x+i)*out_n, out_n); + free(a->out); + raw += (x*out_n+1)*y; + raw_len -= (x*out_n+1)*y; + } + } + a->out = final; + + stbi_png_partial = save; + return 1; +} + +static int compute_transparency(png *z, uint8 tc[3], int out_n) +{ + stbi *s = &z->s; + uint32 i, pixel_count = s->img_x * s->img_y; + uint8 *p = z->out; + + // compute color-based transparency, assuming we've + // already got 255 as the alpha value in the output + assert(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i=0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 255); + p += 2; + } + } else { + for (i=0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int expand_palette(png *a, uint8 *palette, int len, int pal_img_n) +{ + uint32 i, pixel_count = a->s.img_x * a->s.img_y; + uint8 *p, *temp_out, *orig = a->out; + + p = (uint8 *) malloc(pixel_count * pal_img_n); + if (p == NULL) return e("outofmem", "Out of memory"); + + // between here and free(out) below, exitting would leak + temp_out = p; + + if (pal_img_n == 3) { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p += 3; + } + } else { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p[3] = palette[n+3]; + p += 4; + } + } + free(a->out); + a->out = temp_out; + + STBI_NOTUSED(len); + + return 1; +} + +static int stbi_unpremultiply_on_load = 0; +static int stbi_de_iphone_flag = 0; + +void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) +{ + stbi_unpremultiply_on_load = flag_true_if_should_unpremultiply; +} +void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) +{ + stbi_de_iphone_flag = flag_true_if_should_convert; +} + +static void stbi_de_iphone(png *z) +{ + stbi *s = &z->s; + uint32 i, pixel_count = s->img_x * s->img_y; + uint8 *p = z->out; + + if (s->img_out_n == 3) { // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + uint8 t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 3; + } + } else { + assert(s->img_out_n == 4); + if (stbi_unpremultiply_on_load) { + // convert bgr to rgb and unpremultiply + for (i=0; i < pixel_count; ++i) { + uint8 a = p[3]; + uint8 t = p[0]; + if (a) { + p[0] = p[2] * 255 / a; + p[1] = p[1] * 255 / a; + p[2] = t * 255 / a; + } else { + p[0] = p[2]; + p[2] = t; + } + p += 4; + } + } else { + // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + uint8 t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 4; + } + } + } +} + +static int parse_png_file(png *z, int scan, int req_comp) +{ + uint8 palette[1024], pal_img_n=0; + uint8 has_trans=0, tc[3]; + uint32 ioff=0, idata_limit=0, i, pal_len=0; + int first=1,k,interlace=0, iphone=0; + stbi *s = &z->s; + + if (!check_png_header(s)) return 0; + + if (scan == SCAN_type) return 1; + + for (;;) { + chunk c = get_chunk_header(s); + switch (c.type) { + case PNG_TYPE('C','g','B','I'): + iphone = stbi_de_iphone_flag; + skip(s, c.length); + break; + case PNG_TYPE('I','H','D','R'): { + int depth,color,comp,filter; + if (!first) return e("multiple IHDR","Corrupt PNG"); + first = 0; + if (c.length != 13) return e("bad IHDR len","Corrupt PNG"); + s->img_x = get32(s); if (s->img_x > (1 << 24)) return e("too large","Very large image (corrupt?)"); + s->img_y = get32(s); if (s->img_y > (1 << 24)) return e("too large","Very large image (corrupt?)"); + depth = get8(s); if (depth != 8) return e("8bit only","PNG not supported: 8-bit only"); + color = get8(s); if (color > 6) return e("bad ctype","Corrupt PNG"); + if (color == 3) pal_img_n = 3; else if (color & 1) return e("bad ctype","Corrupt PNG"); + comp = get8(s); if (comp) return e("bad comp method","Corrupt PNG"); + filter= get8(s); if (filter) return e("bad filter method","Corrupt PNG"); + interlace = get8(s); if (interlace>1) return e("bad interlace method","Corrupt PNG"); + if (!s->img_x || !s->img_y) return e("0-pixel image","Corrupt PNG"); + if (!pal_img_n) { + s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return e("too large", "Image too large to decode"); + if (scan == SCAN_header) return 1; + } else { + // if paletted, then pal_n is our final components, and + // img_n is # components to decompress/filter. + s->img_n = 1; + if ((1 << 30) / s->img_x / 4 < s->img_y) return e("too large","Corrupt PNG"); + // if SCAN_header, have to scan to see if we have a tRNS + } + break; + } + + case PNG_TYPE('P','L','T','E'): { + if (first) return e("first not IHDR", "Corrupt PNG"); + if (c.length > 256*3) return e("invalid PLTE","Corrupt PNG"); + pal_len = c.length / 3; + if (pal_len * 3 != c.length) return e("invalid PLTE","Corrupt PNG"); + for (i=0; i < pal_len; ++i) { + palette[i*4+0] = get8u(s); + palette[i*4+1] = get8u(s); + palette[i*4+2] = get8u(s); + palette[i*4+3] = 255; + } + break; + } + + case PNG_TYPE('t','R','N','S'): { + if (first) return e("first not IHDR", "Corrupt PNG"); + if (z->idata) return e("tRNS after IDAT","Corrupt PNG"); + if (pal_img_n) { + if (scan == SCAN_header) { s->img_n = 4; return 1; } + if (pal_len == 0) return e("tRNS before PLTE","Corrupt PNG"); + if (c.length > pal_len) return e("bad tRNS len","Corrupt PNG"); + pal_img_n = 4; + for (i=0; i < c.length; ++i) + palette[i*4+3] = get8u(s); + } else { + if (!(s->img_n & 1)) return e("tRNS with alpha","Corrupt PNG"); + if (c.length != (uint32) s->img_n*2) return e("bad tRNS len","Corrupt PNG"); + has_trans = 1; + for (k=0; k < s->img_n; ++k) + tc[k] = (uint8) get16(s); // non 8-bit images will be larger + } + break; + } + + case PNG_TYPE('I','D','A','T'): { + if (first) return e("first not IHDR", "Corrupt PNG"); + if (pal_img_n && !pal_len) return e("no PLTE","Corrupt PNG"); + if (scan == SCAN_header) { s->img_n = pal_img_n; return 1; } + if (ioff + c.length > idata_limit) { + uint8 *p; + if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; + while (ioff + c.length > idata_limit) + idata_limit *= 2; + p = (uint8 *) realloc(z->idata, idata_limit); if (p == NULL) return e("outofmem", "Out of memory"); + z->idata = p; + } + if (!getn(s, z->idata+ioff,c.length)) return e("outofdata","Corrupt PNG"); + ioff += c.length; + break; + } + + case PNG_TYPE('I','E','N','D'): { + uint32 raw_len; + if (first) return e("first not IHDR", "Corrupt PNG"); + if (scan != SCAN_load) return 1; + if (z->idata == NULL) return e("no IDAT","Corrupt PNG"); + z->expanded = (uint8 *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, 16384, (int *) &raw_len, !iphone); + if (z->expanded == NULL) return 0; // zlib should set error + free(z->idata); z->idata = NULL; + if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) + s->img_out_n = s->img_n+1; + else + s->img_out_n = s->img_n; + if (!create_png_image(z, z->expanded, raw_len, s->img_out_n, interlace)) return 0; + if (has_trans) + if (!compute_transparency(z, tc, s->img_out_n)) return 0; + if (iphone && s->img_out_n > 2) + stbi_de_iphone(z); + if (pal_img_n) { + // pal_img_n == 3 or 4 + s->img_n = pal_img_n; // record the actual colors we had + s->img_out_n = pal_img_n; + if (req_comp >= 3) s->img_out_n = req_comp; + if (!expand_palette(z, palette, pal_len, s->img_out_n)) + return 0; + } + free(z->expanded); z->expanded = NULL; + return 1; + } + + default: + // if critical, fail + if (first) return e("first not IHDR", "Corrupt PNG"); + if ((c.type & (1 << 29)) == 0) { + #ifndef STBI_NO_FAILURE_STRINGS + // not threadsafe + static char invalid_chunk[] = "XXXX chunk not known"; + invalid_chunk[0] = (uint8) (c.type >> 24); + invalid_chunk[1] = (uint8) (c.type >> 16); + invalid_chunk[2] = (uint8) (c.type >> 8); + invalid_chunk[3] = (uint8) (c.type >> 0); + #endif + return e(invalid_chunk, "PNG not supported: unknown chunk type"); + } + skip(s, c.length); + break; + } + // end of chunk, read and skip CRC + get32(s); + } +} + +static unsigned char *do_png(png *p, int *x, int *y, int *n, int req_comp) +{ + unsigned char *result=NULL; + p->expanded = NULL; + p->idata = NULL; + p->out = NULL; + if (req_comp < 0 || req_comp > 4) return epuc("bad req_comp", "Internal error"); + if (parse_png_file(p, SCAN_load, req_comp)) { + result = p->out; + p->out = NULL; + if (req_comp && req_comp != p->s.img_out_n) { + result = convert_format(result, p->s.img_out_n, req_comp, p->s.img_x, p->s.img_y); + p->s.img_out_n = req_comp; + if (result == NULL) return result; + } + *x = p->s.img_x; + *y = p->s.img_y; + if (n) *n = p->s.img_n; + } + free(p->out); p->out = NULL; + free(p->expanded); p->expanded = NULL; + free(p->idata); p->idata = NULL; + + return result; +} + +#ifndef STBI_NO_STDIO +unsigned char *stbi_png_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + png p; + start_file(&p.s, f); + return do_png(&p, x,y,comp,req_comp); +} + +unsigned char *stbi_png_load(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *data; + FILE *f = fopen(filename, "rb"); + if (!f) return NULL; + data = stbi_png_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return data; +} +#endif + +unsigned char *stbi_png_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + png p; + start_mem(&p.s, buffer,len); + return do_png(&p, x,y,comp,req_comp); +} + +#ifndef STBI_NO_STDIO +int stbi_png_test_file(FILE *f) +{ + png p; + int n,r; + n = ftell(f); + start_file(&p.s, f); + r = parse_png_file(&p, SCAN_type,STBI_default); + fseek(f,n,SEEK_SET); + return r; +} +#endif + +int stbi_png_test_memory(stbi_uc const *buffer, int len) +{ + png p; + start_mem(&p.s, buffer, len); + return parse_png_file(&p, SCAN_type,STBI_default); +} + +static int stbi_png_info_raw(png *p, int *x, int *y, int *comp) +{ + if (!parse_png_file(p, SCAN_header, 0)) + return 0; + if (x) *x = p->s.img_x; + if (y) *y = p->s.img_y; + if (comp) *comp = p->s.img_n; + return 1; +} + +#ifndef STBI_NO_STDIO +int stbi_png_info (char const *filename, int *x, int *y, int *comp) +{ + int res; + FILE *f = fopen(filename, "rb"); + if (!f) return 0; + res = stbi_png_info_from_file(f, x, y, comp); + fclose(f); + return res; +} + +int stbi_png_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + png p; + int res; + long n = ftell(f); + start_file(&p.s, f); + res = stbi_png_info_raw(&p, x, y, comp); + fseek(f, n, SEEK_SET); + return res; +} +#endif // !STBI_NO_STDIO + +int stbi_png_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + png p; + start_mem(&p.s, buffer, len); + return stbi_png_info_raw(&p, x, y, comp); +} + +// Microsoft/Windows BMP image + +static int bmp_test(stbi *s) +{ + int sz; + if (get8(s) != 'B') return 0; + if (get8(s) != 'M') return 0; + get32le(s); // discard filesize + get16le(s); // discard reserved + get16le(s); // discard reserved + get32le(s); // discard data offset + sz = get32le(s); + if (sz == 12 || sz == 40 || sz == 56 || sz == 108) return 1; + return 0; +} + +#ifndef STBI_NO_STDIO +int stbi_bmp_test_file (FILE *f) +{ + stbi s; + int r,n = ftell(f); + start_file(&s,f); + r = bmp_test(&s); + fseek(f,n,SEEK_SET); + return r; +} +#endif + +int stbi_bmp_test_memory (stbi_uc const *buffer, int len) +{ + stbi s; + start_mem(&s, buffer, len); + return bmp_test(&s); +} + +// returns 0..31 for the highest set bit +static int 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; + return n; +} + +static int bitcount(unsigned int a) +{ + a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 + a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits + a = (a + (a >> 8)); // max 16 per 8 bits + a = (a + (a >> 16)); // max 32 per 8 bits + return a & 0xff; +} + +static int 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; +} + +static stbi_uc *bmp_load(stbi *s, int *x, int *y, int *comp, int req_comp) +{ + uint8 *out; + unsigned int mr=0,mg=0,mb=0,ma=0, fake_a=0; + stbi_uc pal[256][4]; + int psize=0,i,j,compress=0,width; + int bpp, flip_vertically, pad, target, offset, hsz; + if (get8(s) != 'B' || get8(s) != 'M') return epuc("not BMP", "Corrupt BMP"); + get32le(s); // discard filesize + get16le(s); // discard reserved + get16le(s); // discard reserved + offset = get32le(s); + hsz = get32le(s); + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108) return epuc("unknown BMP", "BMP type not supported: unknown"); + if (hsz == 12) { + s->img_x = get16le(s); + s->img_y = get16le(s); + } else { + s->img_x = get32le(s); + s->img_y = get32le(s); + } + if (get16le(s) != 1) return epuc("bad BMP", "bad BMP"); + bpp = get16le(s); + if (bpp == 1) return epuc("monochrome", "BMP type not supported: 1-bit"); + flip_vertically = ((int) s->img_y) > 0; + s->img_y = abs((int) s->img_y); + if (hsz == 12) { + if (bpp < 24) + psize = (offset - 14 - 24) / 3; + } else { + compress = get32le(s); + if (compress == 1 || compress == 2) return epuc("BMP RLE", "BMP type not supported: RLE"); + get32le(s); // discard sizeof + get32le(s); // discard hres + get32le(s); // discard vres + get32le(s); // discard colorsused + get32le(s); // discard max important + if (hsz == 40 || hsz == 56) { + if (hsz == 56) { + get32le(s); + get32le(s); + get32le(s); + get32le(s); + } + if (bpp == 16 || bpp == 32) { + mr = mg = mb = 0; + if (compress == 0) { + if (bpp == 32) { + mr = 0xff << 16; + mg = 0xff << 8; + mb = 0xff << 0; + ma = 0xff << 24; + fake_a = 1; // @TODO: check for cases like alpha value is all 0 and switch it to 255 + } else { + mr = 31 << 10; + mg = 31 << 5; + mb = 31 << 0; + } + } else if (compress == 3) { + mr = get32le(s); + mg = get32le(s); + mb = get32le(s); + // not documented, but generated by photoshop and handled by mspaint + if (mr == mg && mg == mb) { + // ?!?!? + return epuc("bad BMP", "bad BMP"); + } + } else + return epuc("bad BMP", "bad BMP"); + } + } else { + assert(hsz == 108); + mr = get32le(s); + mg = get32le(s); + mb = get32le(s); + ma = get32le(s); + get32le(s); // discard color space + for (i=0; i < 12; ++i) + get32le(s); // discard color space parameters + } + if (bpp < 16) + psize = (offset - 14 - hsz) >> 2; + } + s->img_n = ma ? 4 : 3; + if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 + target = req_comp; + else + target = s->img_n; // if they want monochrome, we'll post-convert + out = (stbi_uc *) malloc(target * s->img_x * s->img_y); + if (!out) return epuc("outofmem", "Out of memory"); + if (bpp < 16) { + int z=0; + if (psize == 0 || psize > 256) { free(out); return epuc("invalid", "Corrupt BMP"); } + for (i=0; i < psize; ++i) { + pal[i][2] = get8(s); + pal[i][1] = get8(s); + pal[i][0] = get8(s); + if (hsz != 12) get8(s); + pal[i][3] = 255; + } + skip(s, offset - 14 - hsz - psize * (hsz == 12 ? 3 : 4)); + if (bpp == 4) width = (s->img_x + 1) >> 1; + else if (bpp == 8) width = s->img_x; + else { free(out); return epuc("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=get8(s),v2=0; + if (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 = (bpp == 8) ? get8(s) : v2; + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + } + 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; + skip(s, offset - 14 - hsz); + if (bpp == 24) width = 3 * s->img_x; + else if (bpp == 16) width = 2*s->img_x; + else /* bpp = 32 and pad = 0 */ width=0; + pad = (-width) & 3; + if (bpp == 24) { + easy = 1; + } else if (bpp == 32) { + if (mb == 0xff && mg == 0xff00 && mr == 0xff000000 && ma == 0xff000000) + easy = 2; + } + if (!easy) { + if (!mr || !mg || !mb) return epuc("bad masks", "Corrupt BMP"); + // right shift amt to put high bit in position #7 + rshift = high_bit(mr)-7; rcount = bitcount(mr); + gshift = high_bit(mg)-7; gcount = bitcount(mr); + bshift = high_bit(mb)-7; bcount = bitcount(mr); + ashift = high_bit(ma)-7; acount = bitcount(mr); + } + for (j=0; j < (int) s->img_y; ++j) { + if (easy) { + for (i=0; i < (int) s->img_x; ++i) { + int a; + out[z+2] = get8(s); + out[z+1] = get8(s); + out[z+0] = get8(s); + z += 3; + a = (easy == 2 ? get8(s) : 255); + if (target == 4) out[z++] = a; + } + } else { + for (i=0; i < (int) s->img_x; ++i) { + uint32 v = (bpp == 16 ? get16le(s) : get32le(s)); + int a; + out[z++] = shiftsigned(v & mr, rshift, rcount); + out[z++] = shiftsigned(v & mg, gshift, gcount); + out[z++] = shiftsigned(v & mb, bshift, bcount); + a = (ma ? shiftsigned(v & ma, ashift, acount) : 255); + if (target == 4) out[z++] = a; + } + } + skip(s, pad); + } + } + if (flip_vertically) { + stbi_uc t; + for (j=0; j < (int) s->img_y>>1; ++j) { + 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; + } + } + } + + if (req_comp && req_comp != target) { + out = convert_format(out, target, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // convert_format frees input on failure + } + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = target; + return out; +} + +#ifndef STBI_NO_STDIO +stbi_uc *stbi_bmp_load (char const *filename, int *x, int *y, int *comp, int req_comp) +{ + stbi_uc *data; + FILE *f = fopen(filename, "rb"); + if (!f) return NULL; + data = stbi_bmp_load_from_file(f, x,y,comp,req_comp); + fclose(f); + return data; +} + +stbi_uc *stbi_bmp_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi s; + start_file(&s, f); + return bmp_load(&s, x,y,comp,req_comp); +} +#endif + +stbi_uc *stbi_bmp_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi s; + start_mem(&s, buffer, len); + return bmp_load(&s, x,y,comp,req_comp); +} + +// Targa Truevision - TGA +// by Jonathan Dummer + +static int tga_info(stbi *s, int *x, int *y, int *comp) +{ + int tga_w, tga_h, tga_comp; + int sz; + get8u(s); // discard Offset + sz = get8u(s); // color type + if( sz > 1 ) return 0; // only RGB or indexed allowed + sz = get8u(s); // image type + // only RGB or grey allowed, +/- RLE + if ((sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11)) return 0; + get16le(s); // discard palette start + get16le(s); // discard palette length + get8(s); // discard bits per palette color entry + get16le(s); // discard x origin + get16le(s); // discard y origin + tga_w = get16le(s); + if( tga_w < 1 ) return 0; // test width + tga_h = get16le(s); + if( tga_h < 1 ) return 0; // test height + sz = get8(s); // bits per pixel + // only RGB or RGBA or grey allowed + if ((sz != 8) && (sz != 16) && (sz != 24) && (sz != 32)) return 0; + tga_comp = sz; + if (x) *x = tga_w; + if (y) *y = tga_h; + if (comp) *comp = tga_comp / 8; + return 1; // seems to have passed everything +} + +int stbi_tga_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + stbi s; + int r; + long n = ftell(f); + start_file(&s, f); + r = tga_info(&s, x, y, comp); + fseek(f, n, SEEK_SET); + return r; +} + +int stbi_tga_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + stbi s; + start_mem(&s, buffer, len); + return tga_info(&s, x, y, comp); +} + +static int tga_test(stbi *s) +{ + int sz; + get8u(s); // discard Offset + sz = get8u(s); // color type + if ( sz > 1 ) return 0; // only RGB or indexed allowed + sz = get8u(s); // image type + if ( (sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11) ) return 0; // only RGB or grey allowed, +/- RLE + get16(s); // discard palette start + get16(s); // discard palette length + get8(s); // discard bits per palette color entry + get16(s); // discard x origin + get16(s); // discard y origin + if ( get16(s) < 1 ) return 0; // test width + if ( get16(s) < 1 ) return 0; // test height + sz = get8(s); // bits per pixel + if ( (sz != 8) && (sz != 16) && (sz != 24) && (sz != 32) ) return 0; // only RGB or RGBA or grey allowed + return 1; // seems to have passed everything +} + +#ifndef STBI_NO_STDIO +int stbi_tga_test_file (FILE *f) +{ + stbi s; + int r,n = ftell(f); + start_file(&s, f); + r = tga_test(&s); + fseek(f,n,SEEK_SET); + return r; +} +#endif + +int stbi_tga_test_memory (stbi_uc const *buffer, int len) +{ + stbi s; + start_mem(&s, buffer, len); + return tga_test(&s); +} + +static stbi_uc *tga_load(stbi *s, int *x, int *y, int *comp, int req_comp) +{ + // read in the TGA header stuff + int tga_offset = get8u(s); + int tga_indexed = get8u(s); + int tga_image_type = get8u(s); + int tga_is_RLE = 0; + int tga_palette_start = get16le(s); + int tga_palette_len = get16le(s); + int tga_palette_bits = get8u(s); + int tga_x_origin = get16le(s); + int tga_y_origin = get16le(s); + int tga_width = get16le(s); + int tga_height = get16le(s); + int tga_bits_per_pixel = get8u(s); + int tga_inverted = get8u(s); + // image data + unsigned char *tga_data; + unsigned char *tga_palette = NULL; + int i, j; + unsigned char raw_data[4]; + unsigned char trans_data[4]; + int RLE_count = 0; + int RLE_repeating = 0; + int read_next_pixel = 1; + + // do a tiny bit of precessing + if ( tga_image_type >= 8 ) + { + tga_image_type -= 8; + tga_is_RLE = 1; + } + /* int tga_alpha_bits = tga_inverted & 15; */ + tga_inverted = 1 - ((tga_inverted >> 5) & 1); + + // error check + if ( //(tga_indexed) || + (tga_width < 1) || (tga_height < 1) || + (tga_image_type < 1) || (tga_image_type > 3) || + ((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16) && + (tga_bits_per_pixel != 24) && (tga_bits_per_pixel != 32)) + ) + { + return NULL; + } + + // If I'm paletted, then I'll use the number of bits from the palette + if ( tga_indexed ) + { + tga_bits_per_pixel = tga_palette_bits; + } + + // tga info + *x = tga_width; + *y = tga_height; + if ( (req_comp < 1) || (req_comp > 4) ) + { + // just use whatever the file was + req_comp = tga_bits_per_pixel / 8; + *comp = req_comp; + } else + { + // force a new number of components + *comp = tga_bits_per_pixel/8; + } + tga_data = (unsigned char*)malloc( tga_width * tga_height * req_comp ); + + // skip to the data's starting position (offset usually = 0) + skip(s, tga_offset ); + // do I need to load a palette? + if ( tga_indexed ) + { + // any data to skip? (offset usually = 0) + skip(s, tga_palette_start ); + // load the palette + tga_palette = (unsigned char*)malloc( tga_palette_len * tga_palette_bits / 8 ); + if (!getn(s, tga_palette, tga_palette_len * tga_palette_bits / 8 )) + return NULL; + } + // load the data + trans_data[0] = trans_data[1] = trans_data[2] = trans_data[3] = 0; + for (i=0; i < tga_width * tga_height; ++i) + { + // if I'm in RLE mode, do I need to get a RLE chunk? + if ( tga_is_RLE ) + { + if ( RLE_count == 0 ) + { + // yep, get the next byte as a RLE command + int RLE_cmd = get8u(s); + RLE_count = 1 + (RLE_cmd & 127); + RLE_repeating = RLE_cmd >> 7; + read_next_pixel = 1; + } else if ( !RLE_repeating ) + { + read_next_pixel = 1; + } + } else + { + read_next_pixel = 1; + } + // OK, if I need to read a pixel, do it now + if ( read_next_pixel ) + { + // load however much data we did have + if ( tga_indexed ) + { + // read in 1 byte, then perform the lookup + int pal_idx = get8u(s); + if ( pal_idx >= tga_palette_len ) + { + // invalid index + pal_idx = 0; + } + pal_idx *= tga_bits_per_pixel / 8; + for (j = 0; j*8 < tga_bits_per_pixel; ++j) + { + raw_data[j] = tga_palette[pal_idx+j]; + } + } else + { + // read in the data raw + for (j = 0; j*8 < tga_bits_per_pixel; ++j) + { + raw_data[j] = get8u(s); + } + } + // convert raw to the intermediate format + switch (tga_bits_per_pixel) + { + case 8: + // Luminous => RGBA + trans_data[0] = raw_data[0]; + trans_data[1] = raw_data[0]; + trans_data[2] = raw_data[0]; + trans_data[3] = 255; + break; + case 16: + // Luminous,Alpha => RGBA + trans_data[0] = raw_data[0]; + trans_data[1] = raw_data[0]; + trans_data[2] = raw_data[0]; + trans_data[3] = raw_data[1]; + break; + case 24: + // BGR => RGBA + trans_data[0] = raw_data[2]; + trans_data[1] = raw_data[1]; + trans_data[2] = raw_data[0]; + trans_data[3] = 255; + break; + case 32: + // BGRA => RGBA + trans_data[0] = raw_data[2]; + trans_data[1] = raw_data[1]; + trans_data[2] = raw_data[0]; + trans_data[3] = raw_data[3]; + break; + } + // clear the reading flag for the next pixel + read_next_pixel = 0; + } // end of reading a pixel + // convert to final format + switch (req_comp) + { + case 1: + // RGBA => Luminance + tga_data[i*req_comp+0] = compute_y(trans_data[0],trans_data[1],trans_data[2]); + break; + case 2: + // RGBA => Luminance,Alpha + tga_data[i*req_comp+0] = compute_y(trans_data[0],trans_data[1],trans_data[2]); + tga_data[i*req_comp+1] = trans_data[3]; + break; + case 3: + // RGBA => RGB + tga_data[i*req_comp+0] = trans_data[0]; + tga_data[i*req_comp+1] = trans_data[1]; + tga_data[i*req_comp+2] = trans_data[2]; + break; + case 4: + // RGBA => RGBA + tga_data[i*req_comp+0] = trans_data[0]; + tga_data[i*req_comp+1] = trans_data[1]; + tga_data[i*req_comp+2] = trans_data[2]; + tga_data[i*req_comp+3] = trans_data[3]; + break; + } + // in case we're in RLE mode, keep counting down + --RLE_count; + } + // do I need to invert the image? + if ( tga_inverted ) + { + for (j = 0; j*2 < tga_height; ++j) + { + int index1 = j * tga_width * req_comp; + int index2 = (tga_height - 1 - j) * tga_width * req_comp; + for (i = tga_width * req_comp; i > 0; --i) + { + unsigned char temp = tga_data[index1]; + tga_data[index1] = tga_data[index2]; + tga_data[index2] = temp; + ++index1; + ++index2; + } + } + } + // clear my palette, if I had one + if ( tga_palette != NULL ) + { + free( tga_palette ); + } + // the things I do to get rid of an error message, and yet keep + // Microsoft's C compilers happy... [8^( + tga_palette_start = tga_palette_len = tga_palette_bits = + tga_x_origin = tga_y_origin = 0; + // OK, done + return tga_data; +} + +#ifndef STBI_NO_STDIO +stbi_uc *stbi_tga_load (char const *filename, int *x, int *y, int *comp, int req_comp) +{ + stbi_uc *data; + FILE *f = fopen(filename, "rb"); + if (!f) return NULL; + data = stbi_tga_load_from_file(f, x,y,comp,req_comp); + fclose(f); + return data; +} + +stbi_uc *stbi_tga_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi s; + start_file(&s, f); + return tga_load(&s, x,y,comp,req_comp); +} +#endif + +stbi_uc *stbi_tga_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi s; + start_mem(&s, buffer, len); + return tga_load(&s, x,y,comp,req_comp); +} + + +// ************************************************************************************************* +// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB + +static int psd_test(stbi *s) +{ + if (get32(s) != 0x38425053) return 0; // "8BPS" + else return 1; +} + +#ifndef STBI_NO_STDIO +int stbi_psd_test_file(FILE *f) +{ + stbi s; + int r,n = ftell(f); + start_file(&s, f); + r = psd_test(&s); + fseek(f,n,SEEK_SET); + return r; +} +#endif + +int stbi_psd_test_memory(stbi_uc const *buffer, int len) +{ + stbi s; + start_mem(&s, buffer, len); + return psd_test(&s); +} + +static stbi_uc *psd_load(stbi *s, int *x, int *y, int *comp, int req_comp) +{ + int pixelCount; + int channelCount, compression; + int channel, i, count, len; + int w,h; + uint8 *out; + + // Check identifier + if (get32(s) != 0x38425053) // "8BPS" + return epuc("not PSD", "Corrupt PSD image"); + + // Check file type version. + if (get16(s) != 1) + return epuc("wrong version", "Unsupported version of PSD image"); + + // Skip 6 reserved bytes. + skip(s, 6 ); + + // Read the number of channels (R, G, B, A, etc). + channelCount = get16(s); + if (channelCount < 0 || channelCount > 16) + return epuc("wrong channel count", "Unsupported number of channels in PSD image"); + + // Read the rows and columns of the image. + h = get32(s); + w = get32(s); + + // Make sure the depth is 8 bits. + if (get16(s) != 8) + return epuc("unsupported bit depth", "PSD bit depth is not 8 bit"); + + // Make sure the color mode is RGB. + // Valid options are: + // 0: Bitmap + // 1: Grayscale + // 2: Indexed color + // 3: RGB color + // 4: CMYK color + // 7: Multichannel + // 8: Duotone + // 9: Lab color + if (get16(s) != 3) + return epuc("wrong color format", "PSD is not in RGB color format"); + + // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) + skip(s,get32(s) ); + + // Skip the image resources. (resolution, pen tool paths, etc) + skip(s, get32(s) ); + + // Skip the reserved data. + skip(s, get32(s) ); + + // Find out if the data is compressed. + // Known values: + // 0: no compression + // 1: RLE compressed + compression = get16(s); + if (compression > 1) + return epuc("bad compression", "PSD has an unknown compression format"); + + // Create the destination image. + out = (stbi_uc *) malloc(4 * w*h); + if (!out) return epuc("outofmem", "Out of memory"); + pixelCount = w*h; + + // Initialize the data to zero. + //memset( out, 0, pixelCount * 4 ); + + // Finally, the image data. + if (compression) { + // RLE as used by .PSD and .TIFF + // Loop until you get the number of unpacked bytes you are expecting: + // Read the next source byte into n. + // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. + // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. + // 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, + // which we're going to just skip. + skip(s, h * channelCount * 2 ); + + // Read the RLE data by channel. + for (channel = 0; channel < 4; channel++) { + uint8 *p; + + p = out+channel; + if (channel >= channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++) *p = (channel == 3 ? 255 : 0), p += 4; + } else { + // Read the RLE data. + count = 0; + while (count < pixelCount) { + len = get8(s); + if (len == 128) { + // No-op. + } else if (len < 128) { + // Copy next len+1 bytes literally. + len++; + count += len; + while (len) { + *p = get8(s); + p += 4; + len--; + } + } else if (len > 128) { + uint32 val; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len ^= 0x0FF; + len += 2; + val = get8(s); + count += len; + while (len) { + *p = val; + p += 4; + len--; + } + } + } + } + } + + } else { + // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) + // where each channel consists of an 8-bit value for each pixel in the image. + + // Read the data by channel. + for (channel = 0; channel < 4; channel++) { + uint8 *p; + + p = out + channel; + if (channel > channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++) *p = channel == 3 ? 255 : 0, p += 4; + } else { + // Read the data. + for (i = 0; i < pixelCount; i++) + *p = get8(s), p += 4; + } + } + } + + if (req_comp && req_comp != 4) { + out = convert_format(out, 4, req_comp, w, h); + if (out == NULL) return out; // convert_format frees input on failure + } + + if (comp) *comp = channelCount; + *y = h; + *x = w; + + return out; +} + +#ifndef STBI_NO_STDIO +stbi_uc *stbi_psd_load(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + stbi_uc *data; + FILE *f = fopen(filename, "rb"); + if (!f) return NULL; + data = stbi_psd_load_from_file(f, x,y,comp,req_comp); + fclose(f); + return data; +} + +stbi_uc *stbi_psd_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi s; + start_file(&s, f); + return psd_load(&s, x,y,comp,req_comp); +} +#endif + +stbi_uc *stbi_psd_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi s; + start_mem(&s, buffer, len); + return psd_load(&s, x,y,comp,req_comp); +} + +// ************************************************************************************************* +// Softimage PIC loader +// by Tom Seddon +// +// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format +// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ + +static int pic_is4(stbi *s,const char *str) +{ + int i; + for (i=0; i<4; ++i) + if (get8(s) != (stbi_uc)str[i]) + return 0; + + return 1; +} + +static int pic_test(stbi *s) +{ + int i; + + if (!pic_is4(s,"\x53\x80\xF6\x34")) + return 0; + + for(i=0;i<84;++i) + get8(s); + + if (!pic_is4(s,"PICT")) + return 0; + + return 1; +} + +typedef struct +{ + stbi_uc size,type,channel; +} pic_packet_t; + +static stbi_uc *pic_readval(stbi *s, int channel, stbi_uc *dest) +{ + int mask=0x80, i; + + for (i=0; i<4; ++i, mask>>=1) { + if (channel & mask) { + if (at_eof(s)) return epuc("bad file","PIC file too short"); + dest[i]=get8(s); + } + } + + return dest; +} + +static void pic_copyval(int channel,stbi_uc *dest,const stbi_uc *src) +{ + int mask=0x80,i; + + for (i=0;i<4; ++i, mask>>=1) + if (channel&mask) + dest[i]=src[i]; +} + +static stbi_uc *pic_load2(stbi *s,int width,int height,int *comp, stbi_uc *result) +{ + int act_comp=0,num_packets=0,y,chained; + pic_packet_t packets[10]; + + // this will (should...) cater for even some bizarre stuff like having data + // for the same channel in multiple packets. + do { + pic_packet_t *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return epuc("bad format","too many packets"); + + packet = &packets[num_packets++]; + + chained = get8(s); + packet->size = get8(s); + packet->type = get8(s); + packet->channel = get8(s); + + act_comp |= packet->channel; + + if (at_eof(s)) return epuc("bad file","file too short (reading packets)"); + if (packet->size != 8) return epuc("bad format","packet isn't 8bpp"); + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? + + for(y=0; ytype) { + default: + return epuc("bad format","packet has bad compression type"); + + case 0: {//uncompressed + int x; + + for(x=0;xchannel,dest)) + return 0; + break; + } + + case 1://Pure RLE + { + int left=width, i; + + while (left>0) { + stbi_uc count,value[4]; + + count=get8(s); + if (at_eof(s)) return epuc("bad file","file too short (pure read count)"); + + if (count > left) + count = left; + + if (!pic_readval(s,packet->channel,value)) return 0; + + for(i=0; ichannel,dest,value); + left -= count; + } + } + break; + + case 2: {//Mixed RLE + int left=width; + while (left>0) { + int count = get8(s), i; + if (at_eof(s)) return epuc("bad file","file too short (mixed read count)"); + + if (count >= 128) { // Repeated + stbi_uc value[4]; + int i; + + if (count==128) + count = get16(s); + else + count -= 127; + if (count > left) + return epuc("bad file","scanline overrun"); + + if (!pic_readval(s,packet->channel,value)) + return 0; + + for(i=0;ichannel,dest,value); + } else { // Raw + ++count; + if (count>left) return epuc("bad file","scanline overrun"); + + for(i=0;ichannel,dest)) + return 0; + } + left-=count; + } + break; + } + } + } + } + + return result; +} + +static stbi_uc *pic_load(stbi *s,int *px,int *py,int *comp,int req_comp) +{ + stbi_uc *result; + int i, x,y; + + for (i=0; i<92; ++i) + get8(s); + + x = get16(s); + y = get16(s); + if (at_eof(s)) return epuc("bad file","file too short (pic header)"); + if ((1 << 28) / x < y) return epuc("too large", "Image too large to decode"); + + get32(s); //skip `ratio' + get16(s); //skip `fields' + get16(s); //skip `pad' + + // intermediate buffer is RGBA + result = (stbi_uc *) malloc(x*y*4); + memset(result, 0xff, x*y*4); + + if (!pic_load2(s,x,y,comp, result)) { + free(result); + result=0; + } + *px = x; + *py = y; + if (req_comp == 0) req_comp = *comp; + result=convert_format(result,4,req_comp,x,y); + + return result; +} + +int stbi_pic_test_memory(stbi_uc const *buffer, int len) +{ + stbi s; + start_mem(&s,buffer,len); + return pic_test(&s); +} + +stbi_uc *stbi_pic_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi s; + start_mem(&s,buffer,len); + return pic_load(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_STDIO +int stbi_pic_test_file(FILE *f) +{ + int result; + long l = ftell(f); + stbi s; + start_file(&s,f); + result = pic_test(&s); + fseek(f,l,SEEK_SET); + return result; +} + +stbi_uc *stbi_pic_load(char const *filename,int *x, int *y, int *comp, int req_comp) +{ + stbi_uc *result; + FILE *f=fopen(filename,"rb"); + if (!f) return 0; + result = stbi_pic_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +stbi_uc *stbi_pic_load_from_file(FILE *f,int *x, int *y, int *comp, int req_comp) +{ + stbi s; + start_file(&s,f); + return pic_load(&s,x,y,comp,req_comp); +} +#endif + +// ************************************************************************************************* +// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb +typedef struct stbi_gif_lzw_struct { + int16 prefix; + uint8 first; + uint8 suffix; +} stbi_gif_lzw; + +typedef struct stbi_gif_struct +{ + int w,h; + stbi_uc *out; // output buffer (always 4 components) + int flags, bgindex, ratio, transparent, eflags; + uint8 pal[256][4]; + uint8 lpal[256][4]; + stbi_gif_lzw codes[4096]; + uint8 *color_table; + int parse, step; + int lflags; + int start_x, start_y; + int max_x, max_y; + int cur_x, cur_y; + int line_size; +} stbi_gif; + +static int gif_test(stbi *s) +{ + int sz; + if (get8(s) != 'G' || get8(s) != 'I' || get8(s) != 'F' || get8(s) != '8') return 0; + sz = get8(s); + if (sz != '9' && sz != '7') return 0; + if (get8(s) != 'a') return 0; + return 1; +} + +#ifndef STBI_NO_STDIO +int stbi_gif_test_file (FILE *f) +{ + stbi s; + int r,n = ftell(f); + start_file(&s,f); + r = gif_test(&s); + fseek(f,n,SEEK_SET); + return r; +} +#endif + +int stbi_gif_test_memory (stbi_uc const *buffer, int len) +{ + stbi s; + start_mem(&s, buffer, len); + return gif_test(&s); +} + +static void stbi_gif_parse_colortable(stbi *s, stbi_gif *g, uint8 pal[256][4], int num_entries, int transp) +{ + int i; + for (i=0; i < num_entries; ++i) { + g->pal[i][2] = get8(s); + g->pal[i][1] = get8(s); + g->pal[i][0] = get8(s); + g->pal[i][3] = transp ? 0 : 255; + } +} + +static int stbi_gif_header(stbi *s, stbi_gif *g, int *comp, int is_info) +{ + uint8 version; + if (get8(s) != 'G' || get8(s) != 'I' || get8(s) != 'F' || get8(s) != '8') + return e("not GIF", "Corrupt GIF"); + + version = get8(s); + if (version != '7' && version != '9') return e("not GIF", "Corrupt GIF"); + if (get8(s) != 'a') return e("not GIF", "Corrupt GIF"); + + failure_reason = ""; + g->w = get16le(s); + g->h = get16le(s); + g->flags = get8(s); + g->bgindex = get8(s); + g->ratio = get8(s); + g->transparent = -1; + + 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; + + if (g->flags & 0x80) + stbi_gif_parse_colortable(s,g,g->pal, 2 << (g->flags & 7), -1); + + return 1; +} + +static int stbi_gif_info_raw(stbi *s, int *x, int *y, int *comp) +{ + stbi_gif g; + if (!stbi_gif_header(s, &g, comp, 1)) return 0; + if (x) *x = g.w; + if (y) *y = g.h; + return 1; +} + +static void stbi_out_gif_code(stbi_gif *g, uint16 code) +{ + uint8 *p, *c; + + // recurse to decode the prefixes, since the linked-list is backwards, + // and working backwards through an interleaved image would be nasty + if (g->codes[code].prefix >= 0) + stbi_out_gif_code(g, g->codes[code].prefix); + + if (g->cur_y >= g->max_y) return; + + p = &g->out[g->cur_x + g->cur_y]; + c = &g->color_table[g->codes[code].suffix * 4]; + + if (c[3] >= 128) { + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = c[3]; + } + g->cur_x += 4; + + if (g->cur_x >= g->max_x) { + g->cur_x = g->start_x; + g->cur_y += g->step; + + while (g->cur_y >= g->max_y && g->parse > 0) { + g->step = (1 << g->parse) * g->line_size; + g->cur_y = g->start_y + (g->step >> 1); + --g->parse; + } + } +} + +static uint8 *stbi_process_gif_raster(stbi *s, stbi_gif *g) +{ + uint8 lzw_cs; + int32 len, code; + uint32 first; + int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; + stbi_gif_lzw *p; + + lzw_cs = get8(s); + clear = 1 << lzw_cs; + first = 1; + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + bits = 0; + valid_bits = 0; + for (code = 0; code < clear; code++) { + g->codes[code].prefix = -1; + g->codes[code].first = code; + g->codes[code].suffix = code; + } + + // support no starting clear code + avail = clear+2; + oldcode = -1; + + len = 0; + for(;;) { + if (valid_bits < codesize) { + if (len == 0) { + len = get8(s); // start new block + if (len == 0) + return g->out; + } + --len; + bits |= (int32) get8(s) << valid_bits; + valid_bits += 8; + } else { + int32 code = bits & codemask; + bits >>= codesize; + valid_bits -= codesize; + // @OPTIMIZE: is there some way we can accelerate the non-clear path? + if (code == clear) { // clear code + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + avail = clear + 2; + oldcode = -1; + first = 0; + } else if (code == clear + 1) { // end of stream code + skip(s, len); + while ((len = get8(s)) > 0) + skip(s,len); + return g->out; + } else if (code <= avail) { + if (first) return epuc("no clear code", "Corrupt GIF"); + + if (oldcode >= 0) { + p = &g->codes[avail++]; + if (avail > 4096) return epuc("too many codes", "Corrupt GIF"); + p->prefix = oldcode; + p->first = g->codes[oldcode].first; + p->suffix = (code == avail) ? p->first : g->codes[code].first; + } else if (code == avail) + return epuc("illegal code in raster", "Corrupt GIF"); + + stbi_out_gif_code(g, code); + + if ((avail & codemask) == 0 && avail <= 0x0FFF) { + codesize++; + codemask = (1 << codesize) - 1; + } + + oldcode = code; + } else { + return epuc("illegal code in raster", "Corrupt GIF"); + } + } + } +} + +static void stbi_fill_gif_background(stbi_gif *g) +{ + int i; + uint8 *c = g->pal[g->bgindex]; + // @OPTIMIZE: write a dword at a time + for (i = 0; i < g->w * g->h * 4; i += 4) { + uint8 *p = &g->out[i]; + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = c[3]; + } +} + +// this function is designed to support animated gifs, although stb_image doesn't support it +static uint8 *stbi_gif_load_next(stbi *s, stbi_gif *g, int *comp, int req_comp) +{ + int i; + uint8 *old_out = 0; + + if (g->out == 0) { + if (!stbi_gif_header(s, g, comp,0)) return 0; // failure_reason set by stbi_gif_header + g->out = (uint8 *) malloc(4 * g->w * g->h); + if (g->out == 0) return epuc("outofmem", "Out of memory"); + stbi_fill_gif_background(g); + } else { + // animated-gif-only path + if (((g->eflags & 0x1C) >> 2) == 3) { + old_out = g->out; + g->out = (uint8 *) malloc(4 * g->w * g->h); + if (g->out == 0) return epuc("outofmem", "Out of memory"); + memcpy(g->out, old_out, g->w*g->h*4); + } + } + + for (;;) { + switch (get8(s)) { + case 0x2C: /* Image Descriptor */ + { + int32 x, y, w, h; + uint8 *o; + + x = get16le(s); + y = get16le(s); + w = get16le(s); + h = get16le(s); + if (((x + w) > (g->w)) || ((y + h) > (g->h))) + return epuc("bad Image Descriptor", "Corrupt GIF"); + + g->line_size = g->w * 4; + g->start_x = x * 4; + g->start_y = y * g->line_size; + g->max_x = g->start_x + w * 4; + g->max_y = g->start_y + h * g->line_size; + g->cur_x = g->start_x; + g->cur_y = g->start_y; + + g->lflags = get8(s); + + if (g->lflags & 0x40) { + g->step = 8 * g->line_size; // first interlaced spacing + g->parse = 3; + } else { + g->step = g->line_size; + g->parse = 0; + } + + if (g->lflags & 0x80) { + stbi_gif_parse_colortable(s,g,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); + g->color_table = (uint8 *) g->lpal; + } else if (g->flags & 0x80) { + for (i=0; i < 256; ++i) // @OPTIMIZE: reset only the previous transparent + g->pal[i][3] = 255; + if (g->transparent >= 0 && (g->eflags & 0x01)) + g->pal[i][3] = 0; + g->color_table = (uint8 *) g->pal; + } else + return epuc("missing color table", "Corrupt GIF"); + + o = stbi_process_gif_raster(s, g); + if (o == NULL) return NULL; + + if (req_comp && req_comp != 4) + o = convert_format(o, 4, req_comp, g->w, g->h); + return o; + } + + case 0x21: // Comment Extension. + { + int len; + if (get8(s) == 0xF9) { // Graphic Control Extension. + len = get8(s); + if (len == 4) { + g->eflags = get8(s); + get16le(s); // delay + g->transparent = get8(s); + } else { + skip(s, len); + break; + } + } + while ((len = get8(s)) != 0) + skip(s, len); + break; + } + + case 0x3B: // gif stream termination code + return (uint8 *) 1; + + default: + return epuc("unknown code", "Corrupt GIF"); + } + } +} + +#ifndef STBI_NO_STDIO +stbi_uc *stbi_gif_load (char const *filename, int *x, int *y, int *comp, int req_comp) +{ + uint8 *data; + FILE *f = fopen(filename, "rb"); + if (!f) return NULL; + data = stbi_gif_load_from_file(f, x,y,comp,req_comp); + fclose(f); + return data; +} + +stbi_uc *stbi_gif_load_from_file (FILE *f, int *x, int *y, int *comp, int req_comp) +{ + uint8 *u = 0; + stbi s; + stbi_gif g={0}; + start_file(&s, f); + + u = stbi_gif_load_next(&s, &g, comp, req_comp); + if (u == (void *) 1) u = 0; // end of animated gif marker + if (u) { + *x = g.w; + *y = g.h; + } + + return u; +} +#endif + +stbi_uc *stbi_gif_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + uint8 *u = 0; + stbi s; + stbi_gif g={0}; + start_mem(&s, buffer, len); + u = stbi_gif_load_next(&s, &g, comp, req_comp); + if (u == (void *) 1) u = 0; // end of animated gif marker + if (u) { + *x = g.w; + *y = g.h; + } + return u; +} + +#ifndef STBI_NO_STDIO +int stbi_gif_info (char const *filename, int *x, int *y, int *comp) +{ + int res; + FILE *f = fopen(filename, "rb"); + if (!f) return 0; + res = stbi_gif_info_from_file(f, x, y, comp); + fclose(f); + return res; +} + +int stbi_gif_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + stbi s; + int res; + long n = ftell(f); + start_file(&s, f); + res = stbi_gif_info_raw(&s, x, y, comp); + fseek(f, n, SEEK_SET); + return res; +} +#endif // !STBI_NO_STDIO + +int stbi_gif_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + stbi s; + start_mem(&s, buffer, len); + return stbi_gif_info_raw(&s, x, y, comp); +} + + + + +// ************************************************************************************************* +// Radiance RGBE HDR loader +// originally by Nicolas Schulz +#ifndef STBI_NO_HDR +static int hdr_test(stbi *s) +{ + const char *signature = "#?RADIANCE\n"; + int i; + for (i=0; signature[i]; ++i) + if (get8(s) != signature[i]) + return 0; + return 1; +} + +int stbi_hdr_test_memory(stbi_uc const *buffer, int len) +{ + stbi s; + start_mem(&s, buffer, len); + return hdr_test(&s); +} + +#ifndef STBI_NO_STDIO +int stbi_hdr_test_file(FILE *f) +{ + stbi s; + int r,n = ftell(f); + start_file(&s, f); + r = hdr_test(&s); + fseek(f,n,SEEK_SET); + return r; +} +#endif + +#define HDR_BUFLEN 1024 +static char *hdr_gettoken(stbi *z, char *buffer) +{ + int len=0; + char c = '\0'; + + c = get8(z); + + while (!at_eof(z) && c != '\n') { + buffer[len++] = c; + if (len == HDR_BUFLEN-1) { + // flush to end of line + while (!at_eof(z) && get8(z) != '\n') + ; + break; + } + c = get8(z); + } + + buffer[len] = 0; + return buffer; +} + +static void hdr_convert(float *output, stbi_uc *input, int req_comp) +{ + if ( input[3] != 0 ) { + float f1; + // Exponent + f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); + if (req_comp <= 2) + output[0] = (input[0] + input[1] + input[2]) * f1 / 3; + else { + output[0] = input[0] * f1; + output[1] = input[1] * f1; + output[2] = input[2] * f1; + } + if (req_comp == 2) output[1] = 1; + if (req_comp == 4) output[3] = 1; + } else { + switch (req_comp) { + case 4: output[3] = 1; /* fallthrough */ + case 3: output[0] = output[1] = output[2] = 0; + break; + case 2: output[1] = 1; /* fallthrough */ + case 1: output[0] = 0; + break; + } + } +} + + +static float *hdr_load(stbi *s, int *x, int *y, int *comp, int req_comp) +{ + char buffer[HDR_BUFLEN]; + char *token; + int valid = 0; + int width, height; + stbi_uc *scanline; + float *hdr_data; + int len; + unsigned char count, value; + int i, j, k, c1,c2, z; + + + // Check identifier + if (strcmp(hdr_gettoken(s,buffer), "#?RADIANCE") != 0) + return epf("not HDR", "Corrupt HDR image"); + + // Parse header + while (1) { + token = hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) return epf("unsupported format", "Unsupported HDR format"); + + // Parse width and height + // can't use sscanf() if we're not using stdio! + token = hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) return epf("unsupported data layout", "Unsupported HDR format"); + token += 3; + height = strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) return epf("unsupported data layout", "Unsupported HDR format"); + token += 3; + width = strtol(token, NULL, 10); + + *x = width; + *y = height; + + *comp = 3; + if (req_comp == 0) req_comp = 3; + + // Read data + hdr_data = (float *) malloc(height * width * req_comp * sizeof(float)); + + // Load image data + // image data is stored as some number of sca + if ( width < 8 || width >= 32768) { + // Read flat data + for (j=0; j < height; ++j) { + for (i=0; i < width; ++i) { + stbi_uc rgbe[4]; + main_decode_loop: + getn(s, rgbe, 4); + hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); + } + } + } else { + // Read RLE-encoded data + scanline = NULL; + + for (j = 0; j < height; ++j) { + c1 = get8(s); + c2 = get8(s); + len = get8(s); + if (c1 != 2 || c2 != 2 || (len & 0x80)) { + // not run-length encoded, so we have to actually use THIS data as a decoded + // pixel (note this can't be a valid pixel--one of RGB must be >= 128) + stbi_uc rgbe[4] = { c1,c2,len, get8(s) }; + hdr_convert(hdr_data, rgbe, req_comp); + i = 1; + j = 0; + free(scanline); + goto main_decode_loop; // yes, this makes no sense + } + len <<= 8; + len |= get8(s); + if (len != width) { free(hdr_data); free(scanline); return epf("invalid decoded scanline length", "corrupt HDR"); } + if (scanline == NULL) scanline = (stbi_uc *) malloc(width * 4); + + for (k = 0; k < 4; ++k) { + i = 0; + while (i < width) { + count = get8(s); + if (count > 128) { + // Run + value = get8(s); + count -= 128; + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = value; + } else { + // Dump + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = get8(s); + } + } + } + for (i=0; i < width; ++i) + hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); + } + free(scanline); + } + + return hdr_data; +} + +#ifndef STBI_NO_STDIO +float *stbi_hdr_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi s; + start_file(&s,f); + return hdr_load(&s,x,y,comp,req_comp); +} +#endif + +float *stbi_hdr_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi s; + start_mem(&s,buffer, len); + return hdr_load(&s,x,y,comp,req_comp); +} + +#endif // STBI_NO_HDR + + +#ifndef STBI_NO_STDIO +int stbi_info(char const *filename, int *x, int *y, int *comp) +{ + FILE *f = fopen(filename, "rb"); + int result; + if (!f) return e("can't fopen", "Unable to open file"); + result = stbi_info_from_file(f, x, y, comp); + fclose(f); + return result; +} + +int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + if (stbi_jpeg_info_from_file(f, x, y, comp)) + return 1; + if (stbi_png_info_from_file(f, x, y, comp)) + return 1; + if (stbi_gif_info_from_file(f, x, y, comp)) + return 1; + // @TODO: stbi_bmp_info_from_file + // @TODO: stbi_psd_info_from_file + #ifndef STBI_NO_HDR + // @TODO: stbi_hdr_info_from_file + #endif + // test tga last because it's a crappy test! + if (stbi_tga_info_from_file(f, x, y, comp)) + return 1; + return e("unknown image type", "Image not of any known type, or corrupt"); +} +#endif // !STBI_NO_STDIO + +int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + if (stbi_jpeg_info_from_memory(buffer, len, x, y, comp)) + return 1; + if (stbi_png_info_from_memory(buffer, len, x, y, comp)) + return 1; + if (stbi_gif_info_from_memory(buffer, len, x, y, comp)) + return 1; + // @TODO: stbi_bmp_info_from_memory + // @TODO: stbi_psd_info_from_memory + #ifndef STBI_NO_HDR + // @TODO: stbi_hdr_info_from_memory + #endif + // test tga last because it's a crappy test! + if (stbi_tga_info_from_memory(buffer, len, x, y, comp)) + return 1; + return e("unknown image type", "Image not of any known type, or corrupt"); +} + +#endif // STBI_HEADER_FILE_ONLY + +/* + revision history: + 1.26 (2010-07-24) + fix bug in file buffering for PNG reported by SpartanJ + 1.25 (2010-07-17) + refix trans_data warning (Won Chun) + 1.24 (2010-07-12) + perf improvements reading from files on platforms with lock-heavy fgetc() + minor perf improvements for jpeg + deprecated type-specific functions so we'll get feedback if they're needed + attempt to fix trans_data warning (Won Chun) + 1.23 fixed bug in iPhone support + 1.22 (2010-07-10) + removed image *writing* support + removed image *writing* support + stbi_info support from Jetro Lauha + GIF support from Jean-Marc Lienher + iPhone PNG-extensions from James Brown + warning-fixes from Nicolas Schulz and Janez Zemva (i.e. Janez (U+017D)emva) + 1.21 fix use of 'uint8' in header (reported by jon blow) + 1.20 added support for Softimage PIC, by Tom Seddon + 1.19 bug in interlaced PNG corruption check (found by ryg) + 1.18 2008-08-02 + fix a threading bug (local mutable static) + 1.17 support interlaced PNG + 1.16 major bugfix - convert_format converted one too many pixels + 1.15 initialize some fields for thread safety + 1.14 fix threadsafe conversion bug + header-file-only version (#define STBI_HEADER_FILE_ONLY before including) + 1.13 threadsafe + 1.12 const qualifiers in the API + 1.11 Support installable IDCT, colorspace conversion routines + 1.10 Fixes for 64-bit (don't use "unsigned long") + optimized upsampling by Fabian "ryg" Giesen + 1.09 Fix format-conversion for PSD code (bad global variables!) + 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz + 1.07 attempt to fix C++ warning/errors again + 1.06 attempt to fix C++ warning/errors again + 1.05 fix TGA loading to return correct *comp and use good luminance calc + 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free + 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR + 1.02 support for (subset of) HDR files, float interface for preferred access to them + 1.01 fix bug: possible bug in handling right-side up bmps... not sure + fix bug: the stbi_bmp_load() and stbi_tga_load() functions didn't work at all + 1.00 interface to zlib that skips zlib header + 0.99 correct handling of alpha in palette + 0.98 TGA loader by lonesock; dynamically add loaders (untested) + 0.97 jpeg errors on too large a file; also catch another malloc failure + 0.96 fix detection of invalid v value - particleman@mollyrocket forum + 0.95 during header scan, seek to markers in case of padding + 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same + 0.93 handle jpegtran output; verbose errors + 0.92 read 4,8,16,24,32-bit BMP files of several formats + 0.91 output 24-bit Windows 3.0 BMP files + 0.90 fix a few more warnings; bump version number to approach 1.0 + 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd + 0.60 fix compiling as c++ + 0.59 fix warnings: merge Dave Moore's -Wall fixes + 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian + 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less + than 16 available + 0.56 fix bug: zlib uncompressed mode len vs. nlen + 0.55 fix bug: restart_interval not initialized to 0 + 0.54 allow NULL for 'int *comp' + 0.53 fix bug in png 3->4; speedup png decoding + 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments + 0.51 obey req_comp requests, 1-component jpegs return as 1-component, + on 'test' only check type, not whether we support this variant +*/ diff --git a/src/SFML/Graphics/stb_image/stb_image_write.h b/src/SFML/Graphics/stb_image/stb_image_write.h new file mode 100644 index 00000000..3c749d5a --- /dev/null +++ b/src/SFML/Graphics/stb_image/stb_image_write.h @@ -0,0 +1,504 @@ +/* stbiw-0.91 - public domain - http://nothings.org/stb/stb_image_write.h + writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010 + no warranty implied; use at your own risk + + +Before including, + + #define STB_IMAGE_WRITE_IMPLEMENTATION + +in the file that you want to have the implementation. + + +ABOUT: + + This header file is a library for writing images to C stdio. It could be + adapted to write to memory or a general streaming interface; let me know. + + The PNG output is not optimal; it is 20-50% larger than the file + written by a decent optimizing implementation. This library is designed + for source code compactness and simplicitly, not optimal image file size + or run-time performance. + +USAGE: + + There are three functions, one for each image file format: + + int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); + int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); + int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); + + Each function returns 0 on failure and non-0 on success. + + The functions create an image file defined by the parameters. The image + is a rectangle of pixels stored from left-to-right, top-to-bottom. + Each pixel contains 'comp' channels of data stored interleaved with 8-bits + per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is + monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall. + The *data pointer points to the first byte of the top-left-most pixel. + For PNG, "stride_in_bytes" is the distance in bytes from the first byte of + a row of pixels to the first byte of the next row of pixels. + + PNG creates output files with the same number of components as the input. + The BMP and TGA formats expand Y to RGB in the file format. BMP does not + output alpha. + + PNG supports writing rectangles of data even when the bytes storing rows of + data are not consecutive in memory (e.g. sub-rectangles of a larger image), + by supplying the stride between the beginning of adjacent rows. The other + formats do not. (Thus you cannot write a native-format BMP through the BMP + writer, both because it is in BGR order and because it may have padding + at the end of the line.) +*/ + +#ifndef INCLUDE_STB_IMAGE_WRITE_H +#define INCLUDE_STB_IMAGE_WRITE_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); +extern int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); +extern int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); + +#ifdef __cplusplus +} +#endif + +#endif//INCLUDE_STB_IMAGE_WRITE_H + +#ifdef STB_IMAGE_WRITE_IMPLEMENTATION + +#include +#include +#include +#include +#include + +typedef unsigned int stbiw_uint32; +typedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1]; + +static void writefv(FILE *f, const char *fmt, va_list v) +{ + while (*fmt) { + switch (*fmt++) { + case ' ': break; + case '1': { unsigned char x = va_arg(v, int); fputc(x,f); break; } + case '2': { int x = va_arg(v,int); unsigned char b[2]; b[0] = x; b[1] = x>>8; fwrite(b,2,1,f); break; } + case '4': { stbiw_uint32 x = va_arg(v,int); unsigned char b[4]; b[0]=x; b[1]=x>>8; b[2]=x>>16; b[3]=x>>24; fwrite(b,4,1,f); break; } + default: + assert(0); + return; + } + } +} + +static void write3(FILE *f, unsigned char a, unsigned char b, unsigned char c) +{ + unsigned char arr[3]; + arr[0] = a, arr[1] = b, arr[2] = c; + fwrite(arr, 3, 1, f); +} + +static void write_pixels(FILE *f, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad) +{ + unsigned char bg[3] = { 255, 0, 255}, px[3]; + stbiw_uint32 zero = 0; + int i,j,k, j_end; + + if (y <= 0) + return; + + if (vdir < 0) + j_end = -1, j = y-1; + else + j_end = y, j = 0; + + for (; j != j_end; j += vdir) { + for (i=0; i < x; ++i) { + unsigned char *d = (unsigned char *) data + (j*x+i)*comp; + if (write_alpha < 0) + fwrite(&d[comp-1], 1, 1, f); + switch (comp) { + case 1: + case 2: write3(f, d[0],d[0],d[0]); + break; + case 4: + if (!write_alpha) { + // composite against pink background + for (k=0; k < 3; ++k) + px[k] = bg[k] + ((d[k] - bg[k]) * d[3])/255; + write3(f, px[1-rgb_dir],px[1],px[1+rgb_dir]); + break; + } + /* FALLTHROUGH */ + case 3: + write3(f, d[1-rgb_dir],d[1],d[1+rgb_dir]); + break; + } + if (write_alpha > 0) + fwrite(&d[comp-1], 1, 1, f); + } + fwrite(&zero,scanline_pad,1,f); + } +} + +static int outfile(char const *filename, int rgb_dir, int vdir, int x, int y, int comp, void *data, int alpha, int pad, const char *fmt, ...) +{ + FILE *f; + if (y < 0 || x < 0) return 0; + f = fopen(filename, "wb"); + if (f) { + va_list v; + va_start(v, fmt); + writefv(f, fmt, v); + va_end(v); + write_pixels(f,rgb_dir,vdir,x,y,comp,data,alpha,pad); + fclose(f); + } + return f != NULL; +} + +int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) +{ + int pad = (-x*3) & 3; + return outfile(filename,-1,-1,x,y,comp,(void *) data,0,pad, + "11 4 22 4" "4 44 22 444444", + 'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40, // file header + 40, x,y, 1,24, 0,0,0,0,0,0); // bitmap header +} + +int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) +{ + int has_alpha = !(comp & 1); + return outfile(filename, -1,-1, x, y, comp, (void *) data, has_alpha, 0, + "111 221 2222 11", 0,0,2, 0,0,0, 0,0,x,y, 24+8*has_alpha, 8*has_alpha); +} + +// stretchy buffer; stbi__sbpush() == vector<>::push_back() -- stbi__sbcount() == vector<>::size() +#define stbi__sbraw(a) ((int *) (a) - 2) +#define stbi__sbm(a) stbi__sbraw(a)[0] +#define stbi__sbn(a) stbi__sbraw(a)[1] + +#define stbi__sbneedgrow(a,n) ((a)==0 || stbi__sbn(a)+n >= stbi__sbm(a)) +#define stbi__sbmaybegrow(a,n) (stbi__sbneedgrow(a,(n)) ? stbi__sbgrow(a,n) : 0) +#define stbi__sbgrow(a,n) stbi__sbgrowf((void **) &(a), (n), sizeof(*(a))) + +#define stbi__sbpush(a, v) (stbi__sbmaybegrow(a,1), (a)[stbi__sbn(a)++] = (v)) +#define stbi__sbcount(a) ((a) ? stbi__sbn(a) : 0) +#define stbi__sbfree(a) ((a) ? free(stbi__sbraw(a)),0 : 0) + +static void *stbi__sbgrowf(void **arr, int increment, int itemsize) +{ + int m = *arr ? 2*stbi__sbm(*arr)+increment : increment+1; + void *p = realloc(*arr ? stbi__sbraw(*arr) : 0, itemsize * m + sizeof(int)*2); + assert(p); + if (p) { + if (!*arr) ((int *) p)[1] = 0; + *arr = (void *) ((int *) p + 2); + stbi__sbm(*arr) = m; + } + return *arr; +} + +static unsigned char *stbi__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) +{ + while (*bitcount >= 8) { + stbi__sbpush(data, *bitbuffer); + *bitbuffer >>= 8; + *bitcount -= 8; + } + return data; +} + +static int stbi__zlib_bitrev(int code, int codebits) +{ + int res=0; + while (codebits--) { + res = (res << 1) | (code & 1); + code >>= 1; + } + return res; +} + +static unsigned int stbi__zlib_countm(unsigned char *a, unsigned char *b, int limit) +{ + int i; + for (i=0; i < limit && i < 258; ++i) + if (a[i] != b[i]) break; + return i; +} + +static unsigned int stbi__zhash(unsigned char *data) +{ + stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; + hash += hash >> 17; + hash ^= hash << 25; + hash += hash >> 6; + return hash; +} + +#define stbi__zlib_flush() (out = stbi__zlib_flushf(out, &bitbuf, &bitcount)) +#define stbi__zlib_add(code,codebits) \ + (bitbuf |= (code) << bitcount, bitcount += (codebits), stbi__zlib_flush()) +#define stbi__zlib_huffa(b,c) stbi__zlib_add(stbi__zlib_bitrev(b,c),c) +// default huffman tables +#define stbi__zlib_huff1(n) stbi__zlib_huffa(0x30 + (n), 8) +#define stbi__zlib_huff2(n) stbi__zlib_huffa(0x190 + (n)-144, 9) +#define stbi__zlib_huff3(n) stbi__zlib_huffa(0 + (n)-256,7) +#define stbi__zlib_huff4(n) stbi__zlib_huffa(0xc0 + (n)-280,8) +#define stbi__zlib_huff(n) ((n) <= 143 ? stbi__zlib_huff1(n) : (n) <= 255 ? stbi__zlib_huff2(n) : (n) <= 279 ? stbi__zlib_huff3(n) : stbi__zlib_huff4(n)) +#define stbi__zlib_huffb(n) ((n) <= 143 ? stbi__zlib_huff1(n) : stbi__zlib_huff2(n)) + +#define stbi__ZHASH 16384 + +unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) +{ + static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; + static unsigned char lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; + static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 }; + static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 }; + unsigned int bitbuf=0; + int i,j, bitcount=0; + unsigned char *out = NULL; + unsigned char **hash_table[stbi__ZHASH]; // 64KB on the stack! + if (quality < 5) quality = 5; + + stbi__sbpush(out, 0x78); // DEFLATE 32K window + stbi__sbpush(out, 0x5e); // FLEVEL = 1 + stbi__zlib_add(1,1); // BFINAL = 1 + stbi__zlib_add(1,2); // BTYPE = 1 -- fixed huffman + + for (i=0; i < stbi__ZHASH; ++i) + hash_table[i] = NULL; + + i=0; + while (i < data_len-3) { + // hash next 3 bytes of data to be compressed + int h = stbi__zhash(data+i)&(stbi__ZHASH-1), best=3; + unsigned char *bestloc = 0; + unsigned char **hlist = hash_table[h]; + int n = stbi__sbcount(hlist); + for (j=0; j < n; ++j) { + if (hlist[j]-data > i-32768) { // if entry lies within window + int d = stbi__zlib_countm(hlist[j], data+i, data_len-i); + if (d >= best) best=d,bestloc=hlist[j]; + } + } + // when hash table entry is too long, delete half the entries + if (hash_table[h] && stbi__sbn(hash_table[h]) == 2*quality) { + memcpy(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality); + stbi__sbn(hash_table[h]) = quality; + } + stbi__sbpush(hash_table[h],data+i); + + if (bestloc) { + // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal + h = stbi__zhash(data+i+1)&(stbi__ZHASH-1); + hlist = hash_table[h]; + n = stbi__sbcount(hlist); + for (j=0; j < n; ++j) { + if (hlist[j]-data > i-32767) { + int e = stbi__zlib_countm(hlist[j], data+i+1, data_len-i-1); + if (e > best) { // if next match is better, bail on current match + bestloc = NULL; + break; + } + } + } + } + + if (bestloc) { + int d = data+i - bestloc; // distance back + assert(d <= 32767 && best <= 258); + for (j=0; best > lengthc[j+1]-1; ++j); + stbi__zlib_huff(j+257); + if (lengtheb[j]) stbi__zlib_add(best - lengthc[j], lengtheb[j]); + for (j=0; d > distc[j+1]-1; ++j); + stbi__zlib_add(stbi__zlib_bitrev(j,5),5); + if (disteb[j]) stbi__zlib_add(d - distc[j], disteb[j]); + i += best; + } else { + stbi__zlib_huffb(data[i]); + ++i; + } + } + // write out final bytes + for (;i < data_len; ++i) + stbi__zlib_huffb(data[i]); + stbi__zlib_huff(256); // end of block + // pad with 0 bits to byte boundary + while (bitcount) + stbi__zlib_add(0,1); + + for (i=0; i < stbi__ZHASH; ++i) + (void) stbi__sbfree(hash_table[i]); + + { + // compute adler32 on input + unsigned int i=0, s1=1, s2=0, blocklen = data_len % 5552; + int j=0; + while (j < data_len) { + for (i=0; i < blocklen; ++i) s1 += data[j+i], s2 += s1; + s1 %= 65521, s2 %= 65521; + j += blocklen; + blocklen = 5552; + } + stbi__sbpush(out, s2 >> 8); + stbi__sbpush(out, s2); + stbi__sbpush(out, s1 >> 8); + stbi__sbpush(out, s1); + } + *out_len = stbi__sbn(out); + // make returned pointer freeable + memmove(stbi__sbraw(out), out, *out_len); + return (unsigned char *) stbi__sbraw(out); +} + +unsigned int stbi__crc32(unsigned char *buffer, int len) +{ + static unsigned int crc_table[256]; + unsigned int crc = ~0; + int i,j; + if (crc_table[1] == 0) + for(i=0; i < 256; i++) + for (crc_table[i]=i, j=0; j < 8; ++j) + crc_table[i] = (crc_table[i] >> 1) ^ (crc_table[i] & 1 ? 0xedb88320 : 0); + for (i=0; i < len; ++i) + crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; + return ~crc; +} + +#define stbi__wpng4(o,a,b,c,d) ((o)[0]=(a),(o)[1]=(b),(o)[2]=(c),(o)[3]=(d),(o)+=4) +#define stbi__wp32(data,v) stbi__wpng4(data, v>>24,v>>16,v>>8,v); +#define stbi__wptag(data,s) stbi__wpng4(data, s[0],s[1],s[2],s[3]) + +static void stbi__wpcrc(unsigned char **data, int len) +{ + unsigned int crc = stbi__crc32(*data - len - 4, len+4); + stbi__wp32(*data, crc); +} + +static int stbi__paeth(int a, int b, int c) +{ + int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c); + if (pa <= pb && pa <= pc) return a; + if (pb <= pc) return b; + return c; +} + +unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) +{ + int ctype[5] = { -1, 0, 4, 2, 6 }; + unsigned char sig[8] = { 137,80,78,71,13,10,26,10 }; + unsigned char *out,*o, *filt, *zlib; + signed char *line_buffer; + int i,j,k,p,zlen; + + if (stride_bytes == 0) + stride_bytes = x * n; + + filt = (unsigned char *) malloc((x*n+1) * y); if (!filt) return 0; + line_buffer = (signed char *) malloc(x * n); if (!line_buffer) { free(filt); return 0; } + for (j=0; j < y; ++j) { + static int mapping[] = { 0,1,2,3,4 }; + static int firstmap[] = { 0,1,0,5,6 }; + int *mymap = j ? mapping : firstmap; + int best = 0, bestval = 0x7fffffff; + for (p=0; p < 2; ++p) { + for (k= p?best:0; k < 5; ++k) { + int type = mymap[k],est=0; + unsigned char *z = pixels + stride_bytes*j; + for (i=0; i < n; ++i) + switch (type) { + case 0: line_buffer[i] = z[i]; break; + case 1: line_buffer[i] = z[i]; break; + case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break; + case 3: line_buffer[i] = z[i] - (z[i-stride_bytes]>>1); break; + case 4: line_buffer[i] = z[i] - stbi__paeth(0,z[i-stride_bytes],0); break; + case 5: line_buffer[i] = z[i]; break; + case 6: line_buffer[i] = z[i]; break; + } + for (i=n; i < x*n; ++i) { + switch (type) { + case 0: line_buffer[i] = z[i]; break; + case 1: line_buffer[i] = z[i] - z[i-n]; break; + case 2: line_buffer[i] = z[i] - z[i-stride_bytes]; break; + case 3: line_buffer[i] = z[i] - ((z[i-n] + z[i-stride_bytes])>>1); break; + case 4: line_buffer[i] = z[i] - stbi__paeth(z[i-n], z[i-stride_bytes], z[i-stride_bytes-n]); break; + case 5: line_buffer[i] = z[i] - (z[i-n]>>1); break; + case 6: line_buffer[i] = z[i] - stbi__paeth(z[i-n], 0,0); break; + } + } + if (p) break; + for (i=0; i < x*n; ++i) + est += abs((signed char) line_buffer[i]); + if (est < bestval) { bestval = est; best = k; } + } + } + // when we get here, best contains the filter type, and line_buffer contains the data + filt[j*(x*n+1)] = best; + memcpy(filt+j*(x*n+1)+1, line_buffer, x*n); + } + free(line_buffer); + zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, 8); // increase 8 to get smaller but use more memory + free(filt); + if (!zlib) return 0; + + // each tag requires 12 bytes of overhead + out = (unsigned char *) malloc(8 + 12+13 + 12+zlen + 12); + if (!out) return 0; + *out_len = 8 + 12+13 + 12+zlen + 12; + + o=out; + memcpy(o,sig,8); o+= 8; + stbi__wp32(o, 13); // header length + stbi__wptag(o, "IHDR"); + stbi__wp32(o, x); + stbi__wp32(o, y); + *o++ = 8; + *o++ = ctype[n]; + *o++ = 0; + *o++ = 0; + *o++ = 0; + stbi__wpcrc(&o,13); + + stbi__wp32(o, zlen); + stbi__wptag(o, "IDAT"); + memcpy(o, zlib, zlen); o += zlen; free(zlib); + stbi__wpcrc(&o, zlen); + + stbi__wp32(o,0); + stbi__wptag(o, "IEND"); + stbi__wpcrc(&o,0); + + assert(o == out + *out_len); + + return out; +} + +int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes) +{ + FILE *f; + int len; + unsigned char *png = stbi_write_png_to_mem((unsigned char *) data, stride_bytes, x, y, comp, &len); + if (!png) return 0; + f = fopen(filename, "wb"); + if (!f) { free(png); return 0; } + fwrite(png, 1, len, f); + fclose(f); + free(png); + return 1; +} +#endif // STB_IMAGE_WRITE_IMPLEMENTATION + +/* Revision history + + 0.91 (2010-07-17) + first public release + 0.90 first internal release +*/