182 #ifndef STBIR_INCLUDE_STB_IMAGE_RESIZE_H
183 #define STBIR_INCLUDE_STB_IMAGE_RESIZE_H
186 typedef unsigned char stbir_uint8;
187 typedef unsigned short stbir_uint16;
188 typedef unsigned int stbir_uint32;
191 typedef uint8_t stbir_uint8;
192 typedef uint16_t stbir_uint16;
193 typedef uint32_t stbir_uint32;
196 #ifdef STB_IMAGE_RESIZE_STATIC
197 #define STBIRDEF static
200 #define STBIRDEF extern "C"
202 #define STBIRDEF extern
225 STBIRDEF
int stbir_resize_uint8(
const unsigned char *input_pixels ,
int input_w ,
int input_h ,
int input_stride_in_bytes,
226 unsigned char *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
229 STBIRDEF
int stbir_resize_float(
const float *input_pixels ,
int input_w ,
int input_h ,
int input_stride_in_bytes,
230 float *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
240 #define STBIR_ALPHA_CHANNEL_NONE -1
245 #define STBIR_FLAG_ALPHA_PREMULTIPLIED (1 << 0)
248 #define STBIR_FLAG_ALPHA_USES_COLORSPACE (1 << 1)
250 STBIRDEF
int stbir_resize_uint8_srgb(
const unsigned char *input_pixels ,
int input_w ,
int input_h ,
int input_stride_in_bytes,
251 unsigned char *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
252 int num_channels,
int alpha_channel,
int flags);
257 STBIR_EDGE_CLAMP = 1,
258 STBIR_EDGE_REFLECT = 2,
264 STBIRDEF
int stbir_resize_uint8_srgb_edgemode(
const unsigned char *input_pixels ,
int input_w ,
int input_h ,
int input_stride_in_bytes,
265 unsigned char *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
266 int num_channels,
int alpha_channel,
int flags,
267 stbir_edge edge_wrap_mode);
286 STBIR_FILTER_DEFAULT = 0,
287 STBIR_FILTER_BOX = 1,
288 STBIR_FILTER_TRIANGLE = 2,
289 STBIR_FILTER_CUBICBSPLINE = 3,
290 STBIR_FILTER_CATMULLROM = 4,
291 STBIR_FILTER_MITCHELL = 5,
296 STBIR_COLORSPACE_LINEAR,
297 STBIR_COLORSPACE_SRGB,
299 STBIR_MAX_COLORSPACES,
304 STBIRDEF
int stbir_resize_uint8_generic(
const unsigned char *input_pixels ,
int input_w ,
int input_h ,
int input_stride_in_bytes,
305 unsigned char *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
306 int num_channels,
int alpha_channel,
int flags,
307 stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
308 void *alloc_context);
310 STBIRDEF
int stbir_resize_uint16_generic(
const stbir_uint16 *input_pixels ,
int input_w ,
int input_h ,
int input_stride_in_bytes,
311 stbir_uint16 *output_pixels ,
int output_w,
int output_h,
int output_stride_in_bytes,
312 int num_channels,
int alpha_channel,
int flags,
313 stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
314 void *alloc_context);
316 STBIRDEF
int stbir_resize_float_generic(
const float *input_pixels ,
int input_w ,
int input_h ,
int input_stride_in_bytes,
317 float *output_pixels ,
int output_w,
int output_h,
int output_stride_in_bytes,
318 int num_channels,
int alpha_channel,
int flags,
319 stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
320 void *alloc_context);
347 STBIRDEF
int stbir_resize(
const void *input_pixels ,
int input_w ,
int input_h ,
int input_stride_in_bytes,
348 void *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
349 stbir_datatype datatype,
350 int num_channels,
int alpha_channel,
int flags,
351 stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
352 stbir_filter filter_horizontal, stbir_filter filter_vertical,
353 stbir_colorspace space,
void *alloc_context);
355 STBIRDEF
int stbir_resize_subpixel(
const void *input_pixels ,
int input_w ,
int input_h ,
int input_stride_in_bytes,
356 void *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
357 stbir_datatype datatype,
358 int num_channels,
int alpha_channel,
int flags,
359 stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
360 stbir_filter filter_horizontal, stbir_filter filter_vertical,
361 stbir_colorspace space,
void *alloc_context,
362 float x_scale,
float y_scale,
363 float x_offset,
float y_offset);
365 STBIRDEF
int stbir_resize_region(
const void *input_pixels ,
int input_w ,
int input_h ,
int input_stride_in_bytes,
366 void *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
367 stbir_datatype datatype,
368 int num_channels,
int alpha_channel,
int flags,
369 stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
370 stbir_filter filter_horizontal, stbir_filter filter_vertical,
371 stbir_colorspace space,
void *alloc_context,
372 float s0,
float t0,
float s1,
float t1);
378 #endif // STBIR_INCLUDE_STB_IMAGE_RESIZE_H
384 #ifdef STB_IMAGE_RESIZE_IMPLEMENTATION
388 #define STBIR_ASSERT(x) assert(x)
399 #define STBIR_MALLOC(size,c) ((void)(c), malloc(size))
400 #define STBIR_FREE(ptr,c) ((void)(c), free(ptr))
405 #define stbir__inline inline
407 #define stbir__inline
410 #define stbir__inline __forceinline
415 typedef unsigned char stbir__validate_uint32[
sizeof(stbir_uint32) == 4 ? 1 : -1];
418 #define STBIR__NOTUSED(v) (void)(v)
420 #define STBIR__NOTUSED(v) (void)sizeof(v)
423 #define STBIR__ARRAY_SIZE(a) (sizeof((a))/sizeof((a)[0]))
425 #ifndef STBIR_DEFAULT_FILTER_UPSAMPLE
426 #define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM
429 #ifndef STBIR_DEFAULT_FILTER_DOWNSAMPLE
430 #define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL
433 #ifndef STBIR_PROGRESS_REPORT
434 #define STBIR_PROGRESS_REPORT(float_0_to_1)
437 #ifndef STBIR_MAX_CHANNELS
438 #define STBIR_MAX_CHANNELS 64
441 #if STBIR_MAX_CHANNELS > 65536
442 #error "Too many channels; STBIR_MAX_CHANNELS must be no more than 65536."
451 #ifndef STBIR_ALPHA_EPSILON
452 #define STBIR_ALPHA_EPSILON ((float)1 / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20))
458 #define STBIR__UNUSED_PARAM(v) (void)(v)
460 #define STBIR__UNUSED_PARAM(v) (void)sizeof(v)
464 static unsigned char stbir__type_size[] = {
472 typedef float (stbir__kernel_fn)(
float x,
float scale);
473 typedef float (stbir__support_fn)(
float scale);
477 stbir__kernel_fn* kernel;
478 stbir__support_fn* support;
479 } stbir__filter_info;
487 } stbir__contributors;
491 const void* input_data;
494 int input_stride_bytes;
499 int output_stride_bytes;
501 float s0, t0, s1, t1;
503 float horizontal_shift;
504 float vertical_shift;
505 float horizontal_scale;
506 float vertical_scale;
512 stbir_filter horizontal_filter;
513 stbir_filter vertical_filter;
514 stbir_edge edge_horizontal;
515 stbir_edge edge_vertical;
516 stbir_colorspace colorspace;
518 stbir__contributors* horizontal_contributors;
519 float* horizontal_coefficients;
521 stbir__contributors* vertical_contributors;
522 float* vertical_coefficients;
524 int decode_buffer_pixels;
525 float* decode_buffer;
527 float* horizontal_buffer;
530 int horizontal_coefficient_width;
531 int vertical_coefficient_width;
532 int horizontal_filter_pixel_width;
533 int vertical_filter_pixel_width;
534 int horizontal_filter_pixel_margin;
535 int vertical_filter_pixel_margin;
536 int horizontal_num_contributors;
537 int vertical_num_contributors;
539 int ring_buffer_length_bytes;
540 int ring_buffer_num_entries;
541 int ring_buffer_first_scanline;
542 int ring_buffer_last_scanline;
543 int ring_buffer_begin_index;
546 float* encode_buffer;
548 int horizontal_contributors_size;
549 int horizontal_coefficients_size;
550 int vertical_contributors_size;
551 int vertical_coefficients_size;
552 int decode_buffer_size;
553 int horizontal_buffer_size;
554 int ring_buffer_size;
555 int encode_buffer_size;
559 static const float stbir__max_uint8_as_float = 255.0f;
560 static const float stbir__max_uint16_as_float = 65535.0f;
561 static const double stbir__max_uint32_as_float = 4294967295.0;
564 static stbir__inline
int stbir__min(
int a,
int b)
566 return a < b ? a : b;
569 static stbir__inline
float stbir__saturate(
float x)
580 #ifdef STBIR_SATURATE_INT
581 static stbir__inline stbir_uint8 stbir__saturate8(
int x)
583 if ((
unsigned int) x <= 255)
592 static stbir__inline stbir_uint16 stbir__saturate16(
int x)
594 if ((
unsigned int) x <= 65535)
604 static float stbir__srgb_uchar_to_linear_float[256] = {
605 0.000000f, 0.000304f, 0.000607f, 0.000911f, 0.001214f, 0.001518f, 0.001821f, 0.002125f, 0.002428f, 0.002732f, 0.003035f,
606 0.003347f, 0.003677f, 0.004025f, 0.004391f, 0.004777f, 0.005182f, 0.005605f, 0.006049f, 0.006512f, 0.006995f, 0.007499f,
607 0.008023f, 0.008568f, 0.009134f, 0.009721f, 0.010330f, 0.010960f, 0.011612f, 0.012286f, 0.012983f, 0.013702f, 0.014444f,
608 0.015209f, 0.015996f, 0.016807f, 0.017642f, 0.018500f, 0.019382f, 0.020289f, 0.021219f, 0.022174f, 0.023153f, 0.024158f,
609 0.025187f, 0.026241f, 0.027321f, 0.028426f, 0.029557f, 0.030713f, 0.031896f, 0.033105f, 0.034340f, 0.035601f, 0.036889f,
610 0.038204f, 0.039546f, 0.040915f, 0.042311f, 0.043735f, 0.045186f, 0.046665f, 0.048172f, 0.049707f, 0.051269f, 0.052861f,
611 0.054480f, 0.056128f, 0.057805f, 0.059511f, 0.061246f, 0.063010f, 0.064803f, 0.066626f, 0.068478f, 0.070360f, 0.072272f,
612 0.074214f, 0.076185f, 0.078187f, 0.080220f, 0.082283f, 0.084376f, 0.086500f, 0.088656f, 0.090842f, 0.093059f, 0.095307f,
613 0.097587f, 0.099899f, 0.102242f, 0.104616f, 0.107023f, 0.109462f, 0.111932f, 0.114435f, 0.116971f, 0.119538f, 0.122139f,
614 0.124772f, 0.127438f, 0.130136f, 0.132868f, 0.135633f, 0.138432f, 0.141263f, 0.144128f, 0.147027f, 0.149960f, 0.152926f,
615 0.155926f, 0.158961f, 0.162029f, 0.165132f, 0.168269f, 0.171441f, 0.174647f, 0.177888f, 0.181164f, 0.184475f, 0.187821f,
616 0.191202f, 0.194618f, 0.198069f, 0.201556f, 0.205079f, 0.208637f, 0.212231f, 0.215861f, 0.219526f, 0.223228f, 0.226966f,
617 0.230740f, 0.234551f, 0.238398f, 0.242281f, 0.246201f, 0.250158f, 0.254152f, 0.258183f, 0.262251f, 0.266356f, 0.270498f,
618 0.274677f, 0.278894f, 0.283149f, 0.287441f, 0.291771f, 0.296138f, 0.300544f, 0.304987f, 0.309469f, 0.313989f, 0.318547f,
619 0.323143f, 0.327778f, 0.332452f, 0.337164f, 0.341914f, 0.346704f, 0.351533f, 0.356400f, 0.361307f, 0.366253f, 0.371238f,
620 0.376262f, 0.381326f, 0.386430f, 0.391573f, 0.396755f, 0.401978f, 0.407240f, 0.412543f, 0.417885f, 0.423268f, 0.428691f,
621 0.434154f, 0.439657f, 0.445201f, 0.450786f, 0.456411f, 0.462077f, 0.467784f, 0.473532f, 0.479320f, 0.485150f, 0.491021f,
622 0.496933f, 0.502887f, 0.508881f, 0.514918f, 0.520996f, 0.527115f, 0.533276f, 0.539480f, 0.545725f, 0.552011f, 0.558340f,
623 0.564712f, 0.571125f, 0.577581f, 0.584078f, 0.590619f, 0.597202f, 0.603827f, 0.610496f, 0.617207f, 0.623960f, 0.630757f,
624 0.637597f, 0.644480f, 0.651406f, 0.658375f, 0.665387f, 0.672443f, 0.679543f, 0.686685f, 0.693872f, 0.701102f, 0.708376f,
625 0.715694f, 0.723055f, 0.730461f, 0.737911f, 0.745404f, 0.752942f, 0.760525f, 0.768151f, 0.775822f, 0.783538f, 0.791298f,
626 0.799103f, 0.806952f, 0.814847f, 0.822786f, 0.830770f, 0.838799f, 0.846873f, 0.854993f, 0.863157f, 0.871367f, 0.879622f,
627 0.887923f, 0.896269f, 0.904661f, 0.913099f, 0.921582f, 0.930111f, 0.938686f, 0.947307f, 0.955974f, 0.964686f, 0.973445f,
628 0.982251f, 0.991102f, 1.0f
631 static float stbir__srgb_to_linear(
float f)
636 return (
float)pow((f + 0.055f) / 1.055f, 2.4f);
639 static float stbir__linear_to_srgb(
float f)
644 return 1.055f * (float)pow(f, 1 / 2.4f) - 0.055f;
647 #ifndef STBIR_NON_IEEE_FLOAT
656 static const stbir_uint32 fp32_to_srgb8_tab4[104] = {
657 0x0073000d, 0x007a000d, 0x0080000d, 0x0087000d, 0x008d000d, 0x0094000d, 0x009a000d, 0x00a1000d,
658 0x00a7001a, 0x00b4001a, 0x00c1001a, 0x00ce001a, 0x00da001a, 0x00e7001a, 0x00f4001a, 0x0101001a,
659 0x010e0033, 0x01280033, 0x01410033, 0x015b0033, 0x01750033, 0x018f0033, 0x01a80033, 0x01c20033,
660 0x01dc0067, 0x020f0067, 0x02430067, 0x02760067, 0x02aa0067, 0x02dd0067, 0x03110067, 0x03440067,
661 0x037800ce, 0x03df00ce, 0x044600ce, 0x04ad00ce, 0x051400ce, 0x057b00c5, 0x05dd00bc, 0x063b00b5,
662 0x06970158, 0x07420142, 0x07e30130, 0x087b0120, 0x090b0112, 0x09940106, 0x0a1700fc, 0x0a9500f2,
663 0x0b0f01cb, 0x0bf401ae, 0x0ccb0195, 0x0d950180, 0x0e56016e, 0x0f0d015e, 0x0fbc0150, 0x10630143,
664 0x11070264, 0x1238023e, 0x1357021d, 0x14660201, 0x156601e9, 0x165a01d3, 0x174401c0, 0x182401af,
665 0x18fe0331, 0x1a9602fe, 0x1c1502d2, 0x1d7e02ad, 0x1ed4028d, 0x201a0270, 0x21520256, 0x227d0240,
666 0x239f0443, 0x25c003fe, 0x27bf03c4, 0x29a10392, 0x2b6a0367, 0x2d1d0341, 0x2ebe031f, 0x304d0300,
667 0x31d105b0, 0x34a80555, 0x37520507, 0x39d504c5, 0x3c37048b, 0x3e7c0458, 0x40a8042a, 0x42bd0401,
668 0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559,
669 0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723,
672 static stbir_uint8 stbir__linear_to_srgb_uchar(
float in)
674 static const stbir__FP32 almostone = { 0x3f7fffff };
675 static const stbir__FP32 minval = { (127-13) << 23 };
676 stbir_uint32 tab,bias,scale,t;
682 if (!(in > minval.f))
684 if (in > almostone.f)
689 tab = fp32_to_srgb8_tab4[(f.u - minval.u) >> 20];
690 bias = (tab >> 16) << 9;
691 scale = tab & 0xffff;
694 t = (f.u >> 12) & 0xff;
695 return (
unsigned char) ((bias + scale*t) >> 16);
700 static int stbir__srgb_offset_to_linear_scaled[256] =
702 0, 40738, 122216, 203693, 285170, 366648, 448125, 529603,
703 611080, 692557, 774035, 855852, 942009, 1033024, 1128971, 1229926,
704 1335959, 1447142, 1563542, 1685229, 1812268, 1944725, 2082664, 2226148,
705 2375238, 2529996, 2690481, 2856753, 3028870, 3206888, 3390865, 3580856,
706 3776916, 3979100, 4187460, 4402049, 4622919, 4850123, 5083710, 5323731,
707 5570236, 5823273, 6082892, 6349140, 6622065, 6901714, 7188133, 7481369,
708 7781466, 8088471, 8402427, 8723380, 9051372, 9386448, 9728650, 10078021,
709 10434603, 10798439, 11169569, 11548036, 11933879, 12327139, 12727857, 13136073,
710 13551826, 13975156, 14406100, 14844697, 15290987, 15745007, 16206795, 16676389,
711 17153826, 17639142, 18132374, 18633560, 19142734, 19659934, 20185196, 20718552,
712 21260042, 21809696, 22367554, 22933648, 23508010, 24090680, 24681686, 25281066,
713 25888850, 26505076, 27129772, 27762974, 28404716, 29055026, 29713942, 30381490,
714 31057708, 31742624, 32436272, 33138682, 33849884, 34569912, 35298800, 36036568,
715 36783260, 37538896, 38303512, 39077136, 39859796, 40651528, 41452360, 42262316,
716 43081432, 43909732, 44747252, 45594016, 46450052, 47315392, 48190064, 49074096,
717 49967516, 50870356, 51782636, 52704392, 53635648, 54576432, 55526772, 56486700,
718 57456236, 58435408, 59424248, 60422780, 61431036, 62449032, 63476804, 64514376,
719 65561776, 66619028, 67686160, 68763192, 69850160, 70947088, 72053992, 73170912,
720 74297864, 75434880, 76581976, 77739184, 78906536, 80084040, 81271736, 82469648,
721 83677792, 84896192, 86124888, 87363888, 88613232, 89872928, 91143016, 92423512,
722 93714432, 95015816, 96327688, 97650056, 98982952, 100326408, 101680440, 103045072,
723 104420320, 105806224, 107202800, 108610064, 110028048, 111456776, 112896264, 114346544,
724 115807632, 117279552, 118762328, 120255976, 121760536, 123276016, 124802440, 126339832,
725 127888216, 129447616, 131018048, 132599544, 134192112, 135795792, 137410592, 139036528,
726 140673648, 142321952, 143981456, 145652208, 147334208, 149027488, 150732064, 152447968,
727 154175200, 155913792, 157663776, 159425168, 161197984, 162982240, 164777968, 166585184,
728 168403904, 170234160, 172075968, 173929344, 175794320, 177670896, 179559120, 181458992,
729 183370528, 185293776, 187228736, 189175424, 191133888, 193104112, 195086128, 197079968,
730 199085648, 201103184, 203132592, 205173888, 207227120, 209292272, 211369392, 213458480,
731 215559568, 217672656, 219797792, 221934976, 224084240, 226245600, 228419056, 230604656,
732 232802400, 235012320, 237234432, 239468736, 241715280, 243974080, 246245120, 248528464,
733 250824112, 253132064, 255452368, 257785040, 260130080, 262487520, 264857376, 267239664,
736 static stbir_uint8 stbir__linear_to_srgb_uchar(
float f)
738 int x = (int) (f * (1 << 28));
743 i = v + 128;
if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
744 i = v + 64;
if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
745 i = v + 32;
if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
746 i = v + 16;
if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
747 i = v + 8;
if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
748 i = v + 4;
if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
749 i = v + 2;
if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
750 i = v + 1;
if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
752 return (stbir_uint8) v;
756 static float stbir__filter_trapezoid(
float x,
float scale)
758 float halfscale = scale / 2;
759 float t = 0.5f + halfscale;
760 STBIR_ASSERT(scale <= 1);
768 float r = 0.5f - halfscale;
772 return (t - x) / scale;
776 static float stbir__support_trapezoid(
float scale)
778 STBIR_ASSERT(scale <= 1);
779 return 0.5f + scale / 2;
782 static float stbir__filter_triangle(
float x,
float s)
784 STBIR__UNUSED_PARAM(s);
794 static float stbir__filter_cubic(
float x,
float s)
796 STBIR__UNUSED_PARAM(s);
801 return (4 + x*x*(3*x - 6))/6;
803 return (8 + x*(-12 + x*(6 - x)))/6;
808 static float stbir__filter_catmullrom(
float x,
float s)
810 STBIR__UNUSED_PARAM(s);
815 return 1 - x*x*(2.5f - 1.5f*x);
817 return 2 - x*(4 + x*(0.5f*x - 2.5f));
822 static float stbir__filter_mitchell(
float x,
float s)
824 STBIR__UNUSED_PARAM(s);
829 return (16 + x*x*(21 * x - 36))/18;
831 return (32 + x*(-60 + x*(36 - 7*x)))/18;
836 static float stbir__support_zero(
float s)
838 STBIR__UNUSED_PARAM(s);
842 static float stbir__support_one(
float s)
844 STBIR__UNUSED_PARAM(s);
848 static float stbir__support_two(
float s)
850 STBIR__UNUSED_PARAM(s);
854 static stbir__filter_info stbir__filter_info_table[] = {
855 { NULL, stbir__support_zero },
856 { stbir__filter_trapezoid, stbir__support_trapezoid },
857 { stbir__filter_triangle, stbir__support_one },
858 { stbir__filter_cubic, stbir__support_two },
859 { stbir__filter_catmullrom, stbir__support_two },
860 { stbir__filter_mitchell, stbir__support_two },
863 stbir__inline
static int stbir__use_upsampling(
float ratio)
868 stbir__inline
static int stbir__use_width_upsampling(stbir__info* stbir_info)
870 return stbir__use_upsampling(stbir_info->horizontal_scale);
873 stbir__inline
static int stbir__use_height_upsampling(stbir__info* stbir_info)
875 return stbir__use_upsampling(stbir_info->vertical_scale);
880 static int stbir__get_filter_pixel_width(stbir_filter filter,
float scale)
882 STBIR_ASSERT(filter != 0);
883 STBIR_ASSERT(filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
885 if (stbir__use_upsampling(scale))
886 return (
int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2);
888 return (
int)ceil(stbir__filter_info_table[filter].support(scale) * 2 / scale);
893 static int stbir__get_filter_pixel_margin(stbir_filter filter,
float scale)
895 return stbir__get_filter_pixel_width(filter, scale) / 2;
898 static int stbir__get_coefficient_width(stbir_filter filter,
float scale)
900 if (stbir__use_upsampling(scale))
901 return (
int)ceil(stbir__filter_info_table[filter].support(1 / scale) * 2);
903 return (
int)ceil(stbir__filter_info_table[filter].support(scale) * 2);
906 static int stbir__get_contributors(
float scale, stbir_filter filter,
int input_size,
int output_size)
908 if (stbir__use_upsampling(scale))
911 return (input_size + stbir__get_filter_pixel_margin(filter, scale) * 2);
914 static int stbir__get_total_horizontal_coefficients(stbir__info* info)
916 return info->horizontal_num_contributors
917 * stbir__get_coefficient_width (info->horizontal_filter, info->horizontal_scale);
920 static int stbir__get_total_vertical_coefficients(stbir__info* info)
922 return info->vertical_num_contributors
923 * stbir__get_coefficient_width (info->vertical_filter, info->vertical_scale);
926 static stbir__contributors* stbir__get_contributor(stbir__contributors* contributors,
int n)
928 return &contributors[n];
933 static float* stbir__get_coefficient(
float* coefficients, stbir_filter filter,
float scale,
int n,
int c)
935 int width = stbir__get_coefficient_width(filter, scale);
936 return &coefficients[width*n + c];
939 static int stbir__edge_wrap_slow(stbir_edge edge,
int n,
int max)
943 case STBIR_EDGE_ZERO:
946 case STBIR_EDGE_CLAMP:
955 case STBIR_EDGE_REFLECT:
977 case STBIR_EDGE_WRAP:
992 STBIR_ASSERT(!
"Unimplemented edge type");
997 stbir__inline
static int stbir__edge_wrap(stbir_edge edge,
int n,
int max)
1000 if (n >= 0 && n < max)
1002 return stbir__edge_wrap_slow(edge, n, max);
1006 static void stbir__calculate_sample_range_upsample(
int n,
float out_filter_radius,
float scale_ratio,
float out_shift,
int* in_first_pixel,
int* in_last_pixel,
float* in_center_of_out)
1008 float out_pixel_center = (float)n + 0.5f;
1009 float out_pixel_influence_lowerbound = out_pixel_center - out_filter_radius;
1010 float out_pixel_influence_upperbound = out_pixel_center + out_filter_radius;
1012 float in_pixel_influence_lowerbound = (out_pixel_influence_lowerbound + out_shift) / scale_ratio;
1013 float in_pixel_influence_upperbound = (out_pixel_influence_upperbound + out_shift) / scale_ratio;
1015 *in_center_of_out = (out_pixel_center + out_shift) / scale_ratio;
1016 *in_first_pixel = (int)(floor(in_pixel_influence_lowerbound + 0.5));
1017 *in_last_pixel = (int)(floor(in_pixel_influence_upperbound - 0.5));
1021 static void stbir__calculate_sample_range_downsample(
int n,
float in_pixels_radius,
float scale_ratio,
float out_shift,
int* out_first_pixel,
int* out_last_pixel,
float* out_center_of_in)
1023 float in_pixel_center = (float)n + 0.5f;
1024 float in_pixel_influence_lowerbound = in_pixel_center - in_pixels_radius;
1025 float in_pixel_influence_upperbound = in_pixel_center + in_pixels_radius;
1027 float out_pixel_influence_lowerbound = in_pixel_influence_lowerbound * scale_ratio - out_shift;
1028 float out_pixel_influence_upperbound = in_pixel_influence_upperbound * scale_ratio - out_shift;
1030 *out_center_of_in = in_pixel_center * scale_ratio - out_shift;
1031 *out_first_pixel = (int)(floor(out_pixel_influence_lowerbound + 0.5));
1032 *out_last_pixel = (int)(floor(out_pixel_influence_upperbound - 0.5));
1035 static void stbir__calculate_coefficients_upsample(stbir_filter filter,
float scale,
int in_first_pixel,
int in_last_pixel,
float in_center_of_out, stbir__contributors* contributor,
float* coefficient_group)
1038 float total_filter = 0;
1041 STBIR_ASSERT(in_last_pixel - in_first_pixel <= (
int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2));
1043 contributor->n0 = in_first_pixel;
1044 contributor->n1 = in_last_pixel;
1046 STBIR_ASSERT(contributor->n1 >= contributor->n0);
1048 for (i = 0; i <= in_last_pixel - in_first_pixel; i++)
1050 float in_pixel_center = (float)(i + in_first_pixel) + 0.5f;
1051 coefficient_group[i] = stbir__filter_info_table[filter].kernel(in_center_of_out - in_pixel_center, 1 / scale);
1054 if (i == 0 && !coefficient_group[i])
1056 contributor->n0 = ++in_first_pixel;
1061 total_filter += coefficient_group[i];
1064 STBIR_ASSERT(stbir__filter_info_table[filter].kernel((
float)(in_last_pixel + 1) + 0.5f - in_center_of_out, 1/scale) == 0);
1066 STBIR_ASSERT(total_filter > 0.9);
1067 STBIR_ASSERT(total_filter < 1.1f);
1070 filter_scale = 1 / total_filter;
1072 for (i = 0; i <= in_last_pixel - in_first_pixel; i++)
1073 coefficient_group[i] *= filter_scale;
1075 for (i = in_last_pixel - in_first_pixel; i >= 0; i--)
1077 if (coefficient_group[i])
1081 contributor->n1 = contributor->n0 + i - 1;
1085 static void stbir__calculate_coefficients_downsample(stbir_filter filter,
float scale_ratio,
int out_first_pixel,
int out_last_pixel,
float out_center_of_in, stbir__contributors* contributor,
float* coefficient_group)
1089 STBIR_ASSERT(out_last_pixel - out_first_pixel <= (
int)ceil(stbir__filter_info_table[filter].support(scale_ratio) * 2));
1091 contributor->n0 = out_first_pixel;
1092 contributor->n1 = out_last_pixel;
1094 STBIR_ASSERT(contributor->n1 >= contributor->n0);
1096 for (i = 0; i <= out_last_pixel - out_first_pixel; i++)
1098 float out_pixel_center = (float)(i + out_first_pixel) + 0.5f;
1099 float x = out_pixel_center - out_center_of_in;
1100 coefficient_group[i] = stbir__filter_info_table[filter].kernel(x, scale_ratio) * scale_ratio;
1103 STBIR_ASSERT(stbir__filter_info_table[filter].kernel((
float)(out_last_pixel + 1) + 0.5f - out_center_of_in, scale_ratio) == 0);
1105 for (i = out_last_pixel - out_first_pixel; i >= 0; i--)
1107 if (coefficient_group[i])
1111 contributor->n1 = contributor->n0 + i - 1;
1115 static void stbir__normalize_downsample_coefficients(stbir__contributors* contributors,
float* coefficients, stbir_filter filter,
float scale_ratio,
int input_size,
int output_size)
1117 int num_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size);
1118 int num_coefficients = stbir__get_coefficient_width(filter, scale_ratio);
1122 for (i = 0; i < output_size; i++)
1127 for (j = 0; j < num_contributors; j++)
1129 if (i >= contributors[j].n0 && i <= contributors[j].n1)
1131 float coefficient = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0);
1132 total += coefficient;
1134 else if (i < contributors[j].n0)
1138 STBIR_ASSERT(total > 0.9f);
1139 STBIR_ASSERT(total < 1.1f);
1143 for (j = 0; j < num_contributors; j++)
1145 if (i >= contributors[j].n0 && i <= contributors[j].n1)
1146 *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0) *= scale;
1147 else if (i < contributors[j].n0)
1154 for (j = 0; j < num_contributors; j++)
1156 int range, max, width;
1159 while (*stbir__get_coefficient(coefficients, filter, scale_ratio, j, skip) == 0)
1162 contributors[j].n0 += skip;
1164 while (contributors[j].n0 < 0)
1166 contributors[j].n0++;
1170 range = contributors[j].n1 - contributors[j].n0 + 1;
1171 max = stbir__min(num_coefficients, range);
1173 width = stbir__get_coefficient_width(filter, scale_ratio);
1174 for (i = 0; i < max; i++)
1176 if (i + skip >= width)
1179 *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i) = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i + skip);
1186 for (i = 0; i < num_contributors; i++)
1187 contributors[i].n1 = stbir__min(contributors[i].n1, output_size - 1);
1192 static void stbir__calculate_filters(stbir__contributors* contributors,
float* coefficients, stbir_filter filter,
float scale_ratio,
float shift,
int input_size,
int output_size)
1195 int total_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size);
1197 if (stbir__use_upsampling(scale_ratio))
1199 float out_pixels_radius = stbir__filter_info_table[filter].support(1 / scale_ratio) * scale_ratio;
1202 for (n = 0; n < total_contributors; n++)
1204 float in_center_of_out;
1205 int in_first_pixel, in_last_pixel;
1207 stbir__calculate_sample_range_upsample(n, out_pixels_radius, scale_ratio, shift, &in_first_pixel, &in_last_pixel, &in_center_of_out);
1209 stbir__calculate_coefficients_upsample(filter, scale_ratio, in_first_pixel, in_last_pixel, in_center_of_out, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0));
1214 float in_pixels_radius = stbir__filter_info_table[filter].support(scale_ratio) / scale_ratio;
1217 for (n = 0; n < total_contributors; n++)
1219 float out_center_of_in;
1220 int out_first_pixel, out_last_pixel;
1221 int n_adjusted = n - stbir__get_filter_pixel_margin(filter, scale_ratio);
1223 stbir__calculate_sample_range_downsample(n_adjusted, in_pixels_radius, scale_ratio, shift, &out_first_pixel, &out_last_pixel, &out_center_of_in);
1225 stbir__calculate_coefficients_downsample(filter, scale_ratio, out_first_pixel, out_last_pixel, out_center_of_in, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0));
1228 stbir__normalize_downsample_coefficients(contributors, coefficients, filter, scale_ratio, input_size, output_size);
1232 static float* stbir__get_decode_buffer(stbir__info* stbir_info)
1236 return &stbir_info->decode_buffer[stbir_info->horizontal_filter_pixel_margin * stbir_info->channels];
1239 #define STBIR__DECODE(type, colorspace) ((type) * (STBIR_MAX_COLORSPACES) + (colorspace))
1241 static void stbir__decode_scanline(stbir__info* stbir_info,
int n)
1244 int channels = stbir_info->channels;
1245 int alpha_channel = stbir_info->alpha_channel;
1246 int type = stbir_info->type;
1247 int colorspace = stbir_info->colorspace;
1248 int input_w = stbir_info->input_w;
1249 size_t input_stride_bytes = stbir_info->input_stride_bytes;
1250 float* decode_buffer = stbir__get_decode_buffer(stbir_info);
1251 stbir_edge edge_horizontal = stbir_info->edge_horizontal;
1252 stbir_edge edge_vertical = stbir_info->edge_vertical;
1253 size_t in_buffer_row_offset = stbir__edge_wrap(edge_vertical, n, stbir_info->input_h) * input_stride_bytes;
1254 const void* input_data = (
char *) stbir_info->input_data + in_buffer_row_offset;
1255 int max_x = input_w + stbir_info->horizontal_filter_pixel_margin;
1256 int decode = STBIR__DECODE(type, colorspace);
1258 int x = -stbir_info->horizontal_filter_pixel_margin;
1262 if (edge_vertical == STBIR_EDGE_ZERO && (n < 0 || n >= stbir_info->input_h))
1264 for (; x < max_x; x++)
1265 for (c = 0; c < channels; c++)
1266 decode_buffer[x*channels + c] = 0;
1272 case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR):
1273 for (; x < max_x; x++)
1275 int decode_pixel_index = x * channels;
1276 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1277 for (c = 0; c < channels; c++)
1278 decode_buffer[decode_pixel_index + c] = ((
float)((
const unsigned char*)input_data)[input_pixel_index + c]) / stbir__max_uint8_as_float;
1282 case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB):
1283 for (; x < max_x; x++)
1285 int decode_pixel_index = x * channels;
1286 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1287 for (c = 0; c < channels; c++)
1288 decode_buffer[decode_pixel_index + c] = stbir__srgb_uchar_to_linear_float[((
const unsigned char*)input_data)[input_pixel_index + c]];
1290 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1291 decode_buffer[decode_pixel_index + alpha_channel] = ((float)((
const unsigned char*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint8_as_float;
1295 case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR):
1296 for (; x < max_x; x++)
1298 int decode_pixel_index = x * channels;
1299 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1300 for (c = 0; c < channels; c++)
1301 decode_buffer[decode_pixel_index + c] = ((
float)((
const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float;
1305 case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB):
1306 for (; x < max_x; x++)
1308 int decode_pixel_index = x * channels;
1309 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1310 for (c = 0; c < channels; c++)
1311 decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((
float)((
const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float);
1313 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1314 decode_buffer[decode_pixel_index + alpha_channel] = ((float)((
const unsigned short*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint16_as_float;
1318 case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR):
1319 for (; x < max_x; x++)
1321 int decode_pixel_index = x * channels;
1322 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1323 for (c = 0; c < channels; c++)
1324 decode_buffer[decode_pixel_index + c] = (
float)(((double)((
const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float);
1328 case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB):
1329 for (; x < max_x; x++)
1331 int decode_pixel_index = x * channels;
1332 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1333 for (c = 0; c < channels; c++)
1334 decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear((
float)(((
double)((
const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float));
1336 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1337 decode_buffer[decode_pixel_index + alpha_channel] = (float)(((
double)((
const unsigned int*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint32_as_float);
1341 case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR):
1342 for (; x < max_x; x++)
1344 int decode_pixel_index = x * channels;
1345 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1346 for (c = 0; c < channels; c++)
1347 decode_buffer[decode_pixel_index + c] = ((
const float*)input_data)[input_pixel_index + c];
1351 case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB):
1352 for (; x < max_x; x++)
1354 int decode_pixel_index = x * channels;
1355 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1356 for (c = 0; c < channels; c++)
1357 decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((
const float*)input_data)[input_pixel_index + c]);
1359 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1360 decode_buffer[decode_pixel_index + alpha_channel] = ((
const float*)input_data)[input_pixel_index + alpha_channel];
1366 STBIR_ASSERT(!
"Unknown type/colorspace/channels combination.");
1370 if (!(stbir_info->flags & STBIR_FLAG_ALPHA_PREMULTIPLIED))
1372 for (x = -stbir_info->horizontal_filter_pixel_margin; x < max_x; x++)
1374 int decode_pixel_index = x * channels;
1377 float alpha = decode_buffer[decode_pixel_index + alpha_channel];
1378 #ifndef STBIR_NO_ALPHA_EPSILON
1379 if (stbir_info->type != STBIR_TYPE_FLOAT) {
1380 alpha += STBIR_ALPHA_EPSILON;
1381 decode_buffer[decode_pixel_index + alpha_channel] = alpha;
1384 for (c = 0; c < channels; c++)
1386 if (c == alpha_channel)
1389 decode_buffer[decode_pixel_index + c] *= alpha;
1394 if (edge_horizontal == STBIR_EDGE_ZERO)
1396 for (x = -stbir_info->horizontal_filter_pixel_margin; x < 0; x++)
1398 for (c = 0; c < channels; c++)
1399 decode_buffer[x*channels + c] = 0;
1401 for (x = input_w; x < max_x; x++)
1403 for (c = 0; c < channels; c++)
1404 decode_buffer[x*channels + c] = 0;
1409 static float* stbir__get_ring_buffer_entry(
float* ring_buffer,
int index,
int ring_buffer_length)
1411 return &ring_buffer[index * ring_buffer_length];
1414 static float* stbir__add_empty_ring_buffer_entry(stbir__info* stbir_info,
int n)
1416 int ring_buffer_index;
1419 stbir_info->ring_buffer_last_scanline = n;
1421 if (stbir_info->ring_buffer_begin_index < 0)
1423 ring_buffer_index = stbir_info->ring_buffer_begin_index = 0;
1424 stbir_info->ring_buffer_first_scanline = n;
1428 ring_buffer_index = (stbir_info->ring_buffer_begin_index + (stbir_info->ring_buffer_last_scanline - stbir_info->ring_buffer_first_scanline)) % stbir_info->ring_buffer_num_entries;
1429 STBIR_ASSERT(ring_buffer_index != stbir_info->ring_buffer_begin_index);
1432 ring_buffer = stbir__get_ring_buffer_entry(stbir_info->ring_buffer, ring_buffer_index, stbir_info->ring_buffer_length_bytes /
sizeof(
float));
1433 memset(ring_buffer, 0, stbir_info->ring_buffer_length_bytes);
1439 static void stbir__resample_horizontal_upsample(stbir__info* stbir_info,
float* output_buffer)
1442 int output_w = stbir_info->output_w;
1443 int channels = stbir_info->channels;
1444 float* decode_buffer = stbir__get_decode_buffer(stbir_info);
1445 stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors;
1446 float* horizontal_coefficients = stbir_info->horizontal_coefficients;
1447 int coefficient_width = stbir_info->horizontal_coefficient_width;
1449 for (x = 0; x < output_w; x++)
1451 int n0 = horizontal_contributors[x].n0;
1452 int n1 = horizontal_contributors[x].n1;
1454 int out_pixel_index = x * channels;
1455 int coefficient_group = coefficient_width * x;
1456 int coefficient_counter = 0;
1458 STBIR_ASSERT(n1 >= n0);
1459 STBIR_ASSERT(n0 >= -stbir_info->horizontal_filter_pixel_margin);
1460 STBIR_ASSERT(n1 >= -stbir_info->horizontal_filter_pixel_margin);
1461 STBIR_ASSERT(n0 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin);
1462 STBIR_ASSERT(n1 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin);
1466 for (k = n0; k <= n1; k++)
1468 int in_pixel_index = k * 1;
1469 float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
1470 STBIR_ASSERT(coefficient != 0);
1471 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1475 for (k = n0; k <= n1; k++)
1477 int in_pixel_index = k * 2;
1478 float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
1479 STBIR_ASSERT(coefficient != 0);
1480 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1481 output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1485 for (k = n0; k <= n1; k++)
1487 int in_pixel_index = k * 3;
1488 float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
1489 STBIR_ASSERT(coefficient != 0);
1490 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1491 output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1492 output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
1496 for (k = n0; k <= n1; k++)
1498 int in_pixel_index = k * 4;
1499 float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
1500 STBIR_ASSERT(coefficient != 0);
1501 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1502 output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1503 output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
1504 output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient;
1508 for (k = n0; k <= n1; k++)
1510 int in_pixel_index = k * channels;
1511 float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
1513 STBIR_ASSERT(coefficient != 0);
1514 for (c = 0; c < channels; c++)
1515 output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient;
1522 static void stbir__resample_horizontal_downsample(stbir__info* stbir_info,
float* output_buffer)
1525 int input_w = stbir_info->input_w;
1526 int channels = stbir_info->channels;
1527 float* decode_buffer = stbir__get_decode_buffer(stbir_info);
1528 stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors;
1529 float* horizontal_coefficients = stbir_info->horizontal_coefficients;
1530 int coefficient_width = stbir_info->horizontal_coefficient_width;
1531 int filter_pixel_margin = stbir_info->horizontal_filter_pixel_margin;
1532 int max_x = input_w + filter_pixel_margin * 2;
1534 STBIR_ASSERT(!stbir__use_width_upsampling(stbir_info));
1538 for (x = 0; x < max_x; x++)
1540 int n0 = horizontal_contributors[x].n0;
1541 int n1 = horizontal_contributors[x].n1;
1543 int in_x = x - filter_pixel_margin;
1544 int in_pixel_index = in_x * 1;
1546 int coefficient_group = coefficient_width * x;
1548 for (k = n0; k <= max_n; k++)
1550 int out_pixel_index = k * 1;
1551 float coefficient = horizontal_coefficients[coefficient_group + k - n0];
1552 STBIR_ASSERT(coefficient != 0);
1553 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1559 for (x = 0; x < max_x; x++)
1561 int n0 = horizontal_contributors[x].n0;
1562 int n1 = horizontal_contributors[x].n1;
1564 int in_x = x - filter_pixel_margin;
1565 int in_pixel_index = in_x * 2;
1567 int coefficient_group = coefficient_width * x;
1569 for (k = n0; k <= max_n; k++)
1571 int out_pixel_index = k * 2;
1572 float coefficient = horizontal_coefficients[coefficient_group + k - n0];
1573 STBIR_ASSERT(coefficient != 0);
1574 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1575 output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1581 for (x = 0; x < max_x; x++)
1583 int n0 = horizontal_contributors[x].n0;
1584 int n1 = horizontal_contributors[x].n1;
1586 int in_x = x - filter_pixel_margin;
1587 int in_pixel_index = in_x * 3;
1589 int coefficient_group = coefficient_width * x;
1591 for (k = n0; k <= max_n; k++)
1593 int out_pixel_index = k * 3;
1594 float coefficient = horizontal_coefficients[coefficient_group + k - n0];
1595 STBIR_ASSERT(coefficient != 0);
1596 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1597 output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1598 output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
1604 for (x = 0; x < max_x; x++)
1606 int n0 = horizontal_contributors[x].n0;
1607 int n1 = horizontal_contributors[x].n1;
1609 int in_x = x - filter_pixel_margin;
1610 int in_pixel_index = in_x * 4;
1612 int coefficient_group = coefficient_width * x;
1614 for (k = n0; k <= max_n; k++)
1616 int out_pixel_index = k * 4;
1617 float coefficient = horizontal_coefficients[coefficient_group + k - n0];
1618 STBIR_ASSERT(coefficient != 0);
1619 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1620 output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1621 output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
1622 output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient;
1628 for (x = 0; x < max_x; x++)
1630 int n0 = horizontal_contributors[x].n0;
1631 int n1 = horizontal_contributors[x].n1;
1633 int in_x = x - filter_pixel_margin;
1634 int in_pixel_index = in_x * channels;
1636 int coefficient_group = coefficient_width * x;
1638 for (k = n0; k <= max_n; k++)
1641 int out_pixel_index = k * channels;
1642 float coefficient = horizontal_coefficients[coefficient_group + k - n0];
1643 STBIR_ASSERT(coefficient != 0);
1644 for (c = 0; c < channels; c++)
1645 output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient;
1652 static void stbir__decode_and_resample_upsample(stbir__info* stbir_info,
int n)
1655 stbir__decode_scanline(stbir_info, n);
1658 if (stbir__use_width_upsampling(stbir_info))
1659 stbir__resample_horizontal_upsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n));
1661 stbir__resample_horizontal_downsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n));
1666 static void stbir__decode_and_resample_downsample(stbir__info* stbir_info,
int n)
1669 stbir__decode_scanline(stbir_info, n);
1671 memset(stbir_info->horizontal_buffer, 0, stbir_info->output_w * stbir_info->channels *
sizeof(
float));
1674 if (stbir__use_width_upsampling(stbir_info))
1675 stbir__resample_horizontal_upsample(stbir_info, stbir_info->horizontal_buffer);
1677 stbir__resample_horizontal_downsample(stbir_info, stbir_info->horizontal_buffer);
1683 static float* stbir__get_ring_buffer_scanline(
int get_scanline,
float* ring_buffer,
int begin_index,
int first_scanline,
int ring_buffer_num_entries,
int ring_buffer_length)
1685 int ring_buffer_index = (begin_index + (get_scanline - first_scanline)) % ring_buffer_num_entries;
1686 return stbir__get_ring_buffer_entry(ring_buffer, ring_buffer_index, ring_buffer_length);
1690 static void stbir__encode_scanline(stbir__info* stbir_info,
int num_pixels,
void *output_buffer,
float *encode_buffer,
int channels,
int alpha_channel,
int decode)
1695 stbir_uint16 nonalpha[STBIR_MAX_CHANNELS];
1697 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_PREMULTIPLIED))
1699 for (x=0; x < num_pixels; ++x)
1701 int pixel_index = x*channels;
1703 float alpha = encode_buffer[pixel_index + alpha_channel];
1704 float reciprocal_alpha = alpha ? 1.0f / alpha : 0;
1707 for (n = 0; n < channels; n++)
1708 if (n != alpha_channel)
1709 encode_buffer[pixel_index + n] *= reciprocal_alpha;
1720 for (x = 0, num_nonalpha = 0; x < channels; ++x)
1722 if (x != alpha_channel || (stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE))
1724 nonalpha[num_nonalpha++] = (stbir_uint16)x;
1728 #define STBIR__ROUND_INT(f) ((int) ((f)+0.5))
1729 #define STBIR__ROUND_UINT(f) ((stbir_uint32) ((f)+0.5))
1731 #ifdef STBIR__SATURATE_INT
1732 #define STBIR__ENCODE_LINEAR8(f) stbir__saturate8 (STBIR__ROUND_INT((f) * stbir__max_uint8_as_float ))
1733 #define STBIR__ENCODE_LINEAR16(f) stbir__saturate16(STBIR__ROUND_INT((f) * stbir__max_uint16_as_float))
1735 #define STBIR__ENCODE_LINEAR8(f) (unsigned char ) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint8_as_float )
1736 #define STBIR__ENCODE_LINEAR16(f) (unsigned short) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint16_as_float)
1741 case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR):
1742 for (x=0; x < num_pixels; ++x)
1744 int pixel_index = x*channels;
1746 for (n = 0; n < channels; n++)
1748 int index = pixel_index + n;
1749 ((
unsigned char*)output_buffer)[index] = STBIR__ENCODE_LINEAR8(encode_buffer[index]);
1754 case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB):
1755 for (x=0; x < num_pixels; ++x)
1757 int pixel_index = x*channels;
1759 for (n = 0; n < num_nonalpha; n++)
1761 int index = pixel_index + nonalpha[n];
1762 ((
unsigned char*)output_buffer)[index] = stbir__linear_to_srgb_uchar(encode_buffer[index]);
1765 if (!(stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE))
1766 ((
unsigned char *)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR8(encode_buffer[pixel_index+alpha_channel]);
1770 case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR):
1771 for (x=0; x < num_pixels; ++x)
1773 int pixel_index = x*channels;
1775 for (n = 0; n < channels; n++)
1777 int index = pixel_index + n;
1778 ((
unsigned short*)output_buffer)[index] = STBIR__ENCODE_LINEAR16(encode_buffer[index]);
1783 case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB):
1784 for (x=0; x < num_pixels; ++x)
1786 int pixel_index = x*channels;
1788 for (n = 0; n < num_nonalpha; n++)
1790 int index = pixel_index + nonalpha[n];
1791 ((
unsigned short*)output_buffer)[index] = (
unsigned short)STBIR__ROUND_INT(stbir__linear_to_srgb(stbir__saturate(encode_buffer[index])) * stbir__max_uint16_as_float);
1794 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1795 ((
unsigned short*)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR16(encode_buffer[pixel_index + alpha_channel]);
1800 case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR):
1801 for (x=0; x < num_pixels; ++x)
1803 int pixel_index = x*channels;
1805 for (n = 0; n < channels; n++)
1807 int index = pixel_index + n;
1808 ((
unsigned int*)output_buffer)[index] = (
unsigned int)STBIR__ROUND_UINT(((
double)stbir__saturate(encode_buffer[index])) * stbir__max_uint32_as_float);
1813 case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB):
1814 for (x=0; x < num_pixels; ++x)
1816 int pixel_index = x*channels;
1818 for (n = 0; n < num_nonalpha; n++)
1820 int index = pixel_index + nonalpha[n];
1821 ((
unsigned int*)output_buffer)[index] = (
unsigned int)STBIR__ROUND_UINT(((
double)stbir__linear_to_srgb(stbir__saturate(encode_buffer[index]))) * stbir__max_uint32_as_float);
1824 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1825 ((
unsigned int*)output_buffer)[pixel_index + alpha_channel] = (
unsigned int)STBIR__ROUND_INT(((
double)stbir__saturate(encode_buffer[pixel_index + alpha_channel])) * stbir__max_uint32_as_float);
1829 case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR):
1830 for (x=0; x < num_pixels; ++x)
1832 int pixel_index = x*channels;
1834 for (n = 0; n < channels; n++)
1836 int index = pixel_index + n;
1837 ((
float*)output_buffer)[index] = encode_buffer[index];
1842 case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB):
1843 for (x=0; x < num_pixels; ++x)
1845 int pixel_index = x*channels;
1847 for (n = 0; n < num_nonalpha; n++)
1849 int index = pixel_index + nonalpha[n];
1850 ((
float*)output_buffer)[index] = stbir__linear_to_srgb(encode_buffer[index]);
1853 if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1854 ((
float*)output_buffer)[pixel_index + alpha_channel] = encode_buffer[pixel_index + alpha_channel];
1859 STBIR_ASSERT(!
"Unknown type/colorspace/channels combination.");
1864 static void stbir__resample_vertical_upsample(stbir__info* stbir_info,
int n)
1867 int output_w = stbir_info->output_w;
1868 stbir__contributors* vertical_contributors = stbir_info->vertical_contributors;
1869 float* vertical_coefficients = stbir_info->vertical_coefficients;
1870 int channels = stbir_info->channels;
1871 int alpha_channel = stbir_info->alpha_channel;
1872 int type = stbir_info->type;
1873 int colorspace = stbir_info->colorspace;
1874 int ring_buffer_entries = stbir_info->ring_buffer_num_entries;
1875 void* output_data = stbir_info->output_data;
1876 float* encode_buffer = stbir_info->encode_buffer;
1877 int decode = STBIR__DECODE(type, colorspace);
1878 int coefficient_width = stbir_info->vertical_coefficient_width;
1879 int coefficient_counter;
1880 int contributor = n;
1882 float* ring_buffer = stbir_info->ring_buffer;
1883 int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index;
1884 int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline;
1885 int ring_buffer_length = stbir_info->ring_buffer_length_bytes/
sizeof(float);
1887 int n0,n1, output_row_start;
1888 int coefficient_group = coefficient_width * contributor;
1890 n0 = vertical_contributors[contributor].n0;
1891 n1 = vertical_contributors[contributor].n1;
1893 output_row_start = n * stbir_info->output_stride_bytes;
1895 STBIR_ASSERT(stbir__use_height_upsampling(stbir_info));
1897 memset(encode_buffer, 0, output_w *
sizeof(
float) * channels);
1902 coefficient_counter = 0;
1905 for (k = n0; k <= n1; k++)
1907 int coefficient_index = coefficient_counter++;
1908 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
1909 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
1910 for (x = 0; x < output_w; ++x)
1912 int in_pixel_index = x * 1;
1913 encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
1918 for (k = n0; k <= n1; k++)
1920 int coefficient_index = coefficient_counter++;
1921 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
1922 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
1923 for (x = 0; x < output_w; ++x)
1925 int in_pixel_index = x * 2;
1926 encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
1927 encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
1932 for (k = n0; k <= n1; k++)
1934 int coefficient_index = coefficient_counter++;
1935 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
1936 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
1937 for (x = 0; x < output_w; ++x)
1939 int in_pixel_index = x * 3;
1940 encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
1941 encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
1942 encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient;
1947 for (k = n0; k <= n1; k++)
1949 int coefficient_index = coefficient_counter++;
1950 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
1951 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
1952 for (x = 0; x < output_w; ++x)
1954 int in_pixel_index = x * 4;
1955 encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
1956 encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
1957 encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient;
1958 encode_buffer[in_pixel_index + 3] += ring_buffer_entry[in_pixel_index + 3] * coefficient;
1963 for (k = n0; k <= n1; k++)
1965 int coefficient_index = coefficient_counter++;
1966 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
1967 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
1968 for (x = 0; x < output_w; ++x)
1970 int in_pixel_index = x * channels;
1972 for (c = 0; c < channels; c++)
1973 encode_buffer[in_pixel_index + c] += ring_buffer_entry[in_pixel_index + c] * coefficient;
1978 stbir__encode_scanline(stbir_info, output_w, (
char *) output_data + output_row_start, encode_buffer, channels, alpha_channel, decode);
1981 static void stbir__resample_vertical_downsample(stbir__info* stbir_info,
int n)
1984 int output_w = stbir_info->output_w;
1985 stbir__contributors* vertical_contributors = stbir_info->vertical_contributors;
1986 float* vertical_coefficients = stbir_info->vertical_coefficients;
1987 int channels = stbir_info->channels;
1988 int ring_buffer_entries = stbir_info->ring_buffer_num_entries;
1989 float* horizontal_buffer = stbir_info->horizontal_buffer;
1990 int coefficient_width = stbir_info->vertical_coefficient_width;
1991 int contributor = n + stbir_info->vertical_filter_pixel_margin;
1993 float* ring_buffer = stbir_info->ring_buffer;
1994 int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index;
1995 int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline;
1996 int ring_buffer_length = stbir_info->ring_buffer_length_bytes/
sizeof(float);
1999 n0 = vertical_contributors[contributor].n0;
2000 n1 = vertical_contributors[contributor].n1;
2002 STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info));
2004 for (k = n0; k <= n1; k++)
2006 int coefficient_index = k - n0;
2007 int coefficient_group = coefficient_width * contributor;
2008 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
2010 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
2014 for (x = 0; x < output_w; x++)
2016 int in_pixel_index = x * 1;
2017 ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
2021 for (x = 0; x < output_w; x++)
2023 int in_pixel_index = x * 2;
2024 ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
2025 ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
2029 for (x = 0; x < output_w; x++)
2031 int in_pixel_index = x * 3;
2032 ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
2033 ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
2034 ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient;
2038 for (x = 0; x < output_w; x++)
2040 int in_pixel_index = x * 4;
2041 ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
2042 ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
2043 ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient;
2044 ring_buffer_entry[in_pixel_index + 3] += horizontal_buffer[in_pixel_index + 3] * coefficient;
2048 for (x = 0; x < output_w; x++)
2050 int in_pixel_index = x * channels;
2053 for (c = 0; c < channels; c++)
2054 ring_buffer_entry[in_pixel_index + c] += horizontal_buffer[in_pixel_index + c] * coefficient;
2061 static void stbir__buffer_loop_upsample(stbir__info* stbir_info)
2064 float scale_ratio = stbir_info->vertical_scale;
2065 float out_scanlines_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(1/scale_ratio) * scale_ratio;
2067 STBIR_ASSERT(stbir__use_height_upsampling(stbir_info));
2069 for (y = 0; y < stbir_info->output_h; y++)
2071 float in_center_of_out = 0;
2072 int in_first_scanline = 0, in_last_scanline = 0;
2074 stbir__calculate_sample_range_upsample(y, out_scanlines_radius, scale_ratio, stbir_info->vertical_shift, &in_first_scanline, &in_last_scanline, &in_center_of_out);
2076 STBIR_ASSERT(in_last_scanline - in_first_scanline + 1 <= stbir_info->ring_buffer_num_entries);
2078 if (stbir_info->ring_buffer_begin_index >= 0)
2081 while (in_first_scanline > stbir_info->ring_buffer_first_scanline)
2083 if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline)
2087 stbir_info->ring_buffer_begin_index = -1;
2088 stbir_info->ring_buffer_first_scanline = 0;
2089 stbir_info->ring_buffer_last_scanline = 0;
2094 stbir_info->ring_buffer_first_scanline++;
2095 stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries;
2101 if (stbir_info->ring_buffer_begin_index < 0)
2102 stbir__decode_and_resample_upsample(stbir_info, in_first_scanline);
2104 while (in_last_scanline > stbir_info->ring_buffer_last_scanline)
2105 stbir__decode_and_resample_upsample(stbir_info, stbir_info->ring_buffer_last_scanline + 1);
2108 stbir__resample_vertical_upsample(stbir_info, y);
2110 STBIR_PROGRESS_REPORT((
float)y / stbir_info->output_h);
2114 static void stbir__empty_ring_buffer(stbir__info* stbir_info,
int first_necessary_scanline)
2116 int output_stride_bytes = stbir_info->output_stride_bytes;
2117 int channels = stbir_info->channels;
2118 int alpha_channel = stbir_info->alpha_channel;
2119 int type = stbir_info->type;
2120 int colorspace = stbir_info->colorspace;
2121 int output_w = stbir_info->output_w;
2122 void* output_data = stbir_info->output_data;
2123 int decode = STBIR__DECODE(type, colorspace);
2125 float* ring_buffer = stbir_info->ring_buffer;
2126 int ring_buffer_length = stbir_info->ring_buffer_length_bytes/
sizeof(float);
2128 if (stbir_info->ring_buffer_begin_index >= 0)
2131 while (first_necessary_scanline > stbir_info->ring_buffer_first_scanline)
2133 if (stbir_info->ring_buffer_first_scanline >= 0 && stbir_info->ring_buffer_first_scanline < stbir_info->output_h)
2135 int output_row_start = stbir_info->ring_buffer_first_scanline * output_stride_bytes;
2136 float* ring_buffer_entry = stbir__get_ring_buffer_entry(ring_buffer, stbir_info->ring_buffer_begin_index, ring_buffer_length);
2137 stbir__encode_scanline(stbir_info, output_w, (
char *) output_data + output_row_start, ring_buffer_entry, channels, alpha_channel, decode);
2138 STBIR_PROGRESS_REPORT((
float)stbir_info->ring_buffer_first_scanline / stbir_info->output_h);
2141 if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline)
2145 stbir_info->ring_buffer_begin_index = -1;
2146 stbir_info->ring_buffer_first_scanline = 0;
2147 stbir_info->ring_buffer_last_scanline = 0;
2152 stbir_info->ring_buffer_first_scanline++;
2153 stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries;
2159 static void stbir__buffer_loop_downsample(stbir__info* stbir_info)
2162 float scale_ratio = stbir_info->vertical_scale;
2163 int output_h = stbir_info->output_h;
2164 float in_pixels_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(scale_ratio) / scale_ratio;
2165 int pixel_margin = stbir_info->vertical_filter_pixel_margin;
2166 int max_y = stbir_info->input_h + pixel_margin;
2168 STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info));
2170 for (y = -pixel_margin; y < max_y; y++)
2172 float out_center_of_in;
2173 int out_first_scanline, out_last_scanline;
2175 stbir__calculate_sample_range_downsample(y, in_pixels_radius, scale_ratio, stbir_info->vertical_shift, &out_first_scanline, &out_last_scanline, &out_center_of_in);
2177 STBIR_ASSERT(out_last_scanline - out_first_scanline + 1 <= stbir_info->ring_buffer_num_entries);
2179 if (out_last_scanline < 0 || out_first_scanline >= output_h)
2182 stbir__empty_ring_buffer(stbir_info, out_first_scanline);
2184 stbir__decode_and_resample_downsample(stbir_info, y);
2187 if (stbir_info->ring_buffer_begin_index < 0)
2188 stbir__add_empty_ring_buffer_entry(stbir_info, out_first_scanline);
2190 while (out_last_scanline > stbir_info->ring_buffer_last_scanline)
2191 stbir__add_empty_ring_buffer_entry(stbir_info, stbir_info->ring_buffer_last_scanline + 1);
2194 stbir__resample_vertical_downsample(stbir_info, y);
2197 stbir__empty_ring_buffer(stbir_info, stbir_info->output_h);
2200 static void stbir__setup(stbir__info *info,
int input_w,
int input_h,
int output_w,
int output_h,
int channels)
2202 info->input_w = input_w;
2203 info->input_h = input_h;
2204 info->output_w = output_w;
2205 info->output_h = output_h;
2206 info->channels = channels;
2209 static void stbir__calculate_transform(stbir__info *info,
float s0,
float t0,
float s1,
float t1,
float *transform)
2218 info->horizontal_scale = transform[0];
2219 info->vertical_scale = transform[1];
2220 info->horizontal_shift = transform[2];
2221 info->vertical_shift = transform[3];
2225 info->horizontal_scale = ((float)info->output_w / info->input_w) / (s1 - s0);
2226 info->vertical_scale = ((float)info->output_h / info->input_h) / (t1 - t0);
2228 info->horizontal_shift = s0 * info->output_w / (s1 - s0);
2229 info->vertical_shift = t0 * info->output_h / (t1 - t0);
2233 static void stbir__choose_filter(stbir__info *info, stbir_filter h_filter, stbir_filter v_filter)
2236 h_filter = stbir__use_upsampling(info->horizontal_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE;
2238 v_filter = stbir__use_upsampling(info->vertical_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE;
2239 info->horizontal_filter = h_filter;
2240 info->vertical_filter = v_filter;
2243 static stbir_uint32 stbir__calculate_memory(stbir__info *info)
2245 int pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale);
2246 int filter_height = stbir__get_filter_pixel_width(info->vertical_filter, info->vertical_scale);
2248 info->horizontal_num_contributors = stbir__get_contributors(info->horizontal_scale, info->horizontal_filter, info->input_w, info->output_w);
2249 info->vertical_num_contributors = stbir__get_contributors(info->vertical_scale , info->vertical_filter , info->input_h, info->output_h);
2252 info->ring_buffer_num_entries = filter_height + 1;
2254 info->horizontal_contributors_size = info->horizontal_num_contributors *
sizeof(stbir__contributors);
2255 info->horizontal_coefficients_size = stbir__get_total_horizontal_coefficients(info) *
sizeof(float);
2256 info->vertical_contributors_size = info->vertical_num_contributors *
sizeof(stbir__contributors);
2257 info->vertical_coefficients_size = stbir__get_total_vertical_coefficients(info) *
sizeof(float);
2258 info->decode_buffer_size = (info->input_w + pixel_margin * 2) * info->channels *
sizeof(
float);
2259 info->horizontal_buffer_size = info->output_w * info->channels *
sizeof(float);
2260 info->ring_buffer_size = info->output_w * info->channels * info->ring_buffer_num_entries *
sizeof(float);
2261 info->encode_buffer_size = info->output_w * info->channels *
sizeof(float);
2263 STBIR_ASSERT(info->horizontal_filter != 0);
2264 STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
2265 STBIR_ASSERT(info->vertical_filter != 0);
2266 STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
2268 if (stbir__use_height_upsampling(info))
2272 info->horizontal_buffer_size = 0;
2276 info->encode_buffer_size = 0;
2278 return info->horizontal_contributors_size + info->horizontal_coefficients_size
2279 + info->vertical_contributors_size + info->vertical_coefficients_size
2280 + info->decode_buffer_size + info->horizontal_buffer_size
2281 + info->ring_buffer_size + info->encode_buffer_size;
2284 static int stbir__resize_allocated(stbir__info *info,
2285 const void* input_data,
int input_stride_in_bytes,
2286 void* output_data,
int output_stride_in_bytes,
2287 int alpha_channel, stbir_uint32 flags, stbir_datatype type,
2288 stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace,
2289 void* tempmem,
size_t tempmem_size_in_bytes)
2291 size_t memory_required = stbir__calculate_memory(info);
2293 int width_stride_input = input_stride_in_bytes ? input_stride_in_bytes : info->channels * info->input_w * stbir__type_size[type];
2294 int width_stride_output = output_stride_in_bytes ? output_stride_in_bytes : info->channels * info->output_w * stbir__type_size[type];
2296 #ifdef STBIR_DEBUG_OVERWRITE_TEST
2297 #define OVERWRITE_ARRAY_SIZE 8
2298 unsigned char overwrite_output_before_pre[OVERWRITE_ARRAY_SIZE];
2299 unsigned char overwrite_tempmem_before_pre[OVERWRITE_ARRAY_SIZE];
2300 unsigned char overwrite_output_after_pre[OVERWRITE_ARRAY_SIZE];
2301 unsigned char overwrite_tempmem_after_pre[OVERWRITE_ARRAY_SIZE];
2303 size_t begin_forbidden = width_stride_output * (info->output_h - 1) + info->output_w * info->channels * stbir__type_size[type];
2304 memcpy(overwrite_output_before_pre, &((
unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE);
2305 memcpy(overwrite_output_after_pre, &((
unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE);
2306 memcpy(overwrite_tempmem_before_pre, &((
unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE);
2307 memcpy(overwrite_tempmem_after_pre, &((
unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE);
2310 STBIR_ASSERT(info->channels >= 0);
2311 STBIR_ASSERT(info->channels <= STBIR_MAX_CHANNELS);
2313 if (info->channels < 0 || info->channels > STBIR_MAX_CHANNELS)
2316 STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
2317 STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
2319 if (info->horizontal_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table))
2321 if (info->vertical_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table))
2324 if (alpha_channel < 0)
2325 flags |= STBIR_FLAG_ALPHA_USES_COLORSPACE | STBIR_FLAG_ALPHA_PREMULTIPLIED;
2327 if (!(flags&STBIR_FLAG_ALPHA_USES_COLORSPACE) || !(flags&STBIR_FLAG_ALPHA_PREMULTIPLIED))
2328 STBIR_ASSERT(alpha_channel >= 0 && alpha_channel < info->channels);
2330 if (alpha_channel >= info->channels)
2333 STBIR_ASSERT(tempmem);
2338 STBIR_ASSERT(tempmem_size_in_bytes >= memory_required);
2340 if (tempmem_size_in_bytes < memory_required)
2343 memset(tempmem, 0, tempmem_size_in_bytes);
2345 info->input_data = input_data;
2346 info->input_stride_bytes = width_stride_input;
2348 info->output_data = output_data;
2349 info->output_stride_bytes = width_stride_output;
2351 info->alpha_channel = alpha_channel;
2352 info->flags = flags;
2354 info->edge_horizontal = edge_horizontal;
2355 info->edge_vertical = edge_vertical;
2356 info->colorspace = colorspace;
2358 info->horizontal_coefficient_width = stbir__get_coefficient_width (info->horizontal_filter, info->horizontal_scale);
2359 info->vertical_coefficient_width = stbir__get_coefficient_width (info->vertical_filter , info->vertical_scale );
2360 info->horizontal_filter_pixel_width = stbir__get_filter_pixel_width (info->horizontal_filter, info->horizontal_scale);
2361 info->vertical_filter_pixel_width = stbir__get_filter_pixel_width (info->vertical_filter , info->vertical_scale );
2362 info->horizontal_filter_pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale);
2363 info->vertical_filter_pixel_margin = stbir__get_filter_pixel_margin(info->vertical_filter , info->vertical_scale );
2365 info->ring_buffer_length_bytes = info->output_w * info->channels *
sizeof(float);
2366 info->decode_buffer_pixels = info->input_w + info->horizontal_filter_pixel_margin * 2;
2368 #define STBIR__NEXT_MEMPTR(current, newtype) (newtype*)(((unsigned char*)current) + current##_size)
2370 info->horizontal_contributors = (stbir__contributors *) tempmem;
2371 info->horizontal_coefficients = STBIR__NEXT_MEMPTR(info->horizontal_contributors,
float);
2372 info->vertical_contributors = STBIR__NEXT_MEMPTR(info->horizontal_coefficients, stbir__contributors);
2373 info->vertical_coefficients = STBIR__NEXT_MEMPTR(info->vertical_contributors,
float);
2374 info->decode_buffer = STBIR__NEXT_MEMPTR(info->vertical_coefficients,
float);
2376 if (stbir__use_height_upsampling(info))
2378 info->horizontal_buffer = NULL;
2379 info->ring_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer,
float);
2380 info->encode_buffer = STBIR__NEXT_MEMPTR(info->ring_buffer,
float);
2382 STBIR_ASSERT((
size_t)STBIR__NEXT_MEMPTR(info->encode_buffer,
unsigned char) == (
size_t)tempmem + tempmem_size_in_bytes);
2386 info->horizontal_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer,
float);
2387 info->ring_buffer = STBIR__NEXT_MEMPTR(info->horizontal_buffer,
float);
2388 info->encode_buffer = NULL;
2390 STBIR_ASSERT((
size_t)STBIR__NEXT_MEMPTR(info->ring_buffer,
unsigned char) == (
size_t)tempmem + tempmem_size_in_bytes);
2393 #undef STBIR__NEXT_MEMPTR
2396 info->ring_buffer_begin_index = -1;
2398 stbir__calculate_filters(info->horizontal_contributors, info->horizontal_coefficients, info->horizontal_filter, info->horizontal_scale, info->horizontal_shift, info->input_w, info->output_w);
2399 stbir__calculate_filters(info->vertical_contributors, info->vertical_coefficients, info->vertical_filter, info->vertical_scale, info->vertical_shift, info->input_h, info->output_h);
2401 STBIR_PROGRESS_REPORT(0);
2403 if (stbir__use_height_upsampling(info))
2404 stbir__buffer_loop_upsample(info);
2406 stbir__buffer_loop_downsample(info);
2408 STBIR_PROGRESS_REPORT(1);
2410 #ifdef STBIR_DEBUG_OVERWRITE_TEST
2411 STBIR_ASSERT(memcmp(overwrite_output_before_pre, &((
unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0);
2412 STBIR_ASSERT(memcmp(overwrite_output_after_pre, &((
unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE) == 0);
2413 STBIR_ASSERT(memcmp(overwrite_tempmem_before_pre, &((
unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0);
2414 STBIR_ASSERT(memcmp(overwrite_tempmem_after_pre, &((
unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE) == 0);
2421 static int stbir__resize_arbitrary(
2422 void *alloc_context,
2423 const void* input_data,
int input_w,
int input_h,
int input_stride_in_bytes,
2424 void* output_data,
int output_w,
int output_h,
int output_stride_in_bytes,
2425 float s0,
float t0,
float s1,
float t1,
float *transform,
2426 int channels,
int alpha_channel, stbir_uint32 flags, stbir_datatype type,
2427 stbir_filter h_filter, stbir_filter v_filter,
2428 stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace)
2432 size_t memory_required;
2435 stbir__setup(&info, input_w, input_h, output_w, output_h, channels);
2436 stbir__calculate_transform(&info, s0,t0,s1,t1,transform);
2437 stbir__choose_filter(&info, h_filter, v_filter);
2438 memory_required = stbir__calculate_memory(&info);
2439 extra_memory = STBIR_MALLOC(memory_required, alloc_context);
2444 result = stbir__resize_allocated(&info, input_data, input_stride_in_bytes,
2445 output_data, output_stride_in_bytes,
2446 alpha_channel, flags, type,
2447 edge_horizontal, edge_vertical,
2448 colorspace, extra_memory, memory_required);
2450 STBIR_FREE(extra_memory, alloc_context);
2455 STBIRDEF
int stbir_resize_uint8(
const unsigned char *input_pixels ,
int input_w ,
int input_h ,
int input_stride_in_bytes,
2456 unsigned char *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
2459 return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
2460 output_pixels, output_w, output_h, output_stride_in_bytes,
2461 0,0,1,1,NULL,num_channels,-1,0, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
2462 STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR);
2465 STBIRDEF
int stbir_resize_float(
const float *input_pixels ,
int input_w ,
int input_h ,
int input_stride_in_bytes,
2466 float *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
2469 return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
2470 output_pixels, output_w, output_h, output_stride_in_bytes,
2471 0,0,1,1,NULL,num_channels,-1,0, STBIR_TYPE_FLOAT, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
2472 STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR);
2475 STBIRDEF
int stbir_resize_uint8_srgb(
const unsigned char *input_pixels ,
int input_w ,
int input_h ,
int input_stride_in_bytes,
2476 unsigned char *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
2477 int num_channels,
int alpha_channel,
int flags)
2479 return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
2480 output_pixels, output_w, output_h, output_stride_in_bytes,
2481 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
2482 STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB);
2485 STBIRDEF
int stbir_resize_uint8_srgb_edgemode(
const unsigned char *input_pixels ,
int input_w ,
int input_h ,
int input_stride_in_bytes,
2486 unsigned char *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
2487 int num_channels,
int alpha_channel,
int flags,
2488 stbir_edge edge_wrap_mode)
2490 return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
2491 output_pixels, output_w, output_h, output_stride_in_bytes,
2492 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
2493 edge_wrap_mode, edge_wrap_mode, STBIR_COLORSPACE_SRGB);
2496 STBIRDEF
int stbir_resize_uint8_generic(
const unsigned char *input_pixels ,
int input_w ,
int input_h ,
int input_stride_in_bytes,
2497 unsigned char *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
2498 int num_channels,
int alpha_channel,
int flags,
2499 stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
2500 void *alloc_context)
2502 return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
2503 output_pixels, output_w, output_h, output_stride_in_bytes,
2504 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, filter, filter,
2505 edge_wrap_mode, edge_wrap_mode, space);
2508 STBIRDEF
int stbir_resize_uint16_generic(
const stbir_uint16 *input_pixels ,
int input_w ,
int input_h ,
int input_stride_in_bytes,
2509 stbir_uint16 *output_pixels ,
int output_w,
int output_h,
int output_stride_in_bytes,
2510 int num_channels,
int alpha_channel,
int flags,
2511 stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
2512 void *alloc_context)
2514 return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
2515 output_pixels, output_w, output_h, output_stride_in_bytes,
2516 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT16, filter, filter,
2517 edge_wrap_mode, edge_wrap_mode, space);
2521 STBIRDEF
int stbir_resize_float_generic(
const float *input_pixels ,
int input_w ,
int input_h ,
int input_stride_in_bytes,
2522 float *output_pixels ,
int output_w,
int output_h,
int output_stride_in_bytes,
2523 int num_channels,
int alpha_channel,
int flags,
2524 stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
2525 void *alloc_context)
2527 return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
2528 output_pixels, output_w, output_h, output_stride_in_bytes,
2529 0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_FLOAT, filter, filter,
2530 edge_wrap_mode, edge_wrap_mode, space);
2534 STBIRDEF
int stbir_resize(
const void *input_pixels ,
int input_w ,
int input_h ,
int input_stride_in_bytes,
2535 void *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
2536 stbir_datatype datatype,
2537 int num_channels,
int alpha_channel,
int flags,
2538 stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
2539 stbir_filter filter_horizontal, stbir_filter filter_vertical,
2540 stbir_colorspace space,
void *alloc_context)
2542 return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
2543 output_pixels, output_w, output_h, output_stride_in_bytes,
2544 0,0,1,1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
2545 edge_mode_horizontal, edge_mode_vertical, space);
2549 STBIRDEF
int stbir_resize_subpixel(
const void *input_pixels ,
int input_w ,
int input_h ,
int input_stride_in_bytes,
2550 void *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
2551 stbir_datatype datatype,
2552 int num_channels,
int alpha_channel,
int flags,
2553 stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
2554 stbir_filter filter_horizontal, stbir_filter filter_vertical,
2555 stbir_colorspace space,
void *alloc_context,
2556 float x_scale,
float y_scale,
2557 float x_offset,
float y_offset)
2560 transform[0] = x_scale;
2561 transform[1] = y_scale;
2562 transform[2] = x_offset;
2563 transform[3] = y_offset;
2564 return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
2565 output_pixels, output_w, output_h, output_stride_in_bytes,
2566 0,0,1,1,transform,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
2567 edge_mode_horizontal, edge_mode_vertical, space);
2570 STBIRDEF
int stbir_resize_region(
const void *input_pixels ,
int input_w ,
int input_h ,
int input_stride_in_bytes,
2571 void *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
2572 stbir_datatype datatype,
2573 int num_channels,
int alpha_channel,
int flags,
2574 stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
2575 stbir_filter filter_horizontal, stbir_filter filter_vertical,
2576 stbir_colorspace space,
void *alloc_context,
2577 float s0,
float t0,
float s1,
float t1)
2579 return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
2580 output_pixels, output_w, output_h, output_stride_in_bytes,
2581 s0,t0,s1,t1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
2582 edge_mode_horizontal, edge_mode_vertical, space);
2585 #endif // STB_IMAGE_RESIZE_IMPLEMENTATION
void if(!TfPyIsInitialized())
Invokes wrapFunc to wrap type T if T is not already wrapped.