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

Ramiro Polla ramiro.polla at gmail.com
Thu Jan 9 15:42:46 CET 2014


On Thu, Jan 9, 2014 at 8:26 AM, Stefano Sabatini <stefasab at gmail.com> wrote:
> On date Thursday 2014-01-09 00:13:37 -0200, Ramiro Polla encoded:
>> From 52b6cda0ee5bfaf6e594eb5a7923be00eac575d8 Mon Sep 17 00:00:00 2001
>> From: Ramiro Polla <ramiro.polla at gmail.com>
>> Date: Thu, 9 Jan 2014 00:05:43 -0200
>> Subject: [PATCH] lavfi/drawtext: add option for drawing border around text
>>
>> ---
>>  doc/filters.texi          |   11 +++++++++++
>>  libavfilter/vf_drawtext.c |   15 +++++++++++++++
>>  2 files changed, 26 insertions(+)
>
> This feature was implemented in the original VHOOK drawtext filter
> (was named "outline"). Since the rendering result was pretty poor I
> decided to drop it.
>
>> diff --git a/doc/filters.texi b/doc/filters.texi
>> index c896edb..9f97dc0 100644
>> --- a/doc/filters.texi
>> +++ b/doc/filters.texi
>> @@ -3548,6 +3548,17 @@ option, check the "Color" section in the ffmpeg-utils manual.
>>
>>  The default value of @var{boxcolor} is "white".
>>
>> + at item border
>> +Used to draw a 1-pixel-thick border around text using @var{bordercolor}.
>> +Value should be either 1 (enable) or 0 (disable).
>> +The default value of @var{border} is 0.
>> +
>> + 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.
>> +
>> +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 91b8218..c14bac3 100644
>> --- a/libavfilter/vf_drawtext.c
>> +++ b/libavfilter/vf_drawtext.c
>> @@ -136,6 +136,7 @@ typedef struct {
>>      int shadowx, shadowy;
>>      unsigned int fontsize;          ///< font size to use
>>
>> +    short int draw_border;          ///< draw border around text - true or false
>>      short int draw_box;             ///< draw box around text - true or false
>>      int use_kerning;                ///< font kerning is used - true/false
>>      int tabsize;                    ///< tab size
>> @@ -144,6 +145,7 @@ 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
>> @@ -179,6 +181,8 @@ 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},
>> +    {"border",      "set border",           OFFSET(draw_border),        AV_OPT_TYPE_INT,    {.i64=0},     0,        1       , 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},
>> @@ -559,6 +563,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;
>> @@ -995,6 +1000,16 @@ static int draw_text(AVFilterContext *ctx, AVFrame *frame,
>>                             frame->data, frame->linesize, width, height,
>>                             s->x, s->y, box_w, box_h);
>>
>
>> +    if (s->draw_border) {
>> +        int offsets[4][2] = { { -1, -1 }, { -1, +1 }, { +1, -1 }, { +1, +1 } };
>> +        for (i = 0; i < 4; i++) {
>> +            ret = draw_glyphs(s, frame, width, height, s->bordercolor.rgba,
>> +                              &s->bordercolor, offsets[i][0], offsets[i][1]);
>> +            if (ret < 0)
>> +                return ret;
>> +        }
>> +    }
>
> This will require printing the glyphs four times, which is not very
> efficient. Alternatively you could implement a system like the one in
> the VHOOK filter, which would be faster but more complicate
> implementation-wise.

Indeed, it is more complicated implementation-wise. There is also the
option of using the FreeType stroker, but that library has a horrible
API and the examples are confusing, so I couldn't get it to work.

> Do you have any specific reason for wanting to implment such a
> feature?

I have a live video capture that may go from lots of light to lots of
dark, so just plain text looks bad most of the time. Shadow also looks
pretty bad. Adding a border makes it OK.


More information about the ffmpeg-devel mailing list