#!/usr/bin/env python3 """量測字型之標點 glyph 墨色位置,產出聚珍 margin 後備模式之偏側建議表。 用途:消費端字型缺 OpenType `halt`(如方正書宋 GBK、多數系統字型)時,margin 後備 模式需知每個標點之「墨色偏側」以於 0.5em 半形盒內正確定位字身。本工具讀字型輪廓, 量各標點 glyph 之 ink bounding box,依墨色中心建議 left/center/right/full,並印出 可貼入 `options.jiya.bias` 之 JSON 片段。 依賴: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:{'有(建議直接用 halt 預設模式,無需 margin 後備)' if halt else '無 → 需 margin 後備模式'}") print(f"# unitsPerEm={upm}") 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()