mirror of
https://github.com/nothings/stb
synced 2024-12-14 12:07:13 +03:00
In some situations with certain filter kernels with negative values it's possible to generate valid results > 1.0, so saturate it before we write it to make sure it doesn't overflow. Also fix incorrect filter radius while downsampling.
This commit is contained in:
parent
af1ed58f51
commit
41dc4c476c
@ -214,6 +214,17 @@ static stbr_inline int stbr__max(int a, int b)
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
static stbr_inline float stbr__saturate(float x)
|
||||
{
|
||||
if (x < 0)
|
||||
return 0;
|
||||
|
||||
if (x > 1)
|
||||
return 1;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
static float stbr__filter_nearest(float x)
|
||||
{
|
||||
@ -450,8 +461,8 @@ static void stbr__calculate_coefficients_upsample(stbr__info* stbr_info, int in_
|
||||
total_filter += coefficient_group[i] = stbr__filter_info_table[filter].kernel(in_center_of_out - in_texel_center);
|
||||
}
|
||||
|
||||
STBR_DEBUG_ASSERT(total_filter > 0);
|
||||
STBR_DEBUG_ASSERT(fabs(1 - total_filter) < 0.1f); // Make sure it's not way off.
|
||||
STBR_DEBUG_ASSERT(total_filter > 0.9);
|
||||
STBR_DEBUG_ASSERT(total_filter < 1.1f); // Make sure it's not way off.
|
||||
|
||||
// Make sure the sum of all coefficients is 1.
|
||||
filter_scale = 1 / total_filter;
|
||||
@ -474,10 +485,34 @@ static void stbr__calculate_coefficients_downsample(stbr__info* stbr_info, float
|
||||
for (i = 0; i <= out_last_texel - out_first_texel; i++)
|
||||
{
|
||||
float in_texel_center = (float)(i + out_first_texel) + 0.5f;
|
||||
coefficient_group[i] = stbr__filter_info_table[filter].kernel(out_center_of_in - in_texel_center) * scale_ratio;
|
||||
coefficient_group[i] = stbr__filter_info_table[filter].kernel((out_center_of_in - in_texel_center)/scale_ratio);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef STBR_DEBUG
|
||||
static void stbr__check_downsample_coefficients(stbr__info* stbr_info)
|
||||
{
|
||||
for (int i = 0; i < stbr_info->output_w; i++)
|
||||
{
|
||||
float total = 0;
|
||||
for (int j = 0; j < stbr__get_horizontal_contributors(stbr_info->filter, stbr_info->input_w, stbr_info->output_w); j++)
|
||||
{
|
||||
if (i >= stbr_info->horizontal_contributors[j].n0 && i <= stbr_info->horizontal_contributors[j].n1)
|
||||
{
|
||||
float coefficient = *stbr__get_coefficient(stbr_info, j, i - stbr_info->horizontal_contributors[j].n0);
|
||||
total += coefficient;
|
||||
}
|
||||
else if (i < stbr_info->horizontal_contributors[j].n0)
|
||||
break;
|
||||
}
|
||||
|
||||
STBR_DEBUG_ASSERT(stbr_info->type == STBR_TYPE_UINT8); // Assert below should be 1 + 1/(2^n-1) where n is bits per int.
|
||||
STBR_DEBUG_ASSERT(total > 0.9f);
|
||||
STBR_DEBUG_ASSERT(total <= 1.0f + 1.0f / 255);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Each scan line uses the same kernel values so we should calculate the kernel
|
||||
// values once and then we can use them for every scan line.
|
||||
static void stbr__calculate_horizontal_filters(stbr__info* stbr_info)
|
||||
@ -504,7 +539,7 @@ static void stbr__calculate_horizontal_filters(stbr__info* stbr_info)
|
||||
}
|
||||
else
|
||||
{
|
||||
float in_pixels_radius = stbr__filter_info_table[stbr_info->filter].support / scale_ratio;
|
||||
float in_pixels_radius = stbr__filter_info_table[stbr_info->filter].support;
|
||||
|
||||
// Looping through in texels
|
||||
for (n = 0; n < total_contributors; n++)
|
||||
@ -517,6 +552,10 @@ static void stbr__calculate_horizontal_filters(stbr__info* stbr_info)
|
||||
|
||||
stbr__calculate_coefficients_downsample(stbr_info, scale_ratio, out_first_texel, out_last_texel, out_center_of_in, stbr__get_contributor(stbr_info, n), stbr__get_coefficient(stbr_info, n, 0));
|
||||
}
|
||||
|
||||
#ifdef STBR_DEBUG
|
||||
stbr__check_downsample_coefficients(stbr_info);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -805,11 +844,7 @@ static void stbr__resample_vertical_upsample(stbr__info* stbr_info, int n, int i
|
||||
}
|
||||
|
||||
for (c = 0; c < channels; c++)
|
||||
{
|
||||
STBR_DEBUG_ASSERT(encode_buffer[c] < 1.0f + 1.0f/255);
|
||||
|
||||
((unsigned char*)output_data)[out_texel_index + c] = (unsigned char)(encode_buffer[c] * 255);
|
||||
}
|
||||
((unsigned char*)output_data)[out_texel_index + c] = (unsigned char)(stbr__saturate(encode_buffer[c]) * 255);
|
||||
}
|
||||
}
|
||||
|
||||
@ -943,11 +978,7 @@ static void stbr__empty_ring_buffer(stbr__info* stbr_info, int first_necessary_s
|
||||
int ring_texel_index = texel_index;
|
||||
int output_texel_index = output_row + texel_index;
|
||||
for (c = 0; c < channels; c++)
|
||||
{
|
||||
//STBR_DEBUG_ASSERT(ring_buffer_entry[ring_texel_index + c] < 1.0f + 1.0f / 255);
|
||||
|
||||
((unsigned char*)output_data)[output_texel_index + c] = (unsigned char)(ring_buffer_entry[ring_texel_index + c] * 255);
|
||||
}
|
||||
((unsigned char*)output_data)[output_texel_index + c] = (unsigned char)(stbr__saturate(ring_buffer_entry[ring_texel_index + c]) * 255);
|
||||
}
|
||||
}
|
||||
|
||||
@ -973,7 +1004,7 @@ static void stbr__buffer_loop_downsample(stbr__info* stbr_info)
|
||||
{
|
||||
int y;
|
||||
float scale_ratio = (float)stbr_info->output_h / stbr_info->input_h;
|
||||
float in_pixels_radius = stbr__filter_info_table[stbr_info->filter].support / scale_ratio;
|
||||
float in_pixels_radius = stbr__filter_info_table[stbr_info->filter].support;
|
||||
int max_y = stbr_info->input_h + stbr__get_filter_texel_margin(stbr_info->filter);
|
||||
|
||||
STBR_DEBUG_ASSERT(!stbr__use_height_upsampling(stbr_info));
|
||||
|
Loading…
Reference in New Issue
Block a user