1 /* stb_image_resize - v0.92 - 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 average of 1% opaque bright green
111 and 99% opaque black produces 50% transparent dark green when
112 non-premultiplied, whereas premultiplied it produces 50%
113 transparent near-black. The former introduces green energy
114 that doesn't exist in the source image.)
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.)
155 ADDITIONAL CONTRIBUTORS
156 Sean Barrett: API design, optimizations
157 Aras Pranckevicius: bugfix
160 0.92 (2017-01-02) fix integer overflow on large (>2GB) images
161 0.91 (2016-04-02) fix warnings; fix handling of subpixel regions
162 0.90 (2014-09-17) first released version
166 This software is dual-licensed to the public domain and under the following
167 license: you are granted a perpetual, irrevocable license to copy, modify,
168 publish, and distribute this file as you see fit.
171 Don't decode all of the image data when only processing a partial tile
172 Don't use full-width decode buffers when only processing a partial tile
173 When processing wide images, break processing into tiles so data fits in L1 cache
175 Resize that respects alpha test coverage
176 (Reference code: FloatImage::alphaTestCoverage and FloatImage::scaleAlphaToCoverage:
177 https://code.google.com/p/nvidia-texture-tools/source/browse/trunk/src/nvimage/FloatImage.cpp )
180 #ifndef STBIR_INCLUDE_STB_IMAGE_RESIZE_H
181 #define STBIR_INCLUDE_STB_IMAGE_RESIZE_H
184 typedef unsigned char stbir_uint8
;
185 typedef unsigned short stbir_uint16
;
186 typedef unsigned int stbir_uint32
;
189 typedef uint8_t stbir_uint8
;
190 typedef uint16_t stbir_uint16
;
191 typedef uint32_t stbir_uint32
;
194 #ifdef STB_IMAGE_RESIZE_STATIC
195 #define STBIRDEF static
198 #define STBIRDEF extern "C"
200 #define STBIRDEF extern
205 //////////////////////////////////////////////////////////////////////////////
209 // * "input pixels" points to an array of image data with 'num_channels' channels (e.g. RGB=3, RGBA=4)
210 // * input_w is input image width (x-axis), input_h is input image height (y-axis)
211 // * stride is the offset between successive rows of image data in memory, in bytes. you can
212 // specify 0 to mean packed continuously in memory
213 // * alpha channel is treated identically to other channels.
214 // * colorspace is linear or sRGB as specified by function name
215 // * returned result is 1 for success or 0 in case of an error.
216 // #define STBIR_ASSERT() to trigger an assert on parameter validation errors.
217 // * Memory required grows approximately linearly with input and output size, but with
218 // discontinuities at input_w == output_w and input_h == output_h.
219 // * These functions use a "default" resampling filter defined at compile time. To change the filter,
220 // you can change the compile-time defaults by #defining STBIR_DEFAULT_FILTER_UPSAMPLE
221 // and STBIR_DEFAULT_FILTER_DOWNSAMPLE, or you can use the medium-complexity API.
223 STBIRDEF
int stbir_resize_uint8( const unsigned char *input_pixels
, int input_w
, int input_h
, int input_stride_in_bytes
,
224 unsigned char *output_pixels
, int output_w
, int output_h
, int output_stride_in_bytes
,
227 STBIRDEF
int stbir_resize_float( const float *input_pixels
, int input_w
, int input_h
, int input_stride_in_bytes
,
228 float *output_pixels
, int output_w
, int output_h
, int output_stride_in_bytes
,
232 // The following functions interpret image data as gamma-corrected sRGB.
233 // Specify STBIR_ALPHA_CHANNEL_NONE if you have no alpha channel,
234 // or otherwise provide the index of the alpha channel. Flags value
235 // of 0 will probably do the right thing if you're not sure what
238 #define STBIR_ALPHA_CHANNEL_NONE -1
240 // Set this flag if your texture has premultiplied alpha. Otherwise, stbir will
241 // use alpha-weighted resampling (effectively premultiplying, resampling,
242 // then unpremultiplying).
243 #define STBIR_FLAG_ALPHA_PREMULTIPLIED (1 << 0)
244 // The specified alpha channel should be handled as gamma-corrected value even
245 // when doing sRGB operations.
246 #define STBIR_FLAG_ALPHA_USES_COLORSPACE (1 << 1)
248 STBIRDEF
int stbir_resize_uint8_srgb(const unsigned char *input_pixels
, int input_w
, int input_h
, int input_stride_in_bytes
,
249 unsigned char *output_pixels
, int output_w
, int output_h
, int output_stride_in_bytes
,
250 int num_channels
, int alpha_channel
, int flags
);
255 STBIR_EDGE_CLAMP
= 1,
256 STBIR_EDGE_REFLECT
= 2,
261 // This function adds the ability to specify how requests to sample off the edge of the image are handled.
262 STBIRDEF
int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels
, int input_w
, int input_h
, int input_stride_in_bytes
,
263 unsigned char *output_pixels
, int output_w
, int output_h
, int output_stride_in_bytes
,
264 int num_channels
, int alpha_channel
, int flags
,
265 stbir_edge edge_wrap_mode
);
267 //////////////////////////////////////////////////////////////////////////////
269 // Medium-complexity API
271 // This extends the easy-to-use API as follows:
273 // * Alpha-channel can be processed separately
274 // * If alpha_channel is not STBIR_ALPHA_CHANNEL_NONE
275 // * Alpha channel will not be gamma corrected (unless flags&STBIR_FLAG_GAMMA_CORRECT)
276 // * Filters will be weighted by alpha channel (unless flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)
277 // * Filter can be selected explicitly
278 // * uint16 image type
279 // * sRGB colorspace available for all types
280 // * context parameter for passing to STBIR_MALLOC
284 STBIR_FILTER_DEFAULT
= 0, // use same filter type that easy-to-use API chooses
285 STBIR_FILTER_BOX
= 1, // A trapezoid w/1-pixel wide ramps, same result as box for integer scale ratios
286 STBIR_FILTER_TRIANGLE
= 2, // On upsampling, produces same results as bilinear texture filtering
287 STBIR_FILTER_CUBICBSPLINE
= 3, // The cubic b-spline (aka Mitchell-Netrevalli with B=1,C=0), gaussian-esque
288 STBIR_FILTER_CATMULLROM
= 4, // An interpolating cubic spline
289 STBIR_FILTER_MITCHELL
= 5, // Mitchell-Netrevalli filter with B=1/3, C=1/3
294 STBIR_COLORSPACE_LINEAR
,
295 STBIR_COLORSPACE_SRGB
,
297 STBIR_MAX_COLORSPACES
,
300 // The following functions are all identical except for the type of the image data
302 STBIRDEF
int stbir_resize_uint8_generic( const unsigned char *input_pixels
, int input_w
, int input_h
, int input_stride_in_bytes
,
303 unsigned char *output_pixels
, int output_w
, int output_h
, int output_stride_in_bytes
,
304 int num_channels
, int alpha_channel
, int flags
,
305 stbir_edge edge_wrap_mode
, stbir_filter filter
, stbir_colorspace space
,
306 void *alloc_context
);
308 STBIRDEF
int stbir_resize_uint16_generic(const stbir_uint16
*input_pixels
, int input_w
, int input_h
, int input_stride_in_bytes
,
309 stbir_uint16
*output_pixels
, int output_w
, int output_h
, int output_stride_in_bytes
,
310 int num_channels
, int alpha_channel
, int flags
,
311 stbir_edge edge_wrap_mode
, stbir_filter filter
, stbir_colorspace space
,
312 void *alloc_context
);
314 STBIRDEF
int stbir_resize_float_generic( const float *input_pixels
, int input_w
, int input_h
, int input_stride_in_bytes
,
315 float *output_pixels
, int output_w
, int output_h
, int output_stride_in_bytes
,
316 int num_channels
, int alpha_channel
, int flags
,
317 stbir_edge edge_wrap_mode
, stbir_filter filter
, stbir_colorspace space
,
318 void *alloc_context
);
322 //////////////////////////////////////////////////////////////////////////////
324 // Full-complexity API
326 // This extends the medium API as follows:
328 // * uint32 image type
330 // * separate filter types for each axis
331 // * separate edge modes for each axis
332 // * can specify scale explicitly for subpixel correctness
333 // * can specify image source tile using texture coordinates
345 STBIRDEF
int stbir_resize( const void *input_pixels
, int input_w
, int input_h
, int input_stride_in_bytes
,
346 void *output_pixels
, int output_w
, int output_h
, int output_stride_in_bytes
,
347 stbir_datatype datatype
,
348 int num_channels
, int alpha_channel
, int flags
,
349 stbir_edge edge_mode_horizontal
, stbir_edge edge_mode_vertical
,
350 stbir_filter filter_horizontal
, stbir_filter filter_vertical
,
351 stbir_colorspace space
, void *alloc_context
);
353 STBIRDEF
int stbir_resize_subpixel(const void *input_pixels
, int input_w
, int input_h
, int input_stride_in_bytes
,
354 void *output_pixels
, int output_w
, int output_h
, int output_stride_in_bytes
,
355 stbir_datatype datatype
,
356 int num_channels
, int alpha_channel
, int flags
,
357 stbir_edge edge_mode_horizontal
, stbir_edge edge_mode_vertical
,
358 stbir_filter filter_horizontal
, stbir_filter filter_vertical
,
359 stbir_colorspace space
, void *alloc_context
,
360 float x_scale
, float y_scale
,
361 float x_offset
, float y_offset
);
363 STBIRDEF
int stbir_resize_region( const void *input_pixels
, int input_w
, int input_h
, int input_stride_in_bytes
,
364 void *output_pixels
, int output_w
, int output_h
, int output_stride_in_bytes
,
365 stbir_datatype datatype
,
366 int num_channels
, int alpha_channel
, int flags
,
367 stbir_edge edge_mode_horizontal
, stbir_edge edge_mode_vertical
,
368 stbir_filter filter_horizontal
, stbir_filter filter_vertical
,
369 stbir_colorspace space
, void *alloc_context
,
370 float s0
, float t0
, float s1
, float t1
);
371 // (s0, t0) & (s1, t1) are the top-left and bottom right corner (uv addressing style: [0, 1]x[0, 1]) of a region of the input image to use.
375 //// end header file /////////////////////////////////////////////////////
376 #endif // STBIR_INCLUDE_STB_IMAGE_RESIZE_H
382 #ifdef STB_IMAGE_RESIZE_IMPLEMENTATION
386 #define STBIR_ASSERT(x) assert(x)
396 #define STBIR_MALLOC(size,c) malloc(size)
397 #define STBIR_FREE(ptr,c) free(ptr)
402 #define stbir__inline inline
404 #define stbir__inline
407 #define stbir__inline __forceinline
411 // should produce compiler error if size is wrong
412 typedef unsigned char stbir__validate_uint32
[sizeof(stbir_uint32
) == 4 ? 1 : -1];
415 #define STBIR__NOTUSED(v) (void)(v)
417 #define STBIR__NOTUSED(v) (void)sizeof(v)
420 #define STBIR__ARRAY_SIZE(a) (sizeof((a))/sizeof((a)[0]))
422 #ifndef STBIR_DEFAULT_FILTER_UPSAMPLE
423 #define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM
426 #ifndef STBIR_DEFAULT_FILTER_DOWNSAMPLE
427 #define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL
430 #ifndef STBIR_PROGRESS_REPORT
431 #define STBIR_PROGRESS_REPORT(float_0_to_1)
434 #ifndef STBIR_MAX_CHANNELS
435 #define STBIR_MAX_CHANNELS 64
438 #if STBIR_MAX_CHANNELS > 65536
439 #error "Too many channels; STBIR_MAX_CHANNELS must be no more than 65536."
440 // because we store the indices in 16-bit variables
443 // This value is added to alpha just before premultiplication to avoid
444 // zeroing out color values. It is equivalent to 2^-80. If you don't want
445 // that behavior (it may interfere if you have floating point images with
446 // very small alpha values) then you can define STBIR_NO_ALPHA_EPSILON to
448 #ifndef STBIR_ALPHA_EPSILON
449 #define STBIR_ALPHA_EPSILON ((float)1 / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20))
455 #define STBIR__UNUSED_PARAM(v) (void)(v)
457 #define STBIR__UNUSED_PARAM(v) (void)sizeof(v)
460 // must match stbir_datatype
461 static unsigned char stbir__type_size
[] = {
462 1, // STBIR_TYPE_UINT8
463 2, // STBIR_TYPE_UINT16
464 4, // STBIR_TYPE_UINT32
465 4, // STBIR_TYPE_FLOAT
468 // Kernel function centered at 0
469 typedef float (stbir__kernel_fn
)(float x
, float scale
);
470 typedef float (stbir__support_fn
)(float scale
);
474 stbir__kernel_fn
* kernel
;
475 stbir__support_fn
* support
;
476 } stbir__filter_info
;
478 // When upsampling, the contributors are which source pixels contribute.
479 // When downsampling, the contributors are which destination pixels are contributed to.
482 int n0
; // First contributing pixel
483 int n1
; // Last contributing pixel
484 } stbir__contributors
;
488 const void* input_data
;
491 int input_stride_bytes
;
496 int output_stride_bytes
;
498 float s0
, t0
, s1
, t1
;
500 float horizontal_shift
; // Units: output pixels
501 float vertical_shift
; // Units: output pixels
502 float horizontal_scale
;
503 float vertical_scale
;
509 stbir_filter horizontal_filter
;
510 stbir_filter vertical_filter
;
511 stbir_edge edge_horizontal
;
512 stbir_edge edge_vertical
;
513 stbir_colorspace colorspace
;
515 stbir__contributors
* horizontal_contributors
;
516 float* horizontal_coefficients
;
518 stbir__contributors
* vertical_contributors
;
519 float* vertical_coefficients
;
521 int decode_buffer_pixels
;
522 float* decode_buffer
;
524 float* horizontal_buffer
;
526 // cache these because ceil/floor are inexplicably showing up in profile
527 int horizontal_coefficient_width
;
528 int vertical_coefficient_width
;
529 int horizontal_filter_pixel_width
;
530 int vertical_filter_pixel_width
;
531 int horizontal_filter_pixel_margin
;
532 int vertical_filter_pixel_margin
;
533 int horizontal_num_contributors
;
534 int vertical_num_contributors
;
536 int ring_buffer_length_bytes
; // The length of an individual entry in the ring buffer. The total number of ring buffers is stbir__get_filter_pixel_width(filter)
537 int ring_buffer_first_scanline
;
538 int ring_buffer_last_scanline
;
539 int ring_buffer_begin_index
;
542 float* encode_buffer
; // A temporary buffer to store floats so we don't lose precision while we do multiply-adds.
544 int horizontal_contributors_size
;
545 int horizontal_coefficients_size
;
546 int vertical_contributors_size
;
547 int vertical_coefficients_size
;
548 int decode_buffer_size
;
549 int horizontal_buffer_size
;
550 int ring_buffer_size
;
551 int encode_buffer_size
;
554 static stbir__inline
int stbir__min(int a
, int b
)
556 return a
< b
? a
: b
;
559 static stbir__inline
int stbir__max(int a
, int b
)
561 return a
> b
? a
: b
;
564 static stbir__inline
float stbir__saturate(float x
)
575 #ifdef STBIR_SATURATE_INT
576 static stbir__inline stbir_uint8
stbir__saturate8(int x
)
578 if ((unsigned int) x
<= 255)
587 static stbir__inline stbir_uint16
stbir__saturate16(int x
)
589 if ((unsigned int) x
<= 65535)
599 static float stbir__srgb_uchar_to_linear_float
[256] = {
600 0.000000f
, 0.000304f
, 0.000607f
, 0.000911f
, 0.001214f
, 0.001518f
, 0.001821f
, 0.002125f
, 0.002428f
, 0.002732f
, 0.003035f
,
601 0.003347f
, 0.003677f
, 0.004025f
, 0.004391f
, 0.004777f
, 0.005182f
, 0.005605f
, 0.006049f
, 0.006512f
, 0.006995f
, 0.007499f
,
602 0.008023f
, 0.008568f
, 0.009134f
, 0.009721f
, 0.010330f
, 0.010960f
, 0.011612f
, 0.012286f
, 0.012983f
, 0.013702f
, 0.014444f
,
603 0.015209f
, 0.015996f
, 0.016807f
, 0.017642f
, 0.018500f
, 0.019382f
, 0.020289f
, 0.021219f
, 0.022174f
, 0.023153f
, 0.024158f
,
604 0.025187f
, 0.026241f
, 0.027321f
, 0.028426f
, 0.029557f
, 0.030713f
, 0.031896f
, 0.033105f
, 0.034340f
, 0.035601f
, 0.036889f
,
605 0.038204f
, 0.039546f
, 0.040915f
, 0.042311f
, 0.043735f
, 0.045186f
, 0.046665f
, 0.048172f
, 0.049707f
, 0.051269f
, 0.052861f
,
606 0.054480f
, 0.056128f
, 0.057805f
, 0.059511f
, 0.061246f
, 0.063010f
, 0.064803f
, 0.066626f
, 0.068478f
, 0.070360f
, 0.072272f
,
607 0.074214f
, 0.076185f
, 0.078187f
, 0.080220f
, 0.082283f
, 0.084376f
, 0.086500f
, 0.088656f
, 0.090842f
, 0.093059f
, 0.095307f
,
608 0.097587f
, 0.099899f
, 0.102242f
, 0.104616f
, 0.107023f
, 0.109462f
, 0.111932f
, 0.114435f
, 0.116971f
, 0.119538f
, 0.122139f
,
609 0.124772f
, 0.127438f
, 0.130136f
, 0.132868f
, 0.135633f
, 0.138432f
, 0.141263f
, 0.144128f
, 0.147027f
, 0.149960f
, 0.152926f
,
610 0.155926f
, 0.158961f
, 0.162029f
, 0.165132f
, 0.168269f
, 0.171441f
, 0.174647f
, 0.177888f
, 0.181164f
, 0.184475f
, 0.187821f
,
611 0.191202f
, 0.194618f
, 0.198069f
, 0.201556f
, 0.205079f
, 0.208637f
, 0.212231f
, 0.215861f
, 0.219526f
, 0.223228f
, 0.226966f
,
612 0.230740f
, 0.234551f
, 0.238398f
, 0.242281f
, 0.246201f
, 0.250158f
, 0.254152f
, 0.258183f
, 0.262251f
, 0.266356f
, 0.270498f
,
613 0.274677f
, 0.278894f
, 0.283149f
, 0.287441f
, 0.291771f
, 0.296138f
, 0.300544f
, 0.304987f
, 0.309469f
, 0.313989f
, 0.318547f
,
614 0.323143f
, 0.327778f
, 0.332452f
, 0.337164f
, 0.341914f
, 0.346704f
, 0.351533f
, 0.356400f
, 0.361307f
, 0.366253f
, 0.371238f
,
615 0.376262f
, 0.381326f
, 0.386430f
, 0.391573f
, 0.396755f
, 0.401978f
, 0.407240f
, 0.412543f
, 0.417885f
, 0.423268f
, 0.428691f
,
616 0.434154f
, 0.439657f
, 0.445201f
, 0.450786f
, 0.456411f
, 0.462077f
, 0.467784f
, 0.473532f
, 0.479320f
, 0.485150f
, 0.491021f
,
617 0.496933f
, 0.502887f
, 0.508881f
, 0.514918f
, 0.520996f
, 0.527115f
, 0.533276f
, 0.539480f
, 0.545725f
, 0.552011f
, 0.558340f
,
618 0.564712f
, 0.571125f
, 0.577581f
, 0.584078f
, 0.590619f
, 0.597202f
, 0.603827f
, 0.610496f
, 0.617207f
, 0.623960f
, 0.630757f
,
619 0.637597f
, 0.644480f
, 0.651406f
, 0.658375f
, 0.665387f
, 0.672443f
, 0.679543f
, 0.686685f
, 0.693872f
, 0.701102f
, 0.708376f
,
620 0.715694f
, 0.723055f
, 0.730461f
, 0.737911f
, 0.745404f
, 0.752942f
, 0.760525f
, 0.768151f
, 0.775822f
, 0.783538f
, 0.791298f
,
621 0.799103f
, 0.806952f
, 0.814847f
, 0.822786f
, 0.830770f
, 0.838799f
, 0.846873f
, 0.854993f
, 0.863157f
, 0.871367f
, 0.879622f
,
622 0.887923f
, 0.896269f
, 0.904661f
, 0.913099f
, 0.921582f
, 0.930111f
, 0.938686f
, 0.947307f
, 0.955974f
, 0.964686f
, 0.973445f
,
623 0.982251f
, 0.991102f
, 1.0f
626 static float stbir__srgb_to_linear(float f
)
631 return (float)pow((f
+ 0.055f
) / 1.055f
, 2.4f
);
634 static float stbir__linear_to_srgb(float f
)
639 return 1.055f
* (float)pow(f
, 1 / 2.4f
) - 0.055f
;
642 #ifndef STBIR_NON_IEEE_FLOAT
643 // From https://gist.github.com/rygorous/2203834
651 static const stbir_uint32 fp32_to_srgb8_tab4
[104] = {
652 0x0073000d, 0x007a000d, 0x0080000d, 0x0087000d, 0x008d000d, 0x0094000d, 0x009a000d, 0x00a1000d,
653 0x00a7001a, 0x00b4001a, 0x00c1001a, 0x00ce001a, 0x00da001a, 0x00e7001a, 0x00f4001a, 0x0101001a,
654 0x010e0033, 0x01280033, 0x01410033, 0x015b0033, 0x01750033, 0x018f0033, 0x01a80033, 0x01c20033,
655 0x01dc0067, 0x020f0067, 0x02430067, 0x02760067, 0x02aa0067, 0x02dd0067, 0x03110067, 0x03440067,
656 0x037800ce, 0x03df00ce, 0x044600ce, 0x04ad00ce, 0x051400ce, 0x057b00c5, 0x05dd00bc, 0x063b00b5,
657 0x06970158, 0x07420142, 0x07e30130, 0x087b0120, 0x090b0112, 0x09940106, 0x0a1700fc, 0x0a9500f2,
658 0x0b0f01cb, 0x0bf401ae, 0x0ccb0195, 0x0d950180, 0x0e56016e, 0x0f0d015e, 0x0fbc0150, 0x10630143,
659 0x11070264, 0x1238023e, 0x1357021d, 0x14660201, 0x156601e9, 0x165a01d3, 0x174401c0, 0x182401af,
660 0x18fe0331, 0x1a9602fe, 0x1c1502d2, 0x1d7e02ad, 0x1ed4028d, 0x201a0270, 0x21520256, 0x227d0240,
661 0x239f0443, 0x25c003fe, 0x27bf03c4, 0x29a10392, 0x2b6a0367, 0x2d1d0341, 0x2ebe031f, 0x304d0300,
662 0x31d105b0, 0x34a80555, 0x37520507, 0x39d504c5, 0x3c37048b, 0x3e7c0458, 0x40a8042a, 0x42bd0401,
663 0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559,
664 0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723,
667 static stbir_uint8
stbir__linear_to_srgb_uchar(float in
)
669 static const stbir__FP32 almostone
= { 0x3f7fffff }; // 1-eps
670 static const stbir__FP32 minval
= { (127-13) << 23 };
671 stbir_uint32 tab
,bias
,scale
,t
;
674 // Clamp to [2^(-13), 1-eps]; these two values map to 0 and 1, respectively.
675 // The tests are carefully written so that NaNs map to 0, same as in the reference
677 if (!(in
> minval
.f
)) // written this way to catch NaNs
679 if (in
> almostone
.f
)
682 // Do the table lookup and unpack bias, scale
684 tab
= fp32_to_srgb8_tab4
[(f
.u
- minval
.u
) >> 20];
685 bias
= (tab
>> 16) << 9;
686 scale
= tab
& 0xffff;
688 // Grab next-highest mantissa bits and perform linear interpolation
689 t
= (f
.u
>> 12) & 0xff;
690 return (unsigned char) ((bias
+ scale
*t
) >> 16);
694 // sRGB transition values, scaled by 1<<28
695 static int stbir__srgb_offset_to_linear_scaled
[256] =
697 0, 40738, 122216, 203693, 285170, 366648, 448125, 529603,
698 611080, 692557, 774035, 855852, 942009, 1033024, 1128971, 1229926,
699 1335959, 1447142, 1563542, 1685229, 1812268, 1944725, 2082664, 2226148,
700 2375238, 2529996, 2690481, 2856753, 3028870, 3206888, 3390865, 3580856,
701 3776916, 3979100, 4187460, 4402049, 4622919, 4850123, 5083710, 5323731,
702 5570236, 5823273, 6082892, 6349140, 6622065, 6901714, 7188133, 7481369,
703 7781466, 8088471, 8402427, 8723380, 9051372, 9386448, 9728650, 10078021,
704 10434603, 10798439, 11169569, 11548036, 11933879, 12327139, 12727857, 13136073,
705 13551826, 13975156, 14406100, 14844697, 15290987, 15745007, 16206795, 16676389,
706 17153826, 17639142, 18132374, 18633560, 19142734, 19659934, 20185196, 20718552,
707 21260042, 21809696, 22367554, 22933648, 23508010, 24090680, 24681686, 25281066,
708 25888850, 26505076, 27129772, 27762974, 28404716, 29055026, 29713942, 30381490,
709 31057708, 31742624, 32436272, 33138682, 33849884, 34569912, 35298800, 36036568,
710 36783260, 37538896, 38303512, 39077136, 39859796, 40651528, 41452360, 42262316,
711 43081432, 43909732, 44747252, 45594016, 46450052, 47315392, 48190064, 49074096,
712 49967516, 50870356, 51782636, 52704392, 53635648, 54576432, 55526772, 56486700,
713 57456236, 58435408, 59424248, 60422780, 61431036, 62449032, 63476804, 64514376,
714 65561776, 66619028, 67686160, 68763192, 69850160, 70947088, 72053992, 73170912,
715 74297864, 75434880, 76581976, 77739184, 78906536, 80084040, 81271736, 82469648,
716 83677792, 84896192, 86124888, 87363888, 88613232, 89872928, 91143016, 92423512,
717 93714432, 95015816, 96327688, 97650056, 98982952, 100326408, 101680440, 103045072,
718 104420320, 105806224, 107202800, 108610064, 110028048, 111456776, 112896264, 114346544,
719 115807632, 117279552, 118762328, 120255976, 121760536, 123276016, 124802440, 126339832,
720 127888216, 129447616, 131018048, 132599544, 134192112, 135795792, 137410592, 139036528,
721 140673648, 142321952, 143981456, 145652208, 147334208, 149027488, 150732064, 152447968,
722 154175200, 155913792, 157663776, 159425168, 161197984, 162982240, 164777968, 166585184,
723 168403904, 170234160, 172075968, 173929344, 175794320, 177670896, 179559120, 181458992,
724 183370528, 185293776, 187228736, 189175424, 191133888, 193104112, 195086128, 197079968,
725 199085648, 201103184, 203132592, 205173888, 207227120, 209292272, 211369392, 213458480,
726 215559568, 217672656, 219797792, 221934976, 224084240, 226245600, 228419056, 230604656,
727 232802400, 235012320, 237234432, 239468736, 241715280, 243974080, 246245120, 248528464,
728 250824112, 253132064, 255452368, 257785040, 260130080, 262487520, 264857376, 267239664,
731 static stbir_uint8
stbir__linear_to_srgb_uchar(float f
)
733 int x
= (int) (f
* (1 << 28)); // has headroom so you don't need to clamp
737 // Refine the guess with a short binary search.
738 i
= v
+ 128; if (x
>= stbir__srgb_offset_to_linear_scaled
[i
]) v
= i
;
739 i
= v
+ 64; if (x
>= stbir__srgb_offset_to_linear_scaled
[i
]) v
= i
;
740 i
= v
+ 32; if (x
>= stbir__srgb_offset_to_linear_scaled
[i
]) v
= i
;
741 i
= v
+ 16; if (x
>= stbir__srgb_offset_to_linear_scaled
[i
]) v
= i
;
742 i
= v
+ 8; if (x
>= stbir__srgb_offset_to_linear_scaled
[i
]) v
= i
;
743 i
= v
+ 4; if (x
>= stbir__srgb_offset_to_linear_scaled
[i
]) v
= i
;
744 i
= v
+ 2; if (x
>= stbir__srgb_offset_to_linear_scaled
[i
]) v
= i
;
745 i
= v
+ 1; if (x
>= stbir__srgb_offset_to_linear_scaled
[i
]) v
= i
;
747 return (stbir_uint8
) v
;
751 static float stbir__filter_trapezoid(float x
, float scale
)
753 float halfscale
= scale
/ 2;
754 float t
= 0.5f
+ halfscale
;
755 STBIR_ASSERT(scale
<= 1);
763 float r
= 0.5f
- halfscale
;
767 return (t
- x
) / scale
;
771 static float stbir__support_trapezoid(float scale
)
773 STBIR_ASSERT(scale
<= 1);
774 return 0.5f
+ scale
/ 2;
777 static float stbir__filter_triangle(float x
, float s
)
779 STBIR__UNUSED_PARAM(s
);
789 static float stbir__filter_cubic(float x
, float s
)
791 STBIR__UNUSED_PARAM(s
);
796 return (4 + x
*x
*(3*x
- 6))/6;
798 return (8 + x
*(-12 + x
*(6 - x
)))/6;
803 static float stbir__filter_catmullrom(float x
, float s
)
805 STBIR__UNUSED_PARAM(s
);
810 return 1 - x
*x
*(2.5f
- 1.5f
*x
);
812 return 2 - x
*(4 + x
*(0.5f
*x
- 2.5f
));
817 static float stbir__filter_mitchell(float x
, float s
)
819 STBIR__UNUSED_PARAM(s
);
824 return (16 + x
*x
*(21 * x
- 36))/18;
826 return (32 + x
*(-60 + x
*(36 - 7*x
)))/18;
831 static float stbir__support_zero(float s
)
833 STBIR__UNUSED_PARAM(s
);
837 static float stbir__support_one(float s
)
839 STBIR__UNUSED_PARAM(s
);
843 static float stbir__support_two(float s
)
845 STBIR__UNUSED_PARAM(s
);
849 static stbir__filter_info stbir__filter_info_table
[] = {
850 { NULL
, stbir__support_zero
},
851 { stbir__filter_trapezoid
, stbir__support_trapezoid
},
852 { stbir__filter_triangle
, stbir__support_one
},
853 { stbir__filter_cubic
, stbir__support_two
},
854 { stbir__filter_catmullrom
, stbir__support_two
},
855 { stbir__filter_mitchell
, stbir__support_two
},
858 stbir__inline
static int stbir__use_upsampling(float ratio
)
863 stbir__inline
static int stbir__use_width_upsampling(stbir__info
* stbir_info
)
865 return stbir__use_upsampling(stbir_info
->horizontal_scale
);
868 stbir__inline
static int stbir__use_height_upsampling(stbir__info
* stbir_info
)
870 return stbir__use_upsampling(stbir_info
->vertical_scale
);
873 // This is the maximum number of input samples that can affect an output sample
874 // with the given filter
875 static int stbir__get_filter_pixel_width(stbir_filter filter
, float scale
)
877 STBIR_ASSERT(filter
!= 0);
878 STBIR_ASSERT(filter
< STBIR__ARRAY_SIZE(stbir__filter_info_table
));
880 if (stbir__use_upsampling(scale
))
881 return (int)ceil(stbir__filter_info_table
[filter
].support(1/scale
) * 2);
883 return (int)ceil(stbir__filter_info_table
[filter
].support(scale
) * 2 / scale
);
886 // This is how much to expand buffers to account for filters seeking outside
887 // the image boundaries.
888 static int stbir__get_filter_pixel_margin(stbir_filter filter
, float scale
)
890 return stbir__get_filter_pixel_width(filter
, scale
) / 2;
893 static int stbir__get_coefficient_width(stbir_filter filter
, float scale
)
895 if (stbir__use_upsampling(scale
))
896 return (int)ceil(stbir__filter_info_table
[filter
].support(1 / scale
) * 2);
898 return (int)ceil(stbir__filter_info_table
[filter
].support(scale
) * 2);
901 static int stbir__get_contributors(float scale
, stbir_filter filter
, int input_size
, int output_size
)
903 if (stbir__use_upsampling(scale
))
906 return (input_size
+ stbir__get_filter_pixel_margin(filter
, scale
) * 2);
909 static int stbir__get_total_horizontal_coefficients(stbir__info
* info
)
911 return info
->horizontal_num_contributors
912 * stbir__get_coefficient_width (info
->horizontal_filter
, info
->horizontal_scale
);
915 static int stbir__get_total_vertical_coefficients(stbir__info
* info
)
917 return info
->vertical_num_contributors
918 * stbir__get_coefficient_width (info
->vertical_filter
, info
->vertical_scale
);
921 static stbir__contributors
* stbir__get_contributor(stbir__contributors
* contributors
, int n
)
923 return &contributors
[n
];
926 // For perf reasons this code is duplicated in stbir__resample_horizontal_upsample/downsample,
927 // if you change it here change it there too.
928 static float* stbir__get_coefficient(float* coefficients
, stbir_filter filter
, float scale
, int n
, int c
)
930 int width
= stbir__get_coefficient_width(filter
, scale
);
931 return &coefficients
[width
*n
+ c
];
934 static int stbir__edge_wrap_slow(stbir_edge edge
, int n
, int max
)
938 case STBIR_EDGE_ZERO
:
939 return 0; // we'll decode the wrong pixel here, and then overwrite with 0s later
941 case STBIR_EDGE_CLAMP
:
948 return n
; // NOTREACHED
950 case STBIR_EDGE_REFLECT
:
969 return n
; // NOTREACHED
972 case STBIR_EDGE_WRAP
:
984 return n
; // NOTREACHED
987 STBIR_ASSERT(!"Unimplemented edge type");
992 stbir__inline
static int stbir__edge_wrap(stbir_edge edge
, int n
, int max
)
994 // avoid per-pixel switch
995 if (n
>= 0 && n
< max
)
997 return stbir__edge_wrap_slow(edge
, n
, max
);
1000 // What input pixels contribute to this output pixel?
1001 static void stbir__calculate_sample_range_upsample(int n
, float out_filter_radius
, float scale_ratio
, float out_shift
, int* in_first_pixel
, int* in_last_pixel
, float* in_center_of_out
)
1003 float out_pixel_center
= (float)n
+ 0.5f
;
1004 float out_pixel_influence_lowerbound
= out_pixel_center
- out_filter_radius
;
1005 float out_pixel_influence_upperbound
= out_pixel_center
+ out_filter_radius
;
1007 float in_pixel_influence_lowerbound
= (out_pixel_influence_lowerbound
+ out_shift
) / scale_ratio
;
1008 float in_pixel_influence_upperbound
= (out_pixel_influence_upperbound
+ out_shift
) / scale_ratio
;
1010 *in_center_of_out
= (out_pixel_center
+ out_shift
) / scale_ratio
;
1011 *in_first_pixel
= (int)(floor(in_pixel_influence_lowerbound
+ 0.5));
1012 *in_last_pixel
= (int)(floor(in_pixel_influence_upperbound
- 0.5));
1015 // What output pixels does this input pixel contribute to?
1016 static void stbir__calculate_sample_range_downsample(int n
, float in_pixels_radius
, float scale_ratio
, float out_shift
, int* out_first_pixel
, int* out_last_pixel
, float* out_center_of_in
)
1018 float in_pixel_center
= (float)n
+ 0.5f
;
1019 float in_pixel_influence_lowerbound
= in_pixel_center
- in_pixels_radius
;
1020 float in_pixel_influence_upperbound
= in_pixel_center
+ in_pixels_radius
;
1022 float out_pixel_influence_lowerbound
= in_pixel_influence_lowerbound
* scale_ratio
- out_shift
;
1023 float out_pixel_influence_upperbound
= in_pixel_influence_upperbound
* scale_ratio
- out_shift
;
1025 *out_center_of_in
= in_pixel_center
* scale_ratio
- out_shift
;
1026 *out_first_pixel
= (int)(floor(out_pixel_influence_lowerbound
+ 0.5));
1027 *out_last_pixel
= (int)(floor(out_pixel_influence_upperbound
- 0.5));
1030 static void stbir__calculate_coefficients_upsample(stbir__info
* stbir_info
, stbir_filter filter
, float scale
, int in_first_pixel
, int in_last_pixel
, float in_center_of_out
, stbir__contributors
* contributor
, float* coefficient_group
)
1033 float total_filter
= 0;
1036 STBIR_ASSERT(in_last_pixel
- in_first_pixel
<= (int)ceil(stbir__filter_info_table
[filter
].support(1/scale
) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical.
1038 contributor
->n0
= in_first_pixel
;
1039 contributor
->n1
= in_last_pixel
;
1041 STBIR_ASSERT(contributor
->n1
>= contributor
->n0
);
1043 for (i
= 0; i
<= in_last_pixel
- in_first_pixel
; i
++)
1045 float in_pixel_center
= (float)(i
+ in_first_pixel
) + 0.5f
;
1046 coefficient_group
[i
] = stbir__filter_info_table
[filter
].kernel(in_center_of_out
- in_pixel_center
, 1 / scale
);
1048 // If the coefficient is zero, skip it. (Don't do the <0 check here, we want the influence of those outside pixels.)
1049 if (i
== 0 && !coefficient_group
[i
])
1051 contributor
->n0
= ++in_first_pixel
;
1056 total_filter
+= coefficient_group
[i
];
1059 STBIR_ASSERT(stbir__filter_info_table
[filter
].kernel((float)(in_last_pixel
+ 1) + 0.5f
- in_center_of_out
, 1/scale
) == 0);
1061 STBIR_ASSERT(total_filter
> 0.9);
1062 STBIR_ASSERT(total_filter
< 1.1f
); // Make sure it's not way off.
1064 // Make sure the sum of all coefficients is 1.
1065 filter_scale
= 1 / total_filter
;
1067 for (i
= 0; i
<= in_last_pixel
- in_first_pixel
; i
++)
1068 coefficient_group
[i
] *= filter_scale
;
1070 for (i
= in_last_pixel
- in_first_pixel
; i
>= 0; i
--)
1072 if (coefficient_group
[i
])
1075 // This line has no weight. We can skip it.
1076 contributor
->n1
= contributor
->n0
+ i
- 1;
1080 static void stbir__calculate_coefficients_downsample(stbir__info
* stbir_info
, stbir_filter filter
, float scale_ratio
, int out_first_pixel
, int out_last_pixel
, float out_center_of_in
, stbir__contributors
* contributor
, float* coefficient_group
)
1084 STBIR_ASSERT(out_last_pixel
- out_first_pixel
<= (int)ceil(stbir__filter_info_table
[filter
].support(scale_ratio
) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical.
1086 contributor
->n0
= out_first_pixel
;
1087 contributor
->n1
= out_last_pixel
;
1089 STBIR_ASSERT(contributor
->n1
>= contributor
->n0
);
1091 for (i
= 0; i
<= out_last_pixel
- out_first_pixel
; i
++)
1093 float out_pixel_center
= (float)(i
+ out_first_pixel
) + 0.5f
;
1094 float x
= out_pixel_center
- out_center_of_in
;
1095 coefficient_group
[i
] = stbir__filter_info_table
[filter
].kernel(x
, scale_ratio
) * scale_ratio
;
1098 STBIR_ASSERT(stbir__filter_info_table
[filter
].kernel((float)(out_last_pixel
+ 1) + 0.5f
- out_center_of_in
, scale_ratio
) == 0);
1100 for (i
= out_last_pixel
- out_first_pixel
; i
>= 0; i
--)
1102 if (coefficient_group
[i
])
1105 // This line has no weight. We can skip it.
1106 contributor
->n1
= contributor
->n0
+ i
- 1;
1110 static void stbir__normalize_downsample_coefficients(stbir__info
* stbir_info
, stbir__contributors
* contributors
, float* coefficients
, stbir_filter filter
, float scale_ratio
, float shift
, int input_size
, int output_size
)
1112 int num_contributors
= stbir__get_contributors(scale_ratio
, filter
, input_size
, output_size
);
1113 int num_coefficients
= stbir__get_coefficient_width(filter
, scale_ratio
);
1117 for (i
= 0; i
< output_size
; i
++)
1122 for (j
= 0; j
< num_contributors
; j
++)
1124 if (i
>= contributors
[j
].n0
&& i
<= contributors
[j
].n1
)
1126 float coefficient
= *stbir__get_coefficient(coefficients
, filter
, scale_ratio
, j
, i
- contributors
[j
].n0
);
1127 total
+= coefficient
;
1129 else if (i
< contributors
[j
].n0
)
1133 STBIR_ASSERT(total
> 0.9f
);
1134 STBIR_ASSERT(total
< 1.1f
);
1138 for (j
= 0; j
< num_contributors
; j
++)
1140 if (i
>= contributors
[j
].n0
&& i
<= contributors
[j
].n1
)
1141 *stbir__get_coefficient(coefficients
, filter
, scale_ratio
, j
, i
- contributors
[j
].n0
) *= scale
;
1142 else if (i
< contributors
[j
].n0
)
1147 // Optimize: Skip zero coefficients and contributions outside of image bounds.
1148 // Do this after normalizing because normalization depends on the n0/n1 values.
1149 for (j
= 0; j
< num_contributors
; j
++)
1151 int range
, max
, width
;
1154 while (*stbir__get_coefficient(coefficients
, filter
, scale_ratio
, j
, skip
) == 0)
1157 contributors
[j
].n0
+= skip
;
1159 while (contributors
[j
].n0
< 0)
1161 contributors
[j
].n0
++;
1165 range
= contributors
[j
].n1
- contributors
[j
].n0
+ 1;
1166 max
= stbir__min(num_coefficients
, range
);
1168 width
= stbir__get_coefficient_width(filter
, scale_ratio
);
1169 for (i
= 0; i
< max
; i
++)
1171 if (i
+ skip
>= width
)
1174 *stbir__get_coefficient(coefficients
, filter
, scale_ratio
, j
, i
) = *stbir__get_coefficient(coefficients
, filter
, scale_ratio
, j
, i
+ skip
);
1180 // Using min to avoid writing into invalid pixels.
1181 for (i
= 0; i
< num_contributors
; i
++)
1182 contributors
[i
].n1
= stbir__min(contributors
[i
].n1
, output_size
- 1);
1185 // Each scan line uses the same kernel values so we should calculate the kernel
1186 // values once and then we can use them for every scan line.
1187 static void stbir__calculate_filters(stbir__info
* stbir_info
, stbir__contributors
* contributors
, float* coefficients
, stbir_filter filter
, float scale_ratio
, float shift
, int input_size
, int output_size
)
1190 int total_contributors
= stbir__get_contributors(scale_ratio
, filter
, input_size
, output_size
);
1192 if (stbir__use_upsampling(scale_ratio
))
1194 float out_pixels_radius
= stbir__filter_info_table
[filter
].support(1 / scale_ratio
) * scale_ratio
;
1196 // Looping through out pixels
1197 for (n
= 0; n
< total_contributors
; n
++)
1199 float in_center_of_out
; // Center of the current out pixel in the in pixel space
1200 int in_first_pixel
, in_last_pixel
;
1202 stbir__calculate_sample_range_upsample(n
, out_pixels_radius
, scale_ratio
, shift
, &in_first_pixel
, &in_last_pixel
, &in_center_of_out
);
1204 stbir__calculate_coefficients_upsample(stbir_info
, filter
, scale_ratio
, in_first_pixel
, in_last_pixel
, in_center_of_out
, stbir__get_contributor(contributors
, n
), stbir__get_coefficient(coefficients
, filter
, scale_ratio
, n
, 0));
1209 float in_pixels_radius
= stbir__filter_info_table
[filter
].support(scale_ratio
) / scale_ratio
;
1211 // Looping through in pixels
1212 for (n
= 0; n
< total_contributors
; n
++)
1214 float out_center_of_in
; // Center of the current out pixel in the in pixel space
1215 int out_first_pixel
, out_last_pixel
;
1216 int n_adjusted
= n
- stbir__get_filter_pixel_margin(filter
, scale_ratio
);
1218 stbir__calculate_sample_range_downsample(n_adjusted
, in_pixels_radius
, scale_ratio
, shift
, &out_first_pixel
, &out_last_pixel
, &out_center_of_in
);
1220 stbir__calculate_coefficients_downsample(stbir_info
, filter
, scale_ratio
, out_first_pixel
, out_last_pixel
, out_center_of_in
, stbir__get_contributor(contributors
, n
), stbir__get_coefficient(coefficients
, filter
, scale_ratio
, n
, 0));
1223 stbir__normalize_downsample_coefficients(stbir_info
, contributors
, coefficients
, filter
, scale_ratio
, shift
, input_size
, output_size
);
1227 static float* stbir__get_decode_buffer(stbir__info
* stbir_info
)
1229 // The 0 index of the decode buffer starts after the margin. This makes
1230 // it okay to use negative indexes on the decode buffer.
1231 return &stbir_info
->decode_buffer
[stbir_info
->horizontal_filter_pixel_margin
* stbir_info
->channels
];
1234 #define STBIR__DECODE(type, colorspace) ((type) * (STBIR_MAX_COLORSPACES) + (colorspace))
1236 static void stbir__decode_scanline(stbir__info
* stbir_info
, int n
)
1239 int channels
= stbir_info
->channels
;
1240 int alpha_channel
= stbir_info
->alpha_channel
;
1241 int type
= stbir_info
->type
;
1242 int colorspace
= stbir_info
->colorspace
;
1243 int input_w
= stbir_info
->input_w
;
1244 size_t input_stride_bytes
= stbir_info
->input_stride_bytes
;
1245 float* decode_buffer
= stbir__get_decode_buffer(stbir_info
);
1246 stbir_edge edge_horizontal
= stbir_info
->edge_horizontal
;
1247 stbir_edge edge_vertical
= stbir_info
->edge_vertical
;
1248 size_t in_buffer_row_offset
= stbir__edge_wrap(edge_vertical
, n
, stbir_info
->input_h
) * input_stride_bytes
;
1249 const void* input_data
= (char *) stbir_info
->input_data
+ in_buffer_row_offset
;
1250 int max_x
= input_w
+ stbir_info
->horizontal_filter_pixel_margin
;
1251 int decode
= STBIR__DECODE(type
, colorspace
);
1253 int x
= -stbir_info
->horizontal_filter_pixel_margin
;
1255 // special handling for STBIR_EDGE_ZERO because it needs to return an item that doesn't appear in the input,
1256 // and we want to avoid paying overhead on every pixel if not STBIR_EDGE_ZERO
1257 if (edge_vertical
== STBIR_EDGE_ZERO
&& (n
< 0 || n
>= stbir_info
->input_h
))
1259 for (; x
< max_x
; x
++)
1260 for (c
= 0; c
< channels
; c
++)
1261 decode_buffer
[x
*channels
+ c
] = 0;
1267 case STBIR__DECODE(STBIR_TYPE_UINT8
, STBIR_COLORSPACE_LINEAR
):
1268 for (; x
< max_x
; x
++)
1270 int decode_pixel_index
= x
* channels
;
1271 int input_pixel_index
= stbir__edge_wrap(edge_horizontal
, x
, input_w
) * channels
;
1272 for (c
= 0; c
< channels
; c
++)
1273 decode_buffer
[decode_pixel_index
+ c
] = ((float)((const unsigned char*)input_data
)[input_pixel_index
+ c
]) / 255;
1277 case STBIR__DECODE(STBIR_TYPE_UINT8
, STBIR_COLORSPACE_SRGB
):
1278 for (; x
< max_x
; x
++)
1280 int decode_pixel_index
= x
* channels
;
1281 int input_pixel_index
= stbir__edge_wrap(edge_horizontal
, x
, input_w
) * channels
;
1282 for (c
= 0; c
< channels
; c
++)
1283 decode_buffer
[decode_pixel_index
+ c
] = stbir__srgb_uchar_to_linear_float
[((const unsigned char*)input_data
)[input_pixel_index
+ c
]];
1285 if (!(stbir_info
->flags
&STBIR_FLAG_ALPHA_USES_COLORSPACE
))
1286 decode_buffer
[decode_pixel_index
+ alpha_channel
] = ((float)((const unsigned char*)input_data
)[input_pixel_index
+ alpha_channel
]) / 255;
1290 case STBIR__DECODE(STBIR_TYPE_UINT16
, STBIR_COLORSPACE_LINEAR
):
1291 for (; x
< max_x
; x
++)
1293 int decode_pixel_index
= x
* channels
;
1294 int input_pixel_index
= stbir__edge_wrap(edge_horizontal
, x
, input_w
) * channels
;
1295 for (c
= 0; c
< channels
; c
++)
1296 decode_buffer
[decode_pixel_index
+ c
] = ((float)((const unsigned short*)input_data
)[input_pixel_index
+ c
]) / 65535;
1300 case STBIR__DECODE(STBIR_TYPE_UINT16
, STBIR_COLORSPACE_SRGB
):
1301 for (; x
< max_x
; x
++)
1303 int decode_pixel_index
= x
* channels
;
1304 int input_pixel_index
= stbir__edge_wrap(edge_horizontal
, x
, input_w
) * channels
;
1305 for (c
= 0; c
< channels
; c
++)
1306 decode_buffer
[decode_pixel_index
+ c
] = stbir__srgb_to_linear(((float)((const unsigned short*)input_data
)[input_pixel_index
+ c
]) / 65535);
1308 if (!(stbir_info
->flags
&STBIR_FLAG_ALPHA_USES_COLORSPACE
))
1309 decode_buffer
[decode_pixel_index
+ alpha_channel
] = ((float)((const unsigned short*)input_data
)[input_pixel_index
+ alpha_channel
]) / 65535;
1313 case STBIR__DECODE(STBIR_TYPE_UINT32
, STBIR_COLORSPACE_LINEAR
):
1314 for (; x
< max_x
; x
++)
1316 int decode_pixel_index
= x
* channels
;
1317 int input_pixel_index
= stbir__edge_wrap(edge_horizontal
, x
, input_w
) * channels
;
1318 for (c
= 0; c
< channels
; c
++)
1319 decode_buffer
[decode_pixel_index
+ c
] = (float)(((double)((const unsigned int*)input_data
)[input_pixel_index
+ c
]) / 4294967295);
1323 case STBIR__DECODE(STBIR_TYPE_UINT32
, STBIR_COLORSPACE_SRGB
):
1324 for (; x
< max_x
; x
++)
1326 int decode_pixel_index
= x
* channels
;
1327 int input_pixel_index
= stbir__edge_wrap(edge_horizontal
, x
, input_w
) * channels
;
1328 for (c
= 0; c
< channels
; c
++)
1329 decode_buffer
[decode_pixel_index
+ c
] = stbir__srgb_to_linear((float)(((double)((const unsigned int*)input_data
)[input_pixel_index
+ c
]) / 4294967295));
1331 if (!(stbir_info
->flags
&STBIR_FLAG_ALPHA_USES_COLORSPACE
))
1332 decode_buffer
[decode_pixel_index
+ alpha_channel
] = (float)(((double)((const unsigned int*)input_data
)[input_pixel_index
+ alpha_channel
]) / 4294967295);
1336 case STBIR__DECODE(STBIR_TYPE_FLOAT
, STBIR_COLORSPACE_LINEAR
):
1337 for (; x
< max_x
; x
++)
1339 int decode_pixel_index
= x
* channels
;
1340 int input_pixel_index
= stbir__edge_wrap(edge_horizontal
, x
, input_w
) * channels
;
1341 for (c
= 0; c
< channels
; c
++)
1342 decode_buffer
[decode_pixel_index
+ c
] = ((const float*)input_data
)[input_pixel_index
+ c
];
1346 case STBIR__DECODE(STBIR_TYPE_FLOAT
, STBIR_COLORSPACE_SRGB
):
1347 for (; x
< max_x
; x
++)
1349 int decode_pixel_index
= x
* channels
;
1350 int input_pixel_index
= stbir__edge_wrap(edge_horizontal
, x
, input_w
) * channels
;
1351 for (c
= 0; c
< channels
; c
++)
1352 decode_buffer
[decode_pixel_index
+ c
] = stbir__srgb_to_linear(((const float*)input_data
)[input_pixel_index
+ c
]);
1354 if (!(stbir_info
->flags
&STBIR_FLAG_ALPHA_USES_COLORSPACE
))
1355 decode_buffer
[decode_pixel_index
+ alpha_channel
] = ((const float*)input_data
)[input_pixel_index
+ alpha_channel
];
1361 STBIR_ASSERT(!"Unknown type/colorspace/channels combination.");
1365 if (!(stbir_info
->flags
& STBIR_FLAG_ALPHA_PREMULTIPLIED
))
1367 for (x
= -stbir_info
->horizontal_filter_pixel_margin
; x
< max_x
; x
++)
1369 int decode_pixel_index
= x
* channels
;
1371 // If the alpha value is 0 it will clobber the color values. Make sure it's not.
1372 float alpha
= decode_buffer
[decode_pixel_index
+ alpha_channel
];
1373 #ifndef STBIR_NO_ALPHA_EPSILON
1374 if (stbir_info
->type
!= STBIR_TYPE_FLOAT
) {
1375 alpha
+= STBIR_ALPHA_EPSILON
;
1376 decode_buffer
[decode_pixel_index
+ alpha_channel
] = alpha
;
1379 for (c
= 0; c
< channels
; c
++)
1381 if (c
== alpha_channel
)
1384 decode_buffer
[decode_pixel_index
+ c
] *= alpha
;
1389 if (edge_horizontal
== STBIR_EDGE_ZERO
)
1391 for (x
= -stbir_info
->horizontal_filter_pixel_margin
; x
< 0; x
++)
1393 for (c
= 0; c
< channels
; c
++)
1394 decode_buffer
[x
*channels
+ c
] = 0;
1396 for (x
= input_w
; x
< max_x
; x
++)
1398 for (c
= 0; c
< channels
; c
++)
1399 decode_buffer
[x
*channels
+ c
] = 0;
1404 static float* stbir__get_ring_buffer_entry(float* ring_buffer
, int index
, int ring_buffer_length
)
1406 return &ring_buffer
[index
* ring_buffer_length
];
1409 static float* stbir__add_empty_ring_buffer_entry(stbir__info
* stbir_info
, int n
)
1411 int ring_buffer_index
;
1414 if (stbir_info
->ring_buffer_begin_index
< 0)
1416 ring_buffer_index
= stbir_info
->ring_buffer_begin_index
= 0;
1417 stbir_info
->ring_buffer_first_scanline
= n
;
1421 ring_buffer_index
= (stbir_info
->ring_buffer_begin_index
+ (stbir_info
->ring_buffer_last_scanline
- stbir_info
->ring_buffer_first_scanline
) + 1) % stbir_info
->vertical_filter_pixel_width
;
1422 STBIR_ASSERT(ring_buffer_index
!= stbir_info
->ring_buffer_begin_index
);
1425 ring_buffer
= stbir__get_ring_buffer_entry(stbir_info
->ring_buffer
, ring_buffer_index
, stbir_info
->ring_buffer_length_bytes
/ sizeof(float));
1426 memset(ring_buffer
, 0, stbir_info
->ring_buffer_length_bytes
);
1428 stbir_info
->ring_buffer_last_scanline
= n
;
1434 static void stbir__resample_horizontal_upsample(stbir__info
* stbir_info
, int n
, float* output_buffer
)
1437 int output_w
= stbir_info
->output_w
;
1438 int kernel_pixel_width
= stbir_info
->horizontal_filter_pixel_width
;
1439 int channels
= stbir_info
->channels
;
1440 float* decode_buffer
= stbir__get_decode_buffer(stbir_info
);
1441 stbir__contributors
* horizontal_contributors
= stbir_info
->horizontal_contributors
;
1442 float* horizontal_coefficients
= stbir_info
->horizontal_coefficients
;
1443 int coefficient_width
= stbir_info
->horizontal_coefficient_width
;
1445 for (x
= 0; x
< output_w
; x
++)
1447 int n0
= horizontal_contributors
[x
].n0
;
1448 int n1
= horizontal_contributors
[x
].n1
;
1450 int out_pixel_index
= x
* channels
;
1451 int coefficient_group
= coefficient_width
* x
;
1452 int coefficient_counter
= 0;
1454 STBIR_ASSERT(n1
>= n0
);
1455 STBIR_ASSERT(n0
>= -stbir_info
->horizontal_filter_pixel_margin
);
1456 STBIR_ASSERT(n1
>= -stbir_info
->horizontal_filter_pixel_margin
);
1457 STBIR_ASSERT(n0
< stbir_info
->input_w
+ stbir_info
->horizontal_filter_pixel_margin
);
1458 STBIR_ASSERT(n1
< stbir_info
->input_w
+ stbir_info
->horizontal_filter_pixel_margin
);
1462 for (k
= n0
; k
<= n1
; k
++)
1464 int in_pixel_index
= k
* 1;
1465 float coefficient
= horizontal_coefficients
[coefficient_group
+ coefficient_counter
++];
1466 STBIR_ASSERT(coefficient
!= 0);
1467 output_buffer
[out_pixel_index
+ 0] += decode_buffer
[in_pixel_index
+ 0] * coefficient
;
1471 for (k
= n0
; k
<= n1
; k
++)
1473 int in_pixel_index
= k
* 2;
1474 float coefficient
= horizontal_coefficients
[coefficient_group
+ coefficient_counter
++];
1475 STBIR_ASSERT(coefficient
!= 0);
1476 output_buffer
[out_pixel_index
+ 0] += decode_buffer
[in_pixel_index
+ 0] * coefficient
;
1477 output_buffer
[out_pixel_index
+ 1] += decode_buffer
[in_pixel_index
+ 1] * coefficient
;
1481 for (k
= n0
; k
<= n1
; k
++)
1483 int in_pixel_index
= k
* 3;
1484 float coefficient
= horizontal_coefficients
[coefficient_group
+ coefficient_counter
++];
1485 STBIR_ASSERT(coefficient
!= 0);
1486 output_buffer
[out_pixel_index
+ 0] += decode_buffer
[in_pixel_index
+ 0] * coefficient
;
1487 output_buffer
[out_pixel_index
+ 1] += decode_buffer
[in_pixel_index
+ 1] * coefficient
;
1488 output_buffer
[out_pixel_index
+ 2] += decode_buffer
[in_pixel_index
+ 2] * coefficient
;
1492 for (k
= n0
; k
<= n1
; k
++)
1494 int in_pixel_index
= k
* 4;
1495 float coefficient
= horizontal_coefficients
[coefficient_group
+ coefficient_counter
++];
1496 STBIR_ASSERT(coefficient
!= 0);
1497 output_buffer
[out_pixel_index
+ 0] += decode_buffer
[in_pixel_index
+ 0] * coefficient
;
1498 output_buffer
[out_pixel_index
+ 1] += decode_buffer
[in_pixel_index
+ 1] * coefficient
;
1499 output_buffer
[out_pixel_index
+ 2] += decode_buffer
[in_pixel_index
+ 2] * coefficient
;
1500 output_buffer
[out_pixel_index
+ 3] += decode_buffer
[in_pixel_index
+ 3] * coefficient
;
1504 for (k
= n0
; k
<= n1
; k
++)
1506 int in_pixel_index
= k
* channels
;
1507 float coefficient
= horizontal_coefficients
[coefficient_group
+ coefficient_counter
++];
1509 STBIR_ASSERT(coefficient
!= 0);
1510 for (c
= 0; c
< channels
; c
++)
1511 output_buffer
[out_pixel_index
+ c
] += decode_buffer
[in_pixel_index
+ c
] * coefficient
;
1518 static void stbir__resample_horizontal_downsample(stbir__info
* stbir_info
, int n
, float* output_buffer
)
1521 int input_w
= stbir_info
->input_w
;
1522 int output_w
= stbir_info
->output_w
;
1523 int kernel_pixel_width
= stbir_info
->horizontal_filter_pixel_width
;
1524 int channels
= stbir_info
->channels
;
1525 float* decode_buffer
= stbir__get_decode_buffer(stbir_info
);
1526 stbir__contributors
* horizontal_contributors
= stbir_info
->horizontal_contributors
;
1527 float* horizontal_coefficients
= stbir_info
->horizontal_coefficients
;
1528 int coefficient_width
= stbir_info
->horizontal_coefficient_width
;
1529 int filter_pixel_margin
= stbir_info
->horizontal_filter_pixel_margin
;
1530 int max_x
= input_w
+ filter_pixel_margin
* 2;
1532 STBIR_ASSERT(!stbir__use_width_upsampling(stbir_info
));
1536 for (x
= 0; x
< max_x
; x
++)
1538 int n0
= horizontal_contributors
[x
].n0
;
1539 int n1
= horizontal_contributors
[x
].n1
;
1541 int in_x
= x
- filter_pixel_margin
;
1542 int in_pixel_index
= in_x
* 1;
1544 int coefficient_group
= coefficient_width
* x
;
1546 for (k
= n0
; k
<= max_n
; k
++)
1548 int out_pixel_index
= k
* 1;
1549 float coefficient
= horizontal_coefficients
[coefficient_group
+ k
- n0
];
1550 STBIR_ASSERT(coefficient
!= 0);
1551 output_buffer
[out_pixel_index
+ 0] += decode_buffer
[in_pixel_index
+ 0] * coefficient
;
1557 for (x
= 0; x
< max_x
; x
++)
1559 int n0
= horizontal_contributors
[x
].n0
;
1560 int n1
= horizontal_contributors
[x
].n1
;
1562 int in_x
= x
- filter_pixel_margin
;
1563 int in_pixel_index
= in_x
* 2;
1565 int coefficient_group
= coefficient_width
* x
;
1567 for (k
= n0
; k
<= max_n
; k
++)
1569 int out_pixel_index
= k
* 2;
1570 float coefficient
= horizontal_coefficients
[coefficient_group
+ k
- n0
];
1571 STBIR_ASSERT(coefficient
!= 0);
1572 output_buffer
[out_pixel_index
+ 0] += decode_buffer
[in_pixel_index
+ 0] * coefficient
;
1573 output_buffer
[out_pixel_index
+ 1] += decode_buffer
[in_pixel_index
+ 1] * coefficient
;
1579 for (x
= 0; x
< max_x
; x
++)
1581 int n0
= horizontal_contributors
[x
].n0
;
1582 int n1
= horizontal_contributors
[x
].n1
;
1584 int in_x
= x
- filter_pixel_margin
;
1585 int in_pixel_index
= in_x
* 3;
1587 int coefficient_group
= coefficient_width
* x
;
1589 for (k
= n0
; k
<= max_n
; k
++)
1591 int out_pixel_index
= k
* 3;
1592 float coefficient
= horizontal_coefficients
[coefficient_group
+ k
- n0
];
1593 STBIR_ASSERT(coefficient
!= 0);
1594 output_buffer
[out_pixel_index
+ 0] += decode_buffer
[in_pixel_index
+ 0] * coefficient
;
1595 output_buffer
[out_pixel_index
+ 1] += decode_buffer
[in_pixel_index
+ 1] * coefficient
;
1596 output_buffer
[out_pixel_index
+ 2] += decode_buffer
[in_pixel_index
+ 2] * coefficient
;
1602 for (x
= 0; x
< max_x
; x
++)
1604 int n0
= horizontal_contributors
[x
].n0
;
1605 int n1
= horizontal_contributors
[x
].n1
;
1607 int in_x
= x
- filter_pixel_margin
;
1608 int in_pixel_index
= in_x
* 4;
1610 int coefficient_group
= coefficient_width
* x
;
1612 for (k
= n0
; k
<= max_n
; k
++)
1614 int out_pixel_index
= k
* 4;
1615 float coefficient
= horizontal_coefficients
[coefficient_group
+ k
- n0
];
1616 STBIR_ASSERT(coefficient
!= 0);
1617 output_buffer
[out_pixel_index
+ 0] += decode_buffer
[in_pixel_index
+ 0] * coefficient
;
1618 output_buffer
[out_pixel_index
+ 1] += decode_buffer
[in_pixel_index
+ 1] * coefficient
;
1619 output_buffer
[out_pixel_index
+ 2] += decode_buffer
[in_pixel_index
+ 2] * coefficient
;
1620 output_buffer
[out_pixel_index
+ 3] += decode_buffer
[in_pixel_index
+ 3] * coefficient
;
1626 for (x
= 0; x
< max_x
; x
++)
1628 int n0
= horizontal_contributors
[x
].n0
;
1629 int n1
= horizontal_contributors
[x
].n1
;
1631 int in_x
= x
- filter_pixel_margin
;
1632 int in_pixel_index
= in_x
* channels
;
1634 int coefficient_group
= coefficient_width
* x
;
1636 for (k
= n0
; k
<= max_n
; k
++)
1639 int out_pixel_index
= k
* channels
;
1640 float coefficient
= horizontal_coefficients
[coefficient_group
+ k
- n0
];
1641 STBIR_ASSERT(coefficient
!= 0);
1642 for (c
= 0; c
< channels
; c
++)
1643 output_buffer
[out_pixel_index
+ c
] += decode_buffer
[in_pixel_index
+ c
] * coefficient
;
1650 static void stbir__decode_and_resample_upsample(stbir__info
* stbir_info
, int n
)
1652 // Decode the nth scanline from the source image into the decode buffer.
1653 stbir__decode_scanline(stbir_info
, n
);
1655 // Now resample it into the ring buffer.
1656 if (stbir__use_width_upsampling(stbir_info
))
1657 stbir__resample_horizontal_upsample(stbir_info
, n
, stbir__add_empty_ring_buffer_entry(stbir_info
, n
));
1659 stbir__resample_horizontal_downsample(stbir_info
, n
, stbir__add_empty_ring_buffer_entry(stbir_info
, n
));
1661 // Now it's sitting in the ring buffer ready to be used as source for the vertical sampling.
1664 static void stbir__decode_and_resample_downsample(stbir__info
* stbir_info
, int n
)
1666 // Decode the nth scanline from the source image into the decode buffer.
1667 stbir__decode_scanline(stbir_info
, n
);
1669 memset(stbir_info
->horizontal_buffer
, 0, stbir_info
->output_w
* stbir_info
->channels
* sizeof(float));
1671 // Now resample it into the horizontal buffer.
1672 if (stbir__use_width_upsampling(stbir_info
))
1673 stbir__resample_horizontal_upsample(stbir_info
, n
, stbir_info
->horizontal_buffer
);
1675 stbir__resample_horizontal_downsample(stbir_info
, n
, stbir_info
->horizontal_buffer
);
1677 // Now it's sitting in the horizontal buffer ready to be distributed into the ring buffers.
1680 // Get the specified scan line from the ring buffer.
1681 static float* stbir__get_ring_buffer_scanline(int get_scanline
, float* ring_buffer
, int begin_index
, int first_scanline
, int ring_buffer_size
, int ring_buffer_length
)
1683 int ring_buffer_index
= (begin_index
+ (get_scanline
- first_scanline
)) % ring_buffer_size
;
1684 return stbir__get_ring_buffer_entry(ring_buffer
, ring_buffer_index
, ring_buffer_length
);
1688 static void stbir__encode_scanline(stbir__info
* stbir_info
, int num_pixels
, void *output_buffer
, float *encode_buffer
, int channels
, int alpha_channel
, int decode
)
1693 stbir_uint16 nonalpha
[STBIR_MAX_CHANNELS
];
1695 if (!(stbir_info
->flags
&STBIR_FLAG_ALPHA_PREMULTIPLIED
))
1697 for (x
=0; x
< num_pixels
; ++x
)
1699 int pixel_index
= x
*channels
;
1701 float alpha
= encode_buffer
[pixel_index
+ alpha_channel
];
1702 float reciprocal_alpha
= alpha
? 1.0f
/ alpha
: 0;
1704 // unrolling this produced a 1% slowdown upscaling a large RGBA linear-space image on my machine - stb
1705 for (n
= 0; n
< channels
; n
++)
1706 if (n
!= alpha_channel
)
1707 encode_buffer
[pixel_index
+ n
] *= reciprocal_alpha
;
1709 // We added in a small epsilon to prevent the color channel from being deleted with zero alpha.
1710 // Because we only add it for integer types, it will automatically be discarded on integer
1711 // conversion, so we don't need to subtract it back out (which would be problematic for
1712 // numeric precision reasons).
1716 // build a table of all channels that need colorspace correction, so
1717 // we don't perform colorspace correction on channels that don't need it.
1718 for (x
=0, num_nonalpha
=0; x
< channels
; ++x
)
1719 if (x
!= alpha_channel
|| (stbir_info
->flags
& STBIR_FLAG_ALPHA_USES_COLORSPACE
))
1720 nonalpha
[num_nonalpha
++] = x
;
1722 #define STBIR__ROUND_INT(f) ((int) ((f)+0.5))
1723 #define STBIR__ROUND_UINT(f) ((stbir_uint32) ((f)+0.5))
1725 #ifdef STBIR__SATURATE_INT
1726 #define STBIR__ENCODE_LINEAR8(f) stbir__saturate8 (STBIR__ROUND_INT((f) * 255 ))
1727 #define STBIR__ENCODE_LINEAR16(f) stbir__saturate16(STBIR__ROUND_INT((f) * 65535))
1729 #define STBIR__ENCODE_LINEAR8(f) (unsigned char ) STBIR__ROUND_INT(stbir__saturate(f) * 255 )
1730 #define STBIR__ENCODE_LINEAR16(f) (unsigned short) STBIR__ROUND_INT(stbir__saturate(f) * 65535)
1735 case STBIR__DECODE(STBIR_TYPE_UINT8
, STBIR_COLORSPACE_LINEAR
):
1736 for (x
=0; x
< num_pixels
; ++x
)
1738 int pixel_index
= x
*channels
;
1740 for (n
= 0; n
< channels
; n
++)
1742 int index
= pixel_index
+ n
;
1743 ((unsigned char*)output_buffer
)[index
] = STBIR__ENCODE_LINEAR8(encode_buffer
[index
]);
1748 case STBIR__DECODE(STBIR_TYPE_UINT8
, STBIR_COLORSPACE_SRGB
):
1749 for (x
=0; x
< num_pixels
; ++x
)
1751 int pixel_index
= x
*channels
;
1753 for (n
= 0; n
< num_nonalpha
; n
++)
1755 int index
= pixel_index
+ nonalpha
[n
];
1756 ((unsigned char*)output_buffer
)[index
] = stbir__linear_to_srgb_uchar(encode_buffer
[index
]);
1759 if (!(stbir_info
->flags
& STBIR_FLAG_ALPHA_USES_COLORSPACE
))
1760 ((unsigned char *)output_buffer
)[pixel_index
+ alpha_channel
] = STBIR__ENCODE_LINEAR8(encode_buffer
[pixel_index
+alpha_channel
]);
1764 case STBIR__DECODE(STBIR_TYPE_UINT16
, STBIR_COLORSPACE_LINEAR
):
1765 for (x
=0; x
< num_pixels
; ++x
)
1767 int pixel_index
= x
*channels
;
1769 for (n
= 0; n
< channels
; n
++)
1771 int index
= pixel_index
+ n
;
1772 ((unsigned short*)output_buffer
)[index
] = STBIR__ENCODE_LINEAR16(encode_buffer
[index
]);
1777 case STBIR__DECODE(STBIR_TYPE_UINT16
, STBIR_COLORSPACE_SRGB
):
1778 for (x
=0; x
< num_pixels
; ++x
)
1780 int pixel_index
= x
*channels
;
1782 for (n
= 0; n
< num_nonalpha
; n
++)
1784 int index
= pixel_index
+ nonalpha
[n
];
1785 ((unsigned short*)output_buffer
)[index
] = (unsigned short)STBIR__ROUND_INT(stbir__linear_to_srgb(stbir__saturate(encode_buffer
[index
])) * 65535);
1788 if (!(stbir_info
->flags
&STBIR_FLAG_ALPHA_USES_COLORSPACE
))
1789 ((unsigned short*)output_buffer
)[pixel_index
+ alpha_channel
] = STBIR__ENCODE_LINEAR16(encode_buffer
[pixel_index
+ alpha_channel
]);
1794 case STBIR__DECODE(STBIR_TYPE_UINT32
, STBIR_COLORSPACE_LINEAR
):
1795 for (x
=0; x
< num_pixels
; ++x
)
1797 int pixel_index
= x
*channels
;
1799 for (n
= 0; n
< channels
; n
++)
1801 int index
= pixel_index
+ n
;
1802 ((unsigned int*)output_buffer
)[index
] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__saturate(encode_buffer
[index
])) * 4294967295);
1807 case STBIR__DECODE(STBIR_TYPE_UINT32
, STBIR_COLORSPACE_SRGB
):
1808 for (x
=0; x
< num_pixels
; ++x
)
1810 int pixel_index
= x
*channels
;
1812 for (n
= 0; n
< num_nonalpha
; n
++)
1814 int index
= pixel_index
+ nonalpha
[n
];
1815 ((unsigned int*)output_buffer
)[index
] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__linear_to_srgb(stbir__saturate(encode_buffer
[index
]))) * 4294967295);
1818 if (!(stbir_info
->flags
&STBIR_FLAG_ALPHA_USES_COLORSPACE
))
1819 ((unsigned int*)output_buffer
)[pixel_index
+ alpha_channel
] = (unsigned int)STBIR__ROUND_INT(((double)stbir__saturate(encode_buffer
[pixel_index
+ alpha_channel
])) * 4294967295);
1823 case STBIR__DECODE(STBIR_TYPE_FLOAT
, STBIR_COLORSPACE_LINEAR
):
1824 for (x
=0; x
< num_pixels
; ++x
)
1826 int pixel_index
= x
*channels
;
1828 for (n
= 0; n
< channels
; n
++)
1830 int index
= pixel_index
+ n
;
1831 ((float*)output_buffer
)[index
] = encode_buffer
[index
];
1836 case STBIR__DECODE(STBIR_TYPE_FLOAT
, STBIR_COLORSPACE_SRGB
):
1837 for (x
=0; x
< num_pixels
; ++x
)
1839 int pixel_index
= x
*channels
;
1841 for (n
= 0; n
< num_nonalpha
; n
++)
1843 int index
= pixel_index
+ nonalpha
[n
];
1844 ((float*)output_buffer
)[index
] = stbir__linear_to_srgb(encode_buffer
[index
]);
1847 if (!(stbir_info
->flags
&STBIR_FLAG_ALPHA_USES_COLORSPACE
))
1848 ((float*)output_buffer
)[pixel_index
+ alpha_channel
] = encode_buffer
[pixel_index
+ alpha_channel
];
1853 STBIR_ASSERT(!"Unknown type/colorspace/channels combination.");
1858 static void stbir__resample_vertical_upsample(stbir__info
* stbir_info
, int n
, int in_first_scanline
, int in_last_scanline
, float in_center_of_out
)
1861 int output_w
= stbir_info
->output_w
;
1862 stbir__contributors
* vertical_contributors
= stbir_info
->vertical_contributors
;
1863 float* vertical_coefficients
= stbir_info
->vertical_coefficients
;
1864 int channels
= stbir_info
->channels
;
1865 int alpha_channel
= stbir_info
->alpha_channel
;
1866 int type
= stbir_info
->type
;
1867 int colorspace
= stbir_info
->colorspace
;
1868 int kernel_pixel_width
= stbir_info
->vertical_filter_pixel_width
;
1869 void* output_data
= stbir_info
->output_data
;
1870 float* encode_buffer
= stbir_info
->encode_buffer
;
1871 int decode
= STBIR__DECODE(type
, colorspace
);
1872 int coefficient_width
= stbir_info
->vertical_coefficient_width
;
1873 int coefficient_counter
;
1874 int contributor
= n
;
1876 float* ring_buffer
= stbir_info
->ring_buffer
;
1877 int ring_buffer_begin_index
= stbir_info
->ring_buffer_begin_index
;
1878 int ring_buffer_first_scanline
= stbir_info
->ring_buffer_first_scanline
;
1879 int ring_buffer_last_scanline
= stbir_info
->ring_buffer_last_scanline
;
1880 int ring_buffer_length
= stbir_info
->ring_buffer_length_bytes
/sizeof(float);
1882 int n0
,n1
, output_row_start
;
1883 int coefficient_group
= coefficient_width
* contributor
;
1885 n0
= vertical_contributors
[contributor
].n0
;
1886 n1
= vertical_contributors
[contributor
].n1
;
1888 output_row_start
= n
* stbir_info
->output_stride_bytes
;
1890 STBIR_ASSERT(stbir__use_height_upsampling(stbir_info
));
1892 memset(encode_buffer
, 0, output_w
* sizeof(float) * channels
);
1894 // I tried reblocking this for better cache usage of encode_buffer
1895 // (using x_outer, k, x_inner), but it lost speed. -- stb
1897 coefficient_counter
= 0;
1900 for (k
= n0
; k
<= n1
; k
++)
1902 int coefficient_index
= coefficient_counter
++;
1903 float* ring_buffer_entry
= stbir__get_ring_buffer_scanline(k
, ring_buffer
, ring_buffer_begin_index
, ring_buffer_first_scanline
, kernel_pixel_width
, ring_buffer_length
);
1904 float coefficient
= vertical_coefficients
[coefficient_group
+ coefficient_index
];
1905 for (x
= 0; x
< output_w
; ++x
)
1907 int in_pixel_index
= x
* 1;
1908 encode_buffer
[in_pixel_index
+ 0] += ring_buffer_entry
[in_pixel_index
+ 0] * coefficient
;
1913 for (k
= n0
; k
<= n1
; k
++)
1915 int coefficient_index
= coefficient_counter
++;
1916 float* ring_buffer_entry
= stbir__get_ring_buffer_scanline(k
, ring_buffer
, ring_buffer_begin_index
, ring_buffer_first_scanline
, kernel_pixel_width
, ring_buffer_length
);
1917 float coefficient
= vertical_coefficients
[coefficient_group
+ coefficient_index
];
1918 for (x
= 0; x
< output_w
; ++x
)
1920 int in_pixel_index
= x
* 2;
1921 encode_buffer
[in_pixel_index
+ 0] += ring_buffer_entry
[in_pixel_index
+ 0] * coefficient
;
1922 encode_buffer
[in_pixel_index
+ 1] += ring_buffer_entry
[in_pixel_index
+ 1] * coefficient
;
1927 for (k
= n0
; k
<= n1
; k
++)
1929 int coefficient_index
= coefficient_counter
++;
1930 float* ring_buffer_entry
= stbir__get_ring_buffer_scanline(k
, ring_buffer
, ring_buffer_begin_index
, ring_buffer_first_scanline
, kernel_pixel_width
, ring_buffer_length
);
1931 float coefficient
= vertical_coefficients
[coefficient_group
+ coefficient_index
];
1932 for (x
= 0; x
< output_w
; ++x
)
1934 int in_pixel_index
= x
* 3;
1935 encode_buffer
[in_pixel_index
+ 0] += ring_buffer_entry
[in_pixel_index
+ 0] * coefficient
;
1936 encode_buffer
[in_pixel_index
+ 1] += ring_buffer_entry
[in_pixel_index
+ 1] * coefficient
;
1937 encode_buffer
[in_pixel_index
+ 2] += ring_buffer_entry
[in_pixel_index
+ 2] * coefficient
;
1942 for (k
= n0
; k
<= n1
; k
++)
1944 int coefficient_index
= coefficient_counter
++;
1945 float* ring_buffer_entry
= stbir__get_ring_buffer_scanline(k
, ring_buffer
, ring_buffer_begin_index
, ring_buffer_first_scanline
, kernel_pixel_width
, ring_buffer_length
);
1946 float coefficient
= vertical_coefficients
[coefficient_group
+ coefficient_index
];
1947 for (x
= 0; x
< output_w
; ++x
)
1949 int in_pixel_index
= x
* 4;
1950 encode_buffer
[in_pixel_index
+ 0] += ring_buffer_entry
[in_pixel_index
+ 0] * coefficient
;
1951 encode_buffer
[in_pixel_index
+ 1] += ring_buffer_entry
[in_pixel_index
+ 1] * coefficient
;
1952 encode_buffer
[in_pixel_index
+ 2] += ring_buffer_entry
[in_pixel_index
+ 2] * coefficient
;
1953 encode_buffer
[in_pixel_index
+ 3] += ring_buffer_entry
[in_pixel_index
+ 3] * coefficient
;
1958 for (k
= n0
; k
<= n1
; k
++)
1960 int coefficient_index
= coefficient_counter
++;
1961 float* ring_buffer_entry
= stbir__get_ring_buffer_scanline(k
, ring_buffer
, ring_buffer_begin_index
, ring_buffer_first_scanline
, kernel_pixel_width
, ring_buffer_length
);
1962 float coefficient
= vertical_coefficients
[coefficient_group
+ coefficient_index
];
1963 for (x
= 0; x
< output_w
; ++x
)
1965 int in_pixel_index
= x
* channels
;
1967 for (c
= 0; c
< channels
; c
++)
1968 encode_buffer
[in_pixel_index
+ c
] += ring_buffer_entry
[in_pixel_index
+ c
] * coefficient
;
1973 stbir__encode_scanline(stbir_info
, output_w
, (char *) output_data
+ output_row_start
, encode_buffer
, channels
, alpha_channel
, decode
);
1976 static void stbir__resample_vertical_downsample(stbir__info
* stbir_info
, int n
, int in_first_scanline
, int in_last_scanline
, float in_center_of_out
)
1979 int output_w
= stbir_info
->output_w
;
1980 int output_h
= stbir_info
->output_h
;
1981 stbir__contributors
* vertical_contributors
= stbir_info
->vertical_contributors
;
1982 float* vertical_coefficients
= stbir_info
->vertical_coefficients
;
1983 int channels
= stbir_info
->channels
;
1984 int kernel_pixel_width
= stbir_info
->vertical_filter_pixel_width
;
1985 void* output_data
= stbir_info
->output_data
;
1986 float* horizontal_buffer
= stbir_info
->horizontal_buffer
;
1987 int coefficient_width
= stbir_info
->vertical_coefficient_width
;
1988 int contributor
= n
+ stbir_info
->vertical_filter_pixel_margin
;
1990 float* ring_buffer
= stbir_info
->ring_buffer
;
1991 int ring_buffer_begin_index
= stbir_info
->ring_buffer_begin_index
;
1992 int ring_buffer_first_scanline
= stbir_info
->ring_buffer_first_scanline
;
1993 int ring_buffer_last_scanline
= stbir_info
->ring_buffer_last_scanline
;
1994 int ring_buffer_length
= stbir_info
->ring_buffer_length_bytes
/sizeof(float);
1997 n0
= vertical_contributors
[contributor
].n0
;
1998 n1
= vertical_contributors
[contributor
].n1
;
2000 STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info
));
2002 for (k
= n0
; k
<= n1
; k
++)
2004 int coefficient_index
= k
- n0
;
2005 int coefficient_group
= coefficient_width
* contributor
;
2006 float coefficient
= vertical_coefficients
[coefficient_group
+ coefficient_index
];
2008 float* ring_buffer_entry
= stbir__get_ring_buffer_scanline(k
, ring_buffer
, ring_buffer_begin_index
, ring_buffer_first_scanline
, kernel_pixel_width
, ring_buffer_length
);
2012 for (x
= 0; x
< output_w
; x
++)
2014 int in_pixel_index
= x
* 1;
2015 ring_buffer_entry
[in_pixel_index
+ 0] += horizontal_buffer
[in_pixel_index
+ 0] * coefficient
;
2019 for (x
= 0; x
< output_w
; x
++)
2021 int in_pixel_index
= x
* 2;
2022 ring_buffer_entry
[in_pixel_index
+ 0] += horizontal_buffer
[in_pixel_index
+ 0] * coefficient
;
2023 ring_buffer_entry
[in_pixel_index
+ 1] += horizontal_buffer
[in_pixel_index
+ 1] * coefficient
;
2027 for (x
= 0; x
< output_w
; x
++)
2029 int in_pixel_index
= x
* 3;
2030 ring_buffer_entry
[in_pixel_index
+ 0] += horizontal_buffer
[in_pixel_index
+ 0] * coefficient
;
2031 ring_buffer_entry
[in_pixel_index
+ 1] += horizontal_buffer
[in_pixel_index
+ 1] * coefficient
;
2032 ring_buffer_entry
[in_pixel_index
+ 2] += horizontal_buffer
[in_pixel_index
+ 2] * coefficient
;
2036 for (x
= 0; x
< output_w
; x
++)
2038 int in_pixel_index
= x
* 4;
2039 ring_buffer_entry
[in_pixel_index
+ 0] += horizontal_buffer
[in_pixel_index
+ 0] * coefficient
;
2040 ring_buffer_entry
[in_pixel_index
+ 1] += horizontal_buffer
[in_pixel_index
+ 1] * coefficient
;
2041 ring_buffer_entry
[in_pixel_index
+ 2] += horizontal_buffer
[in_pixel_index
+ 2] * coefficient
;
2042 ring_buffer_entry
[in_pixel_index
+ 3] += horizontal_buffer
[in_pixel_index
+ 3] * coefficient
;
2046 for (x
= 0; x
< output_w
; x
++)
2048 int in_pixel_index
= x
* channels
;
2051 for (c
= 0; c
< channels
; c
++)
2052 ring_buffer_entry
[in_pixel_index
+ c
] += horizontal_buffer
[in_pixel_index
+ c
] * coefficient
;
2059 static void stbir__buffer_loop_upsample(stbir__info
* stbir_info
)
2062 float scale_ratio
= stbir_info
->vertical_scale
;
2063 float out_scanlines_radius
= stbir__filter_info_table
[stbir_info
->vertical_filter
].support(1/scale_ratio
) * scale_ratio
;
2065 STBIR_ASSERT(stbir__use_height_upsampling(stbir_info
));
2067 for (y
= 0; y
< stbir_info
->output_h
; y
++)
2069 float in_center_of_out
= 0; // Center of the current out scanline in the in scanline space
2070 int in_first_scanline
= 0, in_last_scanline
= 0;
2072 stbir__calculate_sample_range_upsample(y
, out_scanlines_radius
, scale_ratio
, stbir_info
->vertical_shift
, &in_first_scanline
, &in_last_scanline
, &in_center_of_out
);
2074 STBIR_ASSERT(in_last_scanline
- in_first_scanline
<= stbir_info
->vertical_filter_pixel_width
);
2076 if (stbir_info
->ring_buffer_begin_index
>= 0)
2078 // Get rid of whatever we don't need anymore.
2079 while (in_first_scanline
> stbir_info
->ring_buffer_first_scanline
)
2081 if (stbir_info
->ring_buffer_first_scanline
== stbir_info
->ring_buffer_last_scanline
)
2083 // We just popped the last scanline off the ring buffer.
2084 // Reset it to the empty state.
2085 stbir_info
->ring_buffer_begin_index
= -1;
2086 stbir_info
->ring_buffer_first_scanline
= 0;
2087 stbir_info
->ring_buffer_last_scanline
= 0;
2092 stbir_info
->ring_buffer_first_scanline
++;
2093 stbir_info
->ring_buffer_begin_index
= (stbir_info
->ring_buffer_begin_index
+ 1) % stbir_info
->vertical_filter_pixel_width
;
2098 // Load in new ones.
2099 if (stbir_info
->ring_buffer_begin_index
< 0)
2100 stbir__decode_and_resample_upsample(stbir_info
, in_first_scanline
);
2102 while (in_last_scanline
> stbir_info
->ring_buffer_last_scanline
)
2103 stbir__decode_and_resample_upsample(stbir_info
, stbir_info
->ring_buffer_last_scanline
+ 1);
2105 // Now all buffers should be ready to write a row of vertical sampling.
2106 stbir__resample_vertical_upsample(stbir_info
, y
, in_first_scanline
, in_last_scanline
, in_center_of_out
);
2108 STBIR_PROGRESS_REPORT((float)y
/ stbir_info
->output_h
);
2112 static void stbir__empty_ring_buffer(stbir__info
* stbir_info
, int first_necessary_scanline
)
2114 int output_stride_bytes
= stbir_info
->output_stride_bytes
;
2115 int channels
= stbir_info
->channels
;
2116 int alpha_channel
= stbir_info
->alpha_channel
;
2117 int type
= stbir_info
->type
;
2118 int colorspace
= stbir_info
->colorspace
;
2119 int output_w
= stbir_info
->output_w
;
2120 void* output_data
= stbir_info
->output_data
;
2121 int decode
= STBIR__DECODE(type
, colorspace
);
2123 float* ring_buffer
= stbir_info
->ring_buffer
;
2124 int ring_buffer_length
= stbir_info
->ring_buffer_length_bytes
/sizeof(float);
2126 if (stbir_info
->ring_buffer_begin_index
>= 0)
2128 // Get rid of whatever we don't need anymore.
2129 while (first_necessary_scanline
> stbir_info
->ring_buffer_first_scanline
)
2131 if (stbir_info
->ring_buffer_first_scanline
>= 0 && stbir_info
->ring_buffer_first_scanline
< stbir_info
->output_h
)
2133 int output_row_start
= stbir_info
->ring_buffer_first_scanline
* output_stride_bytes
;
2134 float* ring_buffer_entry
= stbir__get_ring_buffer_entry(ring_buffer
, stbir_info
->ring_buffer_begin_index
, ring_buffer_length
);
2135 stbir__encode_scanline(stbir_info
, output_w
, (char *) output_data
+ output_row_start
, ring_buffer_entry
, channels
, alpha_channel
, decode
);
2136 STBIR_PROGRESS_REPORT((float)stbir_info
->ring_buffer_first_scanline
/ stbir_info
->output_h
);
2139 if (stbir_info
->ring_buffer_first_scanline
== stbir_info
->ring_buffer_last_scanline
)
2141 // We just popped the last scanline off the ring buffer.
2142 // Reset it to the empty state.
2143 stbir_info
->ring_buffer_begin_index
= -1;
2144 stbir_info
->ring_buffer_first_scanline
= 0;
2145 stbir_info
->ring_buffer_last_scanline
= 0;
2150 stbir_info
->ring_buffer_first_scanline
++;
2151 stbir_info
->ring_buffer_begin_index
= (stbir_info
->ring_buffer_begin_index
+ 1) % stbir_info
->vertical_filter_pixel_width
;
2157 static void stbir__buffer_loop_downsample(stbir__info
* stbir_info
)
2160 float scale_ratio
= stbir_info
->vertical_scale
;
2161 int output_h
= stbir_info
->output_h
;
2162 float in_pixels_radius
= stbir__filter_info_table
[stbir_info
->vertical_filter
].support(scale_ratio
) / scale_ratio
;
2163 int pixel_margin
= stbir_info
->vertical_filter_pixel_margin
;
2164 int max_y
= stbir_info
->input_h
+ pixel_margin
;
2166 STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info
));
2168 for (y
= -pixel_margin
; y
< max_y
; y
++)
2170 float out_center_of_in
; // Center of the current out scanline in the in scanline space
2171 int out_first_scanline
, out_last_scanline
;
2173 stbir__calculate_sample_range_downsample(y
, in_pixels_radius
, scale_ratio
, stbir_info
->vertical_shift
, &out_first_scanline
, &out_last_scanline
, &out_center_of_in
);
2175 STBIR_ASSERT(out_last_scanline
- out_first_scanline
<= stbir_info
->vertical_filter_pixel_width
);
2177 if (out_last_scanline
< 0 || out_first_scanline
>= output_h
)
2180 stbir__empty_ring_buffer(stbir_info
, out_first_scanline
);
2182 stbir__decode_and_resample_downsample(stbir_info
, y
);
2184 // Load in new ones.
2185 if (stbir_info
->ring_buffer_begin_index
< 0)
2186 stbir__add_empty_ring_buffer_entry(stbir_info
, out_first_scanline
);
2188 while (out_last_scanline
> stbir_info
->ring_buffer_last_scanline
)
2189 stbir__add_empty_ring_buffer_entry(stbir_info
, stbir_info
->ring_buffer_last_scanline
+ 1);
2191 // Now the horizontal buffer is ready to write to all ring buffer rows.
2192 stbir__resample_vertical_downsample(stbir_info
, y
, out_first_scanline
, out_last_scanline
, out_center_of_in
);
2195 stbir__empty_ring_buffer(stbir_info
, stbir_info
->output_h
);
2198 static void stbir__setup(stbir__info
*info
, int input_w
, int input_h
, int output_w
, int output_h
, int channels
)
2200 info
->input_w
= input_w
;
2201 info
->input_h
= input_h
;
2202 info
->output_w
= output_w
;
2203 info
->output_h
= output_h
;
2204 info
->channels
= channels
;
2207 static void stbir__calculate_transform(stbir__info
*info
, float s0
, float t0
, float s1
, float t1
, float *transform
)
2216 info
->horizontal_scale
= transform
[0];
2217 info
->vertical_scale
= transform
[1];
2218 info
->horizontal_shift
= transform
[2];
2219 info
->vertical_shift
= transform
[3];
2223 info
->horizontal_scale
= ((float)info
->output_w
/ info
->input_w
) / (s1
- s0
);
2224 info
->vertical_scale
= ((float)info
->output_h
/ info
->input_h
) / (t1
- t0
);
2226 info
->horizontal_shift
= s0
* info
->output_w
/ (s1
- s0
);
2227 info
->vertical_shift
= t0
* info
->output_h
/ (t1
- t0
);
2231 static void stbir__choose_filter(stbir__info
*info
, stbir_filter h_filter
, stbir_filter v_filter
)
2234 h_filter
= stbir__use_upsampling(info
->horizontal_scale
) ? STBIR_DEFAULT_FILTER_UPSAMPLE
: STBIR_DEFAULT_FILTER_DOWNSAMPLE
;
2236 v_filter
= stbir__use_upsampling(info
->vertical_scale
) ? STBIR_DEFAULT_FILTER_UPSAMPLE
: STBIR_DEFAULT_FILTER_DOWNSAMPLE
;
2237 info
->horizontal_filter
= h_filter
;
2238 info
->vertical_filter
= v_filter
;
2241 static stbir_uint32
stbir__calculate_memory(stbir__info
*info
)
2243 int pixel_margin
= stbir__get_filter_pixel_margin(info
->horizontal_filter
, info
->horizontal_scale
);
2244 int filter_height
= stbir__get_filter_pixel_width(info
->vertical_filter
, info
->vertical_scale
);
2246 info
->horizontal_num_contributors
= stbir__get_contributors(info
->horizontal_scale
, info
->horizontal_filter
, info
->input_w
, info
->output_w
);
2247 info
->vertical_num_contributors
= stbir__get_contributors(info
->vertical_scale
, info
->vertical_filter
, info
->input_h
, info
->output_h
);
2249 info
->horizontal_contributors_size
= info
->horizontal_num_contributors
* sizeof(stbir__contributors
);
2250 info
->horizontal_coefficients_size
= stbir__get_total_horizontal_coefficients(info
) * sizeof(float);
2251 info
->vertical_contributors_size
= info
->vertical_num_contributors
* sizeof(stbir__contributors
);
2252 info
->vertical_coefficients_size
= stbir__get_total_vertical_coefficients(info
) * sizeof(float);
2253 info
->decode_buffer_size
= (info
->input_w
+ pixel_margin
* 2) * info
->channels
* sizeof(float);
2254 info
->horizontal_buffer_size
= info
->output_w
* info
->channels
* sizeof(float);
2255 info
->ring_buffer_size
= info
->output_w
* info
->channels
* filter_height
* sizeof(float);
2256 info
->encode_buffer_size
= info
->output_w
* info
->channels
* sizeof(float);
2258 STBIR_ASSERT(info
->horizontal_filter
!= 0);
2259 STBIR_ASSERT(info
->horizontal_filter
< STBIR__ARRAY_SIZE(stbir__filter_info_table
)); // this now happens too late
2260 STBIR_ASSERT(info
->vertical_filter
!= 0);
2261 STBIR_ASSERT(info
->vertical_filter
< STBIR__ARRAY_SIZE(stbir__filter_info_table
)); // this now happens too late
2263 if (stbir__use_height_upsampling(info
))
2264 // The horizontal buffer is for when we're downsampling the height and we
2265 // can't output the result of sampling the decode buffer directly into the
2267 info
->horizontal_buffer_size
= 0;
2269 // The encode buffer is to retain precision in the height upsampling method
2270 // and isn't used when height downsampling.
2271 info
->encode_buffer_size
= 0;
2273 return info
->horizontal_contributors_size
+ info
->horizontal_coefficients_size
2274 + info
->vertical_contributors_size
+ info
->vertical_coefficients_size
2275 + info
->decode_buffer_size
+ info
->horizontal_buffer_size
2276 + info
->ring_buffer_size
+ info
->encode_buffer_size
;
2279 static int stbir__resize_allocated(stbir__info
*info
,
2280 const void* input_data
, int input_stride_in_bytes
,
2281 void* output_data
, int output_stride_in_bytes
,
2282 int alpha_channel
, stbir_uint32 flags
, stbir_datatype type
,
2283 stbir_edge edge_horizontal
, stbir_edge edge_vertical
, stbir_colorspace colorspace
,
2284 void* tempmem
, size_t tempmem_size_in_bytes
)
2286 size_t memory_required
= stbir__calculate_memory(info
);
2288 int width_stride_input
= input_stride_in_bytes
? input_stride_in_bytes
: info
->channels
* info
->input_w
* stbir__type_size
[type
];
2289 int width_stride_output
= output_stride_in_bytes
? output_stride_in_bytes
: info
->channels
* info
->output_w
* stbir__type_size
[type
];
2291 #ifdef STBIR_DEBUG_OVERWRITE_TEST
2292 #define OVERWRITE_ARRAY_SIZE 8
2293 unsigned char overwrite_output_before_pre
[OVERWRITE_ARRAY_SIZE
];
2294 unsigned char overwrite_tempmem_before_pre
[OVERWRITE_ARRAY_SIZE
];
2295 unsigned char overwrite_output_after_pre
[OVERWRITE_ARRAY_SIZE
];
2296 unsigned char overwrite_tempmem_after_pre
[OVERWRITE_ARRAY_SIZE
];
2298 size_t begin_forbidden
= width_stride_output
* (info
->output_h
- 1) + info
->output_w
* info
->channels
* stbir__type_size
[type
];
2299 memcpy(overwrite_output_before_pre
, &((unsigned char*)output_data
)[-OVERWRITE_ARRAY_SIZE
], OVERWRITE_ARRAY_SIZE
);
2300 memcpy(overwrite_output_after_pre
, &((unsigned char*)output_data
)[begin_forbidden
], OVERWRITE_ARRAY_SIZE
);
2301 memcpy(overwrite_tempmem_before_pre
, &((unsigned char*)tempmem
)[-OVERWRITE_ARRAY_SIZE
], OVERWRITE_ARRAY_SIZE
);
2302 memcpy(overwrite_tempmem_after_pre
, &((unsigned char*)tempmem
)[tempmem_size_in_bytes
], OVERWRITE_ARRAY_SIZE
);
2305 STBIR_ASSERT(info
->channels
>= 0);
2306 STBIR_ASSERT(info
->channels
<= STBIR_MAX_CHANNELS
);
2308 if (info
->channels
< 0 || info
->channels
> STBIR_MAX_CHANNELS
)
2311 STBIR_ASSERT(info
->horizontal_filter
< STBIR__ARRAY_SIZE(stbir__filter_info_table
));
2312 STBIR_ASSERT(info
->vertical_filter
< STBIR__ARRAY_SIZE(stbir__filter_info_table
));
2314 if (info
->horizontal_filter
>= STBIR__ARRAY_SIZE(stbir__filter_info_table
))
2316 if (info
->vertical_filter
>= STBIR__ARRAY_SIZE(stbir__filter_info_table
))
2319 if (alpha_channel
< 0)
2320 flags
|= STBIR_FLAG_ALPHA_USES_COLORSPACE
| STBIR_FLAG_ALPHA_PREMULTIPLIED
;
2322 if (!(flags
&STBIR_FLAG_ALPHA_USES_COLORSPACE
) || !(flags
&STBIR_FLAG_ALPHA_PREMULTIPLIED
))
2323 STBIR_ASSERT(alpha_channel
>= 0 && alpha_channel
< info
->channels
);
2325 if (alpha_channel
>= info
->channels
)
2328 STBIR_ASSERT(tempmem
);
2333 STBIR_ASSERT(tempmem_size_in_bytes
>= memory_required
);
2335 if (tempmem_size_in_bytes
< memory_required
)
2338 memset(tempmem
, 0, tempmem_size_in_bytes
);
2340 info
->input_data
= input_data
;
2341 info
->input_stride_bytes
= width_stride_input
;
2343 info
->output_data
= output_data
;
2344 info
->output_stride_bytes
= width_stride_output
;
2346 info
->alpha_channel
= alpha_channel
;
2347 info
->flags
= flags
;
2349 info
->edge_horizontal
= edge_horizontal
;
2350 info
->edge_vertical
= edge_vertical
;
2351 info
->colorspace
= colorspace
;
2353 info
->horizontal_coefficient_width
= stbir__get_coefficient_width (info
->horizontal_filter
, info
->horizontal_scale
);
2354 info
->vertical_coefficient_width
= stbir__get_coefficient_width (info
->vertical_filter
, info
->vertical_scale
);
2355 info
->horizontal_filter_pixel_width
= stbir__get_filter_pixel_width (info
->horizontal_filter
, info
->horizontal_scale
);
2356 info
->vertical_filter_pixel_width
= stbir__get_filter_pixel_width (info
->vertical_filter
, info
->vertical_scale
);
2357 info
->horizontal_filter_pixel_margin
= stbir__get_filter_pixel_margin(info
->horizontal_filter
, info
->horizontal_scale
);
2358 info
->vertical_filter_pixel_margin
= stbir__get_filter_pixel_margin(info
->vertical_filter
, info
->vertical_scale
);
2360 info
->ring_buffer_length_bytes
= info
->output_w
* info
->channels
* sizeof(float);
2361 info
->decode_buffer_pixels
= info
->input_w
+ info
->horizontal_filter_pixel_margin
* 2;
2363 #define STBIR__NEXT_MEMPTR(current, newtype) (newtype*)(((unsigned char*)current) + current##_size)
2365 info
->horizontal_contributors
= (stbir__contributors
*) tempmem
;
2366 info
->horizontal_coefficients
= STBIR__NEXT_MEMPTR(info
->horizontal_contributors
, float);
2367 info
->vertical_contributors
= STBIR__NEXT_MEMPTR(info
->horizontal_coefficients
, stbir__contributors
);
2368 info
->vertical_coefficients
= STBIR__NEXT_MEMPTR(info
->vertical_contributors
, float);
2369 info
->decode_buffer
= STBIR__NEXT_MEMPTR(info
->vertical_coefficients
, float);
2371 if (stbir__use_height_upsampling(info
))
2373 info
->horizontal_buffer
= NULL
;
2374 info
->ring_buffer
= STBIR__NEXT_MEMPTR(info
->decode_buffer
, float);
2375 info
->encode_buffer
= STBIR__NEXT_MEMPTR(info
->ring_buffer
, float);
2377 STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info
->encode_buffer
, unsigned char) == (size_t)tempmem
+ tempmem_size_in_bytes
);
2381 info
->horizontal_buffer
= STBIR__NEXT_MEMPTR(info
->decode_buffer
, float);
2382 info
->ring_buffer
= STBIR__NEXT_MEMPTR(info
->horizontal_buffer
, float);
2383 info
->encode_buffer
= NULL
;
2385 STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info
->ring_buffer
, unsigned char) == (size_t)tempmem
+ tempmem_size_in_bytes
);
2388 #undef STBIR__NEXT_MEMPTR
2390 // This signals that the ring buffer is empty
2391 info
->ring_buffer_begin_index
= -1;
2393 stbir__calculate_filters(info
, info
->horizontal_contributors
, info
->horizontal_coefficients
, info
->horizontal_filter
, info
->horizontal_scale
, info
->horizontal_shift
, info
->input_w
, info
->output_w
);
2394 stbir__calculate_filters(info
, info
->vertical_contributors
, info
->vertical_coefficients
, info
->vertical_filter
, info
->vertical_scale
, info
->vertical_shift
, info
->input_h
, info
->output_h
);
2396 STBIR_PROGRESS_REPORT(0);
2398 if (stbir__use_height_upsampling(info
))
2399 stbir__buffer_loop_upsample(info
);
2401 stbir__buffer_loop_downsample(info
);
2403 STBIR_PROGRESS_REPORT(1);
2405 #ifdef STBIR_DEBUG_OVERWRITE_TEST
2406 STBIR_ASSERT(memcmp(overwrite_output_before_pre
, &((unsigned char*)output_data
)[-OVERWRITE_ARRAY_SIZE
], OVERWRITE_ARRAY_SIZE
) == 0);
2407 STBIR_ASSERT(memcmp(overwrite_output_after_pre
, &((unsigned char*)output_data
)[begin_forbidden
], OVERWRITE_ARRAY_SIZE
) == 0);
2408 STBIR_ASSERT(memcmp(overwrite_tempmem_before_pre
, &((unsigned char*)tempmem
)[-OVERWRITE_ARRAY_SIZE
], OVERWRITE_ARRAY_SIZE
) == 0);
2409 STBIR_ASSERT(memcmp(overwrite_tempmem_after_pre
, &((unsigned char*)tempmem
)[tempmem_size_in_bytes
], OVERWRITE_ARRAY_SIZE
) == 0);
2416 static int stbir__resize_arbitrary(
2417 void *alloc_context
,
2418 const void* input_data
, int input_w
, int input_h
, int input_stride_in_bytes
,
2419 void* output_data
, int output_w
, int output_h
, int output_stride_in_bytes
,
2420 float s0
, float t0
, float s1
, float t1
, float *transform
,
2421 int channels
, int alpha_channel
, stbir_uint32 flags
, stbir_datatype type
,
2422 stbir_filter h_filter
, stbir_filter v_filter
,
2423 stbir_edge edge_horizontal
, stbir_edge edge_vertical
, stbir_colorspace colorspace
)
2427 size_t memory_required
;
2430 stbir__setup(&info
, input_w
, input_h
, output_w
, output_h
, channels
);
2431 stbir__calculate_transform(&info
, s0
,t0
,s1
,t1
,transform
);
2432 stbir__choose_filter(&info
, h_filter
, v_filter
);
2433 memory_required
= stbir__calculate_memory(&info
);
2434 extra_memory
= STBIR_MALLOC(memory_required
, alloc_context
);
2439 result
= stbir__resize_allocated(&info
, input_data
, input_stride_in_bytes
,
2440 output_data
, output_stride_in_bytes
,
2441 alpha_channel
, flags
, type
,
2442 edge_horizontal
, edge_vertical
,
2443 colorspace
, extra_memory
, memory_required
);
2445 STBIR_FREE(extra_memory
, alloc_context
);
2450 STBIRDEF
int stbir_resize_uint8( const unsigned char *input_pixels
, int input_w
, int input_h
, int input_stride_in_bytes
,
2451 unsigned char *output_pixels
, int output_w
, int output_h
, int output_stride_in_bytes
,
2454 return stbir__resize_arbitrary(NULL
, input_pixels
, input_w
, input_h
, input_stride_in_bytes
,
2455 output_pixels
, output_w
, output_h
, output_stride_in_bytes
,
2456 0,0,1,1,NULL
,num_channels
,-1,0, STBIR_TYPE_UINT8
, STBIR_FILTER_DEFAULT
, STBIR_FILTER_DEFAULT
,
2457 STBIR_EDGE_CLAMP
, STBIR_EDGE_CLAMP
, STBIR_COLORSPACE_LINEAR
);
2460 STBIRDEF
int stbir_resize_float( const float *input_pixels
, int input_w
, int input_h
, int input_stride_in_bytes
,
2461 float *output_pixels
, int output_w
, int output_h
, int output_stride_in_bytes
,
2464 return stbir__resize_arbitrary(NULL
, input_pixels
, input_w
, input_h
, input_stride_in_bytes
,
2465 output_pixels
, output_w
, output_h
, output_stride_in_bytes
,
2466 0,0,1,1,NULL
,num_channels
,-1,0, STBIR_TYPE_FLOAT
, STBIR_FILTER_DEFAULT
, STBIR_FILTER_DEFAULT
,
2467 STBIR_EDGE_CLAMP
, STBIR_EDGE_CLAMP
, STBIR_COLORSPACE_LINEAR
);
2470 STBIRDEF
int stbir_resize_uint8_srgb(const unsigned char *input_pixels
, int input_w
, int input_h
, int input_stride_in_bytes
,
2471 unsigned char *output_pixels
, int output_w
, int output_h
, int output_stride_in_bytes
,
2472 int num_channels
, int alpha_channel
, int flags
)
2474 return stbir__resize_arbitrary(NULL
, input_pixels
, input_w
, input_h
, input_stride_in_bytes
,
2475 output_pixels
, output_w
, output_h
, output_stride_in_bytes
,
2476 0,0,1,1,NULL
,num_channels
,alpha_channel
,flags
, STBIR_TYPE_UINT8
, STBIR_FILTER_DEFAULT
, STBIR_FILTER_DEFAULT
,
2477 STBIR_EDGE_CLAMP
, STBIR_EDGE_CLAMP
, STBIR_COLORSPACE_SRGB
);
2480 STBIRDEF
int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels
, int input_w
, int input_h
, int input_stride_in_bytes
,
2481 unsigned char *output_pixels
, int output_w
, int output_h
, int output_stride_in_bytes
,
2482 int num_channels
, int alpha_channel
, int flags
,
2483 stbir_edge edge_wrap_mode
)
2485 return stbir__resize_arbitrary(NULL
, input_pixels
, input_w
, input_h
, input_stride_in_bytes
,
2486 output_pixels
, output_w
, output_h
, output_stride_in_bytes
,
2487 0,0,1,1,NULL
,num_channels
,alpha_channel
,flags
, STBIR_TYPE_UINT8
, STBIR_FILTER_DEFAULT
, STBIR_FILTER_DEFAULT
,
2488 edge_wrap_mode
, edge_wrap_mode
, STBIR_COLORSPACE_SRGB
);
2491 STBIRDEF
int stbir_resize_uint8_generic( const unsigned char *input_pixels
, int input_w
, int input_h
, int input_stride_in_bytes
,
2492 unsigned char *output_pixels
, int output_w
, int output_h
, int output_stride_in_bytes
,
2493 int num_channels
, int alpha_channel
, int flags
,
2494 stbir_edge edge_wrap_mode
, stbir_filter filter
, stbir_colorspace space
,
2495 void *alloc_context
)
2497 return stbir__resize_arbitrary(alloc_context
, input_pixels
, input_w
, input_h
, input_stride_in_bytes
,
2498 output_pixels
, output_w
, output_h
, output_stride_in_bytes
,
2499 0,0,1,1,NULL
,num_channels
,alpha_channel
,flags
, STBIR_TYPE_UINT8
, filter
, filter
,
2500 edge_wrap_mode
, edge_wrap_mode
, space
);
2503 STBIRDEF
int stbir_resize_uint16_generic(const stbir_uint16
*input_pixels
, int input_w
, int input_h
, int input_stride_in_bytes
,
2504 stbir_uint16
*output_pixels
, int output_w
, int output_h
, int output_stride_in_bytes
,
2505 int num_channels
, int alpha_channel
, int flags
,
2506 stbir_edge edge_wrap_mode
, stbir_filter filter
, stbir_colorspace space
,
2507 void *alloc_context
)
2509 return stbir__resize_arbitrary(alloc_context
, input_pixels
, input_w
, input_h
, input_stride_in_bytes
,
2510 output_pixels
, output_w
, output_h
, output_stride_in_bytes
,
2511 0,0,1,1,NULL
,num_channels
,alpha_channel
,flags
, STBIR_TYPE_UINT16
, filter
, filter
,
2512 edge_wrap_mode
, edge_wrap_mode
, space
);
2516 STBIRDEF
int stbir_resize_float_generic( const float *input_pixels
, int input_w
, int input_h
, int input_stride_in_bytes
,
2517 float *output_pixels
, int output_w
, int output_h
, int output_stride_in_bytes
,
2518 int num_channels
, int alpha_channel
, int flags
,
2519 stbir_edge edge_wrap_mode
, stbir_filter filter
, stbir_colorspace space
,
2520 void *alloc_context
)
2522 return stbir__resize_arbitrary(alloc_context
, input_pixels
, input_w
, input_h
, input_stride_in_bytes
,
2523 output_pixels
, output_w
, output_h
, output_stride_in_bytes
,
2524 0,0,1,1,NULL
,num_channels
,alpha_channel
,flags
, STBIR_TYPE_FLOAT
, filter
, filter
,
2525 edge_wrap_mode
, edge_wrap_mode
, space
);
2529 STBIRDEF
int stbir_resize( const void *input_pixels
, int input_w
, int input_h
, int input_stride_in_bytes
,
2530 void *output_pixels
, int output_w
, int output_h
, int output_stride_in_bytes
,
2531 stbir_datatype datatype
,
2532 int num_channels
, int alpha_channel
, int flags
,
2533 stbir_edge edge_mode_horizontal
, stbir_edge edge_mode_vertical
,
2534 stbir_filter filter_horizontal
, stbir_filter filter_vertical
,
2535 stbir_colorspace space
, void *alloc_context
)
2537 return stbir__resize_arbitrary(alloc_context
, input_pixels
, input_w
, input_h
, input_stride_in_bytes
,
2538 output_pixels
, output_w
, output_h
, output_stride_in_bytes
,
2539 0,0,1,1,NULL
,num_channels
,alpha_channel
,flags
, datatype
, filter_horizontal
, filter_vertical
,
2540 edge_mode_horizontal
, edge_mode_vertical
, space
);
2544 STBIRDEF
int stbir_resize_subpixel(const void *input_pixels
, int input_w
, int input_h
, int input_stride_in_bytes
,
2545 void *output_pixels
, int output_w
, int output_h
, int output_stride_in_bytes
,
2546 stbir_datatype datatype
,
2547 int num_channels
, int alpha_channel
, int flags
,
2548 stbir_edge edge_mode_horizontal
, stbir_edge edge_mode_vertical
,
2549 stbir_filter filter_horizontal
, stbir_filter filter_vertical
,
2550 stbir_colorspace space
, void *alloc_context
,
2551 float x_scale
, float y_scale
,
2552 float x_offset
, float y_offset
)
2555 transform
[0] = x_scale
;
2556 transform
[1] = y_scale
;
2557 transform
[2] = x_offset
;
2558 transform
[3] = y_offset
;
2559 return stbir__resize_arbitrary(alloc_context
, input_pixels
, input_w
, input_h
, input_stride_in_bytes
,
2560 output_pixels
, output_w
, output_h
, output_stride_in_bytes
,
2561 0,0,1,1,transform
,num_channels
,alpha_channel
,flags
, datatype
, filter_horizontal
, filter_vertical
,
2562 edge_mode_horizontal
, edge_mode_vertical
, space
);
2565 STBIRDEF
int stbir_resize_region( const void *input_pixels
, int input_w
, int input_h
, int input_stride_in_bytes
,
2566 void *output_pixels
, int output_w
, int output_h
, int output_stride_in_bytes
,
2567 stbir_datatype datatype
,
2568 int num_channels
, int alpha_channel
, int flags
,
2569 stbir_edge edge_mode_horizontal
, stbir_edge edge_mode_vertical
,
2570 stbir_filter filter_horizontal
, stbir_filter filter_vertical
,
2571 stbir_colorspace space
, void *alloc_context
,
2572 float s0
, float t0
, float s1
, float t1
)
2574 return stbir__resize_arbitrary(alloc_context
, input_pixels
, input_w
, input_h
, input_stride_in_bytes
,
2575 output_pixels
, output_w
, output_h
, output_stride_in_bytes
,
2576 s0
,t0
,s1
,t1
,NULL
,num_channels
,alpha_channel
,flags
, datatype
, filter_horizontal
, filter_vertical
,
2577 edge_mode_horizontal
, edge_mode_vertical
, space
);
2580 #endif // STB_IMAGE_RESIZE_IMPLEMENTATION