- M3 认证/权限/审计/限流 + 全部 REST 接口 - M4 管理面板(MIUIx + 成绩录入/积分榜下钻/大屏控制) - M5a 大屏页面(六页 + 明细覆盖层 + 缩放适配) - M6 WebSocket 实时同步中心 - M7 xlsx 导出 + 赛事包 zip + 备份 - 规则包 YAML 导入导出(差异预览) - 字体 vendor 子集化(4 套 x2 字重) - 集成:realtime/export/rules 接入 main+httpapi;backup 子命令 - 修复:中间件包装 ResponseWriter 丢失 Hijacker,导致 WS 握手 501
82 lines
2.8 KiB
Python
82 lines
2.8 KiB
Python
#!/usr/bin/env python3
|
||
"""把子集字体内部的 name 表 / OS2 字重统一成 CSS 期望的规范值。
|
||
|
||
为什么需要:思源黑体的老版本 OTF 把每个字重写成独立族名
|
||
(`Source Han Sans CN Regular` / `Source Han Sans CN Bold`),
|
||
MiSans 的 usWeightClass 是 330/630 这类非标准值。
|
||
@font-face 的 `font-family` 描述符虽然能屏蔽内部族名,但保持一致更省心,
|
||
也避免字体被单独安装/引用时族名对不上。
|
||
|
||
用法(由 subset-fonts.sh 调用):
|
||
python3 vendor/fonts/tools/normalize-names.py
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
from fontTools.ttLib import TTFont
|
||
|
||
HERE = Path(__file__).resolve().parent
|
||
OUT_DIR = HERE.parent
|
||
CONF = HERE / "fonts.conf"
|
||
|
||
WEIGHTS = (("regular", "Regular", 400), ("bold", "Bold", 700))
|
||
STALE_NAME_IDS = (1, 2, 3, 4, 6, 16, 17, 21, 22)
|
||
PLATFORMS = ((3, 1, 0x409), (1, 0, 0)) # Windows / Mac,英文
|
||
|
||
|
||
def set_name(name, name_id: int, value: str) -> None:
|
||
for platform_id, plat_enc_id, lang_id in PLATFORMS:
|
||
name.setName(value, name_id, platform_id, plat_enc_id, lang_id)
|
||
|
||
|
||
def normalize(path: Path, family: str, style: str, weight: int) -> None:
|
||
font = TTFont(path)
|
||
name = font["name"]
|
||
for record in list(name.names):
|
||
if record.nameID in STALE_NAME_IDS:
|
||
name.removeNames(record.nameID, record.platformID, record.platEncID, record.langID)
|
||
|
||
full_name = family if style == "Regular" else f"{family} {style}"
|
||
set_name(name, 1, family) # family
|
||
set_name(name, 2, style) # subfamily
|
||
set_name(name, 3, f"{full_name}:subset") # unique id
|
||
set_name(name, 4, full_name) # full name
|
||
set_name(name, 6, full_name.replace(" ", "")) # postscript name
|
||
set_name(name, 16, family) # typographic family
|
||
set_name(name, 17, style) # typographic subfamily
|
||
|
||
os2 = font["OS/2"]
|
||
os2.usWeightClass = weight
|
||
if weight >= 700:
|
||
os2.fsSelection = (os2.fsSelection & ~0x40) | 0x20 # BOLD
|
||
font["head"].macStyle |= 0x01
|
||
else:
|
||
os2.fsSelection = (os2.fsSelection & ~0x20) | 0x40 # REGULAR
|
||
font["head"].macStyle &= ~0x01
|
||
|
||
font.flavor = "woff2"
|
||
font.save(path)
|
||
font.close()
|
||
|
||
|
||
def main() -> int:
|
||
for line in CONF.read_text(encoding="utf-8").splitlines():
|
||
line = line.strip()
|
||
if not line or line.startswith("#"):
|
||
continue
|
||
fid, _, family = [p.strip() for p in line.split("|")][:3]
|
||
for weight_name, style, weight_class in WEIGHTS:
|
||
path = OUT_DIR / f"{fid}-{weight_name}.woff2"
|
||
if not path.is_file():
|
||
print(f"缺少产物: {path}", file=sys.stderr)
|
||
return 1
|
||
normalize(path, family, style, weight_class)
|
||
print(f" {path.name:32s} -> {family} / {style} ({weight_class})")
|
||
return 0
|
||
|
||
|
||
if __name__ == "__main__":
|
||
raise SystemExit(main())
|