-
-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Expand file tree
/
Copy pathtest_type1font.py
More file actions
160 lines (140 loc) · 6.24 KB
/
test_type1font.py
File metadata and controls
160 lines (140 loc) · 6.24 KB
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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
import matplotlib._type1font as t1f
import os.path
import difflib
import pytest
def test_Type1Font():
filename = os.path.join(os.path.dirname(__file__), 'data', 'cmr10.pfb')
font = t1f.Type1Font(filename)
slanted = font.transform({'slant': 1})
condensed = font.transform({'extend': 0.5})
with open(filename, 'rb') as fd:
rawdata = fd.read()
assert font.parts[0] == rawdata[0x0006:0x10c5]
assert font.parts[1] == rawdata[0x10cb:0x897f]
assert font.parts[2] == rawdata[0x8985:0x8ba6]
assert font.decrypted.startswith(b'dup\n/Private 18 dict dup begin')
assert font.decrypted.endswith(b'mark currentfile closefile\n')
assert slanted.decrypted.startswith(b'dup\n/Private 18 dict dup begin')
assert slanted.decrypted.endswith(b'mark currentfile closefile\n')
assert b'UniqueID 5000793' in font.parts[0]
assert b'UniqueID 5000793' in font.decrypted
assert font._pos['UniqueID'] == [(797, 818), (4483, 4504)]
len0 = len(font.parts[0])
for key in font._pos.keys():
for pos0, pos1 in font._pos[key]:
if pos0 < len0:
data = font.parts[0][pos0:pos1]
else:
data = font.decrypted[pos0-len0:pos1-len0]
assert data.startswith(f'/{key}'.encode('ascii'))
assert {'FontType', 'FontMatrix', 'PaintType', 'ItalicAngle', 'RD'
} < set(font._pos.keys())
assert b'UniqueID 5000793' not in slanted.parts[0]
assert b'UniqueID 5000793' not in slanted.decrypted
assert 'UniqueID' not in slanted._pos
assert font.prop['Weight'] == 'Medium'
assert not font.prop['isFixedPitch']
assert font.prop['ItalicAngle'] == 0
assert slanted.prop['ItalicAngle'] == -45
assert font.prop['Encoding'][5] == 'Pi'
assert isinstance(font.prop['CharStrings']['Pi'], bytes)
assert font._abbr['ND'] == 'ND'
differ = difflib.Differ()
diff = list(differ.compare(
font.parts[0].decode('latin-1').splitlines(),
slanted.parts[0].decode('latin-1').splitlines()))
for line in (
# Removes UniqueID
'- /UniqueID 5000793 def',
# Changes the font name
'- /FontName /CMR10 def',
'+ /FontName/CMR10_Slant_1000 def',
# Alters FontMatrix
'- /FontMatrix [0.001 0 0 0.001 0 0 ]readonly def',
'+ /FontMatrix [0.001 0 0.001 0.001 0 0] readonly def',
# Alters ItalicAngle
'- /ItalicAngle 0 def',
'+ /ItalicAngle -45.0 def'):
assert line in diff, 'diff to slanted font must contain %s' % line
diff = list(differ.compare(
font.parts[0].decode('latin-1').splitlines(),
condensed.parts[0].decode('latin-1').splitlines()))
for line in (
# Removes UniqueID
'- /UniqueID 5000793 def',
# Changes the font name
'- /FontName /CMR10 def',
'+ /FontName/CMR10_Extend_500 def',
# Alters FontMatrix
'- /FontMatrix [0.001 0 0 0.001 0 0 ]readonly def',
'+ /FontMatrix [0.0005 0 0 0.001 0 0] readonly def'):
assert line in diff, 'diff to condensed font must contain %s' % line
def test_Type1Font_2():
filename = os.path.join(os.path.dirname(__file__), 'data',
'Courier10PitchBT-Bold.pfb')
font = t1f.Type1Font(filename)
assert font.prop['Weight'] == 'Bold'
assert font.prop['isFixedPitch']
assert font.prop['Encoding'][65] == 'A' # the font uses StandardEncoding
(pos0, pos1), = font._pos['Encoding']
assert font.parts[0][pos0:pos1] == b'/Encoding StandardEncoding'
assert font._abbr['ND'] == '|-'
def test_tokenize():
data = (b'1234/abc false -9.81 Foo <<[0 1 2]<0 1ef a\t>>>\n'
b'(string with(nested\t\\) par)ens\\\\)')
# 1 2 x 2 xx1
# 1 and 2 are matching parens, x means escaped character
n, w, num, kw, d = 'name', 'whitespace', 'number', 'keyword', 'delimiter'
b, s = 'boolean', 'string'
correct = [
(num, 1234), (n, 'abc'), (w, ' '), (b, False), (w, ' '), (num, -9.81),
(w, ' '), (kw, 'Foo'), (w, ' '), (d, '<<'), (d, '['), (num, 0),
(w, ' '), (num, 1), (w, ' '), (num, 2), (d, ']'), (s, b'\x01\xef\xa0'),
(d, '>>'), (w, '\n'), (s, 'string with(nested\t) par)ens\\')
]
correct_no_ws = [x for x in correct if x[0] != w]
def convert(tokens):
return [(t.kind, t.value()) for t in tokens]
assert convert(t1f._tokenize(data, False)) == correct
assert convert(t1f._tokenize(data, True)) == correct_no_ws
def bin_after(n):
tokens = t1f._tokenize(data, True)
result = []
for _ in range(n):
result.append(next(tokens))
result.append(tokens.send(10))
return convert(result)
for n in range(1, len(correct_no_ws)):
result = bin_after(n)
assert result[:-1] == correct_no_ws[:n]
assert result[-1][0] == 'binary'
assert isinstance(result[-1][1], bytes)
def test_tokenize_errors():
with pytest.raises(ValueError):
list(t1f._tokenize(b'1234 (this (string) is unterminated\\)', True))
with pytest.raises(ValueError):
list(t1f._tokenize(b'/Foo<01234', True))
with pytest.raises(ValueError):
list(t1f._tokenize(b'/Foo<01234abcg>/Bar', True))
def test_overprecision():
# We used to output too many digits in FontMatrix entries and
# ItalicAngle, which could make Type-1 parsers unhappy.
filename = os.path.join(os.path.dirname(__file__), 'data', 'cmr10.pfb')
font = t1f.Type1Font(filename)
slanted = font.transform({'slant': .167})
lines = slanted.parts[0].decode('ascii').splitlines()
matrix, = (line[line.index('[')+1:line.index(']')]
for line in lines if '/FontMatrix' in line)
angle, = (word
for line in lines if '/ItalicAngle' in line
for word in line.split() if word[0] in '-0123456789')
# the following used to include 0.00016700000000000002
assert matrix == '0.001 0 0.000167 0.001 0 0'
# and here we had -9.48090361795083
assert angle == '-9.4809'
def test_encrypt_decrypt_roundtrip():
data = b'this is my plaintext \0\1\2\3'
encrypted = t1f.Type1Font._encrypt(data, 'eexec')
decrypted = t1f.Type1Font._decrypt(encrypted, 'eexec')
assert encrypted != decrypted
assert data == decrypted