compile as C;
fix some unsigned/signed comparisons; avoid round() since it's not in pre-C99 C; remove MAX_CHANNELS since I never ended up needing it; rename STBIR_EPSILON to STBIR_ALPHA_EPSILON; don't use STBIR_ALPHA_EPSILON on float input (can't remove it properly due to numeric precision, and they can do it themselves); optimize subtraction of STBIR_ALPHA_EPSILON; sorry i forgot to commit these separately!;
This commit is contained in:
parent
1208730e1e
commit
30c7a981ec
@ -19,14 +19,11 @@
|
||||
supported filters see the stbir_filter enum. To add a new filter,
|
||||
write a filter function and add it to stbir__filter_info_table.
|
||||
|
||||
STBIR_MAX_CHANNELS: defaults to 16, if you need more, bump it up
|
||||
|
||||
Revisions:
|
||||
0.50 (2014-??-??) first released version
|
||||
|
||||
TODO:
|
||||
Installable filters
|
||||
Specify wrap and filter modes independently for each axis
|
||||
Resize that respects alpha test coverage
|
||||
(Reference code: FloatImage::alphaTestCoverage and FloatImage::scaleAlphaToCoverage:
|
||||
https://code.google.com/p/nvidia-texture-tools/source/browse/trunk/src/nvimage/FloatImage.cpp )
|
||||
@ -130,7 +127,7 @@ STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels
|
||||
// * Alpha-channel can be processed separately
|
||||
// * If alpha_channel is not STBIR_ALPHA_CHANNEL_NONE
|
||||
// * Alpha channel will not be gamma corrected (unless flags&STBIR_FLAG_GAMMA_CORRECT)
|
||||
// * Filters can be weighted by alpha channel (if flags&STBIR_FLAG_NONPREMUL_ALPHA)
|
||||
// * Filters will be weighted by alpha channel (unless flags&STBIR_FLAG_PREMULTIPLIED_ALPHA)
|
||||
// * Filter can be selected explicitly
|
||||
// * uint16 image type
|
||||
// * sRGB colorspace available for all types
|
||||
@ -246,8 +243,8 @@ STBIRDEF int stbir_resize_region( const void *input_pixels , int input_w , int
|
||||
// that behavior (it may interfere if you have floating point images with
|
||||
// very small alpha values) then you can define STBIR_NO_ALPHA_EPSILON to
|
||||
// disable it.
|
||||
#ifndef STBIR_EPSILON
|
||||
#define STBIR_EPSILON ((float)1 / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20))
|
||||
#ifndef STBIR_ALPHA_EPSILON
|
||||
#define STBIR_ALPHA_EPSILON ((float)1 / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20))
|
||||
#endif
|
||||
|
||||
//
|
||||
@ -317,10 +314,6 @@ typedef unsigned char stbir__validate_uint32[sizeof(stbir_uint32) == 4 ? 1 : -1]
|
||||
#define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_MITCHELL
|
||||
#endif
|
||||
|
||||
#ifndef STBIR_MAX_CHANNELS
|
||||
#define STBIR_MAX_CHANNELS 16
|
||||
#endif
|
||||
|
||||
#define STBIR__UNUSED_PARAM(s) s=s;
|
||||
|
||||
// must match stbir_datatype
|
||||
@ -534,11 +527,11 @@ static unsigned char stbir__linear_to_srgb_uchar(float f)
|
||||
|
||||
static float stbir__filter_trapezoid(float x, float scale)
|
||||
{
|
||||
STBIR__DEBUG_ASSERT(scale <= 1);
|
||||
x = (float)fabs(x);
|
||||
|
||||
float halfscale = scale / 2;
|
||||
float t = 0.5f + halfscale;
|
||||
STBIR__DEBUG_ASSERT(scale <= 1);
|
||||
|
||||
x = (float)fabs(x);
|
||||
|
||||
if (x >= t)
|
||||
return 0;
|
||||
@ -870,6 +863,7 @@ static void stbir__normalize_downsample_coefficients(stbir__info* stbir_info)
|
||||
int i;
|
||||
for (i = 0; i < stbir_info->output_w; i++)
|
||||
{
|
||||
float scale;
|
||||
float total = 0;
|
||||
int j;
|
||||
for (j = 0; j < num_contributors; j++)
|
||||
@ -886,7 +880,7 @@ static void stbir__normalize_downsample_coefficients(stbir__info* stbir_info)
|
||||
STBIR__DEBUG_ASSERT(total > 0.9f);
|
||||
STBIR__DEBUG_ASSERT(total < 1.1f);
|
||||
|
||||
float scale = 1 / total;
|
||||
scale = 1 / total;
|
||||
|
||||
for (j = 0; j < num_contributors; j++)
|
||||
{
|
||||
@ -1097,7 +1091,11 @@ static void stbir__decode_scanline(stbir__info* stbir_info, int n)
|
||||
int decode_pixel_index = x * channels;
|
||||
|
||||
// If the alpha value is 0 it will clobber the color values. Make sure it's not.
|
||||
float alpha = (decode_buffer[decode_pixel_index + alpha_channel] += STBIR_EPSILON);
|
||||
float alpha = decode_buffer[decode_pixel_index + alpha_channel];
|
||||
if (stbir_info->type != STBIR_TYPE_FLOAT) {
|
||||
alpha += STBIR_ALPHA_EPSILON;
|
||||
decode_buffer[decode_pixel_index + alpha_channel] = alpha;
|
||||
}
|
||||
|
||||
for (c = 0; c < channels; c++)
|
||||
{
|
||||
@ -1270,7 +1268,6 @@ static float* stbir__get_ring_buffer_scanline(int get_scanline, float* ring_buff
|
||||
}
|
||||
|
||||
|
||||
// @OPTIMIZE: embed stbir__encode_pixel and move switch out of per-pixel loop
|
||||
static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void *output_buffer, float *encode_buffer, int channels, int alpha_channel, int decode)
|
||||
{
|
||||
int x;
|
||||
@ -1284,14 +1281,14 @@ static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void
|
||||
int pixel_index = x*channels;
|
||||
|
||||
float alpha = encode_buffer[pixel_index + alpha_channel];
|
||||
STBIR__DEBUG_ASSERT(alpha > 0);
|
||||
float reciprocal_alpha = alpha ? 1.0f / alpha : 0;
|
||||
for (n = 0; n < channels; n++)
|
||||
if (n != alpha_channel)
|
||||
encode_buffer[pixel_index + n] *= reciprocal_alpha;
|
||||
|
||||
// We added in a small epsilon to prevent the color channel from being deleted with zero alpha. Remove it now.
|
||||
encode_buffer[pixel_index + alpha_channel] -= STBIR_EPSILON;
|
||||
// We added in a small epsilon to prevent the color channel from being deleted with zero alpha.
|
||||
// Because we only add it for integer types, it will automatically be discarded on integer
|
||||
// conversion.
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -1306,7 +1303,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)(round(stbir__saturate(encode_buffer[index]) * 255));
|
||||
((unsigned char*)output_buffer)[index] = (unsigned char)(floor(stbir__saturate(encode_buffer[index]) * 255 + 0.5f));
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1323,7 +1320,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)(round(stbir__saturate(encode_buffer[pixel_index + alpha_channel]) * 255));
|
||||
((unsigned char*)output_buffer)[pixel_index + alpha_channel] = (unsigned char)(floor(stbir__saturate(encode_buffer[pixel_index + alpha_channel]) * 255+0.5f));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1335,7 +1332,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)(round(stbir__saturate(encode_buffer[index]) * 65535));
|
||||
((unsigned short*)output_buffer)[index] = (unsigned short)(floor(stbir__saturate(encode_buffer[index]) * 65535+0.5f));
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1348,11 +1345,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)(round(stbir__linear_to_srgb(stbir__saturate(encode_buffer[index])) * 65535));
|
||||
((unsigned short*)output_buffer)[index] = (unsigned short)(floor(stbir__linear_to_srgb(stbir__saturate(encode_buffer[index])) * 65535 + 0.5f));
|
||||
}
|
||||
|
||||
if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
|
||||
((unsigned short*)output_buffer)[pixel_index + alpha_channel] = (unsigned short)(round(stbir__saturate(encode_buffer[pixel_index + alpha_channel]) * 65535));
|
||||
((unsigned short*)output_buffer)[pixel_index + alpha_channel] = (unsigned short)(floor(stbir__saturate(encode_buffer[pixel_index + alpha_channel]) * 65535 + 0.5f));
|
||||
}
|
||||
|
||||
break;
|
||||
@ -1365,7 +1362,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)(round(((double)stbir__saturate(encode_buffer[index])) * 4294967295));
|
||||
((unsigned int*)output_buffer)[index] = (unsigned int)(floor(((double)stbir__saturate(encode_buffer[index])) * 4294967295 + 0.5f));
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1378,11 +1375,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)(round(((double)stbir__linear_to_srgb(stbir__saturate(encode_buffer[index]))) * 4294967295));
|
||||
((unsigned int*)output_buffer)[index] = (unsigned int)(floor(((double)stbir__linear_to_srgb(stbir__saturate(encode_buffer[index]))) * 4294967295 + 0.5f));
|
||||
}
|
||||
|
||||
if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
|
||||
((unsigned int*)output_buffer)[pixel_index + alpha_channel] = (unsigned int)(round(((double)stbir__saturate(encode_buffer[pixel_index + alpha_channel])) * 4294967295));
|
||||
((unsigned int*)output_buffer)[pixel_index + alpha_channel] = (unsigned int)(floor(((double)stbir__saturate(encode_buffer[pixel_index + alpha_channel])) * 4294967295 + 0.5f));
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1769,10 +1766,9 @@ static int stbir__resize_allocated(stbir__info *info,
|
||||
memcpy(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE);
|
||||
#endif
|
||||
|
||||
STBIR_ASSERT(info->channels <= STBIR_MAX_CHANNELS);
|
||||
STBIR_ASSERT(info->channels >= 0);
|
||||
|
||||
if (info->channels > STBIR_MAX_CHANNELS || info->channels < 0)
|
||||
if (info->channels < 0)
|
||||
return 0;
|
||||
|
||||
STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
|
||||
|
@ -425,10 +425,10 @@ void test_premul()
|
||||
float ga = (float)25 / 4294967296;
|
||||
float a = (ra + ga) / 2;
|
||||
|
||||
STBIR_ASSERT(output[0] == (int)(r * ra / 2 / a * 4294967296 + 0.5f)); // 232
|
||||
STBIR_ASSERT(output[1] == (int)(g * ga / 2 / a * 4294967296 + 0.5f)); // 23
|
||||
STBIR_ASSERT(output[0] == (unsigned int)(r * ra / 2 / a * 4294967296 + 0.5f)); // 232
|
||||
STBIR_ASSERT(output[1] == (unsigned int)(g * ga / 2 / a * 4294967296 + 0.5f)); // 23
|
||||
STBIR_ASSERT(output[2] == 0);
|
||||
STBIR_ASSERT(output[3] == (int)(a * 4294967296 + 0.5f)); // 140
|
||||
STBIR_ASSERT(output[3] == (unsigned int)(a * 4294967296 + 0.5f)); // 140
|
||||
|
||||
// Now a test to make sure it doesn't clobber existing values.
|
||||
|
||||
@ -606,7 +606,7 @@ void verify_box(void)
|
||||
STBIR_ASSERT(output11[0][0] == ((t+32)>>6));
|
||||
}
|
||||
|
||||
void verify_filter_normalized(stbir_filter filter, int output_size, int value)
|
||||
void verify_filter_normalized(stbir_filter filter, int output_size, unsigned int value)
|
||||
{
|
||||
int i, j;
|
||||
unsigned int output[64];
|
||||
@ -618,6 +618,11 @@ void verify_filter_normalized(stbir_filter filter, int output_size, int value)
|
||||
STBIR_ASSERT(value == output[j*output_size + i]);
|
||||
}
|
||||
|
||||
float round2(float f)
|
||||
{
|
||||
return (float) floor(f+0.5f); // round() isn't C standard pre-C99
|
||||
}
|
||||
|
||||
void test_filters(void)
|
||||
{
|
||||
int i,j;
|
||||
@ -673,7 +678,7 @@ void test_filters(void)
|
||||
|
||||
{
|
||||
// This test is designed to produce coefficients that are very badly denormalized.
|
||||
int v = 556;
|
||||
unsigned int v = 556;
|
||||
|
||||
unsigned int input[100 * 100];
|
||||
unsigned int output[11 * 11];
|
||||
@ -698,13 +703,13 @@ void test_filters(void)
|
||||
|
||||
stbir_resize(input, 3, 1, 0, output, 2, 1, 0, STBIR_TYPE_UINT32, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_BOX, STBIR_FILTER_BOX, STBIR_COLORSPACE_LINEAR, NULL);
|
||||
|
||||
STBIR_ASSERT(output[0] == (int)round((float)(input[0] * 2 + input[1]) / 3));
|
||||
STBIR_ASSERT(output[1] == (int)round((float)(input[2] * 2 + input[1]) / 3));
|
||||
STBIR_ASSERT(output[0] == (unsigned int)round2((float)(input[0] * 2 + input[1]) / 3));
|
||||
STBIR_ASSERT(output[1] == (unsigned int)round2((float)(input[2] * 2 + input[1]) / 3));
|
||||
|
||||
stbir_resize(input, 1, 3, 0, output, 1, 2, 0, STBIR_TYPE_UINT32, 1, STBIR_ALPHA_CHANNEL_NONE, 0, STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_FILTER_BOX, STBIR_FILTER_BOX, STBIR_COLORSPACE_LINEAR, NULL);
|
||||
|
||||
STBIR_ASSERT(output[0] == (int)round((float)(input[0] * 2 + input[1]) / 3));
|
||||
STBIR_ASSERT(output[1] == (int)round((float)(input[2] * 2 + input[1]) / 3));
|
||||
STBIR_ASSERT(output[0] == (unsigned int)round2((float)(input[0] * 2 + input[1]) / 3));
|
||||
STBIR_ASSERT(output[1] == (unsigned int)round2((float)(input[2] * 2 + input[1]) / 3));
|
||||
}
|
||||
|
||||
{
|
||||
@ -767,6 +772,7 @@ void test_suite(int argc, char **argv)
|
||||
else
|
||||
barbara = "barbara.png";
|
||||
|
||||
// check what cases we need normalization for
|
||||
#if 1
|
||||
{
|
||||
float x, y;
|
||||
@ -804,8 +810,11 @@ void test_suite(int argc, char **argv)
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0; i < 256; i++)
|
||||
STBIR_ASSERT(stbir__linear_to_srgb_uchar(stbir__srgb_to_linear(float(i) / 255)) == i);
|
||||
for (i = 0; i < 256; i++) {
|
||||
float f = stbir__srgb_to_linear(float(i) / 255);
|
||||
int n = stbir__linear_to_srgb_uchar(f);
|
||||
STBIR_ASSERT(n == i);
|
||||
}
|
||||
|
||||
#if 0 // linear_to_srgb_uchar table
|
||||
for (i=0; i < 256; ++i) {
|
||||
|
Loading…
Reference in New Issue
Block a user