I wish to find the exact height of text rendered in Windows. I have tried both GetTextExtentPoint32 and calling DrawText with the DT_CALCRECT flag and both give the same result.
It seems that the height returned is based on the full cell height, regardless of the actual text to be drawn.
The code below is the WM_PAINT handler for a standard Visual Studio 2013 Win32 project. It creates a (large) font and draws the sample text. The tallest part of the text is 98 pixels, but the value returned by GetTextExtentPoint32 is 131.
I realise that some applications might want the full cell height, but also some applications (like mine) just want the actual height used by the text.
Does anyone know how to find this information?
Yes, I can render to a memory DC and scan down looking for the first non-background coloured pixel – but that is going to be super slow.
Thanks
case WM_PAINT:
{
hdc = BeginPaint (hWnd, &ps);
HFONT hfont = CreateFont (-99, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, VARIABLE_PITCH, L"Segoe UI Semibold");
auto old_hfont = SelectObject (hdc, hfont);
wchar_t sample_text[] = L"123 Testing 123";
size_t sample_text_length = wcslen (sample_text);
SIZE s;
GetTextExtentPoint32 (hdc, sample_text, sample_text_length, &s);
RECT r = {10, 10, 10 + s.cx, 10 + s.cy};
SetBkColor (hdc, RGB (80, 120, 160));
SetTextColor (hdc, RGB (220, 220, 220));
DrawText (hdc, sample_text, sample_text_length, &r, DT_SINGLELINE | DT_NOPREFIX | DT_LEFT | DT_TOP);
SelectObject (hdc, old_hfont);
DeleteObject (hfont);
EndPaint (hWnd, &ps);
break;
}
Have a look at GetGlyphOutline(GGO_METRICS)
The returned GLYPHMETRICS
struct should contain all the data you need to compute the extent.
Your text isn't drawn directly, first he becomes a path which describes the outlines of your geometries/glyphs. A path consists of moves, lines and curves (and a close flag to the prior). Except curves, other path segments are extreme points to the final fill. Converting curves to lines and iterating through all path segments to find the minimum and maximum in horizontal & vertical dimension by the points results in the closest fitting rectangle to your text.
You can convert your text to a path by drawing him with calling BeginPath before and EndPath after. FlattenPath does the curve->line conversion. GetPath provides access to the path points on context. AbortPath finally removes the path from the context.
When you haven't set the background to transparent, the path may be the background around your text and already the first path segments are the background/extents rectangle lines - not what you want.
To simplify this method, you can exclude repeating characters and group characters by 1) below baseline 2) above midline 3) rest. This all together works very fast in comparison to your "look pixels" try.
Other useful sources about text sizes are font metrics (GetTextMetrics) and character widths (GetCharABCWidths)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With