本專案是基於 ayaka14732/OpenCCFontGenerator 的分支版本,由 tbdavid2019 維護。
感谢原作者 ayaka14732 的出色工作,奠定了本工具的核心基礎。本分支在原版基礎上新增了以下功能:
- Kindle 極致優化:針對 Kindle 等閱讀器缺字問題,自動將缺少的簡體編碼直接映射到繁體字形 (cmap mapping),確保不回退系統字型。
- 變體補全 (Variant Supplement):自動補全字型中缺少的異體字編碼(如「妳」對應到「你」),大幅減少缺字率。
- WOFF2 支援:支援
.woff2作為輸入字型,並可選擇同時輸出 WOFF2 格式。 - Webfont 生成器:獨立的 WOFF2 轉換工具,自動產出
@font-faceCSS 範例。 - 偽直排旋轉 (90° Rotation):針對舊型電子書設備,提供將字元順時針旋轉 90 度(躺平)的功能。
- 多樣化轉換標準:支援
s2hk(香港)、s2tw(台灣) 與t2s(繁轉簡) 等 OpenCC 標準。 - 字型補全 (Glyph Fallback):自動從備用字型提取並注入缺失的字形,徹底解決缺字 (豆腐塊) 問題。
- 通用型 Merge Font 模式:可選擇保留來源字庫,並把 fallback 中來源缺少的所有 codepoint 一起合併進輸出字型。
- Variable CJK Family Builder:將 variable 拉丁字型展開成多個權重,並與對應 CJK fallback 字型合成一整套 family。
- Static Font Family Builder:將一個或一整組非 variable 的靜態字型批次處理,並依字重自動配對對應的 fallback 字型。
--no-punc:可選擇性地排除標點符號的轉換。--force-vertical:自動替換標點符號為直排形式(適合電子書直排字型)。start.py:互動式精靈啟動器,提供引導式問答介面。
將 OpenCC 簡繁轉換邏輯嵌入 OpenType 字型,使用者下載並安裝字型後,所有文字將自動以目標字形呈現,無需任何軟體設定。
Embed OpenCC conversion rules into an OpenType font. Once installed, any application that renders with the font will automatically display target glyphs (Traditional or Simplified) — no software configuration required.
本工具會在字型的 GSUB(字形替換)表中建立 OpenCC 替換規則,並掛到標準 OpenType feature(如 liga、rlig、ccmp),利用 OpenCC 字典將字形映射到對應的目標字形,包含詞彙層面的多對一替換(例如「软件」→「軟體」)。
當開啟「字型補全」功能時,程式會檢查來源字型是否缺少目標字元,並自動從備用字型中抓取所需的字形數據注入到輸出字型中。
即使來源字型本身沒有 GSUB 或 GPOS 表,也可正常完成缺字補全與清理流程。
如果您第一次接觸字型內部結構,可以先把字型想成一個小型資料庫:
glyph(字形)是字型裡實際拿來畫在螢幕或紙上的圖形單位。
它不等於 Unicode 字元本身。
例如:
- Unicode
U+4F60是字元「你」 - 字型裡可能有一個 glyph 叫
uni4F60 - 也可能有不同 glyph 對應同一個字元,例如直排版、異體字、簡繁替代字
所以:
- 字元(character) 是文字編碼概念
- glyph 是字型內部的圖形資產
cmap 是 character map,負責把「Unicode codepoint」對到「glyph」。
例如:
U+4F60->uni4F60U+3001->uni3001
沒有 cmap,系統就不知道您輸入的字元應該拿哪個 glyph 來顯示。
glyf 是 TrueType 字型中存放 glyph 輪廓資料的表。
它描述這個 glyph 長什麼樣子,例如:
- 輪廓點
- 曲線
- composite references(引用其他 glyph 組成新的 glyph)
可以這樣記:
cmap決定「用哪個 glyph」glyf決定「那個 glyph 長怎樣」
GSUB 是 Glyph Substitution,也就是「字形替換表」。
它會在排版時,把一個 glyph 或一串 glyph 換成另一個 glyph 或 glyph 串。
常見用途:
- 連字:
f+i->fi - 簡轉繁:
后->後 - 詞級替換:
软件->軟體 - 直排替代字形
本專案的核心,就是大量利用 GSUB 來實作 OpenCC 簡繁轉換。
這通常是因為缺字回退 (Font Fallback)。
如果您的輸入字型是純繁體字型(例如 jf金萱),它可能完全沒有收錄簡體字碼位的編碼。在舊版邏輯中,程式因為發現來源字型沒有簡體字編碼,會跳過該字的轉換規則。當 Kindle 顯示這些簡體字時,因為字型不含這些碼位,Kindle 會自動改用系統預設字型顯示,導致看起來像是沒轉好。
為了徹底解決這個問題,本分支引進了以下機制:
-
cmap 直接映射:
- 只要目標繁體字在字型中,程式會直接在字型的
cmap表中加入對應簡體字的編碼,並指向該繁體字形。 - 這是一種「硬核」轉換,不依賴軟體是否支援 OpenType 特性,在所有電子書閱讀器上都有效。
- 只要目標繁體字在字型中,程式會直接在字型的
-
變體補全 (Variant Supplementing):
- 讀取
Variants.txt等異體字表,自動將字型中缺少的異體字(如「妳」)編碼指向現有的對應字形(如「你」)。 - 這能最大程度利用字型現有資源,減少「豆腐塊」缺字現象。
- 讀取
GPOS 是 Glyph Positioning,也就是「字形定位表」。
它不負責換字形,而是負責調整 glyph 的位置或間距。
常見用途:
- kerning 字距微調
- 注音或重音符號定位
- 複雜文字排版時的位置修正
- 標點或組合符號的精細對齊
所以差別是:
GSUB= 換 glyphGPOS= 不換 glyph,只調整位置
glyph:字型裡的一個實際字形cmap:字元 -> glyph 的對照表glyf:glyph 的輪廓資料GSUB:glyph 替換規則GPOS:glyph 定位規則
下面這張圖可以幫助理解:當應用程式顯示文字時,字型內部大致會經過哪些步驟。
flowchart TD
A["輸入文字 / Unicode 字元<br/>例如:软件"] --> B["cmap<br/>把字元對應到初始 glyph"]
B --> C["初始 glyph 串<br/>例如:uni8F6F + uni4EF6"]
C --> D["GSUB<br/>依規則替換 glyph"]
D --> E["替換後 glyph 串<br/>例如:uni8EDF + uni9AD4"]
E --> F["GPOS<br/>調整字距、位置、標點對齊"]
F --> G["glyf<br/>讀取每個 glyph 的輪廓資料"]
G --> H["最後顯示在螢幕或紙上"]
用更白話的方式講:
- 使用者輸入的是 Unicode 文字。
cmap先決定每個字元要拿哪個 glyph。GSUB再視需要把 glyph 換成另一個 glyph,或換成整串新的 glyph。GPOS負責把這些 glyph 排好位置。glyf提供每個 glyph 的實際形狀,最後才被畫出來。
本專案做的事情,主要就是在這個流程中強化 GSUB,並在缺字時補上必要的 cmap 與 glyf 資料。
本工具輸出的 _TC 字型,不是「完整保留原始字庫再額外加上簡繁轉換」的 full-copy 字型。
原因是 OpenType 字型的 glyph 數量上限約為 65535。本專案為了實現 OpenCC 的詞彙級轉換,會額外建立大量中介用 pseudo glyph 與 GSUB 規則;若同時完整保留原始字型的大型字庫,常會超過格式上限而無法編譯。
因此目前輸出策略是:
- 優先保留 OpenCC 詞彙級轉換所需的 Han 字與常用非 Han 範圍
- 移除部分原始字型中不在保留範圍內的字元與對應 glyph
- 加入詞彙替換所需的 pseudo glyph 與 GSUB lookup
這表示 _TC 輸出字型更接近「針對 OpenCC 轉換優化的 subset font」,而不是原字型的完整鏡像副本。
如果您的需求是:
- 盡量保留原始字型的完整字庫
- 同時仍要保有 OpenCC 的完整詞彙級轉換
那麼在大型字型上,這兩個目標可能會因 OpenType glyph 上限而互相衝突。
pip install -r requirements.txt
python setup.py build # 下載 OpenCC 資料並生成快取 (包含新標準)同時需要安裝 otfcc(otfccdump 與 otfccbuild)。
如果您在 macOS 並希望自動管理環境,請直接執行:
sh run.sh此腳本會自動建立虛擬環境、建置快取並啟動精靈。
如果您已自行設定好環境,請執行:
python start.py... (Steps 1-10 unchanged)
針對僅支援水平顯示的舊型電子書設備,您可以使用此功能讓字體「躺平」,旋轉設備後即可像直排一樣閱讀。
最佳實踐 (Best Practice):
- 執行
sh run.sh:先將您的簡體字型轉換為 繁體字型 (如_TC.ttf)。 - 執行
sh run90.sh:輸入剛生成的繁體字型,將其 順時針旋轉 90 度。 - 輸出結果為
_TC_Rotated90.ttf。
sh run90.sh功能特點:
- 幾何中心旋轉: 以字元中心點旋轉,確保排版整齊。
- 僅旋轉漢字選項: 支援中英混排,讓英數保留原樣,僅中文字躺平。
- 全域度量修正: 自動調整字高與寬度,模擬直排等寬感。
| 腳本 | 主要功能 | 適用場景 |
|---|---|---|
run.sh |
OpenCC 轉換 (精靈) | 核心功能,將簡體字型轉為繁體 (支援 WOFF2) |
run90.sh |
90度順時針旋轉 (精靈) | 進階功能,針對不支援直排的舊設備進行偽直排處理 |
runVF.sh |
Variable CJK Family Builder (精靈) | 將 variable 拉丁字型展開成多權重 CJK family |
runSTATIC.sh |
Static Font Family Builder (精靈) | 批次處理單一靜態字型或整組靜態字重 family |
runWEBFONT.sh |
Webfont 轉換 (精靈) | 獨立功能,將 TTF/OTF 轉為 WOFF2 並產出 CSS |
start.py |
核心轉換對話入口 | 手動啟動 OpenCC 轉換精靈 |
start90.py |
旋轉對話入口 | 手動啟動 90 度旋轉精靈 |
startVF.py |
Variable Family 對話入口 | 手動啟動 variable 拉丁 + CJK fallback 合成精靈 |
startSTATIC.py |
Static Family 對話入口 | 手動啟動靜態字型批次處理精靈 |
startWEBFONT.py |
Webfont 對話入口 | 手動啟動 Webfont 轉換精靈 |
python -m OpenCCFontGenerator \
-i <來源字型> \
-o <輸出字型> \
[--woff2] \
[--config <s2t|twp|s2tw|s2hk|t2s>] \
[--fallback-font <備用字型路徑>] \
[--merge-mode <opencc|universal>] \
[--fill-charset <none|hant-common|opencc-hant|han>] \
[--font-name <新字型名稱>] \
[--font-version <版本號碼>] \
[--no-punc] \
[--force-vertical]| 參數 | 說明 | 必填 |
|---|---|---|
-i, --input-file |
來源字型路徑(.ttf / .otf / .ttc / .woff2) | ✅ |
-o, --output-file |
輸出字型路徑 | ✅ |
--woff2 |
是否額外輸出 WOFF2 格式 | ❌ |
--kobo |
開啟 Kobo eReader 相容模式,強制清理 metadata | ❌ |
--config |
OpenCC 配置(預設: s2t) |
❌ |
--fallback-font |
備用字型路徑(用於補齊缺字) | ❌ |
--merge-mode |
補字模式:opencc 僅補轉換目標字;universal 會保留來源字庫並合併 fallback 缺少字元 |
❌ |
--fill-charset |
先主動從 fallback 補指定字集;hant-common 適合先補常用繁中字區 |
❌ |
--font-name |
新字型的名稱 | ❌ |
--font-version |
覆寫字型版本號碼 | ❌ |
--twp |
快捷鍵:啟用台灣慣用語轉換 (等同 --config twp) |
❌ |
--no-punc |
排除標點符號的轉換 | ❌ |
--force-vertical |
強制直排模式 | ❌ |
Kobo eReader 對於側載字型 (sideloaded fonts) 的元資料(metadata)解析非常嚴格。如果輸出的字型在 Kobo 上出現無法群組、未辨識,或中文字型名稱顯示亂碼等問題,請加上 --kobo 參數(或在互動精靈中開啟)。
這個模式會:
- 將 Family Name (家族名稱) 中的空格去除。
- 強制過濾掉
nametable 中非 ASCII、或非純英文(如zh-TW繁中)的字串紀錄,確保 Kobo 只能讀取乾淨的英文命名紀錄,以避免它隨機挑選到無法解析的中文名稱。
當您將一個原本只有簡體字的字型轉換為繁體時,如果該字型檔案中根本沒有繁體字形,轉換後的文字會變成「豆腐塊」。
現在,您可以指定一個「備用字型」(例如:思源黑體繁體版),工具會自動從中提取缺失的繁體字形並合併到您的輸出字型中。
預設情況下,--fallback-font 的作用是補齊轉換目標所需的缺字,不會改變本工具整體的 subset 輸出策略。
如果您的來源字型本身繁中字區不完整,建議搭配 --fill-charset hant-common,先主動從 fallback 補常用繁中字集,再進行 OpenCC 轉換。
python -m OpenCCFontGenerator \
-i MyFont.ttf \
-o MyFont_TC.ttf \
--fallback-font NotoSansTC-Regular.ttf \
--fill-charset hant-common \
--merge-mode universal目前支援的值有:
nonehant-commonopencc-hanthan
請注意:在目前版本中,hant-common / opencc-hant / han 三者在實作上暫時等價,都會使用專案內建的 Han codepoint cache 先補字。
也就是說,現階段它們的差別主要是語意命名,方便未來拆分成更細的補字策略:
han:偏廣義 Han 字集合hant-common:偏常用繁中字集opencc-hant:偏 OpenCC 轉換相關繁中字集
如果您目前的目標是:
- 先補足來源字型缺少的繁體中文字
- 再讓 OpenCC 自動把簡體顯示成繁體
那麼這是可以同時做到的,建議直接使用:
--fill-charset hant-common --merge-mode universal --config s2t這組參數的意義是:
- 先從 fallback 補常用繁中字
- 再保留來源字庫並合併其他缺字
- 最後套用 OpenCC 簡轉繁規則
所以答案不是「沒法既要又要」,而是:
- 可以既要又要
- 只是要先補字,再做 OpenCC
- 目前最推薦的組合就是
hant-common + universal + s2t
如果您需要更接近「通用型 merge font」的行為,可以改用:
python -m OpenCCFontGenerator \
-i MyFont.ttf \
-o MyFontMerged.ttf \
--fallback-font FallbackFont.ttf \
--merge-mode universaluniversal 模式會:
- 保留來源字型原本的
cmap字庫 - 將 fallback 字型中來源缺少的 codepoint 一起併入
- 仍可選擇疊加 OpenCC 規則
請注意:
- 大型字型更容易碰到 OpenType 約
65535glyph 上限 - 目前主要合併
cmap、glyf與基本 metrics;不是完整整併兩套字型排版系統的 full font editor
如果您的來源字型是像 MonoLisaVariableNormal.ttf 這類 variable font,但本身只有英數、沒有繁體中文,那麼比較務實的做法不是硬做成單一真正的 variable CJK font,而是:
- 將 variable font 依常見權重展開成多個 static instance
例如:Thin / Regular / Medium / Bold / Black - 為每個權重找對應的 CJK fallback 字型
例如:NotoSansTC-Regular.ttf、NotoSansTC-Bold.ttf - 逐個權重執行
merge_mode=universal合成 - 最後輸出一整套可安裝、可選重的 CJK family
您可以直接執行:
sh runVF.sh這個流程適合:
- 英數保留 variable 拉丁字型風格
- 中文由 Noto 或其他 CJK 字型補齊
- 同時保留 OpenCC 簡繁轉換能力
請注意:
- 這會得到「一整套多權重 family」
- 不是單一真正的 variable CJK 字型
- 如果 fallback 本身是 static 字型,中文部分不會真正擁有 variable interpolation 資料
- 目前
runVF.sh預設也會先執行fill-charset = hant-common,優先補常用繁中字
如果您的來源不是 variable font,而是一個或一整組靜態字型,例如:
MyFont-Regular.ttfMyFont-Medium.ttfMyFont-Bold.ttf
那麼可以使用:
sh runSTATIC.sh這個流程會:
- 接受單一字型檔,或整個資料夾
- 自動依檔名判斷字重,例如
Regular / Medium / Bold - 從 fallback 資料夾中尋找對應字重的字型
- 逐個權重套用 OpenCC 與 fallback 合成
- 批次輸出整組
_TC字型
適合場景:
- 您手上的來源字型不是 variable font
- 想把一整組靜態字重 family 一次轉完
- 想搭配
NotoSansTC-*或其他靜態 CJK fallback 字型 - 想在轉換前先主動補足常用繁中字區
如果來源本身只有單一靜態字型,也可以使用這個流程;它會把它當成只有一個成員的 family 來處理。
python -m OpenCCFontGenerator \
-i MySimplifiedFont.ttf \
-o MyNewTraditionalFont.ttf \
--fallback-font SourceHanSansTC-Regular.otf當開啟此模式時,工具會自動尋找字型內部的 vert 或 vrt2 排版功能,並將標點符號的映射直接指向直排版字形。適合不支援 OpenType 特性的電子書閱讀器。
GPL — 任何衍生作品或採用本程式碼的專案,均須以相同授權條款開放原始碼。

