From caf63e997f5d2275d3d1bfe70151a9c29609939a Mon Sep 17 00:00:00 2001 From: yethie Date: Fri, 3 Feb 2023 14:40:25 +0100 Subject: [PATCH 6/7] new y_align option --- doc/filters.texi | 10 ++++++++++ libavfilter/vf_drawtext.c | 40 ++++++++++++++++++++++++++++++++------- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/doc/filters.texi b/doc/filters.texi index 47e04a3ac3..1fa6ccdea8 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -12085,6 +12085,16 @@ Set the vertical and horizontal alignment of the text with respect to the box bo The value must contain exactly two letters, one for the vertical alignment (T=top, M=middle, B=bottom) and one for the horizontal alignment (L=left, C=center, R=right). +@item y_align +Specify what the @var{y} value is referred to. Possible values are: +@itemize @bullet +@item @code{text} the top of the highest glyph of the first text line is placed at @var{y} +@item @code{baseline} the baseline of the first text line is placed at @var{y} +@item @code{font} the baseline of the first text line is placed at @var{y} plus the + ascent (in pixels) defined in the font metrics +@end itemize +The default value of @var{y_align} is "text" for backward compatibility. + @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. diff --git a/libavfilter/vf_drawtext.c b/libavfilter/vf_drawtext.c index 0b01a78509..4784acb29f 100644 --- a/libavfilter/vf_drawtext.c +++ b/libavfilter/vf_drawtext.c @@ -31,6 +31,9 @@ * - Text can be aligned horizontally (top, middle, bottom) and vertically * (left, center, right) relative to the background box * - The default line height is now the one defined in the font + * - The new y_align parameter specifies if the user provided y value is + * referred to the top of the text, to the font baseline or to the + * top of the font. * - The boxborderw parameter can now contain a different value for each border * (e.g. boxborderw=top|right|bottom|left) * - The following new variables can be used in the x and y expressions: @@ -179,6 +182,12 @@ enum expansion_mode { EXP_STRFTIME, }; +enum y_alignment { + YA_TEXT, + YA_BASELINE, + YA_FONT, +}; + typedef struct HarfbuzzData { hb_buffer_t* buf; hb_font_t* font; @@ -318,6 +327,7 @@ typedef struct DrawTextContext { int boxw; ///< the value of the boxw parameter int boxh; ///< the value of the boxh parameter uint8_t *text_align; ///< the horizontal and vertical text alignment + int y_align; ///< the value of the y_align parameter TextLine *lines; ///< computed information about text lines int line_count; ///< the number of text lines @@ -360,6 +370,10 @@ static const AVOption drawtext_options[]= { {"none", "set no expansion", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_NONE}, 0, 0, FLAGS, "expansion"}, {"normal", "set normal expansion", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_NORMAL}, 0, 0, FLAGS, "expansion"}, {"strftime", "set strftime expansion (deprecated)", OFFSET(exp_mode), AV_OPT_TYPE_CONST, {.i64=EXP_STRFTIME}, 0, 0, FLAGS, "expansion"}, + {"y_align", "set the y alignment", OFFSET(y_align), AV_OPT_TYPE_INT, {.i64=YA_TEXT}, 0, 2, FLAGS, "y_align"}, + {"text", "y is referred to the top of the first text line", OFFSET(y_align), AV_OPT_TYPE_CONST, {.i64=YA_TEXT}, 0, 0, FLAGS, "y_align"}, + {"baseline", "y is referred to the baseline of the first line", OFFSET(y_align), AV_OPT_TYPE_CONST, {.i64=YA_BASELINE}, 0, 0, FLAGS, "y_align"}, + {"font", "y is referred to the font defined line metrics", OFFSET(y_align), AV_OPT_TYPE_CONST, {.i64=YA_FONT}, 0, 0, FLAGS, "y_align"}, {"timecode", "set initial timecode", OFFSET(tc_opt_string), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS}, {"tc24hmax", "set 24 hours max (timecode only)", OFFSET(tc24hmax), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS}, @@ -1749,14 +1763,16 @@ continue_on_failed2: } if (ret == 0) { - int height64; metrics->line_height64 = s->face->size->metrics.height; metrics->width = POS_CEIL(width64, 64); - height64 = (metrics->line_height64 + s->line_spacing * 64) * - (FFMAX(0, line_count - 1)) + first_max_y64 - cur_min_y64; - metrics->height = POS_CEIL(height64, 64); - + if (s->y_align == YA_FONT) { + metrics->height = POS_CEIL(metrics->line_height64 * line_count, 64); + } else { + int height64 = (metrics->line_height64 + s->line_spacing * 64) * + (FFMAX(0, line_count - 1)) + first_max_y64 - cur_min_y64; + metrics->height = POS_CEIL(height64, 64); + } metrics->offset_top64 = first_max_y64; metrics->offset_right64 = last_max_x64; metrics->offset_bottom64 = cur_min_y64; @@ -1927,7 +1943,13 @@ static int draw_text(AVFilterContext *ctx, AVFrame *frame) x = 0; y = 0; x64 = (int)(s->x * 64.); - y64 = (int)(s->y * 64. + metrics.offset_top64); + if (s->y_align == YA_FONT) { + y64 = (int)(s->y * 64. + s->face->size->metrics.ascender); + } else if (s->y_align == YA_BASELINE) { + y64 = (int)(s->y * 64.); + } else { + y64 = (int)(s->y * 64. + metrics.offset_top64); + } for (int l = 0; l < s->line_count; ++l) { TextLine *line = &s->lines[l]; @@ -1971,7 +1993,11 @@ static int draw_text(AVFilterContext *ctx, AVFrame *frame) } metrics.rect_x = s->x; - metrics.rect_y = s->y; + if (s->y_align == YA_BASELINE) { + metrics.rect_y = s->y - metrics.offset_top64 / 64; + } else { + metrics.rect_y = s->y; + } s->box_width = s->boxw == 0 ? metrics.width : s->boxw; s->box_height = s->boxh == 0 ? metrics.height : s->boxh; -- 2.30.2