Thread: Font creation doubt

  1. #1
    Registered User
    Join Date
    Apr 2008
    Posts
    49

    Font creation doubt

    I have a doubt about an example in "Programming Windows 95" (Charles Petzold), Chapter 4.

    The example is the following. It contains a function EzCreateFont whose purpose is to create a font and return its handle.

    Code:
    /*----------------------
       EZFONT.H header file
      ----------------------*/
    
    HFONT EzCreateFont (HDC hdc, char * szFaceName, int iDeciPtHeight,
                        int iDeciPtWidth, int iAttributes, BOOL fLogRes) ;
    
    #define EZ_ATTR_BOLD          1
    #define EZ_ATTR_ITALIC        2
    #define EZ_ATTR_UNDERLINE     4
    #define EZ_ATTR_STRIKEOUT     8
    Code:
    /*---------------------------------------
       EZFONT.C -- Easy Font Creation
                   (c) Charles Petzold, 1996
      ---------------------------------------*/
    
    #include <windows.h>
    #include <string.h>
    #include <math.h>
    #include "ezfont.h"
    
    HFONT EzCreateFont (HDC hdc, char * szFaceName, int iDeciPtHeight,
                        int iDeciPtWidth, int iAttributes, BOOL fLogRes)
         {
         FLOAT      cxDpi, cyDpi ;
         HFONT      hFont ;
         LOGFONT    lf ;
         POINT      pt ;
         TEXTMETRIC tm ;
    
         SaveDC (hdc) ;
    
         SetGraphicsMode (hdc, GM_ADVANCED) ;
         ModifyWorldTransform (hdc, NULL, MWT_IDENTITY) ;
         SetViewportOrgEx (hdc, 0, 0, NULL) ;
         SetWindowOrgEx   (hdc, 0, 0, NULL) ;
    
         if (fLogRes)
              {
              cxDpi = (FLOAT) GetDeviceCaps (hdc, LOGPIXELSX) ;
              cyDpi = (FLOAT) GetDeviceCaps (hdc, LOGPIXELSY) ;
              }
         else
              {
              cxDpi = (FLOAT) (25.4 * GetDeviceCaps (hdc, HORZRES) /
                                      GetDeviceCaps (hdc, HORZSIZE)) ;
    
              cyDpi = (FLOAT) (25.4 * GetDeviceCaps (hdc, VERTRES) /
                                      GetDeviceCaps (hdc, VERTSIZE)) ;
              }
    
         pt.x = (int) (iDeciPtWidth  * cxDpi / 72) ;
         pt.y = (int) (iDeciPtHeight * cyDpi / 72) ;
    
         DPtoLP (hdc, &pt, 1) ;
    
         lf.lfHeight         = - (int) (fabs (pt.y) / 10.0 + 0.5) ;
         lf.lfWidth          = 0 ;
         lf.lfEscapement     = 0 ;
         lf.lfOrientation    = 0 ;
         lf.lfWeight         = iAttributes & EZ_ATTR_BOLD      ? 700 : 0 ;
         lf.lfItalic         = iAttributes & EZ_ATTR_ITALIC    ?   1 : 0 ;
         lf.lfUnderline      = iAttributes & EZ_ATTR_UNDERLINE ?   1 : 0 ;
         lf.lfStrikeOut      = iAttributes & EZ_ATTR_STRIKEOUT ?   1 : 0 ;
         lf.lfCharSet        = 0 ;
         lf.lfOutPrecision   = 0 ;
         lf.lfClipPrecision  = 0 ;
         lf.lfQuality        = 0 ;
         lf.lfPitchAndFamily = 0 ;
    
         strcpy (lf.lfFaceName, szFaceName) ;
    
         hFont = CreateFontIndirect (&lf) ;
    
         if (iDeciPtWidth != 0)
              {
              hFont = (HFONT) SelectObject (hdc, hFont) ;
    
              GetTextMetrics (hdc, &tm) ;
    
              DeleteObject (SelectObject (hdc, hFont)) ;
    
              lf.lfWidth = (int) (tm.tmAveCharWidth *
                                  fabs (pt.x) / fabs (pt.y) + 0.5) ;
    
              hFont = CreateFontIndirect (&lf) ;
              }
    
         RestoreDC (hdc, -1) ;
    
         return hFont ;
         }
    In this function, the parameters of EzCreateFont are the following: hdc is the handle to the device context for which the font will be created; szFaceName is the name of the font; iDeciPtHeight and iDeciPtWidth are the height and width of the font in tenths of a point; iAttributes receives attributes defined in EZFONT.H and is used by EzCreateFont to define font attributes (weight, italic, underline, strike-out); and fLogRes is a boolean value that determines whether or not the font should be created using logical inches.
    I see that the values of iDeciPtWidth and iDeciPtHeight are converted to pixels and then stored in a POINT structure called pt. Then, the function DPtoLP is called, in order to convert pt.x and pt.y into the logical units of the device context.
    I also understand that, if the lfWidth member of the LOGFONT structure is set to zero, the calculation of the appropriate font width will be left to Windows, during the creation of the font, based on the value of lfHeight.
    However, my doubt concerns the part of the code where it determines the value of lfWidth. I see that the code leaves the value of lfWidth as zero initially; afterwards, it creates the font, and, only after that, it verifies the value of the iDeciPtWidth parameter. To determine the value of lfWidth, it selects the already created font into the device context in order to get its average character width (which is available through the GetTextMetrics function). However, I'm not sure why this is needed to correctly determine the value of lfWidth.
    Why can't I just erase the if (iDeciPtWidth != 0) block and write EzCreateFont like below? (the modified portions are highlighted in red)

    Code:
    HFONT EzCreateFont (HDC hdc, char * szFaceName, int iDeciPtHeight,
                        int iDeciPtWidth, int iAttributes, BOOL fLogRes)
         {
         FLOAT      cxDpi, cyDpi ;
         HFONT      hFont ;
         LOGFONT    lf ;
         POINT      pt ;
         TEXTMETRIC tm ;
    
         SaveDC (hdc) ;
    
         SetGraphicsMode (hdc, GM_ADVANCED) ;
         ModifyWorldTransform (hdc, NULL, MWT_IDENTITY) ;
         SetViewportOrgEx (hdc, 0, 0, NULL) ;
         SetWindowOrgEx   (hdc, 0, 0, NULL) ;
    
         if (fLogRes)
              {
              cxDpi = (FLOAT) GetDeviceCaps (hdc, LOGPIXELSX) ;
              cyDpi = (FLOAT) GetDeviceCaps (hdc, LOGPIXELSY) ;
              }
         else
              {
              cxDpi = (FLOAT) (25.4 * GetDeviceCaps (hdc, HORZRES) /
                                      GetDeviceCaps (hdc, HORZSIZE)) ;
    
              cyDpi = (FLOAT) (25.4 * GetDeviceCaps (hdc, VERTRES) /
                                      GetDeviceCaps (hdc, VERTSIZE)) ;
              }
    
         pt.x = (int) (iDeciPtWidth  * cxDpi / 72) ;
         pt.y = (int) (iDeciPtHeight * cyDpi / 72) ;
    
         DPtoLP (hdc, &pt, 1) ;
    
         lf.lfHeight         = - (int) (fabs (pt.y) / 10.0 + 0.5) ;
         lf.lfWidth          = pt.x/10 ; //MODIFIED LINE
         lf.lfEscapement     = 0 ;
         lf.lfOrientation    = 0 ;
         lf.lfWeight         = iAttributes & EZ_ATTR_BOLD      ? 700 : 0 ;
         lf.lfItalic         = iAttributes & EZ_ATTR_ITALIC    ?   1 : 0 ;
         lf.lfUnderline      = iAttributes & EZ_ATTR_UNDERLINE ?   1 : 0 ;
         lf.lfStrikeOut      = iAttributes & EZ_ATTR_STRIKEOUT ?   1 : 0 ;
         lf.lfCharSet        = 0 ;
         lf.lfOutPrecision   = 0 ;
         lf.lfClipPrecision  = 0 ;
         lf.lfQuality        = 0 ;
         lf.lfPitchAndFamily = 0 ;
    
         strcpy (lf.lfFaceName, szFaceName) ;
    
         hFont = CreateFontIndirect (&lf) ;
    
         //The block that recreates the font based on the value of iDeciPtWidth is excluded
         /*
         if (iDeciPtWidth != 0) {
         ...
         }
         */
    
         RestoreDC (hdc, -1) ;
    
         return hFont ;
         }
    I do realize that, with this second version, the font gets created with different dimensions than those of the original version. For example, consider what happens in both versions when I call the EzCreateFont function like this:

    Code:
    HFONT f;
    f = EzCreateFont(hcd, "Times New Roman", 120, 120, 0, TRUE);
    In the original version, I get the same font as if I had called it with the iDeciPtWidth parameter set to zero. However, in the modified version, the width of the created font is a little bigger than what I get using the original version.

    However, I don't quite understand the difference. Could anyone explain?

    Thank you in advance.
    Last edited by pc2-brazil; 07-01-2013 at 05:36 PM.

  2. #2
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    Have you tried it?

    iDeciPtWidth is apparently an input parameter that is meant to be potentially passed in as zero, which skips the iDeciPtWidth != 0 block. If it is non-zero then the average character width of the chosen font is multiplied by the aspect ratio pt.x over pt.y. This stretches or shrinks the average width.

  3. #3
    Registered User
    Join Date
    Apr 2008
    Posts
    49
    Quote Originally Posted by oogabooga View Post
    Have you tried it?

    iDeciPtWidth is apparently an input parameter that is meant to be potentially passed in as zero, which skips the iDeciPtWidth != 0 block. If it is non-zero then the average character width of the chosen font is multiplied by the aspect ratio pt.x over pt.y. This stretches or shrinks the average width.
    Yes, I attempted to create a font with iDeciPtHeight = 120 and iDeciPtWidth = 120 (there is a very brief description of this attempt at the end of the original post). But my doubt is why lfWidth needs to be calculated using this specific method in order to get the appropriate value, as opposed to being calculated as pt.x/10 (the modification that I suggested in the original post).

  4. #4
    Registered User
    Join Date
    Apr 2008
    Posts
    49
    Since I posted only the function EzCreateFont, and not a complete application that others can directly run, it is more difficult for others to help.

    So, just for convenience, here is the application that I used to test EzCreateFont. It uses this function to create a font and display a text in the center of the client area of a window.

    Code:
    #include <windows.h>
    #include <math.h>
    
    LRESULT CALLBACK ProcJan (HWND, UINT, WPARAM, LPARAM);
    
    HFONT EzCreateFont (HDC hdc, char * szFaceName, int iDeciPtHeight,
                        int iDeciPtWidth, int iAttributes, BOOL fLogRes) ;
    
    #define EZ_ATTR_BOLD          1
    #define EZ_ATTR_ITALIC        2
    #define EZ_ATTR_UNDERLINE     4
    #define EZ_ATTR_STRIKEOUT     8
    
    HFONT EzCreateFont (HDC hdc, char * szFaceName, int iDeciPtHeight,
                        int iDeciPtWidth, int iAttributes, BOOL fLogRes)
         {
         FLOAT      cxDpi, cyDpi ;
         HFONT      hFont ;
         LOGFONT    lf ;
         POINT      pt ;
         TEXTMETRIC tm ;
    
         SaveDC (hdc) ;
    
         SetGraphicsMode (hdc, GM_ADVANCED) ;
         ModifyWorldTransform (hdc, NULL, MWT_IDENTITY) ;
         SetViewportOrgEx (hdc, 0, 0, NULL) ;
         SetWindowOrgEx   (hdc, 0, 0, NULL) ;
    
         if (fLogRes)
              {
              cxDpi = (FLOAT) GetDeviceCaps (hdc, LOGPIXELSX) ;
              cyDpi = (FLOAT) GetDeviceCaps (hdc, LOGPIXELSY) ;
              }
         else
              {
              cxDpi = (FLOAT) (25.4 * GetDeviceCaps (hdc, HORZRES) /
                                      GetDeviceCaps (hdc, HORZSIZE)) ;
    
              cyDpi = (FLOAT) (25.4 * GetDeviceCaps (hdc, VERTRES) /
                                      GetDeviceCaps (hdc, VERTSIZE)) ;
              }
    
         pt.x = (int) (iDeciPtWidth  * cxDpi / 72) ;
         pt.y = (int) (iDeciPtHeight * cyDpi / 72) ;
    
         DPtoLP (hdc, &pt, 1) ;
    
         lf.lfHeight         = - (int) (fabs (pt.y) / 10.0 + 0.5) ;
         lf.lfWidth          = 0 ;
         lf.lfEscapement     = 0 ;
         lf.lfOrientation    = 0 ;
         lf.lfWeight         = iAttributes & EZ_ATTR_BOLD      ? 700 : 0 ;
         lf.lfItalic         = iAttributes & EZ_ATTR_ITALIC    ?   1 : 0 ;
         lf.lfUnderline      = iAttributes & EZ_ATTR_UNDERLINE ?   1 : 0 ;
         lf.lfStrikeOut      = iAttributes & EZ_ATTR_STRIKEOUT ?   1 : 0 ;
         lf.lfCharSet        = 0 ;
         lf.lfOutPrecision   = 0 ;
         lf.lfClipPrecision  = 0 ;
         lf.lfQuality        = 0 ;
         lf.lfPitchAndFamily = 0 ;
    
         strcpy (lf.lfFaceName, szFaceName) ;
    
         hFont = CreateFontIndirect (&lf) ;
    
         if (iDeciPtWidth != 0)
              {
              hFont = (HFONT) SelectObject (hdc, hFont) ;
    
              GetTextMetrics (hdc, &tm) ;
    
              DeleteObject (SelectObject (hdc, hFont)) ;
    
              lf.lfWidth = (int) (tm.tmAveCharWidth *
                                  fabs (pt.x) / fabs (pt.y) + 0.5) ;
    
              hFont = CreateFontIndirect (&lf) ;
              }
    
         RestoreDC (hdc, -1) ;
    
         return hFont ;
         }
    
    int WINAPI WinMain (HINSTANCE hCopia, HINSTANCE hCopiaAnt,
                        PSTR szLinhaCmd, int iCmdMostrar)
         {
         static char szNomeAplic[] = "Olawin";
         HWND        hjan;
         MSG         msg;
         WNDCLASSEX  classejan;
    
         classejan.cbSize        = sizeof (classejan);
         classejan.style         = CS_HREDRAW | CS_VREDRAW;
         classejan.lpfnWndProc   = ProcJan;
         classejan.cbClsExtra    = 0;
         classejan.cbWndExtra    = 0;
         classejan.hInstance     = hCopia;
         classejan.hIcon         = LoadIcon (NULL, IDI_APPLICATION);
         classejan.hCursor       = LoadCursor (NULL, IDC_ARROW);
         classejan.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
         classejan.lpszMenuName  = NULL;
         classejan.lpszClassName = szNomeAplic;
         classejan.hIconSm       = LoadIcon (NULL, IDI_APPLICATION);
    
         RegisterClassEx (&classejan);
    
         hjan = CreateWindow (szNomeAplic,
                               "Programa Ola",
                       WS_OVERLAPPEDWINDOW,
                       CW_USEDEFAULT,
                       CW_USEDEFAULT,
                       CW_USEDEFAULT,
                       CW_USEDEFAULT,
                       NULL,
                       NULL,
                       hCopia,
                       NULL);
    
         ShowWindow (hjan, iCmdMostrar);
         UpdateWindow (hjan);
    
         while (GetMessage (&msg, NULL, 0, 0))
              {
              TranslateMessage (&msg);
              DispatchMessage (&msg);
              }
         return msg.wParam;
         }
    
    LRESULT CALLBACK ProcJan (HWND hjan, UINT iMsg, WPARAM wParam, LPARAM lParam)
         {
         HDC         hcd;
         PAINTSTRUCT ps;
         RECT        retang;
    
         switch (iMsg)
              {
    
              case WM_PAINT :
                       hcd = BeginPaint (hjan, &ps);
                    HFONT f;
                    f = EzCreateFont(hcd, "Times New Roman", 120, 120, 0, TRUE);
    
                    SelectObject(hcd, f);
    
                   GetClientRect (hjan, &retang);
    
                   DrawText (hcd, "Sample Text", -1, &retang,
                             DT_SINGLELINE | DT_CENTER | DT_VCENTER);
    
                       EndPaint (hjan, &ps);
    
                       DeleteObject(f);
                   return 0;
    
              case WM_DESTROY :
                   PostQuitMessage (0);
                   return 0;
              }
    
         return DefWindowProc (hjan, iMsg, wParam, lParam);
         }
    Last edited by pc2-brazil; 07-02-2013 at 09:19 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. The Creation of an OS
    By jrahhali in forum Tech Board
    Replies: 8
    Last Post: 09-18-2010, 07:04 AM
  2. Replies: 2
    Last Post: 12-16-2008, 02:43 PM
  3. Dev C++ DLL creation.
    By tol in forum C++ Programming
    Replies: 1
    Last Post: 07-28-2005, 12:59 PM
  4. font & font color in edit control
    By XRIC++ in forum Windows Programming
    Replies: 2
    Last Post: 10-27-2003, 09:07 PM