Skip to content

Commit

Permalink
Add text justification
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
DanOscarsson authored and wm4 committed Nov 12, 2016
1 parent 35dc4dd commit e54c123
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 3 deletions.
1 change: 1 addition & 0 deletions libass/ass.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 4 additions & 0 deletions libass/ass.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand Down
40 changes: 37 additions & 3 deletions libass/ass_render.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions libass/ass_render.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
5 changes: 5 additions & 0 deletions libass/ass_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -73,6 +77,7 @@ typedef struct ass_style {
int Encoding;
int treat_fontname_as_pattern;
double Blur;
int Justify;
} ASS_Style;


Expand Down

0 comments on commit e54c123

Please sign in to comment.