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

Ramiro Polla ramiro.polla at gmail.com
Sat Jan 18 07:03:37 CET 2014


On Fri, Jan 10, 2014 at 6:46 AM, Stefano Sabatini <stefasab at gmail.com> wrote:
> 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

done

>> 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).

Done for the ones added in this patch.

>> +
>> +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.

done

>>      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

done

>> +        }
>> +        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 ? ...;

done

> [...]
>
> Should be fine otherwise if works as expected.

One more change in this patch is in draw_glyphs(), borderw is
subtracted from the position while drawing the border. The border was
not correct around the text in the previous patch.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0002-lavfi-drawtext-add-option-for-drawing-border-around-.patch
Type: text/x-patch
Size: 9932 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20140118/33a417da/attachment.bin>


More information about the ffmpeg-devel mailing list