Home | History | Annotate | Download | only in Snippets
      1 #!/usr/bin/env python
      2 """ Convert SVG paths to UFO glyphs. """
      3 
      4 from __future__ import print_function, absolute_import
      5 
      6 __requires__ = ["FontTools", "ufoLib"]
      7 
      8 from fontTools.misc.py23 import SimpleNamespace
      9 from fontTools.svgLib import SVGPath
     10 
     11 from fontTools.pens.pointPen import SegmentToPointPen
     12 from fontTools.ufoLib.glifLib import writeGlyphToString
     13 
     14 
     15 __all__ = ["svg2glif"]
     16 
     17 
     18 def 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 
     43 def 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 
     94 def 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 
    124 if __name__ == "__main__":
    125     import sys
    126     sys.exit(main())
    127