From 0f367cc55086e46070e4c4cda9a1800176bed3c0 Mon Sep 17 00:00:00 2001 From: Oleg Oshmyan Date: Thu, 13 Mar 2014 03:15:18 +0000 Subject: Calculate \be using [0..64] value range (like VSFilter) To avoid banding in the output, the full [0..255] value range is restored before the last \be pass, which then uses the full range and hides the bands by virtue of being a blur. With this, our \be finally closely matches VSFilter's. The only visible difference (other than the lack of banding) is in clipping: we add proper padding and output the whole blurred image, while VSFilter does not add any padding and hence clips the blurred image too early. --- libass/ass_bitmap.c | 63 +++++++++++++++++++++++++++++++++++++++++++++-------- libass/ass_bitmap.h | 4 ++++ 2 files changed, 58 insertions(+), 9 deletions(-) (limited to 'libass') diff --git a/libass/ass_bitmap.c b/libass/ass_bitmap.c index 97fb26b..5f0991d 100644 --- a/libass/ass_bitmap.c +++ b/libass/ass_bitmap.c @@ -170,13 +170,23 @@ void ass_synth_blur(ASS_SynthPriv *priv_blur, int opaque_box, int be, unsigned stride = bm_o->stride; unsigned char *buf = bm_o->buffer; if(w && h){ - while(passes--){ - memset(tmp, 0, stride * 2); - if(w < 16){ - be_blur_c(buf, w, h, stride, tmp); - }else{ - priv_blur->be_blur_func(buf, w, h, stride, tmp); + if(passes > 1){ + be_blur_pre(buf, w, h, stride); + while(--passes){ + memset(tmp, 0, stride * 2); + if(w < 16){ + be_blur_c(buf, w, h, stride, tmp); + }else{ + priv_blur->be_blur_func(buf, w, h, stride, tmp); + } } + be_blur_post(buf, w, h, stride); + } + memset(tmp, 0, stride * 2); + if(w < 16){ + be_blur_c(buf, w, h, stride, tmp); + }else{ + priv_blur->be_blur_func(buf, w, h, stride, tmp); } } } @@ -187,10 +197,16 @@ void ass_synth_blur(ASS_SynthPriv *priv_blur, int opaque_box, int be, unsigned stride = bm_g->stride; unsigned char *buf = bm_g->buffer; if(w && h){ - while(passes--){ - memset(tmp, 0, stride * 2); - priv_blur->be_blur_func(buf, w, h, stride, tmp); + if(passes > 1){ + be_blur_pre(buf, w, h, stride); + while(--passes){ + memset(tmp, 0, stride * 2); + priv_blur->be_blur_func(buf, w, h, stride, tmp); + } + be_blur_post(buf, w, h, stride); } + memset(tmp, 0, stride * 2); + priv_blur->be_blur_func(buf, w, h, stride, tmp); } } } @@ -704,6 +720,35 @@ void be_blur_c(uint8_t *buf, intptr_t w, } } +void be_blur_pre(uint8_t *buf, intptr_t w, intptr_t h, intptr_t stride) +{ + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + // This is equivalent to (value * 64 + 127) / 255 for all + // values from 0 to 256 inclusive. Assist vectorizing + // compilers by noting that all temporaries fit in 8 bits. + buf[y * stride + x] = + (uint8_t) ((buf[y * stride + x] >> 1) + 1) >> 1; + } + } +} + +void be_blur_post(uint8_t *buf, intptr_t w, intptr_t h, intptr_t stride) +{ + for (int y = 0; y < h; ++y) + { + for (int x = 0; x < w; ++x) + { + // This is equivalent to (value * 255 + 32) / 64 for all values + // from 0 to 96 inclusive, and we only care about 0 to 64. + uint8_t value = buf[y * stride + x]; + buf[y * stride + x] = (value << 2) - (value > 32); + } + } +} + int outline_to_bitmap2(ASS_Renderer *render_priv, ASS_Outline *outline, ASS_Outline *border, Bitmap **bm_g, Bitmap **bm_o) diff --git a/libass/ass_bitmap.h b/libass/ass_bitmap.h index 9a36a3e..5014f51 100644 --- a/libass/ass_bitmap.h +++ b/libass/ass_bitmap.h @@ -72,6 +72,10 @@ void ass_gauss_blur(unsigned char *buffer, unsigned *tmp2, void be_blur_c(uint8_t *buf, intptr_t w, intptr_t h, intptr_t stride, uint16_t *tmp); +void be_blur_pre(uint8_t *buf, intptr_t w, + intptr_t h, intptr_t stride); +void be_blur_post(uint8_t *buf, intptr_t w, + intptr_t h, intptr_t stride); void add_bitmaps_c(uint8_t *dst, intptr_t dst_stride, uint8_t *src, intptr_t src_stride, intptr_t height, intptr_t width); -- cgit v1.2.3