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