@ -82,7 +82,7 @@
and 99 % opaque black produces 50 % transparent dark green when
non - premultiplied , whereas premultiplied it produces 50 %
transparent near - black . The former introduces green energy
that doesn ' t exist in the source . )
that doesn ' t exist in the source imag e . )
2. Artists should not edit premultiplied - alpha images ; artists
want non - premultiplied alpha images . Thus , art tools generally output
@ -247,10 +247,10 @@ STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels
typedef enum
{
STBIR_FILTER_DEFAULT = 0 , // use same filter type that easy-to-use API chooses
STBIR_FILTER_BOX = 1 , // Actually a trapezoid. See https://developer.nvidia.com/content/non-power-two-mipmapping
STBIR_FILTER_BOX = 1 , // A trapezoid w/1-pixel wide ramps, same result as box for integer scale ratios
STBIR_FILTER_TRIANGLE = 2 , // On upsampling, produces same results as bilinear texture filtering
STBIR_FILTER_CUBIC = 3 , // A cubic b-spline: why this one ????????????
STBIR_FILTER_CATMULLROM = 4 , // interpolating cubic spline
STBIR_FILTER_CUBICBSPLINE = 3 , // The cubic b-spline (aka Mitchell-Netrevalli with B=1,C=0), gaussian-esque
STBIR_FILTER_CATMULLROM = 4 , // An interpolating cubic spline
STBIR_FILTER_MITCHELL = 5 , // Mitchell-Netrevalli filter with B=1/3, C=1/3
} stbir_filter ;
@ -488,6 +488,16 @@ typedef struct
float * horizontal_buffer ;
// cache these because ceil/floor are inexplicably showing up in profile
int horizontal_coefficient_width ;
int vertical_coefficient_width ;
int horizontal_filter_pixel_width ;
int vertical_filter_pixel_width ;
int horizontal_filter_pixel_margin ;
int vertical_filter_pixel_margin ;
int horizontal_num_contributors ;
int vertical_num_contributors ;
int ring_buffer_length_bytes ; // The length of an individual entry in the ring buffer. The total number of ring buffers is stbir__get_filter_pixel_width(filter)
int ring_buffer_first_scanline ;
int ring_buffer_last_scanline ;
@ -555,6 +565,10 @@ static float stbir__srgb_uchar_to_linear_float[256] = {
} ;
// sRGB transition values, scaled by 1<<28
// note that if you only scaled by 1<<16, all the values would be 4K smaller,
// so [1] would be ~10, and so that would have around 5% error (10 +- 0.5)
// at the boundary between uint8 0 and 1. This also means that a 64K-entry table
// would have the same 5% error there.
static int stbir__srgb_offset_to_linear_scaled [ 256 ] =
{
0 , 40738 , 122216 , 203693 , 285170 , 366648 , 448125 , 529603 ,
@ -749,7 +763,7 @@ stbir__inline static int stbir__use_height_upsampling(stbir__info* stbir_info)
// This is the maximum number of input samples that can affect an output sample
// with the given filter
stbir__inline static int stbir__get_filter_pixel_width ( stbir_filter filter , float scale )
static int stbir__get_filter_pixel_width ( stbir_filter filter , float scale )
{
STBIR_ASSERT ( filter ! = 0 ) ;
STBIR_ASSERT ( filter < STBIR__ARRAY_SIZE ( stbir__filter_info_table ) ) ;
@ -760,34 +774,14 @@ stbir__inline static int stbir__get_filter_pixel_width(stbir_filter filter, floa
return ( int ) ceil ( stbir__filter_info_table [ filter ] . support ( scale ) * 2 / scale ) ;
}
stbir__inline static int stbir__get_filter_pixel_width_horizontal ( stbir__info * stbir_info )
{
return stbir__get_filter_pixel_width ( stbir_info - > horizontal_filter , stbir_info - > horizontal_scale ) ;
}
stbir__inline static int stbir__get_filter_pixel_width_vertical ( stbir__info * stbir_info )
{
return stbir__get_filter_pixel_width ( stbir_info - > vertical_filter , stbir_info - > vertical_scale ) ;
}
// This is how much to expand buffers to account for filters seeking outside
// the image boundaries.
stbir__inline static int stbir__get_filter_pixel_margin ( stbir_filter filter , float scale )
static int stbir__get_filter_pixel_margin ( stbir_filter filter , float scale )
{
return stbir__get_filter_pixel_width ( filter , scale ) / 2 ;
}
stbir__inline static int stbir__get_filter_pixel_margin_horizontal ( stbir__info * stbir_info )
{
return stbir__get_filter_pixel_width ( stbir_info - > horizontal_filter , stbir_info - > horizontal_scale ) / 2 ;
}
stbir__inline static int stbir__get_filter_pixel_margin_vertical ( stbir__info * stbir_info )
{
return stbir__get_filter_pixel_width ( stbir_info - > vertical_filter , stbir_info - > vertical_scale ) / 2 ;
}
stbir__inline static int stbir__get_coefficient_width ( stbir_filter filter , float scale )
static int stbir__get_coefficient_width ( stbir_filter filter , float scale )
{
if ( stbir__use_upsampling ( scale ) )
return ( int ) ceil ( stbir__filter_info_table [ filter ] . support ( 1 / scale ) * 2 ) ;
@ -795,7 +789,7 @@ stbir__inline static int stbir__get_coefficient_width(stbir_filter filter, float
return ( int ) ceil ( stbir__filter_info_table [ filter ] . support ( scale ) * 2 ) ;
}
stbir__inline static int stbir__get_contributors ( float scale , stbir_filter filter , int input_size , int output_size )
static int stbir__get_contributors ( float scale , stbir_filter filter , int input_size , int output_size )
{
if ( stbir__use_upsampling ( scale ) )
return output_size ;
@ -803,67 +797,31 @@ stbir__inline static int stbir__get_contributors(float scale, stbir_filter filte
return ( input_size + stbir__get_filter_pixel_margin ( filter , scale ) * 2 ) ;
}
stbir__inline static int stbir__get_horizontal_contributor s ( stbir__info * info )
static int stbir__get_total_horizontal_coefficient s ( stbir__info * info )
{
return stbir__get_contributors ( info - > horizontal_scale , info - > horizontal_filter , info - > input_w , info - > output_w ) ;
}
stbir__inline static int stbir__get_vertical_contributors ( stbir__info * info )
{
return stbir__get_contributors ( info - > vertical_scale , info - > vertical_filter , info - > input_h , info - > output_h ) ;
}
stbir__inline static int stbir__get_total_horizontal_coefficients ( stbir__info * info )
{
return stbir__get_horizontal_contributors ( info )
return info - > horizontal_num_contributors
* stbir__get_coefficient_width ( info - > horizontal_filter , info - > horizontal_scale ) ;
}
stbir__inline static int stbir__get_total_vertical_coefficients ( stbir__info * info )
static int stbir__get_total_vertical_coefficients ( stbir__info * info )
{
return stbir__get_vertical_contributors ( info )
return info - > vertical_num_contributors
* stbir__get_coefficient_width ( info - > vertical_filter , info - > vertical_scale ) ;
}
stbir__inline static stbir__contributors * stbir__get_contributor ( stbir__contributors * contributors , int n )
static stbir__contributors * stbir__get_contributor ( stbir__contributors * contributors , int n )
{
return & contributors [ n ] ;
}
stbir__inline static stbir__contributors * stbir__get_horizontal_contributor ( stbir__info * stbir_info , int n )
{
STBIR__DEBUG_ASSERT ( n > = 0 & & n < stbir__get_horizontal_contributors ( stbir_info ) ) ;
return stbir__get_contributor ( stbir_info - > horizontal_contributors , n ) ;
}
stbir__inline static stbir__contributors * stbir__get_vertical_contributor ( stbir__info * stbir_info , int n )
{
STBIR__DEBUG_ASSERT ( n > = 0 & & n < stbir__get_vertical_contributors ( stbir_info ) ) ;
return stbir__get_contributor ( stbir_info - > vertical_contributors , n ) ;
}
// For perf reasons this code is duplicated in stbir__resample_horizontal_upsample/downsample,
// if you change it here change it there too.
stbir__inline static float * stbir__get_coefficient ( float * coefficients , stbir_filter filter , float scale , int n , int c )
static float * stbir__get_coefficient ( float * coefficients , stbir_filter filter , float scale , int n , int c )
{
int width = stbir__get_coefficient_width ( filter , scale ) ;
return & coefficients [ width * n + c ] ;
}
stbir__inline static float * stbir__get_horizontal_coefficient ( stbir__info * stbir_info , int n , int c )
{
STBIR__DEBUG_ASSERT ( c > = 0 & & c < stbir__get_coefficient_width ( stbir_info - > horizontal_filter , stbir_info - > horizontal_scale ) ) ;
STBIR__DEBUG_ASSERT ( n > = 0 & & n < stbir__get_total_horizontal_coefficients ( stbir_info ) ) ;
return stbir__get_coefficient ( stbir_info - > horizontal_coefficients , stbir_info - > horizontal_filter , stbir_info - > horizontal_scale , n , c ) ;
}
stbir__inline static float * stbir__get_vertical_coefficient ( stbir__info * stbir_info , int n , int c )
{
STBIR__DEBUG_ASSERT ( c > = 0 & & c < stbir__get_coefficient_width ( stbir_info - > vertical_filter , stbir_info - > vertical_scale ) ) ;
STBIR__DEBUG_ASSERT ( n > = 0 & & n < stbir__get_total_vertical_coefficients ( stbir_info ) ) ;
return stbir__get_coefficient ( stbir_info - > vertical_coefficients , stbir_info - > vertical_filter , stbir_info - > vertical_scale , n , c ) ;
}
static int stbir__edge_wrap_slow ( stbir_edge edge , int n , int max )
{
switch ( edge )
@ -1081,7 +1039,7 @@ static void stbir__normalize_downsample_coefficients(stbir__info* stbir_info, st
// Do this after normalizing because normalization depends on the n0/n1 values.
for ( j = 0 ; j < num_contributors ; j + + )
{
int range , max ;
int range , max , width ;
skip = 0 ;
while ( * stbir__get_coefficient ( coefficients , filter , scale_ratio , j , skip ) = = 0 )
@ -1098,9 +1056,10 @@ static void stbir__normalize_downsample_coefficients(stbir__info* stbir_info, st
range = contributors [ j ] . n1 - contributors [ j ] . n0 + 1 ;
max = stbir__min ( num_coefficients , range ) ;
width = stbir__get_coefficient_width ( filter , scale_ratio ) ;
for ( i = 0 ; i < max ; i + + )
{
if ( i + skip > = stbir__get_coefficient_ width( filter , scale_ratio ) )
if ( i + skip > = width )
break ;
* stbir__get_coefficient ( coefficients , filter , scale_ratio , j , i ) = * stbir__get_coefficient ( coefficients , filter , scale_ratio , j , i + skip ) ;
@ -1160,7 +1119,7 @@ static float* stbir__get_decode_buffer(stbir__info* stbir_info)
{
// The 0 index of the decode buffer starts after the margin. This makes
// it okay to use negative indexes on the decode buffer.
return & stbir_info - > decode_buffer [ stbir__get_filter_pixel_margin_horizontal ( stbir_info ) * stbir_info - > channels ] ;
return & stbir_info - > decode_buffer [ stbir_info - > horizontal_filter_pixel_margin * stbir_info - > channels ] ;
}
# define STBIR__DECODE(type, colorspace) ((type) * (STBIR_MAX_COLORSPACES) + (colorspace))
@ -1179,10 +1138,10 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
stbir_edge edge_vertical = stbir_info - > edge_vertical ;
int in_buffer_row_offset = stbir__edge_wrap ( edge_vertical , n , stbir_info - > input_h ) * input_stride_bytes ;
const void * input_data = ( char * ) stbir_info - > input_data + in_buffer_row_offset ;
int max_x = input_w + stbir__get_filter_pixel_margin_horizontal ( stbir_info ) ;
int max_x = input_w + stbir_info - > horizontal_filter_pixel_margin ;
int decode = STBIR__DECODE ( type , colorspace ) ;
int x = - stbir__get_filter_pixel_margin_horizontal ( stbir_info ) ;
int x = - stbir_info - > horizontal_filter_pixel_margin ;
// special handling for STBIR_EDGE_ZERO because it needs to return an item that doesn't appear in the input,
// and we want to avoid paying overhead on every pixel if not STBIR_EDGE_ZERO
@ -1296,7 +1255,7 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
if ( ! ( stbir_info - > flags & STBIR_FLAG_ALPHA_PREMULTIPLIED ) )
{
for ( x = - stbir__get_filter_pixel_margin_horizontal ( stbir_info ) ; x < max_x ; x + + )
for ( x = - stbir_info - > horizontal_filter_pixel_margin ; x < max_x ; x + + )
{
int decode_pixel_index = x * channels ;
@ -1320,7 +1279,7 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
if ( edge_horizontal = = STBIR_EDGE_ZERO )
{
for ( x = - stbir__get_filter_pixel_margin_horizontal ( stbir_info ) ; x < 0 ; x + + )
for ( x = - stbir_info - > horizontal_filter_pixel_margin ; x < 0 ; x + + )
{
for ( c = 0 ; c < channels ; c + + )
decode_buffer [ x * channels + c ] = 0 ;
@ -1350,7 +1309,7 @@ static float* stbir__add_empty_ring_buffer_entry(stbir__info* stbir_info, int n)
}
else
{
ring_buffer_index = ( stbir_info - > ring_buffer_begin_index + ( stbir_info - > ring_buffer_last_scanline - stbir_info - > ring_buffer_first_scanline ) + 1 ) % stbir__get_filter_pixel_width_vertical ( stbir_info ) ;
ring_buffer_index = ( stbir_info - > ring_buffer_begin_index + ( stbir_info - > ring_buffer_last_scanline - stbir_info - > ring_buffer_first_scanline ) + 1 ) % stbir_info - > vertical_filter_pixel_width ;
STBIR__DEBUG_ASSERT ( ring_buffer_index ! = stbir_info - > ring_buffer_begin_index ) ;
}
@ -1367,12 +1326,12 @@ static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, int n,
{
int x , k ;
int output_w = stbir_info - > output_w ;
int kernel_pixel_width = stbir__get_filter_pixel_width_horizontal ( stbir_info ) ;
int kernel_pixel_width = stbir_info - > horizontal_filter_pixel_width ;
int channels = stbir_info - > channels ;
float * decode_buffer = stbir__get_decode_buffer ( stbir_info ) ;
stbir__contributors * horizontal_contributors = stbir_info - > horizontal_contributors ;
float * horizontal_coefficients = stbir_info - > horizontal_coefficients ;
int coefficient_width = stbir__get_coefficient_width ( stbir_ info - > horizontal_filter , stbir_info - > horizontal_scale ) ;
int coefficient_width = stbir_info - > horizontal_coefficient_width ;
for ( x = 0 ; x < output_w ; x + + )
{
@ -1384,22 +1343,66 @@ static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, int n,
int coefficient_counter = 0 ;
STBIR__DEBUG_ASSERT ( n1 > = n0 ) ;
STBIR__DEBUG_ASSERT ( n0 > = - stbir__get_filter_pixel_margin_horizontal ( stbir_info ) ) ;
STBIR__DEBUG_ASSERT ( n1 > = - stbir__get_filter_pixel_margin_horizontal ( stbir_info ) ) ;
STBIR__DEBUG_ASSERT ( n0 < stbir_info - > input_w + stbir__get_filter_pixel_margin_horizontal ( stbir_info ) ) ;
STBIR__DEBUG_ASSERT ( n1 < stbir_info - > input_w + stbir__get_filter_pixel_margin_horizontal ( stbir_info ) ) ;
STBIR__DEBUG_ASSERT ( n0 > = - stbir_info - > horizontal_filter_pixel_margin ) ;
STBIR__DEBUG_ASSERT ( n1 > = - stbir_info - > horizontal_filter_pixel_margin ) ;
STBIR__DEBUG_ASSERT ( n0 < stbir_info - > input_w + stbir_info - > horizontal_filter_pixel_margin ) ;
STBIR__DEBUG_ASSERT ( n1 < stbir_info - > input_w + stbir_info - > horizontal_filter_pixel_margin ) ;
switch ( channels ) {
case 1 :
for ( k = n0 ; k < = n1 ; k + + )
{
int in_pixel_index = k * channels ;
int in_pixel_index = k * 1 ;
float coefficient = horizontal_coefficients [ coefficient_group + coefficient_counter + + ] ;
STBIR__DEBUG_ASSERT ( coefficient ! = 0 ) ;
output_buffer [ out_pixel_index + 0 ] + = decode_buffer [ in_pixel_index + 0 ] * coefficient ;
}
break ;
case 2 :
for ( k = n0 ; k < = n1 ; k + + )
{
int in_pixel_index = k * 2 ;
float coefficient = horizontal_coefficients [ coefficient_group + coefficient_counter + + ] ;
STBIR__DEBUG_ASSERT ( coefficient ! = 0 ) ;
output_buffer [ out_pixel_index + 0 ] + = decode_buffer [ in_pixel_index + 0 ] * coefficient ;
output_buffer [ out_pixel_index + 1 ] + = decode_buffer [ in_pixel_index + 1 ] * coefficient ;
}
break ;
case 3 :
for ( k = n0 ; k < = n1 ; k + + )
{
int in_pixel_index = k * 3 ;
float coefficient = horizontal_coefficients [ coefficient_group + coefficient_counter + + ] ;
STBIR__DEBUG_ASSERT ( coefficient ! = 0 ) ;
output_buffer [ out_pixel_index + 0 ] + = decode_buffer [ in_pixel_index + 0 ] * coefficient ;
output_buffer [ out_pixel_index + 1 ] + = decode_buffer [ in_pixel_index + 1 ] * coefficient ;
output_buffer [ out_pixel_index + 2 ] + = decode_buffer [ in_pixel_index + 2 ] * coefficient ;
}
break ;
case 4 :
for ( k = n0 ; k < = n1 ; k + + )
{
int in_pixel_index = k * 4 ;
float coefficient = horizontal_coefficients [ coefficient_group + coefficient_counter + + ] ;
STBIR__DEBUG_ASSERT ( coefficient ! = 0 ) ;
output_buffer [ out_pixel_index + 0 ] + = decode_buffer [ in_pixel_index + 0 ] * coefficient ;
output_buffer [ out_pixel_index + 1 ] + = decode_buffer [ in_pixel_index + 1 ] * coefficient ;
output_buffer [ out_pixel_index + 2 ] + = decode_buffer [ in_pixel_index + 2 ] * coefficient ;
output_buffer [ out_pixel_index + 3 ] + = decode_buffer [ in_pixel_index + 3 ] * coefficient ;
}
break ;
default :
for ( k = n0 ; k < = n1 ; k + + )
{
int in_pixel_index = k * channels ;
float coefficient = horizontal_coefficients [ coefficient_group + coefficient_counter + + ] ;
int c ;
STBIR__DEBUG_ASSERT ( coefficient ! = 0 ) ;
for ( c = 0 ; c < channels ; c + + )
output_buffer [ out_pixel_index + c ] + = decode_buffer [ in_pixel_index + c ] * coefficient ;
}
break ;
}
}
}
@ -1408,39 +1411,131 @@ static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, int n
int x , k ;
int input_w = stbir_info - > input_w ;
int output_w = stbir_info - > output_w ;
int kernel_pixel_width = stbir__get_filter_pixel_width_horizontal ( stbir_info ) ;
int kernel_pixel_width = stbir_info - > horizontal_filter_pixel_width ;
int channels = stbir_info - > channels ;
float * decode_buffer = stbir__get_decode_buffer ( stbir_info ) ;
stbir__contributors * horizontal_contributors = stbir_info - > horizontal_contributors ;
float * horizontal_coefficients = stbir_info - > horizontal_coefficients ;
int coefficient_width = stbir__get_coefficient_width ( stbir_ info - > horizontal_filter , stbir_info - > horizontal_scale ) ;
int filter_pixel_margin = stbir__get_filter_pixel_margin_horizontal ( stbir_info ) ;
int coefficient_width = stbir_info - > horizontal_coefficient_width ;
int filter_pixel_margin = stbir_info - > horizontal_filter_pixel_margin ;
int max_x = input_w + filter_pixel_margin * 2 ;
STBIR__DEBUG_ASSERT ( ! stbir__use_width_upsampling ( stbir_info ) ) ;
switch ( channels ) {
case 1 :
for ( x = 0 ; x < max_x ; x + + )
{
int n0 = horizontal_contributors [ x ] . n0 ;
int n1 = horizontal_contributors [ x ] . n1 ;
int in_x = x - filter_pixel_margin ;
int in_pixel_index = in_x * channels ;
int in_pixel_index = in_x * 1 ;
int max_n = n1 ;
int coefficient_group = coefficient_width * x ;
for ( k = n0 ; k < = max_n ; k + + )
{
int out_pixel_index = k * channels ;
int out_pixel_index = k * 1 ;
float coefficient = horizontal_coefficients [ coefficient_group + k - n0 ] ;
STBIR__DEBUG_ASSERT ( coefficient ! = 0 ) ;
output_buffer [ out_pixel_index + 0 ] + = decode_buffer [ in_pixel_index + 0 ] * coefficient ;
}
}
break ;
case 2 :
for ( x = 0 ; x < max_x ; x + + )
{
int n0 = horizontal_contributors [ x ] . n0 ;
int n1 = horizontal_contributors [ x ] . n1 ;
int in_x = x - filter_pixel_margin ;
int in_pixel_index = in_x * 2 ;
int max_n = n1 ;
int coefficient_group = coefficient_width * x ;
for ( k = n0 ; k < = max_n ; k + + )
{
int out_pixel_index = k * 2 ;
float coefficient = horizontal_coefficients [ coefficient_group + k - n0 ] ;
STBIR__DEBUG_ASSERT ( coefficient ! = 0 ) ;
output_buffer [ out_pixel_index + 0 ] + = decode_buffer [ in_pixel_index + 0 ] * coefficient ;
output_buffer [ out_pixel_index + 1 ] + = decode_buffer [ in_pixel_index + 1 ] * coefficient ;
}
}
break ;
case 3 :
for ( x = 0 ; x < max_x ; x + + )
{
int n0 = horizontal_contributors [ x ] . n0 ;
int n1 = horizontal_contributors [ x ] . n1 ;
int in_x = x - filter_pixel_margin ;
int in_pixel_index = in_x * 3 ;
int max_n = n1 ;
int coefficient_group = coefficient_width * x ;
for ( k = n0 ; k < = max_n ; k + + )
{
int out_pixel_index = k * 3 ;
float coefficient = horizontal_coefficients [ coefficient_group + k - n0 ] ;
STBIR__DEBUG_ASSERT ( coefficient ! = 0 ) ;
output_buffer [ out_pixel_index + 0 ] + = decode_buffer [ in_pixel_index + 0 ] * coefficient ;
output_buffer [ out_pixel_index + 1 ] + = decode_buffer [ in_pixel_index + 1 ] * coefficient ;
output_buffer [ out_pixel_index + 2 ] + = decode_buffer [ in_pixel_index + 2 ] * coefficient ;
}
}
break ;
case 4 :
for ( x = 0 ; x < max_x ; x + + )
{
int n0 = horizontal_contributors [ x ] . n0 ;
int n1 = horizontal_contributors [ x ] . n1 ;
int in_x = x - filter_pixel_margin ;
int in_pixel_index = in_x * 4 ;
int max_n = n1 ;
int coefficient_group = coefficient_width * x ;
for ( k = n0 ; k < = max_n ; k + + )
{
int out_pixel_index = k * 4 ;
float coefficient = horizontal_coefficients [ coefficient_group + k - n0 ] ;
STBIR__DEBUG_ASSERT ( coefficient ! = 0 ) ;
output_buffer [ out_pixel_index + 0 ] + = decode_buffer [ in_pixel_index + 0 ] * coefficient ;
output_buffer [ out_pixel_index + 1 ] + = decode_buffer [ in_pixel_index + 1 ] * coefficient ;
output_buffer [ out_pixel_index + 2 ] + = decode_buffer [ in_pixel_index + 2 ] * coefficient ;
output_buffer [ out_pixel_index + 3 ] + = decode_buffer [ in_pixel_index + 3 ] * coefficient ;
}
}
break ;
default :
for ( x = 0 ; x < max_x ; x + + )
{
int n0 = horizontal_contributors [ x ] . n0 ;
int n1 = horizontal_contributors [ x ] . n1 ;
int in_x = x - filter_pixel_margin ;
int in_pixel_index = in_x * channels ;
int max_n = n1 ;
int coefficient_group = coefficient_width * x ;
for ( k = n0 ; k < = max_n ; k + + )
{
int c ;
int out_pixel_index = k * channels ;
float coefficient = horizontal_coefficients [ coefficient_group + k - n0 ] ;
STBIR__DEBUG_ASSERT ( coefficient ! = 0 ) ;
for ( c = 0 ; c < channels ; c + + )
output_buffer [ out_pixel_index + c ] + = decode_buffer [ in_pixel_index + c ] * coefficient ;
}
}
break ;
}
}
static void stbir__decode_and_resample_upsample ( stbir__info * stbir_info , int n )
@ -1504,6 +1599,8 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
}
}
# define STBIR__ROUND_INT(f) ((int) ((f)+0.5)) //#define STBIR__ROUND_INT(f) (floor((f)+0.5))
switch ( decode )
{
case STBIR__DECODE ( STBIR_TYPE_UINT8 , STBIR_COLORSPACE_LINEAR ) :
@ -1514,7 +1611,7 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
for ( n = 0 ; n < channels ; n + + )
{
int index = pixel_index + n ;
( ( unsigned char * ) output_buffer ) [ index ] = ( unsigned char ) ( floor ( stbir__saturate ( encode_buffer [ index ] ) * 255 + 0.5f ) ) ;
( ( unsigned char * ) output_buffer ) [ index ] = ( unsigned char ) STBIR__ROUND_INT ( stbir__saturate ( encode_buffer [ index ] ) * 255 ) ;
}
}
break ;
@ -1531,7 +1628,7 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
}
if ( ! ( stbir_info - > flags & STBIR_FLAG_ALPHA_USES_COLORSPACE ) )
( ( unsigned char * ) output_buffer ) [ pixel_index + alpha_channel ] = ( unsigned char ) ( floor ( stbir__saturate ( encode_buffer [ pixel_index + alpha_channel ] ) * 255 + 0.5f ) ) ;
( ( unsigned char * ) output_buffer ) [ pixel_index + alpha_channel ] = ( unsigned char ) STBIR__ROUND_INT ( stbir__saturate ( encode_buffer [ pixel_index + alpha_channel ] ) * 255 ) ;
}
break ;
@ -1543,7 +1640,7 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
for ( n = 0 ; n < channels ; n + + )
{
int index = pixel_index + n ;
( ( unsigned short * ) output_buffer ) [ index ] = ( unsigned short ) ( floor ( stbir__saturate ( encode_buffer [ index ] ) * 65535 + 0.5f ) ) ;
( ( unsigned short * ) output_buffer ) [ index ] = ( unsigned short ) STBIR__ROUND_INT ( stbir__saturate ( encode_buffer [ index ] ) * 65535 ) ;
}
}
break ;
@ -1556,11 +1653,11 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
for ( n = 0 ; n < channels ; n + + )
{
int index = pixel_index + n ;
( ( unsigned short * ) output_buffer ) [ index ] = ( unsigned short ) ( floor ( stbir__linear_to_srgb ( stbir__saturate ( encode_buffer [ index ] ) ) * 65535 + 0.5f ) ) ;
( ( unsigned short * ) output_buffer ) [ index ] = ( unsigned short ) STBIR__ROUND_INT ( stbir__linear_to_srgb ( stbir__saturate ( encode_buffer [ index ] ) ) * 65535 ) ;
}
if ( ! ( stbir_info - > flags & STBIR_FLAG_ALPHA_USES_COLORSPACE ) )
( ( unsigned short * ) output_buffer ) [ pixel_index + alpha_channel ] = ( unsigned short ) ( floor ( stbir__saturate ( encode_buffer [ pixel_index + alpha_channel ] ) * 65535 + 0.5f ) ) ;
( ( unsigned short * ) output_buffer ) [ pixel_index + alpha_channel ] = ( unsigned short ) STBIR__ROUND_INT ( stbir__saturate ( encode_buffer [ pixel_index + alpha_channel ] ) * 65535 ) ;
}
break ;
@ -1573,7 +1670,7 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
for ( n = 0 ; n < channels ; n + + )
{
int index = pixel_index + n ;
( ( unsigned int * ) output_buffer ) [ index ] = ( unsigned int ) ( floor ( ( ( double ) stbir__saturate ( encode_buffer [ index ] ) ) * 4294967295 + 0.5f ) ) ;
( ( unsigned int * ) output_buffer ) [ index ] = ( unsigned int ) STBIR__ROUND_INT ( ( ( double ) stbir__saturate ( encode_buffer [ index ] ) ) * 4294967295 ) ;
}
}
break ;
@ -1586,11 +1683,11 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
for ( n = 0 ; n < channels ; n + + )
{
int index = pixel_index + n ;
( ( unsigned int * ) output_buffer ) [ index ] = ( unsigned int ) ( floor ( ( ( double ) stbir__linear_to_srgb ( stbir__saturate ( encode_buffer [ index ] ) ) ) * 4294967295 + 0.5f ) ) ;
( ( unsigned int * ) output_buffer ) [ index ] = ( unsigned int ) STBIR__ROUND_INT ( ( ( double ) stbir__linear_to_srgb ( stbir__saturate ( encode_buffer [ index ] ) ) ) * 4294967295 ) ;
}
if ( ! ( stbir_info - > flags & STBIR_FLAG_ALPHA_USES_COLORSPACE ) )
( ( unsigned int * ) output_buffer ) [ pixel_index + alpha_channel ] = ( unsigned int ) ( floor ( ( ( double ) stbir__saturate ( encode_buffer [ pixel_index + alpha_channel ] ) ) * 4294967295 + 0.5f ) ) ;
( ( unsigned int * ) output_buffer ) [ pixel_index + alpha_channel ] = ( unsigned int ) STBIR__ROUND_INT ( ( ( double ) stbir__saturate ( encode_buffer [ pixel_index + alpha_channel ] ) ) * 4294967295 ) ;
}
break ;
@ -1639,11 +1736,12 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
int alpha_channel = stbir_info - > alpha_channel ;
int type = stbir_info - > type ;
int colorspace = stbir_info - > colorspace ;
int kernel_pixel_width = stbir__get_filter_pixel_width_vertical ( stbir_info ) ;
int kernel_pixel_width = stbir_info - > vertical_filter_pixel_width ;
void * output_data = stbir_info - > output_data ;
float * encode_buffer = stbir_info - > encode_buffer ;
int decode = STBIR__DECODE ( type , colorspace ) ;
int coefficient_width = stbir__get_coefficient_width ( stbir_info - > vertical_filter , stbir_info - > vertical_scale ) ;
int coefficient_width = stbir_info - > vertical_coefficient_width ;
int coefficient_counter ;
int contributor = n ;
float * ring_buffer = stbir_info - > ring_buffer ;
@ -1664,22 +1762,82 @@ static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n, in
memset ( encode_buffer , 0 , output_w * sizeof ( float ) * channels ) ;
coefficient_counter = 0 ;
switch ( channels ) {
case 1 :
for ( k = n0 ; k < = n1 ; k + + )
{
int coefficient_index = coefficient_counter + + ;
float * ring_buffer_entry = stbir__get_ring_buffer_scanline ( k , ring_buffer , ring_buffer_begin_index , ring_buffer_first_scanline , kernel_pixel_width , ring_buffer_length ) ;
float coefficient = vertical_coefficients [ coefficient_group + coefficient_index ] ;
for ( x = 0 ; x < output_w ; x + + )
{
int in_pixel_index = x * channels ;
int coefficient_counter = 0 ;
encode_buffer [ in_pixel_index + 0 ] + = ring_buffer_entry [ in_pixel_index + 0 ] * coefficient ;
}
}
break ;
case 2 :
for ( k = n0 ; k < = n1 ; k + + )
{
int coefficient_index = coefficient_counter + + ;
float * ring_buffer_entry = stbir__get_ring_buffer_scanline ( k , ring_buffer , ring_buffer_begin_index , ring_buffer_first_scanline , kernel_pixel_width , ring_buffer_length ) ;
float coefficient = vertical_coefficients [ coefficient_group + coefficient_index ] ;
for ( x = 0 ; x < output_w ; x + + )
{
int in_pixel_index = x * channels ;
encode_buffer [ in_pixel_index + 0 ] + = ring_buffer_entry [ in_pixel_index + 0 ] * coefficient ;
encode_buffer [ in_pixel_index + 1 ] + = ring_buffer_entry [ in_pixel_index + 1 ] * coefficient ;
}
}
break ;
case 3 :
for ( k = n0 ; k < = n1 ; k + + )
{
int coefficient_index = coefficient_counter + + ;
float * ring_buffer_entry = stbir__get_ring_buffer_scanline ( k , ring_buffer , ring_buffer_begin_index , ring_buffer_first_scanline , kernel_pixel_width , ring_buffer_length ) ;
float coefficient = vertical_coefficients [ coefficient_group + coefficient_index ] ;
for ( x = 0 ; x < output_w ; x + + )
{
int in_pixel_index = x * channels ;
encode_buffer [ in_pixel_index + 0 ] + = ring_buffer_entry [ in_pixel_index + 0 ] * coefficient ;
encode_buffer [ in_pixel_index + 1 ] + = ring_buffer_entry [ in_pixel_index + 1 ] * coefficient ;
encode_buffer [ in_pixel_index + 2 ] + = ring_buffer_entry [ in_pixel_index + 2 ] * coefficient ;
}
}
break ;
case 4 :
for ( k = n0 ; k < = n1 ; k + + )
{
int coefficient_index = coefficient_counter + + ;
float * ring_buffer_entry = stbir__get_ring_buffer_scanline ( k , ring_buffer , ring_buffer_begin_index , ring_buffer_first_scanline , kernel_pixel_width , ring_buffer_length ) ;
float coefficient = vertical_coefficients [ coefficient_group + coefficient_index ] ;
for ( x = 0 ; x < output_w ; x + + )
{
int in_pixel_index = x * channels ;
encode_buffer [ in_pixel_index + 0 ] + = ring_buffer_entry [ in_pixel_index + 0 ] * coefficient ;
encode_buffer [ in_pixel_index + 1 ] + = ring_buffer_entry [ in_pixel_index + 1 ] * coefficient ;
encode_buffer [ in_pixel_index + 2 ] + = ring_buffer_entry [ in_pixel_index + 2 ] * coefficient ;
encode_buffer [ in_pixel_index + 3 ] + = ring_buffer_entry [ in_pixel_index + 3 ] * coefficient ;
}
}
break ;
default :
for ( k = n0 ; k < = n1 ; k + + )
{
int coefficient_index = coefficient_counter + + ;
float * ring_buffer_entry = stbir__get_ring_buffer_scanline ( k , ring_buffer , ring_buffer_begin_index , ring_buffer_first_scanline , kernel_pixel_width , ring_buffer_length ) ;
float coefficient = vertical_coefficients [ coefficient_group + coefficient_index ] ;
for ( x = 0 ; x < output_w ; x + + )
{
int in_pixel_index = x * channels ;
int c ;
for ( c = 0 ; c < channels ; c + + )
encode_buffer [ in_pixel_index + c ] + = ring_buffer_entry [ in_pixel_index + c ] * coefficient ;
}
}
break ;
}
stbir__encode_scanline ( stbir_info , output_w , ( char * ) output_data + output_row_start , encode_buffer , channels , alpha_channel , decode ) ;
}
@ -1691,11 +1849,11 @@ static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n,
stbir__contributors * vertical_contributors = stbir_info - > vertical_contributors ;
float * vertical_coefficients = stbir_info - > vertical_coefficients ;
int channels = stbir_info - > channels ;
int kernel_pixel_width = stbir__get_filter_pixel_width_vertical ( stbir_info ) ;
int kernel_pixel_width = stbir_info - > vertical_filter_pixel_width ;
void * output_data = stbir_info - > output_data ;
float * horizontal_buffer = stbir_info - > horizontal_buffer ;
int coefficient_width = stbir__get_coefficient_width ( stbir_ info - > vertical_filter , stbir_info - > vertical_scale ) ;
int contributor = n + stbir__get_filter_pixel_margin_vertical ( stbir_info ) ;
int coefficient_width = stbir_info - > vertical_coefficient_width ;
int contributor = n + stbir_info - > vertical_filter_pixel_margin ;
float * ring_buffer = stbir_info - > ring_buffer ;
int ring_buffer_begin_index = stbir_info - > ring_buffer_begin_index ;
@ -1717,6 +1875,42 @@ static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n,
float * ring_buffer_entry = stbir__get_ring_buffer_scanline ( k , ring_buffer , ring_buffer_begin_index , ring_buffer_first_scanline , kernel_pixel_width , ring_buffer_length ) ;
switch ( channels ) {
case 1 :
for ( x = 0 ; x < output_w ; x + + )
{
int in_pixel_index = x * 1 ;
ring_buffer_entry [ in_pixel_index + 0 ] + = horizontal_buffer [ in_pixel_index + 0 ] * coefficient ;
}
break ;
case 2 :
for ( x = 0 ; x < output_w ; x + + )
{
int in_pixel_index = x * 2 ;
ring_buffer_entry [ in_pixel_index + 0 ] + = horizontal_buffer [ in_pixel_index + 0 ] * coefficient ;
ring_buffer_entry [ in_pixel_index + 1 ] + = horizontal_buffer [ in_pixel_index + 1 ] * coefficient ;
}
break ;
case 3 :
for ( x = 0 ; x < output_w ; x + + )
{
int in_pixel_index = x * 3 ;
ring_buffer_entry [ in_pixel_index + 0 ] + = horizontal_buffer [ in_pixel_index + 0 ] * coefficient ;
ring_buffer_entry [ in_pixel_index + 1 ] + = horizontal_buffer [ in_pixel_index + 1 ] * coefficient ;
ring_buffer_entry [ in_pixel_index + 2 ] + = horizontal_buffer [ in_pixel_index + 2 ] * coefficient ;
}
break ;
case 4 :
for ( x = 0 ; x < output_w ; x + + )
{
int in_pixel_index = x * 4 ;
ring_buffer_entry [ in_pixel_index + 0 ] + = horizontal_buffer [ in_pixel_index + 0 ] * coefficient ;
ring_buffer_entry [ in_pixel_index + 1 ] + = horizontal_buffer [ in_pixel_index + 1 ] * coefficient ;
ring_buffer_entry [ in_pixel_index + 2 ] + = horizontal_buffer [ in_pixel_index + 2 ] * coefficient ;
ring_buffer_entry [ in_pixel_index + 3 ] + = horizontal_buffer [ in_pixel_index + 3 ] * coefficient ;
}
break ;
default :
for ( x = 0 ; x < output_w ; x + + )
{
int in_pixel_index = x * channels ;
@ -1725,6 +1919,8 @@ static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n,
for ( c = 0 ; c < channels ; c + + )
ring_buffer_entry [ in_pixel_index + c ] + = horizontal_buffer [ in_pixel_index + c ] * coefficient ;
}
break ;
}
}
}
@ -1743,7 +1939,7 @@ static void stbir__buffer_loop_upsample(stbir__info* stbir_info)
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 ) ;
STBIR__DEBUG_ASSERT ( in_last_scanline - in_first_scanline < = stbir__get_filter_pixel_width_vertical ( stbir_info ) ) ;
STBIR__DEBUG_ASSERT ( in_last_scanline - in_first_scanline < = stbir_info - > vertical_filter_pixel_width ) ;
if ( stbir_info - > ring_buffer_begin_index > = 0 )
{
@ -1762,7 +1958,7 @@ static void stbir__buffer_loop_upsample(stbir__info* stbir_info)
else
{
stbir_info - > ring_buffer_first_scanline + + ;
stbir_info - > ring_buffer_begin_index = ( stbir_info - > ring_buffer_begin_index + 1 ) % stbir__get_filter_pixel_width_vertical ( stbir_info ) ;
stbir_info - > ring_buffer_begin_index = ( stbir_info - > ring_buffer_begin_index + 1 ) % stbir_info - > vertical_filter_pixel_width ;
}
}
}
@ -1820,7 +2016,7 @@ static void stbir__empty_ring_buffer(stbir__info* stbir_info, int first_necessar
else
{
stbir_info - > ring_buffer_first_scanline + + ;
stbir_info - > ring_buffer_begin_index = ( stbir_info - > ring_buffer_begin_index + 1 ) % stbir__get_filter_pixel_width_vertical ( stbir_info ) ;
stbir_info - > ring_buffer_begin_index = ( stbir_info - > ring_buffer_begin_index + 1 ) % stbir_info - > vertical_filter_pixel_width ;
}
}
}
@ -1832,7 +2028,7 @@ static void stbir__buffer_loop_downsample(stbir__info* stbir_info)
float scale_ratio = stbir_info - > vertical_scale ;
int output_h = stbir_info - > output_h ;
float in_pixels_radius = stbir__filter_info_table [ stbir_info - > vertical_filter ] . support ( scale_ratio ) / scale_ratio ;
int pixel_margin = stbir__get_filter_pixel_margin_vertical ( stbir_info ) ;
int pixel_margin = stbir_info - > vertical_filter_pixel_margin ;
int max_y = stbir_info - > input_h + pixel_margin ;
STBIR__DEBUG_ASSERT ( ! stbir__use_height_upsampling ( stbir_info ) ) ;
@ -1844,7 +2040,7 @@ static void stbir__buffer_loop_downsample(stbir__info* stbir_info)
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 ) ;
STBIR__DEBUG_ASSERT ( out_last_scanline - out_first_scanline < = stbir__get_filter_pixel_width_vertical ( stbir_info ) ) ;
STBIR__DEBUG_ASSERT ( out_last_scanline - out_first_scanline < = stbir_info - > vertical_filter_pixel_width ) ;
if ( out_last_scanline < 0 | | out_first_scanline > = output_h )
continue ;
@ -1915,9 +2111,12 @@ static stbir_uint32 stbir__calculate_memory(stbir__info *info)
int pixel_margin = stbir__get_filter_pixel_margin ( info - > horizontal_filter , info - > horizontal_scale ) ;
int filter_height = stbir__get_filter_pixel_width ( info - > vertical_filter , info - > vertical_scale ) ;
info - > horizontal_contributors_size = stbir__get_horizontal_contributors ( info ) * sizeof ( stbir__contributors ) ;
info - > horizontal_num_contributors = stbir__get_contributors ( info - > horizontal_scale , info - > horizontal_filter , info - > input_w , info - > output_w ) ;
info - > vertical_num_contributors = stbir__get_contributors ( info - > vertical_scale , info - > vertical_filter , info - > input_h , info - > output_h ) ;
info - > horizontal_contributors_size = info - > horizontal_num_contributors * sizeof ( stbir__contributors ) ;
info - > horizontal_coefficients_size = stbir__get_total_horizontal_coefficients ( info ) * sizeof ( float ) ;
info - > vertical_contributors_size = stbir__get_vertical_contributors ( info ) * sizeof ( stbir__contributors ) ;
info - > vertical_contributors_size = info - > vertical_num_contributors * sizeof ( stbir__contributors ) ;
info - > vertical_coefficients_size = stbir__get_total_vertical_coefficients ( info ) * sizeof ( float ) ;
info - > decode_buffer_size = ( info - > input_w + pixel_margin * 2 ) * info - > channels * sizeof ( float ) ;
info - > horizontal_buffer_size = info - > output_w * info - > channels * sizeof ( float ) ;
@ -2018,8 +2217,15 @@ static int stbir__resize_allocated(stbir__info *info,
info - > edge_vertical = edge_vertical ;
info - > colorspace = colorspace ;
info - > horizontal_coefficient_width = stbir__get_coefficient_width ( info - > horizontal_filter , info - > horizontal_scale ) ;
info - > vertical_coefficient_width = stbir__get_coefficient_width ( info - > vertical_filter , info - > vertical_scale ) ;
info - > horizontal_filter_pixel_width = stbir__get_filter_pixel_width ( info - > horizontal_filter , info - > horizontal_scale ) ;
info - > vertical_filter_pixel_width = stbir__get_filter_pixel_width ( info - > vertical_filter , info - > vertical_scale ) ;
info - > horizontal_filter_pixel_margin = stbir__get_filter_pixel_margin ( info - > horizontal_filter , info - > horizontal_scale ) ;
info - > vertical_filter_pixel_margin = stbir__get_filter_pixel_margin ( info - > vertical_filter , info - > vertical_scale ) ;
info - > ring_buffer_length_bytes = info - > output_w * info - > channels * sizeof ( float ) ;
info - > decode_buffer_pixels = info - > input_w + stbir__get_filter_pixel_margin_horizontal ( info ) * 2 ;
info - > decode_buffer_pixels = info - > input_w + info - > horizontal_filter_pixel_margin * 2 ;
# define STBIR__NEXT_MEMPTR(current, newtype) (newtype*)(((unsigned char*)current) + current##_size)