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
|
#!/usr/bin/env python3
""" Convert SVG paths to UFO glyphs. """
__requires__ = ["fontTools"]
from types 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())
|