diff --git a/Snippets/svg2glif.py b/Snippets/svg2glif.py new file mode 100755 index 000000000..2dd64027e --- /dev/null +++ b/Snippets/svg2glif.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python +""" Convert SVG paths to UFO glyphs. """ + +from __future__ import print_function, absolute_import + +__requires__ = ["FontTools", "ufoLib"] + +from fontTools.misc.py23 import SimpleNamespace +from fontTools.svgLib import SVGPath + +from ufoLib.pointPen import SegmentToPointPen +from ufoLib.glifLib import writeGlyphToString + + +__all__ = ["svg2glif"] + + +def svg2glif(svg, name, width=0, height=0, unicodes=None, transform=None, + version=2): + """ Convert an SVG outline to a UFO glyph with given 'name', advance + 'width' and 'height' (int), and 'unicodes' (list of int). + Return the resulting string in GLIF format (default: version 2). + If 'transform' is provided, apply a transformation matrix before the + conversion (must be tuple of 6 floats, or a FontTools Transform object). + """ + glyph = SimpleNamespace(width=width, height=height, unicodes=unicodes) + outline = SVGPath.fromstring(svg, transform=transform) + + # writeGlyphToString takes a callable (usually a glyph's drawPoints + # method) that accepts a PointPen, however SVGPath currently only has + # a draw method that accepts a segment pen. We need to wrap the call + # with a converter pen. + def drawPoints(pointPen): + pen = SegmentToPointPen(pointPen) + outline.draw(pen) + + return writeGlyphToString(name, + glyphObject=glyph, + drawPointsFunc=drawPoints, + formatVersion=version) + + +def parse_args(args): + import argparse + + def split(arg): + return arg.replace(",", " ").split() + + def unicode_hex_list(arg): + try: + return [int(unihex, 16) for unihex in split(arg)] + except ValueError: + msg = "Invalid unicode hexadecimal value: %r" % arg + raise argparse.ArgumentTypeError(msg) + + def transform_list(arg): + try: + return [float(n) for n in split(arg)] + except ValueError: + msg = "Invalid transformation matrix: %r" % arg + raise argparse.ArgumentTypeError(msg) + + parser = argparse.ArgumentParser( + description="Convert SVG outlines to UFO glyphs (.glif)") + parser.add_argument( + "infile", metavar="INPUT.svg", help="Input SVG file containing " + ' elements with "d" attributes.') + parser.add_argument( + "outfile", metavar="OUTPUT.glif", help="Output GLIF file (default: " + "print to stdout)", nargs='?') + parser.add_argument( + "-n", "--name", help="The glyph name (default: input SVG file " + "basename, without the .svg extension)") + parser.add_argument( + "-w", "--width", help="The glyph advance width (default: 0)", + type=int, default=0) + parser.add_argument( + "-H", "--height", help="The glyph vertical advance (optional if " + '"width" is defined)', type=int, default=0) + parser.add_argument( + "-u", "--unicodes", help="List of Unicode code points as hexadecimal " + 'numbers (e.g. -u "0041 0042")', + type=unicode_hex_list) + parser.add_argument( + "-t", "--transform", help="Transformation matrix as a list of six " + 'float values (e.g. -t "0.1 0 0 -0.1 -50 200")', type=transform_list) + parser.add_argument( + "-f", "--format", help="UFO GLIF format version (default: 2)", + type=int, choices=(1, 2), default=2) + + return parser.parse_args(args) + + +def main(args=None): + from io import open + + options = parse_args(args) + + svg_file = options.infile + + if options.name: + name = options.name + else: + import os + name = os.path.splitext(os.path.basename(svg_file))[0] + + with open(svg_file, "r", encoding="utf-8") as f: + svg = f.read() + + glif = svg2glif(svg, name, + width=options.width, + height=options.height, + unicodes=options.unicodes, + transform=options.transform, + version=options.format) + + if options.outfile is None: + print(glif) + else: + with open(options.outfile, 'w', encoding='utf-8') as f: + f.write(glif) + + +if __name__ == "__main__": + import sys + sys.exit(main())