how to measure width of a string precisely?

Viewed 9912

First of all, question How to measure width of character precisely? which is answered, doesn't really help for this case, so this isn't a duplicate of that.

I have a string. I draw using graphics.DrawString, however when I need to put another one after it, I need to know the precise width of previous string.

For this I use graphics.MeasureString with:

StringFormat format = new StringFormat(StringFormat.GenericTypographic);
format.Alignment = StringAlignment.Center;
format.Trimming = StringTrimming.None;
format.FormatFlags = StringFormatFlags.MeasureTrailingSpaces;

I have tried many other functions, just as TextRendered.MeasureText however all of them fail, with all possible combinations of parameters.

the mentioned combination of MeasureString is most close to what I need (it works in most cases, except for special characters), however using characters like # break it. The width is either shorter or longer.

Is there a way to get a precise size of text produced by DrawString function? How does the DrawString calculate the size of drawing area? It must be clearly some other function because the size always differ.

The source code of whole application is here https://gitorious.org/pidgeon/pidgeon-main/ (File where I work with this, is https://gitorious.org/pidgeon/pidgeon-main/blobs/master/scrollback/SBABox.cs)

4 Answers

A method using Graphics.MeasureCharacterRanges to return all the rectangles enclosing each individual letter in a string and their positions is given here: Measure character positions when drawing long strings in C#

I have used the MeasureCharactersInWord and MeasureCharacters methods from that post, then in order to find the exact width without the spaces added to each side of the string, I use this code:

var w = 0F;
var rects = MeasureCharacters(Graphics.FromHwnd(IntPtr.Zero), font, text);
if (rects.Count>0)
{
    if (rects.Count == 1)
    {
        w = rects.First().Width;
    }
    else
    {
        var r0 = rects.First();
        var rN = rects.Last();
        w = rN.X - r0.X + rN.Width;
    }
}

Note that the height of the rectangle is the height of the font and not of the character itself. If you need the height check this post: Determining exact glyph height in specified font

A final note: the reason why I used MeasureCharacterRanges is because all the other methods I tried were failing at giving me a bounding box without space to the left and right of the text. This post The wonders of text rendering and GDI gives a method to get the string width and remove this space using TextRenderer so the whole thing can be done in about two lines of code. I haven't checked the result though.

Related