Specify a channel as having premultiplied alpha and use it to un-premultiply all other channels before resampling.
This commit is contained in:
parent
a32fa8b4df
commit
8063ea0952
@ -51,12 +51,13 @@
|
||||
// result = stbr_resize_arbitrary(input_data, input_w, input_h, input_stride_in_bytes,
|
||||
// output_data, output_w, output_h, output_stride_in_bytes,
|
||||
// s0, t0, s1, t1,
|
||||
// channels, STBR_TYPE_UINT8, STBR_FILTER_CATMULLROM, STBR_EDGE_CLAMP, STBR_COLORSPACE_SRGB,
|
||||
// channels, premultiplied_alpha_channel, STBR_TYPE_UINT8, STBR_FILTER_CATMULLROM, STBR_EDGE_CLAMP, STBR_COLORSPACE_SRGB,
|
||||
// extra_memory, memory_required);
|
||||
// free(extra_memory);
|
||||
//
|
||||
// input_stride_in_bytes and output_stride_in_bytes can be 0. If so they will be automatically calculated as width * channels.
|
||||
// s0, t0, s1, t1 are the top-left and bottom right corner (uv addressing style: [0, 1]x[0, 1]) of a region of the input image to use.
|
||||
// premultiplied_alpha_channel is 0 if there are no premultiplied alpha channels. If nonzero, the specified channel will be divided from all other channels before resampling, then multiplied back in after.
|
||||
// Returned result is 1 for success or 0 in case of an error. In the case of an error an assert with be triggered, #define STBR_ASSERT() to see it.
|
||||
// stbr_resize_arbitrary() will not allocate any memory, it will use the memory you pass in to do its work.
|
||||
|
||||
@ -155,7 +156,7 @@ extern "C" {
|
||||
STBRDEF int stbr_resize_arbitrary(const void* input_data, int input_w, int input_h, int input_stride_in_bytes,
|
||||
void* output_data, int output_w, int output_h, int output_stride_in_bytes,
|
||||
float s0, float t0, float s1, float t1,
|
||||
int channels, stbr_type type, stbr_filter filter, stbr_edge edge, stbr_colorspace colorspace,
|
||||
int channels, int premultiplied_alpha_channel, stbr_type type, stbr_filter filter, stbr_edge edge, stbr_colorspace colorspace,
|
||||
void* tempmem, stbr_size_t tempmem_size_in_bytes);
|
||||
|
||||
|
||||
@ -256,6 +257,7 @@ typedef struct
|
||||
float vertical_scale;
|
||||
|
||||
int channels;
|
||||
int premul_alpha_channel;
|
||||
stbr_type type;
|
||||
stbr_filter filter;
|
||||
stbr_edge edge;
|
||||
@ -708,6 +710,7 @@ static void stbr__decode_scanline(stbr__info* stbr_info, int n)
|
||||
{
|
||||
int x, c;
|
||||
int channels = stbr_info->channels;
|
||||
int premul_alpha_channel = stbr_info->premul_alpha_channel;
|
||||
int type = stbr_info->type;
|
||||
int colorspace = stbr_info->colorspace;
|
||||
int input_w = stbr_info->input_w;
|
||||
@ -770,6 +773,17 @@ static void stbr__decode_scanline(stbr__info* stbr_info, int n)
|
||||
STBR_UNIMPLEMENTED("Unknown type/colorspace/channels combination.");
|
||||
break;
|
||||
}
|
||||
|
||||
if (premul_alpha_channel)
|
||||
{
|
||||
for (c = 0; c < channels; c++)
|
||||
{
|
||||
if (c == premul_alpha_channel)
|
||||
continue;
|
||||
|
||||
decode_buffer[decode_texel_index + c] /= decode_buffer[decode_texel_index + premul_alpha_channel];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -920,9 +934,21 @@ static float* stbr__get_ring_buffer_scanline(int get_scanline, float* ring_buffe
|
||||
}
|
||||
|
||||
|
||||
static stbr_inline void stbr__encode_scanline(void* output_buffer, int output_texel_index, float* encode_buffer, int encode_texel_index, int channels, int decode)
|
||||
static stbr_inline void stbr__encode_scanline(void* output_buffer, int output_texel_index, float* encode_buffer, int encode_texel_index, int channels, int premul_alpha_channel, int decode)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (premul_alpha_channel)
|
||||
{
|
||||
for (n = 0; n < channels; n++)
|
||||
{
|
||||
if (n == premul_alpha_channel)
|
||||
continue;
|
||||
|
||||
encode_buffer[encode_texel_index + n] *= encode_buffer[encode_texel_index + premul_alpha_channel];
|
||||
}
|
||||
}
|
||||
|
||||
switch (decode)
|
||||
{
|
||||
case STBR__DECODE(STBR_TYPE_UINT8, STBR_COLORSPACE_LINEAR):
|
||||
@ -969,6 +995,18 @@ static stbr_inline void stbr__encode_scanline(void* output_buffer, int output_te
|
||||
STBR_UNIMPLEMENTED("Unknown type/colorspace/channels combination.");
|
||||
break;
|
||||
}
|
||||
|
||||
// Put it back the way it was in case this is a ring buffer.
|
||||
if (premul_alpha_channel)
|
||||
{
|
||||
for (n = 0; n < channels; n++)
|
||||
{
|
||||
if (n == premul_alpha_channel)
|
||||
continue;
|
||||
|
||||
encode_buffer[encode_texel_index + n] /= encode_buffer[encode_texel_index + premul_alpha_channel];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void stbr__resample_vertical_upsample(stbr__info* stbr_info, int n, int in_first_scanline, int in_last_scanline, float in_center_of_out)
|
||||
@ -978,6 +1016,7 @@ static void stbr__resample_vertical_upsample(stbr__info* stbr_info, int n, int i
|
||||
stbr__contributors* vertical_contributors = &stbr_info->vertical_contributors;
|
||||
float* vertical_coefficients = stbr_info->vertical_coefficients;
|
||||
int channels = stbr_info->channels;
|
||||
int premul_alpha_channel = stbr_info->premul_alpha_channel;
|
||||
int type = stbr_info->type;
|
||||
int colorspace = stbr_info->colorspace;
|
||||
int kernel_texel_width = stbr__get_filter_texel_width_vertical(stbr_info);
|
||||
@ -1023,7 +1062,7 @@ static void stbr__resample_vertical_upsample(stbr__info* stbr_info, int n, int i
|
||||
encode_buffer[c] += ring_buffer_entry[in_texel_index + c] * coefficient;
|
||||
}
|
||||
|
||||
stbr__encode_scanline(output_data, out_texel_index, encode_buffer, 0, channels, decode);
|
||||
stbr__encode_scanline(output_data, out_texel_index, encode_buffer, 0, channels, premul_alpha_channel, decode);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1130,6 +1169,7 @@ static void stbr__empty_ring_buffer(stbr__info* stbr_info, int first_necessary_s
|
||||
{
|
||||
int output_stride = stbr_info->output_stride_bytes / stbr__type_size[stbr_info->type];
|
||||
int channels = stbr_info->channels;
|
||||
int premul_alpha_channel = stbr_info->premul_alpha_channel;
|
||||
int type = stbr_info->type;
|
||||
int colorspace = stbr_info->colorspace;
|
||||
int output_w = stbr_info->output_w;
|
||||
@ -1156,7 +1196,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;
|
||||
|
||||
stbr__encode_scanline(output_data, output_texel_index, ring_buffer_entry, ring_texel_index, channels, decode);
|
||||
stbr__encode_scanline(output_data, output_texel_index, ring_buffer_entry, ring_texel_index, channels, premul_alpha_channel, decode);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1221,7 +1261,7 @@ static void stbr__buffer_loop_downsample(stbr__info* stbr_info)
|
||||
STBRDEF int stbr_resize_arbitrary(const void* input_data, int input_w, int input_h, int input_stride_in_bytes,
|
||||
void* output_data, int output_w, int output_h, int output_stride_in_bytes,
|
||||
float s0, float t0, float s1, float t1,
|
||||
int channels, stbr_type type, stbr_filter filter, stbr_edge edge, stbr_colorspace colorspace,
|
||||
int channels, int premul_alpha_channel, stbr_type type, stbr_filter filter, stbr_edge edge, stbr_colorspace colorspace,
|
||||
void* tempmem, stbr_size_t tempmem_size_in_bytes)
|
||||
{
|
||||
stbr_size_t memory_required = stbr_calculate_memory(input_w, input_h, output_w, output_h, s0, t0, s1, t1, channels, filter);
|
||||
@ -1260,6 +1300,11 @@ STBRDEF int stbr_resize_arbitrary(const void* input_data, int input_w, int input
|
||||
if (s1 > 1 || s0 < 0 || t1 > 1 || t0 < 0)
|
||||
return 0;
|
||||
|
||||
STBR_ASSERT(premul_alpha_channel >= 0 && premul_alpha_channel < channels);
|
||||
|
||||
if (premul_alpha_channel < 0 || premul_alpha_channel >= channels)
|
||||
return 0;
|
||||
|
||||
STBR_ASSERT(tempmem);
|
||||
|
||||
if (!tempmem)
|
||||
@ -1296,6 +1341,7 @@ STBRDEF int stbr_resize_arbitrary(const void* input_data, int input_w, int input
|
||||
stbr_info->vertical_shift = t0 * input_h / (t1 - t0);
|
||||
|
||||
stbr_info->channels = channels;
|
||||
stbr_info->premul_alpha_channel = premul_alpha_channel;
|
||||
stbr_info->type = type;
|
||||
stbr_info->filter = filter;
|
||||
stbr_info->edge = edge;
|
||||
@ -1396,7 +1442,7 @@ STBRDEF int stbr_resize_srgb_uint8(const stbr_uint8* input_data, int input_w, in
|
||||
if (!extra_memory)
|
||||
return 0;
|
||||
|
||||
int result = stbr_resize_arbitrary(input_data, input_w, input_h, 0, output_data, output_w, output_h, 0, 0, 0, 1, 1, channels, STBR_TYPE_UINT8, filter, edge, STBR_COLORSPACE_SRGB, extra_memory, memory_required);
|
||||
int result = stbr_resize_arbitrary(input_data, input_w, input_h, 0, output_data, output_w, output_h, 0, 0, 0, 1, 1, channels, 0, STBR_TYPE_UINT8, filter, edge, STBR_COLORSPACE_SRGB, extra_memory, memory_required);
|
||||
|
||||
free(extra_memory);
|
||||
|
||||
@ -1413,7 +1459,7 @@ STBRDEF int stbr_resize_srgb_uint16(const stbr_uint16* input_data, int input_w,
|
||||
if (!extra_memory)
|
||||
return 0;
|
||||
|
||||
int result = stbr_resize_arbitrary(input_data, input_w, input_h, 0, output_data, output_w, output_h, 0, 0, 0, 1, 1, channels, STBR_TYPE_UINT16, filter, edge, STBR_COLORSPACE_SRGB, extra_memory, memory_required);
|
||||
int result = stbr_resize_arbitrary(input_data, input_w, input_h, 0, output_data, output_w, output_h, 0, 0, 0, 1, 1, channels, 0, STBR_TYPE_UINT16, filter, edge, STBR_COLORSPACE_SRGB, extra_memory, memory_required);
|
||||
|
||||
free(extra_memory);
|
||||
|
||||
@ -1430,7 +1476,7 @@ STBRDEF int stbr_resize_srgb_uint32(const stbr_uint32* input_data, int input_w,
|
||||
if (!extra_memory)
|
||||
return 0;
|
||||
|
||||
int result = stbr_resize_arbitrary(input_data, input_w, input_h, 0, output_data, output_w, output_h, 0, 0, 0, 1, 1, channels, STBR_TYPE_UINT32, filter, edge, STBR_COLORSPACE_SRGB, extra_memory, memory_required);
|
||||
int result = stbr_resize_arbitrary(input_data, input_w, input_h, 0, output_data, output_w, output_h, 0, 0, 0, 1, 1, channels, 0, STBR_TYPE_UINT32, filter, edge, STBR_COLORSPACE_SRGB, extra_memory, memory_required);
|
||||
|
||||
free(extra_memory);
|
||||
|
||||
@ -1447,7 +1493,7 @@ STBRDEF int stbr_resize_srgb_float(const float* input_data, int input_w, int inp
|
||||
if (!extra_memory)
|
||||
return 0;
|
||||
|
||||
int result = stbr_resize_arbitrary(input_data, input_w, input_h, 0, output_data, output_w, output_h, 0, 0, 0, 1, 1, channels, STBR_TYPE_FLOAT, filter, edge, STBR_COLORSPACE_SRGB, extra_memory, memory_required);
|
||||
int result = stbr_resize_arbitrary(input_data, input_w, input_h, 0, output_data, output_w, output_h, 0, 0, 0, 1, 1, channels, 0, STBR_TYPE_FLOAT, filter, edge, STBR_COLORSPACE_SRGB, extra_memory, memory_required);
|
||||
|
||||
free(extra_memory);
|
||||
|
||||
|
@ -91,7 +91,7 @@ int main(int argc, char** argv)
|
||||
|
||||
printf("Average: %dms\n", average);
|
||||
#else
|
||||
stbr_resize_arbitrary(input_data + w * border * n + border * n, in_w, in_h, w*n, output_data, out_w, out_h, out_stride, s0, t0, s1, t1, n, STBR_TYPE_UINT8, STBR_FILTER_CATMULLROM, STBR_EDGE_CLAMP, STBR_COLORSPACE_SRGB, extra_memory, memory_required);
|
||||
stbr_resize_arbitrary(input_data + w * border * n + border * n, in_w, in_h, w*n, output_data, out_w, out_h, out_stride, s0, t0, s1, t1, n, 0, STBR_TYPE_UINT8, STBR_FILTER_CATMULLROM, STBR_EDGE_CLAMP, STBR_COLORSPACE_SRGB, extra_memory, memory_required);
|
||||
#endif
|
||||
|
||||
free(extra_memory);
|
||||
@ -123,7 +123,7 @@ void resize_image(const char* filename, float width_percent, float height_percen
|
||||
size_t memory_required = stbr_calculate_memory(w, h, out_w, out_h, 0, 0, 1, 1, n, filter);
|
||||
void* extra_memory = malloc(memory_required);
|
||||
|
||||
stbr_resize_arbitrary(input_data, w, h, 0, output_data, out_w, out_h, 0, 0, 0, 1, 1, n, STBR_TYPE_UINT8, filter, edge, colorspace, extra_memory, memory_required);
|
||||
stbr_resize_arbitrary(input_data, w, h, 0, output_data, out_w, out_h, 0, 0, 0, 1, 1, n, 0, STBR_TYPE_UINT8, filter, edge, colorspace, extra_memory, memory_required);
|
||||
|
||||
free(extra_memory);
|
||||
stbi_image_free(input_data);
|
||||
@ -157,7 +157,7 @@ void test_format(const char* file, float width_percent, float height_percent, st
|
||||
|
||||
size_t required = stbr_calculate_memory(w, h, new_w, new_h, 0, 0, 1, 1, n, STBR_FILTER_CATMULLROM);
|
||||
void* extra_memory = malloc(required);
|
||||
stbr_resize_arbitrary(T_data, w, h, 0, output_data, new_w, new_h, 0, 0, 0, 1, 1, n, type, STBR_FILTER_CATMULLROM, STBR_EDGE_CLAMP, colorspace, extra_memory, required);
|
||||
stbr_resize_arbitrary(T_data, w, h, 0, output_data, new_w, new_h, 0, 0, 0, 1, 1, n, 0, type, STBR_FILTER_CATMULLROM, STBR_EDGE_CLAMP, colorspace, extra_memory, required);
|
||||
free(extra_memory);
|
||||
|
||||
free(T_data);
|
||||
@ -201,7 +201,7 @@ void test_float(const char* file, float width_percent, float height_percent, stb
|
||||
|
||||
size_t required = stbr_calculate_memory(w, h, new_w, new_h, 0, 0, 1, 1, n, STBR_FILTER_CATMULLROM);
|
||||
void* extra_memory = malloc(required);
|
||||
stbr_resize_arbitrary(T_data, w, h, 0, output_data, new_w, new_h, 0, 0, 0, 1, 1, n, type, STBR_FILTER_CATMULLROM, STBR_EDGE_CLAMP, colorspace, extra_memory, required);
|
||||
stbr_resize_arbitrary(T_data, w, h, 0, output_data, new_w, new_h, 0, 0, 0, 1, 1, n, 0, type, STBR_FILTER_CATMULLROM, STBR_EDGE_CLAMP, colorspace, extra_memory, required);
|
||||
free(extra_memory);
|
||||
|
||||
free(T_data);
|
||||
@ -267,7 +267,7 @@ void test_subpixel(const char* file, float width_percent, float height_percent,
|
||||
size_t tempmem_size = stbr_calculate_memory(w, h, new_w, new_h, 0, 0, s1, t1, n, STBR_FILTER_CATMULLROM);
|
||||
void* tempmem = malloc(tempmem_size);
|
||||
|
||||
stbr_resize_arbitrary(input_data, w, h, 0, output_data, new_w, new_h, 0, 0, 0, s1, t1, n, STBR_TYPE_UINT8, STBR_FILTER_CATMULLROM, STBR_EDGE_CLAMP, STBR_COLORSPACE_SRGB, tempmem, tempmem_size);
|
||||
stbr_resize_arbitrary(input_data, w, h, 0, output_data, new_w, new_h, 0, 0, 0, s1, t1, n, 0, STBR_TYPE_UINT8, STBR_FILTER_CATMULLROM, STBR_EDGE_CLAMP, STBR_COLORSPACE_SRGB, tempmem, tempmem_size);
|
||||
|
||||
free(tempmem);
|
||||
|
||||
@ -280,8 +280,43 @@ void test_subpixel(const char* file, float width_percent, float height_percent,
|
||||
free(output_data);
|
||||
}
|
||||
|
||||
void test_premul(const char* file)
|
||||
{
|
||||
int w, h, n;
|
||||
unsigned char* input_data = stbi_load(file, &w, &h, &n, 4);
|
||||
n = 4;
|
||||
|
||||
// Premultiply the first texel.
|
||||
input_data[0] /= 2;
|
||||
input_data[1] /= 2;
|
||||
input_data[2] /= 2;
|
||||
input_data[3] = 255 / 2;
|
||||
|
||||
int new_w = (int)(w * .5);
|
||||
int new_h = (int)(h * .5);
|
||||
|
||||
unsigned char* output_data = (unsigned char*)malloc(new_w * new_h * n * sizeof(unsigned char));
|
||||
|
||||
size_t tempmem_size = stbr_calculate_memory(w, h, new_w, new_h, 0, 0, 1, 1, n, STBR_FILTER_CATMULLROM);
|
||||
void* tempmem = malloc(tempmem_size);
|
||||
|
||||
stbr_resize_arbitrary(input_data, w, h, 0, output_data, new_w, new_h, 0, 0, 0, 1, 1, n, 3, STBR_TYPE_UINT8, STBR_FILTER_CATMULLROM, STBR_EDGE_CLAMP, STBR_COLORSPACE_SRGB, tempmem, tempmem_size);
|
||||
|
||||
free(tempmem);
|
||||
|
||||
stbi_image_free(input_data);
|
||||
|
||||
char output[200];
|
||||
sprintf(output, "test-output/premul-%s", file);
|
||||
stbi_write_png(output, new_w, new_h, n, output_data, 0);
|
||||
|
||||
free(output_data);
|
||||
}
|
||||
|
||||
void test_suite()
|
||||
{
|
||||
test_premul("barbara.png");
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
test_subpixel("barbara.png", 0.5f, 0.5f, (float)i / 10, 1);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user