I am using the ImageSharp library to render multiple lines of text, and I want each line to be justified. I want the spacing to be dynamically calculated to ensure the first character is left aligned and the final character is right aligned.
I wrote some code to do this. This code divides the string up into words, sums up the total word widths, subtracts this total from the available width to determine the available space, and then assigns this space to each word break. It then renders each word separately.
The problem is the vertical alignment. Words can have different vertical heights depending upon the letters they have. The word 'in' has a different height to the word 'Mojo'. Here is how it's currently rendering. You can see vertically small words like 'over' are not aligned properly.
How can I render two words separately so each word's vertical baseline is aligned?
Here is my current code:
public static IPathCollection RenderJustifiedText(
string text,
PointF startPos,
float width,
Font font
)
{
var textOptions = new TextOptions(font);
var wordsAndWidths = text.Split(' ')
.Select(
w =>
new
{
Word = w,
Width = TextMeasurer.MeasureBounds(w, textOptions).Width,
}
).ToArray();
var spaceRemaining = width - wordsAndWidths.Select(ww => ww.Width).Sum();
var eachSpace = spaceRemaining / (wordsAndWidths.Length - 1);
float xPos = startPos.X;
List<IPathCollection> allPaths = new();
foreach (var w in wordsAndWidths)
{
var textPath = new PathBuilder()
.AddLine(
new PointF(
xPos,
startPos.Y
),
new PointF(
xPos + w.Width,
startPos.Y
)
).Build();
allPaths.Add(
TextBuilder.GenerateGlyphs(
w.Word,
textPath,
textOptions
)
);
xPos += w.Width + eachSpace;
}
return new PathCollection(allPaths.SelectMany(pathCollection => pathCollection));
}
As of v1.0.0-beta18 there is a new TextJustification
enum in TextOptions
. The options and implementation supporting the
CSS Text Module Level 3 text-justify property. This allows you to easily justify text of mixed font sizes.
I've added some example output below.
TextJustification.None
TextJustification.InterWord
TextJustification.InterCharacter
TextJustification.None
TextJustification.InterWord
TextJustification.InterCharacter