tags:

views:

488

answers:

5

Given a number of pixels (say: 300) and a Font (fixed type, fixed size, like Consolas), how could I determine the maximum number of characters that I could draw with GDI+?

The text won't be written to a Label or such, but drawn using GDI+:

public void DrawString( string s, Font font, Brush brush, 
    RectangleF layoutRectangle, StringFormat format );

But I want to perform certain text operations before drawing, hence why I'd like to figure out the maximum number of chars I can safely output.

+1  A: 

You could use Drawing.Graphics.MeasureString() to get the size of one of your glyphs.
Then just check how many of them fit into your drawing area.

weichsel
+1  A: 

If it's fixed width why not just use floor(pixelcount/fontwidth)?

dutt
Only works for monospaced fonts.
devstuff
Oops, didn't read the question properly. Sorry about that.
devstuff
A: 

I think System.Drawing.Graphics.MeasureString() can help you. You can combine it with MeasureCharacterRanges or measure a Size of one character and then divide you number of pixels on this value. Something like this, you can play with results to get it work. I am sure that this will be working solution, so please ask if something is unclear =)

Restuta
+4  A: 

The System.Drawing.Graphics method MeasureString pads string widths with a few extra pixels (I do not know why), so measuring the width of one fixed-length character and then dividing that into the maximum width available would give a too-low estimate of the number of characters that could fit into the maximum width.

To get the maximum number of characters, you'd have to do something iterative like this:

using (Graphics g = this.CreateGraphics())
{
    string s = "";
    SizeF size;
    int numberOfCharacters = 0;
    float maxWidth = 50;
    while (true)
    {
        s += "a";
        size = g.MeasureString(s, this.Font);
        if (size.Width > maxWidth)
        {
            break;
        }
        numberOfCharacters++;
    }
    // numberOfCharacters will now contain your max string length
}

Update: you learn something new every day. Graphics.MeasureString (and TextRenderer) pad the bounds with a few extra pixels to accomodate overhanging glyphs. Makes sense, but it can be annoying. See:

http://msdn.microsoft.com/en-us/library/6xe5hazb.aspx

Looks like a better way to do this is:

using (Graphics g = this.CreateGraphics())
{
    g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
    SizeF size = g.MeasureString("a", this.Font, new PointF(0, 0), 
        StringFormat.GenericTypographic);
    float maxWidth = 50; // or whatever
    int numberOfCharacters = (int)(maxWidth / size.Width);
}
MusiGenesis
Thanks for the info, I ended up using something very close to this, although with Consolas font, the "numberOfCharacters" returned, depending upon the char you use. Eg: with an "a" will return 50, if I use " ", it will return a different number. I thought Consolas was Fixed Font - Monospaced ?
Martín Marconcini
+2  A: 

There is also TextRenderer.MeasureText(), which produces a different result (this is what is used when drawing windows controls, so it is generally more accurate).

There is a discussion on SO somewhere about it, but I cannot find it at the moment.

Edit: This MSDN Article goes a little more in depth.

Pondidum
http://stackoverflow.com/questions/1087157/accuracy-of-textrenderer-measuretext-results
MusiGenesis
TextRenderer.MeasureText is slower than Graphics.MeasureString, although this probably doesn't matter for most purposes.
MusiGenesis
Thanks for the info, will check that too. I can only mark 1 answer as the correct one and Musi's reply was what I ended up using.
Martín Marconcini