From 1b0251e7ad18ad4bc3772487e1e4abe237cd1752 Mon Sep 17 00:00:00 2001 From: eugeni Date: Sun, 24 Sep 2006 16:04:37 +0000 Subject: Shadow support in libass. git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@19971 b3059339-0415-0410-9bf9-f77b7e298cf2 --- libass/ass_bitmap.c | 39 ++++++++++++++++++++++++++++++--------- libass/ass_bitmap.h | 2 +- libass/ass_cache.c | 1 + libass/ass_cache.h | 1 + libass/ass_render.c | 34 ++++++++++++++++++++++++++++++---- 5 files changed, 63 insertions(+), 14 deletions(-) diff --git a/libass/ass_bitmap.c b/libass/ass_bitmap.c index df98f5a733..8eee401205 100644 --- a/libass/ass_bitmap.c +++ b/libass/ass_bitmap.c @@ -122,6 +122,15 @@ void ass_free_bitmap(bitmap_t* bm) } } +static bitmap_t* copy_bitmap(const bitmap_t* src) +{ + bitmap_t* dst = alloc_bitmap(src->w, src->h); + dst->left = src->left; + dst->top = src->top; + memcpy(dst->buffer, src->buffer, src->w * src->h); + return dst; +} + static bitmap_t* glyph_to_bitmap_internal(FT_Glyph glyph, int bord) { FT_BitmapGlyph bg; @@ -165,15 +174,19 @@ static bitmap_t* glyph_to_bitmap_internal(FT_Glyph glyph, int bord) return bm; } -static void fix_outline(bitmap_t* bm_g, bitmap_t* bm_o) +static bitmap_t* fix_outline_and_shadow(bitmap_t* bm_g, bitmap_t* bm_o) { int x, y; const int l = bm_o->left > bm_g->left ? bm_o->left : bm_g->left; const int t = bm_o->top > bm_g->top ? bm_o->top : bm_g->top; const int r = bm_o->left + bm_o->w < bm_g->left + bm_g->w ? bm_o->left + bm_o->w : bm_g->left + bm_g->w; const int b = bm_o->top + bm_o->h < bm_g->top + bm_g->h ? bm_o->top + bm_o->h : bm_g->top + bm_g->h; + + bitmap_t* bm_s = copy_bitmap(bm_o); + unsigned char* g = bm_g->buffer + (t - bm_g->top) * bm_g->w + (l - bm_g->left); unsigned char* o = bm_o->buffer + (t - bm_o->top) * bm_o->w + (l - bm_o->left); + unsigned char* s = bm_s->buffer + (t - bm_s->top) * bm_s->w + (l - bm_s->left); for (y = 0; y < b - t; ++y) { for (x = 0; x < r - l; ++x) { @@ -181,33 +194,38 @@ static void fix_outline(bitmap_t* bm_g, bitmap_t* bm_o) c_g = g[x]; c_o = o[x]; o[x] = (c_o > c_g) ? c_o - c_g : 0; + s[x] = (c_o < 0xFF - c_g) ? c_o + c_g : 0xFF; } g += bm_g->w; o += bm_o->w; + s += bm_s->w; } + + assert(bm_s); + return bm_s; } -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) +int glyph_to_bitmap(ass_synth_priv_t* priv, FT_Glyph glyph, FT_Glyph outline_glyph, + bitmap_t** bm_g, bitmap_t** bm_o, bitmap_t** bm_s, int be) { const int bord = be ? ceil(blur_radius) : 0; - assert(bm_g && bm_o); + assert(bm_g && bm_o && bm_s); + + *bm_g = *bm_o = *bm_s = 0; if (glyph) *bm_g = glyph_to_bitmap_internal(glyph, bord); - else - *bm_g = 0; if (!*bm_g) return 1; + if (outline_glyph) { *bm_o = glyph_to_bitmap_internal(outline_glyph, bord); if (!*bm_o) { ass_free_bitmap(*bm_g); return 1; } - } else - *bm_o = 0; - + } if (*bm_o) resize_tmp(priv, (*bm_o)->w, (*bm_o)->h); resize_tmp(priv, (*bm_g)->w, (*bm_g)->h); @@ -219,8 +237,11 @@ int glyph_to_bitmap(ass_synth_priv_t* priv, FT_Glyph glyph, FT_Glyph outline_gly } if (*bm_o) - fix_outline(*bm_g, *bm_o); + *bm_s = fix_outline_and_shadow(*bm_g, *bm_o); + else + *bm_s = copy_bitmap(*bm_g); + assert(bm_s); return 0; } diff --git a/libass/ass_bitmap.h b/libass/ass_bitmap.h index 7a6d7d459f..0cf2eb2cb1 100644 --- a/libass/ass_bitmap.h +++ b/libass/ass_bitmap.h @@ -12,7 +12,7 @@ typedef struct bitmap_s { unsigned char* buffer; // w x h buffer } bitmap_t; -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); +int glyph_to_bitmap(ass_synth_priv_t* priv, FT_Glyph glyph, FT_Glyph outline_glyph, bitmap_t** bm_g, bitmap_t** bm_o, bitmap_t** bm_s, int be); void ass_free_bitmap(bitmap_t* bm); #endif diff --git a/libass/ass_cache.c b/libass/ass_cache.c index a4f4be6169..aaea86b92a 100644 --- a/libass/ass_cache.c +++ b/libass/ass_cache.c @@ -202,6 +202,7 @@ void ass_glyph_cache_done(void) glyph_hash_item_t* next = item->next; if (item->val.bm) ass_free_bitmap(item->val.bm); if (item->val.bm_o) ass_free_bitmap(item->val.bm_o); + if (item->val.bm_s) ass_free_bitmap(item->val.bm_s); free(item); item = next; } diff --git a/libass/ass_cache.h b/libass/ass_cache.h index b17fcdb2e8..1a7aa8038e 100644 --- a/libass/ass_cache.h +++ b/libass/ass_cache.h @@ -38,6 +38,7 @@ typedef struct glyph_hash_key_s { typedef struct glyph_hash_val_s { bitmap_t* bm; // the actual glyph bitmaps bitmap_t* bm_o; + bitmap_t* bm_s; FT_BBox bbox_scaled; // bbox after scaling, but before rotation FT_Vector advance; // 26.6, advance distance to the next glyph in line } glyph_hash_val_t; diff --git a/libass/ass_render.c b/libass/ass_render.c index b35f643054..8a62a3a067 100644 --- a/libass/ass_render.c +++ b/libass/ass_render.c @@ -53,8 +53,9 @@ typedef struct glyph_info_s { unsigned symbol; FT_Glyph glyph; FT_Glyph outline_glyph; - bitmap_t* bm; - bitmap_t* bm_o; + bitmap_t* bm; // glyph bitmap + bitmap_t* bm_o; // outline bitmap + bitmap_t* bm_s; // shadow bitmap FT_BBox bbox; FT_Vector pos; char linebreak; // the first (leading) glyph of some line ? @@ -68,6 +69,7 @@ typedef struct glyph_info_s { int asc, desc; // font max ascender and descender // int height; int be; // blur edges + int shadow; glyph_hash_key_t hash_key; } glyph_info_t; @@ -113,6 +115,7 @@ typedef struct render_context_s { char detect_collisions; uint32_t fade; // alpha from \fad char be; // blur edges + int shadow; effect_t effect_type; int effect_timing; @@ -376,7 +379,8 @@ static ass_image_t* render_text(text_info_t* text_info, int dst_x, int dst_y) continue; 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); + &text_info->glyphs[i].bm, &text_info->glyphs[i].bm_o, + &text_info->glyphs[i].bm_s, text_info->glyphs[i].be); if (error) text_info->glyphs[i].symbol = 0; FT_Done_Glyph(text_info->glyphs[i].glyph); @@ -387,6 +391,7 @@ static ass_image_t* render_text(text_info_t* text_info, int dst_x, int dst_y) hash_val.bbox_scaled = text_info->glyphs[i].bbox; hash_val.bm_o = text_info->glyphs[i].bm_o; hash_val.bm = text_info->glyphs[i].bm; + hash_val.bm_s = text_info->glyphs[i].bm_s; hash_val.advance.x = text_info->glyphs[i].advance.x; hash_val.advance.y = text_info->glyphs[i].advance.y; cache_add_glyph(&(text_info->glyphs[i].hash_key), &hash_val); @@ -394,6 +399,18 @@ static ass_image_t* render_text(text_info_t* text_info, int dst_x, int dst_y) } } + for (i = 0; i < text_info->length; ++i) { + glyph_info_t* info = text_info->glyphs + i; + if ((info->symbol == 0) || (info->symbol == '\n') || !info->bm_s || (info->shadow == 0)) + continue; + + pen_x = dst_x + info->pos.x + info->shadow; + pen_y = dst_y + info->pos.y + info->shadow; + bm = info->bm_s; + + tail = render_glyph(bm, pen_x, pen_y, info->c[3], 0, 1000000, tail); + } + for (i = 0; i < text_info->length; ++i) { glyph_info_t* info = text_info->glyphs + i; if ((info->symbol == 0) || (info->symbol == '\n') || !info->bm_o) @@ -992,6 +1009,12 @@ static char* parse_tag(char* p, double pwr) { if (render_context.effect_timing) render_context.effect_skip_timing += render_context.effect_timing; render_context.effect_timing = val * 10; + } else if (mystrcmp(&p, "shad")) { + int val; + if (mystrtoi(&p, 10, &val)) + render_context.shadow = val; + else + render_context.shadow = render_context.style->Shadow; } return p; @@ -1137,6 +1160,7 @@ static void reset_render_context(void) render_context.scale_y = render_context.style->ScaleY; render_context.hspacing = 0; // FIXME render_context.be = 0; + render_context.shadow = render_context.style->Shadow; // FIXME: does not reset unsupported attributes. } @@ -1208,6 +1232,7 @@ static int get_glyph(int index, int symbol, glyph_info_t* info, FT_Vector* advan info->glyph = info->outline_glyph = 0; info->bm = val->bm; info->bm_o = val->bm_o; + info->bm_s = val->bm_s; info->bbox = val->bbox_scaled; info->advance.x = val->advance.x; info->advance.y = val->advance.y; @@ -1252,7 +1277,7 @@ static int get_glyph(int index, int symbol, glyph_info_t* info, FT_Vector* advan info->outline_glyph = 0; } - info->bm = info->bm_o = 0; + info->bm = info->bm_o = info->bm_s = 0; return 0; } @@ -1625,6 +1650,7 @@ static int ass_render_event(ass_event_t* event, event_images_t* event_images) 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.glyphs[text_info.length].shadow = render_context.shadow; text_info.length++; -- cgit v1.2.3