Solved

How to get a character size in pixels?

Posted on 2008-10-23
12
932 Views
Last Modified: 2011-10-19
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
0
Comment
Question by:UdiRaz
12 Comments
 
LVL 86

Accepted Solution

by:
jkr earned 500 total points
ID: 22788382
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
 
LVL 13

Expert Comment

by:numberkruncher
ID: 22788398
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
 
LVL 30

Expert Comment

by:Zoppo
ID: 22788615
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
 
LVL 39

Expert Comment

by:itsmeandnobodyelse
ID: 22788858
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
 
LVL 13

Expert Comment

by:numberkruncher
ID: 22816866
Hi UdiRaz

Did you manage to solve your problem? or did you need any further assistance?
0
 

Author Comment

by:UdiRaz
ID: 22819408
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
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 

Author Comment

by:UdiRaz
ID: 22831513
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
 
LVL 13

Expert Comment

by:numberkruncher
ID: 22831693
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
 
LVL 13

Expert Comment

by:numberkruncher
ID: 22831811
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
 

Author Comment

by:UdiRaz
ID: 22838426
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
 

Author Comment

by:UdiRaz
ID: 22838454
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
 
LVL 13

Expert Comment

by:numberkruncher
ID: 22843902
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

Featured Post

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

IntroductionThis article is the second in a three part article series on the Visual Studio 2008 Debugger.  It provides tips in setting and using breakpoints. If not familiar with this debugger, you can find a basic introduction in the EE article loc…
C++ Properties One feature missing from standard C++ that you will find in many other Object Oriented Programming languages is something called a Property (http://www.experts-exchange.com/Programming/Languages/CPP/A_3912-Object-Properties-in-C.ht…
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

22 Experts available now in Live!

Get 1:1 Help Now