Textrenderer.Measuretext and Graphics.Measurestring Mismatch in Size

TextRenderer.MeasureText and Graphics.MeasureString mismatch in size

TextRenderer uses GDI to render the text, whereas Graphics uses GDI+. The two use a slightly different method for laying out text so the sizes are different.

Which one you should use depends on what will eventually be used to actually draw the text. If you are drawing it with GDI+ Graphics.DrawString, measure using Graphics.MeasureString. If you are drawing using GDI TextRenderer.DrawText, measure using TextRenderer.MeasureText.

If the text will be displayed inside a Windows Forms control, it uses TextRenderer if UseCompatibleTextRendering is set to false (which is the default).

Reading between the lines of your question, you seem to be using TextRenderer because you don't have a Graphics instance outside the Paint event. If that's the case, you can create one yourself to do the measuring:

using( Graphics g = someControl.CreateGraphics() )
{
SizeF size = g.MeasureString("some text", SystemFonts.DefaultFont);
}

If you don't have access to a control to create the graphics instance you can use this to create one for the screen, which works fine for measurement purposes.

using( Graphics g = Graphics.FromHwnd(IntPtr.Zero) )
{
SizeF size = g.MeasureString("some text", SystemFonts.DefaultFont);
}

Unable to get correct Size of DrawnText using TextRenderer

instead of using TextRenderer use GraphicsPath:

var path = new GraphicsPath();
path.AddString(text, font.FontFamily, (int)font.Style, size, new Point(0, 0), StringFormat.GenericTypographic);
var area = Rectangle.Round(path.GetBounds());

Here is sample code that generates image with size of text:

private Image DrawText(String text, Font font, int size, Color textColor, Color backColor)
{
var path = new GraphicsPath();
path.AddString(text, font.FontFamily, (int)font.Style, size, new Point(0, 0), StringFormat.GenericTypographic);
var area = Rectangle.Round(path.GetBounds());

Rectangle br = Rectangle.Round(path.GetBounds());
var img = new Bitmap(br.Width, br.Height);

var drawing = Graphics.FromImage(img);
drawing.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
drawing.SmoothingMode = SmoothingMode.HighSpeed;
drawing.Clear(backColor);

drawing.TranslateTransform((img.Width - br.Width) / 2 - br.X, (img.Height - br.Height) / 2 - br.Y);
drawing.FillPath(Brushes.Black, path);
Brush textBrush = new SolidBrush(textColor);

drawing.Save();

textBrush.Dispose();
drawing.Dispose();

return img;
}

Here are sample results:

Sample Image
Sample Image
Sample Image

problem with TextRenderer.MeasureText

MeasureText is not known to be accurate.

Heres a better way :

    protected int _MeasureDisplayStringWidth ( Graphics graphics, string text, Font font )
{
if ( text == "" )
return 0;

StringFormat format = new StringFormat ( StringFormat.GenericDefault );
RectangleF rect = new RectangleF ( 0, 0, 1000, 1000 );
CharacterRange[] ranges = { new CharacterRange ( 0, text.Length ) };
Region[] regions = new Region[1];

format.SetMeasurableCharacterRanges ( ranges );
format.FormatFlags = StringFormatFlags.MeasureTrailingSpaces;

regions = graphics.MeasureCharacterRanges ( text, font, rect, format );
rect = regions[0].GetBounds ( graphics );

return (int)( rect.Right );
}

How to correctly measure characters in string using TextRenderer?

You should use MeasureString from the graphics object. Also take a look at TextRenderer.MeasureText and Graphics.MeasureString mismatch in size. It will explain the difference.

Adapt the height of a TextBox

TextBox.GetPositionFromCharIndex returns the pixel position of a character. Position here means top/left so we need to add one more line..

This seems to work here:

textBox.Height = textBox.GetPositionFromCharIndex(textBox4.Text.Length - 1).Y + lineHeight;

I get the line height like this:

int lineHeight = -1;
using (TextBox t = new TextBox() { Font = textBox.Font }) lineHeight = t.Height;

I set the Height instead of the ClientSize.Height, which is slightly wrong unless BorderStyle is None. You can change to textBox.ClientSize = new Size(textBox.ClientSize.Width, l + lh);



Related Topics



Leave a reply



Submit