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