diff options
author | greg <greg@blackbox> | 2009-06-18 14:16:07 +0200 |
---|---|---|
committer | greg <greg@blackbox> | 2009-06-20 03:37:18 +0200 |
commit | 8aa14b319b8f13bd817a116f27610173de37dae7 (patch) | |
tree | a7fc10e93ce398ea0906aa84cd718a70c1bda587 /libass | |
parent | 7036f4774944d8acd2a175f1171e8c988f8c9d36 (diff) | |
download | libass-8aa14b319b8f13bd817a116f27610173de37dae7.tar.bz2 libass-8aa14b319b8f13bd817a116f27610173de37dae7.tar.xz |
Fix up glyph stroker to avoid buggy rendering.
This adds pre-processing to the stroker which removes certain contours
that'd lead to areas wrongly getting not filled. The approach is very
simple, but works well enough for most cases.
Diffstat (limited to 'libass')
-rw-r--r-- | libass/ass_render.c | 81 |
1 files changed, 79 insertions, 2 deletions
diff --git a/libass/ass_render.c b/libass/ass_render.c index 141de49..00a5f39 100644 --- a/libass/ass_render.c +++ b/libass/ass_render.c @@ -1425,6 +1425,82 @@ static void free_render_context(void) { } +// Calculate the cbox of a series of points +static void get_contour_cbox(FT_BBox *box, FT_Vector *points, int start, int end) { + box->xMin = box->yMin = INT_MAX; + box->xMax = box->yMax = INT_MIN; + int i; + + for (i=start; i<end; i++) { + box->xMin = (points[i].x < box->xMin) ? points[i].x : box->xMin; + box->xMax = (points[i].x > box->xMax) ? points[i].x : box->xMax; + box->yMin = (points[i].y < box->yMin) ? points[i].y : box->yMin; + box->yMax = (points[i].y > box->yMax) ? points[i].y : box->yMax; + } +} + +/** + * \brief Fix-up stroker result for huge borders by removing the contours from + * the outline that are harmful. +*/ +static void fix_freetype_stroker(FT_OutlineGlyph glyph, int border) { + int nc = glyph->outline.n_contours; + int begin, stop; + char modified = 0; + char *valid_cont; + int start = 0; + int end = -1; + FT_BBox *boxes = calloc(nc, sizeof(FT_BBox)); + int i, j; + + // Create a list of cboxes of the contours + for (i=0; i < nc; i++) { + start = end + 1; + end = glyph->outline.contours[i]; + get_contour_cbox(&boxes[i], glyph->outline.points, start, end); + } + + // if a) contour's cbox is contained in another contours cbox + // b) contour's height or width is smaller than the border*2 + // the contour can be safely removed. + valid_cont = calloc(1, nc); + for (i=0; i < nc; i++) { + valid_cont[i] = 1; + for (j=0; j < nc; j++) { + if (i == j) continue; + if (boxes[i].xMin >= boxes[j].xMin && + boxes[i].xMax <= boxes[j].xMax && + boxes[i].yMin >= boxes[j].yMin && + boxes[i].yMax <= boxes[j].yMax) { + int width = boxes[i].xMax - boxes[i].xMin; + int height = boxes[i].yMax - boxes[i].yMin; + if (width < border*2 || height < border*2) { + valid_cont[i] = 0; + modified = 1; + break; + } + } + } + } + + // Zero-out contours that can be removed; much simpler than copying + if (modified) { + for (i=0; i<nc; i++) { + if (valid_cont[i]) continue; + begin = (i == 0) ? 0 : glyph->outline.contours[i-1]+1; + stop = glyph->outline.contours[i]; + for (j=begin; j<=stop; j++) { + glyph->outline.points[j].x = 0; + glyph->outline.points[j].y = 0; + glyph->outline.tags[j] = 0; + } + } + } + + free(boxes); + free(valid_cont); +} + /** * \brief Get normal and outline (border) glyphs * \param symbol ucs4 char @@ -1471,8 +1547,9 @@ static void get_outline_glyph(ass_renderer_t* render_priv, int symbol, glyph_inf FT_Glyph_Get_CBox( info->glyph, FT_GLYPH_BBOX_PIXELS, &info->bbox); if (render_priv->state.stroker) { - info->outline_glyph = info->glyph; - error = FT_Glyph_StrokeBorder( &(info->outline_glyph), render_priv->state.stroker, 0 , 0 ); // don't destroy original + FT_Glyph_Copy(info->glyph, &info->outline_glyph); + fix_freetype_stroker((FT_OutlineGlyph) info->outline_glyph, double_to_d6(render_priv->state.border * render_priv->border_scale)); + error = FT_Glyph_StrokeBorder( &(info->outline_glyph), render_priv->state.stroker, 0 , 1); if (error) { mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_FT_Glyph_Stroke_Error, error); } |