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