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