bgdraw

X11 background animator
git clone https://git.sinitax.com/sinitax/bgdraw
Log | Files | Refs | LICENSE | sfeed.txt

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
    188typedef unsigned char  stbir_uint8;
    189typedef unsigned short stbir_uint16;
    190typedef unsigned int   stbir_uint32;
    191#else
    192#include <stdint.h>
    193typedef uint8_t  stbir_uint8;
    194typedef uint16_t stbir_uint16;
    195typedef 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
    228STBIRDEF 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
    232STBIRDEF 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
    253STBIRDEF 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
    258typedef 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.
    267STBIRDEF 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
    287typedef 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
    297typedef 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
    307STBIRDEF 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
    313STBIRDEF 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
    319STBIRDEF 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
    340typedef 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
    350STBIRDEF 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
    358STBIRDEF 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
    368STBIRDEF 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
    418typedef 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
    467static 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
    475typedef float (stbir__kernel_fn)(float x, float scale);
    476typedef float (stbir__support_fn)(float scale);
    477
    478typedef 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.
    486typedef struct
    487{
    488    int n0; // First contributing pixel
    489    int n1; // Last contributing pixel
    490} stbir__contributors;
    491
    492typedef 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
    562static const float stbir__max_uint8_as_float  = 255.0f;
    563static const float stbir__max_uint16_as_float = 65535.0f;
    564static const double stbir__max_uint32_as_float = 4294967295.0;
    565
    566
    567static stbir__inline int stbir__min(int a, int b)
    568{
    569    return a < b ? a : b;
    570}
    571
    572static 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
    584static 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
    595static 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
    607static 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
    634static 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
    642static 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
    653typedef union
    654{
    655    stbir_uint32 u;
    656    float f;
    657} stbir__FP32;
    658
    659static 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
    675static 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
    703static 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
    739static 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
    759static 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
    779static float stbir__support_trapezoid(float scale)
    780{
    781    STBIR_ASSERT(scale <= 1);
    782    return 0.5f + scale / 2;
    783}
    784
    785static 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
    797static 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
    811static 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
    825static 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
    839static float stbir__support_zero(float s)
    840{
    841    STBIR__UNUSED_PARAM(s);
    842    return 0;
    843}
    844
    845static float stbir__support_one(float s)
    846{
    847    STBIR__UNUSED_PARAM(s);
    848    return 1;
    849}
    850
    851static float stbir__support_two(float s)
    852{
    853    STBIR__UNUSED_PARAM(s);
    854    return 2;
    855}
    856
    857static 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
    866stbir__inline static int stbir__use_upsampling(float ratio)
    867{
    868    return ratio > 1;
    869}
    870
    871stbir__inline static int stbir__use_width_upsampling(stbir__info* stbir_info)
    872{
    873    return stbir__use_upsampling(stbir_info->horizontal_scale);
    874}
    875
    876stbir__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
    883static 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.
    896static int stbir__get_filter_pixel_margin(stbir_filter filter, float scale)
    897{
    898    return stbir__get_filter_pixel_width(filter, scale) / 2;
    899}
    900
    901static 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
    909static 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
    917static 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
    923static 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
    929static 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.
    936static 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
    942static 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
   1000stbir__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?
   1009static 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?
   1024static 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
   1038static 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
   1092static 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
   1126static 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.
   1203static 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
   1243static 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
   1252static 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
   1420static 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
   1425static 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
   1450static 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
   1533static 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
   1658static 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
   1672static 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.
   1689static 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
   1696static 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
   1870static 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
   1987static 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
   2067static 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
   2120static 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
   2165static 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
   2206static 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
   2215static 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
   2239static 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
   2249static 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
   2290static 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
   2428static 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
   2462STBIRDEF 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
   2472STBIRDEF 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
   2482STBIRDEF 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
   2492STBIRDEF 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
   2503STBIRDEF 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
   2515STBIRDEF 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
   2528STBIRDEF 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
   2541STBIRDEF 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
   2556STBIRDEF 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
   2577STBIRDEF 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------------------------------------------------------------------------------
   2596This software is available under 2 licenses -- choose whichever you prefer.
   2597------------------------------------------------------------------------------
   2598ALTERNATIVE A - MIT License
   2599Copyright (c) 2017 Sean Barrett
   2600Permission is hereby granted, free of charge, to any person obtaining a copy of
   2601this software and associated documentation files (the "Software"), to deal in
   2602the Software without restriction, including without limitation the rights to
   2603use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
   2604of the Software, and to permit persons to whom the Software is furnished to do
   2605so, subject to the following conditions:
   2606The above copyright notice and this permission notice shall be included in all
   2607copies or substantial portions of the Software.
   2608THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   2609IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   2610FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   2611AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   2612LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   2613OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   2614SOFTWARE.
   2615------------------------------------------------------------------------------
   2616ALTERNATIVE B - Public Domain (www.unlicense.org)
   2617This is free and unencumbered software released into the public domain.
   2618Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
   2619software, either in source code form or as a compiled binary, for any purpose,
   2620commercial or non-commercial, and by any means.
   2621In jurisdictions that recognize copyright laws, the author or authors of this
   2622software dedicate any and all copyright interest in the software to the public
   2623domain. We make this dedication for the benefit of the public at large and to
   2624the detriment of our heirs and successors. We intend this dedication to be an
   2625overt act of relinquishment in perpetuity of all present and future rights to
   2626this software under copyright law.
   2627THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   2628IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   2629FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   2630AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
   2631ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
   2632WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   2633------------------------------------------------------------------------------
   2634*/