avfilter/vf_drawtext: use flags type of option for text_align

This commit is contained in:
Paul B Mahol 2023-06-19 21:50:26 +02:00
parent 01420316d2
commit ea190b8a23
2 changed files with 30 additions and 37 deletions

View File

@ -12386,7 +12386,7 @@ Set the line spacing in pixels. The default value of @var{line_spacing} is 0.
@item text_align @item text_align
Set the vertical and horizontal alignment of the text with respect to the box boundaries. Set the vertical and horizontal alignment of the text with respect to the box boundaries.
The value must contain exactly two letters, one for the vertical alignment (T=top, The value is combination of flags, one for the vertical alignment (T=top,
M=middle, B=bottom) and one for the horizontal alignment (L=left, C=center, R=right). M=middle, B=bottom) and one for the horizontal alignment (L=left, C=center, R=right).
Please note that tab characters are only supported with the left horizontal alignment. Please note that tab characters are only supported with the left horizontal alignment.

View File

@ -177,6 +177,13 @@ enum y_alignment {
YA_FONT, YA_FONT,
}; };
enum text_alignment {
TA_LEFT = (1 << 0),
TA_RIGHT = (1 << 1),
TA_TOP = (1 << 2),
TA_BOTTOM = (1 << 3),
};
typedef struct HarfbuzzData { typedef struct HarfbuzzData {
hb_buffer_t* buf; hb_buffer_t* buf;
hb_font_t* font; hb_font_t* font;
@ -315,7 +322,7 @@ typedef struct DrawTextContext {
int boxw; ///< the value of the boxw parameter int boxw; ///< the value of the boxw parameter
int boxh; ///< the value of the boxh parameter int boxh; ///< the value of the boxh parameter
uint8_t *text_align; ///< the horizontal and vertical text alignment int text_align; ///< the horizontal and vertical text alignment
int y_align; ///< the value of the y_align parameter int y_align; ///< the value of the y_align parameter
TextLine *lines; ///< computed information about text lines TextLine *lines; ///< computed information about text lines
@ -343,7 +350,19 @@ static const AVOption drawtext_options[]= {
{"boxborderw", "set box borders width", OFFSET(boxborderw), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, TFLAGS}, {"boxborderw", "set box borders width", OFFSET(boxborderw), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, TFLAGS},
{"line_spacing", "set line spacing in pixels", OFFSET(line_spacing), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX, TFLAGS}, {"line_spacing", "set line spacing in pixels", OFFSET(line_spacing), AV_OPT_TYPE_INT, {.i64=0}, INT_MIN, INT_MAX, TFLAGS},
{"fontsize", "set font size", OFFSET(fontsize_expr), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, TFLAGS}, {"fontsize", "set font size", OFFSET(fontsize_expr), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, TFLAGS},
{"text_align", "set text alignment", OFFSET(text_align), AV_OPT_TYPE_STRING, {.str="TL"}, 0, 0, TFLAGS}, {"text_align", "set text alignment", OFFSET(text_align), AV_OPT_TYPE_FLAGS, {.i64=0}, 0, (TA_LEFT|TA_RIGHT|TA_TOP|TA_BOTTOM), TFLAGS, "text_align"},
{ "left", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TA_LEFT }, .flags = TFLAGS, .unit = "text_align" },
{ "L", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TA_LEFT }, .flags = TFLAGS, .unit = "text_align" },
{ "right", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TA_RIGHT }, .flags = TFLAGS, .unit = "text_align" },
{ "R", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TA_RIGHT }, .flags = TFLAGS, .unit = "text_align" },
{ "center", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = (TA_LEFT|TA_RIGHT) }, .flags = TFLAGS, .unit = "text_align" },
{ "C", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = (TA_LEFT|TA_RIGHT) }, .flags = TFLAGS, .unit = "text_align" },
{ "top", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TA_TOP }, .flags = TFLAGS, .unit = "text_align" },
{ "T", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TA_TOP }, .flags = TFLAGS, .unit = "text_align" },
{ "bottom", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TA_BOTTOM }, .flags = TFLAGS, .unit = "text_align" },
{ "B", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TA_BOTTOM }, .flags = TFLAGS, .unit = "text_align" },
{ "middle", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = (TA_TOP|TA_BOTTOM) }, .flags = TFLAGS, .unit = "text_align" },
{ "M", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = (TA_TOP|TA_BOTTOM) }, .flags = TFLAGS, .unit = "text_align" },
{"x", "set x expression", OFFSET(x_expr), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, TFLAGS}, {"x", "set x expression", OFFSET(x_expr), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, TFLAGS},
{"y", "set y expression", OFFSET(y_expr), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, TFLAGS}, {"y", "set y expression", OFFSET(y_expr), AV_OPT_TYPE_STRING, {.str="0"}, 0, 0, TFLAGS},
{"boxw", "set box width", OFFSET(boxw), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, TFLAGS}, {"boxw", "set box width", OFFSET(boxw), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, TFLAGS},
@ -866,19 +885,6 @@ static int string_to_array(const char *source, int *result, int result_size)
return counter; return counter;
} }
static int validate_text_align(char* text_align)
{
int err = 0;
if (strlen(text_align) != 2
|| strchr("LCRTMB", text_align[0]) == NULL || strchr("LCRTMB", text_align[1]) == NULL
|| (strchr("TMB", text_align[0]) != NULL && strchr("LCR", text_align[1]) == NULL)
|| (strchr("LCR", text_align[0]) != NULL && strchr("TMB", text_align[1]) == NULL)) {
err = AVERROR(EINVAL);
}
return err;
}
static av_cold int init(AVFilterContext *ctx) static av_cold int init(AVFilterContext *ctx)
{ {
int err; int err;
@ -944,14 +950,6 @@ static av_cold int init(AVFilterContext *ctx)
return AVERROR(EINVAL); return AVERROR(EINVAL);
} }
if ((err = validate_text_align(s->text_align))) {
av_log(ctx, AV_LOG_ERROR,
"The value provided for parameter 'text_align' is not valid,\n");
av_log(ctx, AV_LOG_ERROR,
"please specify a two characters string containing only one letter for horizontal alignment ('LCR') and one for vertical alignment ('TMB')\n");
return err;
}
#if CONFIG_LIBFRIBIDI #if CONFIG_LIBFRIBIDI
if (s->text_shaping) if (s->text_shaping)
if ((err = shape_text(ctx)) < 0) if ((err = shape_text(ctx)) < 0)
@ -1148,11 +1146,6 @@ static int command(AVFilterContext *ctx, const char *cmd, const char *arg, char
FT_STROKER_LINEJOIN_ROUND, 0); FT_STROKER_LINEJOIN_ROUND, 0);
// Dispose the old border glyphs // Dispose the old border glyphs
av_tree_enumerate(old->glyphs, NULL, NULL, glyph_enu_border_free); av_tree_enumerate(old->glyphs, NULL, NULL, glyph_enu_border_free);
} else if (strcmp(cmd, "text_align") == 0) {
if (validate_text_align(old->text_align) != 0) {
av_log(ctx, AV_LOG_ERROR,
"Invalid command value '%s' for 'text_align'\n", old->text_align);
}
} else if (strcmp(cmd, "fontsize") == 0) { } else if (strcmp(cmd, "fontsize") == 0) {
av_expr_free(old->fontsize_pexpr); av_expr_free(old->fontsize_pexpr);
old->fontsize_pexpr = NULL; old->fontsize_pexpr = NULL;
@ -1561,22 +1554,22 @@ static int draw_glyphs(DrawTextContext *s, AVFrame *frame,
Glyph dummy = { 0 }, *glyph; Glyph dummy = { 0 }, *glyph;
FT_Bitmap bitmap; FT_Bitmap bitmap;
FT_BitmapGlyph b_glyph; FT_BitmapGlyph b_glyph;
uint8_t j_center = 0, j_right = 0, j_middle = 0, j_bottom = 0; uint8_t j_left = 0, j_right = 0, j_top = 0, j_bottom = 0;
int line_w, offset_y = 0; int line_w, offset_y = 0;
int clip_x = 0, clip_y = 0; int clip_x = 0, clip_y = 0;
j_center = strstr(s->text_align, "C") > 0; j_left = !!(s->text_align & TA_LEFT);
j_right = strstr(s->text_align, "R") > 0; j_right = !!(s->text_align & TA_RIGHT);
j_middle = strstr(s->text_align, "M") > 0; j_top = !!(s->text_align & TA_TOP);
j_bottom = strstr(s->text_align, "B") > 0; j_bottom = !!(s->text_align & TA_BOTTOM);
if (j_middle) { if (j_top && j_bottom) {
offset_y = (s->box_height - metrics->height) / 2; offset_y = (s->box_height - metrics->height) / 2;
} else if (j_bottom) { } else if (j_bottom) {
offset_y = s->box_height - metrics->height; offset_y = s->box_height - metrics->height;
} }
if ((j_right || j_center) && !s->tab_warning_printed && s->tab_count > 0) { if ((!j_left || j_right) && !s->tab_warning_printed && s->tab_count > 0) {
s->tab_warning_printed = 1; s->tab_warning_printed = 1;
av_log(s, AV_LOG_WARNING, "Tab characters are only supported with left horizontal alignment\n"); av_log(s, AV_LOG_WARNING, "Tab characters are only supported with left horizontal alignment\n");
} }
@ -1604,7 +1597,7 @@ static int draw_glyphs(DrawTextContext *s, AVFrame *frame,
w1 = bitmap.width; w1 = bitmap.width;
h1 = bitmap.rows; h1 = bitmap.rows;
if (j_center) { if (j_left && j_right) {
x1 += (s->box_width - line_w) / 2; x1 += (s->box_width - line_w) / 2;
} else if (j_right) { } else if (j_right) {
x1 += s->box_width - line_w; x1 += s->box_width - line_w;