8000 Fail gracefully if can't decode font names by mdboom · Pull Request #11263 · matplotlib/matplotlib · GitHub
[go: up one dir, main page]

Skip to content

Fail gracefully if can't decode font names #11263

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 2 additions & 8 deletions lib/matplotlib/backends/backend_pdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
from matplotlib.cbook import (get_realpath_and_stat,
is_writable_file_like, maxdict)
from matplotlib.figure import Figure
from matplotlib.font_manager import findfont, is_opentype_cff_font, get_font
from matplotlib.font_manager import findfont, is_opentype_cff_font, get_font, get_sfnt_name
from matplotlib.afm import AFM
import matplotlib.type1font as type1font
import matplotlib.dviread as dviread
Expand Down Expand Up @@ -1130,13 +1130,7 @@ def embedTTFType42(font, characters, descriptor):
# Beginning of main embedTTF function...

# You are lost in a maze of TrueType tables, all different...
sfnt = font.get_sfnt()
try:
ps_name = sfnt[1, 0, 0, 6].decode('mac_roman') # Macintosh scheme
except KeyError:
# Microsoft scheme:
ps_name = sfnt[3, 1, 0x0409, 6].decode('utf-16be')
# (see freetype/ttnameid.h)
ps_name = font_manager.get_sfnt_name(font, 6)
ps_name = ps_name.encode('ascii', 'replace')
ps_name = Name(ps_name)
pclt = font.get_sfnt_table('pclt') or {'capHeight': 0, 'xHeight': 0}
Expand Down
8 changes: 2 additions & 6 deletions lib/matplotlib/backends/backend_ps.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from matplotlib.cbook import (get_realpath_and_stat, is_writable_file_like,
maxdict, file_requires_unicode)

from matplotlib.font_manager import findfont, is_opentype_cff_font, get_font
from matplotlib.font_manager import findfont, is_opentype_cff_font, get_font, get_sfnt_name
from matplotlib.ft2font import KERNING_DEFAULT, LOAD_NO_HINTING
from matplotlib.ttconv import convert_ttf_to_ps
from matplotlib.mathtext import MathTextParser
Expand Down Expand Up @@ -714,11 +714,7 @@ def draw_text(self, gc, x, y, s, prop, angle, ismath=False, mtext=None):
self.track_characters(font, s)

self.set_color(*gc.get_rgb())
sfnt = font.get_sfnt()
try:
ps_name = sfnt[1, 0, 0, 6].decode('mac_roman')
except KeyError:
ps_name = sfnt[3, 1, 0x0409, 6].decode('utf-16be')
ps_name = get_sfnt_name(font, 6)
ps_name = ps_name.encode('ascii', 'replace').decode('ascii')
self.set_font(ps_name, prop.get_size_in_points())

Expand Down
6 changes: 3 additions & 3 deletions lib/matplotlib/backends/backend_svg.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
_Backend, FigureCanvasBase, FigureManagerBase, RendererBase)
from matplotlib.backends.backend_mixed import MixedModeRenderer
from matplotlib.colors import rgb2hex
from matplotlib.font_manager import findfont, get_font
from matplotlib.font_manager import findfont, get_font, get_sfnt_name
from matplotlib.ft2font import LOAD_NO_HINTING
from matplotlib.mathtext import MathTextParser
from matplotlib.path import Path
Expand Down Expand Up @@ -492,8 +492,8 @@ def _write_svgfonts(self):
for font_fname, chars in six.iteritems(self._fonts):
font = get_font(font_fname)
font.set_size(72, 72)
sfnt = font.get_sfnt()
writer.start('font', id=sfnt[1, 0, 0, 4].decode("mac_roman"))
name = get_sfnt_name(font, 4)
writer.start('font', id=name)
writer.element(
'font-face',
attrib={
Expand Down
38 changes: 28 additions & 10 deletions lib/matplotlib/font_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,32 @@
X11FontDirectories.append(str(Path.home() / ".fonts"))


def get_sfnt_name(font, sfnt_id):
"""
Get a sfnt string entry by from the font, given by sfnt_id.

The possibly IDs are documented `here
<https://www.freetype.org/freetype2/docs/reference/ft2-truetype_tables.html#TT_NAME_ID_XXX>`__.

This will first attempt to find a Unicode name in the file, and if one
doesn't exist, will use a MacRoman-encoded entry. If the MacRoman encoding
isn't available in your Python, a ValueError exception is raised.
"""
sfnt = font.get_sfnt()
# 0x0409 == TT_MS_LANGID_ENGLISH_UNITED_STATES
unicode_id = (3, 1, 0x0409, sfnt_id)
if unicode_id in sfnt:
return sfnt[unicode_id].decode('utf-16be')
else:
mac_roman_id = (1, 0, 0, sfnt_id)
if mac_roman_id in sfnt:
try:
return sfnt[mac_roman_id].decode('mac_roman')
except LookupError:
pass
raise ValueError('Can not decode sfnt_id {}'.format(sfnt_id))


def get_fontext_synonyms(fontext):
"""
Return a list of file extensions extensions that are synonyms for
Expand Down Expand Up @@ -326,16 +352,8 @@ def ttfFontProperty(font):
# Styles are: italic, oblique, and normal (default)

sfnt = font.get_sfnt()
sfnt2 = sfnt.get((1,0,0,2))
sfnt4 = sfnt.get((1,0,0,4))
if sfnt2:
sfnt2 = sfnt2.decode('mac_roman').lower()
else:
sfnt2 = ''
if sfnt4:
sfnt4 = sfnt4.decode('mac_roman').lower()
else:
sfnt4 = ''
sfnt2 = get_sfnt_name(font, 2)
sfnt4 = get_sfnt_name(font, 4)
if sfnt4.find('oblique') >= 0:
style = 'oblique'
elif sfnt4.find('italic') >= 0:
Expand Down
8 changes: 2 additions & 6 deletions lib/matplotlib/textpath.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from matplotlib.ft2font import LOAD_TARGET_LIGHT
from matplotlib.mathtext import MathTextParser
import matplotlib.dviread as dviread
from matplotlib.font_manager import FontProperties, get_font
from matplotlib.font_manager import FontProperties, get_font, get_sfnt_name
from matplotlib.transforms import Affine2D


Expand Down Expand Up @@ -56,11 +56,7 @@ def _get_char_id(self, font, ccode):
"""
Return a unique id for the given font and character-code set.
"""
sfnt = font.get_sfnt()
try:
ps_name = sfnt[1, 0, 0, 6].decode('mac_roman')
except KeyError:
ps_name = sfnt[3, 1, 0x0409, 6].decode('utf-16be')
sfnt = font_manager.get_sfnt_name(font, 6)
char_id = urllib.parse.quote('%s-%x' % (ps_name, ccode))
return char_id

Expand Down
0