split_slnt_vf.py 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. """
  2. ...
  3. """
  4. import argparse
  5. import sys
  6. import os
  7. from fontTools.ttLib import TTFont
  8. from fontTools.varLib.instancer import (
  9. instantiateVariableFont,
  10. sanityCheckVariableTables
  11. )
  12. def split_slnt(ttfont, out_dir):
  13. """Use varlib instance to split a variable font if it contains a
  14. slnt or ital axis."""
  15. sanityCheckVariableTables(ttfont)
  16. axes = {a.axisTag: a for a in ttfont['fvar'].axes}
  17. ital_angle = axes['ital'].maxValue
  18. roman = instantiateVariableFont(ttfont, {"ital": 0})
  19. italic = instantiateVariableFont(ttfont, {"ital": ital_angle})
  20. _update_bits(italic)
  21. _update_nametable(italic)
  22. roman_filename = os.path.join(
  23. out_dir,
  24. vf_filename(roman)
  25. )
  26. roman.save(roman_filename)
  27. italic_filename = os.path.join(
  28. out_dir,
  29. vf_filename(italic)
  30. )
  31. italic.save(italic_filename)
  32. def vf_filename(ttfont):
  33. axes = sorted([a.axisTag for a in ttfont['fvar'].axes])
  34. axes = ",".join(axes)
  35. family_name = ttfont['name'].getName(1, 3, 1, 1033)
  36. name = family_name.toUnicode()
  37. if "Italic" in ttfont['name'].getName(2, 3, 1, 1033).toUnicode():
  38. return f"{name}-Italic[{axes}].ttf"
  39. return f"{name}[{axes}].ttf"
  40. def _update_bits(ttfont):
  41. """Update bits for instantiated italic font"""
  42. # OS/2: disable Regular bit and enable italic bit
  43. ttfont['OS/2'].fsSelection ^= (1 << 6) | 1
  44. # head: enable italic bit
  45. ttfont["head"].macStyle |= (1 << 1)
  46. ttfont["post"].italicAngle = -12
  47. ttfont["hhea"].caretSlopeRun = 435
  48. ttfont["hhea"].caretSlopeRise = 2048
  49. def _update_nametable(ttfont):
  50. nametable = ttfont['name']
  51. dflt_axes_loc = {a.axisTag: a.defaultValue for a in ttfont['fvar'].axes}
  52. dflt_nameid = None
  53. for instance in ttfont['fvar'].instances:
  54. if instance.coordinates == dflt_axes_loc:
  55. dflt_nameid = instance.subfamilyNameID
  56. if not dflt_nameid:
  57. raise ValueError("Cannot name font. Default axis locations are not represented by an instance.")
  58. dflt_name = nametable.getName(dflt_nameid, 3, 1, 1033).toUnicode()
  59. # Update subfamily name
  60. nametable.setName(dflt_name, 2, 3, 1, 1033)
  61. # Update unique font identifier
  62. version = "{:.3f}".format(ttfont['head'].fontRevision)
  63. vendor = ttfont['OS/2'].achVendID
  64. familyname = nametable.getName(1, 3, 1, 1033).toUnicode()
  65. unique_name = f"{version} {vendor} {familyname}-{dflt_name}"
  66. nametable.setName(unique_name, 3, 3, 1, 1033)
  67. # Update full font name
  68. full_font_name = f"{familyname} {dflt_name}"
  69. nametable.setName(full_font_name, 4, 3, 1, 1033)
  70. nametable.setName(full_font_name, 4, 1, 0, 0)
  71. # Postscript name
  72. postscript_name = f"{familyname}-{dflt_name}"
  73. nametable.setName(postscript_name, 6, 3, 1, 1033)
  74. nametable.setName(postscript_name, 6, 1, 0, 0)
  75. def main():
  76. ttfont = TTFont(sys.argv[1])
  77. split_slnt(ttfont, sys.argv[2])
  78. if __name__ == "__main__":
  79. main()