History

avfilter/vf_drawtext: implement text alignment

Text can now be aligned vertically (top, middle, bottom) and horizontally (left, center, right) relative to the background box.

yethie committed 3 years ago

Commit 5f2d9071 parent 01d843f2 files · +56 −1Browse files

Showing the changes to libavfilter (1 of 2 files). Show all

Unified · Split

libavfilter/vf_drawtext.c+50−1
@@ -309,12 +309,14 @@ typedef struct DrawTextContext { · 308 unmodified lines
309 309
310 int boxw; ///< the value of the boxw parameter310 int boxw; ///< the value of the boxw parameter
311 int boxh; ///< the value of the boxh parameter311 int boxh; ///< the value of the boxh parameter
312 uint8_t *text_align; ///< the horizontal and vertical text alignment
312 313
313 TextLine *lines; ///< computed information about text lines314 TextLine *lines; ///< computed information about text lines
314 int line_count; ///< the number of text lines315 int line_count; ///< the number of text lines
315 uint32_t *tab_clusters; ///< the position of tab characters in the text316 uint32_t *tab_clusters; ///< the position of tab characters in the text
316 int tab_count; ///< the number of tab characters317 int tab_count; ///< the number of tab characters
317 int blank_advance64; ///< the size of the space character318 int blank_advance64; ///< the size of the space character
319 int tab_warning_printed; ///< ensure the tab warning to be printed only once
318} DrawTextContext;320} DrawTextContext;
319 321
320#define OFFSET(x) offsetof(DrawTextContext, x)322#define OFFSET(x) offsetof(DrawTextContext, x)
@@ -333,6 +335,7 @@ static const AVOption drawtext_options[]= { · 12 unmodified lines
333 {"boxborderw", "set box borders width", OFFSET(boxborderw), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, FLAGS},335 {"boxborderw", "set box borders width", OFFSET(boxborderw), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, FLAGS},
334 {"line_spacing", "set line spacing in pixels", OFFSET(line_spacing), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX, FLAGS},336 {"line_spacing", "set line spacing in pixels", OFFSET(line_spacing), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX, FLAGS},
335 {"fontsize", "set font size", OFFSET(fontsize_expr), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS},337 {"fontsize", "set font size", OFFSET(fontsize_expr), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS},
338 {"text_align", "set text alignment", OFFSET(text_align), AV_OPT_TYPE_STRING, {.str="TL"}, 0, 0, FLAGS},
336 {"x", "set x expression", OFFSET(x_expr), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, FLAGS},339 {"x", "set x expression", OFFSET(x_expr), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, FLAGS},
337 {"y", "set y expression", OFFSET(y_expr), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, FLAGS},340 {"y", "set y expression", OFFSET(y_expr), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, FLAGS},
338 {"boxw", "set box width", OFFSET(boxw), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS},341 {"boxw", "set box width", OFFSET(boxw), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS},
@@ -851,6 +854,19 @@ static int string_to_array(const char *source, int *result, int result_size) · 512 unmodified lines
851 return counter;854 return counter;
852}855}
853 856
857static int validate_text_align(char* text_align)
858{
859 int err = 0;
860 if (strlen(text_align) != 2
861 || strchr("LCRTMB", text_align[0]) == NULL || strchr("LCRTMB", text_align[1]) == NULL
862 || (strchr("TMB", text_align[0]) != NULL && strchr("LCR", text_align[1]) == NULL)
863 || (strchr("LCR", text_align[0]) != NULL && strchr("TMB", text_align[1]) == NULL)) {
864 err = AVERROR(EINVAL);
865 }
866
867 return err;
868}
869
854static av_cold int init(AVFilterContext *ctx)870static av_cold int init(AVFilterContext *ctx)
855{871{
856 int err;872 int err;
@@ -916,6 +932,14 @@ static av_cold int init(AVFilterContext *ctx) · 59 unmodified lines
916 return AVERROR(EINVAL);932 return AVERROR(EINVAL);
917 }933 }
918 934
935 if ((err = validate_text_align(s->text_align))) {
936 av_log(ctx, AV_LOG_ERROR,
937 "The value provided for parameter 'text_align' is not valid,\n");
938 av_log(ctx, AV_LOG_ERROR,
939 "please specify a two characters string containing only one letter for horizontal alignment ('LCR') and one for vertical alignment ('TMB')\n");
940 return err;
941 }
942
919#if CONFIG_LIBFRIBIDI943#if CONFIG_LIBFRIBIDI
920 if (s->text_shaping)944 if (s->text_shaping)
921 if ((err = shape_text(ctx)) < 0)945 if ((err = shape_text(ctx)) < 0)
@@ -1486,13 +1510,32 @@ static int draw_glyphs(DrawTextContext *s, AVFrame *frame, · 564 unmodified lines
1486 Glyph dummy = { 0 }, *glyph;1510 Glyph dummy = { 0 }, *glyph;
1487 FT_Bitmap bitmap;1511 FT_Bitmap bitmap;
1488 FT_BitmapGlyph b_glyph;1512 FT_BitmapGlyph b_glyph;
1513 uint8_t j_center = 0, j_right = 0, j_middle = 0, j_bottom = 0;
1514 int line_w, offset_y = 0;
1489 int clip_x = 0, clip_y = 0;1515 int clip_x = 0, clip_y = 0;
1490 1516
1517 j_center = strstr(s->text_align, "C") > 0;
1518 j_right = strstr(s->text_align, "R") > 0;
1519 j_middle = strstr(s->text_align, "M") > 0;
1520 j_bottom = strstr(s->text_align, "B") > 0;
1521
1522 if (j_middle) {
1523 offset_y = (s->box_height - metrics->height) / 2;
1524 } else if (j_bottom) {
1525 offset_y = s->box_height - metrics->height;
1526 }
1527
1528 if ((j_right || j_center) && !s->tab_warning_printed && s->tab_count > 0) {
1529 s->tab_warning_printed = 1;
1530 av_log(s, AV_LOG_WARNING, "Tab characters are only supported with left horizontal alignment\n");
1531 }
1532
1491 clip_x = FFMIN(metrics->rect_x + s->box_width + s->bb_right, frame->width);1533 clip_x = FFMIN(metrics->rect_x + s->box_width + s->bb_right, frame->width);
1492 clip_y = FFMIN(metrics->rect_y + s->box_height + s->bb_bottom, frame->height);1534 clip_y = FFMIN(metrics->rect_y + s->box_height + s->bb_bottom, frame->height);
1493 1535
1494 for (l = 0; l < s->line_count; ++l) {1536 for (l = 0; l < s->line_count; ++l) {
1495 TextLine *line = &s->lines[l];1537 TextLine *line = &s->lines[l];
1538 line_w = POS_CEIL(line->width64, 64);
1496 for (g = 0; g < line->hb_data.glyph_count; ++g) {1539 for (g = 0; g < line->hb_data.glyph_count; ++g) {
1497 info = &line->glyphs[g];1540 info = &line->glyphs[g];
1498 dummy.fontsize = s->fontsize;1541 dummy.fontsize = s->fontsize;
@@ -1506,10 +1549,16 @@ static int draw_glyphs(DrawTextContext *s, AVFrame *frame, · 7 unmodified lines
1506 b_glyph = borderw ? glyph->border_bglyph[idx] : glyph->bglyph[idx];1549 b_glyph = borderw ? glyph->border_bglyph[idx] : glyph->bglyph[idx];
1507 bitmap = b_glyph->bitmap;1550 bitmap = b_glyph->bitmap;
1508 x1 = x + info->x + b_glyph->left;1551 x1 = x + info->x + b_glyph->left;
1509 y1 = y + info->y - b_glyph->top;1552 y1 = y + info->y - b_glyph->top + offset_y;
1510 w1 = bitmap.width;1553 w1 = bitmap.width;
1511 h1 = bitmap.rows;1554 h1 = bitmap.rows;
1512 1555
1556 if (j_center) {
1557 x1 += (s->box_width - line_w) / 2;
1558 } else if (j_right) {
1559 x1 += s->box_width - line_w;
1560 }
1561
1513 // Offset of the glyph's bitmap in the visible region1562 // Offset of the glyph's bitmap in the visible region
1514 dx = dy = 0;1563 dx = dy = 0;
1515 if (x1 < metrics->rect_x - s->bb_left) {1564 if (x1 < metrics->rect_x - s->bb_left) {

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t