From 567b8acb2f3283f2b58ed8b15ce2d5f931ea3283 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Fri, 16 Aug 2019 12:32:05 +0200 Subject: [PATCH] Add FontManager.addfont to register fonts at specific paths. The naming (without underscore) is similar to findfont. I chose to provide an API adding a single path rather than also wrap findSystemFonts given that the later is basically just a recursive glob (``Path(...).glob("**/*.ttf")``). addfont has no deduplication logic but I think that's fine (really ttflist should be ttfset, but that's a bigger API change). findSystemFonts already assumes that the font extension gives the font type so assuming the same in addfont seems fine. --- doc/api/next_api_changes/2019-08-16-AL.rst | 5 ++ lib/matplotlib/font_manager.py | 53 ++++++++++++++++++++-- 2 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 doc/api/next_api_changes/2019-08-16-AL.rst diff --git a/doc/api/next_api_changes/2019-08-16-AL.rst b/doc/api/next_api_changes/2019-08-16-AL.rst new file mode 100644 index 000000000000..f736bb6af2c1 --- /dev/null +++ b/doc/api/next_api_changes/2019-08-16-AL.rst @@ -0,0 +1,5 @@ +API changes +``````````` + +``font_manager.createFontList`` is deprecated. `.font_manager.FontManager.addfont` +is now available to register a font at a given path. diff --git a/lib/matplotlib/font_manager.py b/lib/matplotlib/font_manager.py index 7b2b46f93c1b..b31358fb1e83 100644 --- a/lib/matplotlib/font_manager.py +++ b/lib/matplotlib/font_manager.py @@ -503,6 +503,7 @@ def afmFontProperty(fontpath, font): return FontEntry(fontpath, name, style, variant, weight, stretch, size) +@cbook.deprecated("3.2", alternative="FontManager.addfont") def createFontList(fontfiles, fontext='ttf'): """ A function to create a font lookup list. The default is to create @@ -967,12 +968,54 @@ def __init__(self, size=None, weight='normal'): 'ttf': 'DejaVu Sans', 'afm': 'Helvetica'} - ttffiles = findSystemFonts(paths) + findSystemFonts() - self.ttflist = createFontList(ttffiles) + self.afmlist = [] + self.ttflist = [] + for fontext in ["afm", "ttf"]: + for path in [*findSystemFonts(paths, fontext=fontext), + *findSystemFonts(fontext=fontext)]: + self.addfont(path) - afmfiles = (findSystemFonts(paths, fontext='afm') - + findSystemFonts(fontext='afm')) - self.afmlist = createFontList(afmfiles, fontext='afm') + def addfont(self, path): + """ + Cache the properties of the font at *path* to make it available to the + `FontManager`. The type of font is inferred from the path suffix. + + Parameters + ---------- + path : str or path-like + """ + if Path(path).suffix.lower() == ".afm": + try: + with open(path, "rb") as fh: + font = afm.AFM(fh) + except EnvironmentError: + _log.info("Could not open font file %s", path) + return + except RuntimeError: + _log.info("Could not parse font file %s", path) + return + try: + prop = afmFontProperty(path, font) + except KeyError as exc: + _log.info("Could not extract properties for %s: %s", path, exc) + return + self.afmlist.append(prop) + else: + try: + font = ft2font.FT2Font(path) + except (OSError, RuntimeError) as exc: + _log.info("Could not open font file %s: %s", path, exc) + return + except UnicodeError: + _log.info("Cannot handle unicode filenames") + return + try: + prop = ttfFontProperty(font) + except (KeyError, RuntimeError, ValueError, + NotImplementedError) as exc: + _log.info("Could not extract properties for %s: %s", path, exc) + return + self.ttflist.append(prop) @property def defaultFont(self):