• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from __future__ import print_function, division, absolute_import
2from fontTools.misc.py23 import *
3from fontTools.pens.basePen import BasePen
4
5
6def pointToString(pt):
7    return " ".join([str(i) for i in pt])
8
9
10class SVGPathPen(BasePen):
11
12    def __init__(self, glyphSet):
13        BasePen.__init__(self, glyphSet)
14        self._commands = []
15        self._lastCommand = None
16        self._lastX = None
17        self._lastY = None
18
19    def _handleAnchor(self):
20        """
21        >>> pen = SVGPathPen(None)
22        >>> pen.moveTo((0, 0))
23        >>> pen.moveTo((10, 10))
24        >>> pen._commands
25        ['M10 10']
26        """
27        if self._lastCommand == "M":
28            self._commands.pop(-1)
29
30    def _moveTo(self, pt):
31        """
32        >>> pen = SVGPathPen(None)
33        >>> pen.moveTo((0, 0))
34        >>> pen._commands
35        ['M0 0']
36
37        >>> pen = SVGPathPen(None)
38        >>> pen.moveTo((10, 0))
39        >>> pen._commands
40        ['M10 0']
41
42        >>> pen = SVGPathPen(None)
43        >>> pen.moveTo((0, 10))
44        >>> pen._commands
45        ['M0 10']
46        """
47        self._handleAnchor()
48        t = "M%s" % (pointToString(pt))
49        self._commands.append(t)
50        self._lastCommand = "M"
51        self._lastX, self._lastY = pt
52
53    def _lineTo(self, pt):
54        """
55        # duplicate point
56        >>> pen = SVGPathPen(None)
57        >>> pen.moveTo((10, 10))
58        >>> pen.lineTo((10, 10))
59        >>> pen._commands
60        ['M10 10']
61
62        # vertical line
63        >>> pen = SVGPathPen(None)
64        >>> pen.moveTo((10, 10))
65        >>> pen.lineTo((10, 0))
66        >>> pen._commands
67        ['M10 10', 'V0']
68
69        # horizontal line
70        >>> pen = SVGPathPen(None)
71        >>> pen.moveTo((10, 10))
72        >>> pen.lineTo((0, 10))
73        >>> pen._commands
74        ['M10 10', 'H0']
75
76        # basic
77        >>> pen = SVGPathPen(None)
78        >>> pen.lineTo((70, 80))
79        >>> pen._commands
80        ['L70 80']
81
82        # basic following a moveto
83        >>> pen = SVGPathPen(None)
84        >>> pen.moveTo((0, 0))
85        >>> pen.lineTo((10, 10))
86        >>> pen._commands
87        ['M0 0', ' 10 10']
88        """
89        x, y = pt
90        # duplicate point
91        if x == self._lastX and y == self._lastY:
92            return
93        # vertical line
94        elif x == self._lastX:
95            cmd = "V"
96            pts = str(y)
97        # horizontal line
98        elif y == self._lastY:
99            cmd = "H"
100            pts = str(x)
101        # previous was a moveto
102        elif self._lastCommand == "M":
103            cmd = None
104            pts = " " + pointToString(pt)
105        # basic
106        else:
107            cmd = "L"
108            pts = pointToString(pt)
109        # write the string
110        t = ""
111        if cmd:
112            t += cmd
113            self._lastCommand = cmd
114        t += pts
115        self._commands.append(t)
116        # store for future reference
117        self._lastX, self._lastY = pt
118
119    def _curveToOne(self, pt1, pt2, pt3):
120        """
121        >>> pen = SVGPathPen(None)
122        >>> pen.curveTo((10, 20), (30, 40), (50, 60))
123        >>> pen._commands
124        ['C10 20 30 40 50 60']
125        """
126        t = "C"
127        t += pointToString(pt1) + " "
128        t += pointToString(pt2) + " "
129        t += pointToString(pt3)
130        self._commands.append(t)
131        self._lastCommand = "C"
132        self._lastX, self._lastY = pt3
133
134    def _qCurveToOne(self, pt1, pt2):
135        """
136        >>> pen = SVGPathPen(None)
137        >>> pen.qCurveTo((10, 20), (30, 40))
138        >>> pen._commands
139        ['Q10 20 30 40']
140        """
141        assert pt2 is not None
142        t = "Q"
143        t += pointToString(pt1) + " "
144        t += pointToString(pt2)
145        self._commands.append(t)
146        self._lastCommand = "Q"
147        self._lastX, self._lastY = pt2
148
149    def _closePath(self):
150        """
151        >>> pen = SVGPathPen(None)
152        >>> pen.closePath()
153        >>> pen._commands
154        ['Z']
155        """
156        self._commands.append("Z")
157        self._lastCommand = "Z"
158        self._lastX = self._lastY = None
159
160    def _endPath(self):
161        """
162        >>> pen = SVGPathPen(None)
163        >>> pen.endPath()
164        >>> pen._commands
165        ['Z']
166        """
167        self._closePath()
168        self._lastCommand = None
169        self._lastX = self._lastY = None
170
171    def getCommands(self):
172        return "".join(self._commands)
173
174
175if __name__ == "__main__":
176    import sys
177    import doctest
178    sys.exit(doctest.testmod().failed)
179