fontsfont-size

Scaling the contour of a glyph to a given font size (matching results from Windows OS)


I'm trying to scale the contours of a glyph to render it at a given font size — say 32 pixels — and, if possible, I’d like the result to match what I see in Windows applications like Paint, Notepad, or Photoshop.

I’ve run into a problem with a font called Lucida Grande UI.ttf. The unitsPerEm is 2048, and I verified the font data using FontDrop, so I’m confident the numbers are correct. When I extract the letter 'E', I get the following data:

xmin/xmax: 191, 1061
ymin/ymax: 0, 1480

Contour data:
x=191 y=0
x=191 y=1480
x=1018 y=1480
x=1018 y=1323
x=401 y=1323
x=401 y=848
x=918 y=848
x=918 y=693
x=401 y=693
x=401 y=157
x=1061 y=157
x=1061 y=0

Font ascent / descent: 1980, -432

What I’ve been doing is calculating the glyph’s height using ymax - ymin, and then multiplying that by fontSize / unitsPerEm. For example:

(1480 - 0) * (32 / 2048) = 23.125

So I expect the rendered height of 'E' to be around 23 pixels.

However, when I render the same glyph in Notepad, Paint, or Photoshop (not photoshop no, see my comment below) at font size 32, it appears to be exactly 32 pixels tall. This suggests that my scaling method is wrong — or at least incomplete — for matching what these Windows apps are doing.

Interestingly, this method (using fontSize / unitsPerEm) has worked for other fonts I’ve used, so I’m not sure why it doesn't match here. It seems like I’ve been doing it incorrectly from the beginning and just didn’t notice until now.

I'd really appreciate it if someone could explain the proper way to scale glyph outlines so they match the rendering in apps like Paint, Notepad, etc.

enter image description here


Solution

  • Your calculation returns the height of the glyph E for 72 dpi

    (1480 - 0) * (32 / 2048) = 23.125 
    

    or relative

    /**
    * units per EM: 
    * usually 2048 for truetype/glyph based Openttypes
    * 1000 for OTF/CFF flavored Opentypes
    */
    let UPM = 2048;
    let heightE = 1480;
    let heightE_relative = heightE/UPM; 
    
    // E height is 72.65% of the font-size
    

    But the actual rendered pixel-count – when measured in apps like Photoshop – depends on the specified image/document dpi settings.

    All in all your scaling calculation is correct but the rastered rendering will return different pixel-heights depending on pixel density.