如何解码 Base64 字体
- 在 Base64 或 data URI 中粘贴以下任意一种:纯 Base64、
data:font/woff2;base64,d09GMg…这样的 data URI,或包含 data URI 的 CSS。如果一条规则中有多个src条目,使用第一个 data URI。 - 预览会用全字母句“The quick brown fox jumps over the lazy dog 0123456789”和一行完整字母表显示字体。在 示例文本 中输入内容,可以试试你自己的文字。
- 信息列表显示字体文件对自身的描述:字体族、样式、全名、版本、字形数 和 每 em 单位数。
- 点击 下载文件,以其格式对应的扩展名保存。
浏览器接受字体后,信息下方的状态行会显示“已使用解码后的字体渲染。”。字体以一个私有名称注册,只在本页有效,解码其他内容时会被移除;页面的内容安全策略只允许 Cloudflare 的浏览量统计这一项网络通信,所以文件哪里也不会去。
支持的格式及工具能读取的信息
| Base64 开头 | 格式 | 名称和字形数 |
|---|---|---|
AAEAAAA | TrueType(.ttf) | 读取 |
T1RUTw | 使用 CFF 轮廓的 OpenType(.otf) | 读取 |
dHRjZg | TrueType 或 OpenType 集合(.ttc),一个文件包含多个字体 | 读取第一个字体的信息,以及字体数量 |
d09GRg | WOFF 1.0,字体表经 zlib 压缩 | 读取 |
d09GMg | WOFF2,字体表经 Brotli 压缩(封装 CFF 轮廓时为 d09GMk9UVE8) | 不读取 |
对于 WOFF2,字体族一行显示“未读取(WOFF2 表经过 Brotli 压缩)”:本页自己不解压 Brotli,而能解压的浏览器字体引擎不会对外提供结果。渲染不受影响,所以你仍然可以看出字体是否正常。保存后要读取名称,可以用 fontconfig 的 fc-scan,它支持 WOFF2:
fc-scan --format "%{family}: %{style}\n" font.woff2
对于 Material Icons 字体,它会输出 Material Icons: Regular。
字体无法渲染时
“你的浏览器拒绝了此字体,它可能已损坏或不是字体文件。”表示浏览器的字体安全检查拒绝了这个文件。Chrome 和 Firefox 在使用每个网页字体之前都会检查其结构错误,被截断的字体,或从更大的文件中按错误偏移量截取出来的字体,都无法通过检查。请把解码后的大小与原始大小对比;丢失了末尾的 Base64 字符串解码后,字体的最后一个表是损坏的。
如果信息列表显示了名称,但示例一直是空的,说明字体中没有你输入内容的字形。以下情况会出现这种问题:
- 图标字体:它们的符号位于私用区码位,例如
U+E000及以上。使用连字的字体,比如 Material Icons,在输入图标名称时会显示图标,例如home。 - 子集字体:网页往往只嵌入需要的字符,有时只有几十个。字形数 会显示文件包含多少个字形。
- 其他文字的字体:为阿拉伯文或天城文设计的字体可能没有拉丁字母。
如果数据根本不是字体,提示会指出它是什么,例如“这看起来是 PDF,而不是字体。”等,并附带相应的下载按钮。
Base64 字体从哪里来
大多数来自 CSS。构建工具会把小字体以 data: URI 的形式内联到样式表中,单文件 HTML 导出、离线报告以及带文字的 SVG 文件也用同样的方式携带字体。内联是有代价的,因为嵌入的字体无法与样式表分开缓存;详情见 data URI 的性能。要把字体文件转换成这样的规则,请使用 字体转 Base64。
用 Python 从样式表中提取所有字体
工具只解码它找到的第一个 data URI。如果样式表中嵌入了多个字体,一个简短的脚本就能以正确的扩展名把它们全部保存下来:
import base64, re
SIGNATURES = {b"wOF2": "woff2", b"wOFF": "woff", b"OTTO": "otf", b"\x00\x01\x00\x00": "ttf", b"ttcf": "ttc"}
css = open("icons.css").read()
pattern = r"data:[^;,]*(?:;[^;,]*)*;base64,([A-Za-z0-9+/=\s]+)"
for i, b64 in enumerate(re.findall(pattern, css)):
data = base64.b64decode(b64)
ext = SIGNATURES.get(data[:4], "bin")
with open(f"font-{i}.{ext}", "wb") as f:
f.write(data)
print(f"font-{i}.{ext}", len(data), "bytes")
扩展名根据前四个字节确定,因为样式表对字体的标注往往很随意(application/font-woff、application/octet-stream)。更多内容见 Python 中的 Base64。
常见问题
怎么从 CSS 的 Base64 中提取字体?
把整条 @font-face 规则或其中的 url(data:…) 部分粘贴到上方的输入框。工具会提取 data URI,预览字体,并通过 下载文件 以与其格式相符的扩展名保存。
为什么我的 WOFF2 字体族名称显示“未读取”?
WOFF2 用 Brotli 压缩了所有字体表,而本页不解压 Brotli,所以 name 表无法读取。字体在预览中仍能正常渲染,保存后用 fc-scan 或任意字体编辑器都能看到名称。
为什么示例文本是空白的,或者全是方框?
字体很可能没有这些字符的字形。图标字体把符号放在私用区码位上,子集化的网页字体通常只包含某个页面用到的字母;请输入字体实际覆盖的字符。
保存后能安装这个字体吗?
TTF 和 OTF 文件可以直接在 Windows、macOS 和 Linux 上安装。WOFF 和 WOFF2 是网页格式,桌面系统通常要求先转换为 TTF 或 OTF;而字体能否使用,要看字体的许可协议。