Github Actions + fonttools 拉取字符并创建中文字体子集
帮助解决中文字体体积过大的问题
创建子集部分参考自谢益辉老师的做法。如果你需要的中文字体在字图CDN有覆盖,用这个也能一定程度上提升性能。
本文将通过解释写好的workflow文件来展开,完整代码见最下方。
on:
workflow_dispatch:
workflow_run:
workflows: ["deploy"]
types:
- completed
告诉Github Actions什么时候自动运行,workflow_dispatch:
使得这个workflow能在对应页面手动点击运行,workflow_run:
这里我定义了使其在名字为deploy
的workflow完成后运行。
steps:
- name: Checkout repository
uses: actions/checkout@v3
checkout
把仓库的代码从Github克隆到workflow构建的运行环境中。
steps:
- name: Install fonttools
run: sudo apt-get update && sudo apt-get install -y fonttools
安装fonttools
。
steps:
- name: Extract used characters from content
run: |
mkdir -p font
find . -name '*.md' -o -name '*.html' | xargs cat \
| grep -oP '[\x{3000}-\x{30FF}\x{31F0}-\x{31FF}\x{4E00}-\x{9FFF}\x{AC00}-\x{D7AF}\x{FF00}-\x{FFEF}\x{FE10}-\x{FE1F}]' \
| sort | uniq > used-chars.txt
从所在项目的.md
和.html
提取出出现过的中日韩字符(CJK):在工作环境创建/font
文件夹,查找当前目录及子目录下所有以.md
或.html
结尾的文件,用cat
拼接成一个文件,用grep
来匹配字符范围(Unicode区间可自行重新设定),sort
排序,uniq
去重,> used-chars.txt
保存到一个文本文件。
steps:
- name: Download fonts
run: |
mkdir -p font/raw
cd font/raw
declare -A urls
urls["SourceHanSansSC-Regular"]="https://github.com/adobe-fonts/source-han-sans/raw/release/OTF/SimplifiedChinese/SourceHanSansSC-Regular.otf"
...
for name in "${!urls[@]}"; do
echo "Downloading ${name}..."
wget -nv --retry-connrefused --waitretry=1 --read-timeout=20 --timeout=15 -t 3 "${urls[$name]}" -O "${name}.otf"
done
echo "Copying local fonts STKaiti and DFKai-SB..."
cp ../../resources/STKaiti.otf .
cp ../../resources/DFKai-SB.otf .
创建/font/raw
目录来保存在线下载的中文字体文件(.otf
格式)。定义了一个关联数组urls
来储存字体名和链接。用for
遍历,用wget
下载每个字体(--retry-connrefused
访问被拒绝的话自动重试,--t 3
最多重试3次)并保存到/font/raw
中。
如果手动准备了字体(这里存储在仓库的/resources
下),用cp
也复制到/font/raw
。
- name: Subset fonts
run: |
mkdir -p font/woff2
for font in font/raw/*.otf; do
name=$(basename "$font" .otf)
pyftsubset "$font" \
--text-file=used-chars.txt \
--flavor=woff2 \
--no-hinting \
--layout-features='*' \
--output-file="font/woff2/${name}-subset.woff2"
done
创建/font/woff2
来存放生成的子集字体。
for
循环遍历.otf
字体,使用pyftsubset
生成子集字体,只保留used-chars.txt
列出的字符,输出格式为woff2
,--no-hinting
不保留字体hinting信息,--layout-features="*"
保留OpenType的功能,--output-file
指定输出文件路径。
- name: Move subset fonts to static/font
run: |
mkdir -p static/font
mv font/woff2/*.woff2 static/font/
移动到仓库的/static/font
目录下。(如果你不需要在这个仓库存一份,可以省去这一步)
- name: Commit and push subset fonts to Github Pages
env:
TOKEN: ${{ secrets.PERSONAL_TOKEN }}
run: |
git clone --depth 1 https://x-access-token:${TOKEN}@github.com/rongbinf/rongbinf.github.io.git out
cp -f static/font/*.woff2 out/font/
cp -f used-chars.txt out/font/used-chars.txt
cd out
git config user.name github-actions
git config user.email github-actions@github.com
git add font/*.woff2
git add font/used-chars.txt
git commit -m "chore: update subset Source Han Sans fonts" || echo "No changes to commit"
git push
推送到Github Pages仓库,使用环境变量TOKEN
认证Git操作(可参考之前写的自动部署Hugo教程),克隆下来到/out
后把子集字体放到/out/font
下,然后配置并push变更。
完整yml
如下:
name: Subset Source Han Sans
on:
workflow_dispatch:
workflow_run:
workflows: ["deploy"]
types:
- completed
jobs:
subset-fonts:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install fonttools
run: sudo apt-get update && sudo apt-get install -y fonttools
- name: Extract used characters from content
run: |
mkdir -p font
find . -name '*.md' -o -name '*.html' | xargs cat \
| grep -oP '[\x{3000}-\x{30FF}\x{31F0}-\x{31FF}\x{4E00}-\x{9FFF}\x{AC00}-\x{D7AF}\x{FF00}-\x{FFEF}\x{FE10}-\x{FE1F}]' \
| sort | uniq > used-chars.txt
- name: Download fonts
run: |
mkdir -p font/raw
cd font/raw
declare -A urls
urls["SourceHanSansSC-Regular"]="https://github.com/adobe-fonts/source-han-sans/raw/release/OTF/SimplifiedChinese/SourceHanSansSC-Regular.otf"
urls["SourceHanSansTC-Regular"]="https://github.com/adobe-fonts/source-han-sans/raw/release/OTF/TraditionalChinese/SourceHanSansTC-Regular.otf"
urls["SourceHanSans-Regular"]="https://github.com/adobe-fonts/source-han-sans/raw/release/OTF/Japanese/SourceHanSans-Regular.otf"
urls["SourceHanSansK-Regular"]="https://github.com/adobe-fonts/source-han-sans/raw/release/OTF/Korean/SourceHanSansK-Regular.otf"
urls["SourceHanSansSC-Bold"]="https://github.com/adobe-fonts/source-han-sans/raw/release/OTF/SimplifiedChinese/SourceHanSansSC-Bold.otf"
urls["SourceHanSansTC-Bold"]="https://github.com/adobe-fonts/source-han-sans/raw/release/OTF/TraditionalChinese/SourceHanSansTC-Bold.otf"
urls["SourceHanSans-Bold"]="https://github.com/adobe-fonts/source-han-sans/raw/release/OTF/Japanese/SourceHanSans-Bold.otf"
urls["SourceHanSansK-Bold"]="https://github.com/adobe-fonts/source-han-sans/raw/release/OTF/Korean/SourceHanSansK-Bold.otf"
for name in "${!urls[@]}"; do
echo "Downloading ${name}..."
wget -nv --retry-connrefused --waitretry=1 --read-timeout=20 --timeout=15 -t 3 "${urls[$name]}" -O "${name}.otf"
done
echo "Copying local fonts STKaiti and DFKai-SB..."
cp ../../resources/STKaiti.otf .
cp ../../resources/DFKai-SB.otf .
- name: Subset fonts
run: |
mkdir -p font/woff2
for font in font/raw/*.otf; do
name=$(basename "$font" .otf)
pyftsubset "$font" \
--text-file=used-chars.txt \
--flavor=woff2 \
--no-hinting \
--layout-features='*' \
--output-file="font/woff2/${name}-subset.woff2"
done
- name: Move subset fonts to static/font
run: |
mkdir -p static/font
mv font/woff2/*.woff2 static/font/
- name: Commit and push subset fonts to Github Pages
env:
TOKEN: ${{ secrets.PERSONAL_TOKEN }}
run: |
git clone --depth 1 https://x-access-token:${TOKEN}@github.com/rongbinf/rongbinf.github.io.git out
cp -f static/font/*.woff2 out/font/
cp -f used-chars.txt out/font/used-chars.txt
cd out
git config user.name github-actions
git config user.email github-actions@github.com
git add font/*.woff2
git add font/used-chars.txt
git commit -m "chore: update subset Source Han Sans fonts" || echo "No changes to commit"
git push