29
29
import numpy as np
30
30
import re
31
31
import struct
32
+ import sys
33
+
34
+ if sys .version_info [0 ] >= 3 :
35
+ def ord (x ):
36
+ return x
32
37
33
38
class Type1Font (object ):
34
39
"""
@@ -64,12 +69,12 @@ def _read(self, file):
64
69
Read the font from a file, decoding into usable parts.
65
70
"""
66
71
rawdata = file .read ()
67
- if not rawdata .startswith (chr ( 128 ) ):
72
+ if not rawdata .startswith (b' \x80 ' ):
68
73
return rawdata
69
74
70
- data = ''
75
+ data = b ''
71
76
while len (rawdata ) > 0 :
72
- if not rawdata .startswith (chr ( 128 ) ):
77
+ if not rawdata .startswith (b' \x80 ' ):
73
78
raise RuntimeError ('Broken pfb file (expected byte 128, got %d)' % \
74
79
ord (rawdata [0 ]))
75
80
type = ord (rawdata [1 ])
@@ -81,8 +86,8 @@ def _read(self, file):
81
86
if type == 1 : # ASCII text: include verbatim
82
87
data += segment
83
88
elif type == 2 : # binary data: encode in hexadecimal
84
- data += '' .join (['%02x' % ord (char )
85
- for char in segment ])
89
+ data += b '' .join ([( '%02x' % ord (char )). encode ( 'ascii' )
90
+ for char in segment ])
86
91
elif type == 3 : # end of file
87
92
break
88
93
else :
@@ -101,18 +106,19 @@ def _split(self, data):
101
106
"""
102
107
103
108
# Cleartext part: just find the eexec and skip whitespace
104
- idx = data .index ('eexec' )
105
- idx += len ('eexec' )
106
- while data [idx ] in ' \t \r \n ' :
109
+ idx = data .index (b 'eexec' )
110
+ idx += len (b 'eexec' )
111
+ while data [idx ] in b ' \t \r \n ' :
107
112
idx += 1
108
113
len1 = idx
109
114
110
115
# Encrypted part: find the cleartomark operator and count
111
116
# zeros backward
112
- idx = data .rindex ('cleartomark' ) - 1
117
+ idx = data .rindex (b 'cleartomark' ) - 1
113
118
zeros = 512
114
- while zeros and data [idx ] in ('0' , '\n ' , '\r ' ):
115
- if data [idx ] == '0' :
119
+ while zeros and ord (data [idx ]) in (
120
+ ord (b'0' [0 ]), ord (b'\n ' [0 ]), ord (b'\r ' [0 ])):
121
+ if ord (data [idx ]) == ord (b'0' [0 ]):
116
122
zeros -= 1
117
123
idx -= 1
118
124
if zeros :
@@ -123,15 +129,15 @@ def _split(self, data):
123
129
# but if we read a pfa file, this part is already in hex, and
124
130
# I am not quite sure if even the pfb format guarantees that
125
131
# it will be in binary).
126
- binary = '' .join ([chr (int (data [i :i + 2 ], 16 ))
127
- for i in range (len1 , idx , 2 )])
132
+ binary = b '' .join ([unichr (int (data [i :i + 2 ], 16 )). encode ( 'latin-1' )
133
+ for i in range (len1 , idx , 2 )])
128
134
129
135
return data [:len1 ], binary , data [idx :]
130
136
131
- _whitespace = re .compile (r '[\0\t\r\014\n ]+' )
132
- _token = re .compile (r '/{0,2}[^]\0\t\r\v\n ()<>{}/%[]+' )
133
- _comment = re .compile (r '%[^\r\n\v]*' )
134
- _instring = re .compile (r '[()\\]' )
137
+ _whitespace = re .compile (br '[\0\t\r\014\n ]+' )
138
+ _token = re .compile (br '/{0,2}[^]\0\t\r\v\n ()<>{}/%[]+' )
139
+ _comment = re .compile (br '%[^\r\n\v]*' )
140
+ _instring = re .compile (br '[()\\]' )
135
141
@classmethod
136
142
def _tokens (cls , text ):
137
143
"""
@@ -191,22 +197,22 @@ def _parse(self):
191
197
tokenizer = self ._tokens (self .parts [0 ])
192
198
filtered = itertools .ifilter (lambda x : x [0 ] != 'whitespace' , tokenizer )
193
199
for token , value in filtered :
194
- if token == 'name' and value .startswith ('/' ):
200
+ if token == b 'name' and value .startswith (b '/' ):
195
201
key = value [1 :]
196
202
token , value = next (filtered )
197
- if token == 'name' :
198
- if value in ('true' , 'false' ):
199
- value = value == 'true'
203
+ if token == b 'name' :
204
+ if value in (b 'true' , b 'false' ):
205
+ value = value == b 'true'
200
206
else :
201
- value = value .lstrip ('/' )
202
- elif token == 'string' :
203
- value = value .lstrip ('(' ).rstrip (')' )
204
- elif token == 'number' :
205
- if '.' in value : value = float (value )
207
+ value = value .lstrip (b '/' )
208
+ elif token == b 'string' :
209
+ value = value .lstrip (b '(' ).rstrip (b ')' )
210
+ elif token == b 'number' :
211
+ if b '.' in value : value = float (value )
206
212
else : value = int (value )
207
213
else : # more complicated value such as an array
208
214
value = None
209
- if key != 'FontInfo' and value is not None :
215
+ if key != b 'FontInfo' and value is not None :
210
216
prop [key ] = value
211
217
212
218
# Fill in the various *Name properties
@@ -291,13 +297,14 @@ def transform(self, effects):
291
297
multiplier by which the font is to be extended (so values less
292
298
than 1.0 condense). Returns a new :class:`Type1Font` object.
293
299
"""
294
-
295
- buffer = io .StringIO ()
300
+ buffer = io .BytesIO ()
296
301
try :
297
302
tokenizer = self ._tokens (self .parts [0 ])
298
303
for value in self ._transformer (tokenizer ,
299
304
slant = effects .get ('slant' , 0.0 ),
300
305
extend = effects .get ('extend' , 1.0 )):
306
+ if sys .version_info [0 ] >= 3 and isinstance (value , int ):
307
+ value = chr (value ).encode ('latin-1' )
301
308
buffer .write (value )
302
309
result = buffer .getvalue ()
303
310
finally :
0 commit comments