YOU CAN CODE!

 

With The Case Of UCanCode.net  Release The Power OF  Visual C++ !   HomeProducts | PurchaseSupport | Downloads  
Download Evaluation
Pricing & Purchase?
E-XD++Visual C++/ MFC Products
Overview
Features Tour 
Electronic Form Solution
Visualization & HMI Solution
Power system HMI Solution
CAD Drawing and Printing Solution

Bar code labeling Solution
Workflow Solution

Coal industry HMI Solution
Instrumentation Gauge Solution

Report Printing Solution
Graphical modeling Solution
GIS mapping solution

Visio graphics solution
Industrial control SCADA &HMI Solution
BPM business process Solution

Industrial monitoring Solution
Flowchart and diagramming Solution
Organization Diagram Solution

Graphic editor Source Code
UML drawing editor Source Code
Map Diagramming Solution

Architectural Graphic Drawing Solution
Request Evaluation
Purchase
ActiveX COM Products
Overview
Download
Purchase
Technical Support
  General Q & A
Discussion Board
Contact Us

Links

Get Ready to Unleash the Power of UCanCode .NET


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:

  1. Paint the text in black colour, in a memory device context filled with white colour, like this:
    Collapse Copy Code
    SIZE sizeText;
    //Calculate the width of the text, by using the classic method
    GetTextExtentPoint32(hDCMem,szText,lstrlen(szText),&sizeText);
    
    //Calculate the width of the last character, as suggested by 'oupoi'
    SIZE sizeLastCharacter;
    GetTextExtentPoint32(hDCMem,&szText[-1+lstrlen(szText)],1,&sizeLastCharacter);
    
    //Set a bounding rectangle wide enough to fit the painted text
    RECT rect={0,0,sizeText.cx+sizeLastCharacter.cx,sizeText.cy};
    
    //Fill the background with white colour then paint the text in black colour
    FillRect(hDCMem,&rect,(HBRUSH)GetStockObject(WHITE_BRUSH));
    DrawText(hDCMem,szText,-1,&rect, 
             DT_LEFT|DT_TOP|DT_SINGLELINE|DT_NOPREFIX);
  2. 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))
          {
              //found a non-white pixel, save the horizontal position 
              //and exit the loops. Job finished.
              iXmax=x;
              bFound=TRUE;
          }
       }
    }
    
    //this is the width of the text painted in italic font!
    LONG lWidthOfText=iXmax+1;//+1 because we use 0-based indexes

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); 
    
    // overhang of the last character
    double dOverhangTrailing = WidthsABC[szText[lstrlen(szText)-1]].abcfC;
    
    if(dOverhangTrailing<0)
    {
       //if the overhang is negative then adjust 
       //the calculated width of the text
       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
    //fill with white
    FillRect(hDCMem,&rect,(HBRUSH)GetStockObject(WHITE_BRUSH));
    
    // Added this by Mihai Nita - August 17, 2006
    // trick, set text background colour to black, before painting!
    SetBkColor(hDCMem,RGB(0,0,0)); 
    
    //reality shows that DrawText fails to properly 
    //paint the surrounding rectangle (??)
    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; // middle
    
    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;
      }
    }

 

 

Copyright ?1998-2009 UCanCode.Net Software , all rights reserved.
Other product and company names herein may be the trademarks of their respective owners.

Please direct your questions or comments to webmaster@ucancode.net