← 部落格

Text.js 中的 FIGlet 字型

@textjs/font 解析 FIGlet .flf 字型,並採用與 figlet 程式相同的版面配置。測試會重播從 figlet 2.2.5 記錄的 273 筆輸出,結果全數吻合。

Adam

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 接受相同的五種配置:

layoutfiglet效果
"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,並未隨附。

完整參考資料請見字型。