Measure character positions in a drawn string in C#

measure character positions

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 Example   Follow me on Twitter   RSS feed




This entry was posted in algorithms, drawing, fonts, graphics, strings and tagged , , , , , , , , , , , , , , , . Bookmark the permalink.

3 Responses to Measure character positions in a drawn string in C#

  1. Pingback: Draw text in random colors in C# -

  2. yt says:

    Hi, how to handle the case that character length greater than 32?

    • RodStephens says:

      Unfortunately there isn’t a good way to handle this as far as I know. You can break the text into pieces and then look at the positions of the letters in the pieces, but there’s no guarantee that the GDI+ library won’t space the pieces differently than you do.

      The only good solution I can think of would be to break the text into words and position each word separately. Then you can measure the positions of the letters in each word. (As long as no word contains more than 32 letters.)

Leave a Reply

Your email address will not be published. Required fields are marked *