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