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

Skip to content

Commit 9418b35

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 b64782e commit 9418b35

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
@@ -264,11 +264,14 @@ class Type1Font:
264264
Subrs - array of byte code subroutines
265265
OtherSubrs - bytes object encoding some PostScript code
266266
"""
267-
__slots__ = ('parts', 'decrypted', 'prop', '_pos')
267+
__slots__ = ('parts', 'decrypted', 'prop', '_pos', '_abbr')
268268
# the _pos dict contains (begin, end) indices to parts[0] + decrypted
269269
# so that they can be replaced when transforming the font;
270270
# but since sometimes a definition appears in both parts[0] and decrypted,
271271
# _pos[name] is an array of such pairs
272+
#
273+
# _abbr maps three standard abbreviations to their particular names in
274+
# this font (e.g. 'RD' is named '-|' in some fonts)
272275

273276
def __init__(self, input):
274277
"""
@@ -288,6 +291,7 @@ def __init__(self, input):
288291
self.parts = self._split(data)
289292

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

293297
def _read(self, file):
@@ -482,10 +486,18 @@ def convert(x): return x.decode('ascii', 'replace')
482486
break
483487

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

493+
# detect the standard abbreviations
494+
if value == b'{noaccess def}':
495+
self._abbr['ND'] = key.encode('ascii')
496+
elif value == b'{noaccess put}':
497+
self._abbr['NP'] = key.encode('ascii')
498+
elif value == b'{string currentfile exch readstring pop}':
499+
self._abbr['RD'] = key.encode('ascii')
500+
489501
# Fill in the various *Name properties
490502
if 'FontName' not in prop:
491503
prop['FontName'] = (prop.get('FullName') or
@@ -511,8 +523,7 @@ def convert(x): return x.decode('ascii', 'replace')
511523
self.prop = prop
512524
self._pos = pos
513525

514-
@staticmethod
515-
def _parse_subrs(tokens, _data):
526+
def _parse_subrs(self, tokens, _data):
516527
count_token = next(tokens)
517528
if not count_token.is_number():
518529
raise RuntimeError(
@@ -539,7 +550,12 @@ def _parse_subrs(tokens, _data):
539550
"Second token following dup in Subrs definition must "
540551
f"be a number, was {nbytes_token}"
541552
)
542-
token = next(tokens) # usually RD or |- but the font can define this to be anything
553+
token = next(tokens)
554+
if not token.is_name(self._abbr['RD']):
555+
raise RuntimeError(
556+
"Token preceding subr must be RD or equivalent, "
557+
f"was {token}"
558+
)
543559
binary_token = tokens.send(1+nbytes_token.numeric_value())
544560
array[index_token.numeric_value()] = binary_token.value[1:]
545561

0 commit comments

Comments
 (0)