1 /* stb_image_resize - v0.96 - public domain image resizing
2 by Jorge L Rodriguez (@VinoBS) - 2014
3 http://github.com/nothings/stb
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.
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.
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)
29 See the "header file" section of the source for API documentation.
31 ADDITIONAL DOCUMENTATION
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.
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:
43 #define STBIR_MALLOC(size,context) ...
44 #define STBIR_FREE(ptr,context) ...
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.
50 Define STBIR_ASSERT(boolval) to override assert() and not use assert.h
53 Define STBIR_SATURATE_INT to compute clamp values in-range using
54 integer operations instead of float operations. This may be faster
58 For functions which don't provide explicit control over what filters
59 to use, you can change the compile-time defaults with
61 #define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_something
62 #define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_something
64 See stbir_filter in the header-file section for the list of 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.
72 For interactive use with slow resize operations, you can install
73 a progress-report callback:
75 #define STBIR_PROGRESS_REPORT(val) some_func(val)
77 The parameter val is a float which goes from 0 to 1 as progress is made.
81 static void my_progress_report(float progress);
82 #define STBIR_PROGRESS_REPORT(val) my_progress_report(val)
84 #define STB_IMAGE_RESIZE_IMPLEMENTATION
85 #include "stb_image_resize.h"
87 static void my_progress_report(float progress)
89 printf("Progress: %f%%\n", progress*100);
93 If your image has more than 64 channels, define STBIR_MAX_CHANNELS
94 to the max you'll have.
97 Most of the resizing functions provide the ability to control how
98 the alpha channel of an image is processed. The important things
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.
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.)
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.
120 3. You will get best results in most cases by converting images
121 to premultiplied alpha before processing them mathematically.
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.
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.)
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.
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.)
156 Jorge L Rodriguez: Implementation
157 Sean Barrett: API design, optimizations
158 Aras Pranckevicius: bugfix
159 Nathan Reed: warning fixes
162 0.97 (2020-02-02) fixed warning
163 0.96 (2019-03-04) fixed warnings
164 0.95 (2017-07-23) fixed warnings
165 0.94 (2017-03-18) fixed warnings
166 0.93 (2017-03-03) fixed bug with certain combinations of heights
167 0.92 (2017-01-02) fix integer overflow on large (>2GB) images
168 0.91 (2016-04-02) fix warnings; fix handling of subpixel regions
169 0.90 (2014-09-17) first released version
172 See end of file for license information.
175 Don't decode all of the image data when only processing a partial tile
176 Don't use full-width decode buffers when only processing a partial tile
177 When processing wide images, break processing into tiles so data fits in L1 cache
179 Resize that respects alpha test coverage
180 (Reference code: FloatImage::alphaTestCoverage and FloatImage::scaleAlphaToCoverage:
181 https://code.google.com/p/nvidia-texture-tools/source/browse/trunk/src/nvimage/FloatImage.cpp )
184 #ifndef STBIR_INCLUDE_STB_IMAGE_RESIZE_H
185 #define STBIR_INCLUDE_STB_IMAGE_RESIZE_H
188 typedef unsigned char stbir_uint8;
189 typedef unsigned short stbir_uint16;
190 typedef unsigned int stbir_uint32;
193 typedef uint8_t stbir_uint8;
194 typedef uint16_t stbir_uint16;
195 typedef uint32_t stbir_uint32;
199 #ifdef STB_IMAGE_RESIZE_STATIC
200 #define STBIRDEF static
203 #define STBIRDEF extern "C"
205 #define STBIRDEF extern
210 //////////////////////////////////////////////////////////////////////////////
214 // * "input pixels" points to an array of image data with 'num_channels' channels (e.g. RGB=3, RGBA=4)
215 // * input_w is input image width (x-axis), input_h is input image height (y-axis)
216 // * stride is the offset between successive rows of image data in memory, in bytes. you can
217 // specify 0 to mean packed continuously in memory
218 // * alpha channel is treated identically to other channels.
219 // * colorspace is linear or sRGB as specified by function name
220 // * returned result is 1 for success or 0 in case of an error.
221 // #define STBIR_ASSERT() to trigger an assert on parameter validation errors.
222 // * Memory required grows approximately linearly with input and output size, but with
223 // discontinuities at input_w == output_w and input_h == output_h.
224 // * These functions use a "default" resampling filter defined at compile time. To change the filter,
225 // you can change the compile-time defaults by #defining STBIR_DEFAULT_FILTER_UPSAMPLE
226 // and STBIR_DEFAULT_FILTER_DOWNSAMPLE, or you can use the medium-complexity API.
228 STBIRDEF int stbir_resize_uint8( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
229 unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
232 STBIRDEF int stbir_resize_float( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
233 float *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
237 // The following functions interpret image data as gamma-corrected sRGB.
238 // Specify STBIR_ALPHA_CHANNEL_NONE if you have no alpha channel,
239 // or otherwise provide the index of the alpha channel. Flags value
240 // of 0 will probably do the right thing if you're not sure what
243 #define STBIR_ALPHA_CHANNEL_NONE -1
245 // Set this flag if your texture has premultiplied alpha. Otherwise, stbir will
246 // use alpha-weighted resampling (effectively premultiplying, resampling,
247 // then unpremultiplying).
248 #define STBIR_FLAG_ALPHA_PREMULTIPLIED (1 << 0)
249 // The specified alpha channel should be handled as gamma-corrected value even
250 // when doing sRGB operations.
251 #define STBIR_FLAG_ALPHA_USES_COLORSPACE (1 << 1)
253 STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
254 unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
255 int num_channels, int alpha_channel, int flags);
260 STBIR_EDGE_CLAMP = 1,
261 STBIR_EDGE_REFLECT = 2,
266 // This function adds the ability to specify how requests to sample off the edge of the image are handled.
267 STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
268 unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
269 int num_channels, int alpha_channel, int flags,
270 stbir_edge edge_wrap_mode);
272 //////////////////////////////////////////////////////////////////////////////
274 // Medium-complexity API
276 // This extends the easy-to-use API as follows:
278 // * Alpha-channel can be processed separately
279 // * If alpha_channel is not STBIR_ALPHA_CHANNEL_NONE
280 // * Alpha channel will not be gamma corrected (unless flags&STBIR_FLAG_GAMMA_CORRECT)
281 // * Filters will be weighted by alpha channel (unless flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)
282 // * Filter can be selected explicitly
283 // * uint16 image type
284 // * sRGB colorspace available for all types
285 // * context parameter for passing to STBIR_MALLOC
289 STBIR_FILTER_DEFAULT = 0, // use same filter type that easy-to-use API chooses
290 STBIR_FILTER_BOX = 1, // A trapezoid w/1-pixel wide ramps, same result as box for integer scale ratios
291 STBIR_FILTER_TRIANGLE = 2, // On upsampling, produces same results as bilinear texture filtering
292 STBIR_FILTER_CUBICBSPLINE = 3, // The cubic b-spline (aka Mitchell-Netrevalli with B=1,C=0), gaussian-esque
293 STBIR_FILTER_CATMULLROM = 4, // An interpolating cubic spline
294 STBIR_FILTER_MITCHELL = 5, // Mitchell-Netrevalli filter with B=1/3, C=1/3
299 STBIR_COLORSPACE_LINEAR,
300 STBIR_COLORSPACE_SRGB,
302 STBIR_MAX_COLORSPACES,
305 // The following functions are all identical except for the type of the image data
307 STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
308 unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
309 int num_channels, int alpha_channel, int flags,
310 stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
311 void *alloc_context);
313 STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
314 stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
315 int num_channels, int alpha_channel, int flags,
316 stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
317 void *alloc_context);
319 STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
320 float *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
321 int num_channels, int alpha_channel, int flags,
322 stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
323 void *alloc_context);
327 //////////////////////////////////////////////////////////////////////////////
329 // Full-complexity API
331 // This extends the medium API as follows:
333 // * uint32 image type
335 // * separate filter types for each axis
336 // * separate edge modes for each axis
337 // * can specify scale explicitly for subpixel correctness
338 // * can specify image source tile using texture coordinates
350 STBIRDEF int stbir_resize( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
351 void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
352 stbir_datatype datatype,
353 int num_channels, int alpha_channel, int flags,
354 stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
355 stbir_filter filter_horizontal, stbir_filter filter_vertical,
356 stbir_colorspace space, void *alloc_context);
358 STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
359 void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
360 stbir_datatype datatype,
361 int num_channels, int alpha_channel, int flags,
362 stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
363 stbir_filter filter_horizontal, stbir_filter filter_vertical,
364 stbir_colorspace space, void *alloc_context,
365 float x_scale, float y_scale,
366 float x_offset, float y_offset);
368 STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
369 void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
370 stbir_datatype datatype,
371 int num_channels, int alpha_channel, int flags,
372 stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
373 stbir_filter filter_horizontal, stbir_filter filter_vertical,
374 stbir_colorspace space, void *alloc_context,
375 float s0, float t0, float s1, float t1);
376 // (s0, t0) & (s1, t1) are the top-left and bottom right corner (uv addressing style: [0, 1]x[0, 1]) of a region of the input image to use.
380 //// end header file /////////////////////////////////////////////////////
381 #endif // STBIR_INCLUDE_STB_IMAGE_RESIZE_H
387 #ifdef STB_IMAGE_RESIZE_IMPLEMENTATION
391 #define STBIR_ASSERT(x) assert(x)
401 // use comma operator to evaluate c, to avoid "unused parameter" warnings
402 #define STBIR_MALLOC(size,c) ((void)(c), malloc(size))
403 #define STBIR_FREE(ptr,c) ((void)(c), free(ptr))
408 #define stbir__inline inline
410 #define stbir__inline
413 #define stbir__inline __forceinline
417 // should produce compiler error if size is wrong
418 typedef unsigned char stbir__validate_uint32[sizeof(stbir_uint32) == 4 ? 1 : -1];
421 #define STBIR__NOTUSED(v) (void)(v)
423 #define STBIR__NOTUSED(v) (void)sizeof(v)
426 #define STBIR__ARRAY_SIZE(a) (sizeof((a))/sizeof((a)[0]))
428 #ifndef STBIR_DEFAULT_FILTER_UPSAMPLE
429 #define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM
432 #ifndef STBIR_DEFAULT_FILTER_DOWNSAMPLE
433 #define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL
436 #ifndef STBIR_PROGRESS_REPORT
437 #define STBIR_PROGRESS_REPORT(float_0_to_1)
440 #ifndef STBIR_MAX_CHANNELS
441 #define STBIR_MAX_CHANNELS 64
444 #if STBIR_MAX_CHANNELS > 65536
445 #error "Too many channels; STBIR_MAX_CHANNELS must be no more than 65536."
446 // because we store the indices in 16-bit variables
449 // This value is added to alpha just before premultiplication to avoid
450 // zeroing out color values. It is equivalent to 2^-80. If you don't want
451 // that behavior (it may interfere if you have floating point images with
452 // very small alpha values) then you can define STBIR_NO_ALPHA_EPSILON to
454 #ifndef STBIR_ALPHA_EPSILON
455 #define STBIR_ALPHA_EPSILON ((float)1 / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20))
461 #define STBIR__UNUSED_PARAM(v) (void)(v)
463 #define STBIR__UNUSED_PARAM(v) (void)sizeof(v)
466 // must match stbir_datatype
467 static unsigned char stbir__type_size[] = {
468 1, // STBIR_TYPE_UINT8
469 2, // STBIR_TYPE_UINT16
470 4, // STBIR_TYPE_UINT32
471 4, // STBIR_TYPE_FLOAT
474 // Kernel function centered at 0
475 typedef float (stbir__kernel_fn)(float x, float scale);
476 typedef float (stbir__support_fn)(float scale);
480 stbir__kernel_fn* kernel;
481 stbir__support_fn* support;
482 } stbir__filter_info;
484 // When upsampling, the contributors are which source pixels contribute.
485 // When downsampling, the contributors are which destination pixels are contributed to.
488 int n0; // First contributing pixel
489 int n1; // Last contributing pixel
490 } stbir__contributors;
494 const void* input_data;
497 int input_stride_bytes;
502 int output_stride_bytes;
504 float s0, t0, s1, t1;
506 float horizontal_shift; // Units: output pixels
507 float vertical_shift; // Units: output pixels
508 float horizontal_scale;
509 float vertical_scale;
515 stbir_filter horizontal_filter;
516 stbir_filter vertical_filter;
517 stbir_edge edge_horizontal;
518 stbir_edge edge_vertical;
519 stbir_colorspace colorspace;
521 stbir__contributors* horizontal_contributors;
522 float* horizontal_coefficients;
524 stbir__contributors* vertical_contributors;
525 float* vertical_coefficients;
527 int decode_buffer_pixels;
528 float* decode_buffer;
530 float* horizontal_buffer;
532 // cache these because ceil/floor are inexplicably showing up in profile
533 int horizontal_coefficient_width;
534 int vertical_coefficient_width;
535 int horizontal_filter_pixel_width;
536 int vertical_filter_pixel_width;
537 int horizontal_filter_pixel_margin;
538 int vertical_filter_pixel_margin;
539 int horizontal_num_contributors;
540 int vertical_num_contributors;
542 int ring_buffer_length_bytes; // The length of an individual entry in the ring buffer. The total number of ring buffers is stbir__get_filter_pixel_width(filter)
543 int ring_buffer_num_entries; // Total number of entries in the ring buffer.
544 int ring_buffer_first_scanline;
545 int ring_buffer_last_scanline;
546 int ring_buffer_begin_index; // first_scanline is at this index in the ring buffer
549 float* encode_buffer; // A temporary buffer to store floats so we don't lose precision while we do multiply-adds.
551 int horizontal_contributors_size;
552 int horizontal_coefficients_size;
553 int vertical_contributors_size;
554 int vertical_coefficients_size;
555 int decode_buffer_size;
556 int horizontal_buffer_size;
557 int ring_buffer_size;
558 int encode_buffer_size;
562 static const float stbir__max_uint8_as_float = 255.0f;
563 static const float stbir__max_uint16_as_float = 65535.0f;
564 static const double stbir__max_uint32_as_float = 4294967295.0;
567 static stbir__inline int stbir__min(int a, int b)
569 return a < b ? a : b;
572 static stbir__inline float stbir__saturate(float x)
583 #ifdef STBIR_SATURATE_INT
584 static stbir__inline stbir_uint8 stbir__saturate8(int x)
586 if ((unsigned int) x <= 255)
595 static stbir__inline stbir_uint16 stbir__saturate16(int x)
597 if ((unsigned int) x <= 65535)
607 static float stbir__srgb_uchar_to_linear_float[256] = {
608 0.000000f, 0.000304f, 0.000607f, 0.000911f, 0.001214f, 0.001518f, 0.001821f, 0.002125f, 0.002428f, 0.002732f, 0.003035f,
609 0.003347f, 0.003677f, 0.004025f, 0.004391f, 0.004777f, 0.005182f, 0.005605f, 0.006049f, 0.006512f, 0.006995f, 0.007499f,
610 0.008023f, 0.008568f, 0.009134f, 0.009721f, 0.010330f, 0.010960f, 0.011612f, 0.012286f, 0.012983f, 0.013702f, 0.014444f,
611 0.015209f, 0.015996f, 0.016807f, 0.017642f, 0.018500f, 0.019382f, 0.020289f, 0.021219f, 0.022174f, 0.023153f, 0.024158f,
612 0.025187f, 0.026241f, 0.027321f, 0.028426f, 0.029557f, 0.030713f, 0.031896f, 0.033105f, 0.034340f, 0.035601f, 0.036889f,
613 0.038204f, 0.039546f, 0.040915f, 0.042311f, 0.043735f, 0.045186f, 0.046665f, 0.048172f, 0.049707f, 0.051269f, 0.052861f,
614 0.054480f, 0.056128f, 0.057805f, 0.059511f, 0.061246f, 0.063010f, 0.064803f, 0.066626f, 0.068478f, 0.070360f, 0.072272f,
615 0.074214f, 0.076185f, 0.078187f, 0.080220f, 0.082283f, 0.084376f, 0.086500f, 0.088656f, 0.090842f, 0.093059f, 0.095307f,
616 0.097587f, 0.099899f, 0.102242f, 0.104616f, 0.107023f, 0.109462f, 0.111932f, 0.114435f, 0.116971f, 0.119538f, 0.122139f,
617 0.124772f, 0.127438f, 0.130136f, 0.132868f, 0.135633f, 0.138432f, 0.141263f, 0.144128f, 0.147027f, 0.149960f, 0.152926f,
618 0.155926f, 0.158961f, 0.162029f, 0.165132f, 0.168269f, 0.171441f, 0.174647f, 0.177888f, 0.181164f, 0.184475f, 0.187821f,
619 0.191202f, 0.194618f, 0.198069f, 0.201556f, 0.205079f, 0.208637f, 0.212231f, 0.215861f, 0.219526f, 0.223228f, 0.226966f,
620 0.230740f, 0.234551f, 0.238398f, 0.242281f, 0.246201f, 0.250158f, 0.254152f, 0.258183f, 0.262251f, 0.266356f, 0.270498f,
621 0.274677f, 0.278894f, 0.283149f, 0.287441f, 0.291771f, 0.296138f, 0.300544f, 0.304987f, 0.309469f, 0.313989f, 0.318547f,
622 0.323143f, 0.327778f, 0.332452f, 0.337164f, 0.341914f, 0.346704f, 0.351533f, 0.356400f, 0.361307f, 0.366253f, 0.371238f,
623 0.376262f, 0.381326f, 0.386430f, 0.391573f, 0.396755f, 0.401978f, 0.407240f, 0.412543f, 0.417885f, 0.423268f, 0.428691f,
624 0.434154f, 0.439657f, 0.445201f, 0.450786f, 0.456411f, 0.462077f, 0.467784f, 0.473532f, 0.479320f, 0.485150f, 0.491021f,
625 0.496933f, 0.502887f, 0.508881f, 0.514918f, 0.520996f, 0.527115f, 0.533276f, 0.539480f, 0.545725f, 0.552011f, 0.558340f,
626 0.564712f, 0.571125f, 0.577581f, 0.584078f, 0.590619f, 0.597202f, 0.603827f, 0.610496f, 0.617207f, 0.623960f, 0.630757f,
627 0.637597f, 0.644480f, 0.651406f, 0.658375f, 0.665387f, 0.672443f, 0.679543f, 0.686685f, 0.693872f, 0.701102f, 0.708376f,
628 0.715694f, 0.723055f, 0.730461f, 0.737911f, 0.745404f, 0.752942f, 0.760525f, 0.768151f, 0.775822f, 0.783538f, 0.791298f,
629 0.799103f, 0.806952f, 0.814847f, 0.822786f, 0.830770f, 0.838799f, 0.846873f, 0.854993f, 0.863157f, 0.871367f, 0.879622f,
630 0.887923f, 0.896269f, 0.904661f, 0.913099f, 0.921582f, 0.930111f, 0.938686f, 0.947307f, 0.955974f, 0.964686f, 0.973445f,
631 0.982251f, 0.991102f, 1.0f
634 static float stbir__srgb_to_linear(float f)
639 return (float)pow((f + 0.055f) / 1.055f, 2.4f);
642 static float stbir__linear_to_srgb(float f)
647 return 1.055f * (float)pow(f, 1 / 2.4f) - 0.055f;
650 #ifndef STBIR_NON_IEEE_FLOAT
651 // From https://gist.github.com/rygorous/2203834
659 static const stbir_uint32 fp32_to_srgb8_tab4[104] = {
660 0x0073000d, 0x007a000d, 0x0080000d, 0x0087000d, 0x008d000d, 0x0094000d, 0x009a000d, 0x00a1000d,
661 0x00a7001a, 0x00b4001a, 0x00c1001a, 0x00ce001a, 0x00da001a, 0x00e7001a, 0x00f4001a, 0x0101001a,
662 0x010e0033, 0x01280033, 0x01410033, 0x015b0033, 0x01750033, 0x018f0033, 0x01a80033, 0x01c20033,
663 0x01dc0067, 0x020f0067, 0x02430067, 0x02760067, 0x02aa0067, 0x02dd0067, 0x03110067, 0x03440067,
664 0x037800ce, 0x03df00ce, 0x044600ce, 0x04ad00ce, 0x051400ce, 0x057b00c5, 0x05dd00bc, 0x063b00b5,
665 0x06970158, 0x07420142, 0x07e30130, 0x087b0120, 0x090b0112, 0x09940106, 0x0a1700fc, 0x0a9500f2,
666 0x0b0f01cb, 0x0bf401ae, 0x0ccb0195, 0x0d950180, 0x0e56016e, 0x0f0d015e, 0x0fbc0150, 0x10630143,
667 0x11070264, 0x1238023e, 0x1357021d, 0x14660201, 0x156601e9, 0x165a01d3, 0x174401c0, 0x182401af,
668 0x18fe0331, 0x1a9602fe, 0x1c1502d2, 0x1d7e02ad, 0x1ed4028d, 0x201a0270, 0x21520256, 0x227d0240,
669 0x239f0443, 0x25c003fe, 0x27bf03c4, 0x29a10392, 0x2b6a0367, 0x2d1d0341, 0x2ebe031f, 0x304d0300,
670 0x31d105b0, 0x34a80555, 0x37520507, 0x39d504c5, 0x3c37048b, 0x3e7c0458, 0x40a8042a, 0x42bd0401,
671 0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559,
672 0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723,
675 static stbir_uint8 stbir__linear_to_srgb_uchar(float in)
677 static const stbir__FP32 almostone = { 0x3f7fffff }; // 1-eps
678 static const stbir__FP32 minval = { (127-13) << 23 };
679 stbir_uint32 tab,bias,scale,t;
682 // Clamp to [2^(-13), 1-eps]; these two values map to 0 and 1, respectively.
683 // The tests are carefully written so that NaNs map to 0, same as in the reference
685 if (!(in > minval.f)) // written this way to catch NaNs
687 if (in > almostone.f)
690 // Do the table lookup and unpack bias, scale
692 tab = fp32_to_srgb8_tab4[(f.u - minval.u) >> 20];
693 bias = (tab >> 16) << 9;
694 scale = tab & 0xffff;
696 // Grab next-highest mantissa bits and perform linear interpolation
697 t = (f.u >> 12) & 0xff;
698 return (unsigned char) ((bias + scale*t) >> 16);
702 // sRGB transition values, scaled by 1<<28
703 static int stbir__srgb_offset_to_linear_scaled[256] =
705 0, 40738, 122216, 203693, 285170, 366648, 448125, 529603,
706 611080, 692557, 774035, 855852, 942009, 1033024, 1128971, 1229926,
707 1335959, 1447142, 1563542, 1685229, 1812268, 1944725, 2082664, 2226148,
708 2375238, 2529996, 2690481, 2856753, 3028870, 3206888, 3390865, 3580856,
709 3776916, 3979100, 4187460, 4402049, 4622919, 4850123, 5083710, 5323731,
710 5570236, 5823273, 6082892, 6349140, 6622065, 6901714, 7188133, 7481369,
711 7781466, 8088471, 8402427, 8723380, 9051372, 9386448, 9728650, 10078021,
712 10434603, 10798439, 11169569, 11548036, 11933879, 12327139, 12727857, 13136073,
713 13551826, 13975156, 14406100, 14844697, 15290987, 15745007, 16206795, 16676389,
714 17153826, 17639142, 18132374, 18633560, 19142734, 19659934, 20185196, 20718552,
715 21260042, 21809696, 22367554, 22933648, 23508010, 24090680, 24681686, 25281066,
716 25888850, 26505076, 27129772, 27762974, 28404716, 29055026, 29713942, 30381490,
717 31057708, 31742624, 32436272, 33138682, 33849884, 34569912, 35298800, 36036568,
718 36783260, 37538896, 38303512, 39077136, 39859796, 40651528, 41452360, 42262316,
719 43081432, 43909732, 44747252, 45594016, 46450052, 47315392, 48190064, 49074096,
720 49967516, 50870356, 51782636, 52704392, 53635648, 54576432, 55526772, 56486700,
721 57456236, 58435408, 59424248, 60422780, 61431036, 62449032, 63476804, 64514376,
722 65561776, 66619028, 67686160, 68763192, 69850160, 70947088, 72053992, 73170912,
723 74297864, 75434880, 76581976, 77739184, 78906536, 80084040, 81271736, 82469648,
724 83677792, 84896192, 86124888, 87363888, 88613232, 89872928, 91143016, 92423512,
725 93714432, 95015816, 96327688, 97650056, 98982952, 100326408, 101680440, 103045072,
726 104420320, 105806224, 107202800, 108610064, 110028048, 111456776, 112896264, 114346544,
727 115807632, 117279552, 118762328, 120255976, 121760536, 123276016, 124802440, 126339832,
728 127888216, 129447616, 131018048, 132599544, 134192112, 135795792, 137410592, 139036528,
729 140673648, 142321952, 143981456, 145652208, 147334208, 149027488, 150732064, 152447968,
730 154175200, 155913792, 157663776, 159425168, 161197984, 162982240, 164777968, 166585184,
731 168403904, 170234160, 172075968, 173929344, 175794320, 177670896, 179559120, 181458992,
732 183370528, 185293776, 187228736, 189175424, 191133888, 193104112, 195086128, 197079968,
733 199085648, 201103184, 203132592, 205173888, 207227120, 209292272, 211369392, 213458480,
734 215559568, 217672656, 219797792, 221934976, 224084240, 226245600, 228419056, 230604656,
735 232802400, 235012320, 237234432, 239468736, 241715280, 243974080, 246245120, 248528464,
736 250824112, 253132064, 255452368, 257785040, 260130080, 262487520, 264857376, 267239664,
739 static stbir_uint8 stbir__linear_to_srgb_uchar(float f)
741 int x = (int) (f * (1 << 28)); // has headroom so you don't need to clamp
745 // Refine the guess with a short binary search.
746 i = v + 128; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
747 i = v + 64; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
748 i = v + 32; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
749 i = v + 16; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
750 i = v + 8; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
751 i = v + 4; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
752 i = v + 2; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
753 i = v + 1; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
755 return (stbir_uint8) v;
759 static float stbir__filter_trapezoid(float x, float scale)
761 float halfscale = scale / 2;
762 float t = 0.5f + halfscale;
763 STBIR_ASSERT(scale <= 1);
771 float r = 0.5f - halfscale;
775 return (t - x) / scale;
779 static float stbir__support_trapezoid(float scale)
781 STBIR_ASSERT(scale <= 1);
782 return 0.5f + scale / 2;
785 static float stbir__filter_triangle(float x, float s)
787 STBIR__UNUSED_PARAM(s);
797 static float stbir__filter_cubic(float x, float s)
799 STBIR__UNUSED_PARAM(s);
804 return (4 + x*x*(3*x - 6))/6;
806 return (8 + x*(-12 + x*(6 - x)))/6;
811 static float stbir__filter_catmullrom(float x, float s)
813 STBIR__UNUSED_PARAM(s);
818 return 1 - x*x*(2.5f - 1.5f*x);
820 return 2 - x*(4 + x*(0.5f*x - 2.5f));
825 static float stbir__filter_mitchell(float x, float s)
827 STBIR__UNUSED_PARAM(s);
832 return (16 + x*x*(21 * x - 36))/18;
834 return (32 + x*(-60 + x*(36 - 7*x)))/18;
839 static float stbir__support_zero(float s)
841 STBIR__UNUSED_PARAM(s);
845 static float stbir__support_one(float s)
847 STBIR__UNUSED_PARAM(s);
851 static float stbir__support_two(float s)
853 STBIR__UNUSED_PARAM(s);
857 static stbir__filter_info stbir__filter_info_table[] = {
858 { NULL, stbir__support_zero },
859 { stbir__filter_trapezoid, stbir__support_trapezoid },
860 { stbir__filter_triangle, stbir__support_one },
861 { stbir__filter_cubic, stbir__support_two },
862 { stbir__filter_catmullrom, stbir__support_two },
863 { stbir__filter_mitchell, stbir__support_two },
866 stbir__inline static int stbir__use_upsampling(float ratio)
871 stbir__inline static int stbir__use_width_upsampling(stbir__info* stbir_info)
873 return stbir__use_upsampling(stbir_info->horizontal_scale);
876 stbir__inline static int stbir__use_height_upsampling(stbir__info* stbir_info)
878 return stbir__use_upsampling(stbir_info->vertical_scale);
881 // This is the maximum number of input samples that can affect an output sample
882 // with the given filter
883 static int stbir__get_filter_pixel_width(stbir_filter filter, float scale)
885 STBIR_ASSERT(filter != 0);
886 STBIR_ASSERT(filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
888 if (stbir__use_upsampling(scale))
889 return (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2);
891 return (int)ceil(stbir__filter_info_table[filter].support(scale) * 2 / scale);
894 // This is how much to expand buffers to account for filters seeking outside
895 // the image boundaries.
896 static int stbir__get_filter_pixel_margin(stbir_filter filter, float scale)
898 return stbir__get_filter_pixel_width(filter, scale) / 2;
901 static int stbir__get_coefficient_width(stbir_filter filter, float scale)
903 if (stbir__use_upsampling(scale))
904 return (int)ceil(stbir__filter_info_table[filter].support(1 / scale) * 2);
906 return (int)ceil(stbir__filter_info_table[filter].support(scale) * 2);
909 static int stbir__get_contributors(float scale, stbir_filter filter, int input_size, int output_size)
911 if (stbir__use_upsampling(scale))
914 return (input_size + stbir__get_filter_pixel_margin(filter, scale) * 2);
917 static int stbir__get_total_horizontal_coefficients(stbir__info* info)
919 return info->horizontal_num_contributors
920 * stbir__get_coefficient_width (info->horizontal_filter, info->horizontal_scale);
923 static int stbir__get_total_vertical_coefficients(stbir__info* info)
925 return info->vertical_num_contributors
926 * stbir__get_coefficient_width (info->vertical_filter, info->vertical_scale);
929 static stbir__contributors* stbir__get_contributor(stbir__contributors* contributors, int n)
931 return &contributors[n];
934 // For perf reasons this code is duplicated in stbir__resample_horizontal_upsample/downsample,
935 // if you change it here change it there too.
936 static float* stbir__get_coefficient(float* coefficients, stbir_filter filter, float scale, int n, int c)
938 int width = stbir__get_coefficient_width(filter, scale);
939 return &coefficients[width*n + c];
942 static int stbir__edge_wrap_slow(stbir_edge edge, int n, int max)
946 case STBIR_EDGE_ZERO:
947 return 0; // we'll decode the wrong pixel here, and then overwrite with 0s later
949 case STBIR_EDGE_CLAMP:
956 return n; // NOTREACHED
958 case STBIR_EDGE_REFLECT:
977 return n; // NOTREACHED
980 case STBIR_EDGE_WRAP:
995 STBIR_ASSERT(!"Unimplemented edge type");
1000 stbir__inline static int stbir__edge_wrap(stbir_edge edge, int n, int max)
1002 // avoid per-pixel switch
1003 if (n >= 0 && n < max)
1005 return stbir__edge_wrap_slow(edge, n, max);
1008 // What input pixels contribute to this output pixel?
1009 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)
1011 float out_pixel_center = (float)n + 0.5f;
1012 float out_pixel_influence_lowerbound = out_pixel_center - out_filter_radius;
1013 float out_pixel_influence_upperbound = out_pixel_center + out_filter_radius;
1015 float in_pixel_influence_lowerbound = (out_pixel_influence_lowerbound + out_shift) / scale_ratio;
1016 float in_pixel_influence_upperbound = (out_pixel_influence_upperbound + out_shift) / scale_ratio;
1018 *in_center_of_out = (out_pixel_center + out_shift) / scale_ratio;
1019 *in_first_pixel = (int)(floor(in_pixel_influence_lowerbound + 0.5));
1020 *in_last_pixel = (int)(floor(in_pixel_influence_upperbound - 0.5));
1023 // What output pixels does this input pixel contribute to?
1024 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)
1026 float in_pixel_center = (float)n + 0.5f;
1027 float in_pixel_influence_lowerbound = in_pixel_center - in_pixels_radius;
1028 float in_pixel_influence_upperbound = in_pixel_center + in_pixels_radius;
1030 float out_pixel_influence_lowerbound = in_pixel_influence_lowerbound * scale_ratio - out_shift;
1031 float out_pixel_influence_upperbound = in_pixel_influence_upperbound * scale_ratio - out_shift;
1033 *out_center_of_in = in_pixel_center * scale_ratio - out_shift;
1034 *out_first_pixel = (int)(floor(out_pixel_influence_lowerbound + 0.5));
1035 *out_last_pixel = (int)(floor(out_pixel_influence_upperbound - 0.5));
1038 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)
1041 float total_filter = 0;
1044 STBIR_ASSERT(in_last_pixel - in_first_pixel <= (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical.
1046 contributor->n0 = in_first_pixel;
1047 contributor->n1 = in_last_pixel;
1049 STBIR_ASSERT(contributor->n1 >= contributor->n0);
1051 for (i = 0; i <= in_last_pixel - in_first_pixel; i++)
1053 float in_pixel_center = (float)(i + in_first_pixel) + 0.5f;
1054 coefficient_group[i] = stbir__filter_info_table[filter].kernel(in_center_of_out - in_pixel_center, 1 / scale);
1056 // If the coefficient is zero, skip it. (Don't do the <0 check here, we want the influence of those outside pixels.)
1057 if (i == 0 && !coefficient_group[i])
1059 contributor->n0 = ++in_first_pixel;
1064 total_filter += coefficient_group[i];
1067 STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(in_last_pixel + 1) + 0.5f - in_center_of_out, 1/scale) == 0);
1069 STBIR_ASSERT(total_filter > 0.9);
1070 STBIR_ASSERT(total_filter < 1.1f); // Make sure it's not way off.
1072 // Make sure the sum of all coefficients is 1.
1073 filter_scale = 1 / total_filter;
1075 for (i = 0; i <= in_last_pixel - in_first_pixel; i++)
1076 coefficient_group[i] *= filter_scale;
1078 for (i = in_last_pixel - in_first_pixel; i >= 0; i--)
1080 if (coefficient_group[i])
1083 // This line has no weight. We can skip it.
1084 contributor->n1 = contributor->n0 + i - 1;
1088 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)
1092 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.
1094 contributor->n0 = out_first_pixel;
1095 contributor->n1 = out_last_pixel;
1097 STBIR_ASSERT(contributor->n1 >= contributor->n0);
1099 for (i = 0; i <= out_last_pixel - out_first_pixel; i++)
1101 float out_pixel_center = (float)(i + out_first_pixel) + 0.5f;
1102 float x = out_pixel_center - out_center_of_in;
1103 coefficient_group[i] = stbir__filter_info_table[filter].kernel(x, scale_ratio) * scale_ratio;
1106 STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(out_last_pixel + 1) + 0.5f - out_center_of_in, scale_ratio) == 0);
1108 for (i = out_last_pixel - out_first_pixel; i >= 0; i--)
1110 if (coefficient_group[i])
1113 // This line has no weight. We can skip it.
1114 contributor->n1 = contributor->n0 + i - 1;
1118 static void stbir__normalize_downsample_coefficients(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, int input_size, int output_size)
1120 int num_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size);
1121 int num_coefficients = stbir__get_coefficient_width(filter, scale_ratio);
1125 for (i = 0; i < output_size; i++)
1130 for (j = 0; j < num_contributors; j++)
1132 if (i >= contributors[j].n0 && i <= contributors[j].n1)
1134 float coefficient = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0);
1135 total += coefficient;
1137 else if (i < contributors[j].n0)
1141 STBIR_ASSERT(total > 0.9f);
1142 STBIR_ASSERT(total < 1.1f);
1146 for (j = 0; j < num_contributors; j++)
1148 if (i >= contributors[j].n0 && i <= contributors[j].n1)
1149 *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0) *= scale;
1150 else if (i < contributors[j].n0)
1155 // Optimize: Skip zero coefficients and contributions outside of image bounds.
1156 // Do this after normalizing because normalization depends on the n0/n1 values.
1157 for (j = 0; j < num_contributors; j++)
1159 int range, max, width;
1162 while (*stbir__get_coefficient(coefficients, filter, scale_ratio, j, skip) == 0)
1165 contributors[j].n0 += skip;
1167 while (contributors[j].n0 < 0)
1169 contributors[j].n0++;
1173 range = contributors[j].n1 - contributors[j].n0 + 1;
1174 max = stbir__min(num_coefficients, range);
1176 width = stbir__get_coefficient_width(filter, scale_ratio);
1177 for (i = 0; i < max; i++)
1179 if (i + skip >= width)
1182 *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i) = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i + skip);
1188 // Using min to avoid writing into invalid pixels.
1189 for (i = 0; i < num_contributors; i++)
1190 contributors[i].n1 = stbir__min(contributors[i].n1, output_size - 1);
1193 // Each scan line uses the same kernel values so we should calculate the kernel
1194 // values once and then we can use them for every scan line.
1195 static void stbir__calculate_filters(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, float shift, int input_size, int output_size)
1198 int total_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size);
1200 if (stbir__use_upsampling(scale_ratio))
1202 float out_pixels_radius = stbir__filter_info_table[filter].support(1 / scale_ratio) * scale_ratio;
1204 // Looping through out pixels
1205 for (n = 0; n < total_contributors; n++)
1207 float in_center_of_out; // Center of the current out pixel in the in pixel space
1208 int in_first_pixel, in_last_pixel;
1210 stbir__calculate_sample_range_upsample(n, out_pixels_radius, scale_ratio, shift, &in_first_pixel, &in_last_pixel, &in_center_of_out);
1212 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));
1217 float in_pixels_radius = stbir__filter_info_table[filter].support(scale_ratio) / scale_ratio;
1219 // Looping through in pixels
1220 for (n = 0; n < total_contributors; n++)
1222 float out_center_of_in; // Center of the current out pixel in the in pixel space
1223 int out_first_pixel, out_last_pixel;
1224 int n_adjusted = n - stbir__get_filter_pixel_margin(filter, scale_ratio);
1226 stbir__calculate_sample_range_downsample(n_adjusted, in_pixels_radius, scale_ratio, shift, &out_first_pixel, &out_last_pixel, &out_center_of_in);
1228 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));
1231 stbir__normalize_downsample_coefficients(contributors, coefficients, filter, scale_ratio, input_size, output_size);
1235 static float* stbir__get_decode_buffer(stbir__info* stbir_info)
1237 // The 0 index of the decode buffer starts after the margin. This makes
1238 // it okay to use negative indexes on the decode buffer.
1239 return &stbir_info->decode_buffer[stbir_info->horizontal_filter_pixel_margin * stbir_info->channels];
1242 #define STBIR__DECODE(type, colorspace) ((int)(type) * (STBIR_MAX_COLORSPACES) + (int)(colorspace))
1244 static void stbir__decode_scanline(stbir__info* stbir_info, int n)
1247 int channels = stbir_info->channels;
1248 int alpha_channel = stbir_info->alpha_channel;
1249 int type = stbir_info->type;
1250 int colorspace = stbir_info->colorspace;
1251 int input_w = stbir_info->input_w;
1252 size_t input_stride_bytes = stbir_info->input_stride_bytes;
1253 float* decode_buffer = stbir__get_decode_buffer(stbir_info);
1254 stbir_edge edge_horizontal = stbir_info->edge_horizontal;
1255 stbir_edge edge_vertical = stbir_info->edge_vertical;
1256 size_t in_buffer_row_offset = stbir__edge_wrap(edge_vertical, n, stbir_info->input_h) * input_stride_bytes;
1257 const void* input_data = (char *) stbir_info->input_data + in_buffer_row_offset;
1258 int max_x = input_w + stbir_info->horizontal_filter_pixel_margin;
1259 int decode = STBIR__DECODE(type, colorspace);
1261 int x = -stbir_info->horizontal_filter_pixel_margin;
1263 // special handling for STBIR_EDGE_ZERO because it needs to return an item that doesn't appear in the input,
1264 // and we want to avoid paying overhead on every pixel if not STBIR_EDGE_ZERO
1265 if (edge_vertical == STBIR_EDGE_ZERO && (n < 0 || n >= stbir_info->input_h))
1267 for (; x < max_x; x++)
1268 for (c = 0; c < channels; c++)
1269 decode_buffer[x*channels + c] = 0;
1275 case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR):
1276 for (; x < max_x; x++)
1278 int decode_pixel_index = x * channels;
1279 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1280 for (c = 0; c < channels; c++)
1281 decode_buffer[decode_pixel_index + c] = ((float)((const unsigned char*)input_data)[input_pixel_index + c]) / stbir__max_uint8_as_float;
1285 case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB):
1286 for (; x < max_x; x++)
1288 int decode_pixel_index = x * channels;
1289 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1290 for (c = 0; c < channels; c++)
1291 decode_buffer[decode_pixel_index + c] = stbir__srgb_uchar_to_linear_float[((const unsigned char*)input_data)[input_pixel_index + c]];
1293 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1294 decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned char*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint8_as_float;
1298 case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR):
1299 for (; x < max_x; x++)
1301 int decode_pixel_index = x * channels;
1302 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1303 for (c = 0; c < channels; c++)
1304 decode_buffer[decode_pixel_index + c] = ((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float;
1308 case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB):
1309 for (; x < max_x; x++)
1311 int decode_pixel_index = x * channels;
1312 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1313 for (c = 0; c < channels; c++)
1314 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);
1316 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1317 decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned short*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint16_as_float;
1321 case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR):
1322 for (; x < max_x; x++)
1324 int decode_pixel_index = x * channels;
1325 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1326 for (c = 0; c < channels; c++)
1327 decode_buffer[decode_pixel_index + c] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float);
1331 case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB):
1332 for (; x < max_x; x++)
1334 int decode_pixel_index = x * channels;
1335 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1336 for (c = 0; c < channels; c++)
1337 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));
1339 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1340 decode_buffer[decode_pixel_index + alpha_channel] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint32_as_float);
1344 case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR):
1345 for (; x < max_x; x++)
1347 int decode_pixel_index = x * channels;
1348 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1349 for (c = 0; c < channels; c++)
1350 decode_buffer[decode_pixel_index + c] = ((const float*)input_data)[input_pixel_index + c];
1354 case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB):
1355 for (; x < max_x; x++)
1357 int decode_pixel_index = x * channels;
1358 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1359 for (c = 0; c < channels; c++)
1360 decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((const float*)input_data)[input_pixel_index + c]);
1362 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1363 decode_buffer[decode_pixel_index + alpha_channel] = ((const float*)input_data)[input_pixel_index + alpha_channel];
1369 STBIR_ASSERT(!"Unknown type/colorspace/channels combination.");
1373 if (!(stbir_info->flags & STBIR_FLAG_ALPHA_PREMULTIPLIED))
1375 for (x = -stbir_info->horizontal_filter_pixel_margin; x < max_x; x++)
1377 int decode_pixel_index = x * channels;
1379 // If the alpha value is 0 it will clobber the color values. Make sure it's not.
1380 float alpha = decode_buffer[decode_pixel_index + alpha_channel];
1381 #ifndef STBIR_NO_ALPHA_EPSILON
1382 if (stbir_info->type != STBIR_TYPE_FLOAT) {
1383 alpha += STBIR_ALPHA_EPSILON;
1384 decode_buffer[decode_pixel_index + alpha_channel] = alpha;
1387 for (c = 0; c < channels; c++)
1389 if (c == alpha_channel)
1392 decode_buffer[decode_pixel_index + c] *= alpha;
1397 if (edge_horizontal == STBIR_EDGE_ZERO)
1399 for (x = -stbir_info->horizontal_filter_pixel_margin; x < 0; x++)
1401 for (c = 0; c < channels; c++)
1402 decode_buffer[x*channels + c] = 0;
1404 for (x = input_w; x < max_x; x++)
1406 for (c = 0; c < channels; c++)
1407 decode_buffer[x*channels + c] = 0;
1412 static float* stbir__get_ring_buffer_entry(float* ring_buffer, int index, int ring_buffer_length)
1414 return &ring_buffer[index * ring_buffer_length];
1417 static float* stbir__add_empty_ring_buffer_entry(stbir__info* stbir_info, int n)
1419 int ring_buffer_index;
1422 stbir_info->ring_buffer_last_scanline = n;
1424 if (stbir_info->ring_buffer_begin_index < 0)
1426 ring_buffer_index = stbir_info->ring_buffer_begin_index = 0;
1427 stbir_info->ring_buffer_first_scanline = n;
1431 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;
1432 STBIR_ASSERT(ring_buffer_index != stbir_info->ring_buffer_begin_index);
1435 ring_buffer = stbir__get_ring_buffer_entry(stbir_info->ring_buffer, ring_buffer_index, stbir_info->ring_buffer_length_bytes / sizeof(float));
1436 memset(ring_buffer, 0, stbir_info->ring_buffer_length_bytes);
1442 static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, float* output_buffer)
1445 int output_w = stbir_info->output_w;
1446 int channels = stbir_info->channels;
1447 float* decode_buffer = stbir__get_decode_buffer(stbir_info);
1448 stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors;
1449 float* horizontal_coefficients = stbir_info->horizontal_coefficients;
1450 int coefficient_width = stbir_info->horizontal_coefficient_width;
1452 for (x = 0; x < output_w; x++)
1454 int n0 = horizontal_contributors[x].n0;
1455 int n1 = horizontal_contributors[x].n1;
1457 int out_pixel_index = x * channels;
1458 int coefficient_group = coefficient_width * x;
1459 int coefficient_counter = 0;
1461 STBIR_ASSERT(n1 >= n0);
1462 STBIR_ASSERT(n0 >= -stbir_info->horizontal_filter_pixel_margin);
1463 STBIR_ASSERT(n1 >= -stbir_info->horizontal_filter_pixel_margin);
1464 STBIR_ASSERT(n0 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin);
1465 STBIR_ASSERT(n1 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin);
1469 for (k = n0; k <= n1; k++)
1471 int in_pixel_index = k * 1;
1472 float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
1473 STBIR_ASSERT(coefficient != 0);
1474 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1478 for (k = n0; k <= n1; k++)
1480 int in_pixel_index = k * 2;
1481 float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
1482 STBIR_ASSERT(coefficient != 0);
1483 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1484 output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1488 for (k = n0; k <= n1; k++)
1490 int in_pixel_index = k * 3;
1491 float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
1492 STBIR_ASSERT(coefficient != 0);
1493 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1494 output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1495 output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
1499 for (k = n0; k <= n1; k++)
1501 int in_pixel_index = k * 4;
1502 float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
1503 STBIR_ASSERT(coefficient != 0);
1504 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1505 output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1506 output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
1507 output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient;
1511 for (k = n0; k <= n1; k++)
1513 int in_pixel_index = k * channels;
1514 float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
1516 STBIR_ASSERT(coefficient != 0);
1517 for (c = 0; c < channels; c++)
1518 output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient;
1525 static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, float* output_buffer)
1528 int input_w = stbir_info->input_w;
1529 int channels = stbir_info->channels;
1530 float* decode_buffer = stbir__get_decode_buffer(stbir_info);
1531 stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors;
1532 float* horizontal_coefficients = stbir_info->horizontal_coefficients;
1533 int coefficient_width = stbir_info->horizontal_coefficient_width;
1534 int filter_pixel_margin = stbir_info->horizontal_filter_pixel_margin;
1535 int max_x = input_w + filter_pixel_margin * 2;
1537 STBIR_ASSERT(!stbir__use_width_upsampling(stbir_info));
1541 for (x = 0; x < max_x; x++)
1543 int n0 = horizontal_contributors[x].n0;
1544 int n1 = horizontal_contributors[x].n1;
1546 int in_x = x - filter_pixel_margin;
1547 int in_pixel_index = in_x * 1;
1549 int coefficient_group = coefficient_width * x;
1551 for (k = n0; k <= max_n; k++)
1553 int out_pixel_index = k * 1;
1554 float coefficient = horizontal_coefficients[coefficient_group + k - n0];
1555 STBIR_ASSERT(coefficient != 0);
1556 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1562 for (x = 0; x < max_x; x++)
1564 int n0 = horizontal_contributors[x].n0;
1565 int n1 = horizontal_contributors[x].n1;
1567 int in_x = x - filter_pixel_margin;
1568 int in_pixel_index = in_x * 2;
1570 int coefficient_group = coefficient_width * x;
1572 for (k = n0; k <= max_n; k++)
1574 int out_pixel_index = k * 2;
1575 float coefficient = horizontal_coefficients[coefficient_group + k - n0];
1576 STBIR_ASSERT(coefficient != 0);
1577 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1578 output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1584 for (x = 0; x < max_x; x++)
1586 int n0 = horizontal_contributors[x].n0;
1587 int n1 = horizontal_contributors[x].n1;
1589 int in_x = x - filter_pixel_margin;
1590 int in_pixel_index = in_x * 3;
1592 int coefficient_group = coefficient_width * x;
1594 for (k = n0; k <= max_n; k++)
1596 int out_pixel_index = k * 3;
1597 float coefficient = horizontal_coefficients[coefficient_group + k - n0];
1598 STBIR_ASSERT(coefficient != 0);
1599 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1600 output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1601 output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
1607 for (x = 0; x < max_x; x++)
1609 int n0 = horizontal_contributors[x].n0;
1610 int n1 = horizontal_contributors[x].n1;
1612 int in_x = x - filter_pixel_margin;
1613 int in_pixel_index = in_x * 4;
1615 int coefficient_group = coefficient_width * x;
1617 for (k = n0; k <= max_n; k++)
1619 int out_pixel_index = k * 4;
1620 float coefficient = horizontal_coefficients[coefficient_group + k - n0];
1621 STBIR_ASSERT(coefficient != 0);
1622 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1623 output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1624 output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
1625 output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient;
1631 for (x = 0; x < max_x; x++)
1633 int n0 = horizontal_contributors[x].n0;
1634 int n1 = horizontal_contributors[x].n1;
1636 int in_x = x - filter_pixel_margin;
1637 int in_pixel_index = in_x * channels;
1639 int coefficient_group = coefficient_width * x;
1641 for (k = n0; k <= max_n; k++)
1644 int out_pixel_index = k * channels;
1645 float coefficient = horizontal_coefficients[coefficient_group + k - n0];
1646 STBIR_ASSERT(coefficient != 0);
1647 for (c = 0; c < channels; c++)
1648 output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient;
1655 static void stbir__decode_and_resample_upsample(stbir__info* stbir_info, int n)
1657 // Decode the nth scanline from the source image into the decode buffer.
1658 stbir__decode_scanline(stbir_info, n);
1660 // Now resample it into the ring buffer.
1661 if (stbir__use_width_upsampling(stbir_info))
1662 stbir__resample_horizontal_upsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n));
1664 stbir__resample_horizontal_downsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n));
1666 // Now it's sitting in the ring buffer ready to be used as source for the vertical sampling.
1669 static void stbir__decode_and_resample_downsample(stbir__info* stbir_info, int n)
1671 // Decode the nth scanline from the source image into the decode buffer.
1672 stbir__decode_scanline(stbir_info, n);
1674 memset(stbir_info->horizontal_buffer, 0, stbir_info->output_w * stbir_info->channels * sizeof(float));
1676 // Now resample it into the horizontal buffer.
1677 if (stbir__use_width_upsampling(stbir_info))
1678 stbir__resample_horizontal_upsample(stbir_info, stbir_info->horizontal_buffer);
1680 stbir__resample_horizontal_downsample(stbir_info, stbir_info->horizontal_buffer);
1682 // Now it's sitting in the horizontal buffer ready to be distributed into the ring buffers.
1685 // Get the specified scan line from the ring buffer.
1686 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)
1688 int ring_buffer_index = (begin_index + (get_scanline - first_scanline)) % ring_buffer_num_entries;
1689 return stbir__get_ring_buffer_entry(ring_buffer, ring_buffer_index, ring_buffer_length);
1693 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)
1698 stbir_uint16 nonalpha[STBIR_MAX_CHANNELS];
1700 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_PREMULTIPLIED))
1702 for (x=0; x < num_pixels; ++x)
1704 int pixel_index = x*channels;
1706 float alpha = encode_buffer[pixel_index + alpha_channel];
1707 float reciprocal_alpha = alpha ? 1.0f / alpha : 0;
1709 // unrolling this produced a 1% slowdown upscaling a large RGBA linear-space image on my machine - stb
1710 for (n = 0; n < channels; n++)
1711 if (n != alpha_channel)
1712 encode_buffer[pixel_index + n] *= reciprocal_alpha;
1714 // We added in a small epsilon to prevent the color channel from being deleted with zero alpha.
1715 // Because we only add it for integer types, it will automatically be discarded on integer
1716 // conversion, so we don't need to subtract it back out (which would be problematic for
1717 // numeric precision reasons).
1721 // build a table of all channels that need colorspace correction, so
1722 // we don't perform colorspace correction on channels that don't need it.
1723 for (x = 0, num_nonalpha = 0; x < channels; ++x)
1725 if (x != alpha_channel || (stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE))
1727 nonalpha[num_nonalpha++] = (stbir_uint16)x;
1731 #define STBIR__ROUND_INT(f) ((int) ((f)+0.5))
1732 #define STBIR__ROUND_UINT(f) ((stbir_uint32) ((f)+0.5))
1734 #ifdef STBIR__SATURATE_INT
1735 #define STBIR__ENCODE_LINEAR8(f) stbir__saturate8 (STBIR__ROUND_INT((f) * stbir__max_uint8_as_float ))
1736 #define STBIR__ENCODE_LINEAR16(f) stbir__saturate16(STBIR__ROUND_INT((f) * stbir__max_uint16_as_float))
1738 #define STBIR__ENCODE_LINEAR8(f) (unsigned char ) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint8_as_float )
1739 #define STBIR__ENCODE_LINEAR16(f) (unsigned short) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint16_as_float)
1744 case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR):
1745 for (x=0; x < num_pixels; ++x)
1747 int pixel_index = x*channels;
1749 for (n = 0; n < channels; n++)
1751 int index = pixel_index + n;
1752 ((unsigned char*)output_buffer)[index] = STBIR__ENCODE_LINEAR8(encode_buffer[index]);
1757 case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB):
1758 for (x=0; x < num_pixels; ++x)
1760 int pixel_index = x*channels;
1762 for (n = 0; n < num_nonalpha; n++)
1764 int index = pixel_index + nonalpha[n];
1765 ((unsigned char*)output_buffer)[index] = stbir__linear_to_srgb_uchar(encode_buffer[index]);
1768 if (!(stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE))
1769 ((unsigned char *)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR8(encode_buffer[pixel_index+alpha_channel]);
1773 case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR):
1774 for (x=0; x < num_pixels; ++x)
1776 int pixel_index = x*channels;
1778 for (n = 0; n < channels; n++)
1780 int index = pixel_index + n;
1781 ((unsigned short*)output_buffer)[index] = STBIR__ENCODE_LINEAR16(encode_buffer[index]);
1786 case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB):
1787 for (x=0; x < num_pixels; ++x)
1789 int pixel_index = x*channels;
1791 for (n = 0; n < num_nonalpha; n++)
1793 int index = pixel_index + nonalpha[n];
1794 ((unsigned short*)output_buffer)[index] = (unsigned short)STBIR__ROUND_INT(stbir__linear_to_srgb(stbir__saturate(encode_buffer[index])) * stbir__max_uint16_as_float);
1797 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1798 ((unsigned short*)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR16(encode_buffer[pixel_index + alpha_channel]);
1803 case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR):
1804 for (x=0; x < num_pixels; ++x)
1806 int pixel_index = x*channels;
1808 for (n = 0; n < channels; n++)
1810 int index = pixel_index + n;
1811 ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__saturate(encode_buffer[index])) * stbir__max_uint32_as_float);
1816 case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB):
1817 for (x=0; x < num_pixels; ++x)
1819 int pixel_index = x*channels;
1821 for (n = 0; n < num_nonalpha; n++)
1823 int index = pixel_index + nonalpha[n];
1824 ((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);
1827 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1828 ((unsigned int*)output_buffer)[pixel_index + alpha_channel] = (unsigned int)STBIR__ROUND_INT(((double)stbir__saturate(encode_buffer[pixel_index + alpha_channel])) * stbir__max_uint32_as_float);
1832 case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR):
1833 for (x=0; x < num_pixels; ++x)
1835 int pixel_index = x*channels;
1837 for (n = 0; n < channels; n++)
1839 int index = pixel_index + n;
1840 ((float*)output_buffer)[index] = encode_buffer[index];
1845 case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB):
1846 for (x=0; x < num_pixels; ++x)
1848 int pixel_index = x*channels;
1850 for (n = 0; n < num_nonalpha; n++)
1852 int index = pixel_index + nonalpha[n];
1853 ((float*)output_buffer)[index] = stbir__linear_to_srgb(encode_buffer[index]);
1856 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1857 ((float*)output_buffer)[pixel_index + alpha_channel] = encode_buffer[pixel_index + alpha_channel];
1862 STBIR_ASSERT(!"Unknown type/colorspace/channels combination.");
1867 static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n)
1870 int output_w = stbir_info->output_w;
1871 stbir__contributors* vertical_contributors = stbir_info->vertical_contributors;
1872 float* vertical_coefficients = stbir_info->vertical_coefficients;
1873 int channels = stbir_info->channels;
1874 int alpha_channel = stbir_info->alpha_channel;
1875 int type = stbir_info->type;
1876 int colorspace = stbir_info->colorspace;
1877 int ring_buffer_entries = stbir_info->ring_buffer_num_entries;
1878 void* output_data = stbir_info->output_data;
1879 float* encode_buffer = stbir_info->encode_buffer;
1880 int decode = STBIR__DECODE(type, colorspace);
1881 int coefficient_width = stbir_info->vertical_coefficient_width;
1882 int coefficient_counter;
1883 int contributor = n;
1885 float* ring_buffer = stbir_info->ring_buffer;
1886 int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index;
1887 int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline;
1888 int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
1890 int n0,n1, output_row_start;
1891 int coefficient_group = coefficient_width * contributor;
1893 n0 = vertical_contributors[contributor].n0;
1894 n1 = vertical_contributors[contributor].n1;
1896 output_row_start = n * stbir_info->output_stride_bytes;
1898 STBIR_ASSERT(stbir__use_height_upsampling(stbir_info));
1900 memset(encode_buffer, 0, output_w * sizeof(float) * channels);
1902 // I tried reblocking this for better cache usage of encode_buffer
1903 // (using x_outer, k, x_inner), but it lost speed. -- stb
1905 coefficient_counter = 0;
1908 for (k = n0; k <= n1; k++)
1910 int coefficient_index = coefficient_counter++;
1911 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);
1912 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
1913 for (x = 0; x < output_w; ++x)
1915 int in_pixel_index = x * 1;
1916 encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
1921 for (k = n0; k <= n1; k++)
1923 int coefficient_index = coefficient_counter++;
1924 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);
1925 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
1926 for (x = 0; x < output_w; ++x)
1928 int in_pixel_index = x * 2;
1929 encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
1930 encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
1935 for (k = n0; k <= n1; k++)
1937 int coefficient_index = coefficient_counter++;
1938 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);
1939 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
1940 for (x = 0; x < output_w; ++x)
1942 int in_pixel_index = x * 3;
1943 encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
1944 encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
1945 encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient;
1950 for (k = n0; k <= n1; k++)
1952 int coefficient_index = coefficient_counter++;
1953 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);
1954 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
1955 for (x = 0; x < output_w; ++x)
1957 int in_pixel_index = x * 4;
1958 encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
1959 encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
1960 encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient;
1961 encode_buffer[in_pixel_index + 3] += ring_buffer_entry[in_pixel_index + 3] * coefficient;
1966 for (k = n0; k <= n1; k++)
1968 int coefficient_index = coefficient_counter++;
1969 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);
1970 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
1971 for (x = 0; x < output_w; ++x)
1973 int in_pixel_index = x * channels;
1975 for (c = 0; c < channels; c++)
1976 encode_buffer[in_pixel_index + c] += ring_buffer_entry[in_pixel_index + c] * coefficient;
1981 stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, encode_buffer, channels, alpha_channel, decode);
1984 static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n)
1987 int output_w = stbir_info->output_w;
1988 stbir__contributors* vertical_contributors = stbir_info->vertical_contributors;
1989 float* vertical_coefficients = stbir_info->vertical_coefficients;
1990 int channels = stbir_info->channels;
1991 int ring_buffer_entries = stbir_info->ring_buffer_num_entries;
1992 float* horizontal_buffer = stbir_info->horizontal_buffer;
1993 int coefficient_width = stbir_info->vertical_coefficient_width;
1994 int contributor = n + stbir_info->vertical_filter_pixel_margin;
1996 float* ring_buffer = stbir_info->ring_buffer;
1997 int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index;
1998 int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline;
1999 int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
2002 n0 = vertical_contributors[contributor].n0;
2003 n1 = vertical_contributors[contributor].n1;
2005 STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info));
2007 for (k = n0; k <= n1; k++)
2009 int coefficient_index = k - n0;
2010 int coefficient_group = coefficient_width * contributor;
2011 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
2013 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
2017 for (x = 0; x < output_w; x++)
2019 int in_pixel_index = x * 1;
2020 ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
2024 for (x = 0; x < output_w; x++)
2026 int in_pixel_index = x * 2;
2027 ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
2028 ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
2032 for (x = 0; x < output_w; x++)
2034 int in_pixel_index = x * 3;
2035 ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
2036 ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
2037 ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient;
2041 for (x = 0; x < output_w; x++)
2043 int in_pixel_index = x * 4;
2044 ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
2045 ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
2046 ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient;
2047 ring_buffer_entry[in_pixel_index + 3] += horizontal_buffer[in_pixel_index + 3] * coefficient;
2051 for (x = 0; x < output_w; x++)
2053 int in_pixel_index = x * channels;
2056 for (c = 0; c < channels; c++)
2057 ring_buffer_entry[in_pixel_index + c] += horizontal_buffer[in_pixel_index + c] * coefficient;
2064 static void stbir__buffer_loop_upsample(stbir__info* stbir_info)
2067 float scale_ratio = stbir_info->vertical_scale;
2068 float out_scanlines_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(1/scale_ratio) * scale_ratio;
2070 STBIR_ASSERT(stbir__use_height_upsampling(stbir_info));
2072 for (y = 0; y < stbir_info->output_h; y++)
2074 float in_center_of_out = 0; // Center of the current out scanline in the in scanline space
2075 int in_first_scanline = 0, in_last_scanline = 0;
2077 stbir__calculate_sample_range_upsample(y, out_scanlines_radius, scale_ratio, stbir_info->vertical_shift, &in_first_scanline, &in_last_scanline, &in_center_of_out);
2079 STBIR_ASSERT(in_last_scanline - in_first_scanline + 1 <= stbir_info->ring_buffer_num_entries);
2081 if (stbir_info->ring_buffer_begin_index >= 0)
2083 // Get rid of whatever we don't need anymore.
2084 while (in_first_scanline > stbir_info->ring_buffer_first_scanline)
2086 if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline)
2088 // We just popped the last scanline off the ring buffer.
2089 // Reset it to the empty state.
2090 stbir_info->ring_buffer_begin_index = -1;
2091 stbir_info->ring_buffer_first_scanline = 0;
2092 stbir_info->ring_buffer_last_scanline = 0;
2097 stbir_info->ring_buffer_first_scanline++;
2098 stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries;
2103 // Load in new ones.
2104 if (stbir_info->ring_buffer_begin_index < 0)
2105 stbir__decode_and_resample_upsample(stbir_info, in_first_scanline);
2107 while (in_last_scanline > stbir_info->ring_buffer_last_scanline)
2108 stbir__decode_and_resample_upsample(stbir_info, stbir_info->ring_buffer_last_scanline + 1);
2110 // Now all buffers should be ready to write a row of vertical sampling.
2111 stbir__resample_vertical_upsample(stbir_info, y);
2113 STBIR_PROGRESS_REPORT((float)y / stbir_info->output_h);
2117 static void stbir__empty_ring_buffer(stbir__info* stbir_info, int first_necessary_scanline)
2119 int output_stride_bytes = stbir_info->output_stride_bytes;
2120 int channels = stbir_info->channels;
2121 int alpha_channel = stbir_info->alpha_channel;
2122 int type = stbir_info->type;
2123 int colorspace = stbir_info->colorspace;
2124 int output_w = stbir_info->output_w;
2125 void* output_data = stbir_info->output_data;
2126 int decode = STBIR__DECODE(type, colorspace);
2128 float* ring_buffer = stbir_info->ring_buffer;
2129 int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
2131 if (stbir_info->ring_buffer_begin_index >= 0)
2133 // Get rid of whatever we don't need anymore.
2134 while (first_necessary_scanline > stbir_info->ring_buffer_first_scanline)
2136 if (stbir_info->ring_buffer_first_scanline >= 0 && stbir_info->ring_buffer_first_scanline < stbir_info->output_h)
2138 int output_row_start = stbir_info->ring_buffer_first_scanline * output_stride_bytes;
2139 float* ring_buffer_entry = stbir__get_ring_buffer_entry(ring_buffer, stbir_info->ring_buffer_begin_index, ring_buffer_length);
2140 stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, ring_buffer_entry, channels, alpha_channel, decode);
2141 STBIR_PROGRESS_REPORT((float)stbir_info->ring_buffer_first_scanline / stbir_info->output_h);
2144 if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline)
2146 // We just popped the last scanline off the ring buffer.
2147 // Reset it to the empty state.
2148 stbir_info->ring_buffer_begin_index = -1;
2149 stbir_info->ring_buffer_first_scanline = 0;
2150 stbir_info->ring_buffer_last_scanline = 0;
2155 stbir_info->ring_buffer_first_scanline++;
2156 stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries;
2162 static void stbir__buffer_loop_downsample(stbir__info* stbir_info)
2165 float scale_ratio = stbir_info->vertical_scale;
2166 int output_h = stbir_info->output_h;
2167 float in_pixels_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(scale_ratio) / scale_ratio;
2168 int pixel_margin = stbir_info->vertical_filter_pixel_margin;
2169 int max_y = stbir_info->input_h + pixel_margin;
2171 STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info));
2173 for (y = -pixel_margin; y < max_y; y++)
2175 float out_center_of_in; // Center of the current out scanline in the in scanline space
2176 int out_first_scanline, out_last_scanline;
2178 stbir__calculate_sample_range_downsample(y, in_pixels_radius, scale_ratio, stbir_info->vertical_shift, &out_first_scanline, &out_last_scanline, &out_center_of_in);
2180 STBIR_ASSERT(out_last_scanline - out_first_scanline + 1 <= stbir_info->ring_buffer_num_entries);
2182 if (out_last_scanline < 0 || out_first_scanline >= output_h)
2185 stbir__empty_ring_buffer(stbir_info, out_first_scanline);
2187 stbir__decode_and_resample_downsample(stbir_info, y);
2189 // Load in new ones.
2190 if (stbir_info->ring_buffer_begin_index < 0)
2191 stbir__add_empty_ring_buffer_entry(stbir_info, out_first_scanline);
2193 while (out_last_scanline > stbir_info->ring_buffer_last_scanline)
2194 stbir__add_empty_ring_buffer_entry(stbir_info, stbir_info->ring_buffer_last_scanline + 1);
2196 // Now the horizontal buffer is ready to write to all ring buffer rows.
2197 stbir__resample_vertical_downsample(stbir_info, y);
2200 stbir__empty_ring_buffer(stbir_info, stbir_info->output_h);
2203 static void stbir__setup(stbir__info *info, int input_w, int input_h, int output_w, int output_h, int channels)
2205 info->input_w = input_w;
2206 info->input_h = input_h;
2207 info->output_w = output_w;
2208 info->output_h = output_h;
2209 info->channels = channels;
2212 static void stbir__calculate_transform(stbir__info *info, float s0, float t0, float s1, float t1, float *transform)
2221 info->horizontal_scale = transform[0];
2222 info->vertical_scale = transform[1];
2223 info->horizontal_shift = transform[2];
2224 info->vertical_shift = transform[3];
2228 info->horizontal_scale = ((float)info->output_w / info->input_w) / (s1 - s0);
2229 info->vertical_scale = ((float)info->output_h / info->input_h) / (t1 - t0);
2231 info->horizontal_shift = s0 * info->output_w / (s1 - s0);
2232 info->vertical_shift = t0 * info->output_h / (t1 - t0);
2236 static void stbir__choose_filter(stbir__info *info, stbir_filter h_filter, stbir_filter v_filter)
2239 h_filter = stbir__use_upsampling(info->horizontal_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE;
2241 v_filter = stbir__use_upsampling(info->vertical_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE;
2242 info->horizontal_filter = h_filter;
2243 info->vertical_filter = v_filter;
2246 static stbir_uint32 stbir__calculate_memory(stbir__info *info)
2248 int pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale);
2249 int filter_height = stbir__get_filter_pixel_width(info->vertical_filter, info->vertical_scale);
2251 info->horizontal_num_contributors = stbir__get_contributors(info->horizontal_scale, info->horizontal_filter, info->input_w, info->output_w);
2252 info->vertical_num_contributors = stbir__get_contributors(info->vertical_scale , info->vertical_filter , info->input_h, info->output_h);
2254 // One extra entry because floating point precision problems sometimes cause an extra to be necessary.
2255 info->ring_buffer_num_entries = filter_height + 1;
2257 info->horizontal_contributors_size = info->horizontal_num_contributors * sizeof(stbir__contributors);
2258 info->horizontal_coefficients_size = stbir__get_total_horizontal_coefficients(info) * sizeof(float);
2259 info->vertical_contributors_size = info->vertical_num_contributors * sizeof(stbir__contributors);
2260 info->vertical_coefficients_size = stbir__get_total_vertical_coefficients(info) * sizeof(float);
2261 info->decode_buffer_size = (info->input_w + pixel_margin * 2) * info->channels * sizeof(float);
2262 info->horizontal_buffer_size = info->output_w * info->channels * sizeof(float);
2263 info->ring_buffer_size = info->output_w * info->channels * info->ring_buffer_num_entries * sizeof(float);
2264 info->encode_buffer_size = info->output_w * info->channels * sizeof(float);
2266 STBIR_ASSERT(info->horizontal_filter != 0);
2267 STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); // this now happens too late
2268 STBIR_ASSERT(info->vertical_filter != 0);
2269 STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); // this now happens too late
2271 if (stbir__use_height_upsampling(info))
2272 // The horizontal buffer is for when we're downsampling the height and we
2273 // can't output the result of sampling the decode buffer directly into the
2275 info->horizontal_buffer_size = 0;
2277 // The encode buffer is to retain precision in the height upsampling method
2278 // and isn't used when height downsampling.
2279 info->encode_buffer_size = 0;
2281 return info->horizontal_contributors_size + info->horizontal_coefficients_size
2282 + info->vertical_contributors_size + info->vertical_coefficients_size
2283 + info->decode_buffer_size + info->horizontal_buffer_size
2284 + info->ring_buffer_size + info->encode_buffer_size;
2287 static int stbir__resize_allocated(stbir__info *info,
2288 const void* input_data, int input_stride_in_bytes,
2289 void* output_data, int output_stride_in_bytes,
2290 int alpha_channel, stbir_uint32 flags, stbir_datatype type,
2291 stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace,
2292 void* tempmem, size_t tempmem_size_in_bytes)
2294 size_t memory_required = stbir__calculate_memory(info);
2296 int width_stride_input = input_stride_in_bytes ? input_stride_in_bytes : info->channels * info->input_w * stbir__type_size[type];
2297 int width_stride_output = output_stride_in_bytes ? output_stride_in_bytes : info->channels * info->output_w * stbir__type_size[type];
2299 #ifdef STBIR_DEBUG_OVERWRITE_TEST
2300 #define OVERWRITE_ARRAY_SIZE 8
2301 unsigned char overwrite_output_before_pre[OVERWRITE_ARRAY_SIZE];
2302 unsigned char overwrite_tempmem_before_pre[OVERWRITE_ARRAY_SIZE];
2303 unsigned char overwrite_output_after_pre[OVERWRITE_ARRAY_SIZE];
2304 unsigned char overwrite_tempmem_after_pre[OVERWRITE_ARRAY_SIZE];
2306 size_t begin_forbidden = width_stride_output * (info->output_h - 1) + info->output_w * info->channels * stbir__type_size[type];
2307 memcpy(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE);
2308 memcpy(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE);
2309 memcpy(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE);
2310 memcpy(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE);
2313 STBIR_ASSERT(info->channels >= 0);
2314 STBIR_ASSERT(info->channels <= STBIR_MAX_CHANNELS);
2316 if (info->channels < 0 || info->channels > STBIR_MAX_CHANNELS)
2319 STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
2320 STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
2322 if (info->horizontal_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table))
2324 if (info->vertical_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table))
2327 if (alpha_channel < 0)
2328 flags |= STBIR_FLAG_ALPHA_USES_COLORSPACE | STBIR_FLAG_ALPHA_PREMULTIPLIED;
2330 if (!(flags&STBIR_FLAG_ALPHA_USES_COLORSPACE) || !(flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)) {
2331 STBIR_ASSERT(alpha_channel >= 0 && alpha_channel < info->channels);
2334 if (alpha_channel >= info->channels)
2337 STBIR_ASSERT(tempmem);
2342 STBIR_ASSERT(tempmem_size_in_bytes >= memory_required);
2344 if (tempmem_size_in_bytes < memory_required)
2347 memset(tempmem, 0, tempmem_size_in_bytes);
2349 info->input_data = input_data;
2350 info->input_stride_bytes = width_stride_input;
2352 info->output_data = output_data;
2353 info->output_stride_bytes = width_stride_output;
2355 info->alpha_channel = alpha_channel;
2356 info->flags = flags;
2358 info->edge_horizontal = edge_horizontal;
2359 info->edge_vertical = edge_vertical;
2360 info->colorspace = colorspace;
2362 info->horizontal_coefficient_width = stbir__get_coefficient_width (info->horizontal_filter, info->horizontal_scale);
2363 info->vertical_coefficient_width = stbir__get_coefficient_width (info->vertical_filter , info->vertical_scale );
2364 info->horizontal_filter_pixel_width = stbir__get_filter_pixel_width (info->horizontal_filter, info->horizontal_scale);
2365 info->vertical_filter_pixel_width = stbir__get_filter_pixel_width (info->vertical_filter , info->vertical_scale );
2366 info->horizontal_filter_pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale);
2367 info->vertical_filter_pixel_margin = stbir__get_filter_pixel_margin(info->vertical_filter , info->vertical_scale );
2369 info->ring_buffer_length_bytes = info->output_w * info->channels * sizeof(float);
2370 info->decode_buffer_pixels = info->input_w + info->horizontal_filter_pixel_margin * 2;
2372 #define STBIR__NEXT_MEMPTR(current, newtype) (newtype*)(((unsigned char*)current) + current##_size)
2374 info->horizontal_contributors = (stbir__contributors *) tempmem;
2375 info->horizontal_coefficients = STBIR__NEXT_MEMPTR(info->horizontal_contributors, float);
2376 info->vertical_contributors = STBIR__NEXT_MEMPTR(info->horizontal_coefficients, stbir__contributors);
2377 info->vertical_coefficients = STBIR__NEXT_MEMPTR(info->vertical_contributors, float);
2378 info->decode_buffer = STBIR__NEXT_MEMPTR(info->vertical_coefficients, float);
2380 if (stbir__use_height_upsampling(info))
2382 info->horizontal_buffer = NULL;
2383 info->ring_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float);
2384 info->encode_buffer = STBIR__NEXT_MEMPTR(info->ring_buffer, float);
2386 STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->encode_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes);
2390 info->horizontal_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float);
2391 info->ring_buffer = STBIR__NEXT_MEMPTR(info->horizontal_buffer, float);
2392 info->encode_buffer = NULL;
2394 STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->ring_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes);
2397 #undef STBIR__NEXT_MEMPTR
2399 // This signals that the ring buffer is empty
2400 info->ring_buffer_begin_index = -1;
2402 stbir__calculate_filters(info->horizontal_contributors, info->horizontal_coefficients, info->horizontal_filter, info->horizontal_scale, info->horizontal_shift, info->input_w, info->output_w);
2403 stbir__calculate_filters(info->vertical_contributors, info->vertical_coefficients, info->vertical_filter, info->vertical_scale, info->vertical_shift, info->input_h, info->output_h);
2405 STBIR_PROGRESS_REPORT(0);
2407 if (stbir__use_height_upsampling(info))
2408 stbir__buffer_loop_upsample(info);
2410 stbir__buffer_loop_downsample(info);
2412 STBIR_PROGRESS_REPORT(1);
2414 #ifdef STBIR_DEBUG_OVERWRITE_TEST
2415 STBIR_ASSERT(memcmp(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0);
2416 STBIR_ASSERT(memcmp(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE) == 0);
2417 STBIR_ASSERT(memcmp(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0);
2418 STBIR_ASSERT(memcmp(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE) == 0);
2425 static int stbir__resize_arbitrary(
2426 void *alloc_context,
2427 const void* input_data, int input_w, int input_h, int input_stride_in_bytes,
2428 void* output_data, int output_w, int output_h, int output_stride_in_bytes,
2429 float s0, float t0, float s1, float t1, float *transform,
2430 int channels, int alpha_channel, stbir_uint32 flags, stbir_datatype type,
2431 stbir_filter h_filter, stbir_filter v_filter,
2432 stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace)
2436 size_t memory_required;
2439 stbir__setup(&info, input_w, input_h, output_w, output_h, channels);
2440 stbir__calculate_transform(&info, s0,t0,s1,t1,transform);
2441 stbir__choose_filter(&info, h_filter, v_filter);
2442 memory_required = stbir__calculate_memory(&info);
2443 extra_memory = STBIR_MALLOC(memory_required, alloc_context);
2448 result = stbir__resize_allocated(&info, input_data, input_stride_in_bytes,
2449 output_data, output_stride_in_bytes,
2450 alpha_channel, flags, type,
2451 edge_horizontal, edge_vertical,
2452 colorspace, extra_memory, memory_required);
2454 STBIR_FREE(extra_memory, alloc_context);
2459 STBIRDEF int stbir_resize_uint8( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
2460 unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
2463 return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
2464 output_pixels, output_w, output_h, output_stride_in_bytes,
2465 0,0,1,1,NULL,num_channels,-1,0, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
2466 STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR);
2469 STBIRDEF int stbir_resize_float( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
2470 float *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
2473 return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
2474 output_pixels, output_w, output_h, output_stride_in_bytes,
2475 0,0,1,1,NULL,num_channels,-1,0, STBIR_TYPE_FLOAT, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
2476 STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR);
2479 STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
2480 unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
2481 int num_channels, int alpha_channel, int flags)
2483 return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
2484 output_pixels, output_w, output_h, output_stride_in_bytes,
2485 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
2486 STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB);
2489 STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
2490 unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
2491 int num_channels, int alpha_channel, int flags,
2492 stbir_edge edge_wrap_mode)
2494 return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
2495 output_pixels, output_w, output_h, output_stride_in_bytes,
2496 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
2497 edge_wrap_mode, edge_wrap_mode, STBIR_COLORSPACE_SRGB);
2500 STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
2501 unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
2502 int num_channels, int alpha_channel, int flags,
2503 stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
2504 void *alloc_context)
2506 return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
2507 output_pixels, output_w, output_h, output_stride_in_bytes,
2508 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, filter, filter,
2509 edge_wrap_mode, edge_wrap_mode, space);
2512 STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
2513 stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
2514 int num_channels, int alpha_channel, int flags,
2515 stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
2516 void *alloc_context)
2518 return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
2519 output_pixels, output_w, output_h, output_stride_in_bytes,
2520 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT16, filter, filter,
2521 edge_wrap_mode, edge_wrap_mode, space);
2525 STBIRDEF int stbir_resize_float_generic( const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
2526 float *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
2527 int num_channels, int alpha_channel, int flags,
2528 stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
2529 void *alloc_context)
2531 return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
2532 output_pixels, output_w, output_h, output_stride_in_bytes,
2533 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_FLOAT, filter, filter,
2534 edge_wrap_mode, edge_wrap_mode, space);
2538 STBIRDEF int stbir_resize( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
2539 void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
2540 stbir_datatype datatype,
2541 int num_channels, int alpha_channel, int flags,
2542 stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
2543 stbir_filter filter_horizontal, stbir_filter filter_vertical,
2544 stbir_colorspace space, void *alloc_context)
2546 return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
2547 output_pixels, output_w, output_h, output_stride_in_bytes,
2548 0,0,1,1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
2549 edge_mode_horizontal, edge_mode_vertical, space);
2553 STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
2554 void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
2555 stbir_datatype datatype,
2556 int num_channels, int alpha_channel, int flags,
2557 stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
2558 stbir_filter filter_horizontal, stbir_filter filter_vertical,
2559 stbir_colorspace space, void *alloc_context,
2560 float x_scale, float y_scale,
2561 float x_offset, float y_offset)
2564 transform[0] = x_scale;
2565 transform[1] = y_scale;
2566 transform[2] = x_offset;
2567 transform[3] = y_offset;
2568 return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
2569 output_pixels, output_w, output_h, output_stride_in_bytes,
2570 0,0,1,1,transform,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
2571 edge_mode_horizontal, edge_mode_vertical, space);
2574 STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
2575 void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
2576 stbir_datatype datatype,
2577 int num_channels, int alpha_channel, int flags,
2578 stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
2579 stbir_filter filter_horizontal, stbir_filter filter_vertical,
2580 stbir_colorspace space, void *alloc_context,
2581 float s0, float t0, float s1, float t1)
2583 return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
2584 output_pixels, output_w, output_h, output_stride_in_bytes,
2585 s0,t0,s1,t1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
2586 edge_mode_horizontal, edge_mode_vertical, space);
2589 #endif // STB_IMAGE_RESIZE_IMPLEMENTATION
2592 ------------------------------------------------------------------------------
2593 This software is available under 2 licenses -- choose whichever you prefer.
2594 ------------------------------------------------------------------------------
2595 ALTERNATIVE A - MIT License
2596 Copyright (c) 2017 Sean Barrett
2597 Permission is hereby granted, free of charge, to any person obtaining a copy of
2598 this software and associated documentation files (the "Software"), to deal in
2599 the Software without restriction, including without limitation the rights to
2600 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
2601 of the Software, and to permit persons to whom the Software is furnished to do
2602 so, subject to the following conditions:
2603 The above copyright notice and this permission notice shall be included in all
2604 copies or substantial portions of the Software.
2605 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2606 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2607 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2608 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2609 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2610 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2612 ------------------------------------------------------------------------------
2613 ALTERNATIVE B - Public Domain (www.unlicense.org)
2614 This is free and unencumbered software released into the public domain.
2615 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
2616 software, either in source code form or as a compiled binary, for any purpose,
2617 commercial or non-commercial, and by any means.
2618 In jurisdictions that recognize copyright laws, the author or authors of this
2619 software dedicate any and all copyright interest in the software to the public
2620 domain. We make this dedication for the benefit of the public at large and to
2621 the detriment of our heirs and successors. We intend this dedication to be an
2622 overt act of relinquishment in perpetuity of all present and future rights to
2623 this software under copyright law.
2624 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2625 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2626 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2627 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2628 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
2629 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2630 ------------------------------------------------------------------------------