changeset 19848:07be98a5dd5f

Add \be (blur edges) support to libass.
author eugeni
date Sat, 16 Sep 2006 13:32:46 +0000
parents d7c2e093e406
children f4504b07bdbd
files libass/ass_bitmap.c libass/ass_bitmap.h libass/ass_cache.c libass/ass_cache.h libass/ass_render.c
diffstat 5 files changed, 128 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/libass/ass_bitmap.c	Sat Sep 16 13:32:19 2006 +0000
+++ b/libass/ass_bitmap.c	Sat Sep 16 13:32:46 2006 +0000
@@ -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 @@
 	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;
 }
 
--- a/libass/ass_bitmap.h	Sat Sep 16 13:32:19 2006 +0000
+++ b/libass/ass_bitmap.h	Sat Sep 16 13:32:46 2006 +0000
@@ -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
--- a/libass/ass_cache.c	Sat Sep 16 13:32:19 2006 +0000
+++ b/libass/ass_cache.c	Sat Sep 16 13:32:46 2006 +0000
@@ -131,6 +131,7 @@
 	val <<= 21;
 	
 	if (key->bitmap)   val &= 0x80000000;
+	if (key->be) val &= 0x40000000;
 	val += key->index;
 	val += key->size << 8;
 	val += key->outline << 3;
--- a/libass/ass_cache.h	Sat Sep 16 13:32:19 2006 +0000
+++ b/libass/ass_cache.h	Sat Sep 16 13:32:46 2006 +0000
@@ -26,6 +26,7 @@
 	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
--- a/libass/ass_render.c	Sat Sep 16 13:32:19 2006 +0000
+++ b/libass/ass_render.c	Sat Sep 16 13:32:46 2006 +0000
@@ -38,6 +38,7 @@
 	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 @@
 	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 @@
 	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 @@
 		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 @@
 	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 @@
 		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 @@
 		// 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 @@
 	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 @@
 	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 @@
 		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++;