Add \be (blur edges) support to libass.
authoreugeni <eugeni@b3059339-0415-0410-9bf9-f77b7e298cf2>
Sat, 16 Sep 2006 13:32:46 +0000 (13:32 +0000)
committereugeni <eugeni@b3059339-0415-0410-9bf9-f77b7e298cf2>
Sat, 16 Sep 2006 13:32:46 +0000 (13:32 +0000)
git-svn-id: svn://git.mplayerhq.hu/mplayer/trunk@19854 b3059339-0415-0410-9bf9-f77b7e298cf2

libass/ass_bitmap.c
libass/ass_bitmap.h
libass/ass_cache.c
libass/ass_cache.h
libass/ass_render.c

index 9d98ec0..c7d5f78 100644 (file)
@@ -6,8 +6,97 @@
 #include FT_GLYPH_H
 
 #include "mp_msg.h"
+#include "libvo/font_load.h" // for blur()
 #include "ass_bitmap.h"
 
+struct ass_synth_priv_s {
+       int tmp_w, tmp_h;
+       unsigned short* tmp;
+
+       int g_r;
+       int g_w;
+
+       unsigned *g;
+       unsigned *gt2;
+};
+
+static const unsigned int maxcolor = 255;
+static const unsigned base = 256;
+static const double blur_radius = 1.5;
+
+static int generate_tables(ass_synth_priv_t* priv, double radius)
+{
+    double A = log(1.0/base)/(radius*radius*2);
+    int mx, i;
+    double volume_diff, volume_factor = 0;
+    unsigned volume;
+    
+    priv->g_r = ceil(radius);
+    priv->g_w = 2*priv->g_r+1;
+
+    if (priv->g_r) {
+       priv->g = malloc(priv->g_w * sizeof(unsigned));
+       priv->gt2 = malloc(256 * priv->g_w * sizeof(unsigned));
+       if (priv->g==NULL || priv->gt2==NULL) {
+           return -1;
+       }
+    }
+
+    if (priv->g_r) {
+       // gaussian curve with volume = 256
+       for (volume_diff=10000000; volume_diff>0.0000001; volume_diff*=0.5){
+           volume_factor+= volume_diff;
+           volume=0;
+           for (i = 0; i<priv->g_w; ++i) {
+               priv->g[i] = (unsigned)(exp(A * (i-priv->g_r)*(i-priv->g_r)) * volume_factor + .5);
+               volume+= priv->g[i];
+           }
+           if(volume>256) volume_factor-= volume_diff;
+       }
+       volume=0;
+       for (i = 0; i<priv->g_w; ++i) {
+           priv->g[i] = (unsigned)(exp(A * (i-priv->g_r)*(i-priv->g_r)) * volume_factor + .5);
+           volume+= priv->g[i];
+       }
+
+       // gauss table:
+       for(mx=0;mx<priv->g_w;mx++){
+           for(i=0;i<256;i++){
+               priv->gt2[mx+i*priv->g_w] = i*priv->g[mx];
+           }
+       }
+    }
+    
+    return 0;
+}
+
+static void resize_tmp(ass_synth_priv_t* priv, int w, int h)
+{
+       if (priv->tmp_w >= w && priv->tmp_h >= h)
+               return;
+       if (priv->tmp_w == 0)
+               priv->tmp_w = 64;
+       if (priv->tmp_h == 0)
+               priv->tmp_h = 64;
+       while (priv->tmp_w < w) priv->tmp_w *= 2;
+       while (priv->tmp_h < h) priv->tmp_h *= 2;
+       if (priv->tmp)
+               free(priv->tmp);
+       priv->tmp = malloc((priv->tmp_w + 1) * priv->tmp_h * sizeof(short));
+}
+
+ass_synth_priv_t* ass_synth_init()
+{
+       ass_synth_priv_t* priv = calloc(1, sizeof(ass_synth_priv_t));
+       generate_tables(priv, blur_radius);
+       return priv;
+}
+
+void ass_synth_done(ass_synth_priv_t* priv)
+{
+       free(priv);
+}
+
 static bitmap_t* alloc_bitmap(int w, int h)
 {
        bitmap_t* bm;
@@ -70,22 +159,34 @@ static bitmap_t* glyph_to_bitmap_internal(FT_Glyph glyph, int bord)
        return bm;
 }
 
-int glyph_to_bitmap(FT_Glyph glyph, FT_Glyph outline_glyph, bitmap_t** bm_g, bitmap_t** bm_o)
+int glyph_to_bitmap(ass_synth_priv_t* priv, FT_Glyph glyph, FT_Glyph outline_glyph, bitmap_t** bm_g, bitmap_t** bm_o, int be)
 {
+       const int bord = ceil(blur_radius);
+
        assert(bm_g);
 
        if (glyph)
-               *bm_g = glyph_to_bitmap_internal(glyph, 0);
+               *bm_g = glyph_to_bitmap_internal(glyph, bord);
        if (!*bm_g)
                return 1;
        if (outline_glyph && bm_o) {
-               *bm_o = glyph_to_bitmap_internal(outline_glyph, 0);
+               *bm_o = glyph_to_bitmap_internal(outline_glyph, bord);
                if (!*bm_o) {
                        ass_free_bitmap(*bm_g);
                        return 1;
                }
        }
 
+       if (bm_o)
+               resize_tmp(priv, (*bm_o)->w, (*bm_o)->h);
+       resize_tmp(priv, (*bm_g)->w, (*bm_g)->h);
+       
+       if (be) {
+               blur((*bm_g)->buffer, priv->tmp, (*bm_g)->w, (*bm_g)->h, (*bm_g)->w, (int*)priv->gt2, priv->g_r, priv->g_w);
+               if (bm_o)
+                       blur((*bm_o)->buffer, priv->tmp, (*bm_o)->w, (*bm_o)->h, (*bm_o)->w, (int*)priv->gt2, priv->g_r, priv->g_w);
+       }
+
        return 0;
 }
 
index edf4790..7a6d7d4 100644 (file)
@@ -1,13 +1,18 @@
 #ifndef __ASS_BITMAP_H__
 #define __ASS_BITMAP_H__
 
+typedef struct ass_synth_priv_s ass_synth_priv_t;
+
+ass_synth_priv_t* ass_synth_init();
+void ass_synth_done(ass_synth_priv_t* priv);
+
 typedef struct bitmap_s {
        int left, top;
        int w, h; // width, height
        unsigned char* buffer; // w x h buffer
 } bitmap_t;
 
-int glyph_to_bitmap(FT_Glyph glyph, FT_Glyph outline_glyph, bitmap_t** bm_g, bitmap_t** bm_o);
+int glyph_to_bitmap(ass_synth_priv_t* priv, FT_Glyph glyph, FT_Glyph outline_glyph, bitmap_t** bm_g, bitmap_t** bm_o, int be);
 void ass_free_bitmap(bitmap_t* bm);
 
 #endif
index 2dce591..a4f4be6 100644 (file)
@@ -131,6 +131,7 @@ static unsigned glyph_hash(glyph_hash_key_t* key) {
        val <<= 21;
        
        if (key->bitmap)   val &= 0x80000000;
+       if (key->be) val &= 0x40000000;
        val += key->index;
        val += key->size << 8;
        val += key->outline << 3;
index f24886e..b17fcdb 100644 (file)
@@ -26,6 +26,7 @@ typedef struct glyph_hash_key_s {
        int index; // glyph index in the face
        unsigned outline; // border width, 16.16 fixed point value
        int bold, italic;
+       char be; // blur edges
 
        // the following affects bitmap glyphs only
        unsigned scale_x, scale_y; // 16.16
index e0096ca..d0def4b 100644 (file)
@@ -38,6 +38,7 @@ struct ass_instance_s {
        fc_instance_t* fontconfig_priv;
        ass_settings_t settings;
        int render_id;
+       ass_synth_priv_t* synth_priv;
 
        ass_image_t* images_root; // rendering result is stored here
 };
@@ -66,6 +67,7 @@ typedef struct glyph_info_s {
        int effect_skip_timing; // delay after the end of last karaoke word
        int asc, desc; // font max ascender and descender
 //     int height;
+       int be; // blur edges
        
        glyph_hash_key_t hash_key;
 } glyph_info_t;
@@ -110,6 +112,7 @@ typedef struct render_context_s {
        int clip_x0, clip_y0, clip_x1, clip_y1;
        char detect_collisions;
        uint32_t fade; // alpha from \fad
+       char be; // blur edges
 
        effect_t effect_type;
        int effect_timing;
@@ -226,6 +229,8 @@ ass_instance_t* ass_init(void)
                goto ass_init_exit;
        }
 
+       priv->synth_priv = ass_synth_init();
+
        priv->library = ft;
        priv->fontconfig_priv = fc_priv;
        // images_root and related stuff is zero-filled in calloc
@@ -248,6 +253,7 @@ void ass_done(ass_instance_t* priv)
        ass_glyph_cache_done();
        if (priv && priv->library) FT_Done_FreeType(priv->library);
        if (priv && priv->fontconfig_priv) fontconfig_done(priv->fontconfig_priv);
+       if (priv && priv->synth_priv) ass_synth_done(priv->synth_priv);
        if (priv) free(priv);
        if (text_info.glyphs) free(text_info.glyphs);
 }
@@ -367,8 +373,9 @@ static ass_image_t* render_text(text_info_t* text_info, int dst_x, int dst_y)
                if (text_info->glyphs[i].glyph) {
                        if ((text_info->glyphs[i].symbol == '\n') || (text_info->glyphs[i].symbol == 0))
                                continue;
-                       error = glyph_to_bitmap(text_info->glyphs[i].glyph, text_info->glyphs[i].outline_glyph,
-                                       &text_info->glyphs[i].bm, &text_info->glyphs[i].bm_o);
+                       error = glyph_to_bitmap(ass_instance->synth_priv,
+                                       text_info->glyphs[i].glyph, text_info->glyphs[i].outline_glyph,
+                                       &text_info->glyphs[i].bm, &text_info->glyphs[i].bm_o, text_info->glyphs[i].be);
                        if (error)
                                text_info->glyphs[i].symbol = 0;
                        FT_Done_Glyph(text_info->glyphs[i].glyph);
@@ -940,7 +947,10 @@ static char* parse_tag(char* p, double pwr) {
                // FIXME: does not reset unsupported attributes.
        } else if (mystrcmp(&p, "be")) {
                int val;
-               mystrtoi(&p, 10, &val);
+               if (mystrtoi(&p, 10, &val))
+                       render_context.be = val ? 1 : 0;
+               else
+                       render_context.be = 0;
                mp_msg(MSGT_GLOBAL, MSGL_V, "be unimplemented \n");
        } else if (mystrcmp(&p, "b")) {
                int b;
@@ -1130,6 +1140,7 @@ static int init_render_context(ass_event_t* event)
        render_context.effect_type = EF_NONE;
        render_context.effect_timing = 0;
        render_context.effect_skip_timing = 0;
+       render_context.be = 0;
        
        if (render_context.family)
                free(render_context.family);
@@ -1193,6 +1204,7 @@ static int get_glyph(int index, int symbol, glyph_info_t* info, FT_Vector* advan
        key->advance = *advance;
        key->bold = render_context.bold;
        key->italic = render_context.italic;
+       key->be = render_context.be;
 
        val = cache_find_glyph(key);
 //     val = 0;
@@ -1602,6 +1614,7 @@ static int ass_render_event(ass_event_t* event, event_images_t* event_images)
                text_info.glyphs[text_info.length].effect_skip_timing = render_context.effect_skip_timing;
                text_info.glyphs[text_info.length].asc = get_face_ascender(render_context.face);
                text_info.glyphs[text_info.length].desc = get_face_descender(render_context.face);
+               text_info.glyphs[text_info.length].be = render_context.be;
 
                text_info.length++;