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.
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.