[FFmpeg-devel] [PATCH 2/2] lavfi/drawtext: add option for drawing border around text

Stefano Sabatini stefasab at gmail.com
Fri Jan 10 09:46:20 CET 2014


On date Friday 2014-01-10 04:36:36 -0200, Ramiro Polla encoded:
> 

> From 56ca123357def67b281a28143a9faa52ecad603b Mon Sep 17 00:00:00 2001
> From: Ramiro Polla <ramiro.polla at gmail.com>
> Date: Fri, 10 Jan 2014 04:30:09 -0200
> Subject: [PATCH 2/2] lavfi/drawtext: add option for drawing border around
>  text
> 

> ---
>  doc/filters.texi          |   10 +++++++++
>  libavfilter/vf_drawtext.c |   50 +++++++++++++++++++++++++++++++++++++++------
>  2 files changed, 54 insertions(+), 6 deletions(-)

Reminder: missing micro bump

> 
> diff --git a/doc/filters.texi b/doc/filters.texi
> index c896edb..f32a969 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
> +The width of the border to be drawn around the text using @var{bordercolor}.
> +The default value of @var{borderw} is 0.

Set the width ...


> + at item bordercolor
> +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.

Set the color ...

(the other options should be fixed as well).

> +
> +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/vf_drawtext.c b/libavfilter/vf_drawtext.c
> index 2dd95ce..7e92dd6 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
> @@ -179,12 +183,14 @@ static const AVOption drawtext_options[]= {
>      {"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},
>      {"shadowcolor", "set shadow color",     OFFSET(shadowcolor.rgba),   AV_OPT_TYPE_COLOR,  {.str="black"}, CHAR_MIN, CHAR_MAX, FLAGS},
> +    {"bordercolor", "set border color",     OFFSET(bordercolor.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},
>      {"x",           "set x expression",     OFFSET(x_expr),             AV_OPT_TYPE_STRING, {.str="0"},   CHAR_MIN, CHAR_MAX, FLAGS},
>      {"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,13 @@ 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;
> +        FT_Glyph_StrokeBorder(&border_glyph, s->stroker, 0, 0);
> +        FT_Glyph_To_Bitmap(&border_glyph, FT_RENDER_MODE_NORMAL, 0, 1);
> +        bitmapglyph = (FT_BitmapGlyph) border_glyph;
> +        glyph->border_bitmap = bitmapglyph->bitmap;
> +    }

Probably you want to add some error checks.

>      if (FT_Glyph_To_Bitmap(glyph->glyph, FT_RENDER_MODE_NORMAL, 0, 1)) {
>          ret = AVERROR(EINVAL);
>          goto error;
> @@ -490,6 +504,16 @@ static av_cold int init(AVFilterContext *ctx)
>          return AVERROR(EINVAL);
>      }
>  
> +    if (s->borderw) {
> +        err = FT_Stroker_New(s->library, &s->stroker);
> +        if (err) {
> +            av_log(ctx, AV_LOG_ERROR, "Coult not init FT stroker\n");

> +            return AVERROR(EINVAL);

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 +570,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 +590,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 +838,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 border)
>  {
>      char *text = s->expanded_text.str;
>      uint32_t code = 0;
> @@ -821,6 +848,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,6 +859,11 @@ static int draw_glyphs(DrawTextContext *s, AVFrame *frame,
>          dummy.code = code;
>          glyph = av_tree_find(s->glyphs, &dummy, (void *)glyph_cmp, NULL);
>  

> +        if (border)
> +            bitmap = glyph->border_bitmap;
> +        else
> +            bitmap = glyph->bitmap;

nit++: bitmap = border ? ...;

[...]

Should be fine otherwise if works as expected.
-- 
FFmpeg = Forgiving & Fancy Mastodontic Peaceful Eccentric Ghost


More information about the ffmpeg-devel mailing list