How to get a character size in pixels?

Hi,
I would like to draw on a given dc some text bounded by a rect.
The problem is that I don't want to get the font height but the character height ( or the max height of a string ). Some font use characters that are much smaller then there font size. an "M" does not reach the top of the font and a "g" does not reach the bottom of the font.

Please advice,
Udi Raz
UdiRazAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

jkrCommented:
You can get that using 'GetTextExtentPoint32()' (http://msdn.microsoft.com/en-us/library/aa911424.aspx), see also http://msdn.microsoft.com/en-us/library/ms534015(VS.85).aspx ("String Widths and Heights")
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
numberkruncherCommented:
Here are some snippets that I used a while back when I was creating a custom text editor.

// If you are using MFC:
CDC dc;
CSize size = dc.GetTextExtent("My String");

// If you are using Win32 SDK
SIZE size = {0};
::GetTextExtentPoint(hdc, "My String", strlen("My String"), &size);

0
ZoppoCommented:
Hi UdiRa,

further you can use 'DrawText' with flag 'DT_CALCRECT' - this is helpful if you want the size of multiline texts if you have a given width to draw to.

ZOPPO
0
Cloud Class® Course: Ruby Fundamentals

This course will introduce you to Ruby, as well as teach you about classes, methods, variables, data structures, loops, enumerable methods, and finishing touches.

itsmeandnobodyelseCommented:
To add to above comments:

For all these functions you must have selected the font to the dc by calling SelectObject. And it actually works only if the dc was associated to an existing window (hwnd) and was ready for painting.
0
numberkruncherCommented:
Hi UdiRaz

Did you manage to solve your problem? or did you need any further assistance?
0
UdiRazAuthor Commented:
I'm sorry guys, my boss ask me to do something else so it will take me couple of day to get back into it.

Thanks
0
UdiRazAuthor Commented:
Both GetTextExtent and GetTextExtentPoint32 returns the font size as height and not the real height of the text.

I created a dialog and draw some characters in english and Hindi using a font that supports both languages.

below is a code snippet and an image of the result.
void CFontSizeTestDlg::OnBnClickedDrawText()
{
	CFont tmpFont;
 
	VERIFY(tmpFont.CreateFont(
		22,						    // nHeight
		0,                         // nWidth
		0,                         // nEscapement
		0,                         // nOrientation
		FW_REGULAR,				   // nWeight
		FALSE,                     // bItalic
		FALSE,                     // bUnderline
		0,                         // cStrikeOut
		ANSI_CHARSET,              // nCharSet
		OUT_DEFAULT_PRECIS,        // nOutPrecision
		CLIP_DEFAULT_PRECIS,       // nClipPrecision
		DEFAULT_QUALITY,           // nQuality
		DEFAULT_PITCH | FF_SWISS,  // nPitchAndFamily
		_T("Mangal")));  // lpszFacename
 
	// Do something with the font just created...
	CDC* dc = GetDC();
	dc->SelectObject(&tmpFont);
 
//	TEXTMETRIC txt;
//	dc->GetTextMetrics( &txt);
	CRect rect;
	rect.SetRect( CPoint(10, 10), CPoint(300, 100));
 
	LPTSTR hindiString = new TCHAR[2];
	hindiString[0] = 0x915;
	hindiString[1] = 0;
	CString str = _T("Mg - ");
	str += hindiString;
 
	dc->DrawText(str, rect, DT_CENTER | DT_VCENTER);
 
	//////////////////////////////////////////////////////
 
	CSize size = dc->GetTextExtent(_T("My String"));
	CSize size1 = dc->GetTextExtent(hindiString);
 
	LPSIZE lpSize = new SIZE, lpSize1 = new SIZE;
	::GetTextExtentPoint32(dc->GetSafeHdc(), _T("My String"), 9, lpSize );
	::GetTextExtentPoint32(dc->GetSafeHdc(), hindiString, 1, lpSize1 );
 
}

Open in new window

drawText.JPG
0
numberkruncherCommented:
dc->GetTextExtent should be returning the height of the white block behind the text.


Also when using the Win32 equivalents you could use the following instead of dynamically allocating memory and forgetting to delete it.
HDC safeHdc = dc->GetSafeHdc();
 
SIZE sizeA = {0}, sizeB = {0};
::GetTextExtentPoint32(safeHdc, _T("My String"), 9, &sizeA);
::GetTextExtentPoint32(safeHdc, hindiString, 1, &sizeB);

Open in new window

0
numberkruncherCommented:
If you are trying to find the height of actual text (i.e. black ink) then you will probably need to manually measure the ink by finding the topmost position of black, and the bottommost position of black, and then calculating the distance between. I don't know of a Win32 API function which will do this for you.

This could of course become a slow process if you are working with a lot of text.
0
UdiRazAuthor Commented:
1. the height of the whiteblock is the font size
2. I do expect to find an api since there are a lot of params that define a character glyph as describes here: http://msdn.microsoft.com/en-us/library/ms534015(VS.85).aspx

I am looking for an api that input a character and return these values.
0
UdiRazAuthor Commented:
I found this method : GetGlyphOutline. But I think I am using it in a wrong way becuase I don't get the expected result.
/****************************************************************************
 *
 *  FUNCTION   : PaintIt(hWnd)
 *
 *  PURPOSE    : Demonstrate getting the glyph information by filling the 
 *               window with a whole bunch of characters.  Very simplistic
 *               character placement is used.
 *
 *  RETURNS    : None.
 *
 ****************************************************************************/
void PASCAL NEAR PaintIt(HWND hWnd)
{
    PAINTSTRUCT ps;
    HDC hdcScreen;
    LOGFONT lf;
    TEXTMETRIC tm;
    WORD x = 0, y = 0;
    UINT i;
    HFONT hfOld;
	GLYPHMETRICS gm;
	MAT2 mat;
 
    hdcScreen = BeginPaint(hWnd, &ps);
    hfOld = SelectObject(hdcScreen, hMyFont);
    GetTextMetrics(hdcScreen, &tm);
	IdentityMat(&mat);
 
	GetGlyphOutline( hdcScreen, 'm', GGO_NATIVE, &gm, 0, NULL, &mat);
 
	OutputGlyph(hdcScreen, 'm', x, y, tm.tmAscent);
	x += (tm.tmMaxCharWidth+2)/2;
	if (x > 600)     // Extremely arbitrary hardcoded width.
	{
		x = 0;
		y += tm.tmHeight + 5;
	}
	GetGlyphOutline( hdcScreen, 'i', GGO_NATIVE, &gm, 0, NULL, &mat);
 
	OutputGlyph(hdcScreen, 'i', x, y, tm.tmAscent);
	x += (tm.tmMaxCharWidth+2)/2;
	if (x > 600)     // Extremely arbitrary hardcoded width.
	{
		x = 0;
		y += tm.tmHeight + 5;
	}
 
	GetGlyphOutline( hdcScreen, 'M', GGO_NATIVE, &gm, 0, NULL, &mat);
 
	OutputGlyph(hdcScreen, 'M', x, y, tm.tmAscent);
	x += (tm.tmMaxCharWidth+2)/2;
	if (x > 600)     // Extremely arbitrary hardcoded width.
	{
		x = 0;
		y += tm.tmHeight + 5;
	}
 
	GetGlyphOutline( hdcScreen, 'g', GGO_NATIVE, &gm, 0, NULL, &mat);
 
	OutputGlyph(hdcScreen, 'g', x, y, tm.tmAscent);
	x += (tm.tmMaxCharWidth+2)/2;
	if (x > 600)     // Extremely arbitrary hardcoded width.
	{
		x = 0;
		y += tm.tmHeight + 5;
	}
 
	hfOld = SelectObject(hdcScreen, hMyHindiFont);
	GetTextMetrics(hdcScreen, &tm);
	IdentityMat(&mat);
 
	GetGlyphOutline( hdcScreen, 0x915, GGO_NATIVE, &gm, 0, NULL, &mat);
 
	OutputGlyph(hdcScreen, 0x915, x, y, tm.tmAscent);
	x += (tm.tmMaxCharWidth+2)/2;
	if (x > 600)     // Extremely arbitrary hardcoded width.
	{
		x = 0;
		y += tm.tmHeight + 5;
	}
 
    SelectObject(hdcScreen, hfOld);
    EndPaint(hWnd, &ps);
}

Open in new window

0
numberkruncherCommented:
I believe that 'GetGlyphOutline' extracts the specified character from a font and puts it into a buffer. Most vector fonts should contain the data you need (gmBlackBoxY) but this approach would require you to decide between:

Fast performance - Preload the desired height of all glyph characters into an integer array, and then refer to these at a later stage. Could be slow during caching process, but would also require more memory.

Efficient memory and initial startup performance - Get glyph character by character, BUT this will probably be extremely slow, especially if you have a lot of text to process character by character.

I used this function a very long time ago to pre-render a font into a bitmap so that I could display it in a video game. Here is a link that demonstrates how this function can be used (the example is some way down the page):
http://www.gamedev.net/community/forums/topic.asp?topic_id=443128
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C++

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.