Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/fontTools/pens/recordingPen.py: 43%
61 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:33 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:33 +0000
1"""Pen recording operations that can be accessed or replayed."""
2from fontTools.pens.basePen import AbstractPen, DecomposingPen
3from fontTools.pens.pointPen import AbstractPointPen
6__all__ = [
7 "replayRecording",
8 "RecordingPen",
9 "DecomposingRecordingPen",
10 "RecordingPointPen",
11]
14def replayRecording(recording, pen):
15 """Replay a recording, as produced by RecordingPen or DecomposingRecordingPen,
16 to a pen.
18 Note that recording does not have to be produced by those pens.
19 It can be any iterable of tuples of method name and tuple-of-arguments.
20 Likewise, pen can be any objects receiving those method calls.
21 """
22 for operator, operands in recording:
23 getattr(pen, operator)(*operands)
26class RecordingPen(AbstractPen):
27 """Pen recording operations that can be accessed or replayed.
29 The recording can be accessed as pen.value; or replayed using
30 pen.replay(otherPen).
32 :Example:
34 from fontTools.ttLib import TTFont
35 from fontTools.pens.recordingPen import RecordingPen
37 glyph_name = 'dollar'
38 font_path = 'MyFont.otf'
40 font = TTFont(font_path)
41 glyphset = font.getGlyphSet()
42 glyph = glyphset[glyph_name]
44 pen = RecordingPen()
45 glyph.draw(pen)
46 print(pen.value)
47 """
49 def __init__(self):
50 self.value = []
52 def moveTo(self, p0):
53 self.value.append(("moveTo", (p0,)))
55 def lineTo(self, p1):
56 self.value.append(("lineTo", (p1,)))
58 def qCurveTo(self, *points):
59 self.value.append(("qCurveTo", points))
61 def curveTo(self, *points):
62 self.value.append(("curveTo", points))
64 def closePath(self):
65 self.value.append(("closePath", ()))
67 def endPath(self):
68 self.value.append(("endPath", ()))
70 def addComponent(self, glyphName, transformation):
71 self.value.append(("addComponent", (glyphName, transformation)))
73 def addVarComponent(self, glyphName, transformation, location):
74 self.value.append(("addVarComponent", (glyphName, transformation, location)))
76 def replay(self, pen):
77 replayRecording(self.value, pen)
80class DecomposingRecordingPen(DecomposingPen, RecordingPen):
81 """Same as RecordingPen, except that it doesn't keep components
82 as references, but draws them decomposed as regular contours.
84 The constructor takes a single 'glyphSet' positional argument,
85 a dictionary of glyph objects (i.e. with a 'draw' method) keyed
86 by thir name::
88 >>> class SimpleGlyph(object):
89 ... def draw(self, pen):
90 ... pen.moveTo((0, 0))
91 ... pen.curveTo((1, 1), (2, 2), (3, 3))
92 ... pen.closePath()
93 >>> class CompositeGlyph(object):
94 ... def draw(self, pen):
95 ... pen.addComponent('a', (1, 0, 0, 1, -1, 1))
96 >>> glyphSet = {'a': SimpleGlyph(), 'b': CompositeGlyph()}
97 >>> for name, glyph in sorted(glyphSet.items()):
98 ... pen = DecomposingRecordingPen(glyphSet)
99 ... glyph.draw(pen)
100 ... print("{}: {}".format(name, pen.value))
101 a: [('moveTo', ((0, 0),)), ('curveTo', ((1, 1), (2, 2), (3, 3))), ('closePath', ())]
102 b: [('moveTo', ((-1, 1),)), ('curveTo', ((0, 2), (1, 3), (2, 4))), ('closePath', ())]
103 """
105 # raises KeyError if base glyph is not found in glyphSet
106 skipMissingComponents = False
109class RecordingPointPen(AbstractPointPen):
110 """PointPen recording operations that can be accessed or replayed.
112 The recording can be accessed as pen.value; or replayed using
113 pointPen.replay(otherPointPen).
115 :Example:
117 from defcon import Font
118 from fontTools.pens.recordingPen import RecordingPointPen
120 glyph_name = 'a'
121 font_path = 'MyFont.ufo'
123 font = Font(font_path)
124 glyph = font[glyph_name]
126 pen = RecordingPointPen()
127 glyph.drawPoints(pen)
128 print(pen.value)
130 new_glyph = font.newGlyph('b')
131 pen.replay(new_glyph.getPointPen())
132 """
134 def __init__(self):
135 self.value = []
137 def beginPath(self, identifier=None, **kwargs):
138 if identifier is not None:
139 kwargs["identifier"] = identifier
140 self.value.append(("beginPath", (), kwargs))
142 def endPath(self):
143 self.value.append(("endPath", (), {}))
145 def addPoint(
146 self, pt, segmentType=None, smooth=False, name=None, identifier=None, **kwargs
147 ):
148 if identifier is not None:
149 kwargs["identifier"] = identifier
150 self.value.append(("addPoint", (pt, segmentType, smooth, name), kwargs))
152 def addComponent(self, baseGlyphName, transformation, identifier=None, **kwargs):
153 if identifier is not None:
154 kwargs["identifier"] = identifier
155 self.value.append(("addComponent", (baseGlyphName, transformation), kwargs))
157 def addVarComponent(
158 self, baseGlyphName, transformation, location, identifier=None, **kwargs
159 ):
160 if identifier is not None:
161 kwargs["identifier"] = identifier
162 self.value.append(
163 ("addVarComponent", (baseGlyphName, transformation, location), kwargs)
164 )
166 def replay(self, pointPen):
167 for operator, args, kwargs in self.value:
168 getattr(pointPen, operator)(*args, **kwargs)
171if __name__ == "__main__":
172 pen = RecordingPen()
173 pen.moveTo((0, 0))
174 pen.lineTo((0, 100))
175 pen.curveTo((50, 75), (60, 50), (50, 25))
176 pen.closePath()
177 from pprint import pprint
179 pprint(pen.value)