from fontTools.pens.basePen import BasePen def pointToString(pt): return " ".join([str(i) for i in pt]) class SVGPathPen(BasePen): def __init__(self, glyphSet): BasePen.__init__(self, glyphSet) self._commands = [] self._lastCommand = None self._lastX = None self._lastY = None def _handleAnchor(self): """ >>> pen = SVGPathPen(None) >>> pen.moveTo((0, 0)) >>> pen.moveTo((10, 10)) >>> pen._commands ['M10 10'] """ if self._lastCommand == "M": self._commands.pop(-1) def _moveTo(self, pt): """ >>> pen = SVGPathPen(None) >>> pen.moveTo((0, 0)) >>> pen._commands ['M0 0'] >>> pen = SVGPathPen(None) >>> pen.moveTo((10, 0)) >>> pen._commands ['M10 0'] >>> pen = SVGPathPen(None) >>> pen.moveTo((0, 10)) >>> pen._commands ['M0 10'] """ self._handleAnchor() t = "M%s" % (pointToString(pt)) self._commands.append(t) self._lastCommand = "M" self._lastX, self._lastY = pt def _lineTo(self, pt): """ # duplicate point >>> pen = SVGPathPen(None) >>> pen.moveTo((10, 10)) >>> pen.lineTo((10, 10)) >>> pen._commands ['M10 10'] # vertical line >>> pen = SVGPathPen(None) >>> pen.moveTo((10, 10)) >>> pen.lineTo((10, 0)) >>> pen._commands ['M10 10', 'V0'] # horizontal line >>> pen = SVGPathPen(None) >>> pen.moveTo((10, 10)) >>> pen.lineTo((0, 10)) >>> pen._commands ['M10 10', 'H0'] # basic >>> pen = SVGPathPen(None) >>> pen.lineTo((70, 80)) >>> pen._commands ['L70 80'] # basic following a moveto >>> pen = SVGPathPen(None) >>> pen.moveTo((0, 0)) >>> pen.lineTo((10, 10)) >>> pen._commands ['M0 0', ' 10 10'] """ x, y = pt # duplicate point if x == self._lastX and y == self._lastY: return # vertical line elif x == self._lastX: cmd = "V" pts = str(y) # horizontal line elif y == self._lastY: cmd = "H" pts = str(x) # previous was a moveto elif self._lastCommand == "M": cmd = None pts = " " + pointToString(pt) # basic else: cmd = "L" pts = pointToString(pt) # write the string t = "" if cmd: t += cmd self._lastCommand = cmd t += pts self._commands.append(t) # store for future reference self._lastX, self._lastY = pt def _curveToOne(self, pt1, pt2, pt3): """ >>> pen = SVGPathPen(None) >>> pen.curveTo((10, 20), (30, 40), (50, 60)) >>> pen._commands ['C10 20 30 40 50 60'] """ t = "C" t += pointToString(pt1) + " " t += pointToString(pt2) + " " t += pointToString(pt3) self._commands.append(t) self._lastCommand = "C" self._lastX, self._lastY = pt3 def _qCurveToOne(self, pt1, pt2): """ >>> pen = SVGPathPen(None) >>> pen.qCurveTo((10, 20), (30, 40)) >>> pen._commands ['Q10 20 30 40'] """ assert pt2 is not None t = "Q" t += pointToString(pt1) + " " t += pointToString(pt2) self._commands.append(t) self._lastCommand = "Q" self._lastX, self._lastY = pt2 def _closePath(self): """ >>> pen = SVGPathPen(None) >>> pen.closePath() >>> pen._commands ['Z'] """ self._commands.append("Z") self._lastCommand = "Z" self._lastX = self._lastY = None def _endPath(self): """ >>> pen = SVGPathPen(None) >>> pen.endPath() >>> pen._commands ['Z'] """ self._closePath() self._lastCommand = None self._lastX = self._lastY = None def getCommands(self): return "".join(self._commands) if __name__ == "__main__": import sys import doctest sys.exit(doctest.testmod().failed)