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