feat: 完成 DOCX 视觉门禁与字体兼容映射

This commit is contained in:
SkyJourney
2026-07-31 20:13:19 +08:00
parent 10bc62cee4
commit e5da699ea3
32 changed files with 3015 additions and 17 deletions
+56 -7
View File
@@ -108,6 +108,7 @@ function setParagraphSpacing(
options: {
beforePt: number;
afterPt: number;
fontSizePt: number;
lineSpacing: number;
firstLineIndentChars?: number;
}
@@ -116,8 +117,10 @@ function setParagraphSpacing(
appendElement(parent, WORD_NAMESPACE, "w:spacing", {
"w:before": pointsToTwips(options.beforePt),
"w:after": pointsToTwips(options.afterPt),
"w:line": String(Math.round(options.lineSpacing * 240)),
"w:lineRule": "auto"
"w:line": pointsToTwips(
options.fontSizePt * options.lineSpacing
),
"w:lineRule": "exact"
});
if (options.firstLineIndentChars !== undefined) {
appendElement(parent, WORD_NAMESPACE, "w:ind", {
@@ -208,6 +211,38 @@ function fallbackFontsForSlot(
return fallback.body.fonts;
}
function fallbackFontSizeForSlot(
slot: DocxStyleSlotName,
fallback: ResolvedDocxThemeStyle
) {
const headingMatch = /^heading-([1-6])$/u.exec(slot);
if (headingMatch) {
return fallback.headings.sizesPt[
Number.parseInt(headingMatch[1]!, 10) - 1
]!;
}
if (slot === "document-title") {
return fallback.headings.sizesPt[0] + 4;
}
if (slot.endsWith("-title")) {
return fallback.headings.sizesPt[0];
}
if (slot === "inline-code" || slot === "code-block") {
return fallback.code.sizePt;
}
if (
slot === "table" ||
slot === "table-header" ||
slot === "table-cell"
) {
return fallback.table.sizePt;
}
if (slot === "caption") {
return fallback.caption.sizePt;
}
return fallback.body.sizePt;
}
function applyTokenRunStyle(
parent: XmlElement,
token: DocxSlotStyleToken,
@@ -306,7 +341,8 @@ function applyTokenBorders(
function applyTokenParagraphStyle(
parent: XmlElement,
token: DocxSlotStyleToken
token: DocxSlotStyleToken,
fallbackFontSizePt: number
) {
if (
token.spacingBeforePt !== undefined ||
@@ -336,9 +372,12 @@ function applyTokenParagraphStyle(
setWordAttribute(
spacing,
"line",
String(Math.round(token.lineSpacing * 240))
pointsToTwips(
(token.fontSizePt ?? fallbackFontSizePt) *
token.lineSpacing
)
);
setWordAttribute(spacing, "lineRule", "auto");
setWordAttribute(spacing, "lineRule", "exact");
}
}
if (
@@ -440,6 +479,7 @@ function applyBodyStyle(
setParagraphSpacing(defaultParagraph, {
beforePt: style.body.spacingBeforePt,
afterPt: style.body.spacingAfterPt,
fontSizePt: style.body.sizePt,
lineSpacing: style.body.lineSpacing,
firstLineIndentChars: style.body.firstLineIndentChars
});
@@ -466,6 +506,7 @@ function applyBodyStyle(
setParagraphSpacing(pPr, {
beforePt: style.body.spacingBeforePt,
afterPt: style.body.spacingAfterPt,
fontSizePt: style.body.sizePt,
lineSpacing: style.body.lineSpacing,
firstLineIndentChars: style.body.firstLineIndentChars
});
@@ -492,6 +533,7 @@ function applyBodyStyle(
{
beforePt: 0,
afterPt: 0,
fontSizePt: style.body.sizePt,
lineSpacing: style.body.lineSpacing,
firstLineIndentChars: 0
}
@@ -525,6 +567,7 @@ function applyHeadings(
setParagraphSpacing(pPr, {
beforePt: style.headings.spacingBeforePt,
afterPt: style.headings.spacingAfterPt,
fontSizePt: sizePt,
lineSpacing: 1.25
});
if (!firstDirectChild(pPr, WORD_NAMESPACE, "keepNext")) {
@@ -569,6 +612,7 @@ function applyHeadings(
setParagraphSpacing(pPr, {
beforePt: 0,
afterPt: style.headings.spacingAfterPt,
fontSizePt: sizePt,
lineSpacing: 1.25
});
removeDirectChildren(pPr, WORD_NAMESPACE, "jc");
@@ -622,6 +666,7 @@ function applyCodeAndQuote(
setParagraphSpacing(codePPr, {
beforePt: 3,
afterPt: 3,
fontSizePt: style.code.sizePt,
lineSpacing: style.code.lineSpacing,
firstLineIndentChars: 0
});
@@ -668,6 +713,7 @@ function applyCodeAndQuote(
setParagraphSpacing(quotePPr, {
beforePt: 6,
afterPt: 6,
fontSizePt: style.body.sizePt,
lineSpacing: style.body.lineSpacing,
firstLineIndentChars: 0
});
@@ -813,6 +859,7 @@ function applyTableAndCaption(
setParagraphSpacing(pPr, {
beforePt: 3,
afterPt: 6,
fontSizePt: style.caption.sizePt,
lineSpacing: 1.25
});
removeDirectChildren(pPr, WORD_NAMESPACE, "jc");
@@ -1002,7 +1049,8 @@ function applyTokenStyles(
WORD_NAMESPACE,
"w:pPr"
),
documentToken
documentToken,
documentToken.fontSizePt ?? fallback.body.sizePt
);
}
}
@@ -1025,7 +1073,8 @@ function applyTokenStyles(
WORD_NAMESPACE,
"w:pPr"
),
entry.style
entry.style,
fallbackFontSizeForSlot(slot, fallback)
);
}
applyTokenRunStyle(