Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

varLib.mutator Font instancing produces invalid font file for certain fonts #3478

Open
mitterdoo opened this issue Apr 12, 2024 · 10 comments
Open

Comments

@mitterdoo
Copy link

Hiya,

I'm trying to create static font files (TTF) for the font Bahnschrift (now included with Windows) since the variable font does not play nice with Autodesk Fusion. However, when I run this command:

fonttools varLib.mutator .\bahnschrift.ttf wght=300 wdth=100

then I try to open the new font file, Windows gives me the following error:
The requested file bahnschrift-instance.ttf is not a valid font file.

I'm not sure what the cause is, and I tried several different weight/width values to no avail. Below is the output with the verbose flag enabled:

Location: {'wght': 300.0, 'wdth': 100.0}
Loading variable font
Reading 'fvar' table from disk
Decompiling 'fvar' table
Reading 'avar' table from disk
Decompiling 'avar' table
Normalized location: {'wght': -1.0, 'wdth': 0.0}
Mutating glyf/gvar tables
Reading 'gvar' table from disk
Decompiling 'gvar' table
Reading 'post' table from disk
Decompiling 'post' table
Reading 'maxp' table from disk
Decompiling 'maxp' table
Reading 'glyf' table from disk
Decompiling 'glyf' table
Reading 'loca' table from disk
Decompiling 'loca' table
Reading 'head' table from disk
Decompiling 'head' table
Reading 'hmtx' table from disk
Decompiling 'hmtx' table
Reading 'hhea' table from disk
Decompiling 'hhea' table
Reading 'vmtx' table from disk
Mutating MVAR table
Reading 'MVAR' table from disk
Decompiling 'MVAR' table
Reading 'OS/2' table from disk
Decompiling 'OS/2' table
Mutating FeatureVariations
Reading 'GSUB' table from disk
Decompiling 'GSUB' table
Reading 'GPOS' table from disk
Decompiling 'GPOS' table
Reading 'GDEF' table from disk
Decompiling 'GDEF' table
Mutating GDEF/GPOS/GSUB tables
Pruning name table
Reading 'name' table from disk
Decompiling 'name' table
Removing variable tables
Saving instance font .\bahnschrift-instance.ttf
Compiling 'glyf' table
Writing 'glyf' table to disk
Compiling 'maxp' table
Writing 'maxp' table to disk
Compiling 'loca' table
Writing 'loca' table to disk
Compiling 'head' table
Writing 'head' table to disk
Compiling 'hmtx' table
Writing 'hmtx' table to disk
Compiling 'hhea' table
Writing 'hhea' table to disk
Compiling 'OS/2' table
Reading 'cmap' table from disk
Decompiling 'cmap' table
Writing 'OS/2' table to disk
Compiling 'cmap' table
Writing 'cmap' table to disk
Reading 'fpgm' table from disk
Writing 'fpgm' table to disk
Reading 'prep' table from disk
Writing 'prep' table to disk
Reading 'cvt ' table from disk
Writing 'cvt ' table to disk
Compiling 'name' table
Writing 'name' table to disk
Compiling 'post' table
Writing 'post' table to disk
Reading 'gasp' table from disk
Writing 'gasp' table to disk
Compiling 'GDEF' table
Writing 'GDEF' table to disk
Compiling 'GPOS' table
uharfbuzz not found, compiling 'GPOS' with pure-python serializer
Writing 'GPOS' table to disk
Compiling 'GSUB' table
uharfbuzz not found, compiling 'GSUB' with pure-python serializer
Writing 'GSUB' table to disk
Reading 'meta' table from disk
Writing 'meta' table to disk

I tested this with another variable font I had, but the resulting instanced font worked fine. I could open it normally and install it. Maybe there's some proprietary data in Bahnschrift that doesn't work well with fonttools? I'm a bit out of my league diagnosing this--my knowledge of font files is pretty shallow.

My environment:

Fonttools version 4.51.0 (from pip)
Python 3.10.7
Windows 11 64-bit version 23H2 build 22631.3447

@behdad
Copy link
Member

behdad commented Apr 12, 2024

It's possible that the font has a DSIG table?

Also, varLib.mutator is obsolete. Please use varLib.instancer.

@kenmcd
Copy link

kenmcd commented Apr 12, 2024

It's possible that the font has a DSIG table?

Yes.

@behdad
Copy link
Member

behdad commented Apr 12, 2024

Would dropping that make it work? You can ttx the instanced font, remove the DSIG table, and ttx it back to ttf.

@ftCLI
Copy link

ftCLI commented Apr 12, 2024

Using varLib.instancer works without removing the DSIG table, but the instancer cannot update the name table.

In line 225 of varLib.instancer.names, None is returned because platformID 1 is parsed before platformID 3. Probably platformID 3 should be preferred, or axisValueNameIDs should be retrieved from platformID 3 when they are not present in platformID 1

C:\Users\cg\Desktop\Banshrift>ftcli converter vf2i . -out static
[ INFO     ] Converting file: bahnschrift.ttf
[ INFO     ] Exporting instance 1 of 15
[ ERROR    ] 'NoneType' object has no attribute 'toUnicode'
Traceback (most recent call last):

  File "D:\PycharmProjects\FondryTools-CLI\foundryToolsCLI\CLI\ftcli_converter.py", line 227, in vf2i
    converter.run(variable_font=variable_font, instances=instances)
    │         │                 │                        └ [<fontTools.ttLib.tables._f_v_a_r.NamedInstance object at 0x000001DEC34E8F70>, <fontTools.ttLib.tables._f_v_a_r.NamedInstance...
    │         │                 └ <foundryToolsCLI.Lib.VFont.VariableFont object at 0x000001DEC3467940>
    │         └ <function VariableToStatic.run at 0x000001DEC3506710>
    └ <foundryToolsCLI.Lib.converters.variable_to_static.VariableToStatic object at 0x000001DEC3467850>

  File "D:\PycharmProjects\FondryTools-CLI\foundryToolsCLI\Lib\converters\variable_to_static.py", line 38, in run
    static_instance = instantiateVariableFont(
                      └ <function instantiateVariableFont at 0x000001DEC34EDF30>

  File "C:\Users\cg\AppData\Local\Programs\Python\Python310\lib\site-packages\fontTools\varLib\instancer\__init__.py", line 1294, in instantiateVariableFont
    names.updateNameTable(varfont, axisLimits)
    │     │               │        └ AxisLimits({'wght': (300, 300, 300), 'wdth': (100, 100, 100)})
    │     │               └ <foundryToolsCLI.Lib.VFont.VariableFont object at 0x000001DEC3528100>
    │     └ <function updateNameTable at 0x000001DEC34A2440>
    └ <module 'fontTools.varLib.instancer.names' from 'C:\\Users\\cg\\AppData\\Local\\Programs\\Python\\Python310\\lib\\site-packag...

  File "C:\Users\cg\AppData\Local\Programs\Python\Python310\lib\site-packages\fontTools\varLib\instancer\names.py", line 131, in updateNameTable
    _updateNameRecords(varfont, axisValueTables)
    │                  │        └ [<fontTools.ttLib.tables.otTables.AxisValue object at 0x000001DEC3528760>]
    │                  └ <foundryToolsCLI.Lib.VFont.VariableFont object at 0x000001DEC3528100>
    └ <function _updateNameRecords at 0x000001DEC34A25F0>

  File "C:\Users\cg\AppData\Local\Programs\Python\Python310\lib\site-packages\fontTools\varLib\instancer\names.py", line 224, in _updateNameRecords
    typoSubFamilyName = " ".join(

  File "C:\Users\cg\AppData\Local\Programs\Python\Python310\lib\site-packages\fontTools\varLib\instancer\names.py", line 225, in <genexpr>
    getName(n, *platform).toUnicode() for n in axisValueNameIDs
    │       │   │                         └ 258
    │       │   └ (1, 0, 0)
    │       └ 258
    └ <bound method table__n_a_m_e.getName of <'name' table at 1dec3529a20>>

AttributeError: 'NoneType' object has no attribute 'toUnicode'
[ INFO     ] Elapsed time: 0.0512 seconds

@anthrotype
Copy link
Member

thanks @ftCLI - unhandled AttributeError is a bug, if getName can sometimes return None its caller must handle that (skip it). Could you PR that? Or I can do it later

@ftCLI
Copy link

ftCLI commented Apr 12, 2024

I Have no idea of how to open a PR in a repository that is not mine (sorry, just a hobbist here). I tried to push a snippet few days ago but the push was rejected.

@anthrotype
Copy link
Member

no worries. In case you're interested, see

https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork

@justvanrossum
Copy link
Collaborator

justvanrossum commented Apr 12, 2024

I Have no idea of how to open a PR in a repository that is not mine

You fork the project to your own account, make a branch there, commit and push. Use GH website to create PR from your own branch/fork.

@ftCLI
Copy link

ftCLI commented Apr 12, 2024

Thanks both!

@ftCLI
Copy link

ftCLI commented Apr 13, 2024

Quick and dirty: enclose the call to instantiateVariableFont in a try-except clause.

#3480

A log message is displayed...

(.venv) D:\GitHub\fonttools>fonttools varLib.instancer bahnschrift.ttf wght=310 wdth=100 --update-name-table
Restricting axes: {'wght': (310, 310, 310), 'wdth': (100, 100, 100)}
Loading variable font
Restricted limits: {'wght': (310, 310, 310), 'wdth': (100, 100, 100)}
Normalized limits: {'wght': (-0.900024, -0.900024, -0.900024, 100, 300), 'wdth': (0, 0, 0, 25, 0)}
Updating name table
Failed to update name table: Cannot find Axis Values {'wght': 310.0}
Instantiating glyf/gvar tables
Instantiating MVAR table
Dropping HVAR table
Instantiating GDEF and GPOS tables
Instantiating FeatureVariations of GSUB table
Dropping avar table
Instantiating STAT table
Dropping fvar table
Pruning name table
Setting OS/2.usWeightClass = 310
Saving instance font bahnschrift-instance.ttf

... instead of crashing

Restricting axes: {'wght': (310, 310, 310), 'wdth': (100, 100, 100)}
Loading variable font
Restricted limits: {'wght': (310, 310, 310), 'wdth': (100, 100, 100)}
Normalized limits: {'wght': (-0.900024, -0.900024, -0.900024, 100, 300), 'wdth': (0, 0, 0, 25, 0)}
Updating name table
Traceback (most recent call last):
  File "C:\Users\cg\AppData\Local\Programs\Python\Python310\lib\runpy.py", line 196, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "C:\Users\cg\AppData\Local\Programs\Python\Python310\lib\runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "D:\GitHub\fonttools\.venv\Scripts\fonttools.exe\__main__.py", line 7, in <module>
  File "D:\GitHub\fonttools\Lib\fontTools\__main__.py", line 31, in main
    runpy.run_module(mod, run_name="__main__")
  File "C:\Users\cg\AppData\Local\Programs\Python\Python310\lib\runpy.py", line 227, in run_module
    return _run_code(code, {}, init_globals, run_name, mod_spec)
  File "C:\Users\cg\AppData\Local\Programs\Python\Python310\lib\runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "D:\GitHub\fonttools\Lib\fontTools\varLib\instancer\__main__.py", line 5, in <module>
    sys.exit(main())
  File "D:\GitHub\fonttools\Lib\fontTools\varLib\instancer\__init__.py", line 1551, in main
    instantiateVariableFont(
  File "D:\GitHub\fonttools\Lib\fontTools\varLib\instancer\__init__.py", line 1294, in instantiateVariableFont
    names.updateNameTable(varfont, axisLimits)
  File "D:\GitHub\fonttools\Lib\fontTools\varLib\instancer\names.py", line 124, in updateNameTable
    checkAxisValuesExist(stat, axisValueTables, defaultAxisCoords.pinnedLocation())
  File "D:\GitHub\fonttools\Lib\fontTools\varLib\instancer\names.py", line 164, in checkAxisValuesExist
    raise ValueError(f"Cannot find Axis Values {{{missing}}}")
ValueError: Cannot find Axis Values {'wght': 310.0}

Maybe using getDebugName could be used instead of getName. This will compile the name table correctly in case the NameRecords are present only on one table (Mac or Win), but I don't know if this is wanted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants