reamkit 1.22.0 → 1.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/core/bmp.d.ts +33 -0
- package/dist/esm/core/bmp.js +276 -0
- package/dist/esm/core/converter/ream.d.ts +16 -0
- package/dist/esm/core/converter/ream.js +59 -9
- package/dist/esm/core/document-model/types.d.ts +55 -0
- package/dist/esm/core/drawingml/chart-geometry.js +14 -7
- package/dist/esm/core/drawingml/colors.d.ts +4 -2
- package/dist/esm/core/drawingml/colors.js +15 -0
- package/dist/esm/core/drawingml/diagram/colors.d.ts +52 -0
- package/dist/esm/core/drawingml/diagram/colors.js +125 -0
- package/dist/esm/core/drawingml/diagram/data-model.d.ts +47 -0
- package/dist/esm/core/drawingml/diagram/data-model.js +119 -0
- package/dist/esm/core/drawingml/diagram/layout-engine.d.ts +46 -0
- package/dist/esm/core/drawingml/diagram/layout-engine.js +948 -0
- package/dist/esm/core/drawingml/diagram/run.d.ts +37 -0
- package/dist/esm/core/drawingml/diagram/run.js +50 -0
- package/dist/esm/core/drawingml/diagram/to-drawing.d.ts +16 -0
- package/dist/esm/core/drawingml/diagram/to-drawing.js +86 -0
- package/dist/esm/core/drawingml/preset-geometry.js +116 -6
- package/dist/esm/core/drawingml/text-warp.d.ts +58 -0
- package/dist/esm/core/drawingml/text-warp.js +355 -0
- package/dist/esm/core/drawingml/theme-parser.d.ts +38 -0
- package/dist/esm/core/drawingml/theme-parser.js +73 -4
- package/dist/esm/core/font/measure.d.ts +12 -0
- package/dist/esm/core/font/measure.js +36 -0
- package/dist/esm/core/fonts/families.d.ts +10 -0
- package/dist/esm/core/fonts/families.js +44 -0
- package/dist/esm/core/fonts/index.d.ts +3 -2
- package/dist/esm/core/fonts/remote-fonts.d.ts +50 -0
- package/dist/esm/core/fonts/remote-fonts.js +114 -8
- package/dist/esm/core/fonts/scripts.d.ts +26 -0
- package/dist/esm/core/fonts/scripts.js +177 -0
- package/dist/esm/core/images.d.ts +30 -2
- package/dist/esm/core/images.js +121 -5
- package/dist/esm/core/metafile/blit.d.ts +33 -0
- package/dist/esm/core/metafile/blit.js +67 -0
- package/dist/esm/core/metafile/dib.d.ts +61 -0
- package/dist/esm/core/metafile/dib.js +205 -0
- package/dist/esm/core/metafile/emf.js +280 -38
- package/dist/esm/core/metafile/picture.d.ts +61 -1
- package/dist/esm/core/metafile/picture.js +70 -1
- package/dist/esm/core/metafile/wmf.js +202 -13
- package/dist/esm/core/ole/escher-blip.d.ts +12 -0
- package/dist/esm/core/ole/escher-blip.js +98 -0
- package/dist/esm/{pdf-reader → core}/png-encode.js +1 -1
- package/dist/esm/excel/print-model.js +5 -3
- package/dist/esm/excel/sheet-drawing.js +1 -1
- package/dist/esm/excel/sheet-to-flow.js +16 -2
- package/dist/esm/excel/styles-parser.js +1 -1
- package/dist/esm/excel/xls/biff-reader.js +53 -18
- package/dist/esm/excel/xls/biff-styles.d.ts +5 -2
- package/dist/esm/excel/xls/biff-styles.js +9 -7
- package/dist/esm/excel/xls/escher.js +90 -24
- package/dist/esm/html/html-writer.js +2 -1
- package/dist/esm/layout/page-doc.d.ts +74 -0
- package/dist/esm/layout/page-doc.js +14 -1
- package/dist/esm/layout/styled-layout.d.ts +2 -2
- package/dist/esm/layout/styled-layout.js +475 -48
- package/dist/esm/pdf/shading.js +8 -6
- package/dist/esm/pdf/styled-page-emitter.js +77 -5
- package/dist/esm/pdf/vector-graphics.js +1 -1
- package/dist/esm/pdf-reader/image-decode.js +1 -1
- package/dist/esm/pptx/embedded-fonts.d.ts +31 -0
- package/dist/esm/pptx/embedded-fonts.js +104 -0
- package/dist/esm/pptx/placeholder-cascade.d.ts +73 -6
- package/dist/esm/pptx/placeholder-cascade.js +114 -18
- package/dist/esm/pptx/ppt/ppt-reader.js +191 -13
- package/dist/esm/pptx/ppt/ppt-text.d.ts +107 -1
- package/dist/esm/pptx/ppt/ppt-text.js +873 -144
- package/dist/esm/pptx/pptx-reader.d.ts +8 -0
- package/dist/esm/pptx/pptx-reader.js +117 -15
- package/dist/esm/pptx/preset-table-styles.d.ts +9 -0
- package/dist/esm/pptx/preset-table-styles.js +27 -0
- package/dist/esm/pptx/slide-parser.d.ts +11 -2
- package/dist/esm/pptx/slide-parser.js +203 -44
- package/dist/esm/pptx/sp-helpers.d.ts +9 -4
- package/dist/esm/pptx/sp-helpers.js +48 -9
- package/dist/esm/pptx/table-style.d.ts +16 -1
- package/dist/esm/pptx/table-style.js +104 -10
- package/dist/esm/svg/svg-writer.js +1 -0
- package/dist/esm/word/document-parser.d.ts +11 -2
- package/dist/esm/word/document-parser.js +10 -7
- package/dist/esm/word/docx-reader.js +32 -16
- package/dist/esm/word/docx-to-pdf.d.ts +8 -7
- package/dist/esm/word/docx-to-pdf.js +25 -7
- package/dist/esm/word/docx-writer.js +4 -0
- package/dist/esm/word/drawing-parser.d.ts +20 -0
- package/dist/esm/word/drawing-parser.js +67 -22
- package/dist/esm/word/numbering-parser.d.ts +2 -1
- package/dist/esm/word/numbering-parser.js +6 -6
- package/dist/esm/word/paragraph-properties.d.ts +2 -1
- package/dist/esm/word/paragraph-properties.js +2 -2
- package/dist/esm/word/run-properties.d.ts +5 -2
- package/dist/esm/word/run-properties.js +13 -8
- package/dist/esm/word/styles-parser.d.ts +2 -1
- package/dist/esm/word/styles-parser.js +12 -12
- package/dist/esm/word/table-parser.js +6 -3
- package/dist/esm/word/theme-fonts.d.ts +10 -0
- package/dist/esm/word/theme-fonts.js +28 -0
- package/package.json +1 -1
- /package/dist/esm/{pdf-reader → core}/png-encode.d.ts +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { pt } from "../core/ir/units.js";
|
|
2
2
|
import { poAttr, poChildren, poIntAttr, poIs, poTag, poText } from "../core/po-helpers.js";
|
|
3
|
-
import { readColorMods, resolveColorNode } from "../core/drawingml/colors.js";
|
|
3
|
+
import { placeholderColors, readColorMods, resolveColorNode } from "../core/drawingml/colors.js";
|
|
4
4
|
//#region src/pptx/table-style.ts
|
|
5
5
|
/** The `a:tblPr` flags, all off unless the table says otherwise. */
|
|
6
6
|
function tableStyleFlags(tblPr) {
|
|
@@ -26,9 +26,10 @@ function tableStyleId(tblPr) {
|
|
|
26
26
|
* @param flags Which conditional parts the table asks for.
|
|
27
27
|
* @param at Where the cell sits.
|
|
28
28
|
* @param colors The deck's colour resolver.
|
|
29
|
+
* @param theme The theme's style lists, for the parts that point at them.
|
|
29
30
|
* @returns The composed part, empty when the style says nothing.
|
|
30
31
|
*/
|
|
31
|
-
function cellStyle(style, flags, at, colors) {
|
|
32
|
+
function cellStyle(style, flags, at, colors, theme) {
|
|
32
33
|
const names = ["a:wholeTbl"];
|
|
33
34
|
if (flags.bandCol) names.push(bandName(at.col, flags.firstCol, "V"));
|
|
34
35
|
if (flags.bandRow) names.push(bandName(at.row, flags.firstRow, "H"));
|
|
@@ -36,31 +37,108 @@ function cellStyle(style, flags, at, colors) {
|
|
|
36
37
|
if (flags.lastCol && at.col === at.colCount - 1) names.push("a:lastCol");
|
|
37
38
|
if (flags.firstRow && at.row === 0) names.push("a:firstRow");
|
|
38
39
|
if (flags.lastRow && at.row === at.rowCount - 1) names.push("a:lastRow");
|
|
39
|
-
let out =
|
|
40
|
+
let out = tableBackground(style, colors, theme);
|
|
40
41
|
for (const name of names) {
|
|
41
42
|
const part = poChildren(style).find((c) => poIs(c, name));
|
|
42
|
-
if (part)
|
|
43
|
+
if (!part) continue;
|
|
44
|
+
const next = partStyle(part, colors, theme);
|
|
45
|
+
out = {
|
|
43
46
|
...out,
|
|
44
|
-
...
|
|
47
|
+
...next,
|
|
48
|
+
...overFill(out.shadingHex, next)
|
|
45
49
|
};
|
|
46
50
|
}
|
|
47
|
-
|
|
51
|
+
const { shadingAlpha: _drop, ...flat } = out;
|
|
52
|
+
return flat;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* A part's fill laid OVER what is already under it.
|
|
56
|
+
*
|
|
57
|
+
* A colour resolves flattened against the page, because that is what a shape's
|
|
58
|
+
* fill sits on; a table cell's sits on the table's background. Undoing the one
|
|
59
|
+
* and redoing the other needs only the alpha: bnc480256's banding is `accent1`
|
|
60
|
+
* at 40% over a background the theme's gradient makes pale, and taken against
|
|
61
|
+
* white instead it came out as the flat accent with every second row white.
|
|
62
|
+
*/
|
|
63
|
+
function overFill(under, part) {
|
|
64
|
+
const a = part.shadingAlpha;
|
|
65
|
+
if (a === void 0 || a >= 1 || part.shadingHex === void 0 || under === void 0) return {};
|
|
66
|
+
const flat = rgb(part.shadingHex);
|
|
67
|
+
const back = rgb(under);
|
|
68
|
+
if (!flat || !back) return {};
|
|
69
|
+
return { shadingHex: toHex(flat.map((v, i) => v - (1 - a) * (1 - (back[i] ?? 1)))) };
|
|
70
|
+
}
|
|
71
|
+
function alphaOf(fill) {
|
|
72
|
+
const walk = (node) => {
|
|
73
|
+
for (const child of poChildren(node)) {
|
|
74
|
+
if (poIs(child, "a:alpha")) {
|
|
75
|
+
const v = poIntAttr(child, "val");
|
|
76
|
+
if (v !== void 0) return Math.max(0, Math.min(1, v / 1e5));
|
|
77
|
+
}
|
|
78
|
+
const deeper = walk(child);
|
|
79
|
+
if (deeper !== void 0) return deeper;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
return walk(fill) ?? 1;
|
|
83
|
+
}
|
|
84
|
+
function rgb(h) {
|
|
85
|
+
const m = /^([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$/u.exec(h);
|
|
86
|
+
return m ? [
|
|
87
|
+
1,
|
|
88
|
+
2,
|
|
89
|
+
3
|
|
90
|
+
].map((i) => parseInt(m[i] ?? "0", 16) / 255) : void 0;
|
|
91
|
+
}
|
|
92
|
+
function toHex(v) {
|
|
93
|
+
return v.map((c) => Math.round(Math.max(0, Math.min(1, c)) * 255).toString(16).padStart(2, "0").toUpperCase()).join("");
|
|
94
|
+
}
|
|
95
|
+
function tableBackground(style, colors, theme) {
|
|
96
|
+
const bg = poChildren(style).find((c) => poIs(c, "a:tblBg"));
|
|
97
|
+
if (!bg) return {};
|
|
98
|
+
const solid = poChildren(bg).find((c) => poIs(c, "a:solidFill"));
|
|
99
|
+
const hex = (solid ? colorOf(solid, colors) : void 0) ?? refFillColor(poChildren(bg).find((c) => poIs(c, "a:fillRef")), colors, theme);
|
|
100
|
+
return hex ? { shadingHex: hex } : {};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* §20.1.4.1.16 `a:fillRef` — a fill named by its place in the theme's list,
|
|
104
|
+
* with the colour to put wherever that fill says `phClr`.
|
|
105
|
+
*
|
|
106
|
+
* Only its COLOUR is taken: a slot may be a gradient or a picture, and a cell's
|
|
107
|
+
* shading is one colour. The first solid colour the slot names, or the
|
|
108
|
+
* reference's own, is the nearest true answer.
|
|
109
|
+
*/
|
|
110
|
+
function refFillColor(ref, colors, theme) {
|
|
111
|
+
if (!ref) return void 0;
|
|
112
|
+
const own = colorOf(ref, colors);
|
|
113
|
+
const idx = poIntAttr(ref, "idx");
|
|
114
|
+
const slot = idx !== void 0 && idx > 0 ? theme?.fills?.[idx - 1] : void 0;
|
|
115
|
+
if (!slot) return own;
|
|
116
|
+
const named = own === void 0 ? colors : placeholderColors(colors, own);
|
|
117
|
+
const solid = poIs(slot, "a:solidFill") ? slot : void 0;
|
|
118
|
+
if (solid) return colorOf(solid, named) ?? own;
|
|
119
|
+
const grad = poIs(slot, "a:gradFill") ? slot : void 0;
|
|
120
|
+
const list = grad ? poChildren(grad).find((c) => poIs(c, "a:gsLst")) : void 0;
|
|
121
|
+
const stops = list ? poChildren(list).filter((c) => poIs(c, "a:gs")) : [];
|
|
122
|
+
const last = stops[stops.length - 1];
|
|
123
|
+
return (last ? colorOf(last, named) : void 0) ?? own;
|
|
48
124
|
}
|
|
49
125
|
function bandName(index, edge, axis) {
|
|
50
126
|
return (edge ? index - 1 : index) % 2 === 0 ? `a:band1${axis}` : `a:band2${axis}`;
|
|
51
127
|
}
|
|
52
|
-
function partStyle(part, colors) {
|
|
128
|
+
function partStyle(part, colors, theme) {
|
|
53
129
|
const tcStyle = poChildren(part).find((c) => poIs(c, "a:tcStyle"));
|
|
54
130
|
const txStyle = poChildren(part).find((c) => poIs(c, "a:tcTxStyle"));
|
|
55
131
|
const fill = tcStyle ? poChildren(tcStyle).find((c) => poIs(c, "a:fill")) : void 0;
|
|
56
132
|
const solid = fill ? poChildren(fill).find((c) => poIs(c, "a:solidFill")) : void 0;
|
|
57
133
|
const shadingHex = solid ? colorOf(solid, colors) : void 0;
|
|
134
|
+
const shadingAlpha = solid ? alphaOf(solid) : void 0;
|
|
58
135
|
const bdr = tcStyle ? poChildren(tcStyle).find((c) => poIs(c, "a:tcBdr")) : void 0;
|
|
59
|
-
const borders = bdr ? partBorders(bdr, colors) : void 0;
|
|
136
|
+
const borders = bdr ? partBorders(bdr, colors, theme) : void 0;
|
|
60
137
|
const on = (name) => poAttr(txStyle, name) === "on";
|
|
61
138
|
const colorHex = txStyle ? colorOf(txStyle, colors) : void 0;
|
|
62
139
|
return {
|
|
63
140
|
...shadingHex ? { shadingHex } : {},
|
|
141
|
+
...shadingAlpha !== void 0 && shadingAlpha < 1 ? { shadingAlpha } : {},
|
|
64
142
|
...borders ? { borders } : {},
|
|
65
143
|
...txStyle && on("b") ? { bold: true } : {},
|
|
66
144
|
...txStyle && on("i") ? { italic: true } : {},
|
|
@@ -75,15 +153,31 @@ var SIDES = [
|
|
|
75
153
|
["a:insideH", "insideH"],
|
|
76
154
|
["a:insideV", "insideV"]
|
|
77
155
|
];
|
|
78
|
-
function partBorders(bdr, colors) {
|
|
156
|
+
function partBorders(bdr, colors, theme) {
|
|
79
157
|
const out = {};
|
|
80
158
|
for (const [tag, side] of SIDES) {
|
|
81
159
|
const holder = poChildren(bdr).find((c) => poIs(c, tag));
|
|
82
160
|
const ln = holder ? poChildren(holder).find((c) => poIs(c, "a:ln")) : void 0;
|
|
83
|
-
if (ln)
|
|
161
|
+
if (ln) {
|
|
162
|
+
out[side] = lineBorder(ln, colors);
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
const border = refBorder(holder ? poChildren(holder).find((c) => poIs(c, "a:lnRef")) : void 0, colors, theme);
|
|
166
|
+
if (border) out[side] = border;
|
|
84
167
|
}
|
|
85
168
|
return Object.keys(out).length > 0 ? out : void 0;
|
|
86
169
|
}
|
|
170
|
+
function refBorder(ref, colors, theme) {
|
|
171
|
+
if (!ref || poAttr(ref, "idx") === "0") return void 0;
|
|
172
|
+
const colorHex = colorOf(ref, colors);
|
|
173
|
+
if (colorHex === void 0) return void 0;
|
|
174
|
+
const idx = poIntAttr(ref, "idx");
|
|
175
|
+
return {
|
|
176
|
+
style: "single",
|
|
177
|
+
colorHex,
|
|
178
|
+
width: pt((idx !== void 0 && idx > 0 ? theme?.lineWidths?.[idx - 1] : void 0) ?? .75)
|
|
179
|
+
};
|
|
180
|
+
}
|
|
87
181
|
/**
|
|
88
182
|
* §20.1.2.1 `a:ln` → the rule it draws on one side of a cell.
|
|
89
183
|
*
|
|
@@ -88,6 +88,7 @@ function emitPage(out, page, laid, losses, idc) {
|
|
|
88
88
|
}
|
|
89
89
|
for (const sh of plan.shapes) emitShape(out, sh.shape, idc);
|
|
90
90
|
for (const picture of plan.pictures) for (const item of picture) emitPageItem(out, item, laid, losses, idc);
|
|
91
|
+
for (const run of plan.ordered) for (const item of run) emitPageItem(out, item, laid, losses, idc);
|
|
91
92
|
for (const t of plan.lines) emitTextLine(out, t, losses, idc);
|
|
92
93
|
}
|
|
93
94
|
/**
|
|
@@ -2,6 +2,7 @@ import { BodyElement, Comment, RunProperties, Section, SectionProperties, ShapeF
|
|
|
2
2
|
import { ColorResolver } from '../core/drawingml/colors.js';
|
|
3
3
|
import { Loss, ResourceId } from '../core/ir/index.js';
|
|
4
4
|
import { PoNode } from '../core/po-helpers.js';
|
|
5
|
+
import { ThemeFonts } from '../core/drawingml/theme-parser.js';
|
|
5
6
|
import { ThemeStyles } from './drawing-parser.js';
|
|
6
7
|
/**
|
|
7
8
|
* Resolves a drawing relationship id to a content-addressed `ResourceId` —
|
|
@@ -38,7 +39,10 @@ export interface ParseContext {
|
|
|
38
39
|
* pre-rendered drawing override, or `undefined` when the file ships none
|
|
39
40
|
* (E-SMARTART SA2).
|
|
40
41
|
*/
|
|
41
|
-
readonly resolveDiagram?: (relId: string
|
|
42
|
+
readonly resolveDiagram?: (relId: string, frame: {
|
|
43
|
+
readonly cx: number;
|
|
44
|
+
readonly cy: number;
|
|
45
|
+
}) => ResolvedDiagram | undefined;
|
|
42
46
|
/**
|
|
43
47
|
* §21.2 a `c:chart` `@r:id` → the chart part's path, the key the reader files
|
|
44
48
|
* parsed charts under. Relationship ids are scoped to their owning part, so a
|
|
@@ -57,6 +61,11 @@ export interface ParseContext {
|
|
|
57
61
|
* the shadow a gallery-drawn shape wears.
|
|
58
62
|
*/
|
|
59
63
|
readonly themeStyles?: ThemeStyles;
|
|
64
|
+
/**
|
|
65
|
+
* §20.1.4.1.16 — the theme's font scheme, for the typefaces a run names by
|
|
66
|
+
* slot (`w:asciiTheme="minorHAnsi"`) rather than by name.
|
|
67
|
+
*/
|
|
68
|
+
readonly themeFonts?: ThemeFonts;
|
|
60
69
|
/**
|
|
61
70
|
* Sink for graceful-degradation notices (E-SMARTART SA3): a SmartArt with no
|
|
62
71
|
* drawing override records a dropped-feature {@link Loss} rather than vanishing.
|
|
@@ -185,7 +194,7 @@ export declare function parseBodyElements(children: ReadonlyArray<PoNode>, ctx?:
|
|
|
185
194
|
* @param sdt The `w:sdt` element.
|
|
186
195
|
* @returns The properties, or `undefined` when the control states none.
|
|
187
196
|
*/
|
|
188
|
-
export declare function sdtRunProperties(sdt: PoNode): RunProperties | undefined;
|
|
197
|
+
export declare function sdtRunProperties(sdt: PoNode, themeFonts?: ThemeFonts): RunProperties | undefined;
|
|
189
198
|
/**
|
|
190
199
|
* Parse `footnotes.xml` / `endnotes.xml` (§17.11) into note content by id. The
|
|
191
200
|
* separator / continuationSeparator / continuationNotice stubs (negative ids or
|
|
@@ -425,7 +425,7 @@ function tryExtractDrawingFromParagraph(p, ctx) {
|
|
|
425
425
|
if (!vml && drawings.every((d) => poChildren(d).some((c) => poIs(c, "wp:anchor")))) return null;
|
|
426
426
|
const parseBody = (children) => parseBodyElements(children, ctx);
|
|
427
427
|
const pPrNode = poChildren(p).find((c) => poIs(c, "w:pPr"));
|
|
428
|
-
const paragraphProperties = pPrNode ? parseParagraphProperties(poElementToFlat(pPrNode), ctx.autoSpacingPt) : {};
|
|
428
|
+
const paragraphProperties = pPrNode ? parseParagraphProperties(poElementToFlat(pPrNode), ctx.autoSpacingPt, ctx.themeFonts) : {};
|
|
429
429
|
if (drawings.length === 0) {
|
|
430
430
|
const content = parseVmlPicture(vml, parseBody);
|
|
431
431
|
if (!content) return null;
|
|
@@ -484,7 +484,10 @@ function blocksForDrawing(content, paragraphProperties, ctx) {
|
|
|
484
484
|
}
|
|
485
485
|
}];
|
|
486
486
|
if (content.kind === "diagram") {
|
|
487
|
-
const diagram = ctx.resolveDiagram?.(content.dmRelId
|
|
487
|
+
const diagram = ctx.resolveDiagram?.(content.dmRelId, {
|
|
488
|
+
cx: content.widthEmu,
|
|
489
|
+
cy: content.heightEmu
|
|
490
|
+
});
|
|
488
491
|
if (!diagram) {
|
|
489
492
|
ctx.onLoss?.(noDiagramOverrideLoss());
|
|
490
493
|
return null;
|
|
@@ -536,7 +539,7 @@ function parseParagraph(p, ctx, extraBookmarks, anchored, sdtRunProps) {
|
|
|
536
539
|
if (bookmarkName !== void 0 && bookmarkName !== "" && bookmarkName !== "_GoBack") bookmarks.push(bookmarkName);
|
|
537
540
|
}
|
|
538
541
|
const pPr = poChildren(p).find((c) => poIs(c, "w:pPr"));
|
|
539
|
-
let properties = parseParagraphProperties(pPr ? poElementToFlat(pPr) : void 0, ctx.autoSpacingPt);
|
|
542
|
+
let properties = parseParagraphProperties(pPr ? poElementToFlat(pPr) : void 0, ctx.autoSpacingPt, ctx.themeFonts);
|
|
540
543
|
if (pPr && poChildren(pPr).some((c) => poIs(c, "w:sectPr"))) properties = {
|
|
541
544
|
...properties,
|
|
542
545
|
sectionBreak: true
|
|
@@ -773,7 +776,7 @@ function collectRuns(container, out, ctx, href, anchor, anchored, sdtRunProps) {
|
|
|
773
776
|
if (bookmark !== void 0 && bookmark !== "") childAnchor = bookmark;
|
|
774
777
|
}
|
|
775
778
|
}
|
|
776
|
-
const childProps = tag === "w:sdt" ? sdtRunProperties(child) ?? sdtRunProps : sdtRunProps;
|
|
779
|
+
const childProps = tag === "w:sdt" ? sdtRunProperties(child, ctx.themeFonts) ?? sdtRunProps : sdtRunProps;
|
|
777
780
|
collectRuns(child, out, ctx, childHref, childAnchor, anchored, childProps);
|
|
778
781
|
}
|
|
779
782
|
}
|
|
@@ -785,11 +788,11 @@ function collectRuns(container, out, ctx, href, anchor, anchored, sdtRunProps) {
|
|
|
785
788
|
* @param sdt The `w:sdt` element.
|
|
786
789
|
* @returns The properties, or `undefined` when the control states none.
|
|
787
790
|
*/
|
|
788
|
-
function sdtRunProperties(sdt) {
|
|
791
|
+
function sdtRunProperties(sdt, themeFonts) {
|
|
789
792
|
const sdtPr = poChildren(sdt).find((c) => poIs(c, "w:sdtPr"));
|
|
790
793
|
const rPr = sdtPr ? poChildren(sdtPr).find((c) => poIs(c, "w:rPr")) : void 0;
|
|
791
794
|
if (!rPr) return void 0;
|
|
792
|
-
const props = parseRunProperties(poElementToFlat(rPr));
|
|
795
|
+
const props = parseRunProperties(poElementToFlat(rPr), themeFonts);
|
|
793
796
|
return Object.keys(props).length > 0 ? props : void 0;
|
|
794
797
|
}
|
|
795
798
|
var WINGDINGS_TO_UNICODE = new Map([
|
|
@@ -870,7 +873,7 @@ function symbolChar(font, char) {
|
|
|
870
873
|
}
|
|
871
874
|
function parseRun(r, ctx, anchored) {
|
|
872
875
|
const rPr = poChildren(r).find((c) => poIs(c, "w:rPr"));
|
|
873
|
-
const properties = parseRunProperties(rPr ? poElementToFlat(rPr) : void 0);
|
|
876
|
+
const properties = parseRunProperties(rPr ? poElementToFlat(rPr) : void 0, ctx.themeFonts);
|
|
874
877
|
let text = "";
|
|
875
878
|
let pageBreak = false;
|
|
876
879
|
let columnBreak = false;
|
|
@@ -5,11 +5,11 @@ import { resolveTableStyles } from "../core/style-cascade/table.js";
|
|
|
5
5
|
import "../core/style-cascade/index.js";
|
|
6
6
|
import { applyNumbering, applyNumberingToHeadersFooters } from "../core/numbering/apply.js";
|
|
7
7
|
import "../core/numbering/index.js";
|
|
8
|
-
import {
|
|
8
|
+
import { cachedDiagramTree, laidOutDiagramTree } from "../core/drawingml/diagram/run.js";
|
|
9
9
|
import { packageHasPart } from "../core/bytes.js";
|
|
10
10
|
import { DEFAULT_THEME_PALETTE, makeColorResolver } from "../core/drawingml/colors.js";
|
|
11
11
|
import { parseChart, withChartColorStyle } from "../core/drawingml/chart-parser.js";
|
|
12
|
-
import { parseTheme, parseThemeBgFillStyles, parseThemeEffectStyles, parseThemeFillStyles, parseThemeLineWidths } from "../core/drawingml/theme-parser.js";
|
|
12
|
+
import { parseTheme, parseThemeBgFillStyles, parseThemeEffectStyles, parseThemeFillStyles, parseThemeFonts, parseThemeLineWidths } from "../core/drawingml/theme-parser.js";
|
|
13
13
|
import { isOoxmlRel } from "../core/opc/relationship-types.js";
|
|
14
14
|
import { OpcPackage } from "../core/opc/package.js";
|
|
15
15
|
import { parseCoreProperties } from "../core/opc/core-properties.js";
|
|
@@ -52,6 +52,7 @@ function readDocx(docx) {
|
|
|
52
52
|
const resolveColor = buildColorResolver(pkg, main.path);
|
|
53
53
|
const themeData = loadTheme(pkg, main.path);
|
|
54
54
|
const themeLineWidths = themeData ? parseThemeLineWidths(themeData) : void 0;
|
|
55
|
+
const themeFonts = themeData ? parseThemeFonts(themeData) : void 0;
|
|
55
56
|
const themeStyles = themeData ? {
|
|
56
57
|
fills: parseThemeFillStyles(themeData),
|
|
57
58
|
bgFills: parseThemeBgFillStyles(themeData),
|
|
@@ -68,6 +69,7 @@ function readDocx(docx) {
|
|
|
68
69
|
...settings.compatibilityMode === void 0 ? { autoSpacingPt: 14 } : {},
|
|
69
70
|
...themeLineWidths && themeLineWidths.length > 0 ? { themeLineWidths } : {},
|
|
70
71
|
...themeStyles ? { themeStyles } : {},
|
|
72
|
+
...themeFonts ? { themeFonts } : {},
|
|
71
73
|
resolveImage,
|
|
72
74
|
resolveHyperlink,
|
|
73
75
|
resolveDiagram: makeDiagramResolver(pkg, main.path, resources),
|
|
@@ -84,11 +86,12 @@ function readDocx(docx) {
|
|
|
84
86
|
endIndex: bodyIndexForBlock(blocks, s.endIndex)
|
|
85
87
|
}));
|
|
86
88
|
const stylesData = pkg.getPart(STYLES_PART);
|
|
87
|
-
const styles = stylesData ? parseStyles(stylesData) : EMPTY_STYLE_SHEET;
|
|
89
|
+
const styles = stylesData ? parseStyles(stylesData, themeFonts) : EMPTY_STYLE_SHEET;
|
|
88
90
|
const numberingData = pkg.getPart(NUMBERING_PART);
|
|
89
|
-
const numbering = numberingData ? parseNumbering(numberingData, makeImageResolver(pkg, resources, NUMBERING_PART)) : EMPTY_NUMBERING;
|
|
91
|
+
const numbering = numberingData ? parseNumbering(numberingData, makeImageResolver(pkg, resources, NUMBERING_PART), themeFonts) : EMPTY_NUMBERING;
|
|
90
92
|
const noteCtx = (part) => ({
|
|
91
93
|
resolveColor,
|
|
94
|
+
...themeFonts ? { themeFonts } : {},
|
|
92
95
|
resolveImage: makeImageResolver(pkg, resources, part),
|
|
93
96
|
resolveHyperlink: makeHyperlinkResolver(pkg, part)
|
|
94
97
|
});
|
|
@@ -182,29 +185,42 @@ function infoFromCore(core) {
|
|
|
182
185
|
}
|
|
183
186
|
function makeDiagramResolver(pkg, partName, store) {
|
|
184
187
|
const cache = /* @__PURE__ */ new Map();
|
|
185
|
-
return (relId) => {
|
|
186
|
-
|
|
188
|
+
return (relId, frame) => {
|
|
189
|
+
const key = `${relId}|${frame.cx}x${frame.cy}`;
|
|
190
|
+
if (cache.has(key)) return cache.get(key);
|
|
187
191
|
let resolved;
|
|
188
192
|
const dataRel = pkg.getPartRelationships(partName).find((r) => r.id === relId);
|
|
189
193
|
const data = dataRel ? pkg.resolveRelatedPart(partName, dataRel) : void 0;
|
|
190
194
|
if (data) {
|
|
191
195
|
const own = pkg.getPartRelationships(data.path).find((r) => r.type.endsWith("/diagramDrawing"));
|
|
192
196
|
const draw = own ? pkg.resolveRelatedPart(data.path, own) : drawingFromOwner(pkg, partName, data.path);
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
197
|
+
const cached = draw ? cachedDiagramTree(draw.data, parseXml) : void 0;
|
|
198
|
+
if (cached && draw) resolved = {
|
|
199
|
+
spTree: cached,
|
|
200
|
+
resolveImage: makeImageResolver(pkg, store, draw.path)
|
|
201
|
+
};
|
|
202
|
+
else {
|
|
203
|
+
const spTree = laidOutDiagramTree({
|
|
204
|
+
data: data.data,
|
|
205
|
+
layout: siblingPart(pkg, partName, data.path, "/diagramLayout"),
|
|
206
|
+
colors: siblingPart(pkg, partName, data.path, "/diagramColors")
|
|
207
|
+
}, frame, parseXml);
|
|
208
|
+
if (spTree) resolved = { spTree };
|
|
202
209
|
}
|
|
203
210
|
}
|
|
204
|
-
cache.set(
|
|
211
|
+
cache.set(key, resolved);
|
|
205
212
|
return resolved;
|
|
206
213
|
};
|
|
207
214
|
}
|
|
215
|
+
function siblingPart(pkg, ownerPart, dataPart, type) {
|
|
216
|
+
const own = pkg.getPartRelationships(dataPart).find((r) => r.type.endsWith(type));
|
|
217
|
+
if (own) return pkg.resolveRelatedPart(dataPart, own)?.data;
|
|
218
|
+
const index = (path) => /(\d*)\.[^.]+$/u.exec(path)?.[1] ?? "";
|
|
219
|
+
const want = index(dataPart);
|
|
220
|
+
const rels = pkg.getPartRelationships(ownerPart).filter((r) => r.type.endsWith(type));
|
|
221
|
+
const rel = rels.find((r) => index(r.target) === want) ?? (rels.length === 1 ? rels[0] : void 0);
|
|
222
|
+
return rel ? pkg.resolveRelatedPart(ownerPart, rel)?.data : void 0;
|
|
223
|
+
}
|
|
208
224
|
function drawingFromOwner(pkg, ownerPart, dataPart) {
|
|
209
225
|
const drawings = pkg.getPartRelationships(ownerPart).filter((r) => r.type.endsWith("/diagramDrawing"));
|
|
210
226
|
if (drawings.length === 0) return void 0;
|
|
@@ -38,10 +38,11 @@ export interface ConvertDocxOptions extends Omit<StyledRenderOptions, 'registry'
|
|
|
38
38
|
*/
|
|
39
39
|
export declare function convertDocxToPdfSync(docx: Uint8Array, options: ConvertDocxOptions): Uint8Array;
|
|
40
40
|
/**
|
|
41
|
-
* The distinct curated font families the document references
|
|
42
|
-
* `
|
|
43
|
-
* `'arimo'` as a fallback for
|
|
44
|
-
*
|
|
41
|
+
* The distinct curated font families the document references — the `w:ascii` of
|
|
42
|
+
* `styles.xml` + `document.xml`, and the theme slots they point at instead
|
|
43
|
+
* (§17.3.2.26) — always including the sans default `'arimo'` as a fallback for
|
|
44
|
+
* unstyled runs / math / charts. The async path fetches one substitute set per
|
|
45
|
+
* family so each run renders in the right one.
|
|
45
46
|
*
|
|
46
47
|
* @param docx The `.docx` bytes.
|
|
47
48
|
* @returns The resolved {@link FamilyKey} set; just the default when the package
|
|
@@ -76,9 +77,9 @@ export declare function resolveDocxAutoFonts(docx: Uint8Array, options?: {
|
|
|
76
77
|
}>;
|
|
77
78
|
/**
|
|
78
79
|
* Best-effort detection of the document's primary font family, used to choose a
|
|
79
|
-
* substitute for auto-download. Prefers the document defaults'
|
|
80
|
-
*
|
|
81
|
-
* need to fully parse for this hint.
|
|
80
|
+
* substitute for auto-download. Prefers the document defaults' font — spelled
|
|
81
|
+
* out or pointed at in the theme — then falls back to the most frequent run
|
|
82
|
+
* font. A cheap regex over the XML: no need to fully parse for this hint.
|
|
82
83
|
*
|
|
83
84
|
* @param docx The `.docx` bytes.
|
|
84
85
|
* @returns The detected family name, or `undefined` when none is found.
|
|
@@ -3,12 +3,15 @@ import { FontRegistry } from "../core/font/font-registry.js";
|
|
|
3
3
|
import { signPdf } from "../pdf/signature.js";
|
|
4
4
|
import { renderStyledPdf, renderStyledPdfEncrypted } from "../pdf/styled-page-renderer.js";
|
|
5
5
|
import "../pdf/index.js";
|
|
6
|
+
import { parseThemeFonts } from "../core/drawingml/theme-parser.js";
|
|
6
7
|
import { OpcPackage } from "../core/opc/package.js";
|
|
7
8
|
import "../core/opc/index.js";
|
|
9
|
+
import { resolveWordThemeFont } from "./theme-fonts.js";
|
|
8
10
|
import { readDocx } from "./docx-reader.js";
|
|
9
11
|
import { flowRenderOptions } from "../core/converter/project.js";
|
|
10
12
|
//#region src/word/docx-to-pdf.ts
|
|
11
13
|
var STYLES_PART = "word/styles.xml";
|
|
14
|
+
var THEME_PART = "word/theme/theme1.xml";
|
|
12
15
|
var MAIN_DOCUMENT_PART = "word/document.xml";
|
|
13
16
|
/**
|
|
14
17
|
* Synchronous one-shot conversion (requires `fonts`/`fontBytes`, no network).
|
|
@@ -49,10 +52,11 @@ function prepareDocxStyledRender(docx, options) {
|
|
|
49
52
|
};
|
|
50
53
|
}
|
|
51
54
|
/**
|
|
52
|
-
* The distinct curated font families the document references
|
|
53
|
-
* `
|
|
54
|
-
* `'arimo'` as a fallback for
|
|
55
|
-
*
|
|
55
|
+
* The distinct curated font families the document references — the `w:ascii` of
|
|
56
|
+
* `styles.xml` + `document.xml`, and the theme slots they point at instead
|
|
57
|
+
* (§17.3.2.26) — always including the sans default `'arimo'` as a fallback for
|
|
58
|
+
* unstyled runs / math / charts. The async path fetches one substitute set per
|
|
59
|
+
* family so each run renders in the right one.
|
|
56
60
|
*
|
|
57
61
|
* @param docx The `.docx` bytes.
|
|
58
62
|
* @returns The resolved {@link FamilyKey} set; just the default when the package
|
|
@@ -67,16 +71,30 @@ function detectDocxFamilyKeys(docx) {
|
|
|
67
71
|
return keys;
|
|
68
72
|
}
|
|
69
73
|
const decoder = new TextDecoder("utf-8");
|
|
70
|
-
const
|
|
74
|
+
const themeFonts = docxThemeFonts(pkg);
|
|
75
|
+
const re = /<w:rFonts[^>]*?\bw:(ascii|asciiTheme)="([^"]+)"/g;
|
|
71
76
|
for (const part of [STYLES_PART, MAIN_DOCUMENT_PART]) {
|
|
72
77
|
const data = pkg.getPart(part);
|
|
73
78
|
if (!data) continue;
|
|
74
79
|
const xml = decoder.decode(data);
|
|
75
80
|
let m;
|
|
76
|
-
while ((m = re.exec(xml)) !== null)
|
|
81
|
+
while ((m = re.exec(xml)) !== null) {
|
|
82
|
+
const name = m[1] === "ascii" ? m[2] : resolveWordThemeFont(m[2], themeFonts);
|
|
83
|
+
if (name !== void 0) keys.add(resolveFamilyKey(name));
|
|
84
|
+
}
|
|
77
85
|
}
|
|
78
86
|
return keys;
|
|
79
87
|
}
|
|
88
|
+
/** §20.1.4.1.16 — the theme's font scheme, for the slots `w:rFonts` points at. */
|
|
89
|
+
function docxThemeFonts(pkg) {
|
|
90
|
+
const data = pkg.getPart(THEME_PART);
|
|
91
|
+
if (!data) return void 0;
|
|
92
|
+
try {
|
|
93
|
+
return parseThemeFonts(data);
|
|
94
|
+
} catch {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
80
98
|
/**
|
|
81
99
|
* One-shot .docx → PDF (auto-downloads a substitute font set when the caller
|
|
82
100
|
* supplies none; zero network with `fonts`/`fontBytes`).
|
|
@@ -140,4 +158,4 @@ async function resolveDocxAutoFonts(docx, options = {}) {
|
|
|
140
158
|
};
|
|
141
159
|
}
|
|
142
160
|
//#endregion
|
|
143
|
-
export { convertDocxToPdf
|
|
161
|
+
export { convertDocxToPdf };
|
|
@@ -157,6 +157,26 @@ export declare function parseVmlPicture(node: PoNode, parseBody?: ParseBody): Dr
|
|
|
157
157
|
* @returns The fill.
|
|
158
158
|
*/
|
|
159
159
|
export declare function vmlFill(shape: PoNode, shapeType?: PoNode, resolveImage?: (id: string) => ResourceId | undefined): ShapeFill;
|
|
160
|
+
/**
|
|
161
|
+
* §20.1.8.55 `a:srcRect` — the picture's own edges, cut away before it is
|
|
162
|
+
* fitted to its frame. Each is a percentage in thousandths (ST_Percentage), so
|
|
163
|
+
* `l="14711"` drops the left 14.711%.
|
|
164
|
+
*
|
|
165
|
+
* @param node The `a:srcRect` element, or `undefined` when the fill declares none.
|
|
166
|
+
* @returns The crop, or `undefined` when nothing is cut away.
|
|
167
|
+
*/
|
|
168
|
+
export declare function parseSrcRect(node: PoNode | undefined): ImageCrop | undefined;
|
|
169
|
+
/**
|
|
170
|
+
* The fill with the direction the SHAPE states, where it states one and no
|
|
171
|
+
* colours: §20.1.8.33's `a:gradFill` holding only an `a:lin` says "sweep the
|
|
172
|
+
* gallery style's run of colours this way". 63200.pptx's ellipse asks for the
|
|
173
|
+
* diagonal where the theme's slot sweeps straight down.
|
|
174
|
+
*
|
|
175
|
+
* @param fill The fill resolved from the style (or anywhere else).
|
|
176
|
+
* @param spPr The shape's own properties.
|
|
177
|
+
* @returns The fill, turned; unchanged when the shape states no bare direction.
|
|
178
|
+
*/
|
|
179
|
+
export declare function withStatedDirection(fill: ShapeFill, spPr: PoNode | undefined): ShapeFill;
|
|
160
180
|
/**
|
|
161
181
|
* Whether an `spPr` states a fill AT ALL — including `a:noFill`, which is a
|
|
162
182
|
* shape saying it has none rather than saying nothing. A placeholder that says
|