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