• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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