引言:字体数据的数字化革命
随着AI在文本生成、字体设计等领域的应用加深,将字体的矢量轮廓数据转化为可计算的Token ID序列变得至关重要。本文将通过一段Python代码,深入解析如何从字体文件中提取矢量路径,并将其编码为模型可处理的离散化表示。
代码核心功能概述
1. 字体矢量数据提取
- 目标:从字体文件(如
.ttf
)中提取每个字符的矢量路径数据。 - 关键步骤:
- 使用
fontTools
库解析字体文件的glyf
表,获取字形轮廓。 - 通过
RecordingPen
记录路径命令(如moveTo
、lineTo
等)。 - 将路径数据压缩为JSON格式,便于存储和传输。
- 使用
2. 矢量数据编码
- 目标:将路径坐标和命令转换为数值化的Token ID序列。
- 关键步骤:
- 定义词汇表(
vocabulary
),包含路径命令(如M
、L
)、坐标增量编码(如+xy_10
、-xy_5
)。 - 通过
gen_ttf_to_token_id
函数将字符的矢量路径映射为Token ID序列。
- 定义词汇表(
3. 特征提取与模型适配
- 目标:为模型提供结构化的输入数据,支持字体生成或风格迁移任务。
- 示例应用:提取“永字八法”(侧、勒、弩等)的矢量特征,作为训练数据的基础。
代码详解:分模块解析
1. 字体数据提取与路径解析
函数:extract_all_glyph_vector_data
def extract_all_glyph_vector_data(font_path):
font = TTFont(font_path)
cmap = font.getBestCmap() # 映射字符编码到字形名称
glyph_set = font.getGlyphSet()
file_content = []
for char_code, glyph_name in cmap.items():
glyph = glyph_set[glyph_name]
pen = RecordingPen()
glyph.draw(pen) # 记录字形的路径命令
character = chr(char_code) if char_code <= 0x10FFFF else f"U+{
char_code:04X}"
# 压缩路径数据为JSON格式
file_content.append({
"text": character,
"unicode": f"U+{
char_code:04X}",
"font": compress_path_to_json(pen.value)
})
return file_content
- 作用:遍历字体中的每个字符,提取其矢量路径并存储为JSON格式。
- 关键点:
RecordingPen
记录路径命令(如moveTo((100, 200))
)。compress_path_to_json
将路径命令转换为简化的JSON格式(如[{"M": [100,200]}, {"L": [200,200]}]
)。
2. 矢量数据压缩与解压缩
压缩函数:compress_path_to_json
def compress_path_to_json(data):
command_map = {
'moveTo': 'M', 'lineTo': 'L', 'qCurveTo': 'Q', 'closePath': 'Z'}
compressed = []
for cmd, params in data:
cmd_short = command_map[cmd]
points = []
for param in params:
points += list(param) # 将坐标点展平为列表
compressed.append({
cmd_short: points})
return json.dumps(compressed)
- 作用:将路径命令(如
moveTo((x,y))
)转换为更紧凑的JSON格式。
解压缩函数:decompress_json_to_path
def decompress_json_to_path(compressed_json):
command_map = {
'M': 'moveTo', 'L': 'lineTo', 'Q': 'qCurveTo', 'Z': 'closePath'}
data = json.loads(compressed_json)
decompressed = []
for item in data:
cmd_char = next(iter(item)) # 获取命令字符(如'M')
points = item[cmd_char]
# 将坐标列表转换为元组
tuples = [(points[i], points[i+1]) for i in range(0, len(points), 2)]
decompressed.append((command_map[cmd_char], tuples))
return decompressed
- 作用:将JSON格式的数据还原为原始路径命令。
3. 词汇表生成与Token编码
函数:gen_voc
def gen_voc():
voc = ["<|zero|>", "<|start|>", "...", "<|end|>"] # 特殊标记
# 添加十六进制字符(用于文本编码)
for i in "0123456789abcdef":
voc.append(i)
for j in "0123456789abcdef":
voc.append(i + j)
# ...(递归添加更长的组合)
# 添加路径命令和坐标增量
for cmd in ["M", "L", "Q", "Z"]:
voc.append(cmd)
for xy in range(512):
if xy == 0:
voc.append("xy_0")
else:
voc.append(f"+xy_{
xy}")
voc.append(f"-xy_{
xy}")
return voc
- 作用:生成包含路径命令、坐标增量和文本编码的词汇表。
- 关键点:
- 坐标增量采用
+xy_10
/-xy_5
形式,便于模型捕捉相对位置变化。
- 坐标增量采用
编码函数:gen_ttf_to_token_id
def gen_ttf_to_token_id(voc, path="simsun.ttf"):
one_ttf = extract_all_glyph_vector_data(path)
# 提取特征字(如“侧、勒”)的Token序列
features = [char for char in one_ttf if char["text"] in ["侧", "勒", "弩", "趯", "策", "掠"