Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to determine maximum number of characters given a fixed width font and a maximum width in pixels

Tags:

c#

.net

gdi+

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.

like image 611
Martin Marconcini Avatar asked Dec 30 '22 13:12

Martin Marconcini


2 Answers

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);
}
like image 66
MusiGenesis Avatar answered Jan 13 '23 15:01

MusiGenesis


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.

like image 27
Pondidum Avatar answered Jan 13 '23 13:01

Pondidum