]> granicus.if.org Git - libass/commitdiff
Calculate \be using [0..64] value range (like VSFilter)
authorOleg Oshmyan <chortos@inbox.lv>
Thu, 13 Mar 2014 03:15:18 +0000 (03:15 +0000)
committerOleg Oshmyan <chortos@inbox.lv>
Tue, 10 Feb 2015 02:42:35 +0000 (04:42 +0200)
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
libass/ass_bitmap.h

index 97fb26b271e29a7da1977281358dfea7a218c83c..5f0991d619ca20c5908c6956963d8f3589f5d3ad 100644 (file)
@@ -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)
index 9a36a3ec305147f4a1e6e4984152652ed7643e2f..5014f51a660a2e6fb8f610d22a06e642c74f6936 100644 (file)
@@ -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);