googlefonts / nanoemoji

A wee tool to build color fonts.
Apache License 2.0
239 stars 19 forks source link

KeyError: 'glyf' when trying to convert Gilbert font to COLR #435

Closed Findus23 closed 1 year ago

Findus23 commented 1 year ago

Hi,

I wanted to convert the Gilbert font from https://www.typewithpride.com/ to COLRv1 so that it also works in Chrome.

The default file name of Gilbert-Color Bold Preview5.otf seems to fail because of the spaces in the name.

But even after renaming the file, I can't seem to get it to work with maximum_color /path/to/test.otf:

I0921 12:00:26.850657 139996433276864 maximum_color.py:449] Generating build.ninja
I0921 12:00:27.044305 139996433276864 ninja.py:113] ninja -C /home/lukas/tmp/nanoemoji/build
ninja: Entering directory `/home/lukas/tmp/nanoemoji/build'
[904/906] /home/lukas/.virtualenvs/te...tput_file MergeSource.glyf_colr_1.ttf
W0921 12:01:18.666877 140660174471104 glyph_reuse.py:69] affine_between failed: M505.3699951171875,289.093994140625 L384.42999267578125,289.093994140625 L384.42999267578125,0.1820068359375 L505.3699951171875,0.1820068359375 L505.3699951171875,289.093994140625 M505.3699951171875,698.9450073242188 L384.42999267578125,698.9450073242188 L384.42999267578125,410.03399658203125 L505.3699951171875,410.03399658203125 L505.3699951171875,698.9450073242188 M160.9600067138672,288.7039794921875 L40.02000045776367,288.7039794921875 L40.02000045776367,-0.59100341796875 L160.9600067138672,-0.59100341796875 L160.9600067138672,288.7039794921875 M160.9600067138672,698.9249877929688 L40.02000045776367,698.9249877929688 L40.02000045776367,410.05401611328125 L160.9600067138672,410.05401611328125 L160.9600067138672,698.9249877929688 
[ some more lines like this]
I0921 12:01:25.416941 140660174471104 __init__.py:47] Pre-processing glyphs
I0921 12:01:25.456688 140660174471104 base.py:178] Running DecomposeComponentsFilter on AnEmojiFamily-Regular
I0921 12:01:25.457893 140660174471104 base.py:178] Running CubicToQuadraticFilter on AnEmojiFamily-Regular
I0921 12:01:25.530013 140660174471104 cubicToQuadratic.py:46] New spline lengths: 1: 844, 2: 796, 3: 372, 4: 30, 5: 9
I0921 12:01:25.530156 140660174471104 __init__.py:243] Building OpenType tables
I0921 12:01:25.994717 140660174471104 write_font.py:247] Writing MergeSource.glyf_colr_1.ttf
I0921 12:01:26.125555 140660174471104 write_font.py:833] Wrote MergeSource.glyf_colr_1.ttf
[905/906] /home/lukas/.virtualenvs/te...eep_glyph_names.added_glyf_colr_1.ttf
FAILED: test.keep_glyph_names.added_glyf_colr_1.ttf 
/home/lukas/.virtualenvs/tempenv-512d212064b6f/bin/python -m nanoemoji.glue_together -v 0 --color_table COLR --target_font test.keep_glyph_names.ttf --donor_font MergeSource.glyf_colr_1.ttf --output_file test.keep_glyph_names.added_glyf_colr_1.ttf
Traceback (most recent call last):
  File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "/home/lukas/.virtualenvs/tempenv-512d212064b6f/lib/python3.10/site-packages/nanoemoji/glue_together.py", line 219, in <module>
    app.run(main)
  File "/home/lukas/.virtualenvs/tempenv-512d212064b6f/lib/python3.10/site-packages/absl/app.py", line 308, in run
    _run_main(main, args)
  File "/home/lukas/.virtualenvs/tempenv-512d212064b6f/lib/python3.10/site-packages/absl/app.py", line 254, in _run_main
    sys.exit(main(argv))
  File "/home/lukas/.virtualenvs/tempenv-512d212064b6f/lib/python3.10/site-packages/nanoemoji/glue_together.py", line 202, in main
    _copy_colr(target, donor)
  File "/home/lukas/.virtualenvs/tempenv-512d212064b6f/lib/python3.10/site-packages/nanoemoji/glue_together.py", line 60, in _copy_colr
    target_glyphs = target["glyf"].glyphs
  File "/home/lukas/.virtualenvs/tempenv-512d212064b6f/lib/python3.10/site-packages/fontTools/ttLib/ttFont.py", line 406, in __getitem__
    table = self._readTable(tag)
  File "/home/lukas/.virtualenvs/tempenv-512d212064b6f/lib/python3.10/site-packages/fontTools/ttLib/ttFont.py", line 413, in _readTable
    data = self.reader[tag]
  File "/home/lukas/.virtualenvs/tempenv-512d212064b6f/lib/python3.10/site-packages/fontTools/ttLib/sfnt.py", line 105, in __getitem__
    entry = self.tables[Tag(tag)]
KeyError: 'glyf'
ninja: build stopped: subcommand failed.
Traceback (most recent call last):
  File "/home/lukas/.virtualenvs/tempenv-512d212064b6f/bin/maximum_color", line 8, in <module>
    sys.exit(main())
  File "/home/lukas/.virtualenvs/tempenv-512d212064b6f/lib/python3.10/site-packages/nanoemoji/maximum_color.py", line 479, in main
    app.run(_run)
  File "/home/lukas/.virtualenvs/tempenv-512d212064b6f/lib/python3.10/site-packages/absl/app.py", line 308, in run
    _run_main(main, args)
  File "/home/lukas/.virtualenvs/tempenv-512d212064b6f/lib/python3.10/site-packages/absl/app.py", line 254, in _run_main
    sys.exit(main(argv))
  File "/home/lukas/.virtualenvs/tempenv-512d212064b6f/lib/python3.10/site-packages/nanoemoji/maximum_color.py", line 474, in _run
    maybe_run_ninja(build_file)
  File "/home/lukas/.virtualenvs/tempenv-512d212064b6f/lib/python3.10/site-packages/nanoemoji/ninja.py", line 114, in maybe_run_ninja
    subprocess.run(ninja_cmd, check=True)
  File "/usr/lib/python3.10/subprocess.py", line 524, in run
    raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command '['ninja', '-C', '/home/lukas/tmp/nanoemoji/build']' returned non-zero exit status 1.
anthrotype commented 1 year ago

thanks for trying out our tools! I think maximum_color is assuming that the input font already contains a "glyf" table, but in your case it only has the "SVG " table, is that correct? I believe an OT-SVG font is not required to have "glyf" (or "CFF "). We should create an empty "glyf" table if it doesn't already exist. The presence of a "CFF " or "CFF2" table in place of the "glyf" table may complicate things further.. Does your font contains "CFF " table for the black and white fallback glyphs, or just "SVG "?

anthrotype commented 1 year ago

the error because of spaces in the filename is a bit embarassing, will get that fixed as well 😅

anthrotype commented 1 year ago

Hm so, yeah, yours is a CFF-flavored opentype font (.otf) so it does not contain any "glyf" table, only "CFF ", with the outlines of the black-&-white only glyphs. In theory we could/should support creating a CFF-flavored COLR font, and nanoemoji can make one already from a set of .svg files (with --color_format=cff_colr_1 flag). Supporting making these from an OT-SVG font using maximum_color tool is possible, just takes some care with adding the extra glyphs to the existing CFF table (need to refresh my memory on that).

In the meantime, I suggest you do this. Convert your CFF-flavored opentype font to a TrueType-flavored one (.ttf), so it will have "glyf" instead of "CFF ". You can use this otf2ttf.py script in fonttools/Snippets directory.

$ git clone https://github.com/fonttools/fonttools
$ cd fonttools/Snippets
$ python3 ./otf2ttf.py -o /tmp/Gilbert-Color_Bold_Preview5.ttf "Gilbert-Color Bold Preview5.otf"
$ maximum_color --build_dir /tmp/gilbert-max-color --output_file Gilbert-Color_Bold_Preview5_SVG+COLRv1.ttf /tmp/Gilbert-Color_Bold_Preview5.ttf
$ ttx -l /tmp/gilbert-max-color/Gilbert-Color_Bold_Preview5_SVG+COLRv1.ttf | grep -E "COLR|SVG"
    COLR  0x495C5A5F     29268     84316
    SVG   0x82E2DDDE    477824    118372
Findus23 commented 1 year ago

Many thanks for the hints!

I converted the font to a ttf as you mentioned and indeed the final output seems to work in both Firefox and Chromium.

And when stored as a woff2, the file size difference is quite small (102kb vs 96kb).

anthrotype commented 1 year ago

Cool! Is that FireFox Nightly?

anthrotype commented 1 year ago

And when stored as a woff2, the file size difference is quite small (102kb vs 96kb).

is the 102kb the one that contains both SVG and COLRv1?

Findus23 commented 1 year ago

No, it is Firefox 104.0.2 (and Chromium 105.0.5195.125).

is the 102kb the one that contains both SVG and COLRv1?

Yes, I'd assume so.

anthrotype commented 1 year ago

ah, ok - Firefox stable 104 is probably just reading the OT-SVG table, not the COLRv1. If you try the latest Nightly it should work with COLRv1 as well. You may not notice the difference because the two tables are suppose to look the same, but you can strip the SVG table and leave only COLR in it to check if FF Nightly loads the COLRv1 table (e.g. ttx -x SVG font.ttf && ttx font.ttx)

Findus23 commented 1 year ago

Indeed. Without the SVG table, the file size becomes 41kb as a woff2 and doesn't work in Firefox stable anymore. So I will stay with the larger file for a while and switch to COLR-only once it is supported in all browsers.

anthrotype commented 1 year ago

By the way, your font doesn't use gradients, only flat colors with transparency, it could also be encoded as a COLR version 0, and that should make it work almost everywhere, so you might not even need to provide both an SVG and a COLR version 1 table.

anthrotype commented 1 year ago

maybe i'll add an option to maximum_color to make it create a COLRv0 from a suitable OT-SVG font like yours

anthrotype commented 1 year ago

I have a quick WIP patch to allow converting your OT-SVG font to COLRv0, it's not ready to merge yet

https://github.com/googlefonts/nanoemoji/compare/otsvg-to-colrv0?expand=1

with this, I was able to add a COLRv0 to your font (the .ttf variant), then after stripping the SVG table from it using ttx, I get an uncompressed .ttf file of 109KB, after woff2 compression it gets down to 33KB. Not bad!

anthrotype commented 1 year ago

i just noticed that that your font doesn't actually contain any transparency, if I grep for "opacity" I get nothing among the .svg files extracted from the OT-SVG table. In fact the colors in the CPAL table generated by maximum_color end all with FF (the A for "alpha" in the BGRA color definitions is basically opaque). You simulate the blending of the opaque color layers as if they were transparent. Interesting!

Findus23 commented 1 year ago

Okay, I can reproduce all of this and indeed the 33KB COLRv0-only file works fine in both Firefox and Chromium. Just to clarify, I know nothing more about this font than that I found it recently and thought it would be great as a webfont in some use cases. And the CC license means that I can share the results of this thread once I have time for it so that others can use the font directly.

BTW @Theelx, you might be interested in this as you also mentioned using this font in this repository (#380)

anthrotype commented 1 year ago

ah thanks, that's ok, sorry I thought you were the author of the fonts :)

Findus23 commented 1 year ago

Okay, I think I have summarized everything at https://github.com/Findus23/RainbowRoad/tree/main/src/font

Thanks again for all the help!

Theelx commented 1 year ago

Thanks so much for the ping! I made a workaround myself, but it only worked for some of the characters because of reasons I can't remember, so I didn't publish it. I'm ecstatic that you seem to have gotten it to work though!

anthrotype commented 1 year ago

@Findus23 FYI, I fixed the bug with spaces in filenames #442 and added a --colr_version flag to maximum_color (so one can select version 0 instead of the default version 1) in #443. I filed a separate #444 for tracking support for CFF-flavored OT-SVG, but won't work on it immediately as there's the otf2ttf.py workaround.