googlefonts / nanoemoji

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

Generation of bad affines #313

Open rsheeter opened 3 years ago

rsheeter commented 3 years ago

Observed with Noto (blocking a full build on latest nanoemoji) and Twemoji, it seems there is a bug in how we produce transforms somewhere. For example:

In a color-fonts checkout, save the following in config/bad_affine.config:

family = "bad_affine-glyf_colr_1"
output_file = "bad_affine-glyf_colr_1.ttf"
color_format = "glyf_colr_1"

[axis.wght]
name = "Weight"
default = 400

[master.regular]
style_name = "Regular"
srcs = ["../font-srcs/twemoji/assets/svg/1f1e6-1f1f4.svg", "../font-srcs/twemoji/assets/svg/1f558.svg"]

[master.regular.position]
wght = 400

Try to build it:

nanoemoji --config bad_affine.config

I0803 20:11:39.007790 140004993345344 __init__.py:234] Building OpenType tables
Traceback (most recent call last):
  File "/usr/lib/python3.9/runpy.py", line 197, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/lib/python3.9/runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "oss/nanoemoji/src/nanoemoji/write_font.py", line 640, in <module>
    app.run(main)
  File "oss/color-fonts/venv/lib/python3.9/site-packages/absl/app.py", line 312, in run
    _run_main(main, args)
  File "oss/color-fonts/venv/lib/python3.9/site-packages/absl/app.py", line 258, in _run_main
    sys.exit(main(argv))
  File "oss/nanoemoji/src/nanoemoji/write_font.py", line 634, in main
    ufo, ttfont = _generate_color_font(font_config, inputs)
  File "oss/nanoemoji/src/nanoemoji/write_font.py", line 600, in _generate_color_font
    ttfont = _make_ttfont(config, ufo, color_glyphs)
  File "oss/nanoemoji/src/nanoemoji/write_font.py", line 197, in _make_ttfont
    ttfont = ufo2ft.compileTTF(ufo, overlapsBackend="pathops")
  File "oss/color-fonts/venv/lib/python3.9/site-packages/ufo2ft/__init__.py", line 252, in compileTTF
    postProcessor = postProcessorClass(otf, ufo, glyphSet=glyphSet)
  File "oss/color-fonts/venv/lib/python3.9/site-packages/ufo2ft/postProcessor.py", line 50, in __init__
    self.otf = _reloadFont(otf)
  File "oss/color-fonts/venv/lib/python3.9/site-packages/ufo2ft/postProcessor.py", line 392, in _reloadFont
    font.save(stream)
  File "oss/color-fonts/venv/lib/python3.9/site-packages/fontTools/ttLib/ttFont.py", line 172, in save
    writer_reordersTables = self._save(tmp)
  File "oss/color-fonts/venv/lib/python3.9/site-packages/fontTools/ttLib/ttFont.py", line 212, in _save
    self._writeTable(tag, writer, done, tableCache)
  File "oss/color-fonts/venv/lib/python3.9/site-packages/fontTools/ttLib/ttFont.py", line 634, in _writeTable
    tabledata = self.getTableData(tag)
  File "oss/color-fonts/venv/lib/python3.9/site-packages/fontTools/ttLib/ttFont.py", line 652, in getTableData
    return self.tables[tag].compile(self)
  File "oss/color-fonts/venv/lib/python3.9/site-packages/fontTools/ttLib/tables/C_O_L_R_.py", line 82, in compile
    table.compile(writer, ttFont)
  File "oss/color-fonts/venv/lib/python3.9/site-packages/fontTools/ttLib/tables/otBase.py", line 773, in compile
    conv.write(writer, font, table, value)
  File "oss/color-fonts/venv/lib/python3.9/site-packages/fontTools/ttLib/tables/otConverters.py", line 645, in write
    value.compile(subWriter, font)
  File "oss/color-fonts/venv/lib/python3.9/site-packages/fontTools/ttLib/tables/otBase.py", line 737, in compile
    conv.writeArray(writer, font, table, value)
  File "oss/color-fonts/venv/lib/python3.9/site-packages/fontTools/ttLib/tables/otConverters.py", line 198, in writeArray
    self.write(writer, font, tableDict, value, i)
  File "oss/color-fonts/venv/lib/python3.9/site-packages/fontTools/ttLib/tables/otConverters.py", line 524, in write
    value.compile(writer, font)
  File "oss/color-fonts/venv/lib/python3.9/site-packages/fontTools/ttLib/tables/otBase.py", line 773, in compile
    conv.write(writer, font, table, value)
  File "oss/color-fonts/venv/lib/python3.9/site-packages/fontTools/ttLib/tables/otConverters.py", line 645, in write
    value.compile(subWriter, font)
  File "oss/color-fonts/venv/lib/python3.9/site-packages/fontTools/ttLib/tables/otBase.py", line 773, in compile
    conv.write(writer, font, table, value)
  File "oss/color-fonts/venv/lib/python3.9/site-packages/fontTools/ttLib/tables/otConverters.py", line 645, in write
    value.compile(subWriter, font)
  File "oss/color-fonts/venv/lib/python3.9/site-packages/fontTools/ttLib/tables/otBase.py", line 773, in compile
    conv.write(writer, font, table, value)
  File "oss/color-fonts/venv/lib/python3.9/site-packages/fontTools/ttLib/tables/otConverters.py", line 424, in write
    writer.writeLong(fl2fi(value, 16))
  File "oss/color-fonts/venv/lib/python3.9/site-packages/fontTools/ttLib/tables/otBase.py", line 456, in writeLong
    self.items.append(struct.pack(">i", value))
struct.error: ("'i' format requires -2147483648 <= number <= 2147483647", 'float', 'Affine2x3', 'Paint', 17, 'BaseGlyphPaintRecord[]', 'BaseGlyphList')
BAD VALUE -5284745164
ninja: build stopped: subcommand failed.
Traceback (most recent call last):
  File "oss/color-fonts/venv/bin/nanoemoji", line 11, in <module>
    load_entry_point('nanoemoji', 'console_scripts', 'nanoemoji')()
  File "oss/nanoemoji/src/nanoemoji/nanoemoji.py", line 376, in main
    app.run(_run)
  File "oss/color-fonts/venv/lib/python3.9/site-packages/absl/app.py", line 312, in run
    _run_main(main, args)
  File "oss/color-fonts/venv/lib/python3.9/site-packages/absl/app.py", line 258, in _run_main
    sys.exit(main(argv))
  File "oss/nanoemoji/src/nanoemoji/nanoemoji.py", line 367, in _run
    subprocess.run(ninja_cmd, check=True)
  File "/usr/lib/python3.9/subprocess.py", line 528, in run
    raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command '['ninja', '-C', 'oss/color-fonts/build']' returned non-zero exit status 1.

The "BAD VALUE" is custom local logging. A config for either of the files individually will build successfully.

rsheeter commented 3 years ago

It seems we come up with the following rather suspicious looking 2x3:

Bad 2x3
   xx 99.9995
   yx -0.0005
   xy 0.0005
   yy 99.9995
   dx -80638.8117
   dy -13009.5193
rsheeter commented 3 years ago

Amusingly the affine is "bad" in one direction only.

A:B Affine2D(a=99.9995, b=-0.0005, c=0.0005, d=99.9995, e=-80638.8117, f=-13009.5193)
B:A Affine2D(a=0.01, b=0.0, c=-0.0, d=0.01, e=806.392, f=130.1)

The actual shapes seem to be a small circle and a big circle (turned into cubics):

image