Title: Measure character positions in a drawn string in C#
You can use the Graphics class's MeasureCharacterRanges method to measure character positions in a drawn string. This method returns information about the regions where strings of characters would be drawn by the Graphics object's DrawString method.
The DrawStringWithCharacterBounds method shown in the following code uses MeasureCharacterRanges to draw a sample string with each character's position outlined in red.
// Draw the string and the bounds for its characters.
private void DrawStringWithCharacterBounds(Graphics gr,
string text, Font font, Rectangle rect)
{
using (StringFormat string_format = new StringFormat())
{
string_format.Alignment = StringAlignment.Center;
string_format.LineAlignment = StringAlignment.Center;
// Draw the string.
gr.DrawString(text, font, Brushes.Blue, rect,
string_format);
// Make a CharacterRange for the string's characters.
List<CharacterRange> range_list =
new List<CharacterRange>();
for (int i = 0; i < text.Length; i++)
{
range_list.Add(new CharacterRange(i, 1));
}
string_format.SetMeasurableCharacterRanges(
range_list.ToArray());
// Measure the string's character ranges.
Region[] regions = gr.MeasureCharacterRanges(
text, font, rect, string_format);
// Draw the character bounds.
for (int i = 0; i < text.Length; i++)
{
Rectangle char_rect =
Rectangle.Round(regions[i].GetBounds(gr));
gr.DrawRectangle(Pens.Red, char_rect);
}
}
}
The code makes a stringFormat object and draws the text. It creates a List of CharacterRange objects and adds one for each of the string's characters. In general a CharacterRange object indicates a first character and the number of characters that you want to measure. In this example, each of the objects indicates a single character.
The code calls the stringFormat object's setMeasurableCharacterRanges method to indicate the CharacterRange objects. This method takes an array of CharacterRange objects as a parameter, so the code calls the List's ToArray method to convert it into an array.
Important: The setMeasurableCharacterRanges method can only measure up to 32 characters at a time. If the array of ranges passed to this method contains more than 32 entries, the method throws an OverflowException with no additional information to tell you what went wrong.
Next the program calls the Graphics object's MeasureCharacterRanges method to get an array of Region objects describing where the characters would be drawn. Finally the code loops through the Regions drawing red rectangles to show the characters' bounds.
If you look closely at the picture you'll notice that the characters don't always remain inside their bounds as reported by MeasureCharacterRanges. For example, to make the characters close up nicely, this font makes the lowercase "f" extend to the right into the next character's bounds. Depending on the following character, the "f" may sometimes even touch that character (as in "fF"). Similarly many characters with descenders, including the italic lowercase "f," also extend to the left into the previous characters' bounds.
These sorts of adjustments vary from font to font, and I don't know of a way to determine when they will happen in code.
Download the example to experiment with it and to see additional details.
|