SDL_image: Add USE_STBIMAGE for LoadPNG/LoadJPG, USE_TINYJPEG for SaveJPG

From 406fd40a7e6a9fb45ae4dfe868affdadb6d01911 Mon Sep 17 00:00:00 2001
From: Ethan Lee <[EMAIL REDACTED]>
Date: Thu, 30 Jan 2020 16:44:45 -0500
Subject: [PATCH] Add USE_STBIMAGE for LoadPNG/LoadJPG, USE_TINYJPEG for
 SaveJPG

---
 IMG_jpg.c   |  168 +-
 IMG_png.c   |   47 +
 IMG_stb.c   |  150 ++
 stb_image.h | 7471 +++++++++++++++++++++++++++++++++++++++++++++++++++
 tiny_jpeg.h | 1285 +++++++++
 5 files changed, 9120 insertions(+), 1 deletion(-)
 create mode 100644 IMG_stb.c
 create mode 100644 stb_image.h
 create mode 100644 tiny_jpeg.h

diff --git a/IMG_jpg.c b/IMG_jpg.c
index 0be00039..c71c3581 100644
--- a/IMG_jpg.c
+++ b/IMG_jpg.c
@@ -551,6 +551,95 @@ static int IMG_SaveJPG_RW_jpeglib(SDL_Surface *surface, SDL_RWops *dst, int free
     return result;
 }
 
+#elif defined(USE_STBIMAGE)
+
+extern SDL_Surface *IMG_LoadSTB_RW(SDL_RWops *src);
+
+int IMG_InitJPG()
+{
+    /* Nothing to load */
+    return 0;
+}
+
+void IMG_QuitJPG()
+{
+    /* Nothing to unload */
+}
+
+/* FIXME: This is a copypaste from JPEGLIB! Pull that out of the ifdefs */
+/* Define this for quicker (but less perfect) JPEG identification */
+#define FAST_IS_JPEG
+/* See if an image is contained in a data source */
+int IMG_isJPG(SDL_RWops *src)
+{
+    Sint64 start;
+    int is_JPG;
+    int in_scan;
+    Uint8 magic[4];
+
+    /* This detection code is by Steaphan Greene <stea@cs.binghamton.edu> */
+    /* Blame me, not Sam, if this doesn't work right. */
+    /* And don't forget to report the problem to the the sdl list too! */
+
+    if ( !src )
+        return 0;
+    start = SDL_RWtell(src);
+    is_JPG = 0;
+    in_scan = 0;
+    if ( SDL_RWread(src, magic, 2, 1) ) {
+        if ( (magic[0] == 0xFF) && (magic[1] == 0xD8) ) {
+            is_JPG = 1;
+            while (is_JPG == 1) {
+                if(SDL_RWread(src, magic, 1, 2) != 2) {
+                    is_JPG = 0;
+                } else if( (magic[0] != 0xFF) && (in_scan == 0) ) {
+                    is_JPG = 0;
+                } else if( (magic[0] != 0xFF) || (magic[1] == 0xFF) ) {
+                    /* Extra padding in JPEG (legal) */
+                    /* or this is data and we are scanning */
+                    SDL_RWseek(src, -1, RW_SEEK_CUR);
+                } else if(magic[1] == 0xD9) {
+                    /* Got to end of good JPEG */
+                    break;
+                } else if( (in_scan == 1) && (magic[1] == 0x00) ) {
+                    /* This is an encoded 0xFF within the data */
+                } else if( (magic[1] >= 0xD0) && (magic[1] < 0xD9) ) {
+                    /* These have nothing else */
+                } else if(SDL_RWread(src, magic+2, 1, 2) != 2) {
+                    is_JPG = 0;
+                } else {
+                    /* Yes, it's big-endian */
+                    Sint64 innerStart;
+                    Uint32 size;
+                    Sint64 end;
+                    innerStart = SDL_RWtell(src);
+                    size = (magic[2] << 8) + magic[3];
+                    end = SDL_RWseek(src, size-2, RW_SEEK_CUR);
+                    if ( end != innerStart + size - 2 ) is_JPG = 0;
+                    if ( magic[1] == 0xDA ) {
+                        /* Now comes the actual JPEG meat */
+#ifdef  FAST_IS_JPEG
+                        /* Ok, I'm convinced.  It is a JPEG. */
+                        break;
+#else
+                        /* I'm not convinced.  Prove it! */
+                        in_scan = 1;
+#endif
+                    }
+                }
+            }
+        }
+    }
+    SDL_RWseek(src, start, RW_SEEK_SET);
+    return(is_JPG);
+}
+
+/* Load a JPEG type image from an SDL datasource */
+SDL_Surface *IMG_LoadJPG_RW(SDL_RWops *src)
+{
+    return IMG_LoadSTB_RW(src);
+}
+
 #else
 #if _MSC_VER >= 1300
 #pragma warning(disable : 4100) /* warning C4100: 'op' : unreferenced formal parameter */
@@ -587,6 +676,81 @@ SDL_Surface *IMG_LoadJPG_RW(SDL_RWops *src)
 
 #ifdef SAVE_JPG
 
+#if !defined(USE_JPEGLIB) && defined(USE_TINYJPEG)
+
+#define assert SDL_assert
+#define ceilf SDL_ceilf
+#define floorf SDL_floorf
+#define memcpy SDL_memcpy
+
+#define tje_log SDL_Log
+#define TJE_IMPLEMENTATION
+#include "tiny_jpeg.h"
+
+static void IMG_SaveJPG_RW_tinyjpeg_callback(void* context, void* data, int size)
+{
+    SDL_RWwrite((SDL_RWops*) context, data, 1, size);
+}
+
+static int IMG_SaveJPG_RW_tinyjpeg(SDL_Surface *surface, SDL_RWops *dst, int freedst, int quality)
+{
+#if SDL_BYTEORDER == SDL_LIL_ENDIAN
+    static const Uint32 jpg_format = SDL_PIXELFORMAT_RGB24;
+#else
+    static const Uint32 jpg_format = SDL_PIXELFORMAT_BGR24;
+#endif
+    SDL_Surface* jpeg_surface = surface;
+    int result = -1;
+
+    if (!dst) {
+        SDL_SetError("Passed NULL dst");
+        goto done;
+    }
+
+    /* Convert surface to format we can save */
+    if (surface->format->format != jpg_format) {
+        jpeg_surface = SDL_ConvertSurfaceFormat(surface, jpg_format, 0);
+        if (!jpeg_surface) {
+            goto done;
+        }
+    }
+
+    /* Quality for tinyjpeg is from 1-3:
+     * 0  - 33  - Lowest quality
+     * 34 - 66  - Middle quality
+     * 67 - 100 - Highest quality
+     */
+    if      (quality < 34) quality = 1;
+    else if (quality < 67) quality = 2;
+    else                   quality = 3;
+
+    result = tje_encode_with_func(
+        IMG_SaveJPG_RW_tinyjpeg_callback,
+        dst,
+        quality,
+        jpeg_surface->w,
+        jpeg_surface->h,
+        3,
+        jpeg_surface->pixels
+    ) - 1; /* tinyjpeg returns 0 on error, 1 on success */
+
+    if (jpeg_surface != surface) {
+        SDL_FreeSurface(jpeg_surface);
+    }
+
+    if (result < 0) {
+        SDL_SetError("tinyjpeg error");
+    }
+
+done:
+    if (freedst) {
+        SDL_RWclose(dst);
+    }
+    return result;
+}
+
+#endif /* !defined(USE_JPEGLIB) && defined(USE_TINYJPEG) */
+
 int IMG_SaveJPG(SDL_Surface *surface, const char *file, int quality)
 {
     SDL_RWops *dst = SDL_RWFromFile(file, "wb");
@@ -601,8 +765,10 @@ int IMG_SaveJPG_RW(SDL_Surface *surface, SDL_RWops *dst, int freedst, int qualit
 {
 #ifdef USE_JPEGLIB
     return IMG_SaveJPG_RW_jpeglib(surface, dst, freedst, quality);
+#elif USE_TINYJPEG
+    return IMG_SaveJPG_RW_tinyjpeg(surface, dst, freedst, quality);
 #else
-    return IMG_SetError("SDL_image not built with jpeglib, saving not supported");
+    return IMG_SetError("SDL_image not built with jpeglib/tinyjpeg, saving not supported");
 #endif
 }
 
diff --git a/IMG_png.c b/IMG_png.c
index 418bf972..d4a45c4b 100644
--- a/IMG_png.c
+++ b/IMG_png.c
@@ -449,6 +449,53 @@ SDL_Surface *IMG_LoadPNG_RW(SDL_RWops *src)
     return(surface);
 }
 
+#elif defined(USE_STBIMAGE)
+
+extern SDL_Surface *IMG_LoadSTB_RW(SDL_RWops *src);
+
+int IMG_InitPNG()
+{
+    /* Nothing to load */
+    return 0;
+}
+
+void IMG_QuitPNG()
+{
+    /* Nothing to unload */
+}
+
+/* FIXME: This is a copypaste from LIBPNG! Pull that out of the ifdefs */
+/* See if an image is contained in a data source */
+int IMG_isPNG(SDL_RWops *src)
+{
+    Sint64 start;
+    int is_PNG;
+    Uint8 magic[4];
+
+    if ( !src ) {
+        return 0;
+    }
+
+    start = SDL_RWtell(src);
+    is_PNG = 0;
+    if ( SDL_RWread(src, magic, 1, sizeof(magic)) == sizeof(magic) ) {
+        if ( magic[0] == 0x89 &&
+             magic[1] == 'P' &&
+             magic[2] == 'N' &&
+             magic[3] == 'G' ) {
+            is_PNG = 1;
+        }
+    }
+    SDL_RWseek(src, start, RW_SEEK_SET);
+    return(is_PNG);
+}
+
+/* Load a PNG type image from an SDL datasource */
+SDL_Surface *IMG_LoadPNG_RW(SDL_RWops *src)
+{
+    return IMG_LoadSTB_RW(src);
+}
+
 #else
 #if _MSC_VER >= 1300
 #pragma warning(disable : 4100) /* warning C4100: 'op' : unreferenced formal parameter */
diff --git a/IMG_stb.c b/IMG_stb.c
new file mode 100644
index 00000000..f8ba197e
--- /dev/null
+++ b/IMG_stb.c
@@ -0,0 +1,150 @@
+/*
+  SDL_image:  An example image loading library for use with SDL
+  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "SDL_image.h"
+
+#ifdef USE_STBIMAGE
+
+#ifndef INT_MAX
+#define INT_MAX 0x7FFFFFFF
+#endif
+
+#define malloc SDL_malloc
+#define realloc SDL_realloc
+#define free SDL_free
+#define memcpy SDL_memcpy
+#define memset SDL_memset
+#define strcmp SDL_strcmp
+#define strncmp SDL_strncmp
+#define strtol SDL_strtol
+#define pow SDL_pow
+#define ldexp SDL_scalbn
+
+#define STBI_NO_STDIO
+#define STBI_ONLY_PNG
+#define STBI_ONLY_JPEG
+#define STBI_ASSERT SDL_assert
+#define STB_IMAGE_IMPLEMENTATION
+#include "stb_image.h"
+
+static int IMG_LoadSTB_RW_read(void *user, char *data, int size)
+{
+    return (int) SDL_RWread((SDL_RWops*) user, data, 1, size);
+}
+
+static void IMG_LoadSTB_RW_skip(void *user, int n)
+{
+    SDL_RWseek((SDL_RWops*) user, n, RW_SEEK_CUR);
+}
+
+static int IMG_LoadSTB_RW_eof(void *user)
+{
+    /* FIXME: Do we not have a way to detect EOF? -flibit */
+    size_t bytes, filler;
+    SDL_RWops *src = (SDL_RWops*) user;
+    bytes = SDL_RWread(src, &filler, 1, 1);
+    if (bytes != 1) /* FIXME: Could also be an error... */
+    {
+        return 1;
+    }
+    SDL_RWseek(src, -1, RW_SEEK_CUR);
+    return 0;
+}
+
+SDL_Surface *IMG_LoadSTB_RW(SDL_RWops *src)
+{
+    Sint64 start;
+    int w, h, format;
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+    int shift;
+#endif
+    Uint32 rmask, gmask, bmask, amask;
+    stbi_uc *pixels;
+    stbi_io_callbacks rw_callbacks;
+    SDL_Surface *surface = NULL;
+
+    if ( !src ) {
+        /* The error message has been set in SDL_RWFromFile */
+        return NULL;
+    }
+    start = SDL_RWtell(src);
+
+    /* Load the image data */
+    rw_callbacks.read = IMG_LoadSTB_RW_read;
+    rw_callbacks.skip = IMG_LoadSTB_RW_skip;
+    rw_callbacks.eof = IMG_LoadSTB_RW_eof;
+    pixels = stbi_load_from_callbacks(
+        &rw_callbacks,
+        src,
+        &w,
+        &h,
+        &format,
+        STBI_default
+    );
+    if ( !pixels ) {
+        SDL_RWseek(src, start, RW_SEEK_SET);
+        IMG_SetError("%s", stbi_failure_reason());
+        return NULL;
+    }
+
+    /* Determine the surface format */
+    SDL_assert(format == STBI_rgb || format == STBI_rgb_alpha);
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+    shift = (format == STBI_rgb) ? 8 : 0;
+    rmask = 0xFF000000 >> shift;
+    gmask = 0x00FF0000 >> shift;
+    bmask = 0x0000FF00 >> shift;
+    amask = 0x000000FF >> shift;
+#else // little endian, like x86
+    rmask = 0x000000FF;
+    gmask = 0x0000FF00;
+    bmask = 0x00FF0000;
+    amask = (format == STBI_rgb) ? 0 : 0xFF000000;
+#endif
+
+    /* Allocate the surface */
+    surface = SDL_CreateRGBSurfaceFrom(
+        pixels,
+        w,
+        h,
+        8 * format,
+        w * format,
+        rmask,
+        gmask,
+        bmask,
+        amask
+    );
+    if ( !surface ) {
+        /* The error message should already be set */
+        SDL_free(pixels);
+        SDL_RWseek(src, start, RW_SEEK_SET);
+    } else {
+        /* FIXME: This sucks. It'd be better to allocate the surface first, then
+         * write directly to the pixel buffer:
+         * https://github.com/nothings/stb/issues/58
+         * -flibit
+         */
+        surface->flags &= ~SDL_PREALLOC;
+    }
+    return surface;
+}
+
+#endif /* USE_STBIMAGE */
diff --git a/stb_image.h b/stb_image.h
new file mode 100644
index 00000000..062b6780
--- /dev/null
+++ b/stb_image.h
@@ -0,0 +1,7471 @@
+/* stb_image - v2.19 - public domain image loader - http://nothings.org/stb
+                                  no warranty implied; use at your own risk
+
+   Do this:
+      #define STB_IMAGE_IMPLEMENTATION
+   before you include this file in *one* C or C++ file to create the implementation.
+
+   // i.e. it should look like this:
+   #include ...
+   #include ...
+   #include ...
+   #define STB_IMAGE_IMPLEMENTATION
+   #include "stb_image.h"
+
+   You can #define STBI_ASSERT(x) before the #include to avoid using assert.h.
+   And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free
+
+
+   QUICK NOTES:
+      Primarily of interest to game developers and other people who can
+          avoid problematic images and only need the trivial interface
+
+      JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib)
+      PNG 1/2/4/8/16-bit-per-channel
+
+      TGA (not sure what subset, if a subset)
+      BMP non-1bpp, non-RLE
+      PSD (composited view only, no extra channels, 8/16 bit-per-channel)
+
+      GIF (*comp always reports as 4-channel)
+      HDR (radiance rgbE format)
+      PIC (Softimage PIC)
+      PNM (PPM and PGM binary only)
+
+      Animated GIF still needs a proper API, but here's one way to do it:
+          http://gist.github.com/urraka/685d9a6340b26b830d49
+
+      - decode from memory or through FILE (define STBI_NO_STDIO to remove code)
+      - decode from arbitrary I/O callbacks
+      - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON)
+
+   Full documentation under "DOCUMENTATION" below.
+
+
+LICENSE
+
+  See end of file for license information.
+
+RECENT REVISION HISTORY:
+
+      2.19  (2018-02-11) fix warning
+      2.18  (2018-01-30) fix warnings
+      2.17  (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings
+      2.16  (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes
+      2.15  (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC
+      2.14  (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs
+      2.13  (2016-12-04) experimental 16-bit API, only for PNG so far; fixes
+      2.12  (2016-04-02) fix typo in 2.11 PSD fix that caused crashes
+      2.11  (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64
+                         RGB-format JPEG; remove white matting in PSD;
+                         allocate large structures on the stack;
+                         correct channel count for PNG & BMP
+      2.10  (2016-01-22) avoid warning introduced in 2.09
+      2.09  (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED
+
+   See end of file for full revision history.
+
+
+ ============================    Contributors    =========================
+
+ Image formats                          Extensions, features
+    Sean Barrett (jpeg, png, bmp)          Jetro Lauha (stbi_info)
+    Nicolas Schulz (hdr, psd)              Martin "SpartanJ" Golini (stbi_info)
+    Jonathan Dummer (tga)                  James "moose2000" Brown (iPhone PNG)
+    Jean-Marc Lienher (gif)                Ben "Disch" Wenger (io callbacks)
+    Tom Seddon (pic)                       Omar Cornut (1/2/4-bit PNG)
+    Thatcher Ulrich (psd)                  Nicolas Guillemot (vertical flip)
+    Ken Miller (pgm, ppm)                  Richard Mitton (16-bit PSD)
+    github:urraka (animated gif)           Junggon Kim (PNM comments)
+    Christopher Forseth (animated gif)     Daniel Gibson (16-bit TGA)
+                                           socks-the-fox (16-bit PNG)
+                                           Jeremy Sawicki (handle all ImageNet JPGs)
+ Optimizations & bugfixes                  Mikhail Morozov (1-bit BMP)
+    Fabian "ryg" Giesen                    Anael Seghezzi (is-16-bit query)
+    Arseny Kapoulkine
+    John-Mark Allen
+
+ Bug & warning fixes
+    Marc LeBlanc            David Woo          Guillaume George   Martins Mozeiko
+    Christpher Lloyd        Jerry Jansson      Joseph Thomson     Phil Jordan
+    Dave Moore              Roy Eltham         Hayaki Saito       Nathan Reed
+    Won Chun                Luke Graham        Johan Duparc       Nick Verigakis
+    the Horde3D community   Thomas Ruf         Ronny Chevalier    github:rlyeh
+    Janez Zemva             John Bartholomew   Michal Cichon      github:romigrou
+    Jonathan Blow           Ken Hamada         Tero Hanninen      github:svdijk
+    Laurent Gomila          Cort Stratton      Sergio Gonzalez    github:snagar
+    Aruelien Pocheville     Thibault Reuille   Cass Everitt       github:Zelex
+    Ryamond Barbiero        Paul Du Bois       Engin Manap        github:grim210
+    Aldo Culquicondor       Philipp Wiesemann  Dale Weiler        github:sammyhw
+    Oriol Ferrer Mesia      Josh Tobin         Matthew Gregan     github:phprus
+    Julian Raschke          Gregory Mullen     Baldur Karlsson    github:poppolopoppo
+    Christian Floisand      Kevin Schmidt                         github:darealshinji
+    Blazej Dariusz Roszkowski                                     github:Michaelangel007
+*/
+
+#ifndef STBI_INCLUDE_STB_IMAGE_H
+#define STBI_INCLUDE_STB_IMAGE_H
+
+// DOCUMENTATION
+//
+// Limitations:
+//    - no 12-bit-per-channel JPEG
+//    - no JPEGs with arithmetic coding
+//    - GIF always returns *comp=4
+//
+// Basic usage (see HDR discussion below for HDR usage):
+//    int x,y,n;
+//    unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
+//    // ... process data if not NULL ...
+//    // ... x = width, y = height, n = # 8-bit components per pixel ...
+//    // ... replace '0' with '1'..'4' to force that many components per pixel
+//    // ... but 'n' will always be the number that it would have been if you said 0
+//    stbi_image_free(data)
+//
+// Standard parameters:
+//    int *x                 -- outputs image width in pixels
+//    int *y                 -- outputs image height in pixels
+//    int *channels_in_file  -- outputs # of image components in image file
+//    int desired_channels   -- 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, or NULL on an allocation failure or if the image is
+// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels,
+// with each pixel consisting of N interleaved 8-bit components; the first
+// pixel pointed to is top-left-most in the image. There is no padding between
+// image scanlines or between pixels, regardless of format. The number of
+// components N is 'desired_channels' if desired_channels is non-zero, or
+// *channels_in_file otherwise. If desired_channels is non-zero,
+// *channels_in_file has the number of components that _would_ have been
+// output otherwise. E.g. if you set desired_channels to 4, you will always
+// get RGBA output, but you can check *channels_in_file to see if it's trivially
+// opaque because e.g. there were only 3 channels in the source image.
+//
+// An output image with N components has the following components interleaved
+// in this order in each pixel:
+//
+//     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, *channels_in_file will be unchanged. The function
+// stbi_failure_reason() can be queried for an extremely brief, end-user
+// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS
+// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly
+// more user-friendly ones.
+//
+// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized.
+//
+// ===========================================================================
+//
+// Philosophy
+//
+// stb libraries are designed with the following priorities:
+//
+//    1. easy to use
+//    2. easy to maintain
+//    3. good performance
+//
+// Sometimes I let "good performance" creep up in priority over "easy to maintain",
+// and for best performance I may provide less-easy-to-use APIs that give higher
+// performance, in addition to the easy to use ones. Nevertheless, it's important
+// to keep in mind that from the standpoint of you, a client of this library,
+// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all.
+//
+// Some secondary priorities arise directly from the first two, some of which
+// make more explicit reasons why performance can't be emphasized.
+//
+//    - Portable ("ease of use")
+//    - Small source code footprint ("easy to maintain")
+//    - No dependencies ("ease of use")
+//
+// ===========================================================================
+//
+// I/O callbacks
+//
+// I/O callbacks allow you to read from arbitrary sources, like packaged
+// files or some other source. Data read from callbacks are processed
+// through a small internal buffer (currently 128 bytes) to try to reduce
+// overhead.
+//
+// The three functions you must define are "read" (reads some bytes of data),
+// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end).
+//
+// ===========================================================================
+//
+// SIMD support
+//
+// The JPEG decoder will try to automatically use SIMD kernels on x86 when
+// supported by the compiler. For ARM Neon support, you must explicitly
+// request it.
+//
+// (The old do-it-yourself SIMD API is no longer supported in the current
+// code.)
+//
+// On x86, SSE2 will automatically be used when available based on a run-time
+// test; if not, the generic C versions are used as a fall-back. On ARM targets,
+// the typical path is to have separate builds for NEON and non-NEON devices
+// (at least this is true for iOS and Android). Therefore, the NEON support is
+// toggled by a build flag: define STBI_NEON to get NEON loops.
+//
+// If for some reason you do not want to use any of SIMD code, or if
+// you have issues compiling it, you can disable it entirely by
+// defining STBI_NO_SIMD.
+//
+// ===========================================================================
+//
+// 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);
+//
+// ===========================================================================
+//
+// iPhone PNG support:
+//
+// By default we convert iphone-formatted PNGs back to RGB, even though
+// they are internally encoded differently. You can disable this conversion
+// by by calling stbi_convert_iphone_png_to_rgb(0), in which case
+// you will always just get the native iphone "format" through (which
+// is BGR stored in RGB).
+//
+// 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).
+//
+// ===========================================================================
+//
+// ADDITIONAL CONFIGURATION
+//
+//  - You can suppress implementation of any of the decoders to reduce
+//    your code footprint by #defining one or more of the following
+//    symbols before creating the implementation.
+//
+//        STBI_NO_JPEG
+//        STBI_NO_PNG
+//        STBI_NO_BMP
+//        STBI_NO_PSD
+//        STBI_NO_TGA
+//        STBI_NO_GIF
+//        STBI_NO_HDR
+//        STBI_NO_PIC
+//        STBI_NO_PNM   (.ppm and .pgm)
+//
+//  - You can request *only* certain decoders and suppress all other ones
+//    (this will be more forward-compatible, as addition of new decoders
+//    doesn't require you to disable them explicitly):
+//
+//        STBI_ONLY_JPEG
+//        STBI_ONLY_PNG
+//        STBI_ONLY_BMP
+//        STBI_ONLY_PSD
+//        STBI_ONLY_TGA
+//        STBI_ONLY_GIF
+//        STBI_ONLY_HDR
+//        STBI_ONLY_PIC
+//        STBI_ONLY_PNM   (.ppm and .pgm)
+//
+//   - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still
+//     want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB
+//
+
+
+#ifndef STBI_NO_STDIO
+#include <stdio.h>
+#endif // STBI_NO_STDIO
+
+#define STBI_VERSION 1
+
+enum
+{
+   STBI_default = 0, // only used for desired_channels
+
+   STBI_grey       = 1,
+   STBI_grey_alpha = 2,
+   STBI_rgb        = 3,
+   STBI_rgb_alpha  = 4
+};
+
+typedef unsigned char stbi_uc;
+typedef unsigned short stbi_us;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef STB_IMAGE_STATIC
+#define STBIDEF static
+#else
+#define STBIDEF extern
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// PRIMARY API - works on images of any type
+//
+
+//
+// load image by filename, open file, or memory buffer
+//
+
+typedef struct
+{
+   int      (*read)  (void *user,char *data,int size);   // fill 'data' with 'size' bytes.  return number of bytes actually read
+   void     (*skip)  (void *user,int n);                 // skip the next 'n' bytes, or 'unget' the last -n bytes if negative
+   int      (*eof)   (void *user);                       // returns nonzero if we are at end of file/data
+} stbi_io_callbacks;
+
+////////////////////////////////////
+//
+// 8-bits-per-channel interface
+//
+
+STBIDEF stbi_uc *stbi_load_from_memory   (stbi_uc           const *buffer, int len   , int *x, int *y, int *channels_in_file, int desired_channels);
+STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk  , void *user, int *x, int *y, int *channels_in_file, int desired_channels);
+#ifndef STBI_NO_GIF
+STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp);
+#endif
+
+
+#ifndef STBI_NO_STDIO
+STBIDEF stbi_uc *stbi_load            (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
+STBIDEF stbi_uc *stbi_load_from_file  (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
+// for stbi_load_from_file, file pointer is left pointing immediately after image
+#endif
+
+////////////////////////////////////
+//
+// 16-bits-per-channel interface
+//
+
+STBIDEF stbi_us *stbi_load_16_from_memory   (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);
+STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels);
+
+#ifndef STBI_NO_STDIO
+STBIDEF stbi_us *stbi_load_16          (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
+STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
+#endif
+
+////////////////////////////////////
+//
+// float-per-channel interface
+//
+#ifndef STBI_NO_LINEAR
+   STBIDEF float *stbi_loadf_from_memory     (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);
+   STBIDEF float *stbi_loadf_from_callbacks  (stbi_io_callbacks const *clbk, void *user, int *x, int *y,  int *channels_in_file, int desired_channels);
+
+   #ifndef STBI_NO_STDIO
+   STBIDEF float *stbi_loadf            (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);
+   STBIDEF float *stbi_loadf_from_file  (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);
+   #endif
+#endif
+
+#ifndef STBI_NO_HDR
+   STBIDEF void   stbi_hdr_to_ldr_gamma(float gamma);
+   STBIDEF void   stbi_hdr_to_ldr_scale(float scale);
+#endif // STBI_NO_HDR
+
+#ifndef STBI_NO_LINEAR
+   STBIDEF void   stbi_ldr_to_hdr_gamma(float gamma);
+   STBIDEF void   stbi_ldr_to_hdr_scale(float scale);
+#endif // STBI_NO_LINEAR
+
+// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR
+STBIDEF int    stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user);
+STBIDEF int    stbi_is_hdr_from_memory(stbi_uc const *buffer, int len);
+#ifndef STBI_NO_STDIO
+STBIDEF int      stbi_is_hdr          (char const *filename);
+STBIDEF int      stbi_is_hdr_from_file(FILE *f);
+#endif // STBI_NO_STDIO
+
+
+// get a VERY brief reason for failure
+// NOT THREADSAFE
+STBIDEF const char *stbi_failure_reason  (void);
+
+// free the loaded image -- this is just free()
+STBIDEF void     stbi_image_free      (void *retval_from_stbi_load);
+
+// get image dimensions & components without fully decoding
+STBIDEF int      stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);
+STBIDEF int      stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);
+STBIDEF int      stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len);
+STBIDEF int      stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user);
+
+#ifndef STBI_NO_STDIO
+STBIDEF int      stbi_info               (char const *filename,     int *x, int *y, int *comp);
+STBIDEF int      stbi_info_from_file     (FILE *f,                  int *x, int *y, int *comp);
+STBIDEF int      stbi_is_16_bit          (char const *filename);
+STBIDEF int      stbi_is_16_bit_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.
+STBIDEF 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"
+STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert);
+
+// flip the image vertically, so the first pixel in the output array is the bottom left
+STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip);
+
+// ZLIB client - used by PNG, available for other purposes
+
+ST

(Patch may be truncated, please check the link at the top of this post.)