184#ifndef STBIR_INCLUDE_STB_IMAGE_RESIZE_H
185#define STBIR_INCLUDE_STB_IMAGE_RESIZE_H
199#ifdef STB_IMAGE_RESIZE_STATIC
200#define STBIRDEF static
203#define STBIRDEF extern "C"
205#define STBIRDEF extern
229 unsigned char *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
233 float *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
243#define STBIR_ALPHA_CHANNEL_NONE -1
248#define STBIR_FLAG_ALPHA_PREMULTIPLIED (1 << 0)
251#define STBIR_FLAG_ALPHA_USES_COLORSPACE (1 << 1)
254 unsigned char *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
255 int num_channels,
int alpha_channel,
int flags);
268 unsigned char *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
269 int num_channels,
int alpha_channel,
int flags,
308 unsigned char *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
309 int num_channels,
int alpha_channel,
int flags,
311 void *alloc_context);
314 stbir_uint16 *output_pixels ,
int output_w,
int output_h,
int output_stride_in_bytes,
315 int num_channels,
int alpha_channel,
int flags,
317 void *alloc_context);
320 float *output_pixels ,
int output_w,
int output_h,
int output_stride_in_bytes,
321 int num_channels,
int alpha_channel,
int flags,
323 void *alloc_context);
351 void *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
353 int num_channels,
int alpha_channel,
int flags,
359 void *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
361 int num_channels,
int alpha_channel,
int flags,
365 float x_scale,
float y_scale,
366 float x_offset,
float y_offset);
369 void *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
371 int num_channels,
int alpha_channel,
int flags,
375 float s0,
float t0,
float s1,
float t1);
387#ifdef STB_IMAGE_RESIZE_IMPLEMENTATION
391#define STBIR_ASSERT(x) assert(x)
402#define STBIR_MALLOC(size,c) ((void)(c), malloc(size))
403#define STBIR_FREE(ptr,c) ((void)(c), free(ptr))
408#define stbir__inline inline
413#define stbir__inline __forceinline
418typedef unsigned char stbir__validate_uint32[
sizeof(
stbir_uint32) == 4 ? 1 : -1];
421#define STBIR__NOTUSED(v) (void)(v)
423#define STBIR__NOTUSED(v) (void)sizeof(v)
426#define STBIR__ARRAY_SIZE(a) (sizeof((a))/sizeof((a)[0]))
428#ifndef STBIR_DEFAULT_FILTER_UPSAMPLE
429#define STBIR_DEFAULT_FILTER_UPSAMPLE STBIR_FILTER_CATMULLROM
432#ifndef STBIR_DEFAULT_FILTER_DOWNSAMPLE
433#define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL
436#ifndef STBIR_PROGRESS_REPORT
437#define STBIR_PROGRESS_REPORT(float_0_to_1)
440#ifndef STBIR_MAX_CHANNELS
441#define STBIR_MAX_CHANNELS 64
444#if STBIR_MAX_CHANNELS > 65536
445#error "Too many channels; STBIR_MAX_CHANNELS must be no more than 65536."
454#ifndef STBIR_ALPHA_EPSILON
455#define STBIR_ALPHA_EPSILON ((float)1 / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20))
461#define STBIR__UNUSED_PARAM(v) (void)(v)
463#define STBIR__UNUSED_PARAM(v) (void)sizeof(v)
467static unsigned char stbir__type_size[] = {
475typedef float (stbir__kernel_fn)(
float x,
float scale);
476typedef float (stbir__support_fn)(
float scale);
480 stbir__kernel_fn* kernel;
481 stbir__support_fn* support;
490} stbir__contributors;
494 const void* input_data;
497 int input_stride_bytes;
502 int output_stride_bytes;
504 float s0, t0, s1, t1;
506 float horizontal_shift;
507 float vertical_shift;
508 float horizontal_scale;
509 float vertical_scale;
521 stbir__contributors* horizontal_contributors;
522 float* horizontal_coefficients;
524 stbir__contributors* vertical_contributors;
525 float* vertical_coefficients;
527 int decode_buffer_pixels;
528 float* decode_buffer;
530 float* horizontal_buffer;
533 int horizontal_coefficient_width;
534 int vertical_coefficient_width;
535 int horizontal_filter_pixel_width;
536 int vertical_filter_pixel_width;
537 int horizontal_filter_pixel_margin;
538 int vertical_filter_pixel_margin;
539 int horizontal_num_contributors;
540 int vertical_num_contributors;
542 int ring_buffer_length_bytes;
543 int ring_buffer_num_entries;
544 int ring_buffer_first_scanline;
545 int ring_buffer_last_scanline;
546 int ring_buffer_begin_index;
549 float* encode_buffer;
551 int horizontal_contributors_size;
552 int horizontal_coefficients_size;
553 int vertical_contributors_size;
554 int vertical_coefficients_size;
555 int decode_buffer_size;
556 int horizontal_buffer_size;
557 int ring_buffer_size;
558 int encode_buffer_size;
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;
567static stbir__inline
int stbir__min(
int a,
int b)
569 return a < b ? a : b;
572static stbir__inline
float stbir__saturate(
float x)
583#ifdef STBIR_SATURATE_INT
584static stbir__inline
stbir_uint8 stbir__saturate8(
int x)
586 if ((
unsigned int) x <= 255)
595static stbir__inline
stbir_uint16 stbir__saturate16(
int x)
597 if ((
unsigned int) x <= 65535)
607static float stbir__srgb_uchar_to_linear_float[256] = {
608 0.000000f, 0.000304f, 0.000607f, 0.000911f, 0.001214f, 0.001518f, 0.001821f, 0.002125f, 0.002428f, 0.002732f, 0.003035f,
609 0.003347f, 0.003677f, 0.004025f, 0.004391f, 0.004777f, 0.005182f, 0.005605f, 0.006049f, 0.006512f, 0.006995f, 0.007499f,
610 0.008023f, 0.008568f, 0.009134f, 0.009721f, 0.010330f, 0.010960f, 0.011612f, 0.012286f, 0.012983f, 0.013702f, 0.014444f,
611 0.015209f, 0.015996f, 0.016807f, 0.017642f, 0.018500f, 0.019382f, 0.020289f, 0.021219f, 0.022174f, 0.023153f, 0.024158f,
612 0.025187f, 0.026241f, 0.027321f, 0.028426f, 0.029557f, 0.030713f, 0.031896f, 0.033105f, 0.034340f, 0.035601f, 0.036889f,
613 0.038204f, 0.039546f, 0.040915f, 0.042311f, 0.043735f, 0.045186f, 0.046665f, 0.048172f, 0.049707f, 0.051269f, 0.052861f,
614 0.054480f, 0.056128f, 0.057805f, 0.059511f, 0.061246f, 0.063010f, 0.064803f, 0.066626f, 0.068478f, 0.070360f, 0.072272f,
615 0.074214f, 0.076185f, 0.078187f, 0.080220f, 0.082283f, 0.084376f, 0.086500f, 0.088656f, 0.090842f, 0.093059f, 0.095307f,
616 0.097587f, 0.099899f, 0.102242f, 0.104616f, 0.107023f, 0.109462f, 0.111932f, 0.114435f, 0.116971f, 0.119538f, 0.122139f,
617 0.124772f, 0.127438f, 0.130136f, 0.132868f, 0.135633f, 0.138432f, 0.141263f, 0.144128f, 0.147027f, 0.149960f, 0.152926f,
618 0.155926f, 0.158961f, 0.162029f, 0.165132f, 0.168269f, 0.171441f, 0.174647f, 0.177888f, 0.181164f, 0.184475f, 0.187821f,
619 0.191202f, 0.194618f, 0.198069f, 0.201556f, 0.205079f, 0.208637f, 0.212231f, 0.215861f, 0.219526f, 0.223228f, 0.226966f,
620 0.230740f, 0.234551f, 0.238398f, 0.242281f, 0.246201f, 0.250158f, 0.254152f, 0.258183f, 0.262251f, 0.266356f, 0.270498f,
621 0.274677f, 0.278894f, 0.283149f, 0.287441f, 0.291771f, 0.296138f, 0.300544f, 0.304987f, 0.309469f, 0.313989f, 0.318547f,
622 0.323143f, 0.327778f, 0.332452f, 0.337164f, 0.341914f, 0.346704f, 0.351533f, 0.356400f, 0.361307f, 0.366253f, 0.371238f,
623 0.376262f, 0.381326f, 0.386430f, 0.391573f, 0.396755f, 0.401978f, 0.407240f, 0.412543f, 0.417885f, 0.423268f, 0.428691f,
624 0.434154f, 0.439657f, 0.445201f, 0.450786f, 0.456411f, 0.462077f, 0.467784f, 0.473532f, 0.479320f, 0.485150f, 0.491021f,
625 0.496933f, 0.502887f, 0.508881f, 0.514918f, 0.520996f, 0.527115f, 0.533276f, 0.539480f, 0.545725f, 0.552011f, 0.558340f,
626 0.564712f, 0.571125f, 0.577581f, 0.584078f, 0.590619f, 0.597202f, 0.603827f, 0.610496f, 0.617207f, 0.623960f, 0.630757f,
627 0.637597f, 0.644480f, 0.651406f, 0.658375f, 0.665387f, 0.672443f, 0.679543f, 0.686685f, 0.693872f, 0.701102f, 0.708376f,
628 0.715694f, 0.723055f, 0.730461f, 0.737911f, 0.745404f, 0.752942f, 0.760525f, 0.768151f, 0.775822f, 0.783538f, 0.791298f,
629 0.799103f, 0.806952f, 0.814847f, 0.822786f, 0.830770f, 0.838799f, 0.846873f, 0.854993f, 0.863157f, 0.871367f, 0.879622f,
630 0.887923f, 0.896269f, 0.904661f, 0.913099f, 0.921582f, 0.930111f, 0.938686f, 0.947307f, 0.955974f, 0.964686f, 0.973445f,
631 0.982251f, 0.991102f, 1.0f
634static float stbir__srgb_to_linear(
float f)
639 return (
float)pow((f + 0.055f) / 1.055f, 2.4f);
642static float stbir__linear_to_srgb(
float f)
647 return 1.055f * (float)pow(f, 1 / 2.4f) - 0.055f;
650#ifndef STBIR_NON_IEEE_FLOAT
660 0x0073000d, 0x007a000d, 0x0080000d, 0x0087000d, 0x008d000d, 0x0094000d, 0x009a000d, 0x00a1000d,
661 0x00a7001a, 0x00b4001a, 0x00c1001a, 0x00ce001a, 0x00da001a, 0x00e7001a, 0x00f4001a, 0x0101001a,
662 0x010e0033, 0x01280033, 0x01410033, 0x015b0033, 0x01750033, 0x018f0033, 0x01a80033, 0x01c20033,
663 0x01dc0067, 0x020f0067, 0x02430067, 0x02760067, 0x02aa0067, 0x02dd0067, 0x03110067, 0x03440067,
664 0x037800ce, 0x03df00ce, 0x044600ce, 0x04ad00ce, 0x051400ce, 0x057b00c5, 0x05dd00bc, 0x063b00b5,
665 0x06970158, 0x07420142, 0x07e30130, 0x087b0120, 0x090b0112, 0x09940106, 0x0a1700fc, 0x0a9500f2,
666 0x0b0f01cb, 0x0bf401ae, 0x0ccb0195, 0x0d950180, 0x0e56016e, 0x0f0d015e, 0x0fbc0150, 0x10630143,
667 0x11070264, 0x1238023e, 0x1357021d, 0x14660201, 0x156601e9, 0x165a01d3, 0x174401c0, 0x182401af,
668 0x18fe0331, 0x1a9602fe, 0x1c1502d2, 0x1d7e02ad, 0x1ed4028d, 0x201a0270, 0x21520256, 0x227d0240,
669 0x239f0443, 0x25c003fe, 0x27bf03c4, 0x29a10392, 0x2b6a0367, 0x2d1d0341, 0x2ebe031f, 0x304d0300,
670 0x31d105b0, 0x34a80555, 0x37520507, 0x39d504c5, 0x3c37048b, 0x3e7c0458, 0x40a8042a, 0x42bd0401,
671 0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559,
672 0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723,
675static stbir_uint8 stbir__linear_to_srgb_uchar(
float in)
677 static const stbir__FP32 almostone = { 0x3f7fffff };
678 static const stbir__FP32 minval = { (127-13) << 23 };
685 if (!(in > minval.f))
687 if (in > almostone.f)
692 tab = fp32_to_srgb8_tab4[(f.u - minval.u) >> 20];
693 bias = (tab >> 16) << 9;
694 scale = tab & 0xffff;
697 t = (f.u >> 12) & 0xff;
698 return (
unsigned char) ((bias + scale*t) >> 16);
703static int stbir__srgb_offset_to_linear_scaled[256] =
705 0, 40738, 122216, 203693, 285170, 366648, 448125, 529603,
706 611080, 692557, 774035, 855852, 942009, 1033024, 1128971, 1229926,
707 1335959, 1447142, 1563542, 1685229, 1812268, 1944725, 2082664, 2226148,
708 2375238, 2529996, 2690481, 2856753, 3028870, 3206888, 3390865, 3580856,
709 3776916, 3979100, 4187460, 4402049, 4622919, 4850123, 5083710, 5323731,
710 5570236, 5823273, 6082892, 6349140, 6622065, 6901714, 7188133, 7481369,
711 7781466, 8088471, 8402427, 8723380, 9051372, 9386448, 9728650, 10078021,
712 10434603, 10798439, 11169569, 11548036, 11933879, 12327139, 12727857, 13136073,
713 13551826, 13975156, 14406100, 14844697, 15290987, 15745007, 16206795, 16676389,
714 17153826, 17639142, 18132374, 18633560, 19142734, 19659934, 20185196, 20718552,
715 21260042, 21809696, 22367554, 22933648, 23508010, 24090680, 24681686, 25281066,
716 25888850, 26505076, 27129772, 27762974, 28404716, 29055026, 29713942, 30381490,
717 31057708, 31742624, 32436272, 33138682, 33849884, 34569912, 35298800, 36036568,
718 36783260, 37538896, 38303512, 39077136, 39859796, 40651528, 41452360, 42262316,
719 43081432, 43909732, 44747252, 45594016, 46450052, 47315392, 48190064, 49074096,
720 49967516, 50870356, 51782636, 52704392, 53635648, 54576432, 55526772, 56486700,
721 57456236, 58435408, 59424248, 60422780, 61431036, 62449032, 63476804, 64514376,
722 65561776, 66619028, 67686160, 68763192, 69850160, 70947088, 72053992, 73170912,
723 74297864, 75434880, 76581976, 77739184, 78906536, 80084040, 81271736, 82469648,
724 83677792, 84896192, 86124888, 87363888, 88613232, 89872928, 91143016, 92423512,
725 93714432, 95015816, 96327688, 97650056, 98982952, 100326408, 101680440, 103045072,
726 104420320, 105806224, 107202800, 108610064, 110028048, 111456776, 112896264, 114346544,
727 115807632, 117279552, 118762328, 120255976, 121760536, 123276016, 124802440, 126339832,
728 127888216, 129447616, 131018048, 132599544, 134192112, 135795792, 137410592, 139036528,
729 140673648, 142321952, 143981456, 145652208, 147334208, 149027488, 150732064, 152447968,
730 154175200, 155913792, 157663776, 159425168, 161197984, 162982240, 164777968, 166585184,
731 168403904, 170234160, 172075968, 173929344, 175794320, 177670896, 179559120, 181458992,
732 183370528, 185293776, 187228736, 189175424, 191133888, 193104112, 195086128, 197079968,
733 199085648, 201103184, 203132592, 205173888, 207227120, 209292272, 211369392, 213458480,
734 215559568, 217672656, 219797792, 221934976, 224084240, 226245600, 228419056, 230604656,
735 232802400, 235012320, 237234432, 239468736, 241715280, 243974080, 246245120, 248528464,
736 250824112, 253132064, 255452368, 257785040, 260130080, 262487520, 264857376, 267239664,
739static stbir_uint8 stbir__linear_to_srgb_uchar(
float f)
741 int x = (int) (f * (1 << 28));
746 i = v + 128;
if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
747 i = v + 64;
if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
748 i = v + 32;
if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
749 i = v + 16;
if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
750 i = v + 8;
if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
751 i = v + 4;
if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
752 i = v + 2;
if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
753 i = v + 1;
if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
759static float stbir__filter_trapezoid(
float x,
float scale)
761 float halfscale = scale / 2;
762 float t = 0.5f + halfscale;
763 STBIR_ASSERT(scale <= 1);
771 float r = 0.5f - halfscale;
775 return (t - x) / scale;
779static float stbir__support_trapezoid(
float scale)
781 STBIR_ASSERT(scale <= 1);
782 return 0.5f + scale / 2;
785static float stbir__filter_triangle(
float x,
float s)
787 STBIR__UNUSED_PARAM(s);
797static float stbir__filter_cubic(
float x,
float s)
799 STBIR__UNUSED_PARAM(s);
804 return (4 + x*x*(3*x - 6))/6;
806 return (8 + x*(-12 + x*(6 - x)))/6;
811static float stbir__filter_catmullrom(
float x,
float s)
813 STBIR__UNUSED_PARAM(s);
818 return 1 - x*x*(2.5f - 1.5f*x);
820 return 2 - x*(4 + x*(0.5f*x - 2.5f));
825static float stbir__filter_mitchell(
float x,
float s)
827 STBIR__UNUSED_PARAM(s);
832 return (16 + x*x*(21 * x - 36))/18;
834 return (32 + x*(-60 + x*(36 - 7*x)))/18;
839static float stbir__support_zero(
float s)
841 STBIR__UNUSED_PARAM(s);
845static float stbir__support_one(
float s)
847 STBIR__UNUSED_PARAM(s);
851static float stbir__support_two(
float s)
853 STBIR__UNUSED_PARAM(s);
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 },
866stbir__inline
static int stbir__use_upsampling(
float ratio)
871stbir__inline
static int stbir__use_width_upsampling(stbir__info* stbir_info)
873 return stbir__use_upsampling(stbir_info->horizontal_scale);
876stbir__inline
static int stbir__use_height_upsampling(stbir__info* stbir_info)
878 return stbir__use_upsampling(stbir_info->vertical_scale);
883static int stbir__get_filter_pixel_width(
stbir_filter filter,
float scale)
885 STBIR_ASSERT(filter != 0);
886 STBIR_ASSERT(filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
888 if (stbir__use_upsampling(scale))
889 return (
int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2);
891 return (
int)ceil(stbir__filter_info_table[filter].support(scale) * 2 / scale);
896static int stbir__get_filter_pixel_margin(
stbir_filter filter,
float scale)
898 return stbir__get_filter_pixel_width(filter, scale) / 2;
901static int stbir__get_coefficient_width(
stbir_filter filter,
float scale)
903 if (stbir__use_upsampling(scale))
904 return (
int)ceil(stbir__filter_info_table[filter].support(1 / scale) * 2);
906 return (
int)ceil(stbir__filter_info_table[filter].support(scale) * 2);
909static int stbir__get_contributors(
float scale,
stbir_filter filter,
int input_size,
int output_size)
911 if (stbir__use_upsampling(scale))
914 return (input_size + stbir__get_filter_pixel_margin(filter, scale) * 2);
917static int stbir__get_total_horizontal_coefficients(stbir__info* info)
919 return info->horizontal_num_contributors
920 * stbir__get_coefficient_width (info->horizontal_filter, info->horizontal_scale);
923static int stbir__get_total_vertical_coefficients(stbir__info* info)
925 return info->vertical_num_contributors
926 * stbir__get_coefficient_width (info->vertical_filter, info->vertical_scale);
929static stbir__contributors* stbir__get_contributor(stbir__contributors* contributors,
int n)
931 return &contributors[n];
936static float* stbir__get_coefficient(
float* coefficients,
stbir_filter filter,
float scale,
int n,
int c)
938 int width = stbir__get_coefficient_width(filter, scale);
939 return &coefficients[width*n + c];
942static int stbir__edge_wrap_slow(
stbir_edge edge,
int n,
int max)
995 STBIR_ASSERT(!
"Unimplemented edge type");
1000stbir__inline
static int stbir__edge_wrap(
stbir_edge edge,
int n,
int max)
1003 if (n >= 0 && n < max)
1005 return stbir__edge_wrap_slow(edge, n, max);
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)
1011 float out_pixel_center = (float)n + 0.5f;
1012 float out_pixel_influence_lowerbound = out_pixel_center - out_filter_radius;
1013 float out_pixel_influence_upperbound = out_pixel_center + out_filter_radius;
1015 float in_pixel_influence_lowerbound = (out_pixel_influence_lowerbound + out_shift) / scale_ratio;
1016 float in_pixel_influence_upperbound = (out_pixel_influence_upperbound + out_shift) / scale_ratio;
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));
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)
1026 float in_pixel_center = (float)n + 0.5f;
1027 float in_pixel_influence_lowerbound = in_pixel_center - in_pixels_radius;
1028 float in_pixel_influence_upperbound = in_pixel_center + in_pixels_radius;
1030 float out_pixel_influence_lowerbound = in_pixel_influence_lowerbound * scale_ratio - out_shift;
1031 float out_pixel_influence_upperbound = in_pixel_influence_upperbound * scale_ratio - out_shift;
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));
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)
1041 float total_filter = 0;
1044 STBIR_ASSERT(in_last_pixel - in_first_pixel <= (
int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2));
1046 contributor->n0 = in_first_pixel;
1047 contributor->n1 = in_last_pixel;
1049 STBIR_ASSERT(contributor->n1 >= contributor->n0);
1051 for (i = 0; i <= in_last_pixel - in_first_pixel; i++)
1053 float in_pixel_center = (float)(i + in_first_pixel) + 0.5f;
1054 coefficient_group[i] = stbir__filter_info_table[filter].kernel(in_center_of_out - in_pixel_center, 1 / scale);
1057 if (i == 0 && !coefficient_group[i])
1059 contributor->n0 = ++in_first_pixel;
1064 total_filter += coefficient_group[i];
1073 STBIR_ASSERT(total_filter > 0.9);
1074 STBIR_ASSERT(total_filter < 1.1f);
1077 filter_scale = 1 / total_filter;
1079 for (i = 0; i <= in_last_pixel - in_first_pixel; i++)
1080 coefficient_group[i] *= filter_scale;
1082 for (i = in_last_pixel - in_first_pixel; i >= 0; i--)
1084 if (coefficient_group[i])
1088 contributor->n1 = contributor->n0 + i - 1;
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)
1096 STBIR_ASSERT(out_last_pixel - out_first_pixel <= (
int)ceil(stbir__filter_info_table[filter].support(scale_ratio) * 2));
1098 contributor->n0 = out_first_pixel;
1099 contributor->n1 = out_last_pixel;
1101 STBIR_ASSERT(contributor->n1 >= contributor->n0);
1103 for (i = 0; i <= out_last_pixel - out_first_pixel; i++)
1105 float out_pixel_center = (float)(i + out_first_pixel) + 0.5f;
1106 float x = out_pixel_center - out_center_of_in;
1107 coefficient_group[i] = stbir__filter_info_table[filter].kernel(x, scale_ratio) * scale_ratio;
1116 for (i = out_last_pixel - out_first_pixel; i >= 0; i--)
1118 if (coefficient_group[i])
1122 contributor->n1 = contributor->n0 + i - 1;
1126static void stbir__normalize_downsample_coefficients(stbir__contributors* contributors,
float* coefficients,
stbir_filter filter,
float scale_ratio,
int input_size,
int output_size)
1128 int num_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size);
1129 int num_coefficients = stbir__get_coefficient_width(filter, scale_ratio);
1133 for (i = 0; i < output_size; i++)
1138 for (j = 0; j < num_contributors; j++)
1140 if (i >= contributors[j].n0 && i <= contributors[j].n1)
1142 float coefficient = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0);
1143 total += coefficient;
1145 else if (i < contributors[j].n0)
1149 STBIR_ASSERT(total > 0.9f);
1150 STBIR_ASSERT(total < 1.1f);
1154 for (j = 0; j < num_contributors; j++)
1156 if (i >= contributors[j].n0 && i <= contributors[j].n1)
1157 *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0) *= scale;
1158 else if (i < contributors[j].n0)
1165 for (j = 0; j < num_contributors; j++)
1167 int range, max, width;
1170 while (*stbir__get_coefficient(coefficients, filter, scale_ratio, j, skip) == 0)
1173 contributors[j].n0 += skip;
1175 while (contributors[j].n0 < 0)
1177 contributors[j].n0++;
1181 range = contributors[j].n1 - contributors[j].n0 + 1;
1182 max = stbir__min(num_coefficients, range);
1184 width = stbir__get_coefficient_width(filter, scale_ratio);
1185 for (i = 0; i < max; i++)
1187 if (i + skip >= width)
1190 *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i) = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i + skip);
1197 for (i = 0; i < num_contributors; i++)
1198 contributors[i].n1 = stbir__min(contributors[i].n1, output_size - 1);
1203static void stbir__calculate_filters(stbir__contributors* contributors,
float* coefficients,
stbir_filter filter,
float scale_ratio,
float shift,
int input_size,
int output_size)
1206 int total_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size);
1208 if (stbir__use_upsampling(scale_ratio))
1210 float out_pixels_radius = stbir__filter_info_table[filter].support(1 / scale_ratio) * scale_ratio;
1213 for (n = 0; n < total_contributors; n++)
1215 float in_center_of_out;
1216 int in_first_pixel, in_last_pixel;
1218 stbir__calculate_sample_range_upsample(n, out_pixels_radius, scale_ratio, shift, &in_first_pixel, &in_last_pixel, &in_center_of_out);
1220 stbir__calculate_coefficients_upsample(filter, scale_ratio, in_first_pixel, in_last_pixel, in_center_of_out, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0));
1225 float in_pixels_radius = stbir__filter_info_table[filter].support(scale_ratio) / scale_ratio;
1228 for (n = 0; n < total_contributors; n++)
1230 float out_center_of_in;
1231 int out_first_pixel, out_last_pixel;
1232 int n_adjusted = n - stbir__get_filter_pixel_margin(filter, scale_ratio);
1234 stbir__calculate_sample_range_downsample(n_adjusted, in_pixels_radius, scale_ratio, shift, &out_first_pixel, &out_last_pixel, &out_center_of_in);
1236 stbir__calculate_coefficients_downsample(filter, scale_ratio, out_first_pixel, out_last_pixel, out_center_of_in, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0));
1239 stbir__normalize_downsample_coefficients(contributors, coefficients, filter, scale_ratio, input_size, output_size);
1243static float* stbir__get_decode_buffer(stbir__info* stbir_info)
1247 return &stbir_info->decode_buffer[stbir_info->horizontal_filter_pixel_margin * stbir_info->channels];
1250#define STBIR__DECODE(type, colorspace) ((int)(type) * (STBIR_MAX_COLORSPACES) + (int)(colorspace))
1252static void stbir__decode_scanline(stbir__info* stbir_info,
int n)
1255 int channels = stbir_info->channels;
1256 int alpha_channel = stbir_info->alpha_channel;
1257 int type = stbir_info->type;
1258 int colorspace = stbir_info->colorspace;
1259 int input_w = stbir_info->input_w;
1260 size_t input_stride_bytes = stbir_info->input_stride_bytes;
1261 float* decode_buffer = stbir__get_decode_buffer(stbir_info);
1262 stbir_edge edge_horizontal = stbir_info->edge_horizontal;
1263 stbir_edge edge_vertical = stbir_info->edge_vertical;
1264 size_t in_buffer_row_offset = stbir__edge_wrap(edge_vertical, n, stbir_info->input_h) * input_stride_bytes;
1265 const void* input_data = (
char *) stbir_info->input_data + in_buffer_row_offset;
1266 int max_x = input_w + stbir_info->horizontal_filter_pixel_margin;
1267 int decode = STBIR__DECODE(type, colorspace);
1269 int x = -stbir_info->horizontal_filter_pixel_margin;
1273 if (edge_vertical ==
STBIR_EDGE_ZERO && (n < 0 || n >= stbir_info->input_h))
1275 for (; x < max_x; x++)
1276 for (c = 0; c < channels; c++)
1277 decode_buffer[x*channels + c] = 0;
1284 for (; x < max_x; x++)
1286 int decode_pixel_index = x * channels;
1287 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1288 for (c = 0; c < channels; c++)
1289 decode_buffer[decode_pixel_index + c] = ((
float)((
const unsigned char*)input_data)[input_pixel_index + c]) / stbir__max_uint8_as_float;
1294 for (; x < max_x; x++)
1296 int decode_pixel_index = x * channels;
1297 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1298 for (c = 0; c < channels; c++)
1299 decode_buffer[decode_pixel_index + c] = stbir__srgb_uchar_to_linear_float[((
const unsigned char*)input_data)[input_pixel_index + c]];
1302 decode_buffer[decode_pixel_index + alpha_channel] = ((float)((
const unsigned char*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint8_as_float;
1307 for (; x < max_x; x++)
1309 int decode_pixel_index = x * channels;
1310 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1311 for (c = 0; c < channels; c++)
1312 decode_buffer[decode_pixel_index + c] = ((
float)((
const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float;
1317 for (; x < max_x; x++)
1319 int decode_pixel_index = x * channels;
1320 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1321 for (c = 0; c < channels; c++)
1322 decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((
float)((
const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float);
1325 decode_buffer[decode_pixel_index + alpha_channel] = ((float)((
const unsigned short*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint16_as_float;
1330 for (; x < max_x; x++)
1332 int decode_pixel_index = x * channels;
1333 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1334 for (c = 0; c < channels; c++)
1335 decode_buffer[decode_pixel_index + c] = (
float)(((double)((
const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float);
1340 for (; x < max_x; x++)
1342 int decode_pixel_index = x * channels;
1343 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1344 for (c = 0; c < channels; c++)
1345 decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear((
float)(((
double)((
const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float));
1348 decode_buffer[decode_pixel_index + alpha_channel] = (float)(((
double)((
const unsigned int*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint32_as_float);
1353 for (; x < max_x; x++)
1355 int decode_pixel_index = x * channels;
1356 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1357 for (c = 0; c < channels; c++)
1358 decode_buffer[decode_pixel_index + c] = ((
const float*)input_data)[input_pixel_index + c];
1363 for (; x < max_x; x++)
1365 int decode_pixel_index = x * channels;
1366 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1367 for (c = 0; c < channels; c++)
1368 decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((
const float*)input_data)[input_pixel_index + c]);
1371 decode_buffer[decode_pixel_index + alpha_channel] = ((
const float*)input_data)[input_pixel_index + alpha_channel];
1377 STBIR_ASSERT(!
"Unknown type/colorspace/channels combination.");
1383 for (x = -stbir_info->horizontal_filter_pixel_margin; x < max_x; x++)
1385 int decode_pixel_index = x * channels;
1388 float alpha = decode_buffer[decode_pixel_index + alpha_channel];
1389#ifndef STBIR_NO_ALPHA_EPSILON
1391 alpha += STBIR_ALPHA_EPSILON;
1392 decode_buffer[decode_pixel_index + alpha_channel] = alpha;
1395 for (c = 0; c < channels; c++)
1397 if (c == alpha_channel)
1400 decode_buffer[decode_pixel_index + c] *= alpha;
1407 for (x = -stbir_info->horizontal_filter_pixel_margin; x < 0; x++)
1409 for (c = 0; c < channels; c++)
1410 decode_buffer[x*channels + c] = 0;
1412 for (x = input_w; x < max_x; x++)
1414 for (c = 0; c < channels; c++)
1415 decode_buffer[x*channels + c] = 0;
1420static float* stbir__get_ring_buffer_entry(
float* ring_buffer,
int index,
int ring_buffer_length)
1422 return &ring_buffer[index * ring_buffer_length];
1425static float* stbir__add_empty_ring_buffer_entry(stbir__info* stbir_info,
int n)
1427 int ring_buffer_index;
1430 stbir_info->ring_buffer_last_scanline = n;
1432 if (stbir_info->ring_buffer_begin_index < 0)
1434 ring_buffer_index = stbir_info->ring_buffer_begin_index = 0;
1435 stbir_info->ring_buffer_first_scanline = n;
1439 ring_buffer_index = (stbir_info->ring_buffer_begin_index + (stbir_info->ring_buffer_last_scanline - stbir_info->ring_buffer_first_scanline)) % stbir_info->ring_buffer_num_entries;
1440 STBIR_ASSERT(ring_buffer_index != stbir_info->ring_buffer_begin_index);
1443 ring_buffer = stbir__get_ring_buffer_entry(stbir_info->ring_buffer, ring_buffer_index, stbir_info->ring_buffer_length_bytes /
sizeof(
float));
1444 memset(ring_buffer, 0, stbir_info->ring_buffer_length_bytes);
1450static void stbir__resample_horizontal_upsample(stbir__info* stbir_info,
float* output_buffer)
1453 int output_w = stbir_info->output_w;
1454 int channels = stbir_info->channels;
1455 float* decode_buffer = stbir__get_decode_buffer(stbir_info);
1456 stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors;
1457 float* horizontal_coefficients = stbir_info->horizontal_coefficients;
1458 int coefficient_width = stbir_info->horizontal_coefficient_width;
1460 for (x = 0; x < output_w; x++)
1462 int n0 = horizontal_contributors[x].n0;
1463 int n1 = horizontal_contributors[x].n1;
1465 int out_pixel_index = x * channels;
1466 int coefficient_group = coefficient_width * x;
1467 int coefficient_counter = 0;
1469 STBIR_ASSERT(n1 >= n0);
1470 STBIR_ASSERT(n0 >= -stbir_info->horizontal_filter_pixel_margin);
1471 STBIR_ASSERT(n1 >= -stbir_info->horizontal_filter_pixel_margin);
1472 STBIR_ASSERT(n0 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin);
1473 STBIR_ASSERT(n1 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin);
1477 for (k = n0; k <= n1; k++)
1479 int in_pixel_index = k * 1;
1480 float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
1481 STBIR_ASSERT(coefficient != 0);
1482 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1486 for (k = n0; k <= n1; k++)
1488 int in_pixel_index = k * 2;
1489 float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
1490 STBIR_ASSERT(coefficient != 0);
1491 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1492 output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1496 for (k = n0; k <= n1; k++)
1498 int in_pixel_index = k * 3;
1499 float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
1500 STBIR_ASSERT(coefficient != 0);
1501 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1502 output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1503 output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
1507 for (k = n0; k <= n1; k++)
1509 int in_pixel_index = k * 4;
1510 float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
1511 STBIR_ASSERT(coefficient != 0);
1512 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1513 output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1514 output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
1515 output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient;
1519 for (k = n0; k <= n1; k++)
1521 int in_pixel_index = k * channels;
1522 float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
1524 STBIR_ASSERT(coefficient != 0);
1525 for (c = 0; c < channels; c++)
1526 output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient;
1533static void stbir__resample_horizontal_downsample(stbir__info* stbir_info,
float* output_buffer)
1536 int input_w = stbir_info->input_w;
1537 int channels = stbir_info->channels;
1538 float* decode_buffer = stbir__get_decode_buffer(stbir_info);
1539 stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors;
1540 float* horizontal_coefficients = stbir_info->horizontal_coefficients;
1541 int coefficient_width = stbir_info->horizontal_coefficient_width;
1542 int filter_pixel_margin = stbir_info->horizontal_filter_pixel_margin;
1543 int max_x = input_w + filter_pixel_margin * 2;
1545 STBIR_ASSERT(!stbir__use_width_upsampling(stbir_info));
1549 for (x = 0; x < max_x; x++)
1551 int n0 = horizontal_contributors[x].n0;
1552 int n1 = horizontal_contributors[x].n1;
1554 int in_x = x - filter_pixel_margin;
1555 int in_pixel_index = in_x * 1;
1557 int coefficient_group = coefficient_width * x;
1559 for (k = n0; k <= max_n; k++)
1561 int out_pixel_index = k * 1;
1562 float coefficient = horizontal_coefficients[coefficient_group + k - n0];
1563 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1569 for (x = 0; x < max_x; x++)
1571 int n0 = horizontal_contributors[x].n0;
1572 int n1 = horizontal_contributors[x].n1;
1574 int in_x = x - filter_pixel_margin;
1575 int in_pixel_index = in_x * 2;
1577 int coefficient_group = coefficient_width * x;
1579 for (k = n0; k <= max_n; k++)
1581 int out_pixel_index = k * 2;
1582 float coefficient = horizontal_coefficients[coefficient_group + k - n0];
1583 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1584 output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1590 for (x = 0; x < max_x; x++)
1592 int n0 = horizontal_contributors[x].n0;
1593 int n1 = horizontal_contributors[x].n1;
1595 int in_x = x - filter_pixel_margin;
1596 int in_pixel_index = in_x * 3;
1598 int coefficient_group = coefficient_width * x;
1600 for (k = n0; k <= max_n; k++)
1602 int out_pixel_index = k * 3;
1603 float coefficient = horizontal_coefficients[coefficient_group + k - n0];
1604 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1605 output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1606 output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
1612 for (x = 0; x < max_x; x++)
1614 int n0 = horizontal_contributors[x].n0;
1615 int n1 = horizontal_contributors[x].n1;
1617 int in_x = x - filter_pixel_margin;
1618 int in_pixel_index = in_x * 4;
1620 int coefficient_group = coefficient_width * x;
1622 for (k = n0; k <= max_n; k++)
1624 int out_pixel_index = k * 4;
1625 float coefficient = horizontal_coefficients[coefficient_group + k - n0];
1626 output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1627 output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1628 output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
1629 output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient;
1635 for (x = 0; x < max_x; x++)
1637 int n0 = horizontal_contributors[x].n0;
1638 int n1 = horizontal_contributors[x].n1;
1640 int in_x = x - filter_pixel_margin;
1641 int in_pixel_index = in_x * channels;
1643 int coefficient_group = coefficient_width * x;
1645 for (k = n0; k <= max_n; k++)
1648 int out_pixel_index = k * channels;
1649 float coefficient = horizontal_coefficients[coefficient_group + k - n0];
1650 for (c = 0; c < channels; c++)
1651 output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient;
1658static void stbir__decode_and_resample_upsample(stbir__info* stbir_info,
int n)
1661 stbir__decode_scanline(stbir_info, n);
1664 if (stbir__use_width_upsampling(stbir_info))
1665 stbir__resample_horizontal_upsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n));
1667 stbir__resample_horizontal_downsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n));
1672static void stbir__decode_and_resample_downsample(stbir__info* stbir_info,
int n)
1675 stbir__decode_scanline(stbir_info, n);
1677 memset(stbir_info->horizontal_buffer, 0, stbir_info->output_w * stbir_info->channels *
sizeof(
float));
1680 if (stbir__use_width_upsampling(stbir_info))
1681 stbir__resample_horizontal_upsample(stbir_info, stbir_info->horizontal_buffer);
1683 stbir__resample_horizontal_downsample(stbir_info, stbir_info->horizontal_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)
1691 int ring_buffer_index = (begin_index + (get_scanline - first_scanline)) % ring_buffer_num_entries;
1692 return stbir__get_ring_buffer_entry(ring_buffer, ring_buffer_index, ring_buffer_length);
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)
1705 for (x=0; x < num_pixels; ++x)
1707 int pixel_index = x*channels;
1709 float alpha = encode_buffer[pixel_index + alpha_channel];
1710 float reciprocal_alpha = alpha ? 1.0f / alpha : 0;
1713 for (n = 0; n < channels; n++)
1714 if (n != alpha_channel)
1715 encode_buffer[pixel_index + n] *= reciprocal_alpha;
1726 for (x = 0, num_nonalpha = 0; x < channels; ++x)
1734 #define STBIR__ROUND_INT(f) ((int) ((f)+0.5))
1735 #define STBIR__ROUND_UINT(f) ((stbir_uint32) ((f)+0.5))
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))
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)
1748 for (x=0; x < num_pixels; ++x)
1750 int pixel_index = x*channels;
1752 for (n = 0; n < channels; n++)
1754 int index = pixel_index + n;
1755 ((
unsigned char*)output_buffer)[index] = STBIR__ENCODE_LINEAR8(encode_buffer[index]);
1761 for (x=0; x < num_pixels; ++x)
1763 int pixel_index = x*channels;
1765 for (n = 0; n < num_nonalpha; n++)
1767 int index = pixel_index + nonalpha[n];
1768 ((
unsigned char*)output_buffer)[index] = stbir__linear_to_srgb_uchar(encode_buffer[index]);
1772 ((
unsigned char *)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR8(encode_buffer[pixel_index+alpha_channel]);
1777 for (x=0; x < num_pixels; ++x)
1779 int pixel_index = x*channels;
1781 for (n = 0; n < channels; n++)
1783 int index = pixel_index + n;
1784 ((
unsigned short*)output_buffer)[index] = STBIR__ENCODE_LINEAR16(encode_buffer[index]);
1790 for (x=0; x < num_pixels; ++x)
1792 int pixel_index = x*channels;
1794 for (n = 0; n < num_nonalpha; n++)
1796 int index = pixel_index + nonalpha[n];
1797 ((
unsigned short*)output_buffer)[index] = (
unsigned short)STBIR__ROUND_INT(stbir__linear_to_srgb(stbir__saturate(encode_buffer[index])) * stbir__max_uint16_as_float);
1801 ((
unsigned short*)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR16(encode_buffer[pixel_index + alpha_channel]);
1807 for (x=0; x < num_pixels; ++x)
1809 int pixel_index = x*channels;
1811 for (n = 0; n < channels; n++)
1813 int index = pixel_index + n;
1814 ((
unsigned int*)output_buffer)[index] = (
unsigned int)STBIR__ROUND_UINT(((
double)stbir__saturate(encode_buffer[index])) * stbir__max_uint32_as_float);
1820 for (x=0; x < num_pixels; ++x)
1822 int pixel_index = x*channels;
1824 for (n = 0; n < num_nonalpha; n++)
1826 int index = pixel_index + nonalpha[n];
1827 ((
unsigned int*)output_buffer)[index] = (
unsigned int)STBIR__ROUND_UINT(((
double)stbir__linear_to_srgb(stbir__saturate(encode_buffer[index]))) * stbir__max_uint32_as_float);
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);
1836 for (x=0; x < num_pixels; ++x)
1838 int pixel_index = x*channels;
1840 for (n = 0; n < channels; n++)
1842 int index = pixel_index + n;
1843 ((
float*)output_buffer)[index] = encode_buffer[index];
1849 for (x=0; x < num_pixels; ++x)
1851 int pixel_index = x*channels;
1853 for (n = 0; n < num_nonalpha; n++)
1855 int index = pixel_index + nonalpha[n];
1856 ((
float*)output_buffer)[index] = stbir__linear_to_srgb(encode_buffer[index]);
1860 ((
float*)output_buffer)[pixel_index + alpha_channel] = encode_buffer[pixel_index + alpha_channel];
1865 STBIR_ASSERT(!
"Unknown type/colorspace/channels combination.");
1870static void stbir__resample_vertical_upsample(stbir__info* stbir_info,
int n)
1873 int output_w = stbir_info->output_w;
1874 stbir__contributors* vertical_contributors = stbir_info->vertical_contributors;
1875 float* vertical_coefficients = stbir_info->vertical_coefficients;
1876 int channels = stbir_info->channels;
1877 int alpha_channel = stbir_info->alpha_channel;
1878 int type = stbir_info->type;
1879 int colorspace = stbir_info->colorspace;
1880 int ring_buffer_entries = stbir_info->ring_buffer_num_entries;
1881 void* output_data = stbir_info->output_data;
1882 float* encode_buffer = stbir_info->encode_buffer;
1883 int decode = STBIR__DECODE(type, colorspace);
1884 int coefficient_width = stbir_info->vertical_coefficient_width;
1885 int coefficient_counter;
1886 int contributor = n;
1888 float* ring_buffer = stbir_info->ring_buffer;
1889 int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index;
1890 int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline;
1891 int ring_buffer_length = stbir_info->ring_buffer_length_bytes/
sizeof(float);
1893 int n0,n1, output_row_start;
1894 int coefficient_group = coefficient_width * contributor;
1896 n0 = vertical_contributors[contributor].n0;
1897 n1 = vertical_contributors[contributor].n1;
1899 output_row_start = n * stbir_info->output_stride_bytes;
1901 STBIR_ASSERT(stbir__use_height_upsampling(stbir_info));
1903 memset(encode_buffer, 0, output_w *
sizeof(
float) * channels);
1908 coefficient_counter = 0;
1911 for (k = n0; k <= n1; k++)
1913 int coefficient_index = coefficient_counter++;
1914 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
1915 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
1916 for (x = 0; x < output_w; ++x)
1918 int in_pixel_index = x * 1;
1919 encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
1924 for (k = n0; k <= n1; k++)
1926 int coefficient_index = coefficient_counter++;
1927 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
1928 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
1929 for (x = 0; x < output_w; ++x)
1931 int in_pixel_index = x * 2;
1932 encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
1933 encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
1938 for (k = n0; k <= n1; k++)
1940 int coefficient_index = coefficient_counter++;
1941 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
1942 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
1943 for (x = 0; x < output_w; ++x)
1945 int in_pixel_index = x * 3;
1946 encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
1947 encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
1948 encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient;
1953 for (k = n0; k <= n1; k++)
1955 int coefficient_index = coefficient_counter++;
1956 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
1957 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
1958 for (x = 0; x < output_w; ++x)
1960 int in_pixel_index = x * 4;
1961 encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
1962 encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
1963 encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient;
1964 encode_buffer[in_pixel_index + 3] += ring_buffer_entry[in_pixel_index + 3] * coefficient;
1969 for (k = n0; k <= n1; k++)
1971 int coefficient_index = coefficient_counter++;
1972 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
1973 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
1974 for (x = 0; x < output_w; ++x)
1976 int in_pixel_index = x * channels;
1978 for (c = 0; c < channels; c++)
1979 encode_buffer[in_pixel_index + c] += ring_buffer_entry[in_pixel_index + c] * coefficient;
1984 stbir__encode_scanline(stbir_info, output_w, (
char *) output_data + output_row_start, encode_buffer, channels, alpha_channel, decode);
1987static void stbir__resample_vertical_downsample(stbir__info* stbir_info,
int n)
1990 int output_w = stbir_info->output_w;
1991 stbir__contributors* vertical_contributors = stbir_info->vertical_contributors;
1992 float* vertical_coefficients = stbir_info->vertical_coefficients;
1993 int channels = stbir_info->channels;
1994 int ring_buffer_entries = stbir_info->ring_buffer_num_entries;
1995 float* horizontal_buffer = stbir_info->horizontal_buffer;
1996 int coefficient_width = stbir_info->vertical_coefficient_width;
1997 int contributor = n + stbir_info->vertical_filter_pixel_margin;
1999 float* ring_buffer = stbir_info->ring_buffer;
2000 int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index;
2001 int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline;
2002 int ring_buffer_length = stbir_info->ring_buffer_length_bytes/
sizeof(float);
2005 n0 = vertical_contributors[contributor].n0;
2006 n1 = vertical_contributors[contributor].n1;
2008 STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info));
2010 for (k = n0; k <= n1; k++)
2012 int coefficient_index = k - n0;
2013 int coefficient_group = coefficient_width * contributor;
2014 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
2016 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
2020 for (x = 0; x < output_w; x++)
2022 int in_pixel_index = x * 1;
2023 ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
2027 for (x = 0; x < output_w; x++)
2029 int in_pixel_index = x * 2;
2030 ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
2031 ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
2035 for (x = 0; x < output_w; x++)
2037 int in_pixel_index = x * 3;
2038 ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
2039 ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
2040 ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient;
2044 for (x = 0; x < output_w; x++)
2046 int in_pixel_index = x * 4;
2047 ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
2048 ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
2049 ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient;
2050 ring_buffer_entry[in_pixel_index + 3] += horizontal_buffer[in_pixel_index + 3] * coefficient;
2054 for (x = 0; x < output_w; x++)
2056 int in_pixel_index = x * channels;
2059 for (c = 0; c < channels; c++)
2060 ring_buffer_entry[in_pixel_index + c] += horizontal_buffer[in_pixel_index + c] * coefficient;
2067static void stbir__buffer_loop_upsample(stbir__info* stbir_info)
2070 float scale_ratio = stbir_info->vertical_scale;
2071 float out_scanlines_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(1/scale_ratio) * scale_ratio;
2073 STBIR_ASSERT(stbir__use_height_upsampling(stbir_info));
2075 for (y = 0; y < stbir_info->output_h; y++)
2077 float in_center_of_out = 0;
2078 int in_first_scanline = 0, in_last_scanline = 0;
2080 stbir__calculate_sample_range_upsample(y, out_scanlines_radius, scale_ratio, stbir_info->vertical_shift, &in_first_scanline, &in_last_scanline, &in_center_of_out);
2082 STBIR_ASSERT(in_last_scanline - in_first_scanline + 1 <= stbir_info->ring_buffer_num_entries);
2084 if (stbir_info->ring_buffer_begin_index >= 0)
2087 while (in_first_scanline > stbir_info->ring_buffer_first_scanline)
2089 if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline)
2093 stbir_info->ring_buffer_begin_index = -1;
2094 stbir_info->ring_buffer_first_scanline = 0;
2095 stbir_info->ring_buffer_last_scanline = 0;
2100 stbir_info->ring_buffer_first_scanline++;
2101 stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries;
2107 if (stbir_info->ring_buffer_begin_index < 0)
2108 stbir__decode_and_resample_upsample(stbir_info, in_first_scanline);
2110 while (in_last_scanline > stbir_info->ring_buffer_last_scanline)
2111 stbir__decode_and_resample_upsample(stbir_info, stbir_info->ring_buffer_last_scanline + 1);
2114 stbir__resample_vertical_upsample(stbir_info, y);
2116 STBIR_PROGRESS_REPORT((
float)y / stbir_info->output_h);
2120static void stbir__empty_ring_buffer(stbir__info* stbir_info,
int first_necessary_scanline)
2122 int output_stride_bytes = stbir_info->output_stride_bytes;
2123 int channels = stbir_info->channels;
2124 int alpha_channel = stbir_info->alpha_channel;
2125 int type = stbir_info->type;
2126 int colorspace = stbir_info->colorspace;
2127 int output_w = stbir_info->output_w;
2128 void* output_data = stbir_info->output_data;
2129 int decode = STBIR__DECODE(type, colorspace);
2131 float* ring_buffer = stbir_info->ring_buffer;
2132 int ring_buffer_length = stbir_info->ring_buffer_length_bytes/
sizeof(float);
2134 if (stbir_info->ring_buffer_begin_index >= 0)
2137 while (first_necessary_scanline > stbir_info->ring_buffer_first_scanline)
2139 if (stbir_info->ring_buffer_first_scanline >= 0 && stbir_info->ring_buffer_first_scanline < stbir_info->output_h)
2141 int output_row_start = stbir_info->ring_buffer_first_scanline * output_stride_bytes;
2142 float* ring_buffer_entry = stbir__get_ring_buffer_entry(ring_buffer, stbir_info->ring_buffer_begin_index, ring_buffer_length);
2143 stbir__encode_scanline(stbir_info, output_w, (
char *) output_data + output_row_start, ring_buffer_entry, channels, alpha_channel, decode);
2144 STBIR_PROGRESS_REPORT((
float)stbir_info->ring_buffer_first_scanline / stbir_info->output_h);
2147 if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline)
2151 stbir_info->ring_buffer_begin_index = -1;
2152 stbir_info->ring_buffer_first_scanline = 0;
2153 stbir_info->ring_buffer_last_scanline = 0;
2158 stbir_info->ring_buffer_first_scanline++;
2159 stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries;
2165static void stbir__buffer_loop_downsample(stbir__info* stbir_info)
2168 float scale_ratio = stbir_info->vertical_scale;
2169 int output_h = stbir_info->output_h;
2170 float in_pixels_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(scale_ratio) / scale_ratio;
2171 int pixel_margin = stbir_info->vertical_filter_pixel_margin;
2172 int max_y = stbir_info->input_h + pixel_margin;
2174 STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info));
2176 for (y = -pixel_margin; y < max_y; y++)
2178 float out_center_of_in;
2179 int out_first_scanline, out_last_scanline;
2181 stbir__calculate_sample_range_downsample(y, in_pixels_radius, scale_ratio, stbir_info->vertical_shift, &out_first_scanline, &out_last_scanline, &out_center_of_in);
2183 STBIR_ASSERT(out_last_scanline - out_first_scanline + 1 <= stbir_info->ring_buffer_num_entries);
2185 if (out_last_scanline < 0 || out_first_scanline >= output_h)
2188 stbir__empty_ring_buffer(stbir_info, out_first_scanline);
2190 stbir__decode_and_resample_downsample(stbir_info, y);
2193 if (stbir_info->ring_buffer_begin_index < 0)
2194 stbir__add_empty_ring_buffer_entry(stbir_info, out_first_scanline);
2196 while (out_last_scanline > stbir_info->ring_buffer_last_scanline)
2197 stbir__add_empty_ring_buffer_entry(stbir_info, stbir_info->ring_buffer_last_scanline + 1);
2200 stbir__resample_vertical_downsample(stbir_info, y);
2203 stbir__empty_ring_buffer(stbir_info, stbir_info->output_h);
2206static void stbir__setup(stbir__info *info,
int input_w,
int input_h,
int output_w,
int output_h,
int channels)
2208 info->input_w = input_w;
2209 info->input_h = input_h;
2210 info->output_w = output_w;
2211 info->output_h = output_h;
2212 info->channels = channels;
2215static void stbir__calculate_transform(stbir__info *info,
float s0,
float t0,
float s1,
float t1,
float *transform)
2224 info->horizontal_scale = transform[0];
2225 info->vertical_scale = transform[1];
2226 info->horizontal_shift = transform[2];
2227 info->vertical_shift = transform[3];
2231 info->horizontal_scale = ((float)info->output_w / info->input_w) / (s1 - s0);
2232 info->vertical_scale = ((float)info->output_h / info->input_h) / (t1 - t0);
2234 info->horizontal_shift = s0 * info->output_w / (s1 - s0);
2235 info->vertical_shift = t0 * info->output_h / (t1 - t0);
2242 h_filter = stbir__use_upsampling(info->horizontal_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE;
2244 v_filter = stbir__use_upsampling(info->vertical_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE;
2245 info->horizontal_filter = h_filter;
2246 info->vertical_filter = v_filter;
2249static stbir_uint32 stbir__calculate_memory(stbir__info *info)
2251 int pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale);
2252 int filter_height = stbir__get_filter_pixel_width(info->vertical_filter, info->vertical_scale);
2254 info->horizontal_num_contributors = stbir__get_contributors(info->horizontal_scale, info->horizontal_filter, info->input_w, info->output_w);
2255 info->vertical_num_contributors = stbir__get_contributors(info->vertical_scale , info->vertical_filter , info->input_h, info->output_h);
2258 info->ring_buffer_num_entries = filter_height + 1;
2260 info->horizontal_contributors_size = info->horizontal_num_contributors *
sizeof(stbir__contributors);
2261 info->horizontal_coefficients_size = stbir__get_total_horizontal_coefficients(info) *
sizeof(float);
2262 info->vertical_contributors_size = info->vertical_num_contributors *
sizeof(stbir__contributors);
2263 info->vertical_coefficients_size = stbir__get_total_vertical_coefficients(info) *
sizeof(float);
2264 info->decode_buffer_size = (info->input_w + pixel_margin * 2) * info->channels *
sizeof(
float);
2265 info->horizontal_buffer_size = info->output_w * info->channels *
sizeof(float);
2266 info->ring_buffer_size = info->output_w * info->channels * info->ring_buffer_num_entries *
sizeof(float);
2267 info->encode_buffer_size = info->output_w * info->channels *
sizeof(float);
2269 STBIR_ASSERT(info->horizontal_filter != 0);
2270 STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
2271 STBIR_ASSERT(info->vertical_filter != 0);
2272 STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
2274 if (stbir__use_height_upsampling(info))
2278 info->horizontal_buffer_size = 0;
2282 info->encode_buffer_size = 0;
2284 return info->horizontal_contributors_size + info->horizontal_coefficients_size
2285 + info->vertical_contributors_size + info->vertical_coefficients_size
2286 + info->decode_buffer_size + info->horizontal_buffer_size
2287 + info->ring_buffer_size + info->encode_buffer_size;
2290static int stbir__resize_allocated(stbir__info *info,
2291 const void* input_data,
int input_stride_in_bytes,
2292 void* output_data,
int output_stride_in_bytes,
2295 void* tempmem,
size_t tempmem_size_in_bytes)
2297 size_t memory_required = stbir__calculate_memory(info);
2299 int width_stride_input = input_stride_in_bytes ? input_stride_in_bytes : info->channels * info->input_w * stbir__type_size[type];
2300 int width_stride_output = output_stride_in_bytes ? output_stride_in_bytes : info->channels * info->output_w * stbir__type_size[type];
2302#ifdef STBIR_DEBUG_OVERWRITE_TEST
2303#define OVERWRITE_ARRAY_SIZE 8
2304 unsigned char overwrite_output_before_pre[OVERWRITE_ARRAY_SIZE];
2305 unsigned char overwrite_tempmem_before_pre[OVERWRITE_ARRAY_SIZE];
2306 unsigned char overwrite_output_after_pre[OVERWRITE_ARRAY_SIZE];
2307 unsigned char overwrite_tempmem_after_pre[OVERWRITE_ARRAY_SIZE];
2309 size_t begin_forbidden = width_stride_output * (info->output_h - 1) + info->output_w * info->channels * stbir__type_size[type];
2310 memcpy(overwrite_output_before_pre, &((
unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE);
2311 memcpy(overwrite_output_after_pre, &((
unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE);
2312 memcpy(overwrite_tempmem_before_pre, &((
unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE);
2313 memcpy(overwrite_tempmem_after_pre, &((
unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE);
2316 STBIR_ASSERT(info->channels >= 0);
2317 STBIR_ASSERT(info->channels <= STBIR_MAX_CHANNELS);
2319 if (info->channels < 0 || info->channels > STBIR_MAX_CHANNELS)
2322 STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
2323 STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
2325 if (info->horizontal_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table))
2327 if (info->vertical_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table))
2330 if (alpha_channel < 0)
2334 STBIR_ASSERT(alpha_channel >= 0 && alpha_channel < info->channels);
2337 if (alpha_channel >= info->channels)
2340 STBIR_ASSERT(tempmem);
2345 STBIR_ASSERT(tempmem_size_in_bytes >= memory_required);
2347 if (tempmem_size_in_bytes < memory_required)
2350 memset(tempmem, 0, tempmem_size_in_bytes);
2352 info->input_data = input_data;
2353 info->input_stride_bytes = width_stride_input;
2355 info->output_data = output_data;
2356 info->output_stride_bytes = width_stride_output;
2358 info->alpha_channel = alpha_channel;
2359 info->flags = flags;
2361 info->edge_horizontal = edge_horizontal;
2362 info->edge_vertical = edge_vertical;
2363 info->colorspace = colorspace;
2365 info->horizontal_coefficient_width = stbir__get_coefficient_width (info->horizontal_filter, info->horizontal_scale);
2366 info->vertical_coefficient_width = stbir__get_coefficient_width (info->vertical_filter , info->vertical_scale );
2367 info->horizontal_filter_pixel_width = stbir__get_filter_pixel_width (info->horizontal_filter, info->horizontal_scale);
2368 info->vertical_filter_pixel_width = stbir__get_filter_pixel_width (info->vertical_filter , info->vertical_scale );
2369 info->horizontal_filter_pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale);
2370 info->vertical_filter_pixel_margin = stbir__get_filter_pixel_margin(info->vertical_filter , info->vertical_scale );
2372 info->ring_buffer_length_bytes = info->output_w * info->channels *
sizeof(float);
2373 info->decode_buffer_pixels = info->input_w + info->horizontal_filter_pixel_margin * 2;
2375#define STBIR__NEXT_MEMPTR(current, newtype) (newtype*)(((unsigned char*)current) + current##_size)
2377 info->horizontal_contributors = (stbir__contributors *) tempmem;
2378 info->horizontal_coefficients = STBIR__NEXT_MEMPTR(info->horizontal_contributors,
float);
2379 info->vertical_contributors = STBIR__NEXT_MEMPTR(info->horizontal_coefficients, stbir__contributors);
2380 info->vertical_coefficients = STBIR__NEXT_MEMPTR(info->vertical_contributors,
float);
2381 info->decode_buffer = STBIR__NEXT_MEMPTR(info->vertical_coefficients,
float);
2383 if (stbir__use_height_upsampling(info))
2385 info->horizontal_buffer =
NULL;
2386 info->ring_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer,
float);
2387 info->encode_buffer = STBIR__NEXT_MEMPTR(info->ring_buffer,
float);
2389 STBIR_ASSERT((
size_t)STBIR__NEXT_MEMPTR(info->encode_buffer,
unsigned char) == (
size_t)tempmem + tempmem_size_in_bytes);
2393 info->horizontal_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer,
float);
2394 info->ring_buffer = STBIR__NEXT_MEMPTR(info->horizontal_buffer,
float);
2395 info->encode_buffer =
NULL;
2397 STBIR_ASSERT((
size_t)STBIR__NEXT_MEMPTR(info->ring_buffer,
unsigned char) == (
size_t)tempmem + tempmem_size_in_bytes);
2400#undef STBIR__NEXT_MEMPTR
2403 info->ring_buffer_begin_index = -1;
2405 stbir__calculate_filters(info->horizontal_contributors, info->horizontal_coefficients, info->horizontal_filter, info->horizontal_scale, info->horizontal_shift, info->input_w, info->output_w);
2406 stbir__calculate_filters(info->vertical_contributors, info->vertical_coefficients, info->vertical_filter, info->vertical_scale, info->vertical_shift, info->input_h, info->output_h);
2408 STBIR_PROGRESS_REPORT(0);
2410 if (stbir__use_height_upsampling(info))
2411 stbir__buffer_loop_upsample(info);
2413 stbir__buffer_loop_downsample(info);
2415 STBIR_PROGRESS_REPORT(1);
2417#ifdef STBIR_DEBUG_OVERWRITE_TEST
2418 STBIR_ASSERT(memcmp(overwrite_output_before_pre, &((
unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0);
2419 STBIR_ASSERT(memcmp(overwrite_output_after_pre, &((
unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE) == 0);
2420 STBIR_ASSERT(memcmp(overwrite_tempmem_before_pre, &((
unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0);
2421 STBIR_ASSERT(memcmp(overwrite_tempmem_after_pre, &((
unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE) == 0);
2428static int stbir__resize_arbitrary(
2429 void *alloc_context,
2430 const void* input_data,
int input_w,
int input_h,
int input_stride_in_bytes,
2431 void* output_data,
int output_w,
int output_h,
int output_stride_in_bytes,
2432 float s0,
float t0,
float s1,
float t1,
float *transform,
2439 size_t memory_required;
2442 stbir__setup(&info, input_w, input_h, output_w, output_h, channels);
2443 stbir__calculate_transform(&info, s0,t0,s1,t1,transform);
2444 stbir__choose_filter(&info, h_filter, v_filter);
2445 memory_required = stbir__calculate_memory(&info);
2446 extra_memory =
STBIR_MALLOC(memory_required, alloc_context);
2451 result = stbir__resize_allocated(&info, input_data, input_stride_in_bytes,
2452 output_data, output_stride_in_bytes,
2453 alpha_channel, flags, type,
2454 edge_horizontal, edge_vertical,
2455 colorspace, extra_memory, memory_required);
2463 unsigned char *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
2466 return stbir__resize_arbitrary(
NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
2467 output_pixels, output_w, output_h, output_stride_in_bytes,
2468 0,0,1,1,
NULL,num_channels,-1,0,
STBIR_TYPE_UINT8,
STBIR_FILTER_DEFAULT,
STBIR_FILTER_DEFAULT,
2473 float *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
2476 return stbir__resize_arbitrary(
NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
2477 output_pixels, output_w, output_h, output_stride_in_bytes,
2478 0,0,1,1,
NULL,num_channels,-1,0,
STBIR_TYPE_FLOAT,
STBIR_FILTER_DEFAULT,
STBIR_FILTER_DEFAULT,
2483 unsigned char *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
2484 int num_channels,
int alpha_channel,
int flags)
2486 return stbir__resize_arbitrary(
NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
2487 output_pixels, output_w, output_h, output_stride_in_bytes,
2488 0,0,1,1,
NULL,num_channels,alpha_channel,flags,
STBIR_TYPE_UINT8,
STBIR_FILTER_DEFAULT,
STBIR_FILTER_DEFAULT,
2493 unsigned char *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
2494 int num_channels,
int alpha_channel,
int flags,
2497 return stbir__resize_arbitrary(
NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
2498 output_pixels, output_w, output_h, output_stride_in_bytes,
2499 0,0,1,1,
NULL,num_channels,alpha_channel,flags,
STBIR_TYPE_UINT8,
STBIR_FILTER_DEFAULT,
STBIR_FILTER_DEFAULT,
2504 unsigned char *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
2505 int num_channels,
int alpha_channel,
int flags,
2507 void *alloc_context)
2509 return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
2510 output_pixels, output_w, output_h, output_stride_in_bytes,
2511 0,0,1,1,
NULL,num_channels,alpha_channel,flags,
STBIR_TYPE_UINT8, filter, filter,
2512 edge_wrap_mode, edge_wrap_mode, space);
2516 stbir_uint16 *output_pixels ,
int output_w,
int output_h,
int output_stride_in_bytes,
2517 int num_channels,
int alpha_channel,
int flags,
2519 void *alloc_context)
2521 return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
2522 output_pixels, output_w, output_h, output_stride_in_bytes,
2523 0,0,1,1,
NULL,num_channels,alpha_channel,flags,
STBIR_TYPE_UINT16, filter, filter,
2524 edge_wrap_mode, edge_wrap_mode, space);
2529 float *output_pixels ,
int output_w,
int output_h,
int output_stride_in_bytes,
2530 int num_channels,
int alpha_channel,
int flags,
2532 void *alloc_context)
2534 return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
2535 output_pixels, output_w, output_h, output_stride_in_bytes,
2536 0,0,1,1,
NULL,num_channels,alpha_channel,flags,
STBIR_TYPE_FLOAT, filter, filter,
2537 edge_wrap_mode, edge_wrap_mode, space);
2541STBIRDEF int stbir_resize(
const void *input_pixels ,
int input_w ,
int input_h ,
int input_stride_in_bytes,
2542 void *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
2544 int num_channels,
int alpha_channel,
int flags,
2549 return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
2550 output_pixels, output_w, output_h, output_stride_in_bytes,
2551 0,0,1,1,
NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
2552 edge_mode_horizontal, edge_mode_vertical, space);
2557 void *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
2559 int num_channels,
int alpha_channel,
int flags,
2563 float x_scale,
float y_scale,
2564 float x_offset,
float y_offset)
2567 transform[0] = x_scale;
2568 transform[1] = y_scale;
2569 transform[2] = x_offset;
2570 transform[3] = y_offset;
2571 return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
2572 output_pixels, output_w, output_h, output_stride_in_bytes,
2573 0,0,1,1,transform,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
2574 edge_mode_horizontal, edge_mode_vertical, space);
2578 void *output_pixels,
int output_w,
int output_h,
int output_stride_in_bytes,
2580 int num_channels,
int alpha_channel,
int flags,
2584 float s0,
float t0,
float s1,
float t1)
2586 return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
2587 output_pixels, output_w, output_h, output_stride_in_bytes,
2588 s0,t0,s1,t1,
NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
2589 edge_mode_horizontal, edge_mode_vertical, space);
#define STBIR_FREE(ptr, c)
#define STBIR_MALLOC(size, c)
STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels, int input_w, int input_h, int input_stride_in_bytes, stbir_uint16 *output_pixels, int output_w, int output_h, int output_stride_in_bytes, int num_channels, int alpha_channel, int flags, stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, void *alloc_context)
STBIRDEF int stbir_resize_region(const void *input_pixels, int input_w, int input_h, int input_stride_in_bytes, void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, stbir_datatype datatype, int num_channels, int alpha_channel, int flags, stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, stbir_filter filter_horizontal, stbir_filter filter_vertical, stbir_colorspace space, void *alloc_context, float s0, float t0, float s1, float t1)
STBIRDEF int stbir_resize_float_generic(const float *input_pixels, int input_w, int input_h, int input_stride_in_bytes, float *output_pixels, int output_w, int output_h, int output_stride_in_bytes, int num_channels, int alpha_channel, int flags, stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, void *alloc_context)
STBIRDEF int stbir_resize_uint8(const unsigned char *input_pixels, int input_w, int input_h, int input_stride_in_bytes, unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, int num_channels)
STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels, int input_w, int input_h, int input_stride_in_bytes, unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, int num_channels, int alpha_channel, int flags, stbir_edge edge_wrap_mode)
@ STBIR_FILTER_CATMULLROM
@ STBIR_FILTER_CUBICBSPLINE
#define STBIR_FLAG_ALPHA_USES_COLORSPACE
STBIRDEF int stbir_resize_uint8_generic(const unsigned char *input_pixels, int input_w, int input_h, int input_stride_in_bytes, unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, int num_channels, int alpha_channel, int flags, stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space, void *alloc_context)
STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels, int input_w, int input_h, int input_stride_in_bytes, unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes, int num_channels, int alpha_channel, int flags)
STBIRDEF int stbir_resize(const void *input_pixels, int input_w, int input_h, int input_stride_in_bytes, void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, stbir_datatype datatype, int num_channels, int alpha_channel, int flags, stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, stbir_filter filter_horizontal, stbir_filter filter_vertical, stbir_colorspace space, void *alloc_context)
STBIRDEF int stbir_resize_subpixel(const void *input_pixels, int input_w, int input_h, int input_stride_in_bytes, void *output_pixels, int output_w, int output_h, int output_stride_in_bytes, stbir_datatype datatype, int num_channels, int alpha_channel, int flags, stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical, stbir_filter filter_horizontal, stbir_filter filter_vertical, stbir_colorspace space, void *alloc_context, float x_scale, float y_scale, float x_offset, float y_offset)
#define STBIR_FLAG_ALPHA_PREMULTIPLIED
STBIRDEF int stbir_resize_float(const float *input_pixels, int input_w, int input_h, int input_stride_in_bytes, float *output_pixels, int output_w, int output_h, int output_stride_in_bytes, int num_channels)
@ STBIR_COLORSPACE_LINEAR