maple-font/source/py/utils.py
2024-12-27 10:17:56 +08:00

184 lines
5.8 KiB
Python

from os import environ, path, remove
import platform
import shutil
import subprocess
from urllib.request import Request, urlopen
from zipfile import ZipFile
from fontTools.ttLib import TTFont
from glyphsLib import GSFont
def is_ci():
ci_envs = [
"JENKINS_HOME",
"TRAVIS",
"CIRCLECI",
"GITHUB_ACTIONS",
"GITLAB_CI",
"TF_BUILD",
]
for env in ci_envs:
if environ.get(env):
return True
return False
def run(command, extra_args=None, log=not is_ci()):
"""
Run a command line interface (CLI) command.
"""
if extra_args is None:
extra_args = []
if isinstance(command, str):
command = command.split()
subprocess.run(command + extra_args, stdout=subprocess.DEVNULL if not log else None)
def set_font_name(font: TTFont, name: str, id: int):
font["name"].setName(name, nameID=id, platformID=1, platEncID=0, langID=0x0)
font["name"].setName(name, nameID=id, platformID=3, platEncID=1, langID=0x409)
def get_font_name(font: TTFont, id: int) -> str:
return (
font["name"]
.getName(nameID=id, platformID=3, platEncID=1, langID=0x409)
.__str__()
)
def del_font_name(font: TTFont, id: int):
font["name"].removeNames(nameID=id)
def joinPaths(*args: list[str]) -> str:
return "/".join(args)
def get_font_forge_bin():
WIN_FONTFORGE_PATH = "C:/Program Files (x86)/FontForgeBuilds/bin/fontforge.exe"
MAC_FONTFORGE_PATH = (
"/Applications/FontForge.app/Contents/Resources/opt/local/bin/fontforge"
)
LINUX_FONTFORGE_PATH = "/usr/bin/fontforge"
system_name = platform.uname()[0]
result = ""
if "Darwin" in system_name:
result = MAC_FONTFORGE_PATH
elif "Windows" in system_name:
result = WIN_FONTFORGE_PATH
else:
result = LINUX_FONTFORGE_PATH
if not path.exists(result):
result = shutil.which("fontforge")
return result
def parse_github_mirror(github_mirror: str) -> str:
github = environ.get("GITHUB") # custom github mirror, for CN users
if not github:
github = github_mirror
return f"https://{github}"
def download_zip_and_extract(
name: str, url: str, zip_path: str, output_dir: str, remove_zip: bool = False
) -> bool:
try:
if not path.exists(zip_path):
try:
print(f"{name} does not exist, download from {url}")
user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
req = Request(url, headers={"User-Agent": user_agent})
with urlopen(req) as response, open(zip_path, "wb") as out_file:
total_size = int(response.getheader("Content-Length").strip())
downloaded_size = 0
block_size = 8192
while True:
buffer = response.read(block_size)
if not buffer:
break
out_file.write(buffer)
if not is_ci():
downloaded_size += len(buffer)
percent_downloaded = (downloaded_size / total_size) * 100
print(
f"Downloading {name}: [{percent_downloaded:.2f}%] {downloaded_size} / {total_size}",
end="\r",
)
except Exception as e:
print(
f"\nFail to download {name}. Please check your internet connection or download it manually from {url}, then put downloaded zip into project's root and run this script again. \n Error: {e}"
)
return False
with ZipFile(zip_path, "r") as zip_ref:
zip_ref.extractall(output_dir)
if remove_zip:
remove(zip_path)
return True
except Exception as e:
print(f"Download zip and extract failed, error: {e}")
return False
def check_font_patcher(
version: str, github_mirror: str = "github.com", target_dir: str = "FontPatcher"
) -> bool:
bin_path = f"{target_dir}/font-patcher"
if path.exists(target_dir):
with open(bin_path, "r", encoding="utf-8") as f:
if f"# Nerd Fonts Version: {version}" in f.read():
return True
else:
print("FontPatcher version not match, delete it")
shutil.rmtree("FontPatcher", ignore_errors=True)
zip_path = "FontPatcher.zip"
url = f"{parse_github_mirror(github_mirror)}/ryanoasis/nerd-fonts/releases/download/v{version}/{zip_path}"
if not download_zip_and_extract(
name="Nerd Font Patcher", url=url, zip_path=zip_path, output_dir=target_dir
):
return False
with open(bin_path, "r", encoding="utf-8") as f:
if f"# Nerd Fonts Version: {version}" in f.read():
return True
print(f"FontPatcher version is not {version}, please download it from {url}")
return False
def download_cn_base_font(
tag: str, zip_path: str, target_dir: str, github_mirror: str = "github.com"
) -> bool:
url = f"{parse_github_mirror(github_mirror)}/subframe7536/maple-font/releases/download/{tag}/{zip_path}"
return download_zip_and_extract(
name=f"{'Static' if 'static' in zip_path else 'Variable'} CN Base Font",
url=url,
zip_path=zip_path,
output_dir=target_dir,
)
def match_unicode_names(file_path: str) -> dict[str, str]:
font = GSFont(file_path)
result = {}
for glyph in font.glyphs:
glyph_name = glyph.name
unicode_values = glyph.unicode
if glyph_name and unicode_values:
unicode_str = f"uni{''.join(unicode_values).upper().zfill(4)}"
result[unicode_str]=glyph_name
return result