[FFmpeg-cvslog] lavfi/drawtext: add option for drawing border around text
Ramiro Polla
git at videolan.org
Sat Jan 25 05:00:28 CET 2014
ffmpeg | branch: master | Ramiro Polla <ramiro.polla at gmail.com> | Sat Jan 18 03:58:34 2014 -0200| [78a9f185eb175e6164b1c0f40d20ff1933ac8fb7] | committer: Michael Niedermayer
lavfi/drawtext: add option for drawing border around text
Reviewed-by: Stefano Sabatini <stefasab at gmail.com>
Signed-off-by: Michael Niedermayer <michaelni at gmx.at>
> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=78a9f185eb175e6164b1c0f40d20ff1933ac8fb7
---
doc/filters.texi | 10 +++++++++
libavfilter/version.h | 2 +-
libavfilter/vf_drawtext.c | 53 ++++++++++++++++++++++++++++++++++++++-------
3 files changed, 56 insertions(+), 9 deletions(-)
diff --git a/doc/filters.texi b/doc/filters.texi
index 602814c..9e67db4 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -3548,6 +3548,16 @@ option, check the "Color" section in the ffmpeg-utils manual.
The default value of @var{boxcolor} is "white".
+ at item borderw
+Set the width of the border to be drawn around the text using @var{bordercolor}.
+The default value of @var{borderw} is 0.
+
+ at item bordercolor
+Set the color to be used for drawing border around text. For the syntax of this
+option, check the "Color" section in the ffmpeg-utils manual.
+
+The default value of @var{bordercolor} is "black".
+
@item expansion
Select how the @var{text} is expanded. Can be either @code{none},
@code{strftime} (deprecated) or
diff --git a/libavfilter/version.h b/libavfilter/version.h
index 2ef4ce7..d86fade 100644
--- a/libavfilter/version.h
+++ b/libavfilter/version.h
@@ -31,7 +31,7 @@
#define LIBAVFILTER_VERSION_MAJOR 4
#define LIBAVFILTER_VERSION_MINOR 1
-#define LIBAVFILTER_VERSION_MICRO 100
+#define LIBAVFILTER_VERSION_MICRO 101
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
LIBAVFILTER_VERSION_MINOR, \
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;
More information about the ffmpeg-cvslog
mailing list