ascii-gen

simple ascii image converter
git clone git://git.jakekoroman.com/ascii-gen
Log | Files | Refs | README

stb_image_resize.h (116516B)


      1 /* stb_image_resize - v0.97 - public domain image resizing
      2    by Jorge L Rodriguez (@VinoBS) - 2014
      3    http://github.com/nothings/stb
      4 
      5    Written with emphasis on usability, portability, and efficiency. (No
      6    SIMD or threads, so it be easily outperformed by libs that use those.)
      7    Only scaling and translation is supported, no rotations or shears.
      8    Easy API downsamples w/Mitchell filter, upsamples w/cubic interpolation.
      9 
     10    COMPILING & LINKING
     11       In one C/C++ file that #includes this file, do this:
     12          #define STB_IMAGE_RESIZE_IMPLEMENTATION
     13       before the #include. That will create the implementation in that file.
     14 
     15    QUICKSTART
     16       stbir_resize_uint8(      input_pixels , in_w , in_h , 0,
     17                                output_pixels, out_w, out_h, 0, num_channels)
     18       stbir_resize_float(...)
     19       stbir_resize_uint8_srgb( input_pixels , in_w , in_h , 0,
     20                                output_pixels, out_w, out_h, 0,
     21                                num_channels , alpha_chan  , 0)
     22       stbir_resize_uint8_srgb_edgemode(
     23                                input_pixels , in_w , in_h , 0,
     24                                output_pixels, out_w, out_h, 0,
     25                                num_channels , alpha_chan  , 0, STBIR_EDGE_CLAMP)
     26                                                             // WRAP/REFLECT/ZERO
     27 
     28    FULL API
     29       See the "header file" section of the source for API documentation.
     30 
     31    ADDITIONAL DOCUMENTATION
     32 
     33       SRGB & FLOATING POINT REPRESENTATION
     34          The sRGB functions presume IEEE floating point. If you do not have
     35          IEEE floating point, define STBIR_NON_IEEE_FLOAT. This will use
     36          a slower implementation.
     37 
     38       MEMORY ALLOCATION
     39          The resize functions here perform a single memory allocation using
     40          malloc. To control the memory allocation, before the #include that
     41          triggers the implementation, do:
     42 
     43             #define STBIR_MALLOC(size,context) ...
     44             #define STBIR_FREE(ptr,context)   ...
     45 
     46          Each resize function makes exactly one call to malloc/free, so to use
     47          temp memory, store the temp memory in the context and return that.
     48 
     49       ASSERT
     50          Define STBIR_ASSERT(boolval) to override assert() and not use assert.h
     51 
     52       OPTIMIZATION
     53          Define STBIR_SATURATE_INT to compute clamp values in-range using
     54          integer operations instead of float operations. This may be faster
     55          on some platforms.
     56 
     57       DEFAULT FILTERS
     58          For functions which don't provide explicit control over what filters
     59          to use, you can change the compile-time defaults with
     60 
     61             #define STBIR_DEFAULT_FILTER_UPSAMPLE     STBIR_FILTER_something
     62             #define STBIR_DEFAULT_FILTER_DOWNSAMPLE   STBIR_FILTER_something
     63 
     64          See stbir_filter in the header-file section for the list of filters.
     65 
     66       NEW FILTERS
     67          A number of 1D filter kernels are used. For a list of
     68          supported filters see the stbir_filter enum. To add a new filter,
     69          write a filter function and add it to stbir__filter_info_table.
     70 
     71       PROGRESS
     72          For interactive use with slow resize operations, you can install
     73          a progress-report callback:
     74 
     75             #define STBIR_PROGRESS_REPORT(val)   some_func(val)
     76 
     77          The parameter val is a float which goes from 0 to 1 as progress is made.
     78 
     79          For example:
     80 
     81             static void my_progress_report(float progress);
     82             #define STBIR_PROGRESS_REPORT(val) my_progress_report(val)
     83 
     84             #define STB_IMAGE_RESIZE_IMPLEMENTATION
     85             #include "stb_image_resize.h"
     86 
     87             static void my_progress_report(float progress)
     88             {
     89                printf("Progress: %f%%\n", progress*100);
     90             }
     91 
     92       MAX CHANNELS
     93          If your image has more than 64 channels, define STBIR_MAX_CHANNELS
     94          to the max you'll have.
     95 
     96       ALPHA CHANNEL
     97          Most of the resizing functions provide the ability to control how
     98          the alpha channel of an image is processed. The important things
     99          to know about this:
    100 
    101          1. The best mathematically-behaved version of alpha to use is
    102          called "premultiplied alpha", in which the other color channels
    103          have had the alpha value multiplied in. If you use premultiplied
    104          alpha, linear filtering (such as image resampling done by this
    105          library, or performed in texture units on GPUs) does the "right
    106          thing". While premultiplied alpha is standard in the movie CGI
    107          industry, it is still uncommon in the videogame/real-time world.
    108 
    109          If you linearly filter non-premultiplied alpha, strange effects
    110          occur. (For example, the 50/50 average of 99% transparent bright green
    111          and 1% transparent black produces 50% transparent dark green when
    112          non-premultiplied, whereas premultiplied it produces 50%
    113          transparent near-black. The former introduces green energy
    114          that doesn't exist in the source image.)
    115 
    116          2. Artists should not edit premultiplied-alpha images; artists
    117          want non-premultiplied alpha images. Thus, art tools generally output
    118          non-premultiplied alpha images.
    119 
    120          3. You will get best results in most cases by converting images
    121          to premultiplied alpha before processing them mathematically.
    122 
    123          4. If you pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED, the
    124          resizer does not do anything special for the alpha channel;
    125          it is resampled identically to other channels. This produces
    126          the correct results for premultiplied-alpha images, but produces
    127          less-than-ideal results for non-premultiplied-alpha images.
    128 
    129          5. If you do not pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED,
    130          then the resizer weights the contribution of input pixels
    131          based on their alpha values, or, equivalently, it multiplies
    132          the alpha value into the color channels, resamples, then divides
    133          by the resultant alpha value. Input pixels which have alpha=0 do
    134          not contribute at all to output pixels unless _all_ of the input
    135          pixels affecting that output pixel have alpha=0, in which case
    136          the result for that pixel is the same as it would be without
    137          STBIR_FLAG_ALPHA_PREMULTIPLIED. However, this is only true for
    138          input images in integer formats. For input images in float format,
    139          input pixels with alpha=0 have no effect, and output pixels
    140          which have alpha=0 will be 0 in all channels. (For float images,
    141          you can manually achieve the same result by adding a tiny epsilon
    142          value to the alpha channel of every image, and then subtracting
    143          or clamping it at the end.)
    144 
    145          6. You can suppress the behavior described in #5 and make
    146          all-0-alpha pixels have 0 in all channels by #defining
    147          STBIR_NO_ALPHA_EPSILON.
    148 
    149          7. You can separately control whether the alpha channel is
    150          interpreted as linear or affected by the colorspace. By default
    151          it is linear; you almost never want to apply the colorspace.
    152          (For example, graphics hardware does not apply sRGB conversion
    153          to the alpha channel.)
    154 
    155    CONTRIBUTORS
    156       Jorge L Rodriguez: Implementation
    157       Sean Barrett: API design, optimizations
    158       Aras Pranckevicius: bugfix
    159       Nathan Reed: warning fixes
    160 
    161    REVISIONS
    162       0.97 (2020-02-02) fixed warning
    163       0.96 (2019-03-04) fixed warnings
    164       0.95 (2017-07-23) fixed warnings
    165       0.94 (2017-03-18) fixed warnings
    166       0.93 (2017-03-03) fixed bug with certain combinations of heights
    167       0.92 (2017-01-02) fix integer overflow on large (>2GB) images
    168       0.91 (2016-04-02) fix warnings; fix handling of subpixel regions
    169       0.90 (2014-09-17) first released version
    170 
    171    LICENSE
    172      See end of file for license information.
    173 
    174    TODO
    175       Don't decode all of the image data when only processing a partial tile
    176       Don't use full-width decode buffers when only processing a partial tile
    177       When processing wide images, break processing into tiles so data fits in L1 cache
    178       Installable filters?
    179       Resize that respects alpha test coverage
    180          (Reference code: FloatImage::alphaTestCoverage and FloatImage::scaleAlphaToCoverage:
    181          https://code.google.com/p/nvidia-texture-tools/source/browse/trunk/src/nvimage/FloatImage.cpp )
    182 */
    183 
    184 #ifndef STBIR_INCLUDE_STB_IMAGE_RESIZE_H
    185 #define STBIR_INCLUDE_STB_IMAGE_RESIZE_H
    186 
    187 #ifdef _MSC_VER
    188 typedef unsigned char  stbir_uint8;
    189 typedef unsigned short stbir_uint16;
    190 typedef unsigned int   stbir_uint32;
    191 #else
    192 #include <stdint.h>
    193 typedef uint8_t  stbir_uint8;
    194 typedef uint16_t stbir_uint16;
    195 typedef uint32_t stbir_uint32;
    196 #endif
    197 
    198 #ifndef STBIRDEF
    199 #ifdef STB_IMAGE_RESIZE_STATIC
    200 #define STBIRDEF static
    201 #else
    202 #ifdef __cplusplus
    203 #define STBIRDEF extern "C"
    204 #else
    205 #define STBIRDEF extern
    206 #endif
    207 #endif
    208 #endif
    209 
    210 //////////////////////////////////////////////////////////////////////////////
    211 //
    212 // Easy-to-use API:
    213 //
    214 //     * "input pixels" points to an array of image data with 'num_channels' channels (e.g. RGB=3, RGBA=4)
    215 //     * input_w is input image width (x-axis), input_h is input image height (y-axis)
    216 //     * stride is the offset between successive rows of image data in memory, in bytes. you can
    217 //       specify 0 to mean packed continuously in memory
    218 //     * alpha channel is treated identically to other channels.
    219 //     * colorspace is linear or sRGB as specified by function name
    220 //     * returned result is 1 for success or 0 in case of an error.
    221 //       #define STBIR_ASSERT() to trigger an assert on parameter validation errors.
    222 //     * Memory required grows approximately linearly with input and output size, but with
    223 //       discontinuities at input_w == output_w and input_h == output_h.
    224 //     * These functions use a "default" resampling filter defined at compile time. To change the filter,
    225 //       you can change the compile-time defaults by #defining STBIR_DEFAULT_FILTER_UPSAMPLE
    226 //       and STBIR_DEFAULT_FILTER_DOWNSAMPLE, or you can use the medium-complexity API.
    227 
    228 STBIRDEF int stbir_resize_uint8(     const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
    229                                            unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
    230                                      int num_channels);
    231 
    232 STBIRDEF int stbir_resize_float(     const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
    233                                            float *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
    234                                      int num_channels);
    235 
    236 
    237 // The following functions interpret image data as gamma-corrected sRGB.
    238 // Specify STBIR_ALPHA_CHANNEL_NONE if you have no alpha channel,
    239 // or otherwise provide the index of the alpha channel. Flags value
    240 // of 0 will probably do the right thing if you're not sure what
    241 // the flags mean.
    242 
    243 #define STBIR_ALPHA_CHANNEL_NONE       -1
    244 
    245 // Set this flag if your texture has premultiplied alpha. Otherwise, stbir will
    246 // use alpha-weighted resampling (effectively premultiplying, resampling,
    247 // then unpremultiplying).
    248 #define STBIR_FLAG_ALPHA_PREMULTIPLIED    (1 << 0)
    249 // The specified alpha channel should be handled as gamma-corrected value even
    250 // when doing sRGB operations.
    251 #define STBIR_FLAG_ALPHA_USES_COLORSPACE  (1 << 1)
    252 
    253 STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
    254                                            unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
    255                                      int num_channels, int alpha_channel, int flags);
    256 
    257 
    258 typedef enum
    259 {
    260     STBIR_EDGE_CLAMP   = 1,
    261     STBIR_EDGE_REFLECT = 2,
    262     STBIR_EDGE_WRAP    = 3,
    263     STBIR_EDGE_ZERO    = 4,
    264 } stbir_edge;
    265 
    266 // This function adds the ability to specify how requests to sample off the edge of the image are handled.
    267 STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
    268                                                     unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
    269                                               int num_channels, int alpha_channel, int flags,
    270                                               stbir_edge edge_wrap_mode);
    271 
    272 //////////////////////////////////////////////////////////////////////////////
    273 //
    274 // Medium-complexity API
    275 //
    276 // This extends the easy-to-use API as follows:
    277 //
    278 //     * Alpha-channel can be processed separately
    279 //       * If alpha_channel is not STBIR_ALPHA_CHANNEL_NONE
    280 //         * Alpha channel will not be gamma corrected (unless flags&STBIR_FLAG_GAMMA_CORRECT)
    281 //         * Filters will be weighted by alpha channel (unless flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)
    282 //     * Filter can be selected explicitly
    283 //     * uint16 image type
    284 //     * sRGB colorspace available for all types
    285 //     * context parameter for passing to STBIR_MALLOC
    286 
    287 typedef enum
    288 {
    289     STBIR_FILTER_DEFAULT      = 0,  // use same filter type that easy-to-use API chooses
    290     STBIR_FILTER_BOX          = 1,  // A trapezoid w/1-pixel wide ramps, same result as box for integer scale ratios
    291     STBIR_FILTER_TRIANGLE     = 2,  // On upsampling, produces same results as bilinear texture filtering
    292     STBIR_FILTER_CUBICBSPLINE = 3,  // The cubic b-spline (aka Mitchell-Netrevalli with B=1,C=0), gaussian-esque
    293     STBIR_FILTER_CATMULLROM   = 4,  // An interpolating cubic spline
    294     STBIR_FILTER_MITCHELL     = 5,  // Mitchell-Netrevalli filter with B=1/3, C=1/3
    295 } stbir_filter;
    296 
    297 typedef enum
    298 {
    299     STBIR_COLORSPACE_LINEAR,
    300     STBIR_COLORSPACE_SRGB,
    301 
    302     STBIR_MAX_COLORSPACES,
    303 } stbir_colorspace;
    304 
    305 // The following functions are all identical except for the type of the image data
    306 
    307 STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
    308                                                unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
    309                                          int num_channels, int alpha_channel, int flags,
    310                                          stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
    311                                          void *alloc_context);
    312 
    313 STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels  , int input_w , int input_h , int input_stride_in_bytes,
    314                                                stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
    315                                          int num_channels, int alpha_channel, int flags,
    316                                          stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
    317                                          void *alloc_context);
    318 
    319 STBIRDEF int stbir_resize_float_generic( const float *input_pixels         , int input_w , int input_h , int input_stride_in_bytes,
    320                                                float *output_pixels        , int output_w, int output_h, int output_stride_in_bytes,
    321                                          int num_channels, int alpha_channel, int flags,
    322                                          stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
    323                                          void *alloc_context);
    324 
    325 
    326 
    327 //////////////////////////////////////////////////////////////////////////////
    328 //
    329 // Full-complexity API
    330 //
    331 // This extends the medium API as follows:
    332 //
    333 //       * uint32 image type
    334 //     * not typesafe
    335 //     * separate filter types for each axis
    336 //     * separate edge modes for each axis
    337 //     * can specify scale explicitly for subpixel correctness
    338 //     * can specify image source tile using texture coordinates
    339 
    340 typedef enum
    341 {
    342     STBIR_TYPE_UINT8 ,
    343     STBIR_TYPE_UINT16,
    344     STBIR_TYPE_UINT32,
    345     STBIR_TYPE_FLOAT ,
    346 
    347     STBIR_MAX_TYPES
    348 } stbir_datatype;
    349 
    350 STBIRDEF int stbir_resize(         const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
    351                                          void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
    352                                    stbir_datatype datatype,
    353                                    int num_channels, int alpha_channel, int flags,
    354                                    stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
    355                                    stbir_filter filter_horizontal,  stbir_filter filter_vertical,
    356                                    stbir_colorspace space, void *alloc_context);
    357 
    358 STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
    359                                          void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
    360                                    stbir_datatype datatype,
    361                                    int num_channels, int alpha_channel, int flags,
    362                                    stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
    363                                    stbir_filter filter_horizontal,  stbir_filter filter_vertical,
    364                                    stbir_colorspace space, void *alloc_context,
    365                                    float x_scale, float y_scale,
    366                                    float x_offset, float y_offset);
    367 
    368 STBIRDEF int stbir_resize_region(  const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
    369                                          void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
    370                                    stbir_datatype datatype,
    371                                    int num_channels, int alpha_channel, int flags,
    372                                    stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
    373                                    stbir_filter filter_horizontal,  stbir_filter filter_vertical,
    374                                    stbir_colorspace space, void *alloc_context,
    375                                    float s0, float t0, float s1, float t1);
    376 // (s0, t0) & (s1, t1) are the top-left and bottom right corner (uv addressing style: [0, 1]x[0, 1]) of a region of the input image to use.
    377 
    378 //
    379 //
    380 ////   end header file   /////////////////////////////////////////////////////
    381 #endif // STBIR_INCLUDE_STB_IMAGE_RESIZE_H
    382 
    383 
    384 
    385 
    386 
    387 #ifdef STB_IMAGE_RESIZE_IMPLEMENTATION
    388 
    389 #ifndef STBIR_ASSERT
    390 #include <assert.h>
    391 #define STBIR_ASSERT(x) assert(x)
    392 #endif
    393 
    394 // For memset
    395 #include <string.h>
    396 
    397 #include <math.h>
    398 
    399 #ifndef STBIR_MALLOC
    400 #include <stdlib.h>
    401 // use comma operator to evaluate c, to avoid "unused parameter" warnings
    402 #define STBIR_MALLOC(size,c) ((void)(c), malloc(size))
    403 #define STBIR_FREE(ptr,c)    ((void)(c), free(ptr))
    404 #endif
    405 
    406 #ifndef _MSC_VER
    407 #ifdef __cplusplus
    408 #define stbir__inline inline
    409 #else
    410 #define stbir__inline
    411 #endif
    412 #else
    413 #define stbir__inline __forceinline
    414 #endif
    415 
    416 
    417 // should produce compiler error if size is wrong
    418 typedef unsigned char stbir__validate_uint32[sizeof(stbir_uint32) == 4 ? 1 : -1];
    419 
    420 #ifdef _MSC_VER
    421 #define STBIR__NOTUSED(v)  (void)(v)
    422 #else
    423 #define STBIR__NOTUSED(v)  (void)sizeof(v)
    424 #endif
    425 
    426 #define STBIR__ARRAY_SIZE(a) (sizeof((a))/sizeof((a)[0]))
    427 
    428 #ifndef STBIR_DEFAULT_FILTER_UPSAMPLE
    429 #define STBIR_DEFAULT_FILTER_UPSAMPLE    STBIR_FILTER_CATMULLROM
    430 #endif
    431 
    432 #ifndef STBIR_DEFAULT_FILTER_DOWNSAMPLE
    433 #define STBIR_DEFAULT_FILTER_DOWNSAMPLE  STBIR_FILTER_MITCHELL
    434 #endif
    435 
    436 #ifndef STBIR_PROGRESS_REPORT
    437 #define STBIR_PROGRESS_REPORT(float_0_to_1)
    438 #endif
    439 
    440 #ifndef STBIR_MAX_CHANNELS
    441 #define STBIR_MAX_CHANNELS 64
    442 #endif
    443 
    444 #if STBIR_MAX_CHANNELS > 65536
    445 #error "Too many channels; STBIR_MAX_CHANNELS must be no more than 65536."
    446 // because we store the indices in 16-bit variables
    447 #endif
    448 
    449 // This value is added to alpha just before premultiplication to avoid
    450 // zeroing out color values. It is equivalent to 2^-80. If you don't want
    451 // that behavior (it may interfere if you have floating point images with
    452 // very small alpha values) then you can define STBIR_NO_ALPHA_EPSILON to
    453 // disable it.
    454 #ifndef STBIR_ALPHA_EPSILON
    455 #define STBIR_ALPHA_EPSILON ((float)1 / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20))
    456 #endif
    457 
    458 
    459 
    460 #ifdef _MSC_VER
    461 #define STBIR__UNUSED_PARAM(v)  (void)(v)
    462 #else
    463 #define STBIR__UNUSED_PARAM(v)  (void)sizeof(v)
    464 #endif
    465 
    466 // must match stbir_datatype
    467 static unsigned char stbir__type_size[] = {
    468     1, // STBIR_TYPE_UINT8
    469     2, // STBIR_TYPE_UINT16
    470     4, // STBIR_TYPE_UINT32
    471     4, // STBIR_TYPE_FLOAT
    472 };
    473 
    474 // Kernel function centered at 0
    475 typedef float (stbir__kernel_fn)(float x, float scale);
    476 typedef float (stbir__support_fn)(float scale);
    477 
    478 typedef struct
    479 {
    480     stbir__kernel_fn* kernel;
    481     stbir__support_fn* support;
    482 } stbir__filter_info;
    483 
    484 // When upsampling, the contributors are which source pixels contribute.
    485 // When downsampling, the contributors are which destination pixels are contributed to.
    486 typedef struct
    487 {
    488     int n0; // First contributing pixel
    489     int n1; // Last contributing pixel
    490 } stbir__contributors;
    491 
    492 typedef struct
    493 {
    494     const void* input_data;
    495     int input_w;
    496     int input_h;
    497     int input_stride_bytes;
    498 
    499     void* output_data;
    500     int output_w;
    501     int output_h;
    502     int output_stride_bytes;
    503 
    504     float s0, t0, s1, t1;
    505 
    506     float horizontal_shift; // Units: output pixels
    507     float vertical_shift;   // Units: output pixels
    508     float horizontal_scale;
    509     float vertical_scale;
    510 
    511     int channels;
    512     int alpha_channel;
    513     stbir_uint32 flags;
    514     stbir_datatype type;
    515     stbir_filter horizontal_filter;
    516     stbir_filter vertical_filter;
    517     stbir_edge edge_horizontal;
    518     stbir_edge edge_vertical;
    519     stbir_colorspace colorspace;
    520 
    521     stbir__contributors* horizontal_contributors;
    522     float* horizontal_coefficients;
    523 
    524     stbir__contributors* vertical_contributors;
    525     float* vertical_coefficients;
    526 
    527     int decode_buffer_pixels;
    528     float* decode_buffer;
    529 
    530     float* horizontal_buffer;
    531 
    532     // cache these because ceil/floor are inexplicably showing up in profile
    533     int horizontal_coefficient_width;
    534     int vertical_coefficient_width;
    535     int horizontal_filter_pixel_width;
    536     int vertical_filter_pixel_width;
    537     int horizontal_filter_pixel_margin;
    538     int vertical_filter_pixel_margin;
    539     int horizontal_num_contributors;
    540     int vertical_num_contributors;
    541 
    542     int ring_buffer_length_bytes;   // The length of an individual entry in the ring buffer. The total number of ring buffers is stbir__get_filter_pixel_width(filter)
    543     int ring_buffer_num_entries;    // Total number of entries in the ring buffer.
    544     int ring_buffer_first_scanline;
    545     int ring_buffer_last_scanline;
    546     int ring_buffer_begin_index;    // first_scanline is at this index in the ring buffer
    547     float* ring_buffer;
    548 
    549     float* encode_buffer; // A temporary buffer to store floats so we don't lose precision while we do multiply-adds.
    550 
    551     int horizontal_contributors_size;
    552     int horizontal_coefficients_size;
    553     int vertical_contributors_size;
    554     int vertical_coefficients_size;
    555     int decode_buffer_size;
    556     int horizontal_buffer_size;
    557     int ring_buffer_size;
    558     int encode_buffer_size;
    559 } stbir__info;
    560 
    561 
    562 static const float stbir__max_uint8_as_float  = 255.0f;
    563 static const float stbir__max_uint16_as_float = 65535.0f;
    564 static const double stbir__max_uint32_as_float = 4294967295.0;
    565 
    566 
    567 static stbir__inline int stbir__min(int a, int b)
    568 {
    569     return a < b ? a : b;
    570 }
    571 
    572 static stbir__inline float stbir__saturate(float x)
    573 {
    574     if (x < 0)
    575         return 0;
    576 
    577     if (x > 1)
    578         return 1;
    579 
    580     return x;
    581 }
    582 
    583 #ifdef STBIR_SATURATE_INT
    584 static stbir__inline stbir_uint8 stbir__saturate8(int x)
    585 {
    586     if ((unsigned int) x <= 255)
    587         return x;
    588 
    589     if (x < 0)
    590         return 0;
    591 
    592     return 255;
    593 }
    594 
    595 static stbir__inline stbir_uint16 stbir__saturate16(int x)
    596 {
    597     if ((unsigned int) x <= 65535)
    598         return x;
    599 
    600     if (x < 0)
    601         return 0;
    602 
    603     return 65535;
    604 }
    605 #endif
    606 
    607 static float stbir__srgb_uchar_to_linear_float[256] = {
    608     0.000000f, 0.000304f, 0.000607f, 0.000911f, 0.001214f, 0.001518f, 0.001821f, 0.002125f, 0.002428f, 0.002732f, 0.003035f,
    609     0.003347f, 0.003677f, 0.004025f, 0.004391f, 0.004777f, 0.005182f, 0.005605f, 0.006049f, 0.006512f, 0.006995f, 0.007499f,
    610     0.008023f, 0.008568f, 0.009134f, 0.009721f, 0.010330f, 0.010960f, 0.011612f, 0.012286f, 0.012983f, 0.013702f, 0.014444f,
    611     0.015209f, 0.015996f, 0.016807f, 0.017642f, 0.018500f, 0.019382f, 0.020289f, 0.021219f, 0.022174f, 0.023153f, 0.024158f,
    612     0.025187f, 0.026241f, 0.027321f, 0.028426f, 0.029557f, 0.030713f, 0.031896f, 0.033105f, 0.034340f, 0.035601f, 0.036889f,
    613     0.038204f, 0.039546f, 0.040915f, 0.042311f, 0.043735f, 0.045186f, 0.046665f, 0.048172f, 0.049707f, 0.051269f, 0.052861f,
    614     0.054480f, 0.056128f, 0.057805f, 0.059511f, 0.061246f, 0.063010f, 0.064803f, 0.066626f, 0.068478f, 0.070360f, 0.072272f,
    615     0.074214f, 0.076185f, 0.078187f, 0.080220f, 0.082283f, 0.084376f, 0.086500f, 0.088656f, 0.090842f, 0.093059f, 0.095307f,
    616     0.097587f, 0.099899f, 0.102242f, 0.104616f, 0.107023f, 0.109462f, 0.111932f, 0.114435f, 0.116971f, 0.119538f, 0.122139f,
    617     0.124772f, 0.127438f, 0.130136f, 0.132868f, 0.135633f, 0.138432f, 0.141263f, 0.144128f, 0.147027f, 0.149960f, 0.152926f,
    618     0.155926f, 0.158961f, 0.162029f, 0.165132f, 0.168269f, 0.171441f, 0.174647f, 0.177888f, 0.181164f, 0.184475f, 0.187821f,
    619     0.191202f, 0.194618f, 0.198069f, 0.201556f, 0.205079f, 0.208637f, 0.212231f, 0.215861f, 0.219526f, 0.223228f, 0.226966f,
    620     0.230740f, 0.234551f, 0.238398f, 0.242281f, 0.246201f, 0.250158f, 0.254152f, 0.258183f, 0.262251f, 0.266356f, 0.270498f,
    621     0.274677f, 0.278894f, 0.283149f, 0.287441f, 0.291771f, 0.296138f, 0.300544f, 0.304987f, 0.309469f, 0.313989f, 0.318547f,
    622     0.323143f, 0.327778f, 0.332452f, 0.337164f, 0.341914f, 0.346704f, 0.351533f, 0.356400f, 0.361307f, 0.366253f, 0.371238f,
    623     0.376262f, 0.381326f, 0.386430f, 0.391573f, 0.396755f, 0.401978f, 0.407240f, 0.412543f, 0.417885f, 0.423268f, 0.428691f,
    624     0.434154f, 0.439657f, 0.445201f, 0.450786f, 0.456411f, 0.462077f, 0.467784f, 0.473532f, 0.479320f, 0.485150f, 0.491021f,
    625     0.496933f, 0.502887f, 0.508881f, 0.514918f, 0.520996f, 0.527115f, 0.533276f, 0.539480f, 0.545725f, 0.552011f, 0.558340f,
    626     0.564712f, 0.571125f, 0.577581f, 0.584078f, 0.590619f, 0.597202f, 0.603827f, 0.610496f, 0.617207f, 0.623960f, 0.630757f,
    627     0.637597f, 0.644480f, 0.651406f, 0.658375f, 0.665387f, 0.672443f, 0.679543f, 0.686685f, 0.693872f, 0.701102f, 0.708376f,
    628     0.715694f, 0.723055f, 0.730461f, 0.737911f, 0.745404f, 0.752942f, 0.760525f, 0.768151f, 0.775822f, 0.783538f, 0.791298f,
    629     0.799103f, 0.806952f, 0.814847f, 0.822786f, 0.830770f, 0.838799f, 0.846873f, 0.854993f, 0.863157f, 0.871367f, 0.879622f,
    630     0.887923f, 0.896269f, 0.904661f, 0.913099f, 0.921582f, 0.930111f, 0.938686f, 0.947307f, 0.955974f, 0.964686f, 0.973445f,
    631     0.982251f, 0.991102f, 1.0f
    632 };
    633 
    634 static float stbir__srgb_to_linear(float f)
    635 {
    636     if (f <= 0.04045f)
    637         return f / 12.92f;
    638     else
    639         return (float)pow((f + 0.055f) / 1.055f, 2.4f);
    640 }
    641 
    642 static float stbir__linear_to_srgb(float f)
    643 {
    644     if (f <= 0.0031308f)
    645         return f * 12.92f;
    646     else
    647         return 1.055f * (float)pow(f, 1 / 2.4f) - 0.055f;
    648 }
    649 
    650 #ifndef STBIR_NON_IEEE_FLOAT
    651 // From https://gist.github.com/rygorous/2203834
    652 
    653 typedef union
    654 {
    655     stbir_uint32 u;
    656     float f;
    657 } stbir__FP32;
    658 
    659 static const stbir_uint32 fp32_to_srgb8_tab4[104] = {
    660     0x0073000d, 0x007a000d, 0x0080000d, 0x0087000d, 0x008d000d, 0x0094000d, 0x009a000d, 0x00a1000d,
    661     0x00a7001a, 0x00b4001a, 0x00c1001a, 0x00ce001a, 0x00da001a, 0x00e7001a, 0x00f4001a, 0x0101001a,
    662     0x010e0033, 0x01280033, 0x01410033, 0x015b0033, 0x01750033, 0x018f0033, 0x01a80033, 0x01c20033,
    663     0x01dc0067, 0x020f0067, 0x02430067, 0x02760067, 0x02aa0067, 0x02dd0067, 0x03110067, 0x03440067,
    664     0x037800ce, 0x03df00ce, 0x044600ce, 0x04ad00ce, 0x051400ce, 0x057b00c5, 0x05dd00bc, 0x063b00b5,
    665     0x06970158, 0x07420142, 0x07e30130, 0x087b0120, 0x090b0112, 0x09940106, 0x0a1700fc, 0x0a9500f2,
    666     0x0b0f01cb, 0x0bf401ae, 0x0ccb0195, 0x0d950180, 0x0e56016e, 0x0f0d015e, 0x0fbc0150, 0x10630143,
    667     0x11070264, 0x1238023e, 0x1357021d, 0x14660201, 0x156601e9, 0x165a01d3, 0x174401c0, 0x182401af,
    668     0x18fe0331, 0x1a9602fe, 0x1c1502d2, 0x1d7e02ad, 0x1ed4028d, 0x201a0270, 0x21520256, 0x227d0240,
    669     0x239f0443, 0x25c003fe, 0x27bf03c4, 0x29a10392, 0x2b6a0367, 0x2d1d0341, 0x2ebe031f, 0x304d0300,
    670     0x31d105b0, 0x34a80555, 0x37520507, 0x39d504c5, 0x3c37048b, 0x3e7c0458, 0x40a8042a, 0x42bd0401,
    671     0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559,
    672     0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723,
    673 };
    674 
    675 static stbir_uint8 stbir__linear_to_srgb_uchar(float in)
    676 {
    677     static const stbir__FP32 almostone = { 0x3f7fffff }; // 1-eps
    678     static const stbir__FP32 minval = { (127-13) << 23 };
    679     stbir_uint32 tab,bias,scale,t;
    680     stbir__FP32 f;
    681 
    682     // Clamp to [2^(-13), 1-eps]; these two values map to 0 and 1, respectively.
    683     // The tests are carefully written so that NaNs map to 0, same as in the reference
    684     // implementation.
    685     if (!(in > minval.f)) // written this way to catch NaNs
    686         in = minval.f;
    687     if (in > almostone.f)
    688         in = almostone.f;
    689 
    690     // Do the table lookup and unpack bias, scale
    691     f.f = in;
    692     tab = fp32_to_srgb8_tab4[(f.u - minval.u) >> 20];
    693     bias = (tab >> 16) << 9;
    694     scale = tab & 0xffff;
    695 
    696     // Grab next-highest mantissa bits and perform linear interpolation
    697     t = (f.u >> 12) & 0xff;
    698     return (unsigned char) ((bias + scale*t) >> 16);
    699 }
    700 
    701 #else
    702 // sRGB transition values, scaled by 1<<28
    703 static int stbir__srgb_offset_to_linear_scaled[256] =
    704 {
    705             0,     40738,    122216,    203693,    285170,    366648,    448125,    529603,
    706        611080,    692557,    774035,    855852,    942009,   1033024,   1128971,   1229926,
    707       1335959,   1447142,   1563542,   1685229,   1812268,   1944725,   2082664,   2226148,
    708       2375238,   2529996,   2690481,   2856753,   3028870,   3206888,   3390865,   3580856,
    709       3776916,   3979100,   4187460,   4402049,   4622919,   4850123,   5083710,   5323731,
    710       5570236,   5823273,   6082892,   6349140,   6622065,   6901714,   7188133,   7481369,
    711       7781466,   8088471,   8402427,   8723380,   9051372,   9386448,   9728650,  10078021,
    712      10434603,  10798439,  11169569,  11548036,  11933879,  12327139,  12727857,  13136073,
    713      13551826,  13975156,  14406100,  14844697,  15290987,  15745007,  16206795,  16676389,
    714      17153826,  17639142,  18132374,  18633560,  19142734,  19659934,  20185196,  20718552,
    715      21260042,  21809696,  22367554,  22933648,  23508010,  24090680,  24681686,  25281066,
    716      25888850,  26505076,  27129772,  27762974,  28404716,  29055026,  29713942,  30381490,
    717      31057708,  31742624,  32436272,  33138682,  33849884,  34569912,  35298800,  36036568,
    718      36783260,  37538896,  38303512,  39077136,  39859796,  40651528,  41452360,  42262316,
    719      43081432,  43909732,  44747252,  45594016,  46450052,  47315392,  48190064,  49074096,
    720      49967516,  50870356,  51782636,  52704392,  53635648,  54576432,  55526772,  56486700,
    721      57456236,  58435408,  59424248,  60422780,  61431036,  62449032,  63476804,  64514376,
    722      65561776,  66619028,  67686160,  68763192,  69850160,  70947088,  72053992,  73170912,
    723      74297864,  75434880,  76581976,  77739184,  78906536,  80084040,  81271736,  82469648,
    724      83677792,  84896192,  86124888,  87363888,  88613232,  89872928,  91143016,  92423512,
    725      93714432,  95015816,  96327688,  97650056,  98982952, 100326408, 101680440, 103045072,
    726     104420320, 105806224, 107202800, 108610064, 110028048, 111456776, 112896264, 114346544,
    727     115807632, 117279552, 118762328, 120255976, 121760536, 123276016, 124802440, 126339832,
    728     127888216, 129447616, 131018048, 132599544, 134192112, 135795792, 137410592, 139036528,
    729     140673648, 142321952, 143981456, 145652208, 147334208, 149027488, 150732064, 152447968,
    730     154175200, 155913792, 157663776, 159425168, 161197984, 162982240, 164777968, 166585184,
    731     168403904, 170234160, 172075968, 173929344, 175794320, 177670896, 179559120, 181458992,
    732     183370528, 185293776, 187228736, 189175424, 191133888, 193104112, 195086128, 197079968,
    733     199085648, 201103184, 203132592, 205173888, 207227120, 209292272, 211369392, 213458480,
    734     215559568, 217672656, 219797792, 221934976, 224084240, 226245600, 228419056, 230604656,
    735     232802400, 235012320, 237234432, 239468736, 241715280, 243974080, 246245120, 248528464,
    736     250824112, 253132064, 255452368, 257785040, 260130080, 262487520, 264857376, 267239664,
    737 };
    738 
    739 static stbir_uint8 stbir__linear_to_srgb_uchar(float f)
    740 {
    741     int x = (int) (f * (1 << 28)); // has headroom so you don't need to clamp
    742     int v = 0;
    743     int i;
    744 
    745     // Refine the guess with a short binary search.
    746     i = v + 128; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
    747     i = v +  64; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
    748     i = v +  32; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
    749     i = v +  16; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
    750     i = v +   8; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
    751     i = v +   4; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
    752     i = v +   2; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
    753     i = v +   1; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
    754 
    755     return (stbir_uint8) v;
    756 }
    757 #endif
    758 
    759 static float stbir__filter_trapezoid(float x, float scale)
    760 {
    761     float halfscale = scale / 2;
    762     float t = 0.5f + halfscale;
    763     STBIR_ASSERT(scale <= 1);
    764 
    765     x = (float)fabs(x);
    766 
    767     if (x >= t)
    768         return 0;
    769     else
    770     {
    771         float r = 0.5f - halfscale;
    772         if (x <= r)
    773             return 1;
    774         else
    775             return (t - x) / scale;
    776     }
    777 }
    778 
    779 static float stbir__support_trapezoid(float scale)
    780 {
    781     STBIR_ASSERT(scale <= 1);
    782     return 0.5f + scale / 2;
    783 }
    784 
    785 static float stbir__filter_triangle(float x, float s)
    786 {
    787     STBIR__UNUSED_PARAM(s);
    788 
    789     x = (float)fabs(x);
    790 
    791     if (x <= 1.0f)
    792         return 1 - x;
    793     else
    794         return 0;
    795 }
    796 
    797 static float stbir__filter_cubic(float x, float s)
    798 {
    799     STBIR__UNUSED_PARAM(s);
    800 
    801     x = (float)fabs(x);
    802 
    803     if (x < 1.0f)
    804         return (4 + x*x*(3*x - 6))/6;
    805     else if (x < 2.0f)
    806         return (8 + x*(-12 + x*(6 - x)))/6;
    807 
    808     return (0.0f);
    809 }
    810 
    811 static float stbir__filter_catmullrom(float x, float s)
    812 {
    813     STBIR__UNUSED_PARAM(s);
    814 
    815     x = (float)fabs(x);
    816 
    817     if (x < 1.0f)
    818         return 1 - x*x*(2.5f - 1.5f*x);
    819     else if (x < 2.0f)
    820         return 2 - x*(4 + x*(0.5f*x - 2.5f));
    821 
    822     return (0.0f);
    823 }
    824 
    825 static float stbir__filter_mitchell(float x, float s)
    826 {
    827     STBIR__UNUSED_PARAM(s);
    828 
    829     x = (float)fabs(x);
    830 
    831     if (x < 1.0f)
    832         return (16 + x*x*(21 * x - 36))/18;
    833     else if (x < 2.0f)
    834         return (32 + x*(-60 + x*(36 - 7*x)))/18;
    835 
    836     return (0.0f);
    837 }
    838 
    839 static float stbir__support_zero(float s)
    840 {
    841     STBIR__UNUSED_PARAM(s);
    842     return 0;
    843 }
    844 
    845 static float stbir__support_one(float s)
    846 {
    847     STBIR__UNUSED_PARAM(s);
    848     return 1;
    849 }
    850 
    851 static float stbir__support_two(float s)
    852 {
    853     STBIR__UNUSED_PARAM(s);
    854     return 2;
    855 }
    856 
    857 static stbir__filter_info stbir__filter_info_table[] = {
    858         { NULL,                     stbir__support_zero },
    859         { stbir__filter_trapezoid,  stbir__support_trapezoid },
    860         { stbir__filter_triangle,   stbir__support_one },
    861         { stbir__filter_cubic,      stbir__support_two },
    862         { stbir__filter_catmullrom, stbir__support_two },
    863         { stbir__filter_mitchell,   stbir__support_two },
    864 };
    865 
    866 stbir__inline static int stbir__use_upsampling(float ratio)
    867 {
    868     return ratio > 1;
    869 }
    870 
    871 stbir__inline static int stbir__use_width_upsampling(stbir__info* stbir_info)
    872 {
    873     return stbir__use_upsampling(stbir_info->horizontal_scale);
    874 }
    875 
    876 stbir__inline static int stbir__use_height_upsampling(stbir__info* stbir_info)
    877 {
    878     return stbir__use_upsampling(stbir_info->vertical_scale);
    879 }
    880 
    881 // This is the maximum number of input samples that can affect an output sample
    882 // with the given filter
    883 static int stbir__get_filter_pixel_width(stbir_filter filter, float scale)
    884 {
    885     STBIR_ASSERT(filter != 0);
    886     STBIR_ASSERT(filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
    887 
    888     if (stbir__use_upsampling(scale))
    889         return (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2);
    890     else
    891         return (int)ceil(stbir__filter_info_table[filter].support(scale) * 2 / scale);
    892 }
    893 
    894 // This is how much to expand buffers to account for filters seeking outside
    895 // the image boundaries.
    896 static int stbir__get_filter_pixel_margin(stbir_filter filter, float scale)
    897 {
    898     return stbir__get_filter_pixel_width(filter, scale) / 2;
    899 }
    900 
    901 static int stbir__get_coefficient_width(stbir_filter filter, float scale)
    902 {
    903     if (stbir__use_upsampling(scale))
    904         return (int)ceil(stbir__filter_info_table[filter].support(1 / scale) * 2);
    905     else
    906         return (int)ceil(stbir__filter_info_table[filter].support(scale) * 2);
    907 }
    908 
    909 static int stbir__get_contributors(float scale, stbir_filter filter, int input_size, int output_size)
    910 {
    911     if (stbir__use_upsampling(scale))
    912         return output_size;
    913     else
    914         return (input_size + stbir__get_filter_pixel_margin(filter, scale) * 2);
    915 }
    916 
    917 static int stbir__get_total_horizontal_coefficients(stbir__info* info)
    918 {
    919     return info->horizontal_num_contributors
    920          * stbir__get_coefficient_width      (info->horizontal_filter, info->horizontal_scale);
    921 }
    922 
    923 static int stbir__get_total_vertical_coefficients(stbir__info* info)
    924 {
    925     return info->vertical_num_contributors
    926          * stbir__get_coefficient_width      (info->vertical_filter, info->vertical_scale);
    927 }
    928 
    929 static stbir__contributors* stbir__get_contributor(stbir__contributors* contributors, int n)
    930 {
    931     return &contributors[n];
    932 }
    933 
    934 // For perf reasons this code is duplicated in stbir__resample_horizontal_upsample/downsample,
    935 // if you change it here change it there too.
    936 static float* stbir__get_coefficient(float* coefficients, stbir_filter filter, float scale, int n, int c)
    937 {
    938     int width = stbir__get_coefficient_width(filter, scale);
    939     return &coefficients[width*n + c];
    940 }
    941 
    942 static int stbir__edge_wrap_slow(stbir_edge edge, int n, int max)
    943 {
    944     switch (edge)
    945     {
    946     case STBIR_EDGE_ZERO:
    947         return 0; // we'll decode the wrong pixel here, and then overwrite with 0s later
    948 
    949     case STBIR_EDGE_CLAMP:
    950         if (n < 0)
    951             return 0;
    952 
    953         if (n >= max)
    954             return max - 1;
    955 
    956         return n; // NOTREACHED
    957 
    958     case STBIR_EDGE_REFLECT:
    959     {
    960         if (n < 0)
    961         {
    962             if (n < max)
    963                 return -n;
    964             else
    965                 return max - 1;
    966         }
    967 
    968         if (n >= max)
    969         {
    970             int max2 = max * 2;
    971             if (n >= max2)
    972                 return 0;
    973             else
    974                 return max2 - n - 1;
    975         }
    976 
    977         return n; // NOTREACHED
    978     }
    979 
    980     case STBIR_EDGE_WRAP:
    981         if (n >= 0)
    982             return (n % max);
    983         else
    984         {
    985             int m = (-n) % max;
    986 
    987             if (m != 0)
    988                 m = max - m;
    989 
    990             return (m);
    991         }
    992         // NOTREACHED
    993 
    994     default:
    995         STBIR_ASSERT(!"Unimplemented edge type");
    996         return 0;
    997     }
    998 }
    999 
   1000 stbir__inline static int stbir__edge_wrap(stbir_edge edge, int n, int max)
   1001 {
   1002     // avoid per-pixel switch
   1003     if (n >= 0 && n < max)
   1004         return n;
   1005     return stbir__edge_wrap_slow(edge, n, max);
   1006 }
   1007 
   1008 // What input pixels contribute to this output pixel?
   1009 static void stbir__calculate_sample_range_upsample(int n, float out_filter_radius, float scale_ratio, float out_shift, int* in_first_pixel, int* in_last_pixel, float* in_center_of_out)
   1010 {
   1011     float out_pixel_center = (float)n + 0.5f;
   1012     float out_pixel_influence_lowerbound = out_pixel_center - out_filter_radius;
   1013     float out_pixel_influence_upperbound = out_pixel_center + out_filter_radius;
   1014 
   1015     float in_pixel_influence_lowerbound = (out_pixel_influence_lowerbound + out_shift) / scale_ratio;
   1016     float in_pixel_influence_upperbound = (out_pixel_influence_upperbound + out_shift) / scale_ratio;
   1017 
   1018     *in_center_of_out = (out_pixel_center + out_shift) / scale_ratio;
   1019     *in_first_pixel = (int)(floor(in_pixel_influence_lowerbound + 0.5));
   1020     *in_last_pixel = (int)(floor(in_pixel_influence_upperbound - 0.5));
   1021 }
   1022 
   1023 // What output pixels does this input pixel contribute to?
   1024 static void stbir__calculate_sample_range_downsample(int n, float in_pixels_radius, float scale_ratio, float out_shift, int* out_first_pixel, int* out_last_pixel, float* out_center_of_in)
   1025 {
   1026     float in_pixel_center = (float)n + 0.5f;
   1027     float in_pixel_influence_lowerbound = in_pixel_center - in_pixels_radius;
   1028     float in_pixel_influence_upperbound = in_pixel_center + in_pixels_radius;
   1029 
   1030     float out_pixel_influence_lowerbound = in_pixel_influence_lowerbound * scale_ratio - out_shift;
   1031     float out_pixel_influence_upperbound = in_pixel_influence_upperbound * scale_ratio - out_shift;
   1032 
   1033     *out_center_of_in = in_pixel_center * scale_ratio - out_shift;
   1034     *out_first_pixel = (int)(floor(out_pixel_influence_lowerbound + 0.5));
   1035     *out_last_pixel = (int)(floor(out_pixel_influence_upperbound - 0.5));
   1036 }
   1037 
   1038 static void stbir__calculate_coefficients_upsample(stbir_filter filter, float scale, int in_first_pixel, int in_last_pixel, float in_center_of_out, stbir__contributors* contributor, float* coefficient_group)
   1039 {
   1040     int i;
   1041     float total_filter = 0;
   1042     float filter_scale;
   1043 
   1044     STBIR_ASSERT(in_last_pixel - in_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical.
   1045 
   1046     contributor->n0 = in_first_pixel;
   1047     contributor->n1 = in_last_pixel;
   1048 
   1049     STBIR_ASSERT(contributor->n1 >= contributor->n0);
   1050 
   1051     for (i = 0; i <= in_last_pixel - in_first_pixel; i++)
   1052     {
   1053         float in_pixel_center = (float)(i + in_first_pixel) + 0.5f;
   1054         coefficient_group[i] = stbir__filter_info_table[filter].kernel(in_center_of_out - in_pixel_center, 1 / scale);
   1055 
   1056         // If the coefficient is zero, skip it. (Don't do the <0 check here, we want the influence of those outside pixels.)
   1057         if (i == 0 && !coefficient_group[i])
   1058         {
   1059             contributor->n0 = ++in_first_pixel;
   1060             i--;
   1061             continue;
   1062         }
   1063 
   1064         total_filter += coefficient_group[i];
   1065     }
   1066 
   1067     // NOTE(fg): Not actually true in general, nor is there any reason to expect it should be.
   1068     // It would be true in exact math but is at best approximately true in floating-point math,
   1069     // and it would not make sense to try and put actual bounds on this here because it depends
   1070     // on the image aspect ratio which can get pretty extreme.
   1071     //STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(in_last_pixel + 1) + 0.5f - in_center_of_out, 1/scale) == 0);
   1072 
   1073     STBIR_ASSERT(total_filter > 0.9);
   1074     STBIR_ASSERT(total_filter < 1.1f); // Make sure it's not way off.
   1075 
   1076     // Make sure the sum of all coefficients is 1.
   1077     filter_scale = 1 / total_filter;
   1078 
   1079     for (i = 0; i <= in_last_pixel - in_first_pixel; i++)
   1080         coefficient_group[i] *= filter_scale;
   1081 
   1082     for (i = in_last_pixel - in_first_pixel; i >= 0; i--)
   1083     {
   1084         if (coefficient_group[i])
   1085             break;
   1086 
   1087         // This line has no weight. We can skip it.
   1088         contributor->n1 = contributor->n0 + i - 1;
   1089     }
   1090 }
   1091 
   1092 static void stbir__calculate_coefficients_downsample(stbir_filter filter, float scale_ratio, int out_first_pixel, int out_last_pixel, float out_center_of_in, stbir__contributors* contributor, float* coefficient_group)
   1093 {
   1094     int i;
   1095 
   1096     STBIR_ASSERT(out_last_pixel - out_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(scale_ratio) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical.
   1097 
   1098     contributor->n0 = out_first_pixel;
   1099     contributor->n1 = out_last_pixel;
   1100 
   1101     STBIR_ASSERT(contributor->n1 >= contributor->n0);
   1102 
   1103     for (i = 0; i <= out_last_pixel - out_first_pixel; i++)
   1104     {
   1105         float out_pixel_center = (float)(i + out_first_pixel) + 0.5f;
   1106         float x = out_pixel_center - out_center_of_in;
   1107         coefficient_group[i] = stbir__filter_info_table[filter].kernel(x, scale_ratio) * scale_ratio;
   1108     }
   1109 
   1110     // NOTE(fg): Not actually true in general, nor is there any reason to expect it should be.
   1111     // It would be true in exact math but is at best approximately true in floating-point math,
   1112     // and it would not make sense to try and put actual bounds on this here because it depends
   1113     // on the image aspect ratio which can get pretty extreme.
   1114     //STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(out_last_pixel + 1) + 0.5f - out_center_of_in, scale_ratio) == 0);
   1115 
   1116     for (i = out_last_pixel - out_first_pixel; i >= 0; i--)
   1117     {
   1118         if (coefficient_group[i])
   1119             break;
   1120 
   1121         // This line has no weight. We can skip it.
   1122         contributor->n1 = contributor->n0 + i - 1;
   1123     }
   1124 }
   1125 
   1126 static void stbir__normalize_downsample_coefficients(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, int input_size, int output_size)
   1127 {
   1128     int num_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size);
   1129     int num_coefficients = stbir__get_coefficient_width(filter, scale_ratio);
   1130     int i, j;
   1131     int skip;
   1132 
   1133     for (i = 0; i < output_size; i++)
   1134     {
   1135         float scale;
   1136         float total = 0;
   1137 
   1138         for (j = 0; j < num_contributors; j++)
   1139         {
   1140             if (i >= contributors[j].n0 && i <= contributors[j].n1)
   1141             {
   1142                 float coefficient = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0);
   1143                 total += coefficient;
   1144             }
   1145             else if (i < contributors[j].n0)
   1146                 break;
   1147         }
   1148 
   1149         STBIR_ASSERT(total > 0.9f);
   1150         STBIR_ASSERT(total < 1.1f);
   1151 
   1152         scale = 1 / total;
   1153 
   1154         for (j = 0; j < num_contributors; j++)
   1155         {
   1156             if (i >= contributors[j].n0 && i <= contributors[j].n1)
   1157                 *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0) *= scale;
   1158             else if (i < contributors[j].n0)
   1159                 break;
   1160         }
   1161     }
   1162 
   1163     // Optimize: Skip zero coefficients and contributions outside of image bounds.
   1164     // Do this after normalizing because normalization depends on the n0/n1 values.
   1165     for (j = 0; j < num_contributors; j++)
   1166     {
   1167         int range, max, width;
   1168 
   1169         skip = 0;
   1170         while (*stbir__get_coefficient(coefficients, filter, scale_ratio, j, skip) == 0)
   1171             skip++;
   1172 
   1173         contributors[j].n0 += skip;
   1174 
   1175         while (contributors[j].n0 < 0)
   1176         {
   1177             contributors[j].n0++;
   1178             skip++;
   1179         }
   1180 
   1181         range = contributors[j].n1 - contributors[j].n0 + 1;
   1182         max = stbir__min(num_coefficients, range);
   1183 
   1184         width = stbir__get_coefficient_width(filter, scale_ratio);
   1185         for (i = 0; i < max; i++)
   1186         {
   1187             if (i + skip >= width)
   1188                 break;
   1189 
   1190             *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i) = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i + skip);
   1191         }
   1192 
   1193         continue;
   1194     }
   1195 
   1196     // Using min to avoid writing into invalid pixels.
   1197     for (i = 0; i < num_contributors; i++)
   1198         contributors[i].n1 = stbir__min(contributors[i].n1, output_size - 1);
   1199 }
   1200 
   1201 // Each scan line uses the same kernel values so we should calculate the kernel
   1202 // values once and then we can use them for every scan line.
   1203 static void stbir__calculate_filters(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, float shift, int input_size, int output_size)
   1204 {
   1205     int n;
   1206     int total_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size);
   1207 
   1208     if (stbir__use_upsampling(scale_ratio))
   1209     {
   1210         float out_pixels_radius = stbir__filter_info_table[filter].support(1 / scale_ratio) * scale_ratio;
   1211 
   1212         // Looping through out pixels
   1213         for (n = 0; n < total_contributors; n++)
   1214         {
   1215             float in_center_of_out; // Center of the current out pixel in the in pixel space
   1216             int in_first_pixel, in_last_pixel;
   1217 
   1218             stbir__calculate_sample_range_upsample(n, out_pixels_radius, scale_ratio, shift, &in_first_pixel, &in_last_pixel, &in_center_of_out);
   1219 
   1220             stbir__calculate_coefficients_upsample(filter, scale_ratio, in_first_pixel, in_last_pixel, in_center_of_out, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0));
   1221         }
   1222     }
   1223     else
   1224     {
   1225         float in_pixels_radius = stbir__filter_info_table[filter].support(scale_ratio) / scale_ratio;
   1226 
   1227         // Looping through in pixels
   1228         for (n = 0; n < total_contributors; n++)
   1229         {
   1230             float out_center_of_in; // Center of the current out pixel in the in pixel space
   1231             int out_first_pixel, out_last_pixel;
   1232             int n_adjusted = n - stbir__get_filter_pixel_margin(filter, scale_ratio);
   1233 
   1234             stbir__calculate_sample_range_downsample(n_adjusted, in_pixels_radius, scale_ratio, shift, &out_first_pixel, &out_last_pixel, &out_center_of_in);
   1235 
   1236             stbir__calculate_coefficients_downsample(filter, scale_ratio, out_first_pixel, out_last_pixel, out_center_of_in, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0));
   1237         }
   1238 
   1239         stbir__normalize_downsample_coefficients(contributors, coefficients, filter, scale_ratio, input_size, output_size);
   1240     }
   1241 }
   1242 
   1243 static float* stbir__get_decode_buffer(stbir__info* stbir_info)
   1244 {
   1245     // The 0 index of the decode buffer starts after the margin. This makes
   1246     // it okay to use negative indexes on the decode buffer.
   1247     return &stbir_info->decode_buffer[stbir_info->horizontal_filter_pixel_margin * stbir_info->channels];
   1248 }
   1249 
   1250 #define STBIR__DECODE(type, colorspace) ((int)(type) * (STBIR_MAX_COLORSPACES) + (int)(colorspace))
   1251 
   1252 static void stbir__decode_scanline(stbir__info* stbir_info, int n)
   1253 {
   1254     int c;
   1255     int channels = stbir_info->channels;
   1256     int alpha_channel = stbir_info->alpha_channel;
   1257     int type = stbir_info->type;
   1258     int colorspace = stbir_info->colorspace;
   1259     int input_w = stbir_info->input_w;
   1260     size_t input_stride_bytes = stbir_info->input_stride_bytes;
   1261     float* decode_buffer = stbir__get_decode_buffer(stbir_info);
   1262     stbir_edge edge_horizontal = stbir_info->edge_horizontal;
   1263     stbir_edge edge_vertical = stbir_info->edge_vertical;
   1264     size_t in_buffer_row_offset = stbir__edge_wrap(edge_vertical, n, stbir_info->input_h) * input_stride_bytes;
   1265     const void* input_data = (char *) stbir_info->input_data + in_buffer_row_offset;
   1266     int max_x = input_w + stbir_info->horizontal_filter_pixel_margin;
   1267     int decode = STBIR__DECODE(type, colorspace);
   1268 
   1269     int x = -stbir_info->horizontal_filter_pixel_margin;
   1270 
   1271     // special handling for STBIR_EDGE_ZERO because it needs to return an item that doesn't appear in the input,
   1272     // and we want to avoid paying overhead on every pixel if not STBIR_EDGE_ZERO
   1273     if (edge_vertical == STBIR_EDGE_ZERO && (n < 0 || n >= stbir_info->input_h))
   1274     {
   1275         for (; x < max_x; x++)
   1276             for (c = 0; c < channels; c++)
   1277                 decode_buffer[x*channels + c] = 0;
   1278         return;
   1279     }
   1280 
   1281     switch (decode)
   1282     {
   1283     case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR):
   1284         for (; x < max_x; x++)
   1285         {
   1286             int decode_pixel_index = x * channels;
   1287             int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
   1288             for (c = 0; c < channels; c++)
   1289                 decode_buffer[decode_pixel_index + c] = ((float)((const unsigned char*)input_data)[input_pixel_index + c]) / stbir__max_uint8_as_float;
   1290         }
   1291         break;
   1292 
   1293     case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB):
   1294         for (; x < max_x; x++)
   1295         {
   1296             int decode_pixel_index = x * channels;
   1297             int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
   1298             for (c = 0; c < channels; c++)
   1299                 decode_buffer[decode_pixel_index + c] = stbir__srgb_uchar_to_linear_float[((const unsigned char*)input_data)[input_pixel_index + c]];
   1300 
   1301             if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
   1302                 decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned char*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint8_as_float;
   1303         }
   1304         break;
   1305 
   1306     case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR):
   1307         for (; x < max_x; x++)
   1308         {
   1309             int decode_pixel_index = x * channels;
   1310             int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
   1311             for (c = 0; c < channels; c++)
   1312                 decode_buffer[decode_pixel_index + c] = ((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float;
   1313         }
   1314         break;
   1315 
   1316     case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB):
   1317         for (; x < max_x; x++)
   1318         {
   1319             int decode_pixel_index = x * channels;
   1320             int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
   1321             for (c = 0; c < channels; c++)
   1322                 decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float);
   1323 
   1324             if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
   1325                 decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned short*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint16_as_float;
   1326         }
   1327         break;
   1328 
   1329     case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR):
   1330         for (; x < max_x; x++)
   1331         {
   1332             int decode_pixel_index = x * channels;
   1333             int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
   1334             for (c = 0; c < channels; c++)
   1335                 decode_buffer[decode_pixel_index + c] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float);
   1336         }
   1337         break;
   1338 
   1339     case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB):
   1340         for (; x < max_x; x++)
   1341         {
   1342             int decode_pixel_index = x * channels;
   1343             int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
   1344             for (c = 0; c < channels; c++)
   1345                 decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear((float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float));
   1346 
   1347             if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
   1348                 decode_buffer[decode_pixel_index + alpha_channel] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint32_as_float);
   1349         }
   1350         break;
   1351 
   1352     case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR):
   1353         for (; x < max_x; x++)
   1354         {
   1355             int decode_pixel_index = x * channels;
   1356             int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
   1357             for (c = 0; c < channels; c++)
   1358                 decode_buffer[decode_pixel_index + c] = ((const float*)input_data)[input_pixel_index + c];
   1359         }
   1360         break;
   1361 
   1362     case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB):
   1363         for (; x < max_x; x++)
   1364         {
   1365             int decode_pixel_index = x * channels;
   1366             int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
   1367             for (c = 0; c < channels; c++)
   1368                 decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((const float*)input_data)[input_pixel_index + c]);
   1369 
   1370             if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
   1371                 decode_buffer[decode_pixel_index + alpha_channel] = ((const float*)input_data)[input_pixel_index + alpha_channel];
   1372         }
   1373 
   1374         break;
   1375 
   1376     default:
   1377         STBIR_ASSERT(!"Unknown type/colorspace/channels combination.");
   1378         break;
   1379     }
   1380 
   1381     if (!(stbir_info->flags & STBIR_FLAG_ALPHA_PREMULTIPLIED))
   1382     {
   1383         for (x = -stbir_info->horizontal_filter_pixel_margin; x < max_x; x++)
   1384         {
   1385             int decode_pixel_index = x * channels;
   1386 
   1387             // If the alpha value is 0 it will clobber the color values. Make sure it's not.
   1388             float alpha = decode_buffer[decode_pixel_index + alpha_channel];
   1389 #ifndef STBIR_NO_ALPHA_EPSILON
   1390             if (stbir_info->type != STBIR_TYPE_FLOAT) {
   1391                 alpha += STBIR_ALPHA_EPSILON;
   1392                 decode_buffer[decode_pixel_index + alpha_channel] = alpha;
   1393             }
   1394 #endif
   1395             for (c = 0; c < channels; c++)
   1396             {
   1397                 if (c == alpha_channel)
   1398                     continue;
   1399 
   1400                 decode_buffer[decode_pixel_index + c] *= alpha;
   1401             }
   1402         }
   1403     }
   1404 
   1405     if (edge_horizontal == STBIR_EDGE_ZERO)
   1406     {
   1407         for (x = -stbir_info->horizontal_filter_pixel_margin; x < 0; x++)
   1408         {
   1409             for (c = 0; c < channels; c++)
   1410                 decode_buffer[x*channels + c] = 0;
   1411         }
   1412         for (x = input_w; x < max_x; x++)
   1413         {
   1414             for (c = 0; c < channels; c++)
   1415                 decode_buffer[x*channels + c] = 0;
   1416         }
   1417     }
   1418 }
   1419 
   1420 static float* stbir__get_ring_buffer_entry(float* ring_buffer, int index, int ring_buffer_length)
   1421 {
   1422     return &ring_buffer[index * ring_buffer_length];
   1423 }
   1424 
   1425 static float* stbir__add_empty_ring_buffer_entry(stbir__info* stbir_info, int n)
   1426 {
   1427     int ring_buffer_index;
   1428     float* ring_buffer;
   1429 
   1430     stbir_info->ring_buffer_last_scanline = n;
   1431 
   1432     if (stbir_info->ring_buffer_begin_index < 0)
   1433     {
   1434         ring_buffer_index = stbir_info->ring_buffer_begin_index = 0;
   1435         stbir_info->ring_buffer_first_scanline = n;
   1436     }
   1437     else
   1438     {
   1439         ring_buffer_index = (stbir_info->ring_buffer_begin_index + (stbir_info->ring_buffer_last_scanline - stbir_info->ring_buffer_first_scanline)) % stbir_info->ring_buffer_num_entries;
   1440         STBIR_ASSERT(ring_buffer_index != stbir_info->ring_buffer_begin_index);
   1441     }
   1442 
   1443     ring_buffer = stbir__get_ring_buffer_entry(stbir_info->ring_buffer, ring_buffer_index, stbir_info->ring_buffer_length_bytes / sizeof(float));
   1444     memset(ring_buffer, 0, stbir_info->ring_buffer_length_bytes);
   1445 
   1446     return ring_buffer;
   1447 }
   1448 
   1449 
   1450 static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, float* output_buffer)
   1451 {
   1452     int x, k;
   1453     int output_w = stbir_info->output_w;
   1454     int channels = stbir_info->channels;
   1455     float* decode_buffer = stbir__get_decode_buffer(stbir_info);
   1456     stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors;
   1457     float* horizontal_coefficients = stbir_info->horizontal_coefficients;
   1458     int coefficient_width = stbir_info->horizontal_coefficient_width;
   1459 
   1460     for (x = 0; x < output_w; x++)
   1461     {
   1462         int n0 = horizontal_contributors[x].n0;
   1463         int n1 = horizontal_contributors[x].n1;
   1464 
   1465         int out_pixel_index = x * channels;
   1466         int coefficient_group = coefficient_width * x;
   1467         int coefficient_counter = 0;
   1468 
   1469         STBIR_ASSERT(n1 >= n0);
   1470         STBIR_ASSERT(n0 >= -stbir_info->horizontal_filter_pixel_margin);
   1471         STBIR_ASSERT(n1 >= -stbir_info->horizontal_filter_pixel_margin);
   1472         STBIR_ASSERT(n0 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin);
   1473         STBIR_ASSERT(n1 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin);
   1474 
   1475         switch (channels) {
   1476             case 1:
   1477                 for (k = n0; k <= n1; k++)
   1478                 {
   1479                     int in_pixel_index = k * 1;
   1480                     float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
   1481                     STBIR_ASSERT(coefficient != 0);
   1482                     output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
   1483                 }
   1484                 break;
   1485             case 2:
   1486                 for (k = n0; k <= n1; k++)
   1487                 {
   1488                     int in_pixel_index = k * 2;
   1489                     float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
   1490                     STBIR_ASSERT(coefficient != 0);
   1491                     output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
   1492                     output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
   1493                 }
   1494                 break;
   1495             case 3:
   1496                 for (k = n0; k <= n1; k++)
   1497                 {
   1498                     int in_pixel_index = k * 3;
   1499                     float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
   1500                     STBIR_ASSERT(coefficient != 0);
   1501                     output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
   1502                     output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
   1503                     output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
   1504                 }
   1505                 break;
   1506             case 4:
   1507                 for (k = n0; k <= n1; k++)
   1508                 {
   1509                     int in_pixel_index = k * 4;
   1510                     float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
   1511                     STBIR_ASSERT(coefficient != 0);
   1512                     output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
   1513                     output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
   1514                     output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
   1515                     output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient;
   1516                 }
   1517                 break;
   1518             default:
   1519                 for (k = n0; k <= n1; k++)
   1520                 {
   1521                     int in_pixel_index = k * channels;
   1522                     float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
   1523                     int c;
   1524                     STBIR_ASSERT(coefficient != 0);
   1525                     for (c = 0; c < channels; c++)
   1526                         output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient;
   1527                 }
   1528                 break;
   1529         }
   1530     }
   1531 }
   1532 
   1533 static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, float* output_buffer)
   1534 {
   1535     int x, k;
   1536     int input_w = stbir_info->input_w;
   1537     int channels = stbir_info->channels;
   1538     float* decode_buffer = stbir__get_decode_buffer(stbir_info);
   1539     stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors;
   1540     float* horizontal_coefficients = stbir_info->horizontal_coefficients;
   1541     int coefficient_width = stbir_info->horizontal_coefficient_width;
   1542     int filter_pixel_margin = stbir_info->horizontal_filter_pixel_margin;
   1543     int max_x = input_w + filter_pixel_margin * 2;
   1544 
   1545     STBIR_ASSERT(!stbir__use_width_upsampling(stbir_info));
   1546 
   1547     switch (channels) {
   1548         case 1:
   1549             for (x = 0; x < max_x; x++)
   1550             {
   1551                 int n0 = horizontal_contributors[x].n0;
   1552                 int n1 = horizontal_contributors[x].n1;
   1553 
   1554                 int in_x = x - filter_pixel_margin;
   1555                 int in_pixel_index = in_x * 1;
   1556                 int max_n = n1;
   1557                 int coefficient_group = coefficient_width * x;
   1558 
   1559                 for (k = n0; k <= max_n; k++)
   1560                 {
   1561                     int out_pixel_index = k * 1;
   1562                     float coefficient = horizontal_coefficients[coefficient_group + k - n0];
   1563                     output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
   1564                 }
   1565             }
   1566             break;
   1567 
   1568         case 2:
   1569             for (x = 0; x < max_x; x++)
   1570             {
   1571                 int n0 = horizontal_contributors[x].n0;
   1572                 int n1 = horizontal_contributors[x].n1;
   1573 
   1574                 int in_x = x - filter_pixel_margin;
   1575                 int in_pixel_index = in_x * 2;
   1576                 int max_n = n1;
   1577                 int coefficient_group = coefficient_width * x;
   1578 
   1579                 for (k = n0; k <= max_n; k++)
   1580                 {
   1581                     int out_pixel_index = k * 2;
   1582                     float coefficient = horizontal_coefficients[coefficient_group + k - n0];
   1583                     output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
   1584                     output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
   1585                 }
   1586             }
   1587             break;
   1588 
   1589         case 3:
   1590             for (x = 0; x < max_x; x++)
   1591             {
   1592                 int n0 = horizontal_contributors[x].n0;
   1593                 int n1 = horizontal_contributors[x].n1;
   1594 
   1595                 int in_x = x - filter_pixel_margin;
   1596                 int in_pixel_index = in_x * 3;
   1597                 int max_n = n1;
   1598                 int coefficient_group = coefficient_width * x;
   1599 
   1600                 for (k = n0; k <= max_n; k++)
   1601                 {
   1602                     int out_pixel_index = k * 3;
   1603                     float coefficient = horizontal_coefficients[coefficient_group + k - n0];
   1604                     output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
   1605                     output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
   1606                     output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
   1607                 }
   1608             }
   1609             break;
   1610 
   1611         case 4:
   1612             for (x = 0; x < max_x; x++)
   1613             {
   1614                 int n0 = horizontal_contributors[x].n0;
   1615                 int n1 = horizontal_contributors[x].n1;
   1616 
   1617                 int in_x = x - filter_pixel_margin;
   1618                 int in_pixel_index = in_x * 4;
   1619                 int max_n = n1;
   1620                 int coefficient_group = coefficient_width * x;
   1621 
   1622                 for (k = n0; k <= max_n; k++)
   1623                 {
   1624                     int out_pixel_index = k * 4;
   1625                     float coefficient = horizontal_coefficients[coefficient_group + k - n0];
   1626                     output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
   1627                     output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
   1628                     output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
   1629                     output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient;
   1630                 }
   1631             }
   1632             break;
   1633 
   1634         default:
   1635             for (x = 0; x < max_x; x++)
   1636             {
   1637                 int n0 = horizontal_contributors[x].n0;
   1638                 int n1 = horizontal_contributors[x].n1;
   1639 
   1640                 int in_x = x - filter_pixel_margin;
   1641                 int in_pixel_index = in_x * channels;
   1642                 int max_n = n1;
   1643                 int coefficient_group = coefficient_width * x;
   1644 
   1645                 for (k = n0; k <= max_n; k++)
   1646                 {
   1647                     int c;
   1648                     int out_pixel_index = k * channels;
   1649                     float coefficient = horizontal_coefficients[coefficient_group + k - n0];
   1650                     for (c = 0; c < channels; c++)
   1651                         output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient;
   1652                 }
   1653             }
   1654             break;
   1655     }
   1656 }
   1657 
   1658 static void stbir__decode_and_resample_upsample(stbir__info* stbir_info, int n)
   1659 {
   1660     // Decode the nth scanline from the source image into the decode buffer.
   1661     stbir__decode_scanline(stbir_info, n);
   1662 
   1663     // Now resample it into the ring buffer.
   1664     if (stbir__use_width_upsampling(stbir_info))
   1665         stbir__resample_horizontal_upsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n));
   1666     else
   1667         stbir__resample_horizontal_downsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n));
   1668 
   1669     // Now it's sitting in the ring buffer ready to be used as source for the vertical sampling.
   1670 }
   1671 
   1672 static void stbir__decode_and_resample_downsample(stbir__info* stbir_info, int n)
   1673 {
   1674     // Decode the nth scanline from the source image into the decode buffer.
   1675     stbir__decode_scanline(stbir_info, n);
   1676 
   1677     memset(stbir_info->horizontal_buffer, 0, stbir_info->output_w * stbir_info->channels * sizeof(float));
   1678 
   1679     // Now resample it into the horizontal buffer.
   1680     if (stbir__use_width_upsampling(stbir_info))
   1681         stbir__resample_horizontal_upsample(stbir_info, stbir_info->horizontal_buffer);
   1682     else
   1683         stbir__resample_horizontal_downsample(stbir_info, stbir_info->horizontal_buffer);
   1684 
   1685     // Now it's sitting in the horizontal buffer ready to be distributed into the ring buffers.
   1686 }
   1687 
   1688 // Get the specified scan line from the ring buffer.
   1689 static float* stbir__get_ring_buffer_scanline(int get_scanline, float* ring_buffer, int begin_index, int first_scanline, int ring_buffer_num_entries, int ring_buffer_length)
   1690 {
   1691     int ring_buffer_index = (begin_index + (get_scanline - first_scanline)) % ring_buffer_num_entries;
   1692     return stbir__get_ring_buffer_entry(ring_buffer, ring_buffer_index, ring_buffer_length);
   1693 }
   1694 
   1695 
   1696 static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void *output_buffer, float *encode_buffer, int channels, int alpha_channel, int decode)
   1697 {
   1698     int x;
   1699     int n;
   1700     int num_nonalpha;
   1701     stbir_uint16 nonalpha[STBIR_MAX_CHANNELS];
   1702 
   1703     if (!(stbir_info->flags&STBIR_FLAG_ALPHA_PREMULTIPLIED))
   1704     {
   1705         for (x=0; x < num_pixels; ++x)
   1706         {
   1707             int pixel_index = x*channels;
   1708 
   1709             float alpha = encode_buffer[pixel_index + alpha_channel];
   1710             float reciprocal_alpha = alpha ? 1.0f / alpha : 0;
   1711 
   1712             // unrolling this produced a 1% slowdown upscaling a large RGBA linear-space image on my machine - stb
   1713             for (n = 0; n < channels; n++)
   1714                 if (n != alpha_channel)
   1715                     encode_buffer[pixel_index + n] *= reciprocal_alpha;
   1716 
   1717             // We added in a small epsilon to prevent the color channel from being deleted with zero alpha.
   1718             // Because we only add it for integer types, it will automatically be discarded on integer
   1719             // conversion, so we don't need to subtract it back out (which would be problematic for
   1720             // numeric precision reasons).
   1721         }
   1722     }
   1723 
   1724     // build a table of all channels that need colorspace correction, so
   1725     // we don't perform colorspace correction on channels that don't need it.
   1726     for (x = 0, num_nonalpha = 0; x < channels; ++x)
   1727     {
   1728         if (x != alpha_channel || (stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE))
   1729         {
   1730             nonalpha[num_nonalpha++] = (stbir_uint16)x;
   1731         }
   1732     }
   1733 
   1734     #define STBIR__ROUND_INT(f)    ((int)          ((f)+0.5))
   1735     #define STBIR__ROUND_UINT(f)   ((stbir_uint32) ((f)+0.5))
   1736 
   1737     #ifdef STBIR__SATURATE_INT
   1738     #define STBIR__ENCODE_LINEAR8(f)   stbir__saturate8 (STBIR__ROUND_INT((f) * stbir__max_uint8_as_float ))
   1739     #define STBIR__ENCODE_LINEAR16(f)  stbir__saturate16(STBIR__ROUND_INT((f) * stbir__max_uint16_as_float))
   1740     #else
   1741     #define STBIR__ENCODE_LINEAR8(f)   (unsigned char ) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint8_as_float )
   1742     #define STBIR__ENCODE_LINEAR16(f)  (unsigned short) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint16_as_float)
   1743     #endif
   1744 
   1745     switch (decode)
   1746     {
   1747         case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR):
   1748             for (x=0; x < num_pixels; ++x)
   1749             {
   1750                 int pixel_index = x*channels;
   1751 
   1752                 for (n = 0; n < channels; n++)
   1753                 {
   1754                     int index = pixel_index + n;
   1755                     ((unsigned char*)output_buffer)[index] = STBIR__ENCODE_LINEAR8(encode_buffer[index]);
   1756                 }
   1757             }
   1758             break;
   1759 
   1760         case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB):
   1761             for (x=0; x < num_pixels; ++x)
   1762             {
   1763                 int pixel_index = x*channels;
   1764 
   1765                 for (n = 0; n < num_nonalpha; n++)
   1766                 {
   1767                     int index = pixel_index + nonalpha[n];
   1768                     ((unsigned char*)output_buffer)[index] = stbir__linear_to_srgb_uchar(encode_buffer[index]);
   1769                 }
   1770 
   1771                 if (!(stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE))
   1772                     ((unsigned char *)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR8(encode_buffer[pixel_index+alpha_channel]);
   1773             }
   1774             break;
   1775 
   1776         case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR):
   1777             for (x=0; x < num_pixels; ++x)
   1778             {
   1779                 int pixel_index = x*channels;
   1780 
   1781                 for (n = 0; n < channels; n++)
   1782                 {
   1783                     int index = pixel_index + n;
   1784                     ((unsigned short*)output_buffer)[index] = STBIR__ENCODE_LINEAR16(encode_buffer[index]);
   1785                 }
   1786             }
   1787             break;
   1788 
   1789         case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB):
   1790             for (x=0; x < num_pixels; ++x)
   1791             {
   1792                 int pixel_index = x*channels;
   1793 
   1794                 for (n = 0; n < num_nonalpha; n++)
   1795                 {
   1796                     int index = pixel_index + nonalpha[n];
   1797                     ((unsigned short*)output_buffer)[index] = (unsigned short)STBIR__ROUND_INT(stbir__linear_to_srgb(stbir__saturate(encode_buffer[index])) * stbir__max_uint16_as_float);
   1798                 }
   1799 
   1800                 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
   1801                     ((unsigned short*)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR16(encode_buffer[pixel_index + alpha_channel]);
   1802             }
   1803 
   1804             break;
   1805 
   1806         case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR):
   1807             for (x=0; x < num_pixels; ++x)
   1808             {
   1809                 int pixel_index = x*channels;
   1810 
   1811                 for (n = 0; n < channels; n++)
   1812                 {
   1813                     int index = pixel_index + n;
   1814                     ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__saturate(encode_buffer[index])) * stbir__max_uint32_as_float);
   1815                 }
   1816             }
   1817             break;
   1818 
   1819         case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB):
   1820             for (x=0; x < num_pixels; ++x)
   1821             {
   1822                 int pixel_index = x*channels;
   1823 
   1824                 for (n = 0; n < num_nonalpha; n++)
   1825                 {
   1826                     int index = pixel_index + nonalpha[n];
   1827                     ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__linear_to_srgb(stbir__saturate(encode_buffer[index]))) * stbir__max_uint32_as_float);
   1828                 }
   1829 
   1830                 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
   1831                     ((unsigned int*)output_buffer)[pixel_index + alpha_channel] = (unsigned int)STBIR__ROUND_INT(((double)stbir__saturate(encode_buffer[pixel_index + alpha_channel])) * stbir__max_uint32_as_float);
   1832             }
   1833             break;
   1834 
   1835         case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR):
   1836             for (x=0; x < num_pixels; ++x)
   1837             {
   1838                 int pixel_index = x*channels;
   1839 
   1840                 for (n = 0; n < channels; n++)
   1841                 {
   1842                     int index = pixel_index + n;
   1843                     ((float*)output_buffer)[index] = encode_buffer[index];
   1844                 }
   1845             }
   1846             break;
   1847 
   1848         case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB):
   1849             for (x=0; x < num_pixels; ++x)
   1850             {
   1851                 int pixel_index = x*channels;
   1852 
   1853                 for (n = 0; n < num_nonalpha; n++)
   1854                 {
   1855                     int index = pixel_index + nonalpha[n];
   1856                     ((float*)output_buffer)[index] = stbir__linear_to_srgb(encode_buffer[index]);
   1857                 }
   1858 
   1859                 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
   1860                     ((float*)output_buffer)[pixel_index + alpha_channel] = encode_buffer[pixel_index + alpha_channel];
   1861             }
   1862             break;
   1863 
   1864         default:
   1865             STBIR_ASSERT(!"Unknown type/colorspace/channels combination.");
   1866             break;
   1867     }
   1868 }
   1869 
   1870 static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n)
   1871 {
   1872     int x, k;
   1873     int output_w = stbir_info->output_w;
   1874     stbir__contributors* vertical_contributors = stbir_info->vertical_contributors;
   1875     float* vertical_coefficients = stbir_info->vertical_coefficients;
   1876     int channels = stbir_info->channels;
   1877     int alpha_channel = stbir_info->alpha_channel;
   1878     int type = stbir_info->type;
   1879     int colorspace = stbir_info->colorspace;
   1880     int ring_buffer_entries = stbir_info->ring_buffer_num_entries;
   1881     void* output_data = stbir_info->output_data;
   1882     float* encode_buffer = stbir_info->encode_buffer;
   1883     int decode = STBIR__DECODE(type, colorspace);
   1884     int coefficient_width = stbir_info->vertical_coefficient_width;
   1885     int coefficient_counter;
   1886     int contributor = n;
   1887 
   1888     float* ring_buffer = stbir_info->ring_buffer;
   1889     int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index;
   1890     int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline;
   1891     int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
   1892 
   1893     int n0,n1, output_row_start;
   1894     int coefficient_group = coefficient_width * contributor;
   1895 
   1896     n0 = vertical_contributors[contributor].n0;
   1897     n1 = vertical_contributors[contributor].n1;
   1898 
   1899     output_row_start = n * stbir_info->output_stride_bytes;
   1900 
   1901     STBIR_ASSERT(stbir__use_height_upsampling(stbir_info));
   1902 
   1903     memset(encode_buffer, 0, output_w * sizeof(float) * channels);
   1904 
   1905     // I tried reblocking this for better cache usage of encode_buffer
   1906     // (using x_outer, k, x_inner), but it lost speed. -- stb
   1907 
   1908     coefficient_counter = 0;
   1909     switch (channels) {
   1910         case 1:
   1911             for (k = n0; k <= n1; k++)
   1912             {
   1913                 int coefficient_index = coefficient_counter++;
   1914                 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
   1915                 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
   1916                 for (x = 0; x < output_w; ++x)
   1917                 {
   1918                     int in_pixel_index = x * 1;
   1919                     encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
   1920                 }
   1921             }
   1922             break;
   1923         case 2:
   1924             for (k = n0; k <= n1; k++)
   1925             {
   1926                 int coefficient_index = coefficient_counter++;
   1927                 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
   1928                 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
   1929                 for (x = 0; x < output_w; ++x)
   1930                 {
   1931                     int in_pixel_index = x * 2;
   1932                     encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
   1933                     encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
   1934                 }
   1935             }
   1936             break;
   1937         case 3:
   1938             for (k = n0; k <= n1; k++)
   1939             {
   1940                 int coefficient_index = coefficient_counter++;
   1941                 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
   1942                 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
   1943                 for (x = 0; x < output_w; ++x)
   1944                 {
   1945                     int in_pixel_index = x * 3;
   1946                     encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
   1947                     encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
   1948                     encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient;
   1949                 }
   1950             }
   1951             break;
   1952         case 4:
   1953             for (k = n0; k <= n1; k++)
   1954             {
   1955                 int coefficient_index = coefficient_counter++;
   1956                 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
   1957                 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
   1958                 for (x = 0; x < output_w; ++x)
   1959                 {
   1960                     int in_pixel_index = x * 4;
   1961                     encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
   1962                     encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
   1963                     encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient;
   1964                     encode_buffer[in_pixel_index + 3] += ring_buffer_entry[in_pixel_index + 3] * coefficient;
   1965                 }
   1966             }
   1967             break;
   1968         default:
   1969             for (k = n0; k <= n1; k++)
   1970             {
   1971                 int coefficient_index = coefficient_counter++;
   1972                 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
   1973                 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
   1974                 for (x = 0; x < output_w; ++x)
   1975                 {
   1976                     int in_pixel_index = x * channels;
   1977                     int c;
   1978                     for (c = 0; c < channels; c++)
   1979                         encode_buffer[in_pixel_index + c] += ring_buffer_entry[in_pixel_index + c] * coefficient;
   1980                 }
   1981             }
   1982             break;
   1983     }
   1984     stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, encode_buffer, channels, alpha_channel, decode);
   1985 }
   1986 
   1987 static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n)
   1988 {
   1989     int x, k;
   1990     int output_w = stbir_info->output_w;
   1991     stbir__contributors* vertical_contributors = stbir_info->vertical_contributors;
   1992     float* vertical_coefficients = stbir_info->vertical_coefficients;
   1993     int channels = stbir_info->channels;
   1994     int ring_buffer_entries = stbir_info->ring_buffer_num_entries;
   1995     float* horizontal_buffer = stbir_info->horizontal_buffer;
   1996     int coefficient_width = stbir_info->vertical_coefficient_width;
   1997     int contributor = n + stbir_info->vertical_filter_pixel_margin;
   1998 
   1999     float* ring_buffer = stbir_info->ring_buffer;
   2000     int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index;
   2001     int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline;
   2002     int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
   2003     int n0,n1;
   2004 
   2005     n0 = vertical_contributors[contributor].n0;
   2006     n1 = vertical_contributors[contributor].n1;
   2007 
   2008     STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info));
   2009 
   2010     for (k = n0; k <= n1; k++)
   2011     {
   2012         int coefficient_index = k - n0;
   2013         int coefficient_group = coefficient_width * contributor;
   2014         float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
   2015 
   2016         float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
   2017 
   2018         switch (channels) {
   2019             case 1:
   2020                 for (x = 0; x < output_w; x++)
   2021                 {
   2022                     int in_pixel_index = x * 1;
   2023                     ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
   2024                 }
   2025                 break;
   2026             case 2:
   2027                 for (x = 0; x < output_w; x++)
   2028                 {
   2029                     int in_pixel_index = x * 2;
   2030                     ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
   2031                     ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
   2032                 }
   2033                 break;
   2034             case 3:
   2035                 for (x = 0; x < output_w; x++)
   2036                 {
   2037                     int in_pixel_index = x * 3;
   2038                     ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
   2039                     ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
   2040                     ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient;
   2041                 }
   2042                 break;
   2043             case 4:
   2044                 for (x = 0; x < output_w; x++)
   2045                 {
   2046                     int in_pixel_index = x * 4;
   2047                     ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
   2048                     ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
   2049                     ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient;
   2050                     ring_buffer_entry[in_pixel_index + 3] += horizontal_buffer[in_pixel_index + 3] * coefficient;
   2051                 }
   2052                 break;
   2053             default:
   2054                 for (x = 0; x < output_w; x++)
   2055                 {
   2056                     int in_pixel_index = x * channels;
   2057 
   2058                     int c;
   2059                     for (c = 0; c < channels; c++)
   2060                         ring_buffer_entry[in_pixel_index + c] += horizontal_buffer[in_pixel_index + c] * coefficient;
   2061                 }
   2062                 break;
   2063         }
   2064     }
   2065 }
   2066 
   2067 static void stbir__buffer_loop_upsample(stbir__info* stbir_info)
   2068 {
   2069     int y;
   2070     float scale_ratio = stbir_info->vertical_scale;
   2071     float out_scanlines_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(1/scale_ratio) * scale_ratio;
   2072 
   2073     STBIR_ASSERT(stbir__use_height_upsampling(stbir_info));
   2074 
   2075     for (y = 0; y < stbir_info->output_h; y++)
   2076     {
   2077         float in_center_of_out = 0; // Center of the current out scanline in the in scanline space
   2078         int in_first_scanline = 0, in_last_scanline = 0;
   2079 
   2080         stbir__calculate_sample_range_upsample(y, out_scanlines_radius, scale_ratio, stbir_info->vertical_shift, &in_first_scanline, &in_last_scanline, &in_center_of_out);
   2081 
   2082         STBIR_ASSERT(in_last_scanline - in_first_scanline + 1 <= stbir_info->ring_buffer_num_entries);
   2083 
   2084         if (stbir_info->ring_buffer_begin_index >= 0)
   2085         {
   2086             // Get rid of whatever we don't need anymore.
   2087             while (in_first_scanline > stbir_info->ring_buffer_first_scanline)
   2088             {
   2089                 if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline)
   2090                 {
   2091                     // We just popped the last scanline off the ring buffer.
   2092                     // Reset it to the empty state.
   2093                     stbir_info->ring_buffer_begin_index = -1;
   2094                     stbir_info->ring_buffer_first_scanline = 0;
   2095                     stbir_info->ring_buffer_last_scanline = 0;
   2096                     break;
   2097                 }
   2098                 else
   2099                 {
   2100                     stbir_info->ring_buffer_first_scanline++;
   2101                     stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries;
   2102                 }
   2103             }
   2104         }
   2105 
   2106         // Load in new ones.
   2107         if (stbir_info->ring_buffer_begin_index < 0)
   2108             stbir__decode_and_resample_upsample(stbir_info, in_first_scanline);
   2109 
   2110         while (in_last_scanline > stbir_info->ring_buffer_last_scanline)
   2111             stbir__decode_and_resample_upsample(stbir_info, stbir_info->ring_buffer_last_scanline + 1);
   2112 
   2113         // Now all buffers should be ready to write a row of vertical sampling.
   2114         stbir__resample_vertical_upsample(stbir_info, y);
   2115 
   2116         STBIR_PROGRESS_REPORT((float)y / stbir_info->output_h);
   2117     }
   2118 }
   2119 
   2120 static void stbir__empty_ring_buffer(stbir__info* stbir_info, int first_necessary_scanline)
   2121 {
   2122     int output_stride_bytes = stbir_info->output_stride_bytes;
   2123     int channels = stbir_info->channels;
   2124     int alpha_channel = stbir_info->alpha_channel;
   2125     int type = stbir_info->type;
   2126     int colorspace = stbir_info->colorspace;
   2127     int output_w = stbir_info->output_w;
   2128     void* output_data = stbir_info->output_data;
   2129     int decode = STBIR__DECODE(type, colorspace);
   2130 
   2131     float* ring_buffer = stbir_info->ring_buffer;
   2132     int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
   2133 
   2134     if (stbir_info->ring_buffer_begin_index >= 0)
   2135     {
   2136         // Get rid of whatever we don't need anymore.
   2137         while (first_necessary_scanline > stbir_info->ring_buffer_first_scanline)
   2138         {
   2139             if (stbir_info->ring_buffer_first_scanline >= 0 && stbir_info->ring_buffer_first_scanline < stbir_info->output_h)
   2140             {
   2141                 int output_row_start = stbir_info->ring_buffer_first_scanline * output_stride_bytes;
   2142                 float* ring_buffer_entry = stbir__get_ring_buffer_entry(ring_buffer, stbir_info->ring_buffer_begin_index, ring_buffer_length);
   2143                 stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, ring_buffer_entry, channels, alpha_channel, decode);
   2144                 STBIR_PROGRESS_REPORT((float)stbir_info->ring_buffer_first_scanline / stbir_info->output_h);
   2145             }
   2146 
   2147             if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline)
   2148             {
   2149                 // We just popped the last scanline off the ring buffer.
   2150                 // Reset it to the empty state.
   2151                 stbir_info->ring_buffer_begin_index = -1;
   2152                 stbir_info->ring_buffer_first_scanline = 0;
   2153                 stbir_info->ring_buffer_last_scanline = 0;
   2154                 break;
   2155             }
   2156             else
   2157             {
   2158                 stbir_info->ring_buffer_first_scanline++;
   2159                 stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries;
   2160             }
   2161         }
   2162     }
   2163 }
   2164 
   2165 static void stbir__buffer_loop_downsample(stbir__info* stbir_info)
   2166 {
   2167     int y;
   2168     float scale_ratio = stbir_info->vertical_scale;
   2169     int output_h = stbir_info->output_h;
   2170     float in_pixels_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(scale_ratio) / scale_ratio;
   2171     int pixel_margin = stbir_info->vertical_filter_pixel_margin;
   2172     int max_y = stbir_info->input_h + pixel_margin;
   2173 
   2174     STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info));
   2175 
   2176     for (y = -pixel_margin; y < max_y; y++)
   2177     {
   2178         float out_center_of_in; // Center of the current out scanline in the in scanline space
   2179         int out_first_scanline, out_last_scanline;
   2180 
   2181         stbir__calculate_sample_range_downsample(y, in_pixels_radius, scale_ratio, stbir_info->vertical_shift, &out_first_scanline, &out_last_scanline, &out_center_of_in);
   2182 
   2183         STBIR_ASSERT(out_last_scanline - out_first_scanline + 1 <= stbir_info->ring_buffer_num_entries);
   2184 
   2185         if (out_last_scanline < 0 || out_first_scanline >= output_h)
   2186             continue;
   2187 
   2188         stbir__empty_ring_buffer(stbir_info, out_first_scanline);
   2189 
   2190         stbir__decode_and_resample_downsample(stbir_info, y);
   2191 
   2192         // Load in new ones.
   2193         if (stbir_info->ring_buffer_begin_index < 0)
   2194             stbir__add_empty_ring_buffer_entry(stbir_info, out_first_scanline);
   2195 
   2196         while (out_last_scanline > stbir_info->ring_buffer_last_scanline)
   2197             stbir__add_empty_ring_buffer_entry(stbir_info, stbir_info->ring_buffer_last_scanline + 1);
   2198 
   2199         // Now the horizontal buffer is ready to write to all ring buffer rows.
   2200         stbir__resample_vertical_downsample(stbir_info, y);
   2201     }
   2202 
   2203     stbir__empty_ring_buffer(stbir_info, stbir_info->output_h);
   2204 }
   2205 
   2206 static void stbir__setup(stbir__info *info, int input_w, int input_h, int output_w, int output_h, int channels)
   2207 {
   2208     info->input_w = input_w;
   2209     info->input_h = input_h;
   2210     info->output_w = output_w;
   2211     info->output_h = output_h;
   2212     info->channels = channels;
   2213 }
   2214 
   2215 static void stbir__calculate_transform(stbir__info *info, float s0, float t0, float s1, float t1, float *transform)
   2216 {
   2217     info->s0 = s0;
   2218     info->t0 = t0;
   2219     info->s1 = s1;
   2220     info->t1 = t1;
   2221 
   2222     if (transform)
   2223     {
   2224         info->horizontal_scale = transform[0];
   2225         info->vertical_scale   = transform[1];
   2226         info->horizontal_shift = transform[2];
   2227         info->vertical_shift   = transform[3];
   2228     }
   2229     else
   2230     {
   2231         info->horizontal_scale = ((float)info->output_w / info->input_w) / (s1 - s0);
   2232         info->vertical_scale = ((float)info->output_h / info->input_h) / (t1 - t0);
   2233 
   2234         info->horizontal_shift = s0 * info->output_w / (s1 - s0);
   2235         info->vertical_shift = t0 * info->output_h / (t1 - t0);
   2236     }
   2237 }
   2238 
   2239 static void stbir__choose_filter(stbir__info *info, stbir_filter h_filter, stbir_filter v_filter)
   2240 {
   2241     if (h_filter == 0)
   2242         h_filter = stbir__use_upsampling(info->horizontal_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE;
   2243     if (v_filter == 0)
   2244         v_filter = stbir__use_upsampling(info->vertical_scale)   ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE;
   2245     info->horizontal_filter = h_filter;
   2246     info->vertical_filter = v_filter;
   2247 }
   2248 
   2249 static stbir_uint32 stbir__calculate_memory(stbir__info *info)
   2250 {
   2251     int pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale);
   2252     int filter_height = stbir__get_filter_pixel_width(info->vertical_filter, info->vertical_scale);
   2253 
   2254     info->horizontal_num_contributors = stbir__get_contributors(info->horizontal_scale, info->horizontal_filter, info->input_w, info->output_w);
   2255     info->vertical_num_contributors   = stbir__get_contributors(info->vertical_scale  , info->vertical_filter  , info->input_h, info->output_h);
   2256 
   2257     // One extra entry because floating point precision problems sometimes cause an extra to be necessary.
   2258     info->ring_buffer_num_entries = filter_height + 1;
   2259 
   2260     info->horizontal_contributors_size = info->horizontal_num_contributors * sizeof(stbir__contributors);
   2261     info->horizontal_coefficients_size = stbir__get_total_horizontal_coefficients(info) * sizeof(float);
   2262     info->vertical_contributors_size = info->vertical_num_contributors * sizeof(stbir__contributors);
   2263     info->vertical_coefficients_size = stbir__get_total_vertical_coefficients(info) * sizeof(float);
   2264     info->decode_buffer_size = (info->input_w + pixel_margin * 2) * info->channels * sizeof(float);
   2265     info->horizontal_buffer_size = info->output_w * info->channels * sizeof(float);
   2266     info->ring_buffer_size = info->output_w * info->channels * info->ring_buffer_num_entries * sizeof(float);
   2267     info->encode_buffer_size = info->output_w * info->channels * sizeof(float);
   2268 
   2269     STBIR_ASSERT(info->horizontal_filter != 0);
   2270     STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); // this now happens too late
   2271     STBIR_ASSERT(info->vertical_filter != 0);
   2272     STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); // this now happens too late
   2273 
   2274     if (stbir__use_height_upsampling(info))
   2275         // The horizontal buffer is for when we're downsampling the height and we
   2276         // can't output the result of sampling the decode buffer directly into the
   2277         // ring buffers.
   2278         info->horizontal_buffer_size = 0;
   2279     else
   2280         // The encode buffer is to retain precision in the height upsampling method
   2281         // and isn't used when height downsampling.
   2282         info->encode_buffer_size = 0;
   2283 
   2284     return info->horizontal_contributors_size + info->horizontal_coefficients_size
   2285         + info->vertical_contributors_size + info->vertical_coefficients_size
   2286         + info->decode_buffer_size + info->horizontal_buffer_size
   2287         + info->ring_buffer_size + info->encode_buffer_size;
   2288 }
   2289 
   2290 static int stbir__resize_allocated(stbir__info *info,
   2291     const void* input_data, int input_stride_in_bytes,
   2292     void* output_data, int output_stride_in_bytes,
   2293     int alpha_channel, stbir_uint32 flags, stbir_datatype type,
   2294     stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace,
   2295     void* tempmem, size_t tempmem_size_in_bytes)
   2296 {
   2297     size_t memory_required = stbir__calculate_memory(info);
   2298 
   2299     int width_stride_input = input_stride_in_bytes ? input_stride_in_bytes : info->channels * info->input_w * stbir__type_size[type];
   2300     int width_stride_output = output_stride_in_bytes ? output_stride_in_bytes : info->channels * info->output_w * stbir__type_size[type];
   2301 
   2302 #ifdef STBIR_DEBUG_OVERWRITE_TEST
   2303 #define OVERWRITE_ARRAY_SIZE 8
   2304     unsigned char overwrite_output_before_pre[OVERWRITE_ARRAY_SIZE];
   2305     unsigned char overwrite_tempmem_before_pre[OVERWRITE_ARRAY_SIZE];
   2306     unsigned char overwrite_output_after_pre[OVERWRITE_ARRAY_SIZE];
   2307     unsigned char overwrite_tempmem_after_pre[OVERWRITE_ARRAY_SIZE];
   2308 
   2309     size_t begin_forbidden = width_stride_output * (info->output_h - 1) + info->output_w * info->channels * stbir__type_size[type];
   2310     memcpy(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE);
   2311     memcpy(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE);
   2312     memcpy(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE);
   2313     memcpy(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE);
   2314 #endif
   2315 
   2316     STBIR_ASSERT(info->channels >= 0);
   2317     STBIR_ASSERT(info->channels <= STBIR_MAX_CHANNELS);
   2318 
   2319     if (info->channels < 0 || info->channels > STBIR_MAX_CHANNELS)
   2320         return 0;
   2321 
   2322     STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
   2323     STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
   2324 
   2325     if (info->horizontal_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table))
   2326         return 0;
   2327     if (info->vertical_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table))
   2328         return 0;
   2329 
   2330     if (alpha_channel < 0)
   2331         flags |= STBIR_FLAG_ALPHA_USES_COLORSPACE | STBIR_FLAG_ALPHA_PREMULTIPLIED;
   2332 
   2333     if (!(flags&STBIR_FLAG_ALPHA_USES_COLORSPACE) || !(flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)) {
   2334         STBIR_ASSERT(alpha_channel >= 0 && alpha_channel < info->channels);
   2335     }
   2336 
   2337     if (alpha_channel >= info->channels)
   2338         return 0;
   2339 
   2340     STBIR_ASSERT(tempmem);
   2341 
   2342     if (!tempmem)
   2343         return 0;
   2344 
   2345     STBIR_ASSERT(tempmem_size_in_bytes >= memory_required);
   2346 
   2347     if (tempmem_size_in_bytes < memory_required)
   2348         return 0;
   2349 
   2350     memset(tempmem, 0, tempmem_size_in_bytes);
   2351 
   2352     info->input_data = input_data;
   2353     info->input_stride_bytes = width_stride_input;
   2354 
   2355     info->output_data = output_data;
   2356     info->output_stride_bytes = width_stride_output;
   2357 
   2358     info->alpha_channel = alpha_channel;
   2359     info->flags = flags;
   2360     info->type = type;
   2361     info->edge_horizontal = edge_horizontal;
   2362     info->edge_vertical = edge_vertical;
   2363     info->colorspace = colorspace;
   2364 
   2365     info->horizontal_coefficient_width   = stbir__get_coefficient_width  (info->horizontal_filter, info->horizontal_scale);
   2366     info->vertical_coefficient_width     = stbir__get_coefficient_width  (info->vertical_filter  , info->vertical_scale  );
   2367     info->horizontal_filter_pixel_width  = stbir__get_filter_pixel_width (info->horizontal_filter, info->horizontal_scale);
   2368     info->vertical_filter_pixel_width    = stbir__get_filter_pixel_width (info->vertical_filter  , info->vertical_scale  );
   2369     info->horizontal_filter_pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale);
   2370     info->vertical_filter_pixel_margin   = stbir__get_filter_pixel_margin(info->vertical_filter  , info->vertical_scale  );
   2371 
   2372     info->ring_buffer_length_bytes = info->output_w * info->channels * sizeof(float);
   2373     info->decode_buffer_pixels = info->input_w + info->horizontal_filter_pixel_margin * 2;
   2374 
   2375 #define STBIR__NEXT_MEMPTR(current, newtype) (newtype*)(((unsigned char*)current) + current##_size)
   2376 
   2377     info->horizontal_contributors = (stbir__contributors *) tempmem;
   2378     info->horizontal_coefficients = STBIR__NEXT_MEMPTR(info->horizontal_contributors, float);
   2379     info->vertical_contributors = STBIR__NEXT_MEMPTR(info->horizontal_coefficients, stbir__contributors);
   2380     info->vertical_coefficients = STBIR__NEXT_MEMPTR(info->vertical_contributors, float);
   2381     info->decode_buffer = STBIR__NEXT_MEMPTR(info->vertical_coefficients, float);
   2382 
   2383     if (stbir__use_height_upsampling(info))
   2384     {
   2385         info->horizontal_buffer = NULL;
   2386         info->ring_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float);
   2387         info->encode_buffer = STBIR__NEXT_MEMPTR(info->ring_buffer, float);
   2388 
   2389         STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->encode_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes);
   2390     }
   2391     else
   2392     {
   2393         info->horizontal_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float);
   2394         info->ring_buffer = STBIR__NEXT_MEMPTR(info->horizontal_buffer, float);
   2395         info->encode_buffer = NULL;
   2396 
   2397         STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->ring_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes);
   2398     }
   2399 
   2400 #undef STBIR__NEXT_MEMPTR
   2401 
   2402     // This signals that the ring buffer is empty
   2403     info->ring_buffer_begin_index = -1;
   2404 
   2405     stbir__calculate_filters(info->horizontal_contributors, info->horizontal_coefficients, info->horizontal_filter, info->horizontal_scale, info->horizontal_shift, info->input_w, info->output_w);
   2406     stbir__calculate_filters(info->vertical_contributors, info->vertical_coefficients, info->vertical_filter, info->vertical_scale, info->vertical_shift, info->input_h, info->output_h);
   2407 
   2408     STBIR_PROGRESS_REPORT(0);
   2409 
   2410     if (stbir__use_height_upsampling(info))
   2411         stbir__buffer_loop_upsample(info);
   2412     else
   2413         stbir__buffer_loop_downsample(info);
   2414 
   2415     STBIR_PROGRESS_REPORT(1);
   2416 
   2417 #ifdef STBIR_DEBUG_OVERWRITE_TEST
   2418     STBIR_ASSERT(memcmp(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0);
   2419     STBIR_ASSERT(memcmp(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE) == 0);
   2420     STBIR_ASSERT(memcmp(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0);
   2421     STBIR_ASSERT(memcmp(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE) == 0);
   2422 #endif
   2423 
   2424     return 1;
   2425 }
   2426 
   2427 
   2428 static int stbir__resize_arbitrary(
   2429     void *alloc_context,
   2430     const void* input_data, int input_w, int input_h, int input_stride_in_bytes,
   2431     void* output_data, int output_w, int output_h, int output_stride_in_bytes,
   2432     float s0, float t0, float s1, float t1, float *transform,
   2433     int channels, int alpha_channel, stbir_uint32 flags, stbir_datatype type,
   2434     stbir_filter h_filter, stbir_filter v_filter,
   2435     stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace)
   2436 {
   2437     stbir__info info;
   2438     int result;
   2439     size_t memory_required;
   2440     void* extra_memory;
   2441 
   2442     stbir__setup(&info, input_w, input_h, output_w, output_h, channels);
   2443     stbir__calculate_transform(&info, s0,t0,s1,t1,transform);
   2444     stbir__choose_filter(&info, h_filter, v_filter);
   2445     memory_required = stbir__calculate_memory(&info);
   2446     extra_memory = STBIR_MALLOC(memory_required, alloc_context);
   2447 
   2448     if (!extra_memory)
   2449         return 0;
   2450 
   2451     result = stbir__resize_allocated(&info, input_data, input_stride_in_bytes,
   2452                                             output_data, output_stride_in_bytes,
   2453                                             alpha_channel, flags, type,
   2454                                             edge_horizontal, edge_vertical,
   2455                                             colorspace, extra_memory, memory_required);
   2456 
   2457     STBIR_FREE(extra_memory, alloc_context);
   2458 
   2459     return result;
   2460 }
   2461 
   2462 STBIRDEF int stbir_resize_uint8(     const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
   2463                                            unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
   2464                                      int num_channels)
   2465 {
   2466     return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
   2467         output_pixels, output_w, output_h, output_stride_in_bytes,
   2468         0,0,1,1,NULL,num_channels,-1,0, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
   2469         STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR);
   2470 }
   2471 
   2472 STBIRDEF int stbir_resize_float(     const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
   2473                                            float *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
   2474                                      int num_channels)
   2475 {
   2476     return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
   2477         output_pixels, output_w, output_h, output_stride_in_bytes,
   2478         0,0,1,1,NULL,num_channels,-1,0, STBIR_TYPE_FLOAT, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
   2479         STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR);
   2480 }
   2481 
   2482 STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
   2483                                            unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
   2484                                      int num_channels, int alpha_channel, int flags)
   2485 {
   2486     return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
   2487         output_pixels, output_w, output_h, output_stride_in_bytes,
   2488         0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
   2489         STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB);
   2490 }
   2491 
   2492 STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
   2493                                                     unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
   2494                                               int num_channels, int alpha_channel, int flags,
   2495                                               stbir_edge edge_wrap_mode)
   2496 {
   2497     return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
   2498         output_pixels, output_w, output_h, output_stride_in_bytes,
   2499         0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
   2500         edge_wrap_mode, edge_wrap_mode, STBIR_COLORSPACE_SRGB);
   2501 }
   2502 
   2503 STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
   2504                                                unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
   2505                                          int num_channels, int alpha_channel, int flags,
   2506                                          stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
   2507                                          void *alloc_context)
   2508 {
   2509     return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
   2510         output_pixels, output_w, output_h, output_stride_in_bytes,
   2511         0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, filter, filter,
   2512         edge_wrap_mode, edge_wrap_mode, space);
   2513 }
   2514 
   2515 STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels  , int input_w , int input_h , int input_stride_in_bytes,
   2516                                                stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
   2517                                          int num_channels, int alpha_channel, int flags,
   2518                                          stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
   2519                                          void *alloc_context)
   2520 {
   2521     return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
   2522         output_pixels, output_w, output_h, output_stride_in_bytes,
   2523         0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT16, filter, filter,
   2524         edge_wrap_mode, edge_wrap_mode, space);
   2525 }
   2526 
   2527 
   2528 STBIRDEF int stbir_resize_float_generic( const float *input_pixels         , int input_w , int input_h , int input_stride_in_bytes,
   2529                                                float *output_pixels        , int output_w, int output_h, int output_stride_in_bytes,
   2530                                          int num_channels, int alpha_channel, int flags,
   2531                                          stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
   2532                                          void *alloc_context)
   2533 {
   2534     return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
   2535         output_pixels, output_w, output_h, output_stride_in_bytes,
   2536         0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_FLOAT, filter, filter,
   2537         edge_wrap_mode, edge_wrap_mode, space);
   2538 }
   2539 
   2540 
   2541 STBIRDEF int stbir_resize(         const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
   2542                                          void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
   2543                                    stbir_datatype datatype,
   2544                                    int num_channels, int alpha_channel, int flags,
   2545                                    stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
   2546                                    stbir_filter filter_horizontal,  stbir_filter filter_vertical,
   2547                                    stbir_colorspace space, void *alloc_context)
   2548 {
   2549     return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
   2550         output_pixels, output_w, output_h, output_stride_in_bytes,
   2551         0,0,1,1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
   2552         edge_mode_horizontal, edge_mode_vertical, space);
   2553 }
   2554 
   2555 
   2556 STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
   2557                                          void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
   2558                                    stbir_datatype datatype,
   2559                                    int num_channels, int alpha_channel, int flags,
   2560                                    stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
   2561                                    stbir_filter filter_horizontal,  stbir_filter filter_vertical,
   2562                                    stbir_colorspace space, void *alloc_context,
   2563                                    float x_scale, float y_scale,
   2564                                    float x_offset, float y_offset)
   2565 {
   2566     float transform[4];
   2567     transform[0] = x_scale;
   2568     transform[1] = y_scale;
   2569     transform[2] = x_offset;
   2570     transform[3] = y_offset;
   2571     return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
   2572         output_pixels, output_w, output_h, output_stride_in_bytes,
   2573         0,0,1,1,transform,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
   2574         edge_mode_horizontal, edge_mode_vertical, space);
   2575 }
   2576 
   2577 STBIRDEF int stbir_resize_region(  const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
   2578                                          void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
   2579                                    stbir_datatype datatype,
   2580                                    int num_channels, int alpha_channel, int flags,
   2581                                    stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
   2582                                    stbir_filter filter_horizontal,  stbir_filter filter_vertical,
   2583                                    stbir_colorspace space, void *alloc_context,
   2584                                    float s0, float t0, float s1, float t1)
   2585 {
   2586     return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
   2587         output_pixels, output_w, output_h, output_stride_in_bytes,
   2588         s0,t0,s1,t1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
   2589         edge_mode_horizontal, edge_mode_vertical, space);
   2590 }
   2591 
   2592 #endif // STB_IMAGE_RESIZE_IMPLEMENTATION
   2593 
   2594 /*
   2595 ------------------------------------------------------------------------------
   2596 This software is available under 2 licenses -- choose whichever you prefer.
   2597 ------------------------------------------------------------------------------
   2598 ALTERNATIVE A - MIT License
   2599 Copyright (c) 2017 Sean Barrett
   2600 Permission is hereby granted, free of charge, to any person obtaining a copy of
   2601 this software and associated documentation files (the "Software"), to deal in
   2602 the Software without restriction, including without limitation the rights to
   2603 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
   2604 of the Software, and to permit persons to whom the Software is furnished to do
   2605 so, subject to the following conditions:
   2606 The above copyright notice and this permission notice shall be included in all
   2607 copies or substantial portions of the Software.
   2608 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   2609 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   2610 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   2611 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   2612 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   2613 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   2614 SOFTWARE.
   2615 ------------------------------------------------------------------------------
   2616 ALTERNATIVE B - Public Domain (www.unlicense.org)
   2617 This is free and unencumbered software released into the public domain.
   2618 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
   2619 software, either in source code form or as a compiled binary, for any purpose,
   2620 commercial or non-commercial, and by any means.
   2621 In jurisdictions that recognize copyright laws, the author or authors of this
   2622 software dedicate any and all copyright interest in the software to the public
   2623 domain. We make this dedication for the benefit of the public at large and to
   2624 the detriment of our heirs and successors. We intend this dedication to be an
   2625 overt act of relinquishment in perpetuity of all present and future rights to
   2626 this software under copyright law.
   2627 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   2628 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   2629 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   2630 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
   2631 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
   2632 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   2633 ------------------------------------------------------------------------------
   2634 */