Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 90b5889

Browse files
committed
Recognize abbreviations of PostScript code
Type-1 fonts are required to have subroutines with specific contents but their names may vary. They are usually ND, NP and RD but names like | and |- appear too.
1 parent 2fc9611 commit 90b5889

File tree

2 files changed

+23
-5
lines changed

2 files changed

+23
-5
lines changed

lib/matplotlib/tests/test_type1font.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ def test_Type1Font():
4141
assert slanted.prop['ItalicAngle'] == -45
4242
assert font.prop['Encoding'][5] == 'Pi'
4343
assert isinstance(font.prop['CharStrings']['Pi'], bytes)
44+
assert font._abbr['ND'] == b'ND'
4445

4546
differ = difflib.Differ()
4647
diff = list(differ.compare(
@@ -84,6 +85,7 @@ def test_Type1Font_2():
8485
assert font.prop['Encoding'][65] == 'A' # the font uses StandardEncoding
8586
(pos0, pos1), = font._pos['Encoding']
8687
assert font.parts[0][pos0:pos1] == b'/Encoding StandardEncoding'
88+
assert font._abbr['ND'] == b'|-'
8789

8890

8991
def test_overprecision():

lib/matplotlib/type1font.py

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -263,11 +263,14 @@ class Type1Font:
263263
Subrs - array of byte code subroutines
264264
OtherSubrs - bytes object encoding some PostScript code
265265
"""
266-
__slots__ = ('parts', 'decrypted', 'prop', '_pos')
266+
__slots__ = ('parts', 'decrypted', 'prop', '_pos', '_abbr')
267267
# the _pos dict contains (begin, end) indices to parts[0] + decrypted
268268
# so that they can be replaced when transforming the font;
269269
# but since sometimes a definition appears in both parts[0] and decrypted,
270270
# _pos[name] is an array of such pairs
271+
#
272+
# _abbr maps three standard abbreviations to their particular names in
273+
# this font (e.g. 'RD' is named '-|' in some fonts)
271274

272275
def __init__(self, input):
273276
"""
@@ -287,6 +290,7 @@ def __init__(self, input):
287290
self.parts = self._split(data)
288291

289292
self.decrypted = self._decrypt(self.parts[1], 'eexec')
293+
self._abbr = {'RD': b'RD', 'ND': b'ND', 'NP': b'NP'}
290294
self._parse()
291295

292296
def _read(self, file):
@@ -486,10 +490,18 @@ def convert(x): return x.decode('ascii', 'replace')
486490
break
487491

488492
# sometimes noaccess def and readonly def are abbreviated
489-
if kw.is_name(b'def', b'ND', b'RD', b'|-'):
493+
if kw.is_name(b'def', self._abbr['ND'], self._abbr['NP']):
490494
prop[key] = value
491495
pos.setdefault(key, []).append((keypos, kw.endpos()))
492496

497+
# detect the standard abbreviations
498+
if value == b'{noaccess def}':
499+
self._abbr['ND'] = key.encode('ascii')
500+
elif value == b'{noaccess put}':
501+
self._abbr['NP'] = key.encode('ascii')
502+
elif value == b'{string currentfile exch readstring pop}':
503+
self._abbr['RD'] = key.encode('ascii')
504+
493505
# Fill in the various *Name properties
494506
if 'FontName' not in prop:
495507
prop['FontName'] = (prop.get('FullName') or
@@ -515,8 +527,7 @@ def convert(x): return x.decode('ascii', 'replace')
515527
self.prop = prop
516528
self._pos = pos
517529

518-
@staticmethod
519-
def _parse_subrs(tokens, _data):
530+
def _parse_subrs(self, tokens, _data):
520531
count_token = next(tokens)
521532
if not count_token.is_number():
522533
raise RuntimeError(
@@ -543,7 +554,12 @@ def _parse_subrs(tokens, _data):
543554
"Second token following dup in Subrs definition must "
544555
f"be a number, was {nbytes_token}"
545556
)
546-
token = next(tokens) # usually RD or |- but the font can define this to be anything
557+
token = next(tokens)
558+
if not token.is_name(self._abbr['RD']):
559+
raise RuntimeError(
560+
"Token preceding subr must be RD or equivalent, "
561+
f"was {token}"
562+
)
547563
binary_token = tokens.send(1+nbytes_token.numeric_value())
548564
array[index_token.numeric_value()] = binary_token.value[1:]
549565

0 commit comments

Comments
 (0)