From e54c123d5a08b6212533ddcced2cb1a50fa3d2b2 Mon Sep 17 00:00:00 2001 From: Dan Oscarsson Date: Wed, 5 Oct 2016 13:52:47 +0200 Subject: Add text justification Subtitle recommendations often include that multi line subtitles should be left justified as this is easier for the eyes. This is also the standard used by several television companies. This add the possibility to define how subtitles are to be justified, independently of where they are aligned. The most common way could be to set justify to left, and have alignment to center. But you can, for example, have alignment to left and justify to center, giving subtitles to the left but justifed on the center (instead of normal left justified). Using justify right and alignment of center, might be good choice for Arabic. If justify is not defined, all works like before. If justify is defined, subtitles are aligned as defined by alignment and justified as defined by justify. ASS is not extended by this, justify can only be defined by setting Justify to wanted justification. --- libass/ass.c | 1 + libass/ass.h | 4 ++++ libass/ass_render.c | 40 +++++++++++++++++++++++++++++++++++++--- libass/ass_render.h | 1 + libass/ass_types.h | 5 +++++ 5 files changed, 48 insertions(+), 3 deletions(-) (limited to 'libass') diff --git a/libass/ass.c b/libass/ass.c index f42fd4b..1cb0d4c 100644 --- a/libass/ass.c +++ b/libass/ass.c @@ -449,6 +449,7 @@ void ass_process_force_style(ASS_Track *track) FPVAL(Angle) INTVAL(BorderStyle) INTVAL(Alignment) + INTVAL(Justify) INTVAL(MarginL) INTVAL(MarginR) INTVAL(MarginV) diff --git a/libass/ass.h b/libass/ass.h index 24a4618..912a7a1 100644 --- a/libass/ass.h +++ b/libass/ass.h @@ -166,6 +166,10 @@ typedef enum { * resolution given by the ASS_Track. */ ASS_OVERRIDE_FULL_STYLE = 1 << 9, + /** + * On dialogue events override: Justify + */ + ASS_OVERRIDE_BIT_JUSTIFY = 1 << 10, } ASS_OverrideBits; /** diff --git a/libass/ass_render.c b/libass/ass_render.c index d57bdac..d0f827d 100644 --- a/libass/ass_render.c +++ b/libass/ass_render.c @@ -784,6 +784,9 @@ static ASS_Style *handle_selective_style_overrides(ASS_Renderer *render_priv, if (requested & ASS_OVERRIDE_BIT_ALIGNMENT) new->Alignment = user->Alignment; + if (requested & ASS_OVERRIDE_BIT_JUSTIFY) + new->Justify = user->Justify; + if (requested & ASS_OVERRIDE_BIT_MARGINS) { new->MarginL = user->MarginL; new->MarginR = user->MarginR; @@ -886,6 +889,7 @@ init_render_context(ASS_Renderer *render_priv, ASS_Event *event) render_priv->state.wrap_style = render_priv->track->WrapStyle; render_priv->state.alignment = render_priv->state.style->Alignment; + render_priv->state.justify = render_priv->state.style->Justify; render_priv->state.pos_x = 0; render_priv->state.pos_y = 0; render_priv->state.org_x = 0; @@ -2071,19 +2075,49 @@ static void align_lines(ASS_Renderer *render_priv, double max_text_width) double width = 0; int last_break = -1; int halign = render_priv->state.alignment & 3; + int justify = render_priv->state.justify; + double max_width = 0; if (render_priv->state.evt_type == EVENT_HSCROLL) return; + for (i = 0; i <= text_info->length; ++i) { // (text_info->length + 1) is the end of the last line + if ((i == text_info->length) || glyphs[i].linebreak) { + max_width = FFMAX(max_width,width); + width = 0; + } + if (i < text_info->length && !glyphs[i].skip && + glyphs[i].symbol != '\n' && glyphs[i].symbol != 0) { + width += d6_to_double(glyphs[i].cluster_advance.x); + } + } for (i = 0; i <= text_info->length; ++i) { // (text_info->length + 1) is the end of the last line if ((i == text_info->length) || glyphs[i].linebreak) { double shift = 0; if (halign == HALIGN_LEFT) { // left aligned, no action - shift = 0; + if (justify == ASS_JUSTIFY_RIGHT) { + shift = max_width - width; + } else if (justify == ASS_JUSTIFY_CENTER) { + shift = (max_width - width) / 2.0; + } else { + shift = 0; + } } else if (halign == HALIGN_RIGHT) { // right aligned - shift = max_text_width - width; + if (justify == ASS_JUSTIFY_LEFT) { + shift = max_text_width - max_width; + } else if (justify == ASS_JUSTIFY_CENTER) { + shift = max_text_width - max_width + (max_width - width) / 2.0; + } else { + shift = max_text_width - width; + } } else if (halign == HALIGN_CENTER) { // centered - shift = (max_text_width - width) / 2.0; + if (justify == ASS_JUSTIFY_LEFT) { + shift = (max_text_width - max_width) / 2.0; + } else if (justify == ASS_JUSTIFY_RIGHT) { + shift = (max_text_width - max_width) / 2.0 + max_width - width; + } else { + shift = (max_text_width - width) / 2.0; + } } for (j = last_break + 1; j < i; ++j) { GlyphInfo *info = glyphs + j; diff --git a/libass/ass_render.h b/libass/ass_render.h index 6e3963e..fad554b 100644 --- a/libass/ass_render.h +++ b/libass/ass_render.h @@ -220,6 +220,7 @@ typedef struct { FT_Stroker stroker; int stroker_radius; // last stroker radius, for caching stroker objects int alignment; // alignment overrides go here; if zero, style value will be used + int justify; // justify instructions double frx, fry, frz; double fax, fay; // text shearing enum { diff --git a/libass/ass_types.h b/libass/ass_types.h index f4a6ae5..88951a7 100644 --- a/libass/ass_types.h +++ b/libass/ass_types.h @@ -28,6 +28,10 @@ #define HALIGN_LEFT 1 #define HALIGN_CENTER 2 #define HALIGN_RIGHT 3 +#define ASS_JUSTIFY_AUTO 0 +#define ASS_JUSTIFY_LEFT 1 +#define ASS_JUSTIFY_CENTER 2 +#define ASS_JUSTIFY_RIGHT 3 #define FONT_WEIGHT_LIGHT 300 #define FONT_WEIGHT_MEDIUM 400 @@ -73,6 +77,7 @@ typedef struct ass_style { int Encoding; int treat_fontname_as_pattern; double Blur; + int Justify; } ASS_Style; -- cgit v1.2.3