Text.js 中的 FIGlet 字体
@textjs/font 解析 FIGlet .flf 字体,按 figlet 程序的方式布局。测试重放了从 figlet 2.2.5 记录的 273 个输出,结果全部匹配。
Text.js 0.3 新增了 @textjs/font,用于解析和渲染 FIGlet 字体。它附带 FIGlet 2.2.5 发行版中的 17 种字体,每种字体各为一个 ES 模块,输出与 figlet 2.2.5 二进制文件完全一致。
import { FigletText } from "@textjs/font/react";import { slant } from "@textjs/font/slant";export default function Page() { return <FigletText font={slant} color="accent">Text.js</FigletText>;} ______ __ _ /_ __/__ _ __/ /_ (_)____ / / / _ \| |/_/ __/ / / ___/ / / / __/> </ /__ / (__ )/_/ \___/_/|_|\__(_)_/ /____/ /___/为什么选择 FIGlet
<AsciiFont> 从 0.1 起就内置了 block 和 compact 两种字样。FIGlet 自 1991 年起就是这类字样的标准,已有数百种 .flf 字体。支持这一格式意味着其中任何一种字体都能用于控制台应用。
FIGlet 字体是纯文本文件。头部行设置高度、硬空格字符和布局规则,随后每个字符由多行组成,每行末尾都有结束标记。在默认布局中,FIGlet 将每个字符向左移动,直到触及前一个字符,再根据字体的挤压规则决定是否将两个接触的子字符合并为一个。
布局模式
figlet 有五种水平布局,renderFiglet 通过 layout 接受相同的五种布局:
layout | figlet | 效果 |
|---|---|---|
"default" | -s | 字体自身的布局,通常为挤压布局 |
"full" | -W | 完整宽度,字符互不接触 |
"fitted" | -k | 字符相向移动,直到接触 |
"smushed" | -S | 按字体规则挤压 |
"universal" | -o | 后面的字符覆盖前面的字符 |
-1 到 63 之间的数字表示原始 -m 布局模式:-1 为完整宽度,0 为贴合,1 到 63 则选择挤压规则。全部六种水平挤压规则均已实现:相同字符、下划线、层级、相对配对、大 X 和硬空格。解析器也支持该格式的其余部分:注释行、以十进制、八进制和十六进制编码标记的字符、缺失字符字形,以及 ivrit 等从右向左的字体。
换行行为也遵循 FIGlet。width 在单词边界处换行,单词宽于行时则在单词内部换行,换行位置与 figlet -w 一致。figlet -w 80 最多输出 79 列,因此 -w N 对应 width: N - 1。
与二进制文件的输出一致
packages/font/test/fixtures/references.json 保存了 273 份输出,由真实的 figlet 2.2.5 对每种内置字体在每种布局模式下运行生成,覆盖换行、对齐、从右向左文本、段落模式,以及使用 run-tests.sh 中标志运行的 FIGlet 自身回归测试输入。每个用例都保存参数、输入和精确输出,测试会将命令行还原为选项:
for (const f of flags) { if (f === "W") opts.layout = "full"; else if (f === "k") opts.layout = "fitted"; else if (f === "S") opts.layout = "smushed"; else if (f === "o") opts.layout = "universal"; else if (f === "s") opts.layout = "default"; else if (f === "c") opts.align = "center"; else if (f === "r") opts.align = "right"; else if (f === "l") opts.align = "left"; else if (f === "R") opts.direction = "rtl"; else if (f === "L") opts.direction = "ltr"; else if (f === "p") opts.paragraph = true; else throw new Error(`unsupported flag -${f}`);}273 个用例全部匹配。要重新生成测试数据,将 figlet 2.2.5 加入 PATH,然后运行 bun run --cwd packages/font references。
单元格网格中的字体
所有内置字体都用可打印的 ASCII 或 Latin-1 字符绘制,因此每个子字符在 Menlo 中恰好占一个单元格,并与网格对齐。<FigletText> 以单元格为单位测量各行,因此字样能像其他 <Text> 一样参与 flexbox 布局,columns 和 align 则控制它在自身框内的换行和对齐。
每种字体都是独立模块,因此应用只会包含导入的字体,且字体在首次渲染时解析,而非导入时。@textjs/font/all 导出所有字体,供字体展示页使用。
其他任何 FIGfont 都可以在运行时获取并解析:
import { parseFont } from "@textjs/font";const doom = parseFont(await (await fetch("/fonts/doom.flf")).text(), "Doom");许可证
内置字体与 figlet-2.2.5.tar.gz 中的字体逐字节相同,按 FIGlet 的 BSD 3-Clause 许可证分发。每种字体的注释行都保留了署名,可通过 font.comment 访问。Doom、Larry 3D、ANSI Shadow 和 Calvin S 等未授予再分发许可的热门字体不包含在内。
完整参考文档见字体。