#!/usr/bin/env python3 # -*- coding: utf-8 -*- """将青柳隷書字体中的文字转换为 SVG 路径""" from fontTools.ttLib import TTFont from fontTools.ttLib.tables import _h_m_t_x, _g_a_s_p import os # 修补表解析 original_hmtx = _h_m_t_x.table__h_m_t_x.decompile def patched_hmtx(self, data, ttFont): try: return original_hmtx(self, data, ttFont) except: self.metrics = {} _h_m_t_x.table__h_m_t_x.decompile = patched_hmtx original_gasp = _g_a_s_p.table__g_a_s_p.decompile def patched_gasp(self, data, ttFont): try: return original_gasp(self, data, ttFont) except: self.gaspRanges = {} _g_a_s_p.table__g_a_s_p.decompile = patched_gasp def get_glyph_path(font, char): """获取字符的 SVG 路径""" cmap = font.getBestCmap() codepoint = ord(char) if codepoint not in cmap: print(f"警告: 字符 '{char}' (U+{codepoint:04X}) 不在字体中") return None, None glyph_name = cmap[codepoint] # 获取 glyf 表 glyf_table = font['glyf'] glyph = glyf_table[glyph_name] # 获取度量 hmtx = font['hmtx'] advance_width, lsb = hmtx[glyph_name] # 获取边界框 if hasattr(glyph, 'xMin') and glyph.xMin is not None: bbox = (glyph.xMin, glyph.yMin, glyph.xMax, glyph.yMax) else: bbox = (0, 0, advance_width, 1000) # 获取字形轮廓 try: coords, endPts, flags = glyph.getCoordinates(glyf_table) except: print(f" 无法获取轮廓: {glyph_name}") return None, None # 构建 SVG 路径 path_parts = [] start_idx = 0 for end_pt in endPts: contour_coords = coords[start_idx:end_pt + 1] contour_flags = flags[start_idx:end_pt + 1] if len(contour_coords) > 0: path_parts.append(f"M {contour_coords[0][0]:.2f} {-contour_coords[0][1]:.2f}") for i in range(1, len(contour_coords)): x, y = contour_coords[i] path_parts.append(f"L {x:.2f} {-y:.2f}") path_parts.append("Z") start_idx = end_pt + 1 return " ".join(path_parts), {'advance': advance_width, 'lsb': lsb, 'bbox': bbox} # 加载字体 font_path = 'public/fonts/AoyagiReisho.ttf' font = TTFont(font_path) print("=" * 60) print("青柳隷書 字形路径提取") print("=" * 60) chars = ['睿', '新', '致', '遠'] glyphs_data = [] for char in chars: print(f"\n字符: {char} (U+{ord(char):04X})") path, metrics = get_glyph_path(font, char) if path and metrics: print(f" Advance: {metrics['advance']}, LSB: {metrics['lsb']}") print(f" BBox: {metrics['bbox']}") print(f" Path length: {len(path)} chars") glyphs_data.append({ 'char': char, 'path': path, 'metrics': metrics }) font.close() # 生成 SVG print("\n" + "=" * 60) print("生成 SVG 文件...") print("=" * 60) # 计算总宽度 total_width = sum(g['metrics']['advance'] for g in glyphs_data) scale = 48 / 1000 # 缩放因子 svg_paths = [] x_offset = 0 for g in glyphs_data: m = g['metrics'] # 计算字符居中偏移 char_width = m['advance'] * scale path = g['path'] # 缩放路径 scaled_path = path for coord in [('M', 'L')]: pass # 路径已经是正确的格式 svg_paths.append(f''' ''') x_offset += char_width print(f"\n总宽度: {total_width * scale:.2f}px") print("\nSVG 路径组:") print("\n".join(svg_paths[:2])) print("...")