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