1from fontTools.pens.filterPen import FilterPen, FilterPointPen 2 3 4__all__ = ["TransformPen"] 5 6 7class TransformPen(FilterPen): 8 9 """Pen that transforms all coordinates using a Affine transformation, 10 and passes them to another pen. 11 """ 12 13 def __init__(self, outPen, transformation): 14 """The 'outPen' argument is another pen object. It will receive the 15 transformed coordinates. The 'transformation' argument can either 16 be a six-tuple, or a fontTools.misc.transform.Transform object. 17 """ 18 super(TransformPen, self).__init__(outPen) 19 if not hasattr(transformation, "transformPoint"): 20 from fontTools.misc.transform import Transform 21 transformation = Transform(*transformation) 22 self._transformation = transformation 23 self._transformPoint = transformation.transformPoint 24 self._stack = [] 25 26 def moveTo(self, pt): 27 self._outPen.moveTo(self._transformPoint(pt)) 28 29 def lineTo(self, pt): 30 self._outPen.lineTo(self._transformPoint(pt)) 31 32 def curveTo(self, *points): 33 self._outPen.curveTo(*self._transformPoints(points)) 34 35 def qCurveTo(self, *points): 36 if points[-1] is None: 37 points = self._transformPoints(points[:-1]) + [None] 38 else: 39 points = self._transformPoints(points) 40 self._outPen.qCurveTo(*points) 41 42 def _transformPoints(self, points): 43 transformPoint = self._transformPoint 44 return [transformPoint(pt) for pt in points] 45 46 def closePath(self): 47 self._outPen.closePath() 48 49 def endPath(self): 50 self._outPen.endPath() 51 52 def addComponent(self, glyphName, transformation): 53 transformation = self._transformation.transform(transformation) 54 self._outPen.addComponent(glyphName, transformation) 55 56 57class TransformPointPen(FilterPointPen): 58 """PointPen that transforms all coordinates using a Affine transformation, 59 and passes them to another PointPen. 60 61 >>> from fontTools.pens.recordingPen import RecordingPointPen 62 >>> rec = RecordingPointPen() 63 >>> pen = TransformPointPen(rec, (2, 0, 0, 2, -10, 5)) 64 >>> v = iter(rec.value) 65 >>> pen.beginPath(identifier="contour-0") 66 >>> next(v) 67 ('beginPath', (), {'identifier': 'contour-0'}) 68 >>> pen.addPoint((100, 100), "line") 69 >>> next(v) 70 ('addPoint', ((190, 205), 'line', False, None), {}) 71 >>> pen.endPath() 72 >>> next(v) 73 ('endPath', (), {}) 74 >>> pen.addComponent("a", (1, 0, 0, 1, -10, 5), identifier="component-0") 75 >>> next(v) 76 ('addComponent', ('a', <Transform [2 0 0 2 -30 15]>), {'identifier': 'component-0'}) 77 """ 78 79 def __init__(self, outPointPen, transformation): 80 """The 'outPointPen' argument is another point pen object. 81 It will receive the transformed coordinates. 82 The 'transformation' argument can either be a six-tuple, or a 83 fontTools.misc.transform.Transform object. 84 """ 85 super().__init__(outPointPen) 86 if not hasattr(transformation, "transformPoint"): 87 from fontTools.misc.transform import Transform 88 transformation = Transform(*transformation) 89 self._transformation = transformation 90 self._transformPoint = transformation.transformPoint 91 92 def addPoint(self, pt, segmentType=None, smooth=False, name=None, **kwargs): 93 self._outPen.addPoint( 94 self._transformPoint(pt), segmentType, smooth, name, **kwargs 95 ) 96 97 def addComponent(self, baseGlyphName, transformation, **kwargs): 98 transformation = self._transformation.transform(transformation) 99 self._outPen.addComponent(baseGlyphName, transformation, **kwargs) 100 101 102if __name__ == "__main__": 103 from fontTools.pens.basePen import _TestPen 104 pen = TransformPen(_TestPen(None), (2, 0, 0.5, 2, -10, 0)) 105 pen.moveTo((0, 0)) 106 pen.lineTo((0, 100)) 107 pen.curveTo((50, 75), (60, 50), (50, 25), (0, 0)) 108 pen.closePath() 109