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