Skip to content

Commit a349634

Browse files
committed
Outline fixes
Adds a to_points_and_codes method Fixes scaling of other outline decomposition methods
1 parent 7d0d31a commit a349634

File tree

6 files changed

+513
-66
lines changed

6 files changed

+513
-66
lines changed

doc/source/api.rst

+1
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ Outline
8080
Outline
8181
OUTLINE
8282
ORIENTATION
83+
CODES
8384

8485
CharMap
8586
-------

docstrings/outline.py

+48
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,21 @@
7979
>>> a = np.asarray(outline.contours)
8080
"""
8181

82+
Outline_decomposed_points = """
83+
A `memoryview` of decomposed points in the outline. Each entry is an
84+
(x, y) pair.
85+
"""
86+
87+
Outline_codes = """
88+
A `memoryview` of codes for the decomposed points in the outline.
89+
Each entry is one of:
90+
91+
- 1: MOVETO (1 point)
92+
- 2: LINETO (1 point)
93+
- 3: CONIC (2 points)
94+
- 4: CUBIC (3 points)
95+
"""
96+
8297
Outline_flags = """
8398
A set of `OUTLINE` flags used to characterize the outline. Gives
8499
hints to the scan-converter and hinter on how to convert/grid-fit it.
@@ -265,6 +280,23 @@ def cubic_to(self, a, b, c):
265280
what it is doing.
266281
"""
267282

283+
Outline_to_points_and_codes = """
284+
|freetypy| Convert the outline to a pair of arrays (points, codes).
285+
286+
- points is an Nx2 array of floats for each point
287+
- codes in a length N array of `CODES` constants:
288+
289+
- 0: `MOVETO` (1 point)
290+
- 1: `LINETO` (1 point)
291+
- 2: `CUBIC` (2 points)
292+
- 3: `CONIC` (3 points)
293+
294+
Returns
295+
-------
296+
arrays : tuple
297+
A (points, codes) pair
298+
"""
299+
268300
Outline_to_string = """
269301
|freetypy| Convert the outline to a text format string of commands.
270302
This function is flexible enough to create path commands for PDF,
@@ -286,6 +318,13 @@ def cubic_to(self, a, b, c):
286318
one is not provided, conic curves will be implicitly converted to
287319
cubic curves.
288320
321+
relative : bool, optional
322+
323+
324+
prefix : bool, optional
325+
If `True`, the command will appear before the points it refers to.
326+
Otherwise, the default is for them to appear after.
327+
289328
Returns
290329
-------
291330
string : bytes
@@ -403,3 +442,12 @@ def cubic_to(self, a, b, c):
403442
- `NONE`: The orientation cannot be determined. That is, different
404443
parts of the glyph have different orientation.
405444
"""
445+
446+
CODES = """
447+
Codes returned by `Outline.to_points_and_codes`:
448+
449+
- 1: `MOVETO` (1 point)
450+
- 2: `LINETO` (1 point)
451+
- 3: `CONIC` (2 points)
452+
- 4: `CUBIC` (3 points)
453+
"""

lib/freetypy/tests/test_numpy.py

+37
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
else:
4545
HAS_NUMPY = True
4646

47+
from numpy.testing import assert_array_equal
48+
4749

4850
@skip_if(not HAS_NUMPY)
4951
def test_glyph():
@@ -144,3 +146,38 @@ def test_outline():
144146
contours = np.array(glyph.outline.contours)
145147
assert contours.shape == (2,)
146148
assert list(contours) == [2, 10]
149+
150+
151+
@skip_if(not HAS_NUMPY)
152+
def test_outline_to_points_and_codes():
153+
face = ft.Face(vera_path())
154+
face.set_charmap(0)
155+
face.set_char_size(12, 12, 300, 300)
156+
glyph = face.load_char(ord('B'))
157+
158+
points, codes = glyph.outline.to_points_and_codes()
159+
points = np.array(points)
160+
codes = np.array(codes)
161+
162+
assert_array_equal(
163+
points,
164+
[[10.0, 17.0], [10.0, 4.0], [17.65625, 4.0], [21.90625, 4.0],
165+
[23.953125, 5.59375], [26.0, 7.203125], [26.0, 10.515625],
166+
[26.0, 13.84375], [23.953125, 15.421875], [21.90625, 17.0],
167+
[17.65625, 17.0], [10.0, 17.0], [10.0, 32.0], [10.0, 21.0],
168+
[17.078125, 21.0], [20.578125, 21.0], [22.28125, 22.359375],
169+
[24.0, 23.71875], [24.0, 26.5], [24.0, 29.265625], [22.28125,
170+
30.625], [20.578125, 32.0], [17.078125, 32.0], [10.0, 32.0],
171+
[5.0, 36.0], [17.421875, 36.0], [22.984375, 36.0], [25.984375,
172+
33.65625], [29.0, 31.328125], [29.0, 27.015625], [29.0,
173+
23.6875], [27.4375, 21.703125], [25.875, 19.734375],
174+
[22.84375, 19.25], [26.71875, 18.484375], [28.859375,
175+
16.046875], [31.0, 13.625], [31.0, 10.0], [31.0, 5.21875],
176+
[27.59375, 2.609375], [24.1875, 0.0], [17.90625, 0.0], [5.0,
177+
0.0], [5.0, 36.0]])
178+
179+
assert_array_equal(
180+
codes,
181+
[1, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 2, 2, 3, 3, 3, 3, 3,
182+
3, 3, 3, 2, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
183+
3, 3, 2, 2])

lib/freetypy/tests/test_outline.py

+49-29
Original file line numberDiff line numberDiff line change
@@ -81,33 +81,53 @@ def cubic_to(self, a, b, c):
8181

8282
glyph.outline.decompose(d)
8383

84+
print(d.entries)
85+
8486
assert d.entries == [
85-
('move_to', (640.0, 1088.0)),
86-
('line_to', (640.0, 256.0)),
87-
('line_to', (1130.0, 256.0)),
88-
('conic_to', (1402.0, 256.0), (1533.0, 358.0)),
89-
('conic_to', (1664.0, 461.0), (1664.0, 673.0)),
90-
('conic_to', (1664.0, 886.0), (1533.0, 987.0)),
91-
('conic_to', (1402.0, 1088.0), (1130.0, 1088.0)),
92-
('line_to', (640.0, 1088.0)),
93-
('move_to', (640.0, 2048.0)),
94-
('line_to', (640.0, 1344.0)),
95-
('line_to',(1093.0, 1344.0)),
96-
('conic_to', (1317.0, 1344.0), (1426.0, 1431.0)),
97-
('conic_to', (1536.0, 1518.0), (1536.0, 1696.0)),
98-
('conic_to', (1536.0, 1873.0), (1426.0, 1960.0)),
99-
('conic_to', (1317.0, 2048.0), (1093.0, 2048.0)),
100-
('line_to', (640.0, 2048.0)),
101-
('move_to', (320.0, 2304.0)),
102-
('line_to', (1115.0, 2304.0)),
103-
('conic_to', (1471.0, 2304.0), (1663.0, 2154.0)),
104-
('conic_to', (1856.0, 2005.0), (1856.0, 1729.0)),
105-
('conic_to', (1856.0, 1516.0), (1756.0, 1389.0)),
106-
('conic_to', (1656.0, 1263.0), (1462.0, 1232.0)),
107-
('conic_to', (1710.0, 1183.0), (1847.0, 1027.0)),
108-
('conic_to', (1984.0, 872.0), (1984.0, 640.0)),
109-
('conic_to', (1984.0, 334.0), (1766.0, 167.0)),
110-
('conic_to', (1548.0, 0.0), (1146.0, 0.0)),
111-
('line_to', (320.0, 0.0)),
112-
('line_to', (320.0, 2304.0))
113-
]
87+
('move_to', (10.0, 17.0)),
88+
('line_to', (10.0, 4.0)),
89+
('line_to', (17.65625, 4.0)),
90+
('conic_to', (21.90625, 4.0), (23.953125, 5.59375)),
91+
('conic_to', (26.0, 7.203125), (26.0, 10.515625)),
92+
('conic_to', (26.0, 13.84375), (23.953125, 15.421875)),
93+
('conic_to', (21.90625, 17.0), (17.65625, 17.0)),
94+
('line_to', (10.0, 17.0)),
95+
('move_to', (10.0, 32.0)),
96+
('line_to', (10.0, 21.0)),
97+
('line_to', (17.078125, 21.0)),
98+
('conic_to', (20.578125, 21.0), (22.28125, 22.359375)),
99+
('conic_to', (24.0, 23.71875), (24.0, 26.5)),
100+
('conic_to', (24.0, 29.265625), (22.28125, 30.625)),
101+
('conic_to', (20.578125, 32.0), (17.078125, 32.0)),
102+
('line_to', (10.0, 32.0)),
103+
('move_to', (5.0, 36.0)),
104+
('line_to', (17.421875, 36.0)),
105+
('conic_to', (22.984375, 36.0), (25.984375, 33.65625)),
106+
('conic_to', (29.0, 31.328125), (29.0, 27.015625)),
107+
('conic_to', (29.0, 23.6875), (27.4375, 21.703125)),
108+
('conic_to', (25.875, 19.734375), (22.84375, 19.25)),
109+
('conic_to', (26.71875, 18.484375), (28.859375, 16.046875)),
110+
('conic_to', (31.0, 13.625), (31.0, 10.0)),
111+
('conic_to', (31.0, 5.21875), (27.59375, 2.609375)),
112+
('conic_to', (24.1875, 0.0), (17.90625, 0.0)),
113+
('line_to', (5.0, 0.0)),
114+
('line_to', (5.0, 36.0))
115+
]
116+
117+
def test_outline_to_string():
118+
face = ft.Face(vera_path())
119+
face.set_charmap(0)
120+
face.set_char_size(12, 12, 300, 300)
121+
glyph = face.load_char(ord('B'))
122+
123+
s = glyph.outline.to_string(' M ', ' L ', ' C ', ' Q ')
124+
125+
print(s)
126+
127+
assert s == b'10 17 M 10 4 L 17.65625 4 L 21.90625 4 23.953125 5.59375 Q 26 7.203125 26 10.515625 Q 26 13.84375 23.953125 15.421875 Q 21.90625 17 17.65625 17 Q 10 17 L 10 32 M 10 21 L 17.078125 21 L 20.578125 21 22.28125 22.359375 Q 24 23.71875 24 26.5 Q 24 29.265625 22.28125 30.625 Q 20.578125 32 17.078125 32 Q 10 32 L 5 36 M 17.421875 36 L 22.984375 36 25.984375 33.65625 Q 29 31.328125 29 27.015625 Q 29 23.6875 27.4375 21.703125 Q 25.875 19.734375 22.84375 19.25 Q 26.71875 18.484375 28.859375 16.046875 Q 31 13.625 31 10 Q 31 5.21875 27.59375 2.609375 Q 24.1875 0 17.90625 0 Q 5 0 L 5 36 L '
128+
129+
s = glyph.outline.to_string(' M ', ' L ', ' C ', ' Q ', prefix=True)
130+
131+
print(s)
132+
133+
assert s == b' M 10 17 L 10 4 L 17.65625 4 Q 21.90625 4 23.953125 5.59375 Q 26 7.203125 26 10.515625 Q 26 13.84375 23.953125 15.421875 Q 21.90625 17 17.65625 17 L 10 17 M 10 32 L 10 21 L 17.078125 21 Q 20.578125 21 22.28125 22.359375 Q 24 23.71875 24 26.5 Q 24 29.265625 22.28125 30.625 Q 20.578125 32 17.078125 32 L 10 32 M 5 36 L 17.421875 36 Q 22.984375 36 25.984375 33.65625 Q 29 31.328125 29 27.015625 Q 29 23.6875 27.4375 21.703125 Q 25.875 19.734375 22.84375 19.25 Q 26.71875 18.484375 28.859375 16.046875 Q 31 13.625 31 10 Q 31 5.21875 27.59375 2.609375 Q 24.1875 0 17.90625 0 L 5 0 L 5 36'

0 commit comments

Comments
 (0)