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