Home | History | Annotate | Download | only in pens
      1 from __future__ import print_function, division, absolute_import
      2 from fontTools.misc.py23 import *
      3 from fontTools.pens.basePen import BasePen
      4 
      5 
      6 def pointToString(pt):
      7     return " ".join([str(i) for i in pt])
      8 
      9 
     10 class 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 
    175 if __name__ == "__main__":
    176     import sys
    177     import doctest
    178     sys.exit(doctest.testmod().failed)
    179