查找适用于matplotlib的中文字体名称与实际文件名对应关系的方法

本文探讨了在matplotlib中查找并使用中文字体的方法,包括matplotlib支持的字体类型、如何查询系统字体、matplotlib内置字体、生成字体列表以及如何确定字体是否为中文字体。通过阅读源码和利用ttfquery等工具,可以更高效地管理和使用中文字体。
摘要由CSDN通过智能技术生成

问题来源

如何在 matplotlib 中使用中文字体是老问题了,相关文章非常多。
前几天有人问我 如何知道中文字体名称和实际文件的对应关系 时,才想起来原来没思考过这个问题,只能让他记住字体与文件的对应关系或者去 fonts 目录查看。
**难道真的就没有稍微自动化、智能化的查看支持matplotlib 的字体名称与文件的对应关系的方法? **

问题解决步骤

matplotlib 与字体相关的模块是 font_manager ,观察源码 font_manager.py 可知:

1. matplotlib支持哪种类型的字体?

    def get_fontext_synonyms(fontext):
      """
      Return a list of file extensions extensions that are synonyms for
      the given file extension *fileext*.
      """
      return {
   
        'afm': ['afm'],
        'otf': ['otf', 'ttc', 'ttf'],
        'ttc': ['otf', 'ttc', 'ttf'],
        'ttf': ['otf', 'ttc', 'ttf'],
      }[fontext]

由此可知 matplotlib 只支持 ttfafm 字体。

  • ‘ttf’: TrueType and OpenType fonts (.ttf, .ttc, .otf)
  • ‘afm’: Adobe Font Metrics (.afm)

2. matplotlib如何查找系统字体?

findSystemFonts 模块函数的作用是查找系统字体。
def findSystemFonts(fontpaths=None, fontext='ttf'): -->list
参数 fontext 默认值为 'ttf' ,另外还支持值 'afm'
参数 fontpaths 默认值是 None
对于 fontpaths 有两种种情况。

fontpathsNone

函数会判断操作系统,如果是Windows,调用函数 win32InstalledFonts ,如果不是Windows,调用函数 get_fontconfig_fonts

对于Windows,函数 win32InstalledFonts 到以下路径查找。

    # OS Font paths
    MSFolders = \
      r'Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders'
    MSFontDirectories = [
      r'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts',
      r'SOFTWARE\Microsoft\Windows\CurrentVersion\Fonts']
    MSUserFontDirectories = [
      str(Path.home() / 'AppData/Local/Microsoft/Windows/Fonts'),
      str(Path.home() / 'AppData/Roaming/Microsoft/Windows/Fonts'),
    ]

对于 非Windows 操作系统,函数 get_fontconfig_fonts 主要依托 fontconfig 包(即 fc- list 命令)查找字体,要求 fontconfig>=2.7

fontpaths 不为 None

fontpaths 不为 None 时,通过 list_fonts() 函数查找字体。
**list_fonts() 函数其实一个通用的按路径、扩展名递归遍历文件路径的函数。 **

    def list_fonts(directory, extensions):
      """
      Return a list of all fonts matching any of the extensions, found
      recursively under the directory.
      """
      extensions = ["." + ext for ext in extensions]
      return [os.path.join(dirpath, filename)
          # os.walk ignores access errors, unlike Path.glob.
          for dirpath, _, filenames in os.walk(directory)
          for filename in filenames
          if Path(filename).suffix.lower() in extensions]

3.matplotlib如何查找matplotlib自带字体?

安装 matplotlib 时,会在 site-packages\matplotlib\mpl-data\fonts 目录放置一系列字体。

通过源码可知 fonts 目录下有 'ttf', 'afm', 'pdfcorefonts' 3个子目录。

    paths = [cbook._get_data_path('fonts', subdir)
             for subdir in ['ttf', 'afm', 'pdfcorefonts']]
    In [1]: import matplotlib.cbook as cbook
    In [2]: paths = [cbook._get_data_path('fonts', subdir)  for subdir in ['ttf', 'afm', 'pdfcorefonts']]
    In [3]: paths
    Out[4]:
    [WindowsPath('c:/users/administrator/appdata/local/programs/python/python37/lib/site-packages/matplotlib/mpl-data/fonts/ttf'),
     WindowsPath('c:/users/administrator/appdata/local/programs/python/python37/lib/site-packages/matplotlib/mpl-data/fonts/afm'),
     WindowsPath('c:/users/administrator/appdata/local/programs/python/python37/lib/site-packages/matplotlib/mpl-data/fonts/pdfcorefonts')]

4.matplotlib如何生成字体列表?

FontManager 类是 matplotlib 管理字体的重要类,是一个单例类。 FontManager 实例在构造后会创建一个
ttf 字体列表和一个 afm 字体列表,并会缓存他们的字体属性。
下面简单看看 ttflistafmlist 列表的元素的属性。

    In [1]: import matplotlib.font_manager as mf
    In [2]: ttflist=mf.FontManager().ttflist
    In [3]: vars(ttflist[0])
    Out[3]:
    {
   'fname': 'c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\matplotlib\\mpl-data\\fonts\\ttf\\DejaVuSansMono-BoldOblique.ttf',
     'name': 'DejaVu Sans Mono',
     'style': 'oblique',
     'variant': 'normal',
     'weight': 700,
     'stretch': 'normal',
     'size': 'scalable'}
    In [4]: len(ttflist)
    Out[4]: 252
    In [5]: afmlist=mf.FontManager().afmlist
    In [6]: vars(afmlist[0])
    Out[6]:
    {
   'fname': 'c:\\users\\administrator\\appdata\\local\\programs\\python\\python37\\lib\\site-packages\\matplotlib\\mpl-data\\fonts\\afm\\pagko8a.afm',
     'name': 'ITC Avant Garde Gothic',
     'style': 'italic',
     'variant': 'normal',
     'weight': 'book',
     'stretch': 'normal',
     'size': 'scalable'}
    In [7]: len(afmlist)
    Out[7]: 60

5.matplotlib的字体属性缓存在哪里?

前面了解到 matplotlib 会缓存字体属性那在什么位置呢?
根据源码可知,字体缓存的所在目录是 .matplotlib ,缓存文件是 fontlist-v330.json
(文件名与版本有关)。在某些老版本的 matplotlib 中字体缓存文件名是 fontList.cache

    _fmcache = os.path.join(
      mpl.get_cachedir(), 'fontlist-v{}.json'.format(FontManager.__version__))
    In [1]: import matplotlib
    In [2]: matplotlib.get_cachedir()
    Out[2]: 'C:\\Users\\Administrator\\.matplotlib'

6. 怎么知道哪些字体是中文字体?

虽然在前面已经知道 matplotlib 会把系统字体和自带字体信息存放在 ttflistafmlist
中,但是在这些字体信息中也不容易确定哪些是中文字体。
通过资料查找有3种方法:

查看Windows的 fonts 系统目录中显示的字体名称和文件名属性。 这种方法效率太低!

通过注册表项 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts] 查看字体名和字体文件名称映射。这种方法一些系统字体仍然看不到汉字名称。

在这里插入图片描述

根据第1种方法想到了去查字体文件的元数据,Python相关的库有两个: fonttools ,作者是老爹Guido的弟弟 Just van RossumTTFQuery ,基于 fonttools 的TTF包,只能查看 TTF 文件而且最后更新日期是2012年。

TTFQery 项目地址 [ https://pypi.org/project/TTFQuery/

](https://pypi.org/project/TTFQuery/)
源码中有些小问题,源码不算复杂,直接修改。

    import sys
    from fontTools.ttLib import TTFont
    from fontTools.ttLib.ttCollection import TTCollection
    
    UNICODE_ENCODINGS = {
   0: 'Unicode 1.0 semantics',
               1: 'Unicode 1.1 semantics',
               2: 'Unicode 1.1 semantics',
               3: 'Unicode 2.0 and onwards semantics, Unicode BMP only (cmap subtable formats 0, 4, 6).',
               4: 'Unicode 2.0 and onwards semantics, Unicode full repertoire (cmap subtable formats 0, 4, 6, 10, 12).',
               5: 'Unicode Variation Sequences (cmap subtable format 14).',
               6: 'Unicode Variation Sequences (cmap subtable format 14).'}
    
    
    WINDOWS_ENCODINGS = {
   0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值