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

1"""Pen recording operations that can be accessed or replayed.""" 

2from fontTools.pens.basePen import AbstractPen, DecomposingPen 

3from fontTools.pens.pointPen import AbstractPointPen 

4 

5 

6__all__ = [ 

7 "replayRecording", 

8 "RecordingPen", 

9 "DecomposingRecordingPen", 

10 "RecordingPointPen", 

11] 

12 

13 

14def replayRecording(recording, pen): 

15 """Replay a recording, as produced by RecordingPen or DecomposingRecordingPen, 

16 to a pen. 

17 

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) 

24 

25 

26class RecordingPen(AbstractPen): 

27 """Pen recording operations that can be accessed or replayed. 

28 

29 The recording can be accessed as pen.value; or replayed using 

30 pen.replay(otherPen). 

31 

32 :Example: 

33 

34 from fontTools.ttLib import TTFont 

35 from fontTools.pens.recordingPen import RecordingPen 

36 

37 glyph_name = 'dollar' 

38 font_path = 'MyFont.otf' 

39 

40 font = TTFont(font_path) 

41 glyphset = font.getGlyphSet() 

42 glyph = glyphset[glyph_name] 

43 

44 pen = RecordingPen() 

45 glyph.draw(pen) 

46 print(pen.value) 

47 """ 

48 

49 def __init__(self): 

50 self.value = [] 

51 

52 def moveTo(self, p0): 

53 self.value.append(("moveTo", (p0,))) 

54 

55 def lineTo(self, p1): 

56 self.value.append(("lineTo", (p1,))) 

57 

58 def qCurveTo(self, *points): 

59 self.value.append(("qCurveTo", points)) 

60 

61 def curveTo(self, *points): 

62 self.value.append(("curveTo", points)) 

63 

64 def closePath(self): 

65 self.value.append(("closePath", ())) 

66 

67 def endPath(self): 

68 self.value.append(("endPath", ())) 

69 

70 def addComponent(self, glyphName, transformation): 

71 self.value.append(("addComponent", (glyphName, transformation))) 

72 

73 def addVarComponent(self, glyphName, transformation, location): 

74 self.value.append(("addVarComponent", (glyphName, transformation, location))) 

75 

76 def replay(self, pen): 

77 replayRecording(self.value, pen) 

78 

79 

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. 

83 

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:: 

87 

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 """ 

104 

105 # raises KeyError if base glyph is not found in glyphSet 

106 skipMissingComponents = False 

107 

108 

109class RecordingPointPen(AbstractPointPen): 

110 """PointPen recording operations that can be accessed or replayed. 

111 

112 The recording can be accessed as pen.value; or replayed using 

113 pointPen.replay(otherPointPen). 

114 

115 :Example: 

116 

117 from defcon import Font 

118 from fontTools.pens.recordingPen import RecordingPointPen 

119 

120 glyph_name = 'a' 

121 font_path = 'MyFont.ufo' 

122 

123 font = Font(font_path) 

124 glyph = font[glyph_name] 

125 

126 pen = RecordingPointPen() 

127 glyph.drawPoints(pen) 

128 print(pen.value) 

129 

130 new_glyph = font.newGlyph('b') 

131 pen.replay(new_glyph.getPointPen()) 

132 """ 

133 

134 def __init__(self): 

135 self.value = [] 

136 

137 def beginPath(self, identifier=None, **kwargs): 

138 if identifier is not None: 

139 kwargs["identifier"] = identifier 

140 self.value.append(("beginPath", (), kwargs)) 

141 

142 def endPath(self): 

143 self.value.append(("endPath", (), {})) 

144 

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)) 

151 

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)) 

156 

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 ) 

165 

166 def replay(self, pointPen): 

167 for operator, args, kwargs in self.value: 

168 getattr(pointPen, operator)(*args, **kwargs) 

169 

170 

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 

178 

179 pprint(pen.value)