Skip to content

Commit beb4821

Browse files
committed
Merge pull request matplotlib#628 from mdboom/pdf-usetex-crash
Make PDF backend work when usetex is True
2 parents 24d9101 + 9dd6692 commit beb4821

File tree

4 files changed

+45
-31
lines changed

4 files changed

+45
-31
lines changed

lib/matplotlib/backends/backend_pdf.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1588,7 +1588,7 @@ def draw_tex(self, gc, x, y, s, prop, angle):
15881588
fontsize = prop.get_size_in_points()
15891589
dvifile = texmanager.make_dvi(s, fontsize)
15901590
dvi = dviread.Dvi(dvifile, 72)
1591-
page = next(iter(dvi))
1591+
page = iter(dvi).next()
15921592
dvi.close()
15931593

15941594
# Gather font information and do some setup for combining

lib/matplotlib/dviread.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,8 @@ class DviFont(object):
424424
__slots__ = ('texname', 'size', 'widths', '_scale', '_vf', '_tfm')
425425

426426
def __init__(self, scale, tfm, texname, vf):
427+
if sys.version_info[0] >= 3 and isinstance(texname, bytes):
428+
texname = texname.decode('ascii')
427429
self._scale, self._tfm, self.texname, self._vf = \
428430
scale, tfm, texname, vf
429431
self.size = scale * (72.0 / (72.27 * 2**16))
@@ -678,7 +680,10 @@ def __init__(self, filename):
678680
self._parse(file)
679681

680682
def __getitem__(self, texname):
681-
result = self._font[texname]
683+
try:
684+
result = self._font[texname]
685+
except KeyError:
686+
result = self._font[texname.decode('ascii')]
682687
fn, enc = result.filename, result.encoding
683688
if fn is not None and not fn.startswith('/'):
684689
result.filename = find_tex_file(fn)

lib/matplotlib/font_manager.py

+2
Original file line numberDiff line numberDiff line change
@@ -1033,6 +1033,8 @@ def score_family(self, families, family2):
10331033
10341034
No match will return 1.0.
10351035
"""
1036+
if not isinstance(families, (list, tuple)):
1037+
families = [families]
10361038
family2 = family2.lower()
10371039
for i, family1 in enumerate(families):
10381040
family1 = family1.lower()

lib/matplotlib/type1font.py

+36-29
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@
2929
import numpy as np
3030
import re
3131
import struct
32+
import sys
33+
34+
if sys.version_info[0] >= 3:
35+
def ord(x):
36+
return x
3237

3338
class Type1Font(object):
3439
"""
@@ -64,12 +69,12 @@ def _read(self, file):
6469
Read the font from a file, decoding into usable parts.
6570
"""
6671
rawdata = file.read()
67-
if not rawdata.startswith(chr(128)):
72+
if not rawdata.startswith(b'\x80'):
6873
return rawdata
6974

70-
data = ''
75+
data = b''
7176
while len(rawdata) > 0:
72-
if not rawdata.startswith(chr(128)):
77+
if not rawdata.startswith(b'\x80'):
7378
raise RuntimeError('Broken pfb file (expected byte 128, got %d)' % \
7479
ord(rawdata[0]))
7580
type = ord(rawdata[1])
@@ -81,8 +86,8 @@ def _read(self, file):
8186
if type == 1: # ASCII text: include verbatim
8287
data += segment
8388
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])
8691
elif type == 3: # end of file
8792
break
8893
else:
@@ -101,18 +106,19 @@ def _split(self, data):
101106
"""
102107

103108
# 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':
107112
idx += 1
108113
len1 = idx
109114

110115
# Encrypted part: find the cleartomark operator and count
111116
# zeros backward
112-
idx = data.rindex('cleartomark') - 1
117+
idx = data.rindex(b'cleartomark') - 1
113118
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]):
116122
zeros -= 1
117123
idx -= 1
118124
if zeros:
@@ -123,15 +129,15 @@ def _split(self, data):
123129
# but if we read a pfa file, this part is already in hex, and
124130
# I am not quite sure if even the pfb format guarantees that
125131
# 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)])
128134

129135
return data[:len1], binary, data[idx:]
130136

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'[()\\]')
135141
@classmethod
136142
def _tokens(cls, text):
137143
"""
@@ -191,22 +197,22 @@ def _parse(self):
191197
tokenizer = self._tokens(self.parts[0])
192198
filtered = itertools.ifilter(lambda x: x[0] != 'whitespace', tokenizer)
193199
for token, value in filtered:
194-
if token == 'name' and value.startswith('/'):
200+
if token == b'name' and value.startswith(b'/'):
195201
key = value[1:]
196202
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'
200206
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)
206212
else: value = int(value)
207213
else: # more complicated value such as an array
208214
value = None
209-
if key != 'FontInfo' and value is not None:
215+
if key != b'FontInfo' and value is not None:
210216
prop[key] = value
211217

212218
# Fill in the various *Name properties
@@ -291,13 +297,14 @@ def transform(self, effects):
291297
multiplier by which the font is to be extended (so values less
292298
than 1.0 condense). Returns a new :class:`Type1Font` object.
293299
"""
294-
295-
buffer = io.StringIO()
300+
buffer = io.BytesIO()
296301
try:
297302
tokenizer = self._tokens(self.parts[0])
298303
for value in self._transformer(tokenizer,
299304
slant=effects.get('slant', 0.0),
300305
extend=effects.get('extend', 1.0)):
306+
if sys.version_info[0] >= 3 and isinstance(value, int):
307+
value = chr(value).encode('latin-1')
301308
buffer.write(value)
302309
result = buffer.getvalue()
303310
finally:

0 commit comments

Comments
 (0)