Coverage for /usr/lib/python3/dist-packages/fontTools/pens/filterPen.py: 44%
55 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1from fontTools.pens.basePen import AbstractPen
2from fontTools.pens.pointPen import AbstractPointPen
3from fontTools.pens.recordingPen import RecordingPen
6class _PassThruComponentsMixin(object):
7 def addComponent(self, glyphName, transformation, **kwargs):
8 self._outPen.addComponent(glyphName, transformation, **kwargs)
11class FilterPen(_PassThruComponentsMixin, AbstractPen):
13 """Base class for pens that apply some transformation to the coordinates
14 they receive and pass them to another pen.
16 You can override any of its methods. The default implementation does
17 nothing, but passes the commands unmodified to the other pen.
19 >>> from fontTools.pens.recordingPen import RecordingPen
20 >>> rec = RecordingPen()
21 >>> pen = FilterPen(rec)
22 >>> v = iter(rec.value)
24 >>> pen.moveTo((0, 0))
25 >>> next(v)
26 ('moveTo', ((0, 0),))
28 >>> pen.lineTo((1, 1))
29 >>> next(v)
30 ('lineTo', ((1, 1),))
32 >>> pen.curveTo((2, 2), (3, 3), (4, 4))
33 >>> next(v)
34 ('curveTo', ((2, 2), (3, 3), (4, 4)))
36 >>> pen.qCurveTo((5, 5), (6, 6), (7, 7), (8, 8))
37 >>> next(v)
38 ('qCurveTo', ((5, 5), (6, 6), (7, 7), (8, 8)))
40 >>> pen.closePath()
41 >>> next(v)
42 ('closePath', ())
44 >>> pen.moveTo((9, 9))
45 >>> next(v)
46 ('moveTo', ((9, 9),))
48 >>> pen.endPath()
49 >>> next(v)
50 ('endPath', ())
52 >>> pen.addComponent('foo', (1, 0, 0, 1, 0, 0))
53 >>> next(v)
54 ('addComponent', ('foo', (1, 0, 0, 1, 0, 0)))
55 """
57 def __init__(self, outPen):
58 self._outPen = outPen
59 self.current_pt = None
61 def moveTo(self, pt):
62 self._outPen.moveTo(pt)
63 self.current_pt = pt
65 def lineTo(self, pt):
66 self._outPen.lineTo(pt)
67 self.current_pt = pt
69 def curveTo(self, *points):
70 self._outPen.curveTo(*points)
71 self.current_pt = points[-1]
73 def qCurveTo(self, *points):
74 self._outPen.qCurveTo(*points)
75 self.current_pt = points[-1]
77 def closePath(self):
78 self._outPen.closePath()
79 self.current_pt = None
81 def endPath(self):
82 self._outPen.endPath()
83 self.current_pt = None
86class ContourFilterPen(_PassThruComponentsMixin, RecordingPen):
87 """A "buffered" filter pen that accumulates contour data, passes
88 it through a ``filterContour`` method when the contour is closed or ended,
89 and finally draws the result with the output pen.
91 Components are passed through unchanged.
92 """
94 def __init__(self, outPen):
95 super(ContourFilterPen, self).__init__()
96 self._outPen = outPen
98 def closePath(self):
99 super(ContourFilterPen, self).closePath()
100 self._flushContour()
102 def endPath(self):
103 super(ContourFilterPen, self).endPath()
104 self._flushContour()
106 def _flushContour(self):
107 result = self.filterContour(self.value)
108 if result is not None:
109 self.value = result
110 self.replay(self._outPen)
111 self.value = []
113 def filterContour(self, contour):
114 """Subclasses must override this to perform the filtering.
116 The contour is a list of pen (operator, operands) tuples.
117 Operators are strings corresponding to the AbstractPen methods:
118 "moveTo", "lineTo", "curveTo", "qCurveTo", "closePath" and
119 "endPath". The operands are the positional arguments that are
120 passed to each method.
122 If the method doesn't return a value (i.e. returns None), it's
123 assumed that the argument was modified in-place.
124 Otherwise, the return value is drawn with the output pen.
125 """
126 return # or return contour
129class FilterPointPen(_PassThruComponentsMixin, AbstractPointPen):
130 """Baseclass for point pens that apply some transformation to the
131 coordinates they receive and pass them to another point pen.
133 You can override any of its methods. The default implementation does
134 nothing, but passes the commands unmodified to the other pen.
136 >>> from fontTools.pens.recordingPen import RecordingPointPen
137 >>> rec = RecordingPointPen()
138 >>> pen = FilterPointPen(rec)
139 >>> v = iter(rec.value)
140 >>> pen.beginPath(identifier="abc")
141 >>> next(v)
142 ('beginPath', (), {'identifier': 'abc'})
143 >>> pen.addPoint((1, 2), "line", False)
144 >>> next(v)
145 ('addPoint', ((1, 2), 'line', False, None), {})
146 >>> pen.addComponent("a", (2, 0, 0, 2, 10, -10), identifier="0001")
147 >>> next(v)
148 ('addComponent', ('a', (2, 0, 0, 2, 10, -10)), {'identifier': '0001'})
149 >>> pen.endPath()
150 >>> next(v)
151 ('endPath', (), {})
152 """
154 def __init__(self, outPointPen):
155 self._outPen = outPointPen
157 def beginPath(self, **kwargs):
158 self._outPen.beginPath(**kwargs)
160 def endPath(self):
161 self._outPen.endPath()
163 def addPoint(self, pt, segmentType=None, smooth=False, name=None, **kwargs):
164 self._outPen.addPoint(pt, segmentType, smooth, name, **kwargs)