From 867aa92076b8b4264e8e1a3378a1b6ed076da7f0 Mon Sep 17 00:00:00 2001 From: eugeni Date: Sat, 16 Sep 2006 13:08:17 +0000 Subject: Store bitmap glyphs in a separate struct, instead of FreeType's internal buffer. This is required for various bitmap modifications (like blur, outline and shadow). git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@19852 b3059339-0415-0410-9bf9-f77b7e298cf2 --- libass/Makefile | 2 +- libass/ass_bitmap.c | 91 +++++++++++++++++++++++++++++++++++++++++++++ libass/ass_bitmap.h | 14 +++++++ libass/ass_cache.c | 6 ++- libass/ass_cache.h | 4 +- libass/ass_render.c | 104 ++++++++++++++++++++++------------------------------ 6 files changed, 156 insertions(+), 65 deletions(-) create mode 100644 libass/ass_bitmap.c create mode 100644 libass/ass_bitmap.h (limited to 'libass') diff --git a/libass/Makefile b/libass/Makefile index 3385a4c067..070c8529be 100644 --- a/libass/Makefile +++ b/libass/Makefile @@ -5,7 +5,7 @@ LIBNAME=libass.a LIBS=$(LIBNAME) -SRCS=ass.c ass_cache.c ass_fontconfig.c ass_render.c ass_utils.c ass_mp.c +SRCS=ass.c ass_cache.c ass_fontconfig.c ass_render.c ass_utils.c ass_mp.c ass_bitmap.c OBJS=$(SRCS:.c=.o) diff --git a/libass/ass_bitmap.c b/libass/ass_bitmap.c new file mode 100644 index 0000000000..9d98ec000a --- /dev/null +++ b/libass/ass_bitmap.c @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include +#include FT_GLYPH_H + +#include "mp_msg.h" +#include "ass_bitmap.h" + +static bitmap_t* alloc_bitmap(int w, int h) +{ + bitmap_t* bm; + bm = calloc(1, sizeof(bitmap_t)); + bm->buffer = malloc(w*h); + bm->w = w; + bm->h = h; + bm->left = bm->top = 0; + return bm; +} + +void ass_free_bitmap(bitmap_t* bm) +{ + if (bm) { + if (bm->buffer) free(bm->buffer); + free(bm); + } +} + +static bitmap_t* glyph_to_bitmap_internal(FT_Glyph glyph, int bord) +{ + FT_BitmapGlyph bg; + FT_Bitmap* bit; + bitmap_t* bm; + int w, h; + unsigned char* src; + unsigned char* dst; + int i; + int error; + + error = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 0); + if (error) { + mp_msg(MSGT_GLOBAL, MSGL_WARN, "FT_Glyph_To_Bitmap error %d \n", error); + return 0; + } + + bg = (FT_BitmapGlyph)glyph; + bit = &(bg->bitmap); + if (bit->pixel_mode != FT_PIXEL_MODE_GRAY) { + mp_msg(MSGT_GLOBAL, MSGL_WARN, "Unsupported pixel mode: %d\n", (int)(bit->pixel_mode)); + FT_Done_Glyph(glyph); + return 0; + } + + w = bit->width; + h = bit->rows; + bm = alloc_bitmap(w + 2*bord, h + 2*bord); + memset(bm->buffer, 0, bm->w * bm->h); + bm->left = bg->left - bord; + bm->top = - bg->top - bord; + + src = bit->buffer; + dst = bm->buffer + bord + bm->w * bord; + for (i = 0; i < h; ++i) { + memcpy(dst, src, w); + src += bit->pitch; + dst += bm->w; + } + + return bm; +} + +int glyph_to_bitmap(FT_Glyph glyph, FT_Glyph outline_glyph, bitmap_t** bm_g, bitmap_t** bm_o) +{ + assert(bm_g); + + if (glyph) + *bm_g = glyph_to_bitmap_internal(glyph, 0); + if (!*bm_g) + return 1; + if (outline_glyph && bm_o) { + *bm_o = glyph_to_bitmap_internal(outline_glyph, 0); + if (!*bm_o) { + ass_free_bitmap(*bm_g); + return 1; + } + } + + return 0; +} + diff --git a/libass/ass_bitmap.h b/libass/ass_bitmap.h new file mode 100644 index 0000000000..edf4790584 --- /dev/null +++ b/libass/ass_bitmap.h @@ -0,0 +1,14 @@ +#ifndef __ASS_BITMAP_H__ +#define __ASS_BITMAP_H__ + +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); +void ass_free_bitmap(bitmap_t* bm); + +#endif + diff --git a/libass/ass_cache.c b/libass/ass_cache.c index 64f915becf..2dce591d93 100644 --- a/libass/ass_cache.c +++ b/libass/ass_cache.c @@ -2,11 +2,13 @@ #include #include FT_FREETYPE_H +#include FT_GLYPH_H #include #include "mp_msg.h" #include "ass_fontconfig.h" +#include "ass_bitmap.h" #include "ass_cache.h" @@ -197,8 +199,8 @@ void ass_glyph_cache_done(void) glyph_hash_item_t* item = glyph_hash_root[i]; while (item) { glyph_hash_item_t* next = item->next; - if (item->val.glyph) FT_Done_Glyph(item->val.glyph); - if (item->val.outline_glyph) FT_Done_Glyph(item->val.outline_glyph); + if (item->val.bm) ass_free_bitmap(item->val.bm); + if (item->val.bm_o) ass_free_bitmap(item->val.bm_o); free(item); item = next; } diff --git a/libass/ass_cache.h b/libass/ass_cache.h index 68f57296bf..f24886e873 100644 --- a/libass/ass_cache.h +++ b/libass/ass_cache.h @@ -35,8 +35,8 @@ typedef struct glyph_hash_key_s { } glyph_hash_key_t; typedef struct glyph_hash_val_s { - FT_Glyph glyph; // the actual glyphs - FT_Glyph outline_glyph; + bitmap_t* bm; // the actual glyph bitmaps + bitmap_t* bm_o; 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 6aee3cd8d4..e0096ca219 100644 --- a/libass/ass_render.c +++ b/libass/ass_render.c @@ -12,6 +12,7 @@ #include "mp_msg.h" #include "ass.h" +#include "ass_bitmap.h" #include "ass_cache.h" #include "ass_utils.h" #include "ass_fontconfig.h" @@ -51,11 +52,12 @@ typedef struct glyph_info_s { unsigned symbol; FT_Glyph glyph; FT_Glyph outline_glyph; + bitmap_t* bm; + bitmap_t* bm_o; FT_BBox bbox; FT_Vector pos; char linebreak; // the first (leading) glyph of some line ? uint32_t c[4]; // colors - char bitmap; // bool FT_Vector advance; // 26.6 effect_t effect_type; int effect_timing; // time duration of current karaoke word @@ -223,6 +225,7 @@ ass_instance_t* ass_init(void) fontconfig_done(fc_priv); goto ass_init_exit; } + priv->library = ft; priv->fontconfig_priv = fc_priv; // images_root and related stuff is zero-filled in calloc @@ -280,7 +283,7 @@ static ass_image_t* my_draw_bitmap(unsigned char* bitmap, int bitmap_w, int bitm * \return pointer to the new list tail * Performs clipping. Uses my_draw_bitmap for actual bitmap convertion. */ -static ass_image_t** render_glyph(FT_BitmapGlyph bit, int dst_x, int dst_y, uint32_t color, uint32_t color2, int brk, ass_image_t** tail) +static ass_image_t** render_glyph(bitmap_t* bm, int dst_x, int dst_y, uint32_t color, uint32_t color2, int brk, ass_image_t** tail) { // brk is relative to dst_x // color = color left of brk @@ -288,19 +291,12 @@ static ass_image_t** render_glyph(FT_BitmapGlyph bit, int dst_x, int dst_y, uint int b_x0, b_y0, b_x1, b_y1; // visible part of the bitmap int clip_x0, clip_y0, clip_x1, clip_y1; int tmp; - FT_Bitmap* bitmap; ass_image_t* img; - bitmap = &(bit->bitmap); - dst_x += bit->left; - dst_y -= bit->top; - brk -= bit->left; + dst_x += bm->left; + dst_y += bm->top; + brk -= bm->left; - if (bitmap->pixel_mode != FT_PIXEL_MODE_GRAY) { - mp_msg(MSGT_GLOBAL, MSGL_WARN, "Unsupported pixel mode: %d\n", (int)(bitmap->pixel_mode)); - return tail; - } - // clipping clip_x0 = render_context.clip_x0; clip_y0 = render_context.clip_y0; @@ -308,8 +304,8 @@ static ass_image_t** render_glyph(FT_BitmapGlyph bit, int dst_x, int dst_y, uint clip_y1 = render_context.clip_y1; b_x0 = 0; b_y0 = 0; - b_x1 = bitmap->width; - b_y1 = bitmap->rows; + b_x1 = bm->w; + b_y1 = bm->h; tmp = dst_x - clip_x0; if (tmp < 0) { @@ -321,15 +317,15 @@ static ass_image_t** render_glyph(FT_BitmapGlyph bit, int dst_x, int dst_y, uint mp_msg(MSGT_GLOBAL, MSGL_DBG2, "clip top\n"); b_y0 = - tmp; } - tmp = clip_x1 - dst_x - bitmap->width; + tmp = clip_x1 - dst_x - bm->w; if (tmp < 0) { mp_msg(MSGT_GLOBAL, MSGL_DBG2, "clip right\n"); - b_x1 = bitmap->width + tmp; + b_x1 = bm->w + tmp; } - tmp = clip_y1 - dst_y - bitmap->rows; + tmp = clip_y1 - dst_y - bm->h; if (tmp < 0) { mp_msg(MSGT_GLOBAL, MSGL_DBG2, "clip bottom\n"); - b_y1 = bitmap->rows + tmp; + b_y1 = bm->h + tmp; } if ((b_y0 >= b_y1) || (b_x0 >= b_x1)) @@ -337,16 +333,16 @@ static ass_image_t** render_glyph(FT_BitmapGlyph bit, int dst_x, int dst_y, uint if (brk > b_x0) { // draw left part if (brk > b_x1) brk = b_x1; - img = my_draw_bitmap(bitmap->buffer + bitmap->pitch * b_y0 + b_x0, - brk - b_x0, b_y1 - b_y0, bitmap->pitch, + img = my_draw_bitmap(bm->buffer + bm->w * b_y0 + b_x0, + brk - b_x0, b_y1 - b_y0, bm->w, dst_x + b_x0, dst_y + b_y0, color); *tail = img; tail = &img->next; } if (brk < b_x1) { // draw right part if (brk < b_x0) brk = b_x0; - img = my_draw_bitmap(bitmap->buffer + bitmap->pitch * b_y0 + brk, - b_x1 - brk, b_y1 - b_y0, bitmap->pitch, + img = my_draw_bitmap(bm->buffer + bm->w * b_y0 + brk, + b_x1 - brk, b_y1 - b_y0, bm->w, dst_x + brk, dst_y + b_y0, color2); *tail = img; tail = &img->next; @@ -361,37 +357,31 @@ static ass_image_t** render_glyph(FT_BitmapGlyph bit, int dst_x, int dst_y, uint static ass_image_t* render_text(text_info_t* text_info, int dst_x, int dst_y) { int pen_x, pen_y; - int error, error2; - int i; - FT_Glyph image; - FT_BitmapGlyph bit; + int i, error; + bitmap_t* bm; glyph_hash_val_t hash_val; ass_image_t* head; ass_image_t** tail = &head; for (i = 0; i < text_info->length; ++i) { - if (text_info->glyphs[i].bitmap != 1) { + if (text_info->glyphs[i].glyph) { if ((text_info->glyphs[i].symbol == '\n') || (text_info->glyphs[i].symbol == 0)) continue; - error = FT_Glyph_To_Bitmap( &(text_info->glyphs[i].outline_glyph), FT_RENDER_MODE_NORMAL, 0, 1); - error2 = FT_Glyph_To_Bitmap( &(text_info->glyphs[i].glyph), FT_RENDER_MODE_NORMAL, 0, 1); - - if (error || error2) { - FT_Done_Glyph(text_info->glyphs[i].outline_glyph); - FT_Done_Glyph(text_info->glyphs[i].glyph); - mp_msg(MSGT_GLOBAL, MSGL_WARN, "FT_Glyph_To_Bitmap error %d %d, symbol %d, index %d\n", - error, error2, text_info->glyphs[i].symbol, text_info->glyphs[i].hash_key.index); - text_info->glyphs[i].symbol = 0; // do not render - 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); + if (error) + text_info->glyphs[i].symbol = 0; + FT_Done_Glyph(text_info->glyphs[i].glyph); + FT_Done_Glyph(text_info->glyphs[i].outline_glyph); + // cache - text_info->glyphs[i].hash_key.bitmap = 1; // other hash_key fields were set in get_glyph() hash_val.bbox_scaled = text_info->glyphs[i].bbox; - hash_val.outline_glyph = text_info->glyphs[i].outline_glyph; - hash_val.glyph = text_info->glyphs[i].glyph; + hash_val.bm_o = text_info->glyphs[i].bm_o; + hash_val.bm = text_info->glyphs[i].bm; 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); + } } @@ -402,13 +392,12 @@ static ass_image_t* render_text(text_info_t* text_info, int dst_x, int dst_y) pen_x = dst_x + info->pos.x; pen_y = dst_y + info->pos.y; - image = info->outline_glyph; - bit = (FT_BitmapGlyph)image; + bm = info->bm_o; if ((info->effect_type == EF_KARAOKE_KO) && (info->effect_timing <= info->bbox.xMax)) { // do nothing } else - tail = render_glyph(bit, pen_x, pen_y, info->c[2], 0, 1000000, tail); + tail = render_glyph(bm, pen_x, pen_y, info->c[2], 0, 1000000, tail); } for (i = 0; i < text_info->length; ++i) { glyph_info_t* info = text_info->glyphs + i; @@ -417,18 +406,17 @@ static ass_image_t* render_text(text_info_t* text_info, int dst_x, int dst_y) pen_x = dst_x + info->pos.x; pen_y = dst_y + info->pos.y; - image = info->glyph; - bit = (FT_BitmapGlyph)image; + bm = info->bm; if ((info->effect_type == EF_KARAOKE) || (info->effect_type == EF_KARAOKE_KO)) { if (info->effect_timing > info->bbox.xMax) - tail = render_glyph(bit, pen_x, pen_y, info->c[0], 0, 1000000, tail); + tail = render_glyph(bm, pen_x, pen_y, info->c[0], 0, 1000000, tail); else - tail = render_glyph(bit, pen_x, pen_y, info->c[1], 0, 1000000, tail); + tail = render_glyph(bm, pen_x, pen_y, info->c[1], 0, 1000000, tail); } else if (info->effect_type == EF_KARAOKE_KF) { - tail = render_glyph(bit, pen_x, pen_y, info->c[0], info->c[1], info->effect_timing, tail); + tail = render_glyph(bm, pen_x, pen_y, info->c[0], info->c[1], info->effect_timing, tail); } else - tail = render_glyph(bit, pen_x, pen_y, info->c[0], 0, 1000000, tail); + tail = render_glyph(bm, pen_x, pen_y, info->c[0], 0, 1000000, tail); } *tail = 0; @@ -1206,20 +1194,16 @@ static int get_glyph(int index, int symbol, glyph_info_t* info, FT_Vector* advan key->bold = render_context.bold; key->italic = render_context.italic; - key->bitmap = 1; // looking for bitmap glyph - - val = cache_find_glyph(key); // val = 0; if (val) { - // bitmap glyph found, no need for FT_Glyph_Copy - info->glyph = val->glyph; - info->outline_glyph = val->outline_glyph; + info->glyph = info->outline_glyph = 0; + info->bm = val->bm; + info->bm_o = val->bm_o; info->bbox = val->bbox_scaled; info->advance.x = val->advance.x; info->advance.y = val->advance.y; - info->bitmap = 1; // bitmap glyph return 0; } @@ -1258,7 +1242,7 @@ static int get_glyph(int index, int symbol, glyph_info_t* info, FT_Vector* advan FT_Glyph_Copy(info->glyph, &info->outline_glyph); } - info->bitmap = 0; // outline glyph + info->bm = info->bm_o = 0; return 0; } @@ -1599,7 +1583,7 @@ static int ass_render_event(ass_event_t* event, event_images_t* event_images) pen.y += text_info.glyphs[text_info.length].advance.y; // if it's an outline glyph, we still need to fill the bbox - if (text_info.glyphs[text_info.length].bitmap != 1) { + if (text_info.glyphs[text_info.length].glyph) { FT_Glyph_Get_CBox( text_info.glyphs[text_info.length].glyph, FT_GLYPH_BBOX_PIXELS, &(text_info.glyphs[text_info.length].bbox) ); } @@ -1822,7 +1806,7 @@ static int ass_render_event(ass_event_t* event, event_images_t* event_images) info->pos.y -= start.y >> 6; // mp_msg(MSGT_GLOBAL, MSGL_DBG2, "shift: %d, %d\n", start.x / 64, start.y / 64); - if (info->bitmap != 1) { + if (info->glyph) { FT_Glyph_Transform( info->glyph, &matrix_rotate, 0 ); FT_Glyph_Transform( info->outline_glyph, &matrix_rotate, 0 ); } -- cgit v1.2.3