-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathglyph.py
135 lines (116 loc) · 4.39 KB
/
glyph.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
from fontTools.pens.basePen import BasePen
from robofab.objects.objectsRF import RFont, RGlyph
from drawBot import *
class DrawBotPen(BasePen):
"""
A pen that draws a glyph into a drawbot.
I don't think this can deal with components or anything so be careful.
"""
def _moveTo(self, coordinate):
moveTo(coordinate)
def _lineTo(self, coordinate):
lineTo(coordinate)
def _curveToOne(self, coordinate1, coordinate2, coordinate3):
curveTo(coordinate1, coordinate2, coordinate3)
def closePath(self):
closePath()
def drawGlyph(glyph):
"""
Mimics the in-RoboFont drawbot, but using DrawBotPen.
"""
newPath()
pen = DrawBotPen(glyph.getParent())
glyph.draw(pen)
drawPath()
def _getKernGroups(groups):
leftKernGroups = {}
rightKernGroups = {}
leftKernNames = ['@public.kern1', '@MMK_L_']
rightKernNames = ['@public.kern2', '@MMK_R_']
for groupName, groupGlyphs in groups.items():
for name in leftKernNames:
if name in groupName:
leftKernGroups[groupName] = groupGlyphs
for name in rightKernNames:
if name in groupName:
rightKernGroups[groupName] = groupGlyphs
return leftKernGroups, rightKernGroups
def _getGlyphNamesFromTextString(textString, f, showMissing='.notdef'):
gnames = []
m = f.getCharacterMapping()
for char in textString:
gname = m.get(ord(char))
if gname:
gnames.append(gname[0])
elif showMissing:
if f.has_key(showMissing):
gnames.append(showMissing)
return gnames
def ufoText(textString, pos, font, fontSize, showMissing='.notdef', kerning=True, draw=True):
"""
A function that uses drawGlyph() to draw a string from a robofab object.
It acts like DrawBot's text() function, but you pass the font and fontSize directly.
It does not handle any advanced text layout or features. For that you
should generate a font and use compositor.
ufoText(u'Your text here.', (0, 0), font=f, fontSize=50, kerning=False)
"""
# get glyph names
gnames = _getGlyphNamesFromTextString(textString, font, showMissing)
# before we begin, get kerning
# there is probably a better way to do this
# but for now we will explode kerning once so we don't ahve to
if kerning:
explodedKerning = font.kerning.copy()
explodedKerning.explodeClasses(*_getKernGroups(font.groups))
save()
# move to the position
if draw: translate(*pos)
save()
# drawGlyph draws at 1 pt = 1 font unit.
scaleFactor = fontSize / font.info.unitsPerEm
if draw: scale(scaleFactor)
totalWidth = 0
# loop through glyphs and draw them
previousGname = None
for gname in gnames:
if kerning:
kern = explodedKerning.get((previousGname, gname)) or 0
translate(kern, 0)
totalWidth += kern
if draw: drawGlyph(font[gname])
if draw: translate(font[gname].width, 0)
totalWidth += font[gname].width
previousGname = gname
restore()
restore()
return totalWidth, fontSize
def ufoTextSize(textString, font, fontSize, kerning=True):
"""
Just like textSize, but using a UFO.
This is pretty dang inefficient, but such is life!
"""
return ufoText(textString, font, fontSize, draw=False)
### BY JUST ####
import AppKit
_methodMap = {
AppKit.NSMoveToBezierPathElement: "moveTo",
AppKit.NSLineToBezierPathElement: "lineTo",
AppKit.NSCurveToBezierPathElement: "curveTo",
AppKit.NSClosePathBezierPathElement: "closePath",
}
def drawPathToPen(path, pen):
didClosePath = True
for i in range(path._path.elementCount()):
instr, pts = path._path.elementAtIndex_associatedPoints_(i)
methodName = _methodMap[instr]
if methodName == "moveTo":
if not didClosePath:
# Previous contour was open, we should call pen.endPath()
pen.endPath()
didClosePath = False
elif methodName == "closePath":
didClosePath = True
getattr(pen, methodName)(*pts)
if not didClosePath:
# The final subpath is open, we must still call endPath()
pen.endPath()