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