cli.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. import os
  2. import argparse
  3. import logging
  4. from fontTools.misc.cliTools import makeOutputFileName
  5. from fontTools.ttLib import TTFont
  6. from fontTools.pens.qu2cuPen import Qu2CuPen
  7. from fontTools.pens.ttGlyphPen import TTGlyphPen
  8. import fontTools
  9. logger = logging.getLogger("fontTools.qu2cu")
  10. def _font_to_cubic(input_path, output_path=None, **kwargs):
  11. font = TTFont(input_path)
  12. logger.info("Converting curves for %s", input_path)
  13. stats = {} if kwargs["dump_stats"] else None
  14. qu2cu_kwargs = {
  15. "stats": stats,
  16. "max_err": kwargs["max_err_em"] * font["head"].unitsPerEm,
  17. "all_cubic": kwargs["all_cubic"],
  18. }
  19. assert "gvar" not in font, "Cannot convert variable font"
  20. glyphSet = font.getGlyphSet()
  21. glyphOrder = font.getGlyphOrder()
  22. glyf = font["glyf"]
  23. for glyphName in glyphOrder:
  24. glyph = glyphSet[glyphName]
  25. ttpen = TTGlyphPen(glyphSet)
  26. pen = Qu2CuPen(ttpen, **qu2cu_kwargs)
  27. glyph.draw(pen)
  28. glyf[glyphName] = ttpen.glyph(dropImpliedOnCurves=True)
  29. font["head"].glyphDataFormat = 1
  30. if kwargs["dump_stats"]:
  31. logger.info("Stats: %s", stats)
  32. logger.info("Saving %s", output_path)
  33. font.save(output_path)
  34. def main(args=None):
  35. """Convert an OpenType font from quadratic to cubic curves"""
  36. parser = argparse.ArgumentParser(prog="qu2cu")
  37. parser.add_argument("--version", action="version", version=fontTools.__version__)
  38. parser.add_argument(
  39. "infiles",
  40. nargs="+",
  41. metavar="INPUT",
  42. help="one or more input TTF source file(s).",
  43. )
  44. parser.add_argument("-v", "--verbose", action="count", default=0)
  45. parser.add_argument(
  46. "-e",
  47. "--conversion-error",
  48. type=float,
  49. metavar="ERROR",
  50. default=0.001,
  51. help="maxiumum approximation error measured in EM (default: 0.001)",
  52. )
  53. parser.add_argument(
  54. "-c",
  55. "--all-cubic",
  56. default=False,
  57. action="store_true",
  58. help="whether to only use cubic curves",
  59. )
  60. output_parser = parser.add_mutually_exclusive_group()
  61. output_parser.add_argument(
  62. "-o",
  63. "--output-file",
  64. default=None,
  65. metavar="OUTPUT",
  66. help=("output filename for the converted TTF."),
  67. )
  68. output_parser.add_argument(
  69. "-d",
  70. "--output-dir",
  71. default=None,
  72. metavar="DIRECTORY",
  73. help="output directory where to save converted TTFs",
  74. )
  75. options = parser.parse_args(args)
  76. if not options.verbose:
  77. level = "WARNING"
  78. elif options.verbose == 1:
  79. level = "INFO"
  80. else:
  81. level = "DEBUG"
  82. logging.basicConfig(level=level)
  83. if len(options.infiles) > 1 and options.output_file:
  84. parser.error("-o/--output-file can't be used with multile inputs")
  85. if options.output_dir:
  86. output_dir = options.output_dir
  87. if not os.path.exists(output_dir):
  88. os.mkdir(output_dir)
  89. elif not os.path.isdir(output_dir):
  90. parser.error("'%s' is not a directory" % output_dir)
  91. output_paths = [
  92. os.path.join(output_dir, os.path.basename(p)) for p in options.infiles
  93. ]
  94. elif options.output_file:
  95. output_paths = [options.output_file]
  96. else:
  97. output_paths = [
  98. makeOutputFileName(p, overWrite=True, suffix=".cubic")
  99. for p in options.infiles
  100. ]
  101. kwargs = dict(
  102. dump_stats=options.verbose > 0,
  103. max_err_em=options.conversion_error,
  104. all_cubic=options.all_cubic,
  105. )
  106. for input_path, output_path in zip(options.infiles, output_paths):
  107. _font_to_cubic(input_path, output_path, **kwargs)