Useful Text Rendering Algorithms
While writing various graphics programs, I wrote the following algorithms to help render text. At the time I was using C# and GDI+, but the concepts can easily be ported to other languages.
On the right are two examples using different target window sizes. The input text was unwrapped, and only the target font family was defined.
Calculating Font Size to Fit Area
When drawing text, there is a unique font size that allows the text to completely fill a target screen area. However, many programs choose to rely on static font sizes. Using this approach, text may not fill the target area entirely, or may overflow outside of the box.
Using an algorithm, we can choose the optimal font size for any given situation. The final algorithm should compute quickly, and use few calls to graphics routines.
/// <param name="text">Text to be rendered.</param>
/// <param name="dest">Destination <c>RectangleF</c> to render in.</param>
public GraphicsPath GeneratePath(string text, RectangleF dest) {
// draw a default path of a given size
GraphicsPath p = new GraphicsPath();
p.AddString(text, FontFamily.GenericSansSerif, FontStyle.Regular,
24f, new Point(0, 0), StringFormat.GenericDefault);
// calculate best ratio for stretching
RectangleF bound = p.GetBounds();
float ratio = Math.Min((dest.Width / bound.Width) * 0.95f,
(dest.Height / bound.Height) * 0.8f);
// scale to that ratio and translate into corner
Matrix m = new Matrix();
m.Scale(ratio, ratio);
m.Translate(-bound.Left, -bound.Top);
p.Transform(m);
m.Reset();
return p;
}
It works by first drawing the text off-screen using an average text size (24pt). In C# we can do this with a GraphicsPath object, which simply holds drawing instructions. Then, we compare the dimensions of this temporary render with those of the target text area.
We calculate a ratio for each dimension that effectively enlarges the temporary render to fill the target text area. Then we choose the smaller of those two ratios, and scale the GraphicsPath object so the text fills the target area.
Automatically Wrapping for Best Fit
The first algorithm is useless if the text is wrapped improperly. Wrapping too aggressively introduces extra horizontal white space, and too lazily causes vertical white space. By wrapping the text correctly, we can optimally fill that target screen area.
Any wrapping algorithm needs to pay careful attention to sentence structure. One approach (used here) gives weights to different punctuation. The algorithm uses those weights to prevent splitting a word between two lines. Finally, by using the height-to-width ratio of the target area and font being used, we don't need to make any graphics calls, making it reasonably fast.
|