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