• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2""" Convert SVG paths to UFO glyphs. """
3
4from __future__ import print_function, absolute_import
5
6__requires__ = ["FontTools", "ufoLib"]
7
8from fontTools.misc.py23 import SimpleNamespace
9from fontTools.svgLib import SVGPath
10
11from fontTools.pens.pointPen import SegmentToPointPen
12from fontTools.ufoLib.glifLib import writeGlyphToString
13
14
15__all__ = ["svg2glif"]
16
17
18def svg2glif(svg, name, width=0, height=0, unicodes=None, transform=None,
19             version=2):
20    """ Convert an SVG outline to a UFO glyph with given 'name', advance
21    'width' and 'height' (int), and 'unicodes' (list of int).
22    Return the resulting string in GLIF format (default: version 2).
23    If 'transform' is provided, apply a transformation matrix before the
24    conversion (must be tuple of 6 floats, or a FontTools Transform object).
25    """
26    glyph = SimpleNamespace(width=width, height=height, unicodes=unicodes)
27    outline = SVGPath.fromstring(svg, transform=transform)
28
29    # writeGlyphToString takes a callable (usually a glyph's drawPoints
30    # method) that accepts a PointPen, however SVGPath currently only has
31    # a draw method that accepts a segment pen. We need to wrap the call
32    # with a converter pen.
33    def drawPoints(pointPen):
34        pen = SegmentToPointPen(pointPen)
35        outline.draw(pen)
36
37    return writeGlyphToString(name,
38                              glyphObject=glyph,
39                              drawPointsFunc=drawPoints,
40                              formatVersion=version)
41
42
43def parse_args(args):
44    import argparse
45
46    def split(arg):
47        return arg.replace(",", " ").split()
48
49    def unicode_hex_list(arg):
50        try:
51            return [int(unihex, 16) for unihex in split(arg)]
52        except ValueError:
53            msg = "Invalid unicode hexadecimal value: %r" % arg
54            raise argparse.ArgumentTypeError(msg)
55
56    def transform_list(arg):
57        try:
58            return [float(n) for n in split(arg)]
59        except ValueError:
60            msg = "Invalid transformation matrix: %r" % arg
61            raise argparse.ArgumentTypeError(msg)
62
63    parser = argparse.ArgumentParser(
64        description="Convert SVG outlines to UFO glyphs (.glif)")
65    parser.add_argument(
66        "infile", metavar="INPUT.svg", help="Input SVG file containing "
67        '<path> elements with "d" attributes.')
68    parser.add_argument(
69        "outfile", metavar="OUTPUT.glif", help="Output GLIF file (default: "
70        "print to stdout)", nargs='?')
71    parser.add_argument(
72        "-n", "--name", help="The glyph name (default: input SVG file "
73        "basename, without the .svg extension)")
74    parser.add_argument(
75        "-w", "--width", help="The glyph advance width (default: 0)",
76        type=int, default=0)
77    parser.add_argument(
78        "-H", "--height", help="The glyph vertical advance (optional if "
79        '"width" is defined)', type=int, default=0)
80    parser.add_argument(
81        "-u", "--unicodes", help="List of Unicode code points as hexadecimal "
82        'numbers (e.g. -u "0041 0042")',
83        type=unicode_hex_list)
84    parser.add_argument(
85        "-t", "--transform", help="Transformation matrix as a list of six "
86        'float values (e.g. -t "0.1 0 0 -0.1 -50 200")', type=transform_list)
87    parser.add_argument(
88        "-f", "--format", help="UFO GLIF format version (default: 2)",
89        type=int, choices=(1, 2), default=2)
90
91    return parser.parse_args(args)
92
93
94def main(args=None):
95    from io import open
96
97    options = parse_args(args)
98
99    svg_file = options.infile
100
101    if options.name:
102        name = options.name
103    else:
104        import os
105        name = os.path.splitext(os.path.basename(svg_file))[0]
106
107    with open(svg_file, "r", encoding="utf-8") as f:
108        svg = f.read()
109
110    glif = svg2glif(svg, name,
111                    width=options.width,
112                    height=options.height,
113                    unicodes=options.unicodes,
114                    transform=options.transform,
115                    version=options.format)
116
117    if options.outfile is None:
118        print(glif)
119    else:
120        with open(options.outfile, 'w', encoding='utf-8') as f:
121            f.write(glif)
122
123
124if __name__ == "__main__":
125    import sys
126    sys.exit(main())
127