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