Files
cjk-autospace/tools/measure-bias.py
T
admin 3a4fa1c932 fix: 修复行缘、切分还原与语言解析并同步文档
保留逐字 margin/jiya.bias 字体后备方案;补齐 demo 重排、量测边界说明及共享规则 1.0.1 反例向量。

验证:完整构建通过,Node 376 项、WKWebView 64 项及原生 demo 9 项通过;Firefox 仍暂缓。
2026-10-03 21:15:54 +08:00

104 lines
3.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""量測字型之標點 glyph 墨色位置,產出聚珍 margin 後備模式之偏側建議表。
用途:消費端字型缺 OpenType `halt`(如方正書宋 GBK、多數系統字型)時,margin 後備
模式需知每個標點之「墨色偏側」以於 0.5em 半形盒內正確定位字身。本工具讀字型輪廓,
量各標點 glyph 之 ink bounding box,依墨色中心建議 left/center/right/full,並印出
可貼入 `options.jiya.bias` 之 JSON 片段。
只量預設 cmap glyph,未做 shaping、未應用 `locl`;語言參數僅選 JSON 的語言分類鍵,
不切換字型的語言字形。`halt` feature 存在也不保證涵蓋所有標點。建議表須按瀏覽器
實際字形逐字微調,尤其是會依語言替換 glyph 的字型。
依賴:fonttools(`pip install fonttools`)。
用法:python3 tools/measure-bias.py /path/to/font.ttf [zh-Hans|zh-Hant|ja|other]
輸出之偏側語義(決定字身於 0.5em 盒內之左移;見 README「halt/margin 後備」):
left 墨偏左 → 不移(字身左對齊,墨在盒內、右側空白溢出)
center 墨居中 → 左移 0.25em
right 墨偏右 → 左移 0.5em(右半入盒,左側空白溢出)
full 無 glyph/空白 glyph → 不收、維持全形
門檻:ink 中心 < 0.375 → left;0.375–0.625 → center;> 0.625 → right。
判讀後仍建議於瀏覽器目視微調(字身側鬚、字面留白因字型而異)。
"""
import json
import sys
from fontTools.pens.boundsPen import BoundsPen
from fontTools.ttLib import TTFont
# 聚珍 margin 模式會收半形之標點(句末點號僅半角式收,此處一併量供參考)。
PUNCT = {
"pause_stop": ",、。.;:!?",
"open": "「『(《〈【〖〔[{“‘",
"close": "」』)》〉】〗〕]}”’",
}
def has_feature(font, tag):
for t in ("GSUB", "GPOS"):
if t in font and font[t].table.FeatureList:
for fr in font[t].table.FeatureList.FeatureRecord:
if fr.FeatureTag == tag:
return True
return False
def bias_of(font, upm, cmap, gs, ch):
cp = ord(ch)
if cp not in cmap:
return "full", None
g = gs[cmap[cp]]
pen = BoundsPen(gs)
g.draw(pen)
if pen.bounds is None:
return "full", None
x_min, _, x_max, _ = pen.bounds
center = ((x_min + x_max) / 2) / upm
if center < 0.375:
b = "left"
elif center > 0.625:
b = "right"
else:
b = "center"
return b, center
def main():
if len(sys.argv) < 2:
print(__doc__)
sys.exit(1)
path = sys.argv[1]
lang = sys.argv[2] if len(sys.argv) > 2 else "zh-Hans"
font = TTFont(path)
upm = font["head"].unitsPerEm
cmap = font.getBestCmap()
gs = font.getGlyphSet()
halt = has_feature(font, "halt")
print(f"# 字型:{path}")
print(f"# OpenType halt:{'有(feature 存在不保證涵蓋所有標點,須逐字確認)' if halt else '無 → 可用 margin 後備模式'}")
print(f"# unitsPerEm={upm}")
print("# 量測預設 cmap glyph,未做 shaping/未應用 locl;語言參數僅選 JSON 分類鍵。")
print("# 請按瀏覽器實際字形逐字微調建議表。")
print()
table = {}
for group, chars in PUNCT.items():
print(f"# {group}")
for ch in chars:
b, center = bias_of(font, upm, cmap, gs, ch)
cstr = f"{center:.2f}" if center is not None else " - "
print(f"# {ch} inkcenter={cstr} -> {b}")
table[ch] = b
print()
print("// 貼入 options.jiya.bias(依瀏覽器目視再微調):")
print(json.dumps({lang: table}, ensure_ascii=False, indent=2))
if __name__ == "__main__":
main()