使用Pillow渲染字体字形时出现空白方框的问题求助
问题根因
渲染出现空白方框是字体内置的.notdef缺字占位符,核心原因是你加载的字体本身不包含目标Unicode字符的字形定义,和布局引擎、编码参数无关:
- 现有代码仅校验字体文件是否可正常加载,未校验字体是否支持目标字符,只要字体能成功加载就直接执行渲染,必然会出现缺字空框
- Pillow 缺字时不会抛出异常,会自动渲染缺字占位方框,原有try-except逻辑完全无法捕获这类情况。
解决方案
无需手动遍历25万张渲染图剔除无效结果,在渲染前增加字形有效性校验即可,Pillow 8.0.0及以上版本提供的getbbox()、getmask()接口可以在渲染前快速判断字符是否被字体支持,校验耗时远低于渲染后做图像识别排查。
- 缺字时
getbbox()会返回.notdef占位符的边界,getmask()返回的像素数据只有方框轮廓的少量非白像素,正常字形的有效绘制像素占比远高于空框 - 校验逻辑嵌入渲染流程后,批量渲染时可以自动跳过不支持目标字符的字体,全程无需人工介入。
修正后可自动过滤空框的实现代码
from PIL import Image, ImageFont, ImageDraw def draw_glyph(font_file, unicode_char, glyph_size=128): try: font = ImageFont.truetype( font=font_file, encoding="", size=glyph_size, layout_engine=ImageFont.LAYOUT_RAQM, ) except Exception: return None # 渲染前校验字符是否存在于当前字体中 bbox = font.getbbox(unicode_char, anchor='mm') char_mask = font.getmask(unicode_char, anchor='mm') # 统计mask中非0(实际绘制内容)的像素占比,缺字空框的非0像素占比极低 non_blank_pixel = sum(1 for p in char_mask if p > 0) # 阈值可根据使用的字体灵活调整 if non_blank_pixel < glyph_size * glyph_size * 0.005: return None img = Image.new('L', (glyph_size, glyph_size), 'white') draw = ImageDraw.Draw(img) draw.text( xy=(glyph_size//2, glyph_size//2), text=unicode_char, font=font, anchor='mm', ) return img
补充说明
- 若使用的Pillow版本低于8.0.0,先升级到新版本即可使用上述字形查询接口,低版本无对应查询API,只能渲染后统计图像非白像素占比判断是否为空框,运行效率更低
- 代码里的非空像素占比阈值
0.005可根据实际使用的字体调整:如果出现极细笔画字符被误判为缺字,可适当调低阈值;如果仍有漏判的空框,可适当调高阈值 - 字体加载时保持
encoding=""默认参数即可,自定义编码值反而可能导致Unicode字形映射错误。
内容的提问来源于stack exchange,提问作者tachycardiazxc
相关产品推荐
相关产品推荐

