Introduction
Our purpose is to measure accurately the width of text written in italic font.
Using the Code
The GetTextExtentPoint32
Win32 API function or the DrawText
Win32 API function with the DT_CALCRECT
flag, will -not- tell us the correct width of text in italic font, only the calculated height is correct. For most of the italic fonts, using these two functions, the calculated width is too narrow and the displayed text looks right-trimmed.
We could try using the GetCharABCWidths
or GetCharABCWidthsFloat
Win32 API functions. These functions will give us information about the underhang and the overhang of each character of the text we're interested in.
Please check these MSDN articles for more details about using the underhang and overhang values:
This updated version of the EXE includes a new checkbox, to see how adding the 'overhang of the last character' will help in getting a more accurate result.
However, in this article, I am suggesting another approach:
- Paint the text in black colour, in a memory device context filled with white colour, like this:
SIZE sizeText;
GetTextExtentPoint32(hDCMem,szText,lstrlen(szText),&sizeText);
SIZE sizeLastCharacter;
GetTextExtentPoint32(hDCMem,&szText[-1+lstrlen(szText)],1,&sizeLastCharacter);
RECT rect={0,0,sizeText.cx+sizeLastCharacter.cx,sizeText.cy};
FillRect(hDCMem,&rect,(HBRUSH)GetStockObject(WHITE_BRUSH));
DrawText(hDCMem,szText,-1,&rect,
DT_LEFT|DT_TOP|DT_SINGLELINE|DT_NOPREFIX);
- Then, scan the colour of the pixels in the memory device context, from right-to-left, like this:
int iXmax=0;
BOOL bFound=FALSE;
for(int x=rect.right-1; x>=0 && !bFound; x--)
{
for(int y=0; y<=rect.bottom-1 && !bFound; y++)
{
COLORREF rgbColor=GetPixel(hDCMem,x,y);
if(rgbColor!=RGB(255,255,255))
{
iXmax=x;
bFound=TRUE;
}
}
}
LONG lWidthOfText=iXmax+1;
A few comments:
- Painted text can be narrower than text calculated with
GetTextExtentPoint32
. See, for example, Verdana 12 Italic. - In a dialog box, the edit controls have left/right and up/down margins to take into account. I have not used edit controls in this sample.
- In a dialog box, the label controls seem to be +1 pixel wider, unless the
SS_SIMPLE
style is used. See the image below.
History
- Version 1.0 [July 23, 2006] - Created
- Version 1.1 [August 6, 2006] - New checkbox to see how adding the 'overhang of the last character' to the classic method of calculating the text width will help in getting a more accurate result.
Like this:
SIZE sizeText;
GetTextExtentPoint32(hDCMem, szText, lstrlen(szText), &sizeText);
LONG lWidthOfText= sizeText.cx;
ABCFLOAT WidthsABC[256];
GetCharABCWidthsFloat(hDCMem, 0, 255, WidthsABC);
double dOverhangTrailing = WidthsABC[szText[lstrlen(szText)-1]].abcfC;
if(dOverhangTrailing<0)
{
lWidthOfText-=dOverhangTrailing;
}
But as already mentioned above, this article is suggesting another method, which doesn't require using any of these underhang and overhang values.
- Version 1.2 [August 17, 2006] - Adjustment to the right-to-left pixel colour scanning algorithm.
Set the right-limit of the bounding rectangle to be scanned to just 'sizeText.cx+widthOfTheLastCharacter
', as suggested by 'oupoi'.
We now also have a new checkbox to test if using the Mihai Nita's trick will help in getting a faster calculation and at the same time, of course, an accurate result.
Unless I've made a mistake somewhere, I'm not satisfied by the precision of the result by using the Mihai Nita's trick.
Like this:
FillRect(hDCMem,&rect,(HBRUSH)GetStockObject(WHITE_BRUSH));
SetBkColor(hDCMem,RGB(0,0,0));
DrawText(hDCMem,szText,-1, &rect,
DT_LEFT|DT_TOP|DT_SINGLELINE|DT_NOPREFIX);
int iXmax=0;
BOOL bFound=FALSE;
int iYmed=(rect.bottom+rect.top)/2;
for(int x=rect.right-1;x>=0 && !bFound ;x--)
{
COLORREF rgbColor=GetPixel(hDCMem,x,iYmed);
if(rgbColor!=RGB(255,255,255))
{
iXmax=x;
bFound=TRUE;
}
}
- Version 1.3 [July 25, 2018] - Recompiled the demo program to display regional characters like șȚ
License
This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below.
A list of licenses authors might use can be found here.