blob: 858cc87fc8b02a578134039ad77ad05a7a5902ed [file] [log] [blame]
Sadik Armagan93e2e402019-05-02 09:31:38 +01001/* stb_image_resize - v0.95 - public domain image resizing
2 by Jorge L Rodriguez (@VinoBS) - 2014
3 http://github.com/nothings/stb
4
5 Written with emphasis on usability, portability, and efficiency. (No
6 SIMD or threads, so it be easily outperformed by libs that use those.)
7 Only scaling and translation is supported, no rotations or shears.
8 Easy API downsamples w/Mitchell filter, upsamples w/cubic interpolation.
9
10 COMPILING & LINKING
11 In one C/C++ file that #includes this file, do this:
12 #define STB_IMAGE_RESIZE_IMPLEMENTATION
13 before the #include. That will create the implementation in that file.
14
15 QUICKSTART
16 stbir_resize_uint8( input_pixels , in_w , in_h , 0,
17 output_pixels, out_w, out_h, 0, num_channels)
18 stbir_resize_float(...)
19 stbir_resize_uint8_srgb( input_pixels , in_w , in_h , 0,
20 output_pixels, out_w, out_h, 0,
21 num_channels , alpha_chan , 0)
22 stbir_resize_uint8_srgb_edgemode(
23 input_pixels , in_w , in_h , 0,
24 output_pixels, out_w, out_h, 0,
25 num_channels , alpha_chan , 0, STBIR_EDGE_CLAMP)
26 // WRAP/REFLECT/ZERO
27
28 FULL API
29 See the "header file" section of the source for API documentation.
30
31 ADDITIONAL DOCUMENTATION
32
33 SRGB & FLOATING POINT REPRESENTATION
34 The sRGB functions presume IEEE floating point. If you do not have
35 IEEE floating point, define STBIR_NON_IEEE_FLOAT. This will use
36 a slower implementation.
37
38 MEMORY ALLOCATION
39 The resize functions here perform a single memory allocation using
40 malloc. To control the memory allocation, before the #include that
41 triggers the implementation, do:
42
43 #define STBIR_MALLOC(size,context) ...
44 #define STBIR_FREE(ptr,context) ...
45
46 Each resize function makes exactly one call to malloc/free, so to use
47 temp memory, store the temp memory in the context and return that.
48
49 ASSERT
50 Define STBIR_ASSERT(boolval) to override assert() and not use assert.h
51
52 OPTIMIZATION
53 Define STBIR_SATURATE_INT to compute clamp values in-range using
54 integer operations instead of float operations. This may be faster
55 on some platforms.
56
57 DEFAULT FILTERS
58 For functions which don't provide explicit control over what filters
59 to use, you can change the compile-time defaults with
60
61 #define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_something
62 #define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_something
63
64 See stbir_filter in the header-file section for the list of filters.
65
66 NEW FILTERS
67 A number of 1D filter kernels are used. For a list of
68 supported filters see the stbir_filter enum. To add a new filter,
69 write a filter function and add it to stbir__filter_info_table.
70
71 PROGRESS
72 For interactive use with slow resize operations, you can install
73 a progress-report callback:
74
75 #define STBIR_PROGRESS_REPORT(val) some_func(val)
76
77 The parameter val is a float which goes from 0 to 1 as progress is made.
78
79 For example:
80
81 static void my_progress_report(float progress);
82 #define STBIR_PROGRESS_REPORT(val) my_progress_report(val)
83
84 #define STB_IMAGE_RESIZE_IMPLEMENTATION
85 #include "stb_image_resize.h"
86
87 static void my_progress_report(float progress)
88 {
89 printf("Progress: %f%%\n", progress*100);
90 }
91
92 MAX CHANNELS
93 If your image has more than 64 channels, define STBIR_MAX_CHANNELS
94 to the max you'll have.
95
96 ALPHA CHANNEL
97 Most of the resizing functions provide the ability to control how
98 the alpha channel of an image is processed. The important things
99 to know about this:
100
101 1. The best mathematically-behaved version of alpha to use is
102 called "premultiplied alpha", in which the other color channels
103 have had the alpha value multiplied in. If you use premultiplied
104 alpha, linear filtering (such as image resampling done by this
105 library, or performed in texture units on GPUs) does the "right
106 thing". While premultiplied alpha is standard in the movie CGI
107 industry, it is still uncommon in the videogame/real-time world.
108
109 If you linearly filter non-premultiplied alpha, strange effects
110 occur. (For example, the 50/50 average of 99% transparent bright green
111 and 1% transparent black produces 50% transparent dark green when
112 non-premultiplied, whereas premultiplied it produces 50%
113 transparent near-black. The former introduces green energy
114 that doesn't exist in the source image.)
115
116 2. Artists should not edit premultiplied-alpha images; artists
117 want non-premultiplied alpha images. Thus, art tools generally output
118 non-premultiplied alpha images.
119
120 3. You will get best results in most cases by converting images
121 to premultiplied alpha before processing them mathematically.
122
123 4. If you pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED, the
124 resizer does not do anything special for the alpha channel;
125 it is resampled identically to other channels. This produces
126 the correct results for premultiplied-alpha images, but produces
127 less-than-ideal results for non-premultiplied-alpha images.
128
129 5. If you do not pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED,
130 then the resizer weights the contribution of input pixels
131 based on their alpha values, or, equivalently, it multiplies
132 the alpha value into the color channels, resamples, then divides
133 by the resultant alpha value. Input pixels which have alpha=0 do
134 not contribute at all to output pixels unless _all_ of the input
135 pixels affecting that output pixel have alpha=0, in which case
136 the result for that pixel is the same as it would be without
137 STBIR_FLAG_ALPHA_PREMULTIPLIED. However, this is only true for
138 input images in integer formats. For input images in float format,
139 input pixels with alpha=0 have no effect, and output pixels
140 which have alpha=0 will be 0 in all channels. (For float images,
141 you can manually achieve the same result by adding a tiny epsilon
142 value to the alpha channel of every image, and then subtracting
143 or clamping it at the end.)
144
145 6. You can suppress the behavior described in #5 and make
146 all-0-alpha pixels have 0 in all channels by #defining
147 STBIR_NO_ALPHA_EPSILON.
148
149 7. You can separately control whether the alpha channel is
150 interpreted as linear or affected by the colorspace. By default
151 it is linear; you almost never want to apply the colorspace.
152 (For example, graphics hardware does not apply sRGB conversion
153 to the alpha channel.)
154
155 CONTRIBUTORS
156 Jorge L Rodriguez: Implementation
157 Sean Barrett: API design, optimizations
158 Aras Pranckevicius: bugfix
159 Nathan Reed: warning fixes
160
161 REVISIONS
162 0.95 (2017-07-23) fixed warnings
163 0.94 (2017-03-18) fixed warnings
164 0.93 (2017-03-03) fixed bug with certain combinations of heights
165 0.92 (2017-01-02) fix integer overflow on large (>2GB) images
166 0.91 (2016-04-02) fix warnings; fix handling of subpixel regions
167 0.90 (2014-09-17) first released version
168
169 LICENSE
170 See end of file for license information.
171
172 TODO
173 Don't decode all of the image data when only processing a partial tile
174 Don't use full-width decode buffers when only processing a partial tile
175 When processing wide images, break processing into tiles so data fits in L1 cache
176 Installable filters?
177 Resize that respects alpha test coverage
178 (Reference code: FloatImage::alphaTestCoverage and FloatImage::scaleAlphaToCoverage:
179 https://code.google.com/p/nvidia-texture-tools/source/browse/trunk/src/nvimage/FloatImage.cpp )
180*/
181
182#ifndef STBIR_INCLUDE_STB_IMAGE_RESIZE_H
183#define STBIR_INCLUDE_STB_IMAGE_RESIZE_H
184
185#ifdef _MSC_VER
186typedef unsigned char stbir_uint8;
187typedef unsigned short stbir_uint16;
188typedef unsigned int stbir_uint32;
189#else
190#include <stdint.h>
191typedef uint8_t stbir_uint8;
192typedef uint16_t stbir_uint16;
193typedef uint32_t stbir_uint32;
194#endif
195
196#ifdef STB_IMAGE_RESIZE_STATIC
197#define STBIRDEF static
198#else
199#ifdef __cplusplus
200#define STBIRDEF extern "C"
201#else
202#define STBIRDEF extern
203#endif
204#endif
205
206
207//////////////////////////////////////////////////////////////////////////////
208//
209// Easy-to-use API:
210//
211// * "input pixels" points to an array of image data with 'num_channels' channels (e.g. RGB=3, RGBA=4)
212// * input_w is input image width (x-axis), input_h is input image height (y-axis)
213// * stride is the offset between successive rows of image data in memory, in bytes. you can
214// specify 0 to mean packed continuously in memory
215// * alpha channel is treated identically to other channels.
216// * colorspace is linear or sRGB as specified by function name
217// * returned result is 1 for success or 0 in case of an error.
218// #define STBIR_ASSERT() to trigger an assert on parameter validation errors.
219// * Memory required grows approximately linearly with input and output size, but with
220// discontinuities at input_w == output_w and input_h == output_h.
221// * These functions use a "default" resampling filter defined at compile time. To change the filter,
222// you can change the compile-time defaults by #defining STBIR_DEFAULT_FILTER_UPSAMPLE
223// and STBIR_DEFAULT_FILTER_DOWNSAMPLE, or you can use the medium-complexity API.
224
225STBIRDEF int stbir_resize_uint8( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
226 unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
227 int num_channels);
228
229STBIRDEF int stbir_resize_float( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
230 float *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
231 int num_channels);
232
233
234// The following functions interpret image data as gamma-corrected sRGB.
235// Specify STBIR_ALPHA_CHANNEL_NONE if you have no alpha channel,
236// or otherwise provide the index of the alpha channel. Flags value
237// of 0 will probably do the right thing if you're not sure what
238// the flags mean.
239
240#define STBIR_ALPHA_CHANNEL_NONE -1
241
242// Set this flag if your texture has premultiplied alpha. Otherwise, stbir will
243// use alpha-weighted resampling (effectively premultiplying, resampling,
244// then unpremultiplying).
245#define STBIR_FLAG_ALPHA_PREMULTIPLIED (1 << 0)
246// The specified alpha channel should be handled as gamma-corrected value even
247// when doing sRGB operations.
248#define STBIR_FLAG_ALPHA_USES_COLORSPACE (1 << 1)
249
250STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
251 unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
252 int num_channels, int alpha_channel, int flags);
253
254
255typedef enum
256{
257 STBIR_EDGE_CLAMP = 1,
258 STBIR_EDGE_REFLECT = 2,
259 STBIR_EDGE_WRAP = 3,
260 STBIR_EDGE_ZERO = 4,
261} stbir_edge;
262
263// This function adds the ability to specify how requests to sample off the edge of the image are handled.
264STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
265 unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
266 int num_channels, int alpha_channel, int flags,
267 stbir_edge edge_wrap_mode);
268
269//////////////////////////////////////////////////////////////////////////////
270//
271// Medium-complexity API
272//
273// This extends the easy-to-use API as follows:
274//
275// * Alpha-channel can be processed separately
276// * If alpha_channel is not STBIR_ALPHA_CHANNEL_NONE
277// * Alpha channel will not be gamma corrected (unless flags&STBIR_FLAG_GAMMA_CORRECT)
278// * Filters will be weighted by alpha channel (unless flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)
279// * Filter can be selected explicitly
280// * uint16 image type
281// * sRGB colorspace available for all types
282// * context parameter for passing to STBIR_MALLOC
283
284typedef enum
285{
286 STBIR_FILTER_DEFAULT = 0, // use same filter type that easy-to-use API chooses
287 STBIR_FILTER_BOX = 1, // A trapezoid w/1-pixel wide ramps, same result as box for integer scale ratios
288 STBIR_FILTER_TRIANGLE = 2, // On upsampling, produces same results as bilinear texture filtering
289 STBIR_FILTER_CUBICBSPLINE = 3, // The cubic b-spline (aka Mitchell-Netrevalli with B=1,C=0), gaussian-esque
290 STBIR_FILTER_CATMULLROM = 4, // An interpolating cubic spline
291 STBIR_FILTER_MITCHELL = 5, // Mitchell-Netrevalli filter with B=1/3, C=1/3
292} stbir_filter;
293
294typedef enum
295{
296 STBIR_COLORSPACE_LINEAR,
297 STBIR_COLORSPACE_SRGB,
298
299 STBIR_MAX_COLORSPACES,
300} stbir_colorspace;
301
302// The following functions are all identical except for the type of the image data
303
304STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
305 unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
306 int num_channels, int alpha_channel, int flags,
307 stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
308 void *alloc_context);
309
310STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
311 stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
312 int num_channels, int alpha_channel, int flags,
313 stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
314 void *alloc_context);
315
316STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
317 float *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
318 int num_channels, int alpha_channel, int flags,
319 stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
320 void *alloc_context);
321
322
323
324//////////////////////////////////////////////////////////////////////////////
325//
326// Full-complexity API
327//
328// This extends the medium API as follows:
329//
330// * uint32 image type
331// * not typesafe
332// * separate filter types for each axis
333// * separate edge modes for each axis
334// * can specify scale explicitly for subpixel correctness
335// * can specify image source tile using texture coordinates
336
337typedef enum
338{
339 STBIR_TYPE_UINT8 ,
340 STBIR_TYPE_UINT16,
341 STBIR_TYPE_UINT32,
342 STBIR_TYPE_FLOAT ,
343
344 STBIR_MAX_TYPES
345} stbir_datatype;
346
347STBIRDEF int stbir_resize( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
348 void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
349 stbir_datatype datatype,
350 int num_channels, int alpha_channel, int flags,
351 stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
352 stbir_filter filter_horizontal, stbir_filter filter_vertical,
353 stbir_colorspace space, void *alloc_context);
354
355STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
356 void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
357 stbir_datatype datatype,
358 int num_channels, int alpha_channel, int flags,
359 stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
360 stbir_filter filter_horizontal, stbir_filter filter_vertical,
361 stbir_colorspace space, void *alloc_context,
362 float x_scale, float y_scale,
363 float x_offset, float y_offset);
364
365STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
366 void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
367 stbir_datatype datatype,
368 int num_channels, int alpha_channel, int flags,
369 stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
370 stbir_filter filter_horizontal, stbir_filter filter_vertical,
371 stbir_colorspace space, void *alloc_context,
372 float s0, float t0, float s1, float t1);
373// (s0, t0) & (s1, t1) are the top-left and bottom right corner (uv addressing style: [0, 1]x[0, 1]) of a region of the input image to use.
374
375//
376//
377//// end header file /////////////////////////////////////////////////////
378#endif // STBIR_INCLUDE_STB_IMAGE_RESIZE_H
379
380
381
382
383
384#ifdef STB_IMAGE_RESIZE_IMPLEMENTATION
385
386#ifndef STBIR_ASSERT
387#include <assert.h>
388#define STBIR_ASSERT(x) assert(x)
389#endif
390
391// For memset
392#include <string.h>
393
394#include <math.h>
395
396#ifndef STBIR_MALLOC
397#include <stdlib.h>
398// use comma operator to evaluate c, to avoid "unused parameter" warnings
399#define STBIR_MALLOC(size,c) ((void)(c), malloc(size))
400#define STBIR_FREE(ptr,c) ((void)(c), free(ptr))
401#endif
402
403#ifndef _MSC_VER
404#ifdef __cplusplus
405#define stbir__inline inline
406#else
407#define stbir__inline
408#endif
409#else
410#define stbir__inline __forceinline
411#endif
412
413
414// should produce compiler error if size is wrong
415typedef unsigned char stbir__validate_uint32[sizeof(stbir_uint32) == 4 ? 1 : -1];
416
417#ifdef _MSC_VER
418#define STBIR__NOTUSED(v) (void)(v)
419#else
420#define STBIR__NOTUSED(v) (void)sizeof(v)
421#endif
422
423#define STBIR__ARRAY_SIZE(a) (sizeof((a))/sizeof((a)[0]))
424
425#ifndef STBIR_DEFAULT_FILTER_UPSAMPLE
426#define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM
427#endif
428
429#ifndef STBIR_DEFAULT_FILTER_DOWNSAMPLE
430#define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL
431#endif
432
433#ifndef STBIR_PROGRESS_REPORT
434#define STBIR_PROGRESS_REPORT(float_0_to_1)
435#endif
436
437#ifndef STBIR_MAX_CHANNELS
438#define STBIR_MAX_CHANNELS 64
439#endif
440
441#if STBIR_MAX_CHANNELS > 65536
442#error "Too many channels; STBIR_MAX_CHANNELS must be no more than 65536."
443// because we store the indices in 16-bit variables
444#endif
445
446// This value is added to alpha just before premultiplication to avoid
447// zeroing out color values. It is equivalent to 2^-80. If you don't want
448// that behavior (it may interfere if you have floating point images with
449// very small alpha values) then you can define STBIR_NO_ALPHA_EPSILON to
450// disable it.
451#ifndef STBIR_ALPHA_EPSILON
452#define STBIR_ALPHA_EPSILON ((float)1 / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20))
453#endif
454
455
456
457#ifdef _MSC_VER
458#define STBIR__UNUSED_PARAM(v) (void)(v)
459#else
460#define STBIR__UNUSED_PARAM(v) (void)sizeof(v)
461#endif
462
463// must match stbir_datatype
464static unsigned char stbir__type_size[] = {
465 1, // STBIR_TYPE_UINT8
466 2, // STBIR_TYPE_UINT16
467 4, // STBIR_TYPE_UINT32
468 4, // STBIR_TYPE_FLOAT
469};
470
471// Kernel function centered at 0
472typedef float (stbir__kernel_fn)(float x, float scale);
473typedef float (stbir__support_fn)(float scale);
474
475typedef struct
476{
477 stbir__kernel_fn* kernel;
478 stbir__support_fn* support;
479} stbir__filter_info;
480
481// When upsampling, the contributors are which source pixels contribute.
482// When downsampling, the contributors are which destination pixels are contributed to.
483typedef struct
484{
485 int n0; // First contributing pixel
486 int n1; // Last contributing pixel
487} stbir__contributors;
488
489typedef struct
490{
491 const void* input_data;
492 int input_w;
493 int input_h;
494 int input_stride_bytes;
495
496 void* output_data;
497 int output_w;
498 int output_h;
499 int output_stride_bytes;
500
501 float s0, t0, s1, t1;
502
503 float horizontal_shift; // Units: output pixels
504 float vertical_shift; // Units: output pixels
505 float horizontal_scale;
506 float vertical_scale;
507
508 int channels;
509 int alpha_channel;
510 stbir_uint32 flags;
511 stbir_datatype type;
512 stbir_filter horizontal_filter;
513 stbir_filter vertical_filter;
514 stbir_edge edge_horizontal;
515 stbir_edge edge_vertical;
516 stbir_colorspace colorspace;
517
518 stbir__contributors* horizontal_contributors;
519 float* horizontal_coefficients;
520
521 stbir__contributors* vertical_contributors;
522 float* vertical_coefficients;
523
524 int decode_buffer_pixels;
525 float* decode_buffer;
526
527 float* horizontal_buffer;
528
529 // cache these because ceil/floor are inexplicably showing up in profile
530 int horizontal_coefficient_width;
531 int vertical_coefficient_width;
532 int horizontal_filter_pixel_width;
533 int vertical_filter_pixel_width;
534 int horizontal_filter_pixel_margin;
535 int vertical_filter_pixel_margin;
536 int horizontal_num_contributors;
537 int vertical_num_contributors;
538
539 int ring_buffer_length_bytes; // The length of an individual entry in the ring buffer. The total number of ring buffers is stbir__get_filter_pixel_width(filter)
540 int ring_buffer_num_entries; // Total number of entries in the ring buffer.
541 int ring_buffer_first_scanline;
542 int ring_buffer_last_scanline;
543 int ring_buffer_begin_index; // first_scanline is at this index in the ring buffer
544 float* ring_buffer;
545
546 float* encode_buffer; // A temporary buffer to store floats so we don't lose precision while we do multiply-adds.
547
548 int horizontal_contributors_size;
549 int horizontal_coefficients_size;
550 int vertical_contributors_size;
551 int vertical_coefficients_size;
552 int decode_buffer_size;
553 int horizontal_buffer_size;
554 int ring_buffer_size;
555 int encode_buffer_size;
556} stbir__info;
557
558
559static const float stbir__max_uint8_as_float = 255.0f;
560static const float stbir__max_uint16_as_float = 65535.0f;
561static const double stbir__max_uint32_as_float = 4294967295.0;
562
563
564static stbir__inline int stbir__min(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_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_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
955 case STBIR_EDGE_REFLECT:
956 {
957 if (n < 0)
958 {
959 if (n < max)
960 return -n;
961 else
962 return max - 1;
963 }
964
965 if (n >= max)
966 {
967 int max2 = max * 2;
968 if (n >= max2)
969 return 0;
970 else
971 return max2 - n - 1;
972 }
973
974 return n; // NOTREACHED
975 }
976
977 case STBIR_EDGE_WRAP:
978 if (n >= 0)
979 return (n % max);
980 else
981 {
982 int m = (-n) % max;
983
984 if (m != 0)
985 m = max - m;
986
987 return (m);
988 }
989 // NOTREACHED
990
991 default:
992 STBIR_ASSERT(!"Unimplemented edge type");
993 return 0;
994 }
995}
996
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_filter filter, float scale, int in_first_pixel, int in_last_pixel, float in_center_of_out, stbir__contributors* contributor, float* coefficient_group)
1036{
1037 int i;
1038 float total_filter = 0;
1039 float filter_scale;
1040
1041 STBIR_ASSERT(in_last_pixel - in_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical.
1042
1043 contributor->n0 = in_first_pixel;
1044 contributor->n1 = in_last_pixel;
1045
1046 STBIR_ASSERT(contributor->n1 >= contributor->n0);
1047
1048 for (i = 0; i <= in_last_pixel - in_first_pixel; i++)
1049 {
1050 float in_pixel_center = (float)(i + in_first_pixel) + 0.5f;
1051 coefficient_group[i] = stbir__filter_info_table[filter].kernel(in_center_of_out - in_pixel_center, 1 / scale);
1052
1053 // If the coefficient is zero, skip it. (Don't do the <0 check here, we want the influence of those outside pixels.)
1054 if (i == 0 && !coefficient_group[i])
1055 {
1056 contributor->n0 = ++in_first_pixel;
1057 i--;
1058 continue;
1059 }
1060
1061 total_filter += coefficient_group[i];
1062 }
1063
1064 STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(in_last_pixel + 1) + 0.5f - in_center_of_out, 1/scale) == 0);
1065
1066 STBIR_ASSERT(total_filter > 0.9);
1067 STBIR_ASSERT(total_filter < 1.1f); // Make sure it's not way off.
1068
1069 // Make sure the sum of all coefficients is 1.
1070 filter_scale = 1 / total_filter;
1071
1072 for (i = 0; i <= in_last_pixel - in_first_pixel; i++)
1073 coefficient_group[i] *= filter_scale;
1074
1075 for (i = in_last_pixel - in_first_pixel; i >= 0; i--)
1076 {
1077 if (coefficient_group[i])
1078 break;
1079
1080 // This line has no weight. We can skip it.
1081 contributor->n1 = contributor->n0 + i - 1;
1082 }
1083}
1084
1085static void stbir__calculate_coefficients_downsample(stbir_filter filter, float scale_ratio, int out_first_pixel, int out_last_pixel, float out_center_of_in, stbir__contributors* contributor, float* coefficient_group)
1086{
1087 int i;
1088
1089 STBIR_ASSERT(out_last_pixel - out_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(scale_ratio) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical.
1090
1091 contributor->n0 = out_first_pixel;
1092 contributor->n1 = out_last_pixel;
1093
1094 STBIR_ASSERT(contributor->n1 >= contributor->n0);
1095
1096 for (i = 0; i <= out_last_pixel - out_first_pixel; i++)
1097 {
1098 float out_pixel_center = (float)(i + out_first_pixel) + 0.5f;
1099 float x = out_pixel_center - out_center_of_in;
1100 coefficient_group[i] = stbir__filter_info_table[filter].kernel(x, scale_ratio) * scale_ratio;
1101 }
1102
1103 STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(out_last_pixel + 1) + 0.5f - out_center_of_in, scale_ratio) == 0);
1104
1105 for (i = out_last_pixel - out_first_pixel; i >= 0; i--)
1106 {
1107 if (coefficient_group[i])
1108 break;
1109
1110 // This line has no weight. We can skip it.
1111 contributor->n1 = contributor->n0 + i - 1;
1112 }
1113}
1114
1115static void stbir__normalize_downsample_coefficients(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, int input_size, int output_size)
1116{
1117 int num_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size);
1118 int num_coefficients = stbir__get_coefficient_width(filter, scale_ratio);
1119 int i, j;
1120 int skip;
1121
1122 for (i = 0; i < output_size; i++)
1123 {
1124 float scale;
1125 float total = 0;
1126
1127 for (j = 0; j < num_contributors; j++)
1128 {
1129 if (i >= contributors[j].n0 && i <= contributors[j].n1)
1130 {
1131 float coefficient = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0);
1132 total += coefficient;
1133 }
1134 else if (i < contributors[j].n0)
1135 break;
1136 }
1137
1138 STBIR_ASSERT(total > 0.9f);
1139 STBIR_ASSERT(total < 1.1f);
1140
1141 scale = 1 / total;
1142
1143 for (j = 0; j < num_contributors; j++)
1144 {
1145 if (i >= contributors[j].n0 && i <= contributors[j].n1)
1146 *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0) *= scale;
1147 else if (i < contributors[j].n0)
1148 break;
1149 }
1150 }
1151
1152 // Optimize: Skip zero coefficients and contributions outside of image bounds.
1153 // Do this after normalizing because normalization depends on the n0/n1 values.
1154 for (j = 0; j < num_contributors; j++)
1155 {
1156 int range, max, width;
1157
1158 skip = 0;
1159 while (*stbir__get_coefficient(coefficients, filter, scale_ratio, j, skip) == 0)
1160 skip++;
1161
1162 contributors[j].n0 += skip;
1163
1164 while (contributors[j].n0 < 0)
1165 {
1166 contributors[j].n0++;
1167 skip++;
1168 }
1169
1170 range = contributors[j].n1 - contributors[j].n0 + 1;
1171 max = stbir__min(num_coefficients, range);
1172
1173 width = stbir__get_coefficient_width(filter, scale_ratio);
1174 for (i = 0; i < max; i++)
1175 {
1176 if (i + skip >= width)
1177 break;
1178
1179 *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i) = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i + skip);
1180 }
1181
1182 continue;
1183 }
1184
1185 // Using min to avoid writing into invalid pixels.
1186 for (i = 0; i < num_contributors; i++)
1187 contributors[i].n1 = stbir__min(contributors[i].n1, output_size - 1);
1188}
1189
1190// Each scan line uses the same kernel values so we should calculate the kernel
1191// values once and then we can use them for every scan line.
1192static void stbir__calculate_filters(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, float shift, int input_size, int output_size)
1193{
1194 int n;
1195 int total_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size);
1196
1197 if (stbir__use_upsampling(scale_ratio))
1198 {
1199 float out_pixels_radius = stbir__filter_info_table[filter].support(1 / scale_ratio) * scale_ratio;
1200
1201 // Looping through out pixels
1202 for (n = 0; n < total_contributors; n++)
1203 {
1204 float in_center_of_out; // Center of the current out pixel in the in pixel space
1205 int in_first_pixel, in_last_pixel;
1206
1207 stbir__calculate_sample_range_upsample(n, out_pixels_radius, scale_ratio, shift, &in_first_pixel, &in_last_pixel, &in_center_of_out);
1208
1209 stbir__calculate_coefficients_upsample(filter, scale_ratio, in_first_pixel, in_last_pixel, in_center_of_out, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0));
1210 }
1211 }
1212 else
1213 {
1214 float in_pixels_radius = stbir__filter_info_table[filter].support(scale_ratio) / scale_ratio;
1215
1216 // Looping through in pixels
1217 for (n = 0; n < total_contributors; n++)
1218 {
1219 float out_center_of_in; // Center of the current out pixel in the in pixel space
1220 int out_first_pixel, out_last_pixel;
1221 int n_adjusted = n - stbir__get_filter_pixel_margin(filter, scale_ratio);
1222
1223 stbir__calculate_sample_range_downsample(n_adjusted, in_pixels_radius, scale_ratio, shift, &out_first_pixel, &out_last_pixel, &out_center_of_in);
1224
1225 stbir__calculate_coefficients_downsample(filter, scale_ratio, out_first_pixel, out_last_pixel, out_center_of_in, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0));
1226 }
1227
1228 stbir__normalize_downsample_coefficients(contributors, coefficients, filter, scale_ratio, input_size, output_size);
1229 }
1230}
1231
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 size_t input_stride_bytes = stbir_info->input_stride_bytes;
1250 float* decode_buffer = stbir__get_decode_buffer(stbir_info);
1251 stbir_edge edge_horizontal = stbir_info->edge_horizontal;
1252 stbir_edge edge_vertical = stbir_info->edge_vertical;
1253 size_t in_buffer_row_offset = stbir__edge_wrap(edge_vertical, n, stbir_info->input_h) * input_stride_bytes;
1254 const void* input_data = (char *) stbir_info->input_data + in_buffer_row_offset;
1255 int max_x = input_w + stbir_info->horizontal_filter_pixel_margin;
1256 int decode = STBIR__DECODE(type, colorspace);
1257
1258 int x = -stbir_info->horizontal_filter_pixel_margin;
1259
1260 // special handling for STBIR_EDGE_ZERO because it needs to return an item that doesn't appear in the input,
1261 // and we want to avoid paying overhead on every pixel if not STBIR_EDGE_ZERO
1262 if (edge_vertical == STBIR_EDGE_ZERO && (n < 0 || n >= stbir_info->input_h))
1263 {
1264 for (; x < max_x; x++)
1265 for (c = 0; c < channels; c++)
1266 decode_buffer[x*channels + c] = 0;
1267 return;
1268 }
1269
1270 switch (decode)
1271 {
1272 case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR):
1273 for (; x < max_x; x++)
1274 {
1275 int decode_pixel_index = x * channels;
1276 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1277 for (c = 0; c < channels; c++)
1278 decode_buffer[decode_pixel_index + c] = ((float)((const unsigned char*)input_data)[input_pixel_index + c]) / stbir__max_uint8_as_float;
1279 }
1280 break;
1281
1282 case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB):
1283 for (; x < max_x; x++)
1284 {
1285 int decode_pixel_index = x * channels;
1286 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1287 for (c = 0; c < channels; c++)
1288 decode_buffer[decode_pixel_index + c] = stbir__srgb_uchar_to_linear_float[((const unsigned char*)input_data)[input_pixel_index + c]];
1289
1290 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1291 decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned char*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint8_as_float;
1292 }
1293 break;
1294
1295 case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR):
1296 for (; x < max_x; x++)
1297 {
1298 int decode_pixel_index = x * channels;
1299 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1300 for (c = 0; c < channels; c++)
1301 decode_buffer[decode_pixel_index + c] = ((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float;
1302 }
1303 break;
1304
1305 case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB):
1306 for (; x < max_x; x++)
1307 {
1308 int decode_pixel_index = x * channels;
1309 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1310 for (c = 0; c < channels; c++)
1311 decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float);
1312
1313 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1314 decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned short*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint16_as_float;
1315 }
1316 break;
1317
1318 case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR):
1319 for (; x < max_x; x++)
1320 {
1321 int decode_pixel_index = x * channels;
1322 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1323 for (c = 0; c < channels; c++)
1324 decode_buffer[decode_pixel_index + c] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float);
1325 }
1326 break;
1327
1328 case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB):
1329 for (; x < max_x; x++)
1330 {
1331 int decode_pixel_index = x * channels;
1332 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1333 for (c = 0; c < channels; c++)
1334 decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear((float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float));
1335
1336 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1337 decode_buffer[decode_pixel_index + alpha_channel] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint32_as_float);
1338 }
1339 break;
1340
1341 case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR):
1342 for (; x < max_x; x++)
1343 {
1344 int decode_pixel_index = x * channels;
1345 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1346 for (c = 0; c < channels; c++)
1347 decode_buffer[decode_pixel_index + c] = ((const float*)input_data)[input_pixel_index + c];
1348 }
1349 break;
1350
1351 case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB):
1352 for (; x < max_x; x++)
1353 {
1354 int decode_pixel_index = x * channels;
1355 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1356 for (c = 0; c < channels; c++)
1357 decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((const float*)input_data)[input_pixel_index + c]);
1358
1359 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1360 decode_buffer[decode_pixel_index + alpha_channel] = ((const float*)input_data)[input_pixel_index + alpha_channel];
1361 }
1362
1363 break;
1364
1365 default:
1366 STBIR_ASSERT(!"Unknown type/colorspace/channels combination.");
1367 break;
1368 }
1369
1370 if (!(stbir_info->flags & STBIR_FLAG_ALPHA_PREMULTIPLIED))
1371 {
1372 for (x = -stbir_info->horizontal_filter_pixel_margin; x < max_x; x++)
1373 {
1374 int decode_pixel_index = x * channels;
1375
1376 // If the alpha value is 0 it will clobber the color values. Make sure it's not.
1377 float alpha = decode_buffer[decode_pixel_index + alpha_channel];
1378#ifndef STBIR_NO_ALPHA_EPSILON
1379 if (stbir_info->type != STBIR_TYPE_FLOAT) {
1380 alpha += STBIR_ALPHA_EPSILON;
1381 decode_buffer[decode_pixel_index + alpha_channel] = alpha;
1382 }
1383#endif
1384 for (c = 0; c < channels; c++)
1385 {
1386 if (c == alpha_channel)
1387 continue;
1388
1389 decode_buffer[decode_pixel_index + c] *= alpha;
1390 }
1391 }
1392 }
1393
1394 if (edge_horizontal == STBIR_EDGE_ZERO)
1395 {
1396 for (x = -stbir_info->horizontal_filter_pixel_margin; x < 0; x++)
1397 {
1398 for (c = 0; c < channels; c++)
1399 decode_buffer[x*channels + c] = 0;
1400 }
1401 for (x = input_w; x < max_x; x++)
1402 {
1403 for (c = 0; c < channels; c++)
1404 decode_buffer[x*channels + c] = 0;
1405 }
1406 }
1407}
1408
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 stbir_info->ring_buffer_last_scanline = n;
1420
1421 if (stbir_info->ring_buffer_begin_index < 0)
1422 {
1423 ring_buffer_index = stbir_info->ring_buffer_begin_index = 0;
1424 stbir_info->ring_buffer_first_scanline = n;
1425 }
1426 else
1427 {
1428 ring_buffer_index = (stbir_info->ring_buffer_begin_index + (stbir_info->ring_buffer_last_scanline - stbir_info->ring_buffer_first_scanline)) % stbir_info->ring_buffer_num_entries;
1429 STBIR_ASSERT(ring_buffer_index != stbir_info->ring_buffer_begin_index);
1430 }
1431
1432 ring_buffer = stbir__get_ring_buffer_entry(stbir_info->ring_buffer, ring_buffer_index, stbir_info->ring_buffer_length_bytes / sizeof(float));
1433 memset(ring_buffer, 0, stbir_info->ring_buffer_length_bytes);
1434
1435 return ring_buffer;
1436}
1437
1438
1439static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, float* output_buffer)
1440{
1441 int x, k;
1442 int output_w = stbir_info->output_w;
1443 int channels = stbir_info->channels;
1444 float* decode_buffer = stbir__get_decode_buffer(stbir_info);
1445 stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors;
1446 float* horizontal_coefficients = stbir_info->horizontal_coefficients;
1447 int coefficient_width = stbir_info->horizontal_coefficient_width;
1448
1449 for (x = 0; x < output_w; x++)
1450 {
1451 int n0 = horizontal_contributors[x].n0;
1452 int n1 = horizontal_contributors[x].n1;
1453
1454 int out_pixel_index = x * channels;
1455 int coefficient_group = coefficient_width * x;
1456 int coefficient_counter = 0;
1457
1458 STBIR_ASSERT(n1 >= n0);
1459 STBIR_ASSERT(n0 >= -stbir_info->horizontal_filter_pixel_margin);
1460 STBIR_ASSERT(n1 >= -stbir_info->horizontal_filter_pixel_margin);
1461 STBIR_ASSERT(n0 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin);
1462 STBIR_ASSERT(n1 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin);
1463
1464 switch (channels) {
1465 case 1:
1466 for (k = n0; k <= n1; k++)
1467 {
1468 int in_pixel_index = k * 1;
1469 float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
1470 STBIR_ASSERT(coefficient != 0);
1471 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1472 }
1473 break;
1474 case 2:
1475 for (k = n0; k <= n1; k++)
1476 {
1477 int in_pixel_index = k * 2;
1478 float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
1479 STBIR_ASSERT(coefficient != 0);
1480 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1481 output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1482 }
1483 break;
1484 case 3:
1485 for (k = n0; k <= n1; k++)
1486 {
1487 int in_pixel_index = k * 3;
1488 float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
1489 STBIR_ASSERT(coefficient != 0);
1490 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1491 output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1492 output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
1493 }
1494 break;
1495 case 4:
1496 for (k = n0; k <= n1; k++)
1497 {
1498 int in_pixel_index = k * 4;
1499 float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
1500 STBIR_ASSERT(coefficient != 0);
1501 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1502 output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1503 output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
1504 output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient;
1505 }
1506 break;
1507 default:
1508 for (k = n0; k <= n1; k++)
1509 {
1510 int in_pixel_index = k * channels;
1511 float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
1512 int c;
1513 STBIR_ASSERT(coefficient != 0);
1514 for (c = 0; c < channels; c++)
1515 output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient;
1516 }
1517 break;
1518 }
1519 }
1520}
1521
1522static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, float* output_buffer)
1523{
1524 int x, k;
1525 int input_w = stbir_info->input_w;
1526 int channels = stbir_info->channels;
1527 float* decode_buffer = stbir__get_decode_buffer(stbir_info);
1528 stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors;
1529 float* horizontal_coefficients = stbir_info->horizontal_coefficients;
1530 int coefficient_width = stbir_info->horizontal_coefficient_width;
1531 int filter_pixel_margin = stbir_info->horizontal_filter_pixel_margin;
1532 int max_x = input_w + filter_pixel_margin * 2;
1533
1534 STBIR_ASSERT(!stbir__use_width_upsampling(stbir_info));
1535
1536 switch (channels) {
1537 case 1:
1538 for (x = 0; x < max_x; x++)
1539 {
1540 int n0 = horizontal_contributors[x].n0;
1541 int n1 = horizontal_contributors[x].n1;
1542
1543 int in_x = x - filter_pixel_margin;
1544 int in_pixel_index = in_x * 1;
1545 int max_n = n1;
1546 int coefficient_group = coefficient_width * x;
1547
1548 for (k = n0; k <= max_n; k++)
1549 {
1550 int out_pixel_index = k * 1;
1551 float coefficient = horizontal_coefficients[coefficient_group + k - n0];
1552 STBIR_ASSERT(coefficient != 0);
1553 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1554 }
1555 }
1556 break;
1557
1558 case 2:
1559 for (x = 0; x < max_x; x++)
1560 {
1561 int n0 = horizontal_contributors[x].n0;
1562 int n1 = horizontal_contributors[x].n1;
1563
1564 int in_x = x - filter_pixel_margin;
1565 int in_pixel_index = in_x * 2;
1566 int max_n = n1;
1567 int coefficient_group = coefficient_width * x;
1568
1569 for (k = n0; k <= max_n; k++)
1570 {
1571 int out_pixel_index = k * 2;
1572 float coefficient = horizontal_coefficients[coefficient_group + k - n0];
1573 STBIR_ASSERT(coefficient != 0);
1574 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1575 output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1576 }
1577 }
1578 break;
1579
1580 case 3:
1581 for (x = 0; x < max_x; x++)
1582 {
1583 int n0 = horizontal_contributors[x].n0;
1584 int n1 = horizontal_contributors[x].n1;
1585
1586 int in_x = x - filter_pixel_margin;
1587 int in_pixel_index = in_x * 3;
1588 int max_n = n1;
1589 int coefficient_group = coefficient_width * x;
1590
1591 for (k = n0; k <= max_n; k++)
1592 {
1593 int out_pixel_index = k * 3;
1594 float coefficient = horizontal_coefficients[coefficient_group + k - n0];
1595 STBIR_ASSERT(coefficient != 0);
1596 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1597 output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1598 output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
1599 }
1600 }
1601 break;
1602
1603 case 4:
1604 for (x = 0; x < max_x; x++)
1605 {
1606 int n0 = horizontal_contributors[x].n0;
1607 int n1 = horizontal_contributors[x].n1;
1608
1609 int in_x = x - filter_pixel_margin;
1610 int in_pixel_index = in_x * 4;
1611 int max_n = n1;
1612 int coefficient_group = coefficient_width * x;
1613
1614 for (k = n0; k <= max_n; k++)
1615 {
1616 int out_pixel_index = k * 4;
1617 float coefficient = horizontal_coefficients[coefficient_group + k - n0];
1618 STBIR_ASSERT(coefficient != 0);
1619 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1620 output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1621 output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
1622 output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient;
1623 }
1624 }
1625 break;
1626
1627 default:
1628 for (x = 0; x < max_x; x++)
1629 {
1630 int n0 = horizontal_contributors[x].n0;
1631 int n1 = horizontal_contributors[x].n1;
1632
1633 int in_x = x - filter_pixel_margin;
1634 int in_pixel_index = in_x * channels;
1635 int max_n = n1;
1636 int coefficient_group = coefficient_width * x;
1637
1638 for (k = n0; k <= max_n; k++)
1639 {
1640 int c;
1641 int out_pixel_index = k * channels;
1642 float coefficient = horizontal_coefficients[coefficient_group + k - n0];
1643 STBIR_ASSERT(coefficient != 0);
1644 for (c = 0; c < channels; c++)
1645 output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient;
1646 }
1647 }
1648 break;
1649 }
1650}
1651
1652static void stbir__decode_and_resample_upsample(stbir__info* stbir_info, int n)
1653{
1654 // Decode the nth scanline from the source image into the decode buffer.
1655 stbir__decode_scanline(stbir_info, n);
1656
1657 // Now resample it into the ring buffer.
1658 if (stbir__use_width_upsampling(stbir_info))
1659 stbir__resample_horizontal_upsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n));
1660 else
1661 stbir__resample_horizontal_downsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n));
1662
1663 // Now it's sitting in the ring buffer ready to be used as source for the vertical sampling.
1664}
1665
1666static void stbir__decode_and_resample_downsample(stbir__info* stbir_info, int n)
1667{
1668 // Decode the nth scanline from the source image into the decode buffer.
1669 stbir__decode_scanline(stbir_info, n);
1670
1671 memset(stbir_info->horizontal_buffer, 0, stbir_info->output_w * stbir_info->channels * sizeof(float));
1672
1673 // Now resample it into the horizontal buffer.
1674 if (stbir__use_width_upsampling(stbir_info))
1675 stbir__resample_horizontal_upsample(stbir_info, stbir_info->horizontal_buffer);
1676 else
1677 stbir__resample_horizontal_downsample(stbir_info, stbir_info->horizontal_buffer);
1678
1679 // Now it's sitting in the horizontal buffer ready to be distributed into the ring buffers.
1680}
1681
1682// Get the specified scan line from the ring buffer.
1683static float* stbir__get_ring_buffer_scanline(int get_scanline, float* ring_buffer, int begin_index, int first_scanline, int ring_buffer_num_entries, int ring_buffer_length)
1684{
1685 int ring_buffer_index = (begin_index + (get_scanline - first_scanline)) % ring_buffer_num_entries;
1686 return stbir__get_ring_buffer_entry(ring_buffer, ring_buffer_index, ring_buffer_length);
1687}
1688
1689
1690static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void *output_buffer, float *encode_buffer, int channels, int alpha_channel, int decode)
1691{
1692 int x;
1693 int n;
1694 int num_nonalpha;
1695 stbir_uint16 nonalpha[STBIR_MAX_CHANNELS];
1696
1697 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_PREMULTIPLIED))
1698 {
1699 for (x=0; x < num_pixels; ++x)
1700 {
1701 int pixel_index = x*channels;
1702
1703 float alpha = encode_buffer[pixel_index + alpha_channel];
1704 float reciprocal_alpha = alpha ? 1.0f / alpha : 0;
1705
1706 // unrolling this produced a 1% slowdown upscaling a large RGBA linear-space image on my machine - stb
1707 for (n = 0; n < channels; n++)
1708 if (n != alpha_channel)
1709 encode_buffer[pixel_index + n] *= reciprocal_alpha;
1710
1711 // We added in a small epsilon to prevent the color channel from being deleted with zero alpha.
1712 // Because we only add it for integer types, it will automatically be discarded on integer
1713 // conversion, so we don't need to subtract it back out (which would be problematic for
1714 // numeric precision reasons).
1715 }
1716 }
1717
1718 // build a table of all channels that need colorspace correction, so
1719 // we don't perform colorspace correction on channels that don't need it.
1720 for (x = 0, num_nonalpha = 0; x < channels; ++x)
1721 {
1722 if (x != alpha_channel || (stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE))
1723 {
1724 nonalpha[num_nonalpha++] = (stbir_uint16)x;
1725 }
1726 }
1727
1728 #define STBIR__ROUND_INT(f) ((int) ((f)+0.5))
1729 #define STBIR__ROUND_UINT(f) ((stbir_uint32) ((f)+0.5))
1730
1731 #ifdef STBIR__SATURATE_INT
1732 #define STBIR__ENCODE_LINEAR8(f) stbir__saturate8 (STBIR__ROUND_INT((f) * stbir__max_uint8_as_float ))
1733 #define STBIR__ENCODE_LINEAR16(f) stbir__saturate16(STBIR__ROUND_INT((f) * stbir__max_uint16_as_float))
1734 #else
1735 #define STBIR__ENCODE_LINEAR8(f) (unsigned char ) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint8_as_float )
1736 #define STBIR__ENCODE_LINEAR16(f) (unsigned short) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint16_as_float)
1737 #endif
1738
1739 switch (decode)
1740 {
1741 case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR):
1742 for (x=0; x < num_pixels; ++x)
1743 {
1744 int pixel_index = x*channels;
1745
1746 for (n = 0; n < channels; n++)
1747 {
1748 int index = pixel_index + n;
1749 ((unsigned char*)output_buffer)[index] = STBIR__ENCODE_LINEAR8(encode_buffer[index]);
1750 }
1751 }
1752 break;
1753
1754 case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB):
1755 for (x=0; x < num_pixels; ++x)
1756 {
1757 int pixel_index = x*channels;
1758
1759 for (n = 0; n < num_nonalpha; n++)
1760 {
1761 int index = pixel_index + nonalpha[n];
1762 ((unsigned char*)output_buffer)[index] = stbir__linear_to_srgb_uchar(encode_buffer[index]);
1763 }
1764
1765 if (!(stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE))
1766 ((unsigned char *)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR8(encode_buffer[pixel_index+alpha_channel]);
1767 }
1768 break;
1769
1770 case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR):
1771 for (x=0; x < num_pixels; ++x)
1772 {
1773 int pixel_index = x*channels;
1774
1775 for (n = 0; n < channels; n++)
1776 {
1777 int index = pixel_index + n;
1778 ((unsigned short*)output_buffer)[index] = STBIR__ENCODE_LINEAR16(encode_buffer[index]);
1779 }
1780 }
1781 break;
1782
1783 case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB):
1784 for (x=0; x < num_pixels; ++x)
1785 {
1786 int pixel_index = x*channels;
1787
1788 for (n = 0; n < num_nonalpha; n++)
1789 {
1790 int index = pixel_index + nonalpha[n];
1791 ((unsigned short*)output_buffer)[index] = (unsigned short)STBIR__ROUND_INT(stbir__linear_to_srgb(stbir__saturate(encode_buffer[index])) * stbir__max_uint16_as_float);
1792 }
1793
1794 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1795 ((unsigned short*)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR16(encode_buffer[pixel_index + alpha_channel]);
1796 }
1797
1798 break;
1799
1800 case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR):
1801 for (x=0; x < num_pixels; ++x)
1802 {
1803 int pixel_index = x*channels;
1804
1805 for (n = 0; n < channels; n++)
1806 {
1807 int index = pixel_index + n;
1808 ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__saturate(encode_buffer[index])) * stbir__max_uint32_as_float);
1809 }
1810 }
1811 break;
1812
1813 case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB):
1814 for (x=0; x < num_pixels; ++x)
1815 {
1816 int pixel_index = x*channels;
1817
1818 for (n = 0; n < num_nonalpha; n++)
1819 {
1820 int index = pixel_index + nonalpha[n];
1821 ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__linear_to_srgb(stbir__saturate(encode_buffer[index]))) * stbir__max_uint32_as_float);
1822 }
1823
1824 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1825 ((unsigned int*)output_buffer)[pixel_index + alpha_channel] = (unsigned int)STBIR__ROUND_INT(((double)stbir__saturate(encode_buffer[pixel_index + alpha_channel])) * stbir__max_uint32_as_float);
1826 }
1827 break;
1828
1829 case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR):
1830 for (x=0; x < num_pixels; ++x)
1831 {
1832 int pixel_index = x*channels;
1833
1834 for (n = 0; n < channels; n++)
1835 {
1836 int index = pixel_index + n;
1837 ((float*)output_buffer)[index] = encode_buffer[index];
1838 }
1839 }
1840 break;
1841
1842 case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB):
1843 for (x=0; x < num_pixels; ++x)
1844 {
1845 int pixel_index = x*channels;
1846
1847 for (n = 0; n < num_nonalpha; n++)
1848 {
1849 int index = pixel_index + nonalpha[n];
1850 ((float*)output_buffer)[index] = stbir__linear_to_srgb(encode_buffer[index]);
1851 }
1852
1853 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1854 ((float*)output_buffer)[pixel_index + alpha_channel] = encode_buffer[pixel_index + alpha_channel];
1855 }
1856 break;
1857
1858 default:
1859 STBIR_ASSERT(!"Unknown type/colorspace/channels combination.");
1860 break;
1861 }
1862}
1863
1864static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n)
1865{
1866 int x, k;
1867 int output_w = stbir_info->output_w;
1868 stbir__contributors* vertical_contributors = stbir_info->vertical_contributors;
1869 float* vertical_coefficients = stbir_info->vertical_coefficients;
1870 int channels = stbir_info->channels;
1871 int alpha_channel = stbir_info->alpha_channel;
1872 int type = stbir_info->type;
1873 int colorspace = stbir_info->colorspace;
1874 int ring_buffer_entries = stbir_info->ring_buffer_num_entries;
1875 void* output_data = stbir_info->output_data;
1876 float* encode_buffer = stbir_info->encode_buffer;
1877 int decode = STBIR__DECODE(type, colorspace);
1878 int coefficient_width = stbir_info->vertical_coefficient_width;
1879 int coefficient_counter;
1880 int contributor = n;
1881
1882 float* ring_buffer = stbir_info->ring_buffer;
1883 int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index;
1884 int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline;
1885 int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
1886
1887 int n0,n1, output_row_start;
1888 int coefficient_group = coefficient_width * contributor;
1889
1890 n0 = vertical_contributors[contributor].n0;
1891 n1 = vertical_contributors[contributor].n1;
1892
1893 output_row_start = n * stbir_info->output_stride_bytes;
1894
1895 STBIR_ASSERT(stbir__use_height_upsampling(stbir_info));
1896
1897 memset(encode_buffer, 0, output_w * sizeof(float) * channels);
1898
1899 // I tried reblocking this for better cache usage of encode_buffer
1900 // (using x_outer, k, x_inner), but it lost speed. -- stb
1901
1902 coefficient_counter = 0;
1903 switch (channels) {
1904 case 1:
1905 for (k = n0; k <= n1; k++)
1906 {
1907 int coefficient_index = coefficient_counter++;
1908 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
1909 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
1910 for (x = 0; x < output_w; ++x)
1911 {
1912 int in_pixel_index = x * 1;
1913 encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
1914 }
1915 }
1916 break;
1917 case 2:
1918 for (k = n0; k <= n1; k++)
1919 {
1920 int coefficient_index = coefficient_counter++;
1921 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
1922 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
1923 for (x = 0; x < output_w; ++x)
1924 {
1925 int in_pixel_index = x * 2;
1926 encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
1927 encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
1928 }
1929 }
1930 break;
1931 case 3:
1932 for (k = n0; k <= n1; k++)
1933 {
1934 int coefficient_index = coefficient_counter++;
1935 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
1936 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
1937 for (x = 0; x < output_w; ++x)
1938 {
1939 int in_pixel_index = x * 3;
1940 encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
1941 encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
1942 encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient;
1943 }
1944 }
1945 break;
1946 case 4:
1947 for (k = n0; k <= n1; k++)
1948 {
1949 int coefficient_index = coefficient_counter++;
1950 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
1951 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
1952 for (x = 0; x < output_w; ++x)
1953 {
1954 int in_pixel_index = x * 4;
1955 encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
1956 encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
1957 encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient;
1958 encode_buffer[in_pixel_index + 3] += ring_buffer_entry[in_pixel_index + 3] * coefficient;
1959 }
1960 }
1961 break;
1962 default:
1963 for (k = n0; k <= n1; k++)
1964 {
1965 int coefficient_index = coefficient_counter++;
1966 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
1967 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
1968 for (x = 0; x < output_w; ++x)
1969 {
1970 int in_pixel_index = x * channels;
1971 int c;
1972 for (c = 0; c < channels; c++)
1973 encode_buffer[in_pixel_index + c] += ring_buffer_entry[in_pixel_index + c] * coefficient;
1974 }
1975 }
1976 break;
1977 }
1978 stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, encode_buffer, channels, alpha_channel, decode);
1979}
1980
1981static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n)
1982{
1983 int x, k;
1984 int output_w = stbir_info->output_w;
1985 stbir__contributors* vertical_contributors = stbir_info->vertical_contributors;
1986 float* vertical_coefficients = stbir_info->vertical_coefficients;
1987 int channels = stbir_info->channels;
1988 int ring_buffer_entries = stbir_info->ring_buffer_num_entries;
1989 float* horizontal_buffer = stbir_info->horizontal_buffer;
1990 int coefficient_width = stbir_info->vertical_coefficient_width;
1991 int contributor = n + stbir_info->vertical_filter_pixel_margin;
1992
1993 float* ring_buffer = stbir_info->ring_buffer;
1994 int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index;
1995 int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline;
1996 int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
1997 int n0,n1;
1998
1999 n0 = vertical_contributors[contributor].n0;
2000 n1 = vertical_contributors[contributor].n1;
2001
2002 STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info));
2003
2004 for (k = n0; k <= n1; k++)
2005 {
2006 int coefficient_index = k - n0;
2007 int coefficient_group = coefficient_width * contributor;
2008 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
2009
2010 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
2011
2012 switch (channels) {
2013 case 1:
2014 for (x = 0; x < output_w; x++)
2015 {
2016 int in_pixel_index = x * 1;
2017 ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
2018 }
2019 break;
2020 case 2:
2021 for (x = 0; x < output_w; x++)
2022 {
2023 int in_pixel_index = x * 2;
2024 ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
2025 ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
2026 }
2027 break;
2028 case 3:
2029 for (x = 0; x < output_w; x++)
2030 {
2031 int in_pixel_index = x * 3;
2032 ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
2033 ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
2034 ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient;
2035 }
2036 break;
2037 case 4:
2038 for (x = 0; x < output_w; x++)
2039 {
2040 int in_pixel_index = x * 4;
2041 ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
2042 ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
2043 ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient;
2044 ring_buffer_entry[in_pixel_index + 3] += horizontal_buffer[in_pixel_index + 3] * coefficient;
2045 }
2046 break;
2047 default:
2048 for (x = 0; x < output_w; x++)
2049 {
2050 int in_pixel_index = x * channels;
2051
2052 int c;
2053 for (c = 0; c < channels; c++)
2054 ring_buffer_entry[in_pixel_index + c] += horizontal_buffer[in_pixel_index + c] * coefficient;
2055 }
2056 break;
2057 }
2058 }
2059}
2060
2061static void stbir__buffer_loop_upsample(stbir__info* stbir_info)
2062{
2063 int y;
2064 float scale_ratio = stbir_info->vertical_scale;
2065 float out_scanlines_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(1/scale_ratio) * scale_ratio;
2066
2067 STBIR_ASSERT(stbir__use_height_upsampling(stbir_info));
2068
2069 for (y = 0; y < stbir_info->output_h; y++)
2070 {
2071 float in_center_of_out = 0; // Center of the current out scanline in the in scanline space
2072 int in_first_scanline = 0, in_last_scanline = 0;
2073
2074 stbir__calculate_sample_range_upsample(y, out_scanlines_radius, scale_ratio, stbir_info->vertical_shift, &in_first_scanline, &in_last_scanline, &in_center_of_out);
2075
2076 STBIR_ASSERT(in_last_scanline - in_first_scanline + 1 <= stbir_info->ring_buffer_num_entries);
2077
2078 if (stbir_info->ring_buffer_begin_index >= 0)
2079 {
2080 // Get rid of whatever we don't need anymore.
2081 while (in_first_scanline > stbir_info->ring_buffer_first_scanline)
2082 {
2083 if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline)
2084 {
2085 // We just popped the last scanline off the ring buffer.
2086 // Reset it to the empty state.
2087 stbir_info->ring_buffer_begin_index = -1;
2088 stbir_info->ring_buffer_first_scanline = 0;
2089 stbir_info->ring_buffer_last_scanline = 0;
2090 break;
2091 }
2092 else
2093 {
2094 stbir_info->ring_buffer_first_scanline++;
2095 stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries;
2096 }
2097 }
2098 }
2099
2100 // Load in new ones.
2101 if (stbir_info->ring_buffer_begin_index < 0)
2102 stbir__decode_and_resample_upsample(stbir_info, in_first_scanline);
2103
2104 while (in_last_scanline > stbir_info->ring_buffer_last_scanline)
2105 stbir__decode_and_resample_upsample(stbir_info, stbir_info->ring_buffer_last_scanline + 1);
2106
2107 // Now all buffers should be ready to write a row of vertical sampling.
2108 stbir__resample_vertical_upsample(stbir_info, y);
2109
2110 STBIR_PROGRESS_REPORT((float)y / stbir_info->output_h);
2111 }
2112}
2113
2114static void stbir__empty_ring_buffer(stbir__info* stbir_info, int first_necessary_scanline)
2115{
2116 int output_stride_bytes = stbir_info->output_stride_bytes;
2117 int channels = stbir_info->channels;
2118 int alpha_channel = stbir_info->alpha_channel;
2119 int type = stbir_info->type;
2120 int colorspace = stbir_info->colorspace;
2121 int output_w = stbir_info->output_w;
2122 void* output_data = stbir_info->output_data;
2123 int decode = STBIR__DECODE(type, colorspace);
2124
2125 float* ring_buffer = stbir_info->ring_buffer;
2126 int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
2127
2128 if (stbir_info->ring_buffer_begin_index >= 0)
2129 {
2130 // Get rid of whatever we don't need anymore.
2131 while (first_necessary_scanline > stbir_info->ring_buffer_first_scanline)
2132 {
2133 if (stbir_info->ring_buffer_first_scanline >= 0 && stbir_info->ring_buffer_first_scanline < stbir_info->output_h)
2134 {
2135 int output_row_start = stbir_info->ring_buffer_first_scanline * output_stride_bytes;
2136 float* ring_buffer_entry = stbir__get_ring_buffer_entry(ring_buffer, stbir_info->ring_buffer_begin_index, ring_buffer_length);
2137 stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, ring_buffer_entry, channels, alpha_channel, decode);
2138 STBIR_PROGRESS_REPORT((float)stbir_info->ring_buffer_first_scanline / stbir_info->output_h);
2139 }
2140
2141 if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline)
2142 {
2143 // We just popped the last scanline off the ring buffer.
2144 // Reset it to the empty state.
2145 stbir_info->ring_buffer_begin_index = -1;
2146 stbir_info->ring_buffer_first_scanline = 0;
2147 stbir_info->ring_buffer_last_scanline = 0;
2148 break;
2149 }
2150 else
2151 {
2152 stbir_info->ring_buffer_first_scanline++;
2153 stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries;
2154 }
2155 }
2156 }
2157}
2158
2159static void stbir__buffer_loop_downsample(stbir__info* stbir_info)
2160{
2161 int y;
2162 float scale_ratio = stbir_info->vertical_scale;
2163 int output_h = stbir_info->output_h;
2164 float in_pixels_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(scale_ratio) / scale_ratio;
2165 int pixel_margin = stbir_info->vertical_filter_pixel_margin;
2166 int max_y = stbir_info->input_h + pixel_margin;
2167
2168 STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info));
2169
2170 for (y = -pixel_margin; y < max_y; y++)
2171 {
2172 float out_center_of_in; // Center of the current out scanline in the in scanline space
2173 int out_first_scanline, out_last_scanline;
2174
2175 stbir__calculate_sample_range_downsample(y, in_pixels_radius, scale_ratio, stbir_info->vertical_shift, &out_first_scanline, &out_last_scanline, &out_center_of_in);
2176
2177 STBIR_ASSERT(out_last_scanline - out_first_scanline + 1 <= stbir_info->ring_buffer_num_entries);
2178
2179 if (out_last_scanline < 0 || out_first_scanline >= output_h)
2180 continue;
2181
2182 stbir__empty_ring_buffer(stbir_info, out_first_scanline);
2183
2184 stbir__decode_and_resample_downsample(stbir_info, y);
2185
2186 // Load in new ones.
2187 if (stbir_info->ring_buffer_begin_index < 0)
2188 stbir__add_empty_ring_buffer_entry(stbir_info, out_first_scanline);
2189
2190 while (out_last_scanline > stbir_info->ring_buffer_last_scanline)
2191 stbir__add_empty_ring_buffer_entry(stbir_info, stbir_info->ring_buffer_last_scanline + 1);
2192
2193 // Now the horizontal buffer is ready to write to all ring buffer rows.
2194 stbir__resample_vertical_downsample(stbir_info, y);
2195 }
2196
2197 stbir__empty_ring_buffer(stbir_info, stbir_info->output_h);
2198}
2199
2200static void stbir__setup(stbir__info *info, int input_w, int input_h, int output_w, int output_h, int channels)
2201{
2202 info->input_w = input_w;
2203 info->input_h = input_h;
2204 info->output_w = output_w;
2205 info->output_h = output_h;
2206 info->channels = channels;
2207}
2208
2209static void stbir__calculate_transform(stbir__info *info, float s0, float t0, float s1, float t1, float *transform)
2210{
2211 info->s0 = s0;
2212 info->t0 = t0;
2213 info->s1 = s1;
2214 info->t1 = t1;
2215
2216 if (transform)
2217 {
2218 info->horizontal_scale = transform[0];
2219 info->vertical_scale = transform[1];
2220 info->horizontal_shift = transform[2];
2221 info->vertical_shift = transform[3];
2222 }
2223 else
2224 {
2225 info->horizontal_scale = ((float)info->output_w / info->input_w) / (s1 - s0);
2226 info->vertical_scale = ((float)info->output_h / info->input_h) / (t1 - t0);
2227
2228 info->horizontal_shift = s0 * info->output_w / (s1 - s0);
2229 info->vertical_shift = t0 * info->output_h / (t1 - t0);
2230 }
2231}
2232
2233static void stbir__choose_filter(stbir__info *info, stbir_filter h_filter, stbir_filter v_filter)
2234{
2235 if (h_filter == 0)
2236 h_filter = stbir__use_upsampling(info->horizontal_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE;
2237 if (v_filter == 0)
2238 v_filter = stbir__use_upsampling(info->vertical_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE;
2239 info->horizontal_filter = h_filter;
2240 info->vertical_filter = v_filter;
2241}
2242
2243static stbir_uint32 stbir__calculate_memory(stbir__info *info)
2244{
2245 int pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale);
2246 int filter_height = stbir__get_filter_pixel_width(info->vertical_filter, info->vertical_scale);
2247
2248 info->horizontal_num_contributors = stbir__get_contributors(info->horizontal_scale, info->horizontal_filter, info->input_w, info->output_w);
2249 info->vertical_num_contributors = stbir__get_contributors(info->vertical_scale , info->vertical_filter , info->input_h, info->output_h);
2250
2251 // One extra entry because floating point precision problems sometimes cause an extra to be necessary.
2252 info->ring_buffer_num_entries = filter_height + 1;
2253
2254 info->horizontal_contributors_size = info->horizontal_num_contributors * sizeof(stbir__contributors);
2255 info->horizontal_coefficients_size = stbir__get_total_horizontal_coefficients(info) * sizeof(float);
2256 info->vertical_contributors_size = info->vertical_num_contributors * sizeof(stbir__contributors);
2257 info->vertical_coefficients_size = stbir__get_total_vertical_coefficients(info) * sizeof(float);
2258 info->decode_buffer_size = (info->input_w + pixel_margin * 2) * info->channels * sizeof(float);
2259 info->horizontal_buffer_size = info->output_w * info->channels * sizeof(float);
2260 info->ring_buffer_size = info->output_w * info->channels * info->ring_buffer_num_entries * sizeof(float);
2261 info->encode_buffer_size = info->output_w * info->channels * sizeof(float);
2262
2263 STBIR_ASSERT(info->horizontal_filter != 0);
2264 STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); // this now happens too late
2265 STBIR_ASSERT(info->vertical_filter != 0);
2266 STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); // this now happens too late
2267
2268 if (stbir__use_height_upsampling(info))
2269 // The horizontal buffer is for when we're downsampling the height and we
2270 // can't output the result of sampling the decode buffer directly into the
2271 // ring buffers.
2272 info->horizontal_buffer_size = 0;
2273 else
2274 // The encode buffer is to retain precision in the height upsampling method
2275 // and isn't used when height downsampling.
2276 info->encode_buffer_size = 0;
2277
2278 return info->horizontal_contributors_size + info->horizontal_coefficients_size
2279 + info->vertical_contributors_size + info->vertical_coefficients_size
2280 + info->decode_buffer_size + info->horizontal_buffer_size
2281 + info->ring_buffer_size + info->encode_buffer_size;
2282}
2283
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)
2325 flags |= STBIR_FLAG_ALPHA_USES_COLORSPACE | STBIR_FLAG_ALPHA_PREMULTIPLIED;
2326
2327 if (!(flags&STBIR_FLAG_ALPHA_USES_COLORSPACE) || !(flags&STBIR_FLAG_ALPHA_PREMULTIPLIED))
2328 STBIR_ASSERT(alpha_channel >= 0 && alpha_channel < info->channels);
2329
2330 if (alpha_channel >= info->channels)
2331 return 0;
2332
2333 STBIR_ASSERT(tempmem);
2334
2335 if (!tempmem)
2336 return 0;
2337
2338 STBIR_ASSERT(tempmem_size_in_bytes >= memory_required);
2339
2340 if (tempmem_size_in_bytes < memory_required)
2341 return 0;
2342
2343 memset(tempmem, 0, tempmem_size_in_bytes);
2344
2345 info->input_data = input_data;
2346 info->input_stride_bytes = width_stride_input;
2347
2348 info->output_data = output_data;
2349 info->output_stride_bytes = width_stride_output;
2350
2351 info->alpha_channel = alpha_channel;
2352 info->flags = flags;
2353 info->type = type;
2354 info->edge_horizontal = edge_horizontal;
2355 info->edge_vertical = edge_vertical;
2356 info->colorspace = colorspace;
2357
2358 info->horizontal_coefficient_width = stbir__get_coefficient_width (info->horizontal_filter, info->horizontal_scale);
2359 info->vertical_coefficient_width = stbir__get_coefficient_width (info->vertical_filter , info->vertical_scale );
2360 info->horizontal_filter_pixel_width = stbir__get_filter_pixel_width (info->horizontal_filter, info->horizontal_scale);
2361 info->vertical_filter_pixel_width = stbir__get_filter_pixel_width (info->vertical_filter , info->vertical_scale );
2362 info->horizontal_filter_pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale);
2363 info->vertical_filter_pixel_margin = stbir__get_filter_pixel_margin(info->vertical_filter , info->vertical_scale );
2364
2365 info->ring_buffer_length_bytes = info->output_w * info->channels * sizeof(float);
2366 info->decode_buffer_pixels = info->input_w + info->horizontal_filter_pixel_margin * 2;
2367
2368#define STBIR__NEXT_MEMPTR(current, newtype) (newtype*)(((unsigned char*)current) + current##_size)
2369
2370 info->horizontal_contributors = (stbir__contributors *) tempmem;
2371 info->horizontal_coefficients = STBIR__NEXT_MEMPTR(info->horizontal_contributors, float);
2372 info->vertical_contributors = STBIR__NEXT_MEMPTR(info->horizontal_coefficients, stbir__contributors);
2373 info->vertical_coefficients = STBIR__NEXT_MEMPTR(info->vertical_contributors, float);
2374 info->decode_buffer = STBIR__NEXT_MEMPTR(info->vertical_coefficients, float);
2375
2376 if (stbir__use_height_upsampling(info))
2377 {
2378 info->horizontal_buffer = NULL;
2379 info->ring_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float);
2380 info->encode_buffer = STBIR__NEXT_MEMPTR(info->ring_buffer, float);
2381
2382 STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->encode_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes);
2383 }
2384 else
2385 {
2386 info->horizontal_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float);
2387 info->ring_buffer = STBIR__NEXT_MEMPTR(info->horizontal_buffer, float);
2388 info->encode_buffer = NULL;
2389
2390 STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->ring_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes);
2391 }
2392
2393#undef STBIR__NEXT_MEMPTR
2394
2395 // This signals that the ring buffer is empty
2396 info->ring_buffer_begin_index = -1;
2397
2398 stbir__calculate_filters(info->horizontal_contributors, info->horizontal_coefficients, info->horizontal_filter, info->horizontal_scale, info->horizontal_shift, info->input_w, info->output_w);
2399 stbir__calculate_filters(info->vertical_contributors, info->vertical_coefficients, info->vertical_filter, info->vertical_scale, info->vertical_shift, info->input_h, info->output_h);
2400
2401 STBIR_PROGRESS_REPORT(0);
2402
2403 if (stbir__use_height_upsampling(info))
2404 stbir__buffer_loop_upsample(info);
2405 else
2406 stbir__buffer_loop_downsample(info);
2407
2408 STBIR_PROGRESS_REPORT(1);
2409
2410#ifdef STBIR_DEBUG_OVERWRITE_TEST
2411 STBIR_ASSERT(memcmp(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0);
2412 STBIR_ASSERT(memcmp(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE) == 0);
2413 STBIR_ASSERT(memcmp(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0);
2414 STBIR_ASSERT(memcmp(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE) == 0);
2415#endif
2416
2417 return 1;
2418}
2419
2420
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,
2462 STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR);
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,
2472 STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR);
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,
2482 STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB);
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
2587/*
2588------------------------------------------------------------------------------
2589MIT License
2590Copyright (c) 2017 Sean Barrett
2591Permission is hereby granted, free of charge, to any person obtaining a copy of
2592this software and associated documentation files (the "Software"), to deal in
2593the Software without restriction, including without limitation the rights to
2594use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
2595of the Software, and to permit persons to whom the Software is furnished to do
2596so, subject to the following conditions:
2597The above copyright notice and this permission notice shall be included in all
2598copies or substantial portions of the Software.
2599THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2600IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2601FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2602AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2603LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2604OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2605SOFTWARE.
2606------------------------------------------------------------------------------
2607*/