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