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

如何用Python将woff/ttf/otf转为ReportLab兼容的TTF字体

解决ReportLab兼容的字体转换问题:OTF/TTF/WOFF转可用TTF

问题概述

需要将包含自定义字体的SVG转PNG,通过svglib+ReportLab实现。部分字体转换后可正常加载,但无法预判兼容性;使用fonttools转换后的字体无法适配代码,但在线工具转换后的字体只要文件名与字体族名一致就能正常工作。核心需求是用Python实现任意OTF/TTF/WOFF(至少支持WOFF)转换为ReportLab兼容的TTF字体。

关键问题分析

  1. WOFF转TTF: 单纯使用woff2.decompress可能丢失ReportLab依赖的字体元数据或必要表结构,导致加载失败。
  2. OTF转TTF: fonttools的font.flavor = None仅移除OTF的格式标记,并未将PostScript轮廓转换为ReportLab要求的TrueType轮廓,因此无法正常识别。
  3. 字体匹配: ReportLab加载字体时依赖文件名与字体族名一致,这是在线工具转换后能工作的核心原因之一。

解决方案

1. WOFF转TTF(保留完整结构)

解压WOFF后验证并确保必要字体表存在:

import woff2
from fontTools.ttLib import TTFont

def woff_to_ttf(woff_path, output_ttf_path):
    # 解压WOFF到TTF
    with open(woff_path, 'rb') as woff_file, open(output_ttf_path, 'wb') as ttf_file:
        woff2.decompress(woff_file, ttf_file)
    
    # 验证必要字体表
    required_tables = ['cmap', 'head', 'hhea', 'maxp', 'name', 'post']
    font = TTFont(output_ttf_path)
    for table in required_tables:
        if table not in font:
            raise ValueError(f"转换后的字体缺少必要表:{table}")
    font.save(output_ttf_path)

2. OTF转TTF(轮廓转换)

OTF的PostScript轮廓需转为TrueType,借助fontforge完成转换:

import fontforge

def otf_to_ttf(otf_path, output_ttf_path):
    f = fontforge.open(otf_path)
    # 生成无提示、无位图的TTF
    f.generate(output_ttf_path, flags=("no-hints", "no-bitmaps"))
    f.close()

3. 确保文件名与字体族名一致

ReportLab依赖文件名匹配字体族名,转换后自动调整:

from fontTools.ttLib import TTFont
import os

def ensure_filename_matches_family(ttf_path):
    font = TTFont(ttf_path)
    # 获取字体族名,替换空格为下划线
    family_name = font['name'].getDebugName(1).replace(' ', '_')
    new_path = os.path.join(os.path.dirname(ttf_path), f"{family_name}.ttf")
    if ttf_path != new_path:
        os.rename(ttf_path, new_path)
    return new_path

4. 完整转换函数整合

import os
import shutil
import woff2
from fontTools.ttLib import TTFont
import fontforge

def convert_to_reportlab_ttf(input_path, output_dir=None):
    if output_dir is None:
        output_dir = os.path.dirname(input_path)
    
    ext = os.path.splitext(input_path)[1].lower()
    temp_ttf = os.path.join(output_dir, "temp_ttf_conversion.ttf")
    
    try:
        if ext in ('.woff', '.woff2'):
            woff_to_ttf(input_path, temp_ttf)
        elif ext == '.otf':
            otf_to_ttf(input_path, temp_ttf)
        elif ext == '.ttf':
            shutil.copy(input_path, temp_ttf)
        else:
            raise ValueError(f"不支持的字体格式:{ext}")
        
        # 调整文件名并返回最终路径
        final_ttf = ensure_filename_matches_family(temp_ttf)
        return final_ttf
    except Exception as e:
        if os.path.exists(temp_ttf):
            os.remove(temp_ttf)
        raise RuntimeError(f"字体转换失败:{str(e)}")

# 使用示例
# converted_font = convert_to_reportlab_ttf("./my_custom_font.woff")
# 将转换后的字体放在SVG同目录,运行原SVG转PNG代码即可

依赖安装

  • fonttools: pip install fonttools
  • python-woff2: pip install python-woff2
  • fontforge-python: 系统级安装,如Ubuntu用apt install fontforge-python3,Windows需下载预编译包

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 07:40:36