MeasureString() pads the text on the left and the right
Asked Answered
F

5

18

I'm using GDI+ in C++. (This issue might exist in C# too).

I notice that whenever I call Graphics::MeasureString() or Graphics::DrawString(), the string is padded with blank space on the left and right.

For example, if I am using a Courier font, (not italic!) and I measure "P" I get 90, but "PP" gives me 150. I would expect a monospace font to give exactly double the width for "PP".

My question is: is this intended or documented behaviour, and how do I disable this?

RectF Rect(0,0,32767,32767);
RectF Bounds1, Bounds2;
graphics->MeasureString(L"PP", 1, font, Rect, &Bounds1);
graphics->MeasureString(L"PP", 2, font, Rect, &Bounds2);
margin = Bounds1.Width * 2 - Bounds2.Width;
Frog answered 23/9, 2008 at 1:45 Comment(0)
F
13

It's by design, that method doesn't use the actual glyphs to measure the width and so adds a little padding in the case of overhangs.

MSDN suggests using a different method if you need more accuracy:

To obtain metrics suitable for adjacent strings in layout (for example, when implementing formatted text), use the MeasureCharacterRanges method or one of the MeasureString methods that takes a StringFormat, and pass GenericTypographic. Also, ensure the TextRenderingHint for the Graphics is AntiAlias.

From answered 23/9, 2008 at 2:10 Comment(2)
This removes the horizontal padding, but not the vertical padding. Ugh.Buttonball
I did all this tuning and it improved the situation, but anyway MeasureString returns a little bit smaller value for width. I have to add 0.3333f for every character in string to compensate this and get the correct width. With this it works almost perfectly. Any thoughts what have I missed so that I have to make this manual adjustment? It doesn't depend on the letters used - narrow or wide; just have to add this value for every character in the string.Airscrew
L
6

It's true that is by design, however the link on the accepted answer is actually not perfect. The issue is the use of floats in all those methods when what you really want to be using is pixels (ints).

The TextRenderer class is meant for this purpose and works with the true sizes. See this link from msdn for a walkthrough of using this.

Licit answered 12/11, 2008 at 8:28 Comment(2)
I get better results with TextRenderer class.Brigid
TextRenderer was exactly what I needed in a similar situationLakendra
T
5

Append StringFormat.GenericTypographic will fix your issue:

graphics->MeasureString(L"PP", 1, font, width, StringFormat.GenericTypographic);

Apply the same attribute to DrawString.

Tolentino answered 15/12, 2011 at 6:20 Comment(2)
GenericTypographic is ideal for me, because I'm using my own margin in the control anyway.Cash
Almost perfect but the little paddings are necessary.Bragi
S
1

Sounds like it might also be connecting to hinting, based on this kb article, Why text appears different when drawn with GDIPlus versus GDI

Shortie answered 23/9, 2008 at 2:13 Comment(0)
H
0

TextRenderer was great for getting the size of the font. But in the drawing loop, using TextRenderer.DrawText was excruciatingly slow compared to graphics.DrawString().

Since the width of a string is the problem, your much better off using a combination of TextRenderer.MeasureText and graphics.DrawString..

Hemato answered 4/12, 2008 at 21:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.