Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. how to set the height of a truetype font ?

how to set the height of a truetype font ?

Scheduled Pinned Locked Moved C / C++ / MFC
tutorialhelpquestionlearning
7 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • J Offline
    J Offline
    JP GOBLET
    wrote on last edited by
    #1

    For a technical drafting program, i need to draw truetype fonts with total control on their height : for example i want a text of exactly 10mm high. The problem is in interpretation of height; for truetype fonts, this height is made of 3 arts : Descent (part under the baseline), Ascent (part over the baseline), InternalLeading (some space above the character). All these values are returned by pDC->GetTextMetrics() when you have selected a font in the pDC. In my case, when i say i want a font 10 mm high, it means a font whose characters above the baseline (such as digits) will be 10 mm high. This convention is used by programs such as Autocad, MicroStation, ... For creating a CFont object, you have to fill a LOGFONT struct with the properties of the font, such as font name, height, weight, ... But as said before, the height specified here include descent + ascent + leading. Here is how i try to get what i want : CFont *pOldFont, newfont; TEXTMETRIC Metrics; LOGFONT lf; double HcarFromFont, HcarWanted; memset(&lf, 0, sizeof(LOGFONT)); strcpy(lf.lfFaceName, "Arial"); // HcarWanted is the required height (say 10 mm) converted in pixels; // the height must be specified in logical units, which are pixels because the the current mapMode is MM_TEXT. HcarWanted = 10 /* mm */ * ConversionFactor; // ConversionFactor translates mm in pixels // set the height - this is just a first try : lf.lfHeight = - (long)HcarWanted; // note the minus sign, this is normal (see doc. for LOGFONT) ... // set others font properties newfont.CreateFontIndirect(&lf); pOldFont = pDC->SelectObject(&newfont); pDC->GetTextMetrics(&Metrics); // get metrics (in pixels) for the font just created // read the current height for ascent part : HcarFromFont = Metrics.tmAscent - Metrics.tmInternalLeading; // here is the trick : the height of the ascent part is of course smaller than the required height; // so i correct the total height (lf.lfHeight) so that the ascent part grows up to the required height : lf.lfHeight = (long) (lf.lfHeight * (HcarWanted / HcarFromFont)); // example : let's say that HcarWanted is 100 pixels and that GetTextMetrics() // returned HcarFromFont = Metrics.tmAscent - Metrics.tmInternalLeading = 60; // so the new lf.lfHeight is multiplied by * 100/60 = 1.66 newfont.Detach(); newfont.DeleteObject(); newfont.CreateFontIndirect(&lf); // recreate the font with the corrected height pDC->SelectObject(&newfont); // the following lines just check that the new height of the ascent part

    M G 2 Replies Last reply
    0
    • J JP GOBLET

      For a technical drafting program, i need to draw truetype fonts with total control on their height : for example i want a text of exactly 10mm high. The problem is in interpretation of height; for truetype fonts, this height is made of 3 arts : Descent (part under the baseline), Ascent (part over the baseline), InternalLeading (some space above the character). All these values are returned by pDC->GetTextMetrics() when you have selected a font in the pDC. In my case, when i say i want a font 10 mm high, it means a font whose characters above the baseline (such as digits) will be 10 mm high. This convention is used by programs such as Autocad, MicroStation, ... For creating a CFont object, you have to fill a LOGFONT struct with the properties of the font, such as font name, height, weight, ... But as said before, the height specified here include descent + ascent + leading. Here is how i try to get what i want : CFont *pOldFont, newfont; TEXTMETRIC Metrics; LOGFONT lf; double HcarFromFont, HcarWanted; memset(&lf, 0, sizeof(LOGFONT)); strcpy(lf.lfFaceName, "Arial"); // HcarWanted is the required height (say 10 mm) converted in pixels; // the height must be specified in logical units, which are pixels because the the current mapMode is MM_TEXT. HcarWanted = 10 /* mm */ * ConversionFactor; // ConversionFactor translates mm in pixels // set the height - this is just a first try : lf.lfHeight = - (long)HcarWanted; // note the minus sign, this is normal (see doc. for LOGFONT) ... // set others font properties newfont.CreateFontIndirect(&lf); pOldFont = pDC->SelectObject(&newfont); pDC->GetTextMetrics(&Metrics); // get metrics (in pixels) for the font just created // read the current height for ascent part : HcarFromFont = Metrics.tmAscent - Metrics.tmInternalLeading; // here is the trick : the height of the ascent part is of course smaller than the required height; // so i correct the total height (lf.lfHeight) so that the ascent part grows up to the required height : lf.lfHeight = (long) (lf.lfHeight * (HcarWanted / HcarFromFont)); // example : let's say that HcarWanted is 100 pixels and that GetTextMetrics() // returned HcarFromFont = Metrics.tmAscent - Metrics.tmInternalLeading = 60; // so the new lf.lfHeight is multiplied by * 100/60 = 1.66 newfont.Detach(); newfont.DeleteObject(); newfont.CreateFontIndirect(&lf); // recreate the font with the corrected height pDC->SelectObject(&newfont); // the following lines just check that the new height of the ascent part

      M Offline
      M Offline
      Mike Dimmick
      wrote on last edited by
      #2

      Have you considered working in a different mapping mode, for example, MM_LOMETRIC? If you want to implement printing, using such a device-independent mapping mode will seriously simplify your code. One thing that will bite you is that MM_LOMETRIC has the y axis increasing from the bottom of the screen to the top, unlike MM_TEXT which is the other way round. By default, the (0, 0) position is still in the top left of the window. You can implement zooms and pans simply by modifying the window and viewport extents. For more information, see Mapping Modes and Translations[^].

      J 1 Reply Last reply
      0
      • M Mike Dimmick

        Have you considered working in a different mapping mode, for example, MM_LOMETRIC? If you want to implement printing, using such a device-independent mapping mode will seriously simplify your code. One thing that will bite you is that MM_LOMETRIC has the y axis increasing from the bottom of the screen to the top, unlike MM_TEXT which is the other way round. By default, the (0, 0) position is still in the top left of the window. You can implement zooms and pans simply by modifying the window and viewport extents. For more information, see Mapping Modes and Translations[^].

        J Offline
        J Offline
        JP GOBLET
        wrote on last edited by
        #3

        I have made tests with 2 mapping modes : on screen : mapmode = MM_TEXT : 1 logical unit = 1 pixel when printing : mapmode = MM_LOMETRIC : 1 logical unit = .1 mm The problem stays independently of the map mode; i don't think it's a problem of map mode, since for a same mapmode and a same lfHeight (in the LOGFONT struct), the effective height of the text will vary with the font. And my problem is not only that the height changes with the font : for a given font i want that the height of the 'ascent' part of the font is precisely 10 mm, and i can't get that. For example i want digits (these characters have no descent part) of exactly 10 mm. (Of course i don't set lfHeight = 10, but i apply a factor converting mm to pixels; i know this factor is correct, i use it for drawing lines).

        1 Reply Last reply
        0
        • J JP GOBLET

          For a technical drafting program, i need to draw truetype fonts with total control on their height : for example i want a text of exactly 10mm high. The problem is in interpretation of height; for truetype fonts, this height is made of 3 arts : Descent (part under the baseline), Ascent (part over the baseline), InternalLeading (some space above the character). All these values are returned by pDC->GetTextMetrics() when you have selected a font in the pDC. In my case, when i say i want a font 10 mm high, it means a font whose characters above the baseline (such as digits) will be 10 mm high. This convention is used by programs such as Autocad, MicroStation, ... For creating a CFont object, you have to fill a LOGFONT struct with the properties of the font, such as font name, height, weight, ... But as said before, the height specified here include descent + ascent + leading. Here is how i try to get what i want : CFont *pOldFont, newfont; TEXTMETRIC Metrics; LOGFONT lf; double HcarFromFont, HcarWanted; memset(&lf, 0, sizeof(LOGFONT)); strcpy(lf.lfFaceName, "Arial"); // HcarWanted is the required height (say 10 mm) converted in pixels; // the height must be specified in logical units, which are pixels because the the current mapMode is MM_TEXT. HcarWanted = 10 /* mm */ * ConversionFactor; // ConversionFactor translates mm in pixels // set the height - this is just a first try : lf.lfHeight = - (long)HcarWanted; // note the minus sign, this is normal (see doc. for LOGFONT) ... // set others font properties newfont.CreateFontIndirect(&lf); pOldFont = pDC->SelectObject(&newfont); pDC->GetTextMetrics(&Metrics); // get metrics (in pixels) for the font just created // read the current height for ascent part : HcarFromFont = Metrics.tmAscent - Metrics.tmInternalLeading; // here is the trick : the height of the ascent part is of course smaller than the required height; // so i correct the total height (lf.lfHeight) so that the ascent part grows up to the required height : lf.lfHeight = (long) (lf.lfHeight * (HcarWanted / HcarFromFont)); // example : let's say that HcarWanted is 100 pixels and that GetTextMetrics() // returned HcarFromFont = Metrics.tmAscent - Metrics.tmInternalLeading = 60; // so the new lf.lfHeight is multiplied by * 100/60 = 1.66 newfont.Detach(); newfont.DeleteObject(); newfont.CreateFontIndirect(&lf); // recreate the font with the corrected height pDC->SelectObject(&newfont); // the following lines just check that the new height of the ascent part

          G Offline
          G Offline
          G Steudtel
          wrote on last edited by
          #4

          Hi, I far as I can remember there is something like a negative height. When the height in the logfont structure is positive it is the height with the leading, when the height is negative it the cell height. But I do not know if it's just the ascending or the ascending+descending. I vaguely remember that the TEXTMETRICS structure has members for ascent descent and so on. So for your code the line HcarFromFont = Metrics.tmAscent should do what you need; Regards G. Steudtel

          J 1 Reply Last reply
          0
          • G G Steudtel

            Hi, I far as I can remember there is something like a negative height. When the height in the logfont structure is positive it is the height with the leading, when the height is negative it the cell height. But I do not know if it's just the ascending or the ascending+descending. I vaguely remember that the TEXTMETRICS structure has members for ascent descent and so on. So for your code the line HcarFromFont = Metrics.tmAscent should do what you need; Regards G. Steudtel

            J Offline
            J Offline
            JP GOBLET
            wrote on last edited by
            #5

            yes indeed I use a negative lfHeight, it means that height is the character height (ascent + descent, including an internal leading); a positive lfHeight would mean the cell height (= character height + external leading). G. Steudtel wrote: HcarFromFont = Metrics.tmAscent should do what you need so I presume I write : lf.lfHeight = -HcarWanted; // first try : HcarWanted = 10 mm (in pixels) font.CreateFontIndirect(&lf); pDC->SelectObject(&font); pDC->GetTextMetrics(&Metrics); HcarFromFont = Metrics.tmAscent; lf.lfHeight = -HcarFromFont; font.CreateFontIndirect(&lf); But don't forget that CreateFontIndirect(&lf) will consider lf.lfHeight as the total character height, how can it known it's meant to be the ascent height ? Or is there something i didn't grasp ? Nevertheless I did test the above code : it does not work : the font is now much too small; suppose the initial height was 10 mm : say 6 mm for ascent and 4 mm for descent; so with the 2nd assignment of lfHeight, i will ask a font whose total height is 4 mm.

            G 1 Reply Last reply
            0
            • J JP GOBLET

              yes indeed I use a negative lfHeight, it means that height is the character height (ascent + descent, including an internal leading); a positive lfHeight would mean the cell height (= character height + external leading). G. Steudtel wrote: HcarFromFont = Metrics.tmAscent should do what you need so I presume I write : lf.lfHeight = -HcarWanted; // first try : HcarWanted = 10 mm (in pixels) font.CreateFontIndirect(&lf); pDC->SelectObject(&font); pDC->GetTextMetrics(&Metrics); HcarFromFont = Metrics.tmAscent; lf.lfHeight = -HcarFromFont; font.CreateFontIndirect(&lf); But don't forget that CreateFontIndirect(&lf) will consider lf.lfHeight as the total character height, how can it known it's meant to be the ascent height ? Or is there something i didn't grasp ? Nevertheless I did test the above code : it does not work : the font is now much too small; suppose the initial height was 10 mm : say 6 mm for ascent and 4 mm for descent; so with the 2nd assignment of lfHeight, i will ask a font whose total height is 4 mm.

              G Offline
              G Offline
              G Steudtel
              wrote on last edited by
              #6

              Hi, Sorry that I made it too short. Off course if you take a smaller value you get a smaller font. The fault is by me for not thinking any further. Two approaches: 1) In a loop increase the height of the font until tmAscent becomes 10. 2) HcarFormFont = INeededHeight*Metrics.tmHeight/Metrics.tmAscent; with iNeededHeight being a constant of 10 ( or what ever height you need). I'm not so sure about the calculation but the ratio of height to ascent should be the factor to increase the height of the font. Also you should do some casting to double and back to integer to minimize rounding errors. But basically the second method seems reasonable. Regards G. Steudtel

              J 1 Reply Last reply
              0
              • G G Steudtel

                Hi, Sorry that I made it too short. Off course if you take a smaller value you get a smaller font. The fault is by me for not thinking any further. Two approaches: 1) In a loop increase the height of the font until tmAscent becomes 10. 2) HcarFormFont = INeededHeight*Metrics.tmHeight/Metrics.tmAscent; with iNeededHeight being a constant of 10 ( or what ever height you need). I'm not so sure about the calculation but the ratio of height to ascent should be the factor to increase the height of the font. Also you should do some casting to double and back to integer to minimize rounding errors. But basically the second method seems reasonable. Regards G. Steudtel

                J Offline
                J Offline
                JP GOBLET
                wrote on last edited by
                #7

                In my first code, i did a similar interpolation that the one you suggest. HcarFormFont = INeededHeight*Metrics.tmHeight/Metrics.tmAscent. Nevertheless, using your formula or mine, the results are very near, and on screen the font looks either too small, either too big (it depends of the font). Note that, curiuously, after having set the height with the interpolation formula, if i request again the metrics with GetTextMetrics(), i see that the height of ascent part is now equal (or very near) to the initial height i requested. So the formula seems to work, and yet on screen that's not OK... Thanks, JPG

                1 Reply Last reply
                0
                Reply
                • Reply as topic
                Log in to reply
                • Oldest to Newest
                • Newest to Oldest
                • Most Votes


                • Login

                • Don't have an account? Register

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • World
                • Users
                • Groups