13

I have a WinForms user control and I'm trying to obtain the exact horizontal character spacing for the current font, which is expected to be mono-spaced.

Looks like the font's Size property provides this information but is apparently in points and I'm working in pixels.

var fontWidth = this.Font.Size;   // Returns em-size in points--not pixels

If I create the font myself, I can specify that it uses Pixel units. But in my case the font is set through a property of my user control and I can't determine how the font is created. Unfortunately, the font's Unit property is read-only.

How can I make an existing font return metrics in pixels?

Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466
  • Font.Size returns the *height* of the font, not the width. You'll need to measure with, say, TextRenderer.MeasureText(); Painful because of the padding. Measure, say, new string('m', 100) and divide by 100. – Hans Passant Nov 18 '12 at 19:41
  • Thanks, I was used to hearing about em in the context of the width. I looked at `Graphics.MeasureString` but looks like `MeasureText` is in pixels. I'll check that out, although I'm starting to think my best approach is to add declarations to call the Windows `GetTextMetrics` function. – Jonathan Wood Nov 18 '12 at 19:45
  • @JonathanWood: MeasureText or MeasureString would not give you character spacing, would it? – Victor Zakharov Nov 18 '12 at 19:47
  • @Neolisk: Well, it could be used to calculate character spacing. But it seems there are a lot of complexities from padding, etc. I may go directly to the Windows API or I might be able to rethink what I'm trying to do. – Jonathan Wood Nov 18 '12 at 19:50
  • Avoid assuming there's magic there, TextRenderer also uses the winapi. DrawTextEx() both for measuring and drawing. – Hans Passant Nov 18 '12 at 20:03
  • 1
    @HansPassant: No one is assuming magic. The API will provide `TEXTMETRIC.tmAveCharWidth`. If you see a way to provide this information in pixels via the .NET libraries, then please share. That's all I want. – Jonathan Wood Nov 18 '12 at 20:31
  • As far as I can tell, `TextRenderer.MeasureText("SomeText", MyFont)` doesn't honor decimal font size. If your font is, say, "Courier New, 11.5F", it will return a size based on "Courier New, 12.0F". So it seems a bit useless for any real-world applications where font scaling is involved. – SteveCinq Jul 11 '19 at 23:23

2 Answers2

8

Please see this article on MSDN:

How to: Obtain Font Metrics

To get pixels, you use conversion formula.

descentPixel = font.Size * descent / fontFamily.GetEmHeight(FontStyle.Regular);

Also see Get single glyph metrics (.net).

Burhan
  • 668
  • 5
  • 27
Victor Zakharov
  • 25,801
  • 18
  • 85
  • 151
  • 1
    Thanks but I'm having trouble making sense of this. First, what is `descent`? And second, if I'm trying to get the horizontal spacing, why would we use `GetEmHeight()`, which is returning something about the font height? (Note: I've updating my question as perhaps I wasn't entirely clear I needed the horizontal spacing.) – Jonathan Wood Nov 18 '12 at 19:16
  • @JonathanWood: Still not quite clear on your intent. `Font.Size` is a vertical size of the character, not spacing, and definitely has nothing to do with horizontal character spacing of the font, which is specific to the font you picked. Did you try [this](http://stackoverflow.com/a/485061/897326) to convert em points to pixels? – Victor Zakharov Nov 18 '12 at 19:54
  • Yes, as I pointed out in response to other comments, it appears I was confused about what `Size` does. So it looks like I don't even have a value now to convert. Looking at either the Windows API `GetTextMetrics` or perhaps another approach. – Jonathan Wood Nov 18 '12 at 19:59
8

If using a System.Windows.Forms.Control object, you can use the following code:

using (Graphics g = this.CreateGraphics())
{
    var points = myFont.SizeInPoints;
    var pixels = points * g.DpiX / 72;
    MessageBox.Show("myFont size in pixels: " + pixels);
}
Vedran
  • 10,369
  • 5
  • 50
  • 57