huangcm
2025-02-24 69ed55dec4b2116a19e4cca4393cbc014fce5fb2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
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 fontTools.pens.pointPen import SegmentToPointPen
from fontTools.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 "
        '<path> 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())