-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbitmapPen.py
120 lines (99 loc) · 3.97 KB
/
bitmapPen.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
from fontTools.pens.basePen import BasePen
import numpy as np
class BitmapPen(BasePen):
"""This class draws a bitmap to a numpy array using horizontal scanlines"""
def __init__(self, glyphSet, xmin, ymin, xmax, ymax, width, height):
super().__init__(glyphSet)
self.offset = np.array([xmin,ymin])
self.size = np.array([xmax+1,ymax+1])-self.offset
self.resetBitmap(width, height)
def resetBitmap(self, width, height):
self.bitmap = np.zeros((height, width), dtype=np.uint8)
def getBitmap(self):
return np.where(self.bitmap != 0, 255, 0).astype(np.uint8)
def _moveTo(self, pt):
pass
def _lineTo(self, pt):
x1, y1 = self._transform(self._getCurrentPoint())
x2, y2 = self._transform(pt)
# Ignore horizontal lines
if y1 == y2:
return
m = (x2-x1)/(y2-y1)
c = x1 - m*y1
goingUp = y2 > y1
start = (int(y1) if goingUp else int(y2))+1
stop = (int(y2) if goingUp else int(y1))+1
for y in range(start,stop):
x = int(round(m*y + c))
self.bitmap[y,x:] += 1 if goingUp else -1
def _curveToOne(self, pt1, pt2, pt3):
x1, y1 = self._transform(self._getCurrentPoint())
x2, y2 = self._transform(pt1)
x3, y3 = self._transform(pt2)
x4, y4 = self._transform(pt3)
start = int(min([y1,y2,y3,y4]))+1
stop = int(max([y1,y2,y3,y4]))+1
dy = y1
cy = (y2 - dy) * 3.0
by = (y3 - y2) * 3.0 - cy
ay = y4 - dy - cy - by
dx = x1
cx = (x2 - dx) * 3.0
bx = (x3 - x2) * 3.0 - cx
ax = x4 - dx - cx - bx
for y in range(start,stop):
roots = np.roots([ay,by,cy,dy-y])
roots = roots[np.isreal(roots)]
roots = roots[np.logical_and(-1e-10 <= roots, roots <= 1+1e-10)]
roots = np.sort(roots)
if not len(roots):
continue
lastT = None
for t in roots:
if t==lastT:
continue
lastT = t
t2 = t * t
t3 = t2 * t
direction = 3*ay*t2 + 2*by*t + cy
if direction == 0.0:
direction = 6*ay*t + 2*by
if direction == 0.0:
direction = ay
if direction == 0.0:
# Ignore horizontal lines
continue
else:
# We have a turning point. Ignore it
continue
goingUp = direction > 0.0
xt = int(round(ax*t3 + bx*t2 + cx*t + dx))
delta = 0
# Double check against endpoints incase rounding errors have
# given false positives (extremely unlikely but possible).
if t <= 0.0 and y == y1 and not goingUp:
delta = -1
elif t >= 1.0 and y == y4 and goingUp:
delta = 1
elif 0.0 < t < 1.0:
delta = 1 if goingUp else -1
else:
continue
self.bitmap[y,xt:] += delta
def _transform(self, pt):
bmpSize = self.bitmap.shape
return ((pt[0]-self.offset[0])*bmpSize[1]/self.size[0], (pt[1]-self.offset[1])*bmpSize[0]/self.size[1])
def addComponent(self, glyphName, transformation):
"""This default implementation simply transforms the points
of the base glyph and draws it onto self.
"""
from fontTools.pens.transformPen import TransformPen
try:
glyph = self.glyphSet[glyphName]
except KeyError:
pass
else:
tPen = TransformPen(self, transformation)
#Monkey patched to add second argument
glyph.draw(tPen, self.glyphSet)