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