summaryrefslogtreecommitdiffstats
path: root/libavfilter/vf_drawtext.c
diff options
context:
space:
mode:
authorRamiro Polla <ramiro.polla@gmail.com>2014-01-18 03:58:34 -0200
committerMichael Niedermayer <michaelni@gmx.at>2014-01-25 04:59:28 +0100
commit78a9f185eb175e6164b1c0f40d20ff1933ac8fb7 (patch)
treee58e29a7b3dca6b40085e2b8fae57131c85feaca /libavfilter/vf_drawtext.c
parent222fb8276dc4d32b26e939fb130165ddb6d5dddd (diff)
downloadffmpeg-streaming-78a9f185eb175e6164b1c0f40d20ff1933ac8fb7.zip
ffmpeg-streaming-78a9f185eb175e6164b1c0f40d20ff1933ac8fb7.tar.gz
lavfi/drawtext: add option for drawing border around text
Reviewed-by: Stefano Sabatini <stefasab@gmail.com> Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
Diffstat (limited to 'libavfilter/vf_drawtext.c')
-rw-r--r--libavfilter/vf_drawtext.c53
1 files changed, 45 insertions, 8 deletions
diff --git a/libavfilter/vf_drawtext.c b/libavfilter/vf_drawtext.c
index e1e151b..f185c58 100644
--- a/libavfilter/vf_drawtext.c
+++ b/libavfilter/vf_drawtext.c
@@ -50,6 +50,7 @@
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
+#include FT_STROKER_H
#if CONFIG_FONTCONFIG
#include <fontconfig/fontconfig.h>
#endif
@@ -134,6 +135,7 @@ typedef struct {
int max_glyph_w; ///< max glyph width
int max_glyph_h; ///< max glyph height
int shadowx, shadowy;
+ int borderw; ///< border width
unsigned int fontsize; ///< font size to use
short int draw_box; ///< draw box around text - true or false
@@ -144,10 +146,12 @@ typedef struct {
FFDrawContext dc;
FFDrawColor fontcolor; ///< foreground color
FFDrawColor shadowcolor; ///< shadow color
+ FFDrawColor bordercolor; ///< border color
FFDrawColor boxcolor; ///< background color
FT_Library library; ///< freetype font library handle
FT_Face face; ///< freetype font face handle
+ FT_Stroker stroker; ///< freetype stroker handle
struct AVTreeNode *glyphs; ///< rendered glyphs, stored using the UTF-32 char code
char *x_expr; ///< expression for x position
char *y_expr; ///< expression for y position
@@ -178,6 +182,7 @@ static const AVOption drawtext_options[]= {
{"textfile", "set text file", OFFSET(textfile), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS},
{"fontcolor", "set foreground color", OFFSET(fontcolor.rgba), AV_OPT_TYPE_COLOR, {.str="black"}, CHAR_MIN, CHAR_MAX, FLAGS},
{"boxcolor", "set box color", OFFSET(boxcolor.rgba), AV_OPT_TYPE_COLOR, {.str="white"}, CHAR_MIN, CHAR_MAX, FLAGS},
+ {"bordercolor", "set border color", OFFSET(bordercolor.rgba), AV_OPT_TYPE_COLOR, {.str="black"}, CHAR_MIN, CHAR_MAX, FLAGS},
{"shadowcolor", "set shadow color", OFFSET(shadowcolor.rgba), AV_OPT_TYPE_COLOR, {.str="black"}, CHAR_MIN, CHAR_MAX, FLAGS},
{"box", "set box", OFFSET(draw_box), AV_OPT_TYPE_INT, {.i64=0}, 0, 1 , FLAGS},
{"fontsize", "set font size", OFFSET(fontsize), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX , FLAGS},
@@ -185,6 +190,7 @@ static const AVOption drawtext_options[]= {
{"y", "set y expression", OFFSET(y_expr), AV_OPT_TYPE_STRING, {.str="0"}, CHAR_MIN, CHAR_MAX, FLAGS},
{"shadowx", "set x", OFFSET(shadowx), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX , FLAGS},
{"shadowy", "set y", OFFSET(shadowy), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX , FLAGS},
+ {"borderw", "set border width", OFFSET(borderw), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX , FLAGS},
{"tabsize", "set tab size", OFFSET(tabsize), AV_OPT_TYPE_INT, {.i64=4}, 0, INT_MAX , FLAGS},
{"basetime", "set base time", OFFSET(basetime), AV_OPT_TYPE_INT64, {.i64=AV_NOPTS_VALUE}, INT64_MIN, INT64_MAX , FLAGS},
#if FF_API_DRAWTEXT_OLD_TIMELINE
@@ -245,6 +251,7 @@ typedef struct {
FT_Glyph *glyph;
uint32_t code;
FT_Bitmap bitmap; ///< array holding bitmaps of font
+ FT_Bitmap border_bitmap; ///< array holding bitmaps of font border
FT_BBox bbox;
int advance;
int bitmap_left;
@@ -285,6 +292,16 @@ static int load_glyph(AVFilterContext *ctx, Glyph **glyph_ptr, uint32_t code)
ret = AVERROR(EINVAL);
goto error;
}
+ if (s->borderw) {
+ FT_Glyph border_glyph = *glyph->glyph;
+ if (FT_Glyph_StrokeBorder(&border_glyph, s->stroker, 0, 0) ||
+ FT_Glyph_To_Bitmap(&border_glyph, FT_RENDER_MODE_NORMAL, 0, 1)) {
+ ret = AVERROR_EXTERNAL;
+ goto error;
+ }
+ bitmapglyph = (FT_BitmapGlyph) border_glyph;
+ glyph->border_bitmap = bitmapglyph->bitmap;
+ }
if (FT_Glyph_To_Bitmap(glyph->glyph, FT_RENDER_MODE_NORMAL, 0, 1)) {
ret = AVERROR_EXTERNAL;
goto error;
@@ -490,6 +507,15 @@ static av_cold int init(AVFilterContext *ctx)
return AVERROR(EINVAL);
}
+ if (s->borderw) {
+ if (FT_Stroker_New(s->library, &s->stroker)) {
+ av_log(ctx, AV_LOG_ERROR, "Coult not init FT stroker\n");
+ return AVERROR_EXTERNAL;
+ }
+ FT_Stroker_Set(s->stroker, s->borderw << 6, FT_STROKER_LINECAP_ROUND,
+ FT_STROKER_LINEJOIN_ROUND, 0);
+ }
+
s->use_kerning = FT_HAS_KERNING(s->face);
/* load the fallback glyph with code 0 */
@@ -546,6 +572,7 @@ static av_cold void uninit(AVFilterContext *ctx)
s->glyphs = NULL;
FT_Done_Face(s->face);
+ FT_Stroker_Done(s->stroker);
FT_Done_FreeType(s->library);
av_bprint_finalize(&s->expanded_text, NULL);
@@ -565,6 +592,7 @@ static int config_input(AVFilterLink *inlink)
ff_draw_init(&s->dc, inlink->format, 0);
ff_draw_color(&s->dc, &s->fontcolor, s->fontcolor.rgba);
ff_draw_color(&s->dc, &s->shadowcolor, s->shadowcolor.rgba);
+ ff_draw_color(&s->dc, &s->bordercolor, s->bordercolor.rgba);
ff_draw_color(&s->dc, &s->boxcolor, s->boxcolor.rgba);
s->var_values[VAR_w] = s->var_values[VAR_W] = s->var_values[VAR_MAIN_W] = inlink->w;
@@ -812,7 +840,8 @@ static int expand_text(AVFilterContext *ctx)
}
static int draw_glyphs(DrawTextContext *s, AVFrame *frame,
- int width, int height, const uint8_t rgbcolor[4], FFDrawColor *color, int x, int y)
+ int width, int height, const uint8_t rgbcolor[4],
+ FFDrawColor *color, int x, int y, int borderw)
{
char *text = s->expanded_text.str;
uint32_t code = 0;
@@ -821,6 +850,7 @@ static int draw_glyphs(DrawTextContext *s, AVFrame *frame,
Glyph *glyph = NULL;
for (i = 0, p = text; *p; i++) {
+ FT_Bitmap bitmap;
Glyph dummy = { 0 };
GET_UTF8(code, *p++, continue;);
@@ -831,18 +861,20 @@ static int draw_glyphs(DrawTextContext *s, AVFrame *frame,
dummy.code = code;
glyph = av_tree_find(s->glyphs, &dummy, (void *)glyph_cmp, NULL);
+ bitmap = borderw ? glyph->border_bitmap : glyph->bitmap;
+
if (glyph->bitmap.pixel_mode != FT_PIXEL_MODE_MONO &&
glyph->bitmap.pixel_mode != FT_PIXEL_MODE_GRAY)
return AVERROR(EINVAL);
- x1 = s->positions[i].x+s->x+x;
- y1 = s->positions[i].y+s->y+y;
+ x1 = s->positions[i].x+s->x+x - borderw;
+ y1 = s->positions[i].y+s->y+y - borderw;
ff_blend_mask(&s->dc, color,
frame->data, frame->linesize, width, height,
- glyph->bitmap.buffer, glyph->bitmap.pitch,
- glyph->bitmap.width, glyph->bitmap.rows,
- glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 0 : 3,
+ bitmap.buffer, bitmap.pitch,
+ bitmap.width, bitmap.rows,
+ bitmap.pixel_mode == FT_PIXEL_MODE_MONO ? 0 : 3,
0, x1, y1);
}
@@ -1003,12 +1035,17 @@ static int draw_text(AVFilterContext *ctx, AVFrame *frame,
if (s->shadowx || s->shadowy) {
if ((ret = draw_glyphs(s, frame, width, height, s->shadowcolor.rgba,
- &s->shadowcolor, s->shadowx, s->shadowy)) < 0)
+ &s->shadowcolor, s->shadowx, s->shadowy, 0)) < 0)
return ret;
}
+ if (s->borderw) {
+ if ((ret = draw_glyphs(s, frame, width, height, s->bordercolor.rgba,
+ &s->bordercolor, 0, 0, s->borderw)) < 0)
+ return ret;
+ }
if ((ret = draw_glyphs(s, frame, width, height, s->fontcolor.rgba,
- &s->fontcolor, 0, 0)) < 0)
+ &s->fontcolor, 0, 0, 0)) < 0)
return ret;
return 0;
OpenPOWER on IntegriCloud