Skip to content

Commit

Permalink
Merge pull request matplotlib#628 from mdboom/pdf-usetex-crash
Browse files Browse the repository at this point in the history
Make PDF backend work when usetex is True
  • Loading branch information
mdboom committed Jan 5, 2012
2 parents 24d9101 + 9dd6692 commit beb4821
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 31 deletions.
2 changes: 1 addition & 1 deletion lib/matplotlib/backends/backend_pdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -1588,7 +1588,7 @@ def draw_tex(self, gc, x, y, s, prop, angle):
fontsize = prop.get_size_in_points()
dvifile = texmanager.make_dvi(s, fontsize)
dvi = dviread.Dvi(dvifile, 72)
page = next(iter(dvi))
page = iter(dvi).next()
dvi.close()

# Gather font information and do some setup for combining
Expand Down
7 changes: 6 additions & 1 deletion lib/matplotlib/dviread.py
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,8 @@ class DviFont(object):
__slots__ = ('texname', 'size', 'widths', '_scale', '_vf', '_tfm')

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

def __getitem__(self, texname):
result = self._font[texname]
try:
result = self._font[texname]
except KeyError:
result = self._font[texname.decode('ascii')]
fn, enc = result.filename, result.encoding
if fn is not None and not fn.startswith('/'):
result.filename = find_tex_file(fn)
Expand Down
2 changes: 2 additions & 0 deletions lib/matplotlib/font_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -1033,6 +1033,8 @@ def score_family(self, families, family2):
No match will return 1.0.
"""
if not isinstance(families, (list, tuple)):
families = [families]
family2 = family2.lower()
for i, family1 in enumerate(families):
family1 = family1.lower()
Expand Down
65 changes: 36 additions & 29 deletions lib/matplotlib/type1font.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@
import numpy as np
import re
import struct
import sys

if sys.version_info[0] >= 3:
def ord(x):
return x

class Type1Font(object):
"""
Expand Down Expand Up @@ -64,12 +69,12 @@ def _read(self, file):
Read the font from a file, decoding into usable parts.
"""
rawdata = file.read()
if not rawdata.startswith(chr(128)):
if not rawdata.startswith(b'\x80'):
return rawdata

data = ''
data = b''
while len(rawdata) > 0:
if not rawdata.startswith(chr(128)):
if not rawdata.startswith(b'\x80'):
raise RuntimeError('Broken pfb file (expected byte 128, got %d)' % \
ord(rawdata[0]))
type = ord(rawdata[1])
Expand All @@ -81,8 +86,8 @@ def _read(self, file):
if type == 1: # ASCII text: include verbatim
data += segment
elif type == 2: # binary data: encode in hexadecimal
data += ''.join(['%02x' % ord(char)
for char in segment])
data += b''.join([('%02x' % ord(char)).encode('ascii')
for char in segment])
elif type == 3: # end of file
break
else:
Expand All @@ -101,18 +106,19 @@ def _split(self, data):
"""

# Cleartext part: just find the eexec and skip whitespace
idx = data.index('eexec')
idx += len('eexec')
while data[idx] in ' \t\r\n':
idx = data.index(b'eexec')
idx += len(b'eexec')
while data[idx] in b' \t\r\n':
idx += 1
len1 = idx

# Encrypted part: find the cleartomark operator and count
# zeros backward
idx = data.rindex('cleartomark') - 1
idx = data.rindex(b'cleartomark') - 1
zeros = 512
while zeros and data[idx] in ('0', '\n', '\r'):
if data[idx] == '0':
while zeros and ord(data[idx]) in (
ord(b'0'[0]), ord(b'\n'[0]), ord(b'\r'[0])):
if ord(data[idx]) == ord(b'0'[0]):
zeros -= 1
idx -= 1
if zeros:
Expand All @@ -123,15 +129,15 @@ def _split(self, data):
# but if we read a pfa file, this part is already in hex, and
# I am not quite sure if even the pfb format guarantees that
# it will be in binary).
binary = ''.join([chr(int(data[i:i+2], 16))
for i in range(len1, idx, 2)])
binary = b''.join([unichr(int(data[i:i+2], 16)).encode('latin-1')
for i in range(len1, idx, 2)])

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

_whitespace = re.compile(r'[\0\t\r\014\n ]+')
_token = re.compile(r'/{0,2}[^]\0\t\r\v\n ()<>{}/%[]+')
_comment = re.compile(r'%[^\r\n\v]*')
_instring = re.compile(r'[()\\]')
_whitespace = re.compile(br'[\0\t\r\014\n ]+')
_token = re.compile(br'/{0,2}[^]\0\t\r\v\n ()<>{}/%[]+')
_comment = re.compile(br'%[^\r\n\v]*')
_instring = re.compile(br'[()\\]')
@classmethod
def _tokens(cls, text):
"""
Expand Down Expand Up @@ -191,22 +197,22 @@ def _parse(self):
tokenizer = self._tokens(self.parts[0])
filtered = itertools.ifilter(lambda x: x[0] != 'whitespace', tokenizer)
for token, value in filtered:
if token == 'name' and value.startswith('/'):
if token == b'name' and value.startswith(b'/'):
key = value[1:]
token, value = next(filtered)
if token == 'name':
if value in ('true', 'false'):
value = value == 'true'
if token == b'name':
if value in (b'true', b'false'):
value = value == b'true'
else:
value = value.lstrip('/')
elif token == 'string':
value = value.lstrip('(').rstrip(')')
elif token == 'number':
if '.' in value: value = float(value)
value = value.lstrip(b'/')
elif token == b'string':
value = value.lstrip(b'(').rstrip(b')')
elif token == b'number':
if b'.' in value: value = float(value)
else: value = int(value)
else: # more complicated value such as an array
value = None
if key != 'FontInfo' and value is not None:
if key != b'FontInfo' and value is not None:
prop[key] = value

# Fill in the various *Name properties
Expand Down Expand Up @@ -291,13 +297,14 @@ def transform(self, effects):
multiplier by which the font is to be extended (so values less
than 1.0 condense). Returns a new :class:`Type1Font` object.
"""

buffer = io.StringIO()
buffer = io.BytesIO()
try:
tokenizer = self._tokens(self.parts[0])
for value in self._transformer(tokenizer,
slant=effects.get('slant', 0.0),
extend=effects.get('extend', 1.0)):
if sys.version_info[0] >= 3 and isinstance(value, int):
value = chr(value).encode('latin-1')
buffer.write(value)
result = buffer.getvalue()
finally:
Expand Down

0 comments on commit beb4821

Please sign in to comment.