fix: 内置DOCX双中文字体包
This commit is contained in:
@@ -41,6 +41,11 @@ module.exports = {
|
|||||||
to: "samples",
|
to: "samples",
|
||||||
filter: ["**/*"]
|
filter: ["**/*"]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
from: "../../output/font-packs/root",
|
||||||
|
to: "font-packs",
|
||||||
|
filter: ["**/*"]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
from: `.runtime/pandoc/${pandocRuntime.version}/windows-x86_64`,
|
from: `.runtime/pandoc/${pandocRuntime.version}/windows-x86_64`,
|
||||||
to: `pandoc/${pandocRuntime.version}/windows-x86_64`,
|
to: `pandoc/${pandocRuntime.version}/windows-x86_64`,
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ function getDesktopThemeDirectory() {
|
|||||||
: path.resolve(currentDirectory, "../../..", ".local", "themes");
|
: path.resolve(currentDirectory, "../../..", ".local", "themes");
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDesktopFontPackDirectory() {
|
function getDesktopUserFontPackDirectory() {
|
||||||
if (!app.isPackaged) {
|
if (!app.isPackaged) {
|
||||||
return path.resolve(
|
return path.resolve(
|
||||||
currentDirectory,
|
currentDirectory,
|
||||||
@@ -147,6 +147,15 @@ function getDesktopFontPackDirectory() {
|
|||||||
|
|
||||||
function createDesktopApplicationService() {
|
function createDesktopApplicationService() {
|
||||||
const projectRoot = path.resolve(currentDirectory, "../../..");
|
const projectRoot = path.resolve(currentDirectory, "../../..");
|
||||||
|
const fontPackRoots = app.isPackaged
|
||||||
|
? [
|
||||||
|
path.join(process.resourcesPath, "font-packs"),
|
||||||
|
getDesktopUserFontPackDirectory()
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
path.join(projectRoot, "output", "font-packs", "root"),
|
||||||
|
getDesktopUserFontPackDirectory()
|
||||||
|
];
|
||||||
return createApplicationService({
|
return createApplicationService({
|
||||||
bundledRoot: app.isPackaged
|
bundledRoot: app.isPackaged
|
||||||
? path.join(process.resourcesPath, "themes")
|
? path.join(process.resourcesPath, "themes")
|
||||||
@@ -155,7 +164,7 @@ function createDesktopApplicationService() {
|
|||||||
createAssetUrl: (themeId, assetPath) =>
|
createAssetUrl: (themeId, assetPath) =>
|
||||||
`${APP_SCHEME}://${THEME_HOST}/${encodeURIComponent(themeId)}/${encodeThemeAssetPath(assetPath)}`,
|
`${APP_SCHEME}://${THEME_HOST}/${encodeURIComponent(themeId)}/${encodeThemeAssetPath(assetPath)}`,
|
||||||
fontPacks: {
|
fontPacks: {
|
||||||
roots: [getDesktopFontPackDirectory()],
|
roots: fontPackRoots,
|
||||||
appVersion: app.getVersion(),
|
appVersion: app.getVersion(),
|
||||||
createAssetUrl: (
|
createAssetUrl: (
|
||||||
packId,
|
packId,
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ describe("桌面发行构建链", () => {
|
|||||||
"npm run prepare:pandoc"
|
"npm run prepare:pandoc"
|
||||||
);
|
);
|
||||||
expect(rootManifest.scripts?.["desktop:package"]).toBe(
|
expect(rootManifest.scripts?.["desktop:package"]).toBe(
|
||||||
"npm run package -w @md-to-pdf/desktop"
|
"npm run build:font-pack && npm run package -w @md-to-pdf/desktop"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -180,32 +180,28 @@ describe("桌面发行构建链", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("仅在组合构建时接入经过哈希校验的同目录字体包", () => {
|
it("在安装版与便携版中强制内置完整字体包集合", () => {
|
||||||
const builderConfig = readFileSync(
|
const builderConfig = readFileSync(
|
||||||
`${desktopRoot}/electron-builder.config.cjs`,
|
`${desktopRoot}/electron-builder.config.cjs`,
|
||||||
"utf8"
|
"utf8"
|
||||||
);
|
);
|
||||||
const installerInclude = readFileSync(
|
const desktopMain = readFileSync(
|
||||||
`${desktopRoot}/build/installer.nsh`,
|
`${desktopRoot}/src/main.ts`,
|
||||||
"utf8"
|
"utf8"
|
||||||
);
|
);
|
||||||
const companionBuild = readFileSync(
|
const bundledBuild = readFileSync(
|
||||||
`${projectRoot}/scripts/build-desktop-with-font-pack.mjs`,
|
`${projectRoot}/scripts/build-desktop-with-font-pack.mjs`,
|
||||||
"utf8"
|
"utf8"
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(builderConfig).toContain("MD_TO_PDF_NSIS_INCLUDE");
|
expect(builderConfig).toContain('../../output/font-packs/root');
|
||||||
expect(installerInclude).toContain("FONT_PACK_COMPANION_SHA256");
|
expect(builderConfig).toContain('to: "font-packs"');
|
||||||
expect(installerInclude).toContain("StdUtils.HashFile");
|
expect(desktopMain).toContain(
|
||||||
expect(installerInclude).toContain("/WITHFONTPACK=");
|
'path.join(process.resourcesPath, "font-packs")'
|
||||||
expect(companionBuild).toContain("createDesktopCompanionInclude");
|
|
||||||
expect(companionBuild).toContain("MD_TO_PDF_NSIS_INCLUDE");
|
|
||||||
expect(companionBuild).toContain(
|
|
||||||
"MorphDoc-FontPack-mdtp-serif-sc-1.0.0-x86_64-Setup.exe"
|
|
||||||
);
|
|
||||||
expect(companionBuild).toContain(
|
|
||||||
"MorphDoc-FontPack-mdtp-serif-sc-1.0.0.zip"
|
|
||||||
);
|
);
|
||||||
|
expect(desktopMain).toContain("getDesktopUserFontPackDirectory()");
|
||||||
|
expect(bundledBuild).not.toContain("createDesktopCompanionInclude");
|
||||||
|
expect(bundledBuild).toContain("已生成内置字体包");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("将 DOCX Lua Filter 复制到桌面主进程资源目录", () => {
|
it("将 DOCX Lua Filter 复制到桌面主进程资源目录", () => {
|
||||||
|
|||||||
@@ -166,6 +166,7 @@ ENV HOST=127.0.0.1 \
|
|||||||
FONT_PACK_ROOT=/app/.local/font-packs
|
FONT_PACK_ROOT=/app/.local/font-packs
|
||||||
|
|
||||||
RUN test -f /app/.local/font-packs/mdtp-serif-sc/1.0.0/font-pack.json
|
RUN test -f /app/.local/font-packs/mdtp-serif-sc/1.0.0/font-pack.json
|
||||||
|
RUN test -f /app/.local/font-packs/mdtp-sans-sc/1.0.0/font-pack.json
|
||||||
|
|
||||||
USER pwuser
|
USER pwuser
|
||||||
|
|
||||||
|
|||||||
@@ -15,12 +15,10 @@ const image = process.env.MD_TO_PDF_IMAGE?.trim() || "md-to-pdf:local";
|
|||||||
const fontPackRoot = path.resolve(
|
const fontPackRoot = path.resolve(
|
||||||
path.join(repositoryRoot, "output", "font-packs", "root")
|
path.join(repositoryRoot, "output", "font-packs", "root")
|
||||||
);
|
);
|
||||||
const manifestPath = path.join(
|
const expectedFontPacks = [
|
||||||
fontPackRoot,
|
{ id: "mdtp-serif-sc", version: "1.0.0" },
|
||||||
"mdtp-serif-sc",
|
{ id: "mdtp-sans-sc", version: "1.0.0" }
|
||||||
"1.0.0",
|
];
|
||||||
"font-pack.json"
|
|
||||||
);
|
|
||||||
|
|
||||||
function assert(condition, message) {
|
function assert(condition, message) {
|
||||||
if (!condition) {
|
if (!condition) {
|
||||||
@@ -126,7 +124,14 @@ assert(
|
|||||||
fontPackStatus?.isDirectory(),
|
fontPackStatus?.isDirectory(),
|
||||||
`未找到有效字体包根目录:${fontPackRoot}。请先运行 npm run build:font-pack。`
|
`未找到有效字体包根目录:${fontPackRoot}。请先运行 npm run build:font-pack。`
|
||||||
);
|
);
|
||||||
const localManifest = await readFile(manifestPath);
|
const localManifests = await Promise.all(
|
||||||
|
expectedFontPacks.map(async (pack) => ({
|
||||||
|
...pack,
|
||||||
|
content: await readFile(
|
||||||
|
path.join(fontPackRoot, pack.id, pack.version, "font-pack.json")
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
);
|
||||||
const buildEnvironment = {
|
const buildEnvironment = {
|
||||||
...process.env,
|
...process.env,
|
||||||
MD_TO_PDF_IMAGE: image
|
MD_TO_PDF_IMAGE: image
|
||||||
@@ -137,7 +142,9 @@ run(
|
|||||||
{ env: buildEnvironment }
|
{ env: buildEnvironment }
|
||||||
);
|
);
|
||||||
run("docker", ["image", "inspect", image], { capture: true });
|
run("docker", ["image", "inspect", image], { capture: true });
|
||||||
const embeddedManifestHash = run(
|
const embeddedManifestHashes = {};
|
||||||
|
for (const manifest of localManifests) {
|
||||||
|
const embeddedHash = run(
|
||||||
"docker",
|
"docker",
|
||||||
[
|
[
|
||||||
"run",
|
"run",
|
||||||
@@ -145,14 +152,16 @@ const embeddedManifestHash = run(
|
|||||||
"--entrypoint",
|
"--entrypoint",
|
||||||
"sha256sum",
|
"sha256sum",
|
||||||
image,
|
image,
|
||||||
"/app/.local/font-packs/mdtp-serif-sc/1.0.0/font-pack.json"
|
`/app/.local/font-packs/${manifest.id}/${manifest.version}/font-pack.json`
|
||||||
],
|
],
|
||||||
{ capture: true }
|
{ capture: true }
|
||||||
).split(/\s+/u)[0];
|
).split(/\s+/u)[0];
|
||||||
assert(
|
assert(
|
||||||
embeddedManifestHash === sha256(localManifest),
|
embeddedHash === sha256(manifest.content),
|
||||||
"镜像内字体包清单与本次受校验构建产物不一致"
|
`镜像内字体包清单不一致:${manifest.id}@${manifest.version}`
|
||||||
);
|
);
|
||||||
|
embeddedManifestHashes[`${manifest.id}@${manifest.version}`] = embeddedHash;
|
||||||
|
}
|
||||||
|
|
||||||
const port = await freePort();
|
const port = await freePort();
|
||||||
const projectName = `morphdoc-font-pack-${randomUUID().slice(0, 8)}`;
|
const projectName = `morphdoc-font-pack-${randomUUID().slice(0, 8)}`;
|
||||||
@@ -237,7 +246,7 @@ try {
|
|||||||
`${JSON.stringify(
|
`${JSON.stringify(
|
||||||
{
|
{
|
||||||
image,
|
image,
|
||||||
embeddedManifestSha256: embeddedManifestHash,
|
embeddedManifestSha256: embeddedManifestHashes,
|
||||||
runtimeFontPackMount: false,
|
runtimeFontPackMount: false,
|
||||||
fontPackAvailable: true,
|
fontPackAvailable: true,
|
||||||
pandocVersion: capability.detectedVersion,
|
pandocVersion: capability.detectedVersion,
|
||||||
|
|||||||
+10
-1
@@ -1502,7 +1502,16 @@ ECharts 第二阶段浏览器与 PDF 验证结果:
|
|||||||
总计 76 个阻断问题;`formal-feasibility--landscape--binding` 验证 A4
|
总计 76 个阻断问题;`formal-feasibility--landscape--binding` 验证 A4
|
||||||
横向、非对称装订边距和独立封面整页 strict 门禁,封面因墨迹与边缘
|
横向、非对称装订边距和独立封面整页 strict 门禁,封面因墨迹与边缘
|
||||||
IoU 不达标被阻断;全仓库测试、类型检查、生产构建和差异检查通过;
|
IoU 不达标被阻断;全仓库测试、类型检查、生产构建和差异检查通过;
|
||||||
- 阶段 D:修复主题封面、块元素样式和字体解析、嵌入、回退;
|
- 阶段 D:进行中。字体门禁已扩展到 PDF 实际字体解析、DOCX 声明与嵌入
|
||||||
|
数量,以及 Word/WPS 是否真正采用 Office 嵌入别名。字体资产第一批已
|
||||||
|
新增 `mdtp-sans-sc@1.0.0` 静态 TrueType/WOFF2,与现有
|
||||||
|
`mdtp-serif-sc@1.0.0` 组成受 `font-packs/bundle.json` 约束的确定性
|
||||||
|
双字体包集合;Desktop 安装版和便携版改为直接内置,Docker 同步执行
|
||||||
|
双清单哈希验证,不再依赖可选伴随安装器。`red-briefing` 与
|
||||||
|
`gov-red-standard` 已收敛为每主题三个中文字体面,真实 Chromium、Word、
|
||||||
|
WPS 输出均实际采用 MdTP 宋体/黑体,DOCX 各包含三个字体部件且字体门禁
|
||||||
|
失败为 0。下一步将同一映射规则扩展到其余 12 套主题,再修复封面和正文
|
||||||
|
语义块视觉差异;
|
||||||
- 阶段 E:完成源码服务、Docker Web API、Desktop 安装版发布后复验;
|
- 阶段 E:完成源码服务、Docker Web API、Desktop 安装版发布后复验;
|
||||||
- 阶段 F:完成 `v0.6.1` 版本、发行说明、发布产物、发布提交和标签。
|
- 阶段 F:完成 `v0.6.1` 版本、发行说明、发布产物、发布提交和标签。
|
||||||
|
|
||||||
|
|||||||
+25
-65
@@ -1,9 +1,9 @@
|
|||||||
# 可选字体包构建
|
# 内置字体包集合构建
|
||||||
|
|
||||||
本目录保存字体包配方、许可证、来源说明和正式冻结字体资产。字体二进制
|
本目录保存字体包配方、许可证、来源说明和正式冻结字体资产。字体二进制
|
||||||
位于固定的 `font-packs/assets/`,统一由 Git LFS 管理,普通 Git 对象只保存
|
位于固定的 `font-packs/assets/`,统一由 Git LFS 管理,普通 Git 对象只保存
|
||||||
LFS 指针。普通 Desktop 主安装包不包含字体;组合 Desktop 发行把字体作为
|
LFS 指针。Desktop 安装版、便携版和 Docker 镜像都直接包含本次受校验的
|
||||||
同目录可选附件,Docker 发行构建则把本次受校验的字体包写入镜像层。
|
完整字体包集合,不再依赖用户另行安装字体附件。
|
||||||
|
|
||||||
## 源目录
|
## 源目录
|
||||||
|
|
||||||
@@ -16,10 +16,18 @@ font-packs/assets/mdtp-serif-sc/1.0.0/
|
|||||||
├── MdTPSerifSC-Regular.woff2
|
├── MdTPSerifSC-Regular.woff2
|
||||||
├── MdTPSerifSC-Bold.ttf
|
├── MdTPSerifSC-Bold.ttf
|
||||||
└── MdTPSerifSC-Bold.woff2
|
└── 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。
|
该目录中的 `ttf/otf/woff/woff2` 由 `.gitattributes` 强制使用 Git LFS。
|
||||||
构建器不会联网下载、转换或自动替换字体。每个输入文件都必须与配方声明的
|
构建器不会联网下载或自动替换字体。派生字体通过
|
||||||
|
`font-packs/scripts/build-noto-static.py` 从来源说明固定的 Noto CJK
|
||||||
|
可变字体生成;每个发行输入文件都必须与配方声明的
|
||||||
字节数和 SHA-256 完全一致;TTF 还必须是无需运行时规范化的原生静态
|
字节数和 SHA-256 完全一致;TTF 还必须是无需运行时规范化的原生静态
|
||||||
TrueType,并具有可安装或可编辑的文档嵌入权限。
|
TrueType,并具有可安装或可编辑的文档嵌入权限。
|
||||||
|
|
||||||
@@ -30,17 +38,13 @@ npm run build:font-pack
|
|||||||
npm run verify: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 内容时,字体构建会因文件大小
|
克隆仓库后应先执行 `git lfs pull`。缺少 LFS 内容时,字体构建会因文件大小
|
||||||
或 SHA-256 不匹配而拒绝继续,不允许使用系统字体或相近字体静默替代。
|
或 SHA-256 不匹配而拒绝继续,不允许使用系统字体或相近字体静默替代。
|
||||||
|
|
||||||
默认运行时字体包根目录为 `output/font-packs/root`,构建报告写入
|
受版本控制的 `font-packs/bundle.json` 是正式字体包集合清单。构建命令会
|
||||||
`output/font-packs/build-report.json`,两者均被 Git 忽略。输出布局为:
|
逐包构建、验证,并拒绝 `output/font-packs/root` 中出现清单外字体包,
|
||||||
|
避免本地残留进入发行产物。各包报告写入
|
||||||
|
`output/font-packs/<pack-id>-build-report.json`。输出布局为:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
root/<pack-id>/<semver>/font-pack.json
|
root/<pack-id>/<semver>/font-pack.json
|
||||||
@@ -53,34 +57,12 @@ root/<pack-id>/<semver>/font-pack.json
|
|||||||
`Mdpdf Fandol Song` 的 400/700 字重,不匹配 `SimSun` 等通用别名,避免
|
`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 工具链构建独立
|
## Desktop 内置发行
|
||||||
字体包安装器,不需要额外安装系统 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 伴随发行
|
|
||||||
|
|
||||||
组合构建命令为:
|
组合构建命令为:
|
||||||
|
|
||||||
@@ -88,32 +70,10 @@ output/font-packs/windows/
|
|||||||
npm run desktop:make:with-font-pack
|
npm run desktop:make:with-font-pack
|
||||||
```
|
```
|
||||||
|
|
||||||
该命令把主安装器、字体包安装器和字体包 ZIP 作为同目录文件发行。主安装器
|
该命令先重建完整字体包集合,再构建主安装器和便携 ZIP。electron-builder
|
||||||
只编译字体包安装器的文件名与 SHA-256,不嵌入字体二进制;仅当同目录文件
|
把 `output/font-packs/root` 复制到 `resources/font-packs`;Desktop 生产
|
||||||
存在且哈希完全一致时,交互安装向导才显示默认勾选的字体包选项。字体包
|
运行时优先读取该只读内置根目录,再读取用户目录中的额外字体包。内置包
|
||||||
失败不回滚已安装的主程序。
|
因此不会被缺失、旧版或同 ID 用户包替换。
|
||||||
|
|
||||||
主安装器静默运行时默认不安装伴随字体包;只有显式传入以下参数才会安装:
|
|
||||||
|
|
||||||
```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 两类字体资产;相同输入会生成逐字节一致的附件。
|
|
||||||
|
|
||||||
## Docker 内置发行
|
## 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()
|
||||||
+4
-6
@@ -25,13 +25,11 @@
|
|||||||
"dev:web": "npm run dev -w @md-to-pdf/web",
|
"dev:web": "npm run dev -w @md-to-pdf/web",
|
||||||
"dev:desktop": "npm run dev -w @md-to-pdf/desktop",
|
"dev:desktop": "npm run dev -w @md-to-pdf/desktop",
|
||||||
"desktop:dev": "npm run build -w @md-to-pdf/markdown-echarts && npm run build -w @md-to-pdf/core && npm run build -w @md-to-pdf/semantic-document && npm run build -w @md-to-pdf/font-pack-registry && npm run build -w @md-to-pdf/docx-engine && npm run build -w @md-to-pdf/renderer && npm run build -w @md-to-pdf/application && npm run build -w @md-to-pdf/preview-engine && concurrently -k -n web,desktop \"npm:dev:web\" \"npm:dev:desktop\"",
|
"desktop:dev": "npm run build -w @md-to-pdf/markdown-echarts && npm run build -w @md-to-pdf/core && npm run build -w @md-to-pdf/semantic-document && npm run build -w @md-to-pdf/font-pack-registry && npm run build -w @md-to-pdf/docx-engine && npm run build -w @md-to-pdf/renderer && npm run build -w @md-to-pdf/application && npm run build -w @md-to-pdf/preview-engine && concurrently -k -n web,desktop \"npm:dev:web\" \"npm:dev:desktop\"",
|
||||||
"desktop:package": "npm run package -w @md-to-pdf/desktop",
|
"desktop:package": "npm run build:font-pack && npm run package -w @md-to-pdf/desktop",
|
||||||
"build:font-pack": "npm run build -w @md-to-pdf/core && npm run build -w @md-to-pdf/docx-theme-engine && npm run build -w @md-to-pdf/font-pack-registry && npm run build -w @md-to-pdf/docx-engine && npm run build -w @md-to-pdf/font-pack-builder && node packages/font-pack-builder/dist/cli.js build",
|
"build:font-pack": "npm run build -w @md-to-pdf/core && npm run build -w @md-to-pdf/docx-theme-engine && npm run build -w @md-to-pdf/font-pack-registry && npm run build -w @md-to-pdf/docx-engine && npm run build -w @md-to-pdf/font-pack-builder && node scripts/build-font-packs.mjs",
|
||||||
"verify:font-pack": "npm run build -w @md-to-pdf/core && npm run build -w @md-to-pdf/docx-theme-engine && npm run build -w @md-to-pdf/font-pack-registry && npm run build -w @md-to-pdf/docx-engine && npm run build -w @md-to-pdf/font-pack-builder && node packages/font-pack-builder/dist/cli.js verify",
|
"verify:font-pack": "npm run build:font-pack",
|
||||||
"verify:docker-font-pack": "npm run verify:font-pack && npm run build:web-runtime && npm run build -w @md-to-pdf/server && node deploy/verify-font-pack-compose.mjs",
|
"verify:docker-font-pack": "npm run verify:font-pack && npm run build:web-runtime && npm run build -w @md-to-pdf/server && node deploy/verify-font-pack-compose.mjs",
|
||||||
"build:font-pack:windows": "npm run verify:font-pack && node packages/font-pack-builder/dist/cli.js windows-installer",
|
"desktop:make:with-font-pack": "npm run build:font-pack && node scripts/build-desktop-with-font-pack.mjs",
|
||||||
"build:font-pack:archive": "npm run verify:font-pack && node packages/font-pack-builder/dist/cli.js archive",
|
|
||||||
"desktop:make:with-font-pack": "npm run build:font-pack:windows && npm run build:font-pack:archive && node scripts/build-desktop-with-font-pack.mjs",
|
|
||||||
"release:stage": "node scripts/stage-release.mjs",
|
"release:stage": "node scripts/stage-release.mjs",
|
||||||
"test:release-stage": "node --test scripts/stage-release.test.mjs",
|
"test:release-stage": "node --test scripts/stage-release.test.mjs",
|
||||||
"test:docx-layout-visual-matrix-cases": "node --test scripts/docx-layout-visual-matrix-cases.test.mjs",
|
"test:docx-layout-visual-matrix-cases": "node --test scripts/docx-layout-visual-matrix-cases.test.mjs",
|
||||||
|
|||||||
@@ -1,45 +1,13 @@
|
|||||||
import { copyFile, mkdir, readFile } from "node:fs/promises";
|
import { readFile } from "node:fs/promises";
|
||||||
import { spawn } from "node:child_process";
|
import { spawn } from "node:child_process";
|
||||||
import { dirname, join, resolve } from "node:path";
|
import { dirname, join, resolve } from "node:path";
|
||||||
import { fileURLToPath } from "node:url";
|
import { fileURLToPath } from "node:url";
|
||||||
import { createDesktopCompanionInclude } from "../packages/font-pack-builder/dist/index.js";
|
|
||||||
|
|
||||||
const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
||||||
const desktopRoot = join(repositoryRoot, "apps", "desktop");
|
const desktopRoot = join(repositoryRoot, "apps", "desktop");
|
||||||
const desktopManifest = JSON.parse(
|
const desktopManifest = JSON.parse(
|
||||||
await readFile(join(desktopRoot, "package.json"), "utf8")
|
await readFile(join(desktopRoot, "package.json"), "utf8")
|
||||||
);
|
);
|
||||||
const fontInstallerName =
|
|
||||||
"MorphDoc-FontPack-mdtp-serif-sc-1.0.0-x86_64-Setup.exe";
|
|
||||||
const fontArchiveName = "MorphDoc-FontPack-mdtp-serif-sc-1.0.0.zip";
|
|
||||||
const fontInstallerPath = join(
|
|
||||||
repositoryRoot,
|
|
||||||
"output",
|
|
||||||
"font-packs",
|
|
||||||
"windows",
|
|
||||||
fontInstallerName
|
|
||||||
);
|
|
||||||
const generatedInclude = join(
|
|
||||||
repositoryRoot,
|
|
||||||
"output",
|
|
||||||
"font-packs",
|
|
||||||
"desktop-companion.nsh"
|
|
||||||
);
|
|
||||||
const fontArchivePath = join(
|
|
||||||
repositoryRoot,
|
|
||||||
"output",
|
|
||||||
"font-packs",
|
|
||||||
"release",
|
|
||||||
fontArchiveName
|
|
||||||
);
|
|
||||||
|
|
||||||
await createDesktopCompanionInclude({
|
|
||||||
installerPath: fontInstallerPath,
|
|
||||||
baseIncludePath: join(desktopRoot, "build", "installer.nsh"),
|
|
||||||
outputPath: generatedInclude,
|
|
||||||
displayName: "MdTP 中文宋体兼容包 1.0.0"
|
|
||||||
});
|
|
||||||
|
|
||||||
const npmCli =
|
const npmCli =
|
||||||
process.env.npm_execpath ||
|
process.env.npm_execpath ||
|
||||||
join(dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
|
join(dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
|
||||||
@@ -49,10 +17,7 @@ await new Promise((resolvePromise, reject) => {
|
|||||||
[npmCli, "run", "make", "-w", "@md-to-pdf/desktop"],
|
[npmCli, "run", "make", "-w", "@md-to-pdf/desktop"],
|
||||||
{
|
{
|
||||||
cwd: repositoryRoot,
|
cwd: repositoryRoot,
|
||||||
env: {
|
env: process.env,
|
||||||
...process.env,
|
|
||||||
MD_TO_PDF_NSIS_INCLUDE: generatedInclude
|
|
||||||
},
|
|
||||||
stdio: "inherit",
|
stdio: "inherit",
|
||||||
windowsHide: true
|
windowsHide: true
|
||||||
}
|
}
|
||||||
@@ -71,10 +36,6 @@ await new Promise((resolvePromise, reject) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const desktopOutput = join(desktopRoot, "out", `v${desktopManifest.version}`);
|
|
||||||
await mkdir(desktopOutput, { recursive: true });
|
|
||||||
await copyFile(fontInstallerPath, join(desktopOutput, fontInstallerName));
|
|
||||||
await copyFile(fontArchivePath, join(desktopOutput, fontArchiveName));
|
|
||||||
process.stdout.write(
|
process.stdout.write(
|
||||||
`主安装器、字体包伴随安装器与 ZIP 附件已生成:${desktopOutput}\n`
|
`已生成内置字体包的主安装器与便携 ZIP:${join(desktopRoot, "out", `v${desktopManifest.version}`)}\n`
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import { readFile } from "node:fs/promises";
|
||||||
|
import { dirname, join, resolve } from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
import {
|
||||||
|
buildFontPack,
|
||||||
|
verifyFontPack
|
||||||
|
} from "../packages/font-pack-builder/dist/index.js";
|
||||||
|
import { discoverFontPacks } from "../packages/font-pack-registry/dist/index.js";
|
||||||
|
|
||||||
|
const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
||||||
|
const bundlePath = join(repositoryRoot, "font-packs", "bundle.json");
|
||||||
|
const bundle = JSON.parse(await readFile(bundlePath, "utf8"));
|
||||||
|
const outputRoot = join(repositoryRoot, "output", "font-packs", "root");
|
||||||
|
const appVersion = process.env.npm_package_version || "0.6.0";
|
||||||
|
|
||||||
|
if (
|
||||||
|
bundle.schemaVersion !== 1 ||
|
||||||
|
!Array.isArray(bundle.packs) ||
|
||||||
|
bundle.packs.length === 0
|
||||||
|
) {
|
||||||
|
throw new Error("字体包集合清单无效");
|
||||||
|
}
|
||||||
|
|
||||||
|
const identities = new Set();
|
||||||
|
const reports = [];
|
||||||
|
for (const pack of bundle.packs) {
|
||||||
|
const identity = `${pack.id}@${pack.version}`;
|
||||||
|
if (identities.has(identity)) {
|
||||||
|
throw new Error(`字体包集合存在重复项:${identity}`);
|
||||||
|
}
|
||||||
|
identities.add(identity);
|
||||||
|
const reportPath = join(
|
||||||
|
repositoryRoot,
|
||||||
|
"output",
|
||||||
|
"font-packs",
|
||||||
|
`${pack.id}-build-report.json`
|
||||||
|
);
|
||||||
|
const built = await buildFontPack({
|
||||||
|
recipePath: resolve(repositoryRoot, pack.recipe),
|
||||||
|
sourceRoot: resolve(repositoryRoot, pack.sourceRoot),
|
||||||
|
outputRoot,
|
||||||
|
reportPath
|
||||||
|
});
|
||||||
|
const verified = await verifyFontPack({
|
||||||
|
root: outputRoot,
|
||||||
|
appVersion,
|
||||||
|
packId: pack.id,
|
||||||
|
packVersion: pack.version
|
||||||
|
});
|
||||||
|
reports.push({ identity, built, verified });
|
||||||
|
}
|
||||||
|
|
||||||
|
const registry = await discoverFontPacks({
|
||||||
|
roots: [outputRoot],
|
||||||
|
appVersion
|
||||||
|
});
|
||||||
|
const errors = registry.diagnostics.filter((item) => item.severity === "error");
|
||||||
|
if (errors.length > 0) {
|
||||||
|
throw new Error(
|
||||||
|
`字体包集合注册失败:${errors.map((item) => `${item.code} ${item.message}`).join(";")}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const actualIdentities = registry.packs
|
||||||
|
.map((pack) => `${pack.id}@${pack.version}`)
|
||||||
|
.sort();
|
||||||
|
const expectedIdentities = [...identities].sort();
|
||||||
|
if (JSON.stringify(actualIdentities) !== JSON.stringify(expectedIdentities)) {
|
||||||
|
throw new Error(
|
||||||
|
`字体包输出根目录包含清单外内容:期望 ${expectedIdentities.join(", ")},实际 ${actualIdentities.join(", ")}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
process.stdout.write(
|
||||||
|
`${JSON.stringify({ appVersion, outputRoot, registryFingerprint: registry.fingerprint, reports }, null, 2)}\n`
|
||||||
|
);
|
||||||
@@ -184,9 +184,7 @@ export async function stageRelease(options = {}) {
|
|||||||
);
|
);
|
||||||
const desktopNames = [
|
const desktopNames = [
|
||||||
`MorphDoc-${version}-x86_64-Setup.exe`,
|
`MorphDoc-${version}-x86_64-Setup.exe`,
|
||||||
`MorphDoc-${version}-x86_64.zip`,
|
`MorphDoc-${version}-x86_64.zip`
|
||||||
"MorphDoc-FontPack-mdtp-serif-sc-1.0.0-x86_64-Setup.exe",
|
|
||||||
"MorphDoc-FontPack-mdtp-serif-sc-1.0.0.zip"
|
|
||||||
];
|
];
|
||||||
const releaseNotesSource = join(
|
const releaseNotesSource = join(
|
||||||
repositoryRoot,
|
repositoryRoot,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
#write {
|
#write {
|
||||||
color: var(--official-ink);
|
color: var(--official-ink);
|
||||||
font-family:
|
font-family:
|
||||||
"FandolFang", "FangSong", "STFangsong", "Noto Serif CJK SC",
|
"FandolSong", "FangSong", "STFangsong", "Noto Serif CJK SC",
|
||||||
"Source Han Serif SC", "SimSun", serif;
|
"Source Han Serif SC", "SimSun", serif;
|
||||||
font-size: 21.333px;
|
font-size: 21.333px;
|
||||||
line-height: 1.75;
|
line-height: 1.75;
|
||||||
@@ -64,13 +64,13 @@
|
|||||||
|
|
||||||
#write .doc-signatory > span {
|
#write .doc-signatory > span {
|
||||||
font-family:
|
font-family:
|
||||||
"FandolFang", "FangSong", "STFangsong",
|
"FandolSong", "FangSong", "STFangsong",
|
||||||
"Noto Serif CJK SC", serif;
|
"Noto Serif CJK SC", serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
#write .doc-signatory {
|
#write .doc-signatory {
|
||||||
font-family:
|
font-family:
|
||||||
"FandolKai", "KaiTi", "STKaiti",
|
"FandolSong", "KaiTi", "STKaiti",
|
||||||
"Noto Serif CJK SC", serif;
|
"Noto Serif CJK SC", serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,7 +110,7 @@
|
|||||||
#write h5,
|
#write h5,
|
||||||
#write h6 {
|
#write h6 {
|
||||||
font-family:
|
font-family:
|
||||||
"FandolKai", "KaiTi", "STKaiti",
|
"FandolSong", "KaiTi", "STKaiti",
|
||||||
"Noto Serif CJK SC", serif;
|
"Noto Serif CJK SC", serif;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
@@ -222,7 +222,7 @@
|
|||||||
border-bottom: 0.35mm solid var(--official-rule);
|
border-bottom: 0.35mm solid var(--official-rule);
|
||||||
break-inside: avoid;
|
break-inside: avoid;
|
||||||
font-family:
|
font-family:
|
||||||
"FandolFang", "FangSong", "STFangsong",
|
"FandolSong", "FangSong", "STFangsong",
|
||||||
"Noto Serif CJK SC", serif;
|
"Noto Serif CJK SC", serif;
|
||||||
font-size: 0.875em;
|
font-size: 0.875em;
|
||||||
line-height: 1.7;
|
line-height: 1.7;
|
||||||
|
|||||||
@@ -77,23 +77,11 @@
|
|||||||
"weight": 700,
|
"weight": 700,
|
||||||
"license": "GPL-3.0-or-later WITH Font-exception-2.0"
|
"license": "GPL-3.0-or-later WITH Font-exception-2.0"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"family": "FandolFang",
|
|
||||||
"aliases": ["Mdpdf Fandol Fang", "FangSong", "STFangsong"],
|
|
||||||
"source": "theme-shared:official-fonts/FandolFang-Regular.woff2",
|
|
||||||
"license": "GPL-3.0-or-later WITH Font-exception-2.0"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"family": "FandolHei",
|
"family": "FandolHei",
|
||||||
"aliases": ["Mdpdf Fandol Hei", "SimHei", "Noto Sans CJK SC", "Source Han Sans SC", "Microsoft YaHei"],
|
"aliases": ["Mdpdf Fandol Hei", "SimHei", "Noto Sans CJK SC", "Source Han Sans SC", "Microsoft YaHei"],
|
||||||
"source": "theme-shared:official-fonts/FandolHei-Regular.woff2",
|
"source": "theme-shared:official-fonts/FandolHei-Regular.woff2",
|
||||||
"license": "GPL-3.0-or-later WITH Font-exception-2.0"
|
"license": "GPL-3.0-or-later WITH Font-exception-2.0"
|
||||||
},
|
|
||||||
{
|
|
||||||
"family": "FandolKai",
|
|
||||||
"aliases": ["Mdpdf Fandol Kai", "KaiTi", "STKaiti"],
|
|
||||||
"source": "theme-shared:official-fonts/FandolKai-Regular.woff2",
|
|
||||||
"license": "GPL-3.0-or-later WITH Font-exception-2.0"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
#write {
|
#write {
|
||||||
color: var(--briefing-ink);
|
color: var(--briefing-ink);
|
||||||
font-family:
|
font-family:
|
||||||
"Noto Serif CJK SC", "Source Han Serif SC",
|
"FandolSong", "Noto Serif CJK SC", "Source Han Serif SC",
|
||||||
"Microsoft YaHei", "SimSun", serif;
|
"Microsoft YaHei", "SimSun", serif;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
line-height: 1.8;
|
line-height: 1.8;
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
border-bottom: 1mm solid var(--briefing-red);
|
border-bottom: 1mm solid var(--briefing-red);
|
||||||
color: var(--briefing-red);
|
color: var(--briefing-red);
|
||||||
font-family:
|
font-family:
|
||||||
"STZhongsong", "Noto Serif CJK SC", "Source Han Serif SC", serif;
|
"FandolSong", "STZhongsong", "Noto Serif CJK SC", "Source Han Serif SC", serif;
|
||||||
font-size: 2.35em;
|
font-size: 2.35em;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: 0.18em;
|
letter-spacing: 0.18em;
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
#write .doc-title {
|
#write .doc-title {
|
||||||
margin: 0 0 8mm;
|
margin: 0 0 8mm;
|
||||||
font-family:
|
font-family:
|
||||||
"STZhongsong", "Noto Serif CJK SC", "Source Han Serif SC", serif;
|
"FandolSong", "STZhongsong", "Noto Serif CJK SC", "Source Han Serif SC", serif;
|
||||||
font-size: 1.65em;
|
font-size: 1.65em;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
@@ -68,7 +68,7 @@
|
|||||||
#write h4 {
|
#write h4 {
|
||||||
margin: 1.35em 0 0.5em;
|
margin: 1.35em 0 0.5em;
|
||||||
font-family:
|
font-family:
|
||||||
"Noto Sans CJK SC", "Source Han Sans SC", "Microsoft YaHei", sans-serif;
|
"MdTP Sans SC", "Noto Sans CJK SC", "Source Han Sans SC", "Microsoft YaHei", sans-serif;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,5 +32,30 @@
|
|||||||
"docxStyle": {
|
"docxStyle": {
|
||||||
"preset": "official"
|
"preset": "official"
|
||||||
},
|
},
|
||||||
|
"docxFonts": {
|
||||||
|
"faces": [
|
||||||
|
{
|
||||||
|
"family": "FandolSong",
|
||||||
|
"aliases": ["Mdpdf Fandol Song", "STZhongsong", "Noto Serif CJK SC", "Source Han Serif SC", "SimSun"],
|
||||||
|
"source": "theme-shared:official-fonts/FandolSong-Regular.woff2",
|
||||||
|
"weight": 400,
|
||||||
|
"license": "GPL-3.0-or-later WITH Font-exception-2.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"family": "FandolSong",
|
||||||
|
"aliases": ["Mdpdf Fandol Song", "STZhongsong", "Noto Serif CJK SC", "Source Han Serif SC", "SimSun"],
|
||||||
|
"source": "theme-shared:official-fonts/FandolSong-Bold.woff2",
|
||||||
|
"weight": 700,
|
||||||
|
"license": "GPL-3.0-or-later WITH Font-exception-2.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"family": "MdTP Sans SC",
|
||||||
|
"aliases": ["FandolHei", "Noto Sans CJK SC", "Source Han Sans SC", "Microsoft YaHei"],
|
||||||
|
"source": "theme-shared:official-fonts/FandolHei-Regular.woff2",
|
||||||
|
"weight": 700,
|
||||||
|
"license": "OFL-1.1"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"bundled": true
|
"bundled": true
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user