错误RuntimeWarning: Glyph xxxxx missing from current font的产生原因解析,检测当前字体是否包含某字符
RuntimeWarning: Glyph 26631 missing from current font.font.set_text(s, 0.0, flags=flags)
RuntimeWarning: Glyph xxxx missing from current font
是matplotlib
的经典错误。
原因大家都清楚:字体不匹配,显示不了对应的字符。
现象就是:本该显示的字符,显示为方框了,一般出现在汉字当中。
那这个错误是怎么产生的呢?
调试信息
d:\ProgramData\Anaconda3\lib\site-packages\matplotlib\backends\backend_agg.py:201:
RuntimeWarning: Glyph 39064 missing from current font.
font.set_text(s, 0, flags=flags)
根据traceback
信息可知:
- 提示当前字体中找不到
Glyph 39064
。 - 错误发生在
backend_agg.py
。 - 出错代码在
font.set_text(s, 0, flags=flags)
。
问题分析
Glyph
是象形文字的意思,可以理解为符号,那39064
是什么呢?通过查找汉字unicode编码表可知,39064
对应的汉字就是题
。从字面意思上看,错误信息就是表示在当前设置的字体中找不到对应字符
。不单汉字会出现这样的错误提示,只要当前字体中不存在对应字符都会报这个错误
。backend_agg.py
是matplotlib
的绘图后端模块。font.set_text(s, 0, flags=flags)
属于RendererAgg
类中的draw_text
方法。相关代码为:
font = self._get_agg_font(prop)
if font is None:
return None
# We pass '0' for angle here, since it will be rotated (in raster
# space) in the following call to draw_text_image).
font.set_text(s, 0, flags=flags)
再次追踪 _get_agg_font(prop)。
def _get_agg_font(self, prop):
"""
Get the font for text instance t, caching for efficiency
"""
fname = findfont(prop)
font = get_font(fname)
font.clear()
size = prop.get_size_in_points()
font.set_size(size, self.dpi)
return font
font = get_font(fname)
from matplotlib.font_manager import findfont, get_font
问题又回到了font_manager
模块了!
_get_font = lru_cache(64)(ft2font.FT2Font)
# FT2Font objects cannot be used across fork()s because they reference the same
# FT_Library object. While invalidating *all* existing FT2Fonts after a fork
# would be too complicated to be worth it, the main way FT2Fonts get reused is
# via the cache of _get_font, which we can empty upon forking (in Py3.7+).
if hasattr(os, "register_at_fork"):
os.register_at_fork(after_in_child=_get_font.cache_clear)
def get_font(filename, hinting_factor=None):
# Resolving the path avoids embedding the font twice in pdf/ps output if a
# single font is selected using two different relative paths.
filename = os.path.realpath(filename)
if hinting_factor is None:
hinting_factor = rcParams['text.hinting_factor']
return _get_font(os.fspath(filename), hinting_factor,
_kerning_factor=rcParams['text.kerning_factor'])
from matplotlib import afm, cbook, ft2font, rcParams
ft2font
是matplotlib
的模块,在我的计算机上文件名是ft2font.cp37-win_amd64.pyd
,看来是用其他语言编译的模块。
通过查找可知,ft2font
模块的源码即https://github.com/matplotlib/matplotlib/blob/master/src/ft2font.cpp
。
static FT_UInt ft_get_char_index_or_warn(FT_Face face, FT_ULong charcode)
{
FT_UInt glyph_index = FT_Get_Char_Index(face, charcode);
if (!glyph_index) {
PyErr_WarnFormat(NULL, 1, "Glyph %lu missing from current font.", charcode);
// Apparently PyErr_WarnFormat returns 0 even if the exception propagates
// due to running with -Werror, so check the error flag directly instead.
if (PyErr_Occurred()) {
throw py::exception();
}
}
return glyph_index;
}
由此可知,这条错误从哪儿来了的!就是字体里没有对应的字符
!
检测当前字体是否含有该字符
根据fonttools
写了一个简易检测当前字体是否含有该字符的小工具。
import sys
from itertools import chain
from fontTools.ttLib import TTFont
from fontTools.unicode import Unicode
font_path=r"c:\windows\fonts\simhei.ttf"
def font_validation(input_string,font_path):
font =TTFont(font_path)
chars = chain.from_iterable([y + (Unicode[y[0]],) for y in x.cmap.items()] for x in font["cmap"].tables)
for i in input_string:
char=ord(i)
# 输出字符、10进制Unicode编号、16进制Unicode编号、Unicode名称、是否包含在字体内
print(i,char,hex(char),Unicode[char],char in (x[0] for x in chars))
font.close()
font_validation("标题₩",font_path)
从结果看,韩元符号₩
黑体是没有的。
标 26631 0x6807 CJK UNIFIED IDEOGRAPH-6807 True
题 39064 0x9898 CJK UNIFIED IDEOGRAPH-9898 True
₩ 65510 0xffe6 FULLWIDTH WON SIGN False
使用黑体
绘图测试下:
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
font = FontProperties(fname=r"c:\windows\fonts\simhei.ttf", size=30)
plt.title("标题₩", fontproperties=font)
plt.show()
使用gulim
绘图测试下:
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
font_path=r"C:\Users\Administrator\AppData\Local\Microsoft\Windows\Fonts\gulim.ttc"
font = FontProperties(fname=font_path, size=30)
plt.title("标题₩", fontproperties=font)
plt.show()
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)