From: eugeni Date: Sat, 16 Sep 2006 13:32:46 +0000 (+0000) Subject: Add \be (blur edges) support to libass. X-Git-Tag: 0.9.7~448 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=bf0cb3bdf8d4829f41f4a340e18e9603f8088f86;p=libass Add \be (blur edges) support to libass. git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@19854 b3059339-0415-0410-9bf9-f77b7e298cf2 --- diff --git a/libass/ass_bitmap.c b/libass/ass_bitmap.c index 9d98ec0..c7d5f78 100644 --- a/libass/ass_bitmap.c +++ b/libass/ass_bitmap.c @@ -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; ig_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; ig_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;mxg_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; } diff --git a/libass/ass_bitmap.h b/libass/ass_bitmap.h index edf4790..7a6d7d4 100644 --- a/libass/ass_bitmap.h +++ b/libass/ass_bitmap.h @@ -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 diff --git a/libass/ass_cache.c b/libass/ass_cache.c index 2dce591..a4f4be6 100644 --- a/libass/ass_cache.c +++ b/libass/ass_cache.c @@ -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; diff --git a/libass/ass_cache.h b/libass/ass_cache.h index f24886e..b17fcdb 100644 --- a/libass/ass_cache.h +++ b/libass/ass_cache.h @@ -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 diff --git a/libass/ass_render.c b/libass/ass_render.c index e0096ca..d0def4b 100644 --- a/libass/ass_render.c +++ b/libass/ass_render.c @@ -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++;