1from __future__ import ( 2 print_function, division, absolute_import, unicode_literals) 3from fontTools.misc.py23 import * 4 5from fontTools.pens.transformPen import TransformPen 6from fontTools.misc import etree 7from .parser import parse_path 8from .shapes import PathBuilder 9 10 11__all__ = [tostr(s) for s in ("SVGPath", "parse_path")] 12 13 14class SVGPath(object): 15 """ Parse SVG ``path`` elements from a file or string, and draw them 16 onto a glyph object that supports the FontTools Pen protocol. 17 18 For example, reading from an SVG file and drawing to a Defcon Glyph: 19 20 import defcon 21 glyph = defcon.Glyph() 22 pen = glyph.getPen() 23 svg = SVGPath("path/to/a.svg") 24 svg.draw(pen) 25 26 Or reading from a string containing SVG data, using the alternative 27 'fromstring' (a class method): 28 29 data = '<?xml version="1.0" ...' 30 svg = SVGPath.fromstring(data) 31 svg.draw(pen) 32 33 Both constructors can optionally take a 'transform' matrix (6-float 34 tuple, or a FontTools Transform object) to modify the draw output. 35 """ 36 37 def __init__(self, filename=None, transform=None): 38 if filename is None: 39 self.root = etree.ElementTree() 40 else: 41 tree = etree.parse(filename) 42 self.root = tree.getroot() 43 self.transform = transform 44 45 @classmethod 46 def fromstring(cls, data, transform=None): 47 self = cls(transform=transform) 48 self.root = etree.fromstring(data) 49 return self 50 51 def draw(self, pen): 52 if self.transform: 53 pen = TransformPen(pen, self.transform) 54 pb = PathBuilder() 55 # xpath | doesn't seem to reliable work so just walk it 56 for el in self.root.iter(): 57 pb.add_path_from_element(el) 58 original_pen = pen 59 for path, transform in zip(pb.paths, pb.transforms): 60 if transform: 61 pen = TransformPen(original_pen, transform) 62 else: 63 pen = original_pen 64 parse_path(path, pen) 65