8000 Fix a number of font manager issues: · matplotlib/matplotlib@af9954d · GitHub
[go: up one dir, main page]

Skip to content

Commit af9954d

Browse files
committed
Fix a number of font manager issues:
1) AFM fonts now store stretch information in the FontManager database 2) pdf.use14corefonts and ps.useafm will now only use the afm files for their respective formats 3) The fontList.cache file is now versioned -- if the version doesn't match the current version of matplotlib it is thrown away and regenerated svn path=/trunk/matplotlib/; revision=7956
1 parent 8c200da commit af9954d

File tree

4 files changed

+70
-37
lines changed

4 files changed

+70
-37
lines changed

lib/matplotlib/backends/backend_pdf.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,8 @@ def __init__(self, filename):
363363
else:
364364
raise ValueError("filename must be a path or a file-like object")
365365

366+
self._core14fontdir = os.path.join(
367+
rcParams['datapath'], 'fonts', 'pdfcorefonts')
366368
self.fh = fh
367369
self.currentstream = None # stream object to write to, if any
368370
fh.write("%PDF-1.4\n") # 1.4 is the first version to have alpha
@@ -507,7 +509,11 @@ def fontName(self, fontprop):
507509
if is_string_like(fontprop):
508510
filename = fontprop
509511
elif rcParams['pdf.use14corefonts']:
510-
filename = findfont(fontprop, fontext='afm')
512+
filename = findfont(
513+
fontprop, fontext='afm', directory=self._core14fontdir)
514+
if filename is None:
515+
filename = findfont(
516+
"Helvetica", fontext='afm', directory=self._core14fontdir)
511517
else:
512518
filename = findfont(fontprop)
513519

@@ -1743,7 +1749,12 @@ def _get_font_afm(self, prop):
17431749
key = hash(prop)
17441750
font = self.afm_font_cache.get(key)
17451751
if font is None:
1746-
filename = findfont(prop, fontext='afm')
1752+
filename = findfont(
1753+
prop, fontext='afm', directory=self.file._core14fontdir)
1754+
if filename is None:
1755+
filename = findfont(
1756+
"Helvetica", fontext='afm',
1757+
directory=self.file._core14fontdir)
17471758
font = self.afm_font_cache.get(filename)
17481759
if font is None:
17491760
fh = file(filename)

lib/matplotlib/backends/backend_ps.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,9 @@ def __init__(self, width, height, pswriter, imagedpi=72):
170170
self.used_characters = {}
171171
self.mathtext_parser = MathTextParser("PS")
172172

173+
self._afm_font_dir = os.path.join(
174+
rcParams['datapath'], 'fonts', 'afm')
175+
173176
def track_characters(self, font, s):
174177
"""Keeps track of which characters are required from
175178
each font."""
@@ -312,10 +315,13 @@ def _get_font_afm(self, prop):
312315
key = hash(prop)
313316
font = self.afmfontd.get(key)
314317
if font is None:
315-
fname = findfont(prop, fontext='afm')
318+
fname = findfont(prop, fontext='afm', directory=self._afm_font_dir)
319+
if fname is None:
320+
fname = findfont(
321+
"Helvetica", fontext='afm', directory=self._afm_font_dir)
316322
font = self.afmfontd.get(fname)
317323
if font is None:
318-
font = AFM(file(findfont(prop, fontext='afm')))
324+
6D40 font = AFM(file(fname))
319325
self.afmfontd[fname] = font
320326
self.afmfontd[key] = font
321327
return font

lib/matplotlib/font_manager.py

Lines changed: 44 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ def get_fontconfig_fonts(fontext='ttf'):
301301
except OSError:
302302
# Calling fc-list did not work, so we'll just return nothing
303303
return fontfiles
304-
304+
305305
if pipe.returncode == 0:
306306
for line in output.split('\n'):
307307
fname = line.split(':')[0]
@@ -463,8 +463,7 @@ def ttfFontProperty(font):
463463
# Relative stretches are: wider, narrower
464464
# Child value is: inherit
465465

466-
# !!!! Incomplete
467-
if sfnt4.find('narrow') >= 0 or sfnt4.find('condensed') >= 0 or \
466+
if sfnt4.find('narrow') >= 0 or sfnt4.find('condensed') >= 0 or \
468467
sfnt4.find('cond') >= 0:
469468
stretch = 'condensed'
470469
elif sfnt4.find('demi cond') >= 0:
@@ -502,6 +501,7 @@ def afmFontProperty(fontpath, font):
502501
"""
503502

504503
name = font.get_familyname()
504+
fontname = font.get_fontname().lower()
505505

506506
# Styles are: italic, oblique, and normal (default)
507507

@@ -532,9 +532,15 @@ def afmFontProperty(fontpath, font):
532532
# and ultra-expanded.
533533
# Relative stretches are: wider, narrower
534534
# Child value is: inherit
535-
536-
# !!!! Incomplete
537-
stretch = 'normal'
535+
if fontname.find('narrow') >= 0 or fontname.find('condensed') >= 0 or \
536+
fontname.find('cond') >= 0:
537+
stretch = 'condensed'
538+
elif fontname.find('demi cond') >= 0:
539+
stretch = 'semi-condensed'
540+
elif fontname.find('wide') >= 0 or fontname.find('expanded') >= 0:
541+
stretch = 'expanded'
542+
else:
543+
stretch = 'normal'
538544

539545
# Sizes can be absolute and relative.
540546
# Absolute sizes are: xx-small, x-small, small, medium, large, x-large,
@@ -960,12 +966,20 @@ class FontManager:
960966
matches the specification. If no good enough match is found, a
961967
default font is returned.
962968
"""
969+
# Increment this version number whenever the font cache data
970+
# format or behavior has changed and requires a existing font
971+
# cache files to be rebuilt.
972+
__version__ = 5
973+
963974
def __init__(self, size=None, weight='normal'):
975+
self._version = self.__version__
976+
964977
self.__default_weight = weight
965978
self.default_size = size
966979

967980
paths = [os.path.join(rcParams['datapath'], 'fonts', 'ttf'),
968-
os.path.join(rcParams['datapath'], 'fonts', 'afm')]
981+
os.path.join(rcParams['datapath'], 'fonts', 'afm'),
982+
os.path.join(rcParams['datapath'], 'fonts', 'pdfcorefonts')]
969983

970984
# Create list of font paths
971985
for pathname in ['TTFPATH', 'AFMPATH']:
@@ -982,32 +996,23 @@ def __init__(self, size=None, weight='normal'):
982996
# Load TrueType fonts and create font dictionary.
983997

984998
self.ttffiles = findSystemFonts(paths) + findSystemFonts()
999+
self.defaultFont = {}
9851000

9861001
for fname in self.ttffiles:
9871002
verbose.report('trying fontname %s' % fname, 'debug')
9881003
if fname.lower().find('vera.ttf')>=0:
989-
self.defaultFont = fname
1004+
self.defaultFont['ttf'] = fname
9901005
break
9911006
else:
9921007
# use anything
993-
self.defaultFont = self.ttffiles[0]
1008+
self.defaultFont['ttf'] = self.ttffiles[0]
9941009

9951010
self.ttflist = createFontList(self.ttffiles)
9961011

997-
if rcParams['pdf.use14corefonts']:
998-
# Load only the 14 PDF core fonts. These fonts do not need to be
999-
# embedded; every PDF viewing application is required to have them:
1000-
# Helvetica, Helvetica-Bold, Helvetica-Oblique, Helvetica-BoldOblique,
1001-
# Courier, Courier-Bold, Courier-Oblique, Courier-BoldOblique,
1002-
# Times-Roman, Times-Bold, Times-Italic, Times-BoldItalic, Symbol,
1003-
# ZapfDingbats.
1004-
afmpath = os.path.join(rcParams['datapath'],'fonts','pdfcorefonts')
1005-
afmfiles = findSystemFonts(afmpath, fontext='afm')
1006-
self.afmlist = createFontList(afmfiles, fontext='afm')
1007-
else:
1008-
self.afmfiles = findSystemFonts(paths, fontext='afm') + \
1009-
findSystemFonts(fontext='afm')
1010-
self.afmlist = createFontList(self.afmfiles, fontext='afm')
1012+
self.afmfiles = findSystemFonts(paths, fontext='afm') + \
1013+
findSystemFonts(fontext='afm')
1014+
self.afmlist = createFontList(self.afmfiles, fontext='afm')
1015+
self.defaultFont['afm'] = None
10111016

10121017
self.ttf_lookup_cache = {}
10131018
self.afm_lookup_cache = {}
@@ -1151,7 +1156,7 @@ def score_size(self, size1, size2):
11511156
return 1.0
11521157
return abs(sizeval1 - sizeval2) / 72.0
11531158

1154-
def findfont(self, prop, fontext='ttf'):
1159+
def findfont(self, prop, fontext='ttf', directory=None):
11551160
"""
11561161
Search the font list for the font that most closely matches
11571162
the :class:`FontProperties` *prop*.
@@ -1162,6 +1167,9 @@ def findfont(self, prop, fontext='ttf'):
11621167
returned. If no matches below a certain threshold are found,
11631168
the default font (usually Vera Sans) is returned.
11641169
1170+
`directory`, is specified, will only return fonts from the
1171+
given directory (or subdirectory of that directory).
1172+
11651173
The result is cached, so subsequent lookups don't have to
11661174
perform the O(n) nearest neighbor search.
11671175
@@ -1194,6 +1202,10 @@ def findfont(self, prop, fontext='ttf'):
11941202
best_font = None
11951203

11961204
for font in fontlist:
1205+
if (directory is not None and
1206+
os.path.commonprefix([font.fname, directory]) != directory):
1207+
print directory, font.fname, os.path.commonprefix([font.fname, directory])
1208+
continue
11971209
# Matching family should have highest priority, so it is multiplied
11981210
# by 10.0
11991211
score = \
@@ -1211,8 +1223,8 @@ def findfont(self, prop, fontext='ttf'):
12111223

12121224
if best_font is None or best_score >= 10.0:
12131225
verbose.report('findfont: Could not match %s. Returning %s' %
1214-
(prop, self.defaultFont))
1215-
result = self.defaultFont
1226+
(prop, self.defaultFont[fontext]))
1227+
result = self.defaultFont[fontext]
12161228
else:
12171229
verbose.report('findfont: Matching %s to %s (%s) with score of %f' %
12181230
(prop, best_font.name, best_font.fname, best_score))
@@ -1289,16 +1301,16 @@ def _rebuild():
12891301

12901302
try:
12911303
fontManager = pickle_load(_fmcache)
1292-
fontManager.default_size = None
1293-
verbose.report("Using fontManager instance from %s" % _fmcache)
1304+
if (not hasattr(fontManager, '_version') or
1305+
fontManager._version != FontManager.__version__):
1306+
_rebuild()
1307+
else:
1308+
fontManager.default_size = None
1309+
verbose.report("Using fontManager instance from %s" % _fmcache)
12941310
except:
12951311
_rebuild()
12961312

12971313
def findfont(prop, **kw):
12981314
global fontManager
12991315
font = fontManager.findfont(prop, **kw)
1300-
if not os.path.exists(font):
1301-
verbose.report("%s returned by pickled fontManager does not exist" % font)
1302-
_rebuild()
1303-
font = fontManager.findfont(prop, **kw)
13041316
return font

lib/matplotlib/mathtext.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1032,7 +1032,11 @@ def __init__(self, default_font_prop):
10321032
self.glyphd = {}
10331033
self.fonts = {}
10341034

1035-
filename = findfont(default_font_prop, fontext='afm')
1035+
filename = findfont(default_font_prop, fontext='afm',
1036+
directory=self.basepath)
1037+
if filename is None:
1038+
filename = findfont('Helvetica', fontext='afm',
1039+
directory=self.basepath)
10361040
default_font = AFM(file(filename, 'r'))
10371041
default_font.fname = filename
10381042

0 commit comments

Comments
 (0)
0