fix: 内置DOCX双中文字体包
This commit is contained in:
+25
-65
@@ -1,9 +1,9 @@
|
||||
# 可选字体包构建
|
||||
# 内置字体包集合构建
|
||||
|
||||
本目录保存字体包配方、许可证、来源说明和正式冻结字体资产。字体二进制
|
||||
位于固定的 `font-packs/assets/`,统一由 Git LFS 管理,普通 Git 对象只保存
|
||||
LFS 指针。普通 Desktop 主安装包不包含字体;组合 Desktop 发行把字体作为
|
||||
同目录可选附件,Docker 发行构建则把本次受校验的字体包写入镜像层。
|
||||
LFS 指针。Desktop 安装版、便携版和 Docker 镜像都直接包含本次受校验的
|
||||
完整字体包集合,不再依赖用户另行安装字体附件。
|
||||
|
||||
## 源目录
|
||||
|
||||
@@ -16,10 +16,18 @@ font-packs/assets/mdtp-serif-sc/1.0.0/
|
||||
├── MdTPSerifSC-Regular.woff2
|
||||
├── MdTPSerifSC-Bold.ttf
|
||||
└── MdTPSerifSC-Bold.woff2
|
||||
|
||||
font-packs/assets/mdtp-sans-sc/1.0.0/
|
||||
├── MdTPSansSC-Regular.ttf
|
||||
├── MdTPSansSC-Regular.woff2
|
||||
├── MdTPSansSC-Bold.ttf
|
||||
└── MdTPSansSC-Bold.woff2
|
||||
```
|
||||
|
||||
该目录中的 `ttf/otf/woff/woff2` 由 `.gitattributes` 强制使用 Git LFS。
|
||||
构建器不会联网下载、转换或自动替换字体。每个输入文件都必须与配方声明的
|
||||
构建器不会联网下载或自动替换字体。派生字体通过
|
||||
`font-packs/scripts/build-noto-static.py` 从来源说明固定的 Noto CJK
|
||||
可变字体生成;每个发行输入文件都必须与配方声明的
|
||||
字节数和 SHA-256 完全一致;TTF 还必须是无需运行时规范化的原生静态
|
||||
TrueType,并具有可安装或可编辑的文档嵌入权限。
|
||||
|
||||
@@ -30,17 +38,13 @@ npm run build:font-pack
|
||||
npm run verify:font-pack
|
||||
```
|
||||
|
||||
也可以显式指定源目录:
|
||||
|
||||
```powershell
|
||||
npm run build:font-pack -- --source-root D:/font-pack-sources/mdtp-serif-sc/1.0.0
|
||||
```
|
||||
|
||||
克隆仓库后应先执行 `git lfs pull`。缺少 LFS 内容时,字体构建会因文件大小
|
||||
或 SHA-256 不匹配而拒绝继续,不允许使用系统字体或相近字体静默替代。
|
||||
|
||||
默认运行时字体包根目录为 `output/font-packs/root`,构建报告写入
|
||||
`output/font-packs/build-report.json`,两者均被 Git 忽略。输出布局为:
|
||||
受版本控制的 `font-packs/bundle.json` 是正式字体包集合清单。构建命令会
|
||||
逐包构建、验证,并拒绝 `output/font-packs/root` 中出现清单外字体包,
|
||||
避免本地残留进入发行产物。各包报告写入
|
||||
`output/font-packs/<pack-id>-build-report.json`。输出布局为:
|
||||
|
||||
```text
|
||||
root/<pack-id>/<semver>/font-pack.json
|
||||
@@ -53,34 +57,12 @@ root/<pack-id>/<semver>/font-pack.json
|
||||
`Mdpdf Fandol Song` 的 400/700 字重,不匹配 `SimSun` 等通用别名,避免
|
||||
错误替换仿宋、黑体、楷体或普通外部主题字体。
|
||||
|
||||
## Windows 独立安装器
|
||||
`mdtp-sans-sc@1.0.0` 提供 `MdTP Sans SC`、`FandolHei`、
|
||||
`Microsoft YaHei`、`PingFang SC`、`Noto Sans CJK SC` 和
|
||||
`Source Han Sans SC` 的 400/700 字重映射。主题仍需明确声明所需字体面,
|
||||
注册器不会对未声明字体进行静默替换。
|
||||
|
||||
发布人员可以使用 electron-builder 锁定并校验的 NSIS 工具链构建独立
|
||||
字体包安装器,不需要额外安装系统 NSIS:
|
||||
|
||||
```powershell
|
||||
npm run build:font-pack:windows
|
||||
```
|
||||
|
||||
默认产物为:
|
||||
|
||||
```text
|
||||
output/font-packs/windows/
|
||||
└── MorphDoc-FontPack-mdtp-serif-sc-1.0.0-x86_64-Setup.exe
|
||||
```
|
||||
|
||||
安装器使用当前用户权限,将整个 `mdtp-serif-sc` ID 安装到:
|
||||
|
||||
```text
|
||||
%LOCALAPPDATA%/md-to-pdf/font-packs/mdtp-serif-sc/1.0.0/
|
||||
```
|
||||
|
||||
它不向 Windows 系统字体目录注册字体。同一版本重装保持幂等,升级时先把
|
||||
该 ID 的现有目录移入备份,再原子提升新版本;失败会回滚。独立卸载项只
|
||||
删除安装器拥有的 `mdtp-serif-sc` ID,不影响其他字体包 ID。安装器支持
|
||||
`/S` 静默安装和卸载。
|
||||
|
||||
## Desktop 伴随发行
|
||||
## Desktop 内置发行
|
||||
|
||||
组合构建命令为:
|
||||
|
||||
@@ -88,32 +70,10 @@ output/font-packs/windows/
|
||||
npm run desktop:make:with-font-pack
|
||||
```
|
||||
|
||||
该命令把主安装器、字体包安装器和字体包 ZIP 作为同目录文件发行。主安装器
|
||||
只编译字体包安装器的文件名与 SHA-256,不嵌入字体二进制;仅当同目录文件
|
||||
存在且哈希完全一致时,交互安装向导才显示默认勾选的字体包选项。字体包
|
||||
失败不回滚已安装的主程序。
|
||||
|
||||
主安装器静默运行时默认不安装伴随字体包;只有显式传入以下参数才会安装:
|
||||
|
||||
```powershell
|
||||
MorphDoc-<version>-x86_64-Setup.exe /S /WITHFONTPACK=1
|
||||
```
|
||||
|
||||
普通 `npm run make -w @md-to-pdf/desktop` 不启用伴随逻辑,避免本地残留的
|
||||
生成文件影响常规桌面构建。
|
||||
|
||||
## ZIP 发行附件
|
||||
|
||||
独立生成可手动部署的确定性 ZIP:
|
||||
|
||||
```powershell
|
||||
npm run build:font-pack:archive
|
||||
```
|
||||
|
||||
产物为 `output/font-packs/release/MorphDoc-FontPack-mdtp-serif-sc-1.0.0.zip`。
|
||||
归档顶层已经包含 `mdtp-serif-sc/1.0.0/`,用户可直接解压到
|
||||
`%LOCALAPPDATA%/md-to-pdf/font-packs`。ZIP 内保留清单、许可证、来源说明
|
||||
以及 Web/DOCX 两类字体资产;相同输入会生成逐字节一致的附件。
|
||||
该命令先重建完整字体包集合,再构建主安装器和便携 ZIP。electron-builder
|
||||
把 `output/font-packs/root` 复制到 `resources/font-packs`;Desktop 生产
|
||||
运行时优先读取该只读内置根目录,再读取用户目录中的额外字体包。内置包
|
||||
因此不会被缺失、旧版或同 ID 用户包替换。
|
||||
|
||||
## Docker 内置发行
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"packs": [
|
||||
{
|
||||
"id": "mdtp-serif-sc",
|
||||
"version": "1.0.0",
|
||||
"recipe": "font-packs/recipes/mdtp-serif-sc/recipe.json",
|
||||
"sourceRoot": "font-packs/assets/mdtp-serif-sc/1.0.0"
|
||||
},
|
||||
{
|
||||
"id": "mdtp-sans-sc",
|
||||
"version": "1.0.0",
|
||||
"recipe": "font-packs/recipes/mdtp-sans-sc/recipe.json",
|
||||
"sourceRoot": "font-packs/assets/mdtp-sans-sc/1.0.0"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
Copyright 2012 Google Inc. All Rights Reserved.
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License,
|
||||
Version 1.1.
|
||||
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font
|
||||
creation efforts of academic and linguistic communities, and to
|
||||
provide a free and open framework in which fonts may be shared and
|
||||
improved in partnership with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply to
|
||||
any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software
|
||||
components as distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to,
|
||||
deleting, or substituting -- in part or in whole -- any of the
|
||||
components of the Original Version, by changing formats or by porting
|
||||
the Font Software to a new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed,
|
||||
modify, redistribute, and sell modified and unmodified copies of the
|
||||
Font Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components, in
|
||||
Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the
|
||||
corresponding Copyright Holder. This restriction only applies to the
|
||||
primary font name as presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created using
|
||||
the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
@@ -0,0 +1,29 @@
|
||||
# MdTP Sans SC 字体来源说明
|
||||
|
||||
本字体包的 Regular 400 与 Bold 700 字形面派生自 Noto Sans SC 可变字体。
|
||||
|
||||
- 上游项目:Noto CJK
|
||||
- 上游仓库:<https://github.com/notofonts/noto-cjk>
|
||||
- Google Fonts 源提交:`985fa52c81c1d6692ccdd82bc3656e8fb932fd89`
|
||||
- 上游源文件:`google-fonts/NotoSansSC[wght].ttf`
|
||||
- 上游源 SHA-256:`b1736bb633392cfc59b50d97c353d234111bd1721c9c83eaf643eaab9392e7f9`
|
||||
- 许可证:SIL Open Font License 1.1
|
||||
|
||||
发行字形面使用 fontTools 4.60.1 从 `wght` 轴固定生成,并将主字体家族改名
|
||||
为 `MdTP Sans SC`、PostScript 前缀改名为 `MdTPSansSC`。改名用于明确
|
||||
标识派生版本,并避免派生字体占用上游字体名称。字形轮廓与字符覆盖未做
|
||||
删减;`OS/2.fsType` 为 0,允许安装和文档嵌入。
|
||||
|
||||
可复现生成命令:
|
||||
|
||||
```powershell
|
||||
python font-packs/scripts/build-noto-static.py `
|
||||
--source .local/font-pack-upstream/NotoSansSC-wght.ttf `
|
||||
--output font-packs/assets/mdtp-sans-sc/1.0.0 `
|
||||
--family "MdTP Sans SC" `
|
||||
--postscript-family MdTPSansSC
|
||||
```
|
||||
|
||||
字体包构建器不从网络下载字体。发布人员必须先核对固定上游文件的
|
||||
SHA-256,再生成配方声明的四个冻结资源;构建器会继续校验文件大小、
|
||||
SHA-256、格式、字体内部家族、字重与嵌入权限。
|
||||
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"recipeVersion": 1,
|
||||
"manifestVersion": 1,
|
||||
"id": "mdtp-sans-sc",
|
||||
"version": "1.0.0",
|
||||
"name": "MdTP 中文黑体兼容包",
|
||||
"description": "为现代文档与商务主题提供经过 Word/WPS 验证的原生静态中文黑体 Regular 与 Bold 字形面。",
|
||||
"internalFamily": "MdTP Sans SC",
|
||||
"license": "OFL-1.1",
|
||||
"licenseSource": "OFL-NotoSansSC.txt",
|
||||
"licensePath": "OFL-NotoSansSC.txt",
|
||||
"licenseBytes": 4350,
|
||||
"licenseSha256": "5e0da210fb04058a8c0087985d2d456b931c2579811a49655721d3cf0c36b6d6",
|
||||
"noticeSource": "SOURCE.md",
|
||||
"noticePath": "SOURCE.md",
|
||||
"compatibility": {
|
||||
"minimumAppVersion": "0.6.0"
|
||||
},
|
||||
"faces": [
|
||||
{
|
||||
"id": "sans-regular",
|
||||
"targets": ["MdTP Sans SC", "FandolHei", "Microsoft YaHei", "PingFang SC", "Noto Sans CJK SC", "Source Han Sans SC"],
|
||||
"weight": 400,
|
||||
"style": "normal",
|
||||
"web": {
|
||||
"source": "MdTPSansSC-Regular.woff2",
|
||||
"path": "fonts/MdTPSansSC-Regular.woff2",
|
||||
"bytes": 4192788,
|
||||
"sha256": "45f4ea0072861106b028f975b05752c13b46541dc84799e2746a657593c0c62d"
|
||||
},
|
||||
"docx": {
|
||||
"source": "MdTPSansSC-Regular.ttf",
|
||||
"path": "fonts/MdTPSansSC-Regular.ttf",
|
||||
"bytes": 10596656,
|
||||
"sha256": "a1d7e9c407d664c6d13ab9c01c48eca6775d77fd6daa3448c41ff7f1a3f316e1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "sans-bold",
|
||||
"targets": ["MdTP Sans SC", "FandolHei", "Microsoft YaHei", "PingFang SC", "Noto Sans CJK SC", "Source Han Sans SC"],
|
||||
"weight": 700,
|
||||
"style": "normal",
|
||||
"web": {
|
||||
"source": "MdTPSansSC-Bold.woff2",
|
||||
"path": "fonts/MdTPSansSC-Bold.woff2",
|
||||
"bytes": 4314832,
|
||||
"sha256": "729e7b445a1db47e588597eaacecebb892ef4de331379ff2439fb0be95aa808a"
|
||||
},
|
||||
"docx": {
|
||||
"source": "MdTPSansSC-Bold.ttf",
|
||||
"path": "fonts/MdTPSansSC-Bold.ttf",
|
||||
"bytes": 10586172,
|
||||
"sha256": "85fcfab7284fd72dfbbdb1a579230a9034dc6f9fc351b40cecd34d46125eebd6"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
"""从固定的 Noto CJK 可变字体生成墨呈静态字体面。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
from fontTools.ttLib import TTFont
|
||||
from fontTools.varLib.instancer import instantiateVariableFont
|
||||
|
||||
|
||||
def set_name(font: TTFont, name_id: int, value: str) -> None:
|
||||
name_table = font["name"]
|
||||
for platform_id, encoding_id, language_id in (
|
||||
(3, 1, 0x0409),
|
||||
(1, 0, 0),
|
||||
):
|
||||
name_table.setName(
|
||||
value,
|
||||
name_id,
|
||||
platform_id,
|
||||
encoding_id,
|
||||
language_id,
|
||||
)
|
||||
|
||||
|
||||
def build_face(
|
||||
source: Path,
|
||||
output_root: Path,
|
||||
family: str,
|
||||
postscript_family: str,
|
||||
weight: int,
|
||||
style: str,
|
||||
) -> None:
|
||||
font = TTFont(source, recalcTimestamp=False)
|
||||
instantiateVariableFont(font, {"wght": weight}, inplace=True, optimize=True)
|
||||
|
||||
set_name(font, 1, family)
|
||||
set_name(font, 2, style)
|
||||
set_name(font, 4, f"{family} {style}")
|
||||
set_name(font, 6, f"{postscript_family}-{style}")
|
||||
set_name(font, 16, family)
|
||||
set_name(font, 17, style)
|
||||
set_name(font, 25, postscript_family)
|
||||
font["OS/2"].usWeightClass = weight
|
||||
font["OS/2"].fsType = 0
|
||||
|
||||
output_root.mkdir(parents=True, exist_ok=True)
|
||||
ttf_path = output_root / f"{postscript_family}-{style}.ttf"
|
||||
font.flavor = None
|
||||
font.save(ttf_path, reorderTables=False)
|
||||
|
||||
woff2_path = output_root / f"{postscript_family}-{style}.woff2"
|
||||
font.flavor = "woff2"
|
||||
font.save(woff2_path, reorderTables=False)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--source", type=Path, required=True)
|
||||
parser.add_argument("--output", type=Path, required=True)
|
||||
parser.add_argument("--family", required=True)
|
||||
parser.add_argument("--postscript-family", required=True)
|
||||
arguments = parser.parse_args()
|
||||
|
||||
build_face(
|
||||
arguments.source,
|
||||
arguments.output,
|
||||
arguments.family,
|
||||
arguments.postscript_family,
|
||||
400,
|
||||
"Regular",
|
||||
)
|
||||
build_face(
|
||||
arguments.source,
|
||||
arguments.output,
|
||||
arguments.family,
|
||||
arguments.postscript_family,
|
||||
700,
|
||||
"Bold",
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user