158 lines
4.2 KiB
Python
Executable File
158 lines
4.2 KiB
Python
Executable File
#!/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())
|