Files
cert/certgen/fonts.py
T

87 lines
2.4 KiB
Python

"""Поиск системных шрифтов (в т.ч. с кириллицей)."""
from __future__ import annotations
import subprocess
from functools import lru_cache
from pathlib import Path
SEARCH_DIRS = [
Path(__file__).resolve().parent / "assets" / "fonts", # шрифты, вложенные в проект
Path("/usr/share/fonts"),
Path("/usr/local/share/fonts"),
Path.home() / ".local/share/fonts",
Path("/Library/Fonts"),
Path("/System/Library/Fonts"),
Path("C:/Windows/Fonts"),
]
ALIASES = {
"serif": "DejaVuSerif",
"serif-bold": "DejaVuSerif-Bold",
"serif-italic": "DejaVuSerif-Italic",
"serif-bolditalic": "DejaVuSerif-BoldItalic",
"sans": "DejaVuSans",
"sans-bold": "DejaVuSans-Bold",
"sans-italic": "DejaVuSans-Oblique",
"sans-bolditalic": "DejaVuSans-BoldOblique",
"mono": "DejaVuSansMono",
}
@lru_cache(maxsize=1)
def _index() -> dict[str, str]:
idx: dict[str, str] = {}
for d in SEARCH_DIRS:
if not d.exists():
continue
for f in d.rglob("*"):
if f.suffix.lower() in (".ttf", ".otf", ".ttc"):
idx.setdefault(f.stem.lower(), str(f))
idx.setdefault(f.name.lower(), str(f))
return idx
def _fallback() -> str:
idx = _index()
for key in ("dejavusans", "dejavuserif", "liberationsans", "notosans",
"arial", "arialunicode"):
if key in idx:
return idx[key]
return next(iter(idx.values()), "")
@lru_cache(maxsize=256)
def find_font(name: str | None) -> str:
"""Вернуть путь к файлу шрифта по имени или алиасу."""
name = (name or "sans").strip()
p = Path(name)
if p.is_absolute() and p.exists():
return str(p)
key = ALIASES.get(name.lower(), name).lower()
idx = _index()
if key in idx:
return idx[key]
if key + ".ttf" in idx:
return idx[key + ".ttf"]
# частичное совпадение
matches = [v for k, v in idx.items() if key in k]
if matches:
return matches[0]
# спросим fontconfig
try:
out = subprocess.run(
["fc-match", "-f", "%{file}", name],
capture_output=True, text=True, timeout=10,
)
path = out.stdout.strip()
if path and Path(path).exists():
return path
except Exception:
pass
return _fallback()