UCanCode
Software focuses on general application software development. We provide complete solution for developers. No matter you want to develop a simple database
workflow application, or an large flow/diagram based system, our product will provide a complete solution for you. Our product had been used by hundreds of top companies around the world!
"100% source code provided! Free you from not daring to use components because of unable to master the key technology of components!"
|
VC++
Article: Calculate the width of text with
GetTextExtentPoint32,
DT_CALCRECT
and GetCharABCWidths
|
|
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 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:
Collapse
Copy Code
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:
Collapse
Copy Code
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 getting
a more accurate result.
Like this:
Collapse
Copy Code
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 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:
Collapse
Copy Code
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;
}
}
|
|
|
|
|
|