You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何检测OTF字体中同一字符的多语言字形并在Jupyter中渲染?

检查并渲染OTF字体中同一Unicode字符的语言专属字形

Unicode字符\u76F4(对应汉字「直」)在中文里的样式为带竖钩的写法,在日语里则是不带竖钩的横排样式。以下是如何用fonttools检查字体是否包含该字符的日文字形,以及在Jupyter Notebook中渲染它的方法:

一、检查字体是否包含「直」的日文字形

你的字体包含GSUB表,这类语言专属字形通常通过GSUB的**语言系统(Language System)和特性(Feature)**实现(比如日语的JP语言标签)。可以用fonttools解析GSUB表验证:

from fontTools.ttLib import TTFont

font_path = "SiYuanHeavyFont.otf"
font = TTFont(font_path)

# 检查是否支持日语语言系统
gsub = font["GSUB"]
lang_systems = gsub.table.LanguageSystemList.LanguageSystemRecord
has_japanese = any(ls.LanguageSystemTag == "JP " for ls in lang_systems)
print(f"字体是否支持日语语言系统: {has_japanese}")

# 检查字符\u76F4是否有日语专属替换规则
char_code = 0x76F4
cmap = font.getBestCmap()
base_glyph = cmap.get(char_code)

if not base_glyph:
    print("字体中无该字符基础字形")
else:
    # 遍历GSUB规则查找日语替换字形
    for lookup in gsub.table.LookupList.Lookup:
        for subtable in lookup.SubTable:
            if hasattr(subtable, 'LangSys') and subtable.LangSys == "JP ":
                if hasattr(subtable, 'mapping') and base_glyph in subtable.mapping:
                    print(f"找到日语专属字形: {subtable.mapping[base_glyph]}")
                    break

如果上述代码未找到日语字形,说明该字体仅包含「直」的中文字形,没有提供日语地域变体。

二、在Jupyter Notebook中渲染日文字形

PIL的ImageFont默认不会触发GSUB的语言特性,需要用支持OpenType特性的库指定语言标签:

方法1:使用freetype-py指定日语语言特性

import freetype
import numpy as np
from PIL import Image

font_path = "SiYuanHeavyFont.otf"
face = freetype.Face(font_path)
face.set_char_size(64 * 64)  # 设置字号为64(单位:1/64像素)

# 指定日语语言标签加载字符
char_code = 0x76F4
face.select_charmap(freetype.FT_ENCODING_UNICODE)
face.set_script("han")
face.set_language("JP")
face.load_char(chr(char_code), freetype.FT_LOAD_RENDER)

# 将渲染结果转为PIL图像
glyph_bitmap = face.glyph.bitmap
data = np.array(glyph_bitmap.buffer, dtype=np.uint8).reshape(glyph_bitmap.rows, glyph_bitmap.width)
image = Image.fromarray(255 - data, mode='L')
# 填充到128x128画布
image = image.crop((0, 0, 128, 128)) if image.size >= (128,128) else image.pad((0, 128 - image.height, 128 - image.width, 0), fill=224)
image

方法2:使用fonttools生成指定语言的字形

from fontTools.ttLib import TTFont
import matplotlib.pyplot as plt
from fontTools.pens.cocoaPen import CocoaPen

font_path = "SiYuanHeavyFont.otf"
font = TTFont(font_path)
gsub = font["GSUB"]

char_code = 0x76F4
base_glyph = font.getBestCmap()[char_code]
japanese_glyph = base_glyph

# 应用GSUB日语特性获取替换字形
lookup_index = gsub.getLookupIndexForLangSys("JP ")
if lookup_index is not None:
    for lookup in gsub.table.LookupList.Lookup[:lookup_index+1]:
        for subtable in lookup.SubTable:
            if hasattr(subtable, 'mapping') and base_glyph in subtable.mapping:
                japanese_glyph = subtable.mapping[base_glyph]
                break

# 渲染字形
glyph_set = font.getGlyphSet()
glyph = glyph_set[japanese_glyph]
pen = CocoaPen(glyph_set)
glyph.draw(pen)

# 用matplotlib展示
fig, ax = plt.subplots(figsize=(2,2), dpi=64)
ax.add_patch(plt.PathPatch(pen.path, facecolor='black'))
ax.set_xlim(0, font['hhea'].advanceWidthMax)
ax.set_ylim(0, font['head'].unitsPerEm)
ax.invert_yaxis()
ax.axis('off')
plt.show()

内容的提问来源于stack exchange,提问作者martin li

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 05:35:15