typemytype / drawbot

http://www.drawbot.com
Other
393 stars 61 forks source link

variable font is not able to add glyphs by glyphName #544

Open typemytype opened 9 months ago

typemytype commented 9 months ago

When adding a glyphName in as.appendGlyph("a") a warning is raised and no glyph is added. The font clearly contains the requested glyph.

This seems to work fine when adding a glyph by index.

This seems to work fine with "Skia" but not with AdobeVFPrototype.ttf. I guess the rvrn substitution is the main difference here..

Tested on macOS 13.5.2

s = FormattedString()

path = 'AdobeVFPrototype.ttf'

s.font(path)
s.fontSize(300)

s.fontVariations(wght=675)
s += "$¢ "

print(s.listFontGlyphNames().index("glyph00312"))
s.appendGlyph("glyph00312")
s.appendGlyph(311) # by index
s.appendGlyph("A")
s.appendGlyph(24) # by index

text(s, (54, 102))
justvanrossum commented 9 months ago

I get this:

Traceback (most recent call last):
  File "<untitled>", line 11, in <module>
ValueError: 'glyph00312' is not in list

This is on macOS 14.0.

When I make a TTX dump of the font, I see indeed that it doesn't contain a glyph named "glyph00312".

Could it be you're looking at a different version of the font, perhaps one with a post 3 table?

It seems that appendGlyph() uses the OS way to refer to a glyph by name, but listFontGlyphNames() uses fonttools. This should work well as long as the font has a post table that that contains glyph names, but may lead to discrepancies when the post table does not contain glyph names (post format 3).

justvanrossum commented 9 months ago

If I comment out line 11, the image l get is this:

image

But I also get a warning:

*** DrawBot warning: font 'AdobeVFPrototype-Default_wght2A30000_CNTR' has no glyph with the name 'glyph00312' ***

But that probably matches what you're seeing?

justvanrossum commented 9 months ago

It works for me if I use "cent" and "cent.nostroke" for the glyph names.

typemytype commented 9 months ago

super strange, testing it directly with fontTools inside the script

image
justvanrossum commented 9 months ago

I'm getting this:

>>> from fontTools.ttLib import TTFont
>>> path = '/Users/just/Downloads/AdobeVFPrototype (1).ttf'
>>> ft = TTFont(path)
>>> print("glyph00312" in ft.getGlyphOrder())
False
justvanrossum commented 9 months ago
from fontTools.ttLib import TTFont
path = '/Users/just/Downloads/AdobeVFPrototype (1).ttf'
ft = TTFont(path)
print("glyph00312" in ft.getGlyphOrder())
print(ft["head"].fontRevision)
print(ft["head"].modified)

Output:

False
1.003997802734375
3634020435
typemytype commented 9 months ago

🤯

typemytype commented 9 months ago
True
1.003997802734375
3669988076

different modified value

justvanrossum commented 9 months ago

Ahhh, I downloaded 1.004, not 1.005a.

justvanrossum commented 9 months ago

And yes, 1.005a has a post table format 3.

justvanrossum commented 9 months ago

Apologies for the mixup, my brain went for the blue download links, which is 1.004 as it's the latest non-pre-release...

image
justvanrossum commented 9 months ago

We could fix appendGlyph() by using the TTFont instance to convert the glyph name to glyph ID (ft.getGlyphID()).

typemytype commented 9 months ago

my first thought was idd to use fontTools to get the glyph index...

and glyphWithName_ is deprecated https://developer.apple.com/documentation/appkit/nsfont/1530847-glyphwithname?language=objc

justvanrossum commented 9 months ago

Ok, that's another reason to use fonttools for this.

justvanrossum commented 9 months ago

The hard part: it looks like we use fonttools in many places, but don't keep the TTFont instance around, but we should for this use case.

typemytype commented 9 months ago

mmm must be something similar to this: https://github.com/typemytype/drawbot/blob/master/drawBot/context/baseContext.py#L1852-L1867

where we need the fontPath, fontNumber, res_name_or_index

typemytype commented 9 months ago

adding a memoized function to cache the ttFont object similar as to getNSFontFromNameOrPath