reamkit 1.21.0 → 1.22.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/bytes.d.ts +22 -4
- package/dist/esm/core/bytes.js +73 -5
- package/dist/esm/core/document-model/types.d.ts +60 -0
- package/dist/esm/core/drawingml/chart-parser.d.ts +2 -1
- package/dist/esm/core/drawingml/chart-parser.js +23 -1
- package/dist/esm/core/drawingml/colors.d.ts +27 -3
- package/dist/esm/core/drawingml/colors.js +30 -6
- package/dist/esm/core/drawingml/preset-geometry.js +236 -0
- package/dist/esm/core/metafile/emf.js +2 -1
- package/dist/esm/core/metafile/symbol-fonts.d.ts +42 -0
- package/dist/esm/core/metafile/symbol-fonts.js +154 -0
- package/dist/esm/core/metafile/wmf.js +35 -2
- package/dist/esm/core/vector.d.ts +5 -0
- package/dist/esm/excel/sheet-shape-parser.js +1 -12
- package/dist/esm/excel/xlsx-reader.d.ts +1 -1
- package/dist/esm/excel/xlsx-reader.js +3 -3
- package/dist/esm/layout/page-doc.d.ts +38 -0
- package/dist/esm/layout/page-doc.js +34 -18
- package/dist/esm/layout/styled-layout.js +174 -49
- package/dist/esm/pdf/shading.d.ts +19 -0
- package/dist/esm/pdf/shading.js +84 -11
- package/dist/esm/pdf/styled-page-emitter.js +614 -444
- package/dist/esm/pptx/ole-preview.d.ts +10 -0
- package/dist/esm/pptx/ole-preview.js +52 -0
- package/dist/esm/pptx/placeholder-cascade.d.ts +69 -5
- package/dist/esm/pptx/placeholder-cascade.js +162 -25
- package/dist/esm/pptx/pptx-reader.js +247 -39
- package/dist/esm/pptx/slide-parser.d.ts +72 -10
- package/dist/esm/pptx/slide-parser.js +310 -82
- package/dist/esm/pptx/sp-helpers.js +19 -4
- package/dist/esm/pptx/table-style.d.ts +56 -0
- package/dist/esm/pptx/table-style.js +161 -0
- package/dist/esm/svg/svg-writer.js +53 -5
- package/dist/esm/word/docx-reader.js +2 -2
- package/dist/esm/word/drawing-parser.d.ts +34 -0
- package/dist/esm/word/drawing-parser.js +159 -13
- package/package.json +1 -1
|
@@ -4,14 +4,15 @@ import { FEATURES } from "../core/ir/features.js";
|
|
|
4
4
|
import { EMPTY_STYLE_SHEET, resolveBodyStyles } from "../core/style-cascade/resolver.js";
|
|
5
5
|
import "../core/style-cascade/index.js";
|
|
6
6
|
import { poAttr, poChildren, poFindDescendant, poIntAttr, poIs } from "../core/po-helpers.js";
|
|
7
|
-
import {
|
|
8
|
-
import { DEFAULT_THEME_PALETTE, defaultColorResolver, makeColorResolver } from "../core/drawingml/colors.js";
|
|
7
|
+
import { packageHasPart } from "../core/bytes.js";
|
|
8
|
+
import { DEFAULT_SCHEME_ALIAS, DEFAULT_THEME_PALETTE, defaultColorResolver, makeColorResolver } from "../core/drawingml/colors.js";
|
|
9
9
|
import { parseChart, withChartColorStyle } from "../core/drawingml/chart-parser.js";
|
|
10
|
-
import { parseTheme } from "../core/drawingml/theme-parser.js";
|
|
10
|
+
import { parseTheme, parseThemeBgFillStyles, parseThemeFillStyles, parseThemeLineWidths } from "../core/drawingml/theme-parser.js";
|
|
11
11
|
import { OpcPackage } from "../core/opc/package.js";
|
|
12
12
|
import "../core/opc/index.js";
|
|
13
|
-
import { buildPlaceholderCascade } from "./placeholder-cascade.js";
|
|
14
|
-
import {
|
|
13
|
+
import { buildPlaceholderCascade, parseLevelStyles } from "./placeholder-cascade.js";
|
|
14
|
+
import { normalizeSpid, parseVmlImageRels } from "./ole-preview.js";
|
|
15
|
+
import { asBackdrop, backdropElement, parseBackgroundFill, parseSlideShapes } from "./slide-parser.js";
|
|
15
16
|
import { XMLParser } from "fast-xml-parser";
|
|
16
17
|
//#region src/pptx/pptx-reader.ts
|
|
17
18
|
var EMU_PER_PT = 12700;
|
|
@@ -47,15 +48,18 @@ function readPptx(bytes) {
|
|
|
47
48
|
const losses = [];
|
|
48
49
|
const pkg = OpcPackage.open(bytes);
|
|
49
50
|
const presPath = pkg.getMainDocumentPath();
|
|
51
|
+
const tableStyles = makeTableStyleResolver(pkg, presPath);
|
|
50
52
|
const presData = pkg.getPart(presPath);
|
|
51
53
|
const resources = new ResourceStore();
|
|
52
54
|
const charts = /* @__PURE__ */ new Map();
|
|
53
55
|
let cx = DEFAULT_CX;
|
|
54
56
|
let cy = DEFAULT_CY;
|
|
57
|
+
let defaultTextStyle;
|
|
55
58
|
const slideParts = [];
|
|
56
59
|
if (presData) {
|
|
57
60
|
const pres = parser.parse(decoder.decode(presData)).find((n) => poIs(n, "p:presentation"));
|
|
58
61
|
const kids = pres ? poChildren(pres) : [];
|
|
62
|
+
defaultTextStyle = kids.find((c) => poIs(c, "p:defaultTextStyle"));
|
|
59
63
|
const sldSz = kids.find((c) => poIs(c, "p:sldSz"));
|
|
60
64
|
cx = (sldSz ? poIntAttr(sldSz, "cx") : void 0) || DEFAULT_CX;
|
|
61
65
|
cy = (sldSz ? poIntAttr(sldSz, "cy") : void 0) || DEFAULT_CY;
|
|
@@ -103,20 +107,37 @@ function readPptx(bytes) {
|
|
|
103
107
|
});
|
|
104
108
|
const part = slideParts[i];
|
|
105
109
|
if (part) {
|
|
106
|
-
const
|
|
110
|
+
const slideTree = parseXml(part.data);
|
|
111
|
+
const styles = slideStylesFor(pkg, part.path, stylesByLayout, resources, charts, (loss) => losses.push(loss.where ? loss : {
|
|
112
|
+
...loss,
|
|
113
|
+
where: `slide ${i + 1}`
|
|
114
|
+
}), defaultTextStyle, {
|
|
115
|
+
widthPt: pageW,
|
|
116
|
+
heightPt: pageH
|
|
117
|
+
}, overrideAlias(slideTree, "p:sld"));
|
|
107
118
|
const ctx = {
|
|
108
119
|
...styles.cascade ? { cascade: styles.cascade } : {},
|
|
109
120
|
colors: styles.colors,
|
|
121
|
+
...styles.background ? { backgroundFill: styles.background } : {},
|
|
122
|
+
slideSize: {
|
|
123
|
+
widthPt: pageW,
|
|
124
|
+
heightPt: pageH
|
|
125
|
+
},
|
|
126
|
+
...styles.themeFills ? { themeFills: styles.themeFills } : {},
|
|
127
|
+
...styles.themeLineWidths ? { themeLineWidths: styles.themeLineWidths } : {},
|
|
110
128
|
resolveImage: makeSlideImageResolver(pkg, part.path, resources),
|
|
111
|
-
resolveChart: makeSlideChartResolver(pkg, part.path, charts, styles.colors),
|
|
129
|
+
resolveChart: makeSlideChartResolver(pkg, part.path, charts, styles.colors, resources),
|
|
112
130
|
resolveHyperlink: makeHyperlinkResolver(pkg, part.path),
|
|
113
131
|
resolveDiagram: makeSlideDiagramResolver(pkg, part.path),
|
|
132
|
+
resolveOlePreview: makeOlePreviewResolver(pkg, part.path, resources),
|
|
133
|
+
resolveTableStyle: tableStyles,
|
|
114
134
|
onLoss: (loss) => losses.push(loss.where ? loss : {
|
|
115
135
|
...loss,
|
|
116
136
|
where: `slide ${i + 1}`
|
|
117
137
|
})
|
|
118
138
|
};
|
|
119
|
-
|
|
139
|
+
const inherited = showMasterShapes(slideTree, "p:sld") ? styles.inheritedShapes ?? [] : [];
|
|
140
|
+
body.push(...parseSlide(slideTree, ctx, styles.background, pageW, pageH, inherited));
|
|
120
141
|
}
|
|
121
142
|
}
|
|
122
143
|
const section = {
|
|
@@ -154,23 +175,29 @@ function readPptx(bytes) {
|
|
|
154
175
|
function parseXml(data) {
|
|
155
176
|
return parser.parse(decoder.decode(data));
|
|
156
177
|
}
|
|
157
|
-
function parseSlide(
|
|
158
|
-
const sld =
|
|
178
|
+
function parseSlide(tree, ctx, inheritedBg, pageW, pageH, inheritedShapes = []) {
|
|
179
|
+
const sld = tree.find((n) => poIs(n, "p:sld"));
|
|
159
180
|
const cSld = sld ? poChildren(sld).find((c) => poIs(c, "p:cSld")) : void 0;
|
|
160
181
|
const colors = ctx.colors ?? defaultColorResolver;
|
|
161
182
|
const bgNode = cSld ? poChildren(cSld).find((c) => poIs(c, "p:bg")) : void 0;
|
|
162
|
-
const
|
|
183
|
+
const own = bgNode ? parseBackgroundFill(bgNode, colors, ctx.resolveImage, ctx.themeFills) : void 0;
|
|
184
|
+
const bg = own ?? inheritedBg;
|
|
163
185
|
const spTree = cSld ? poChildren(cSld).find((c) => poIs(c, "p:spTree")) : void 0;
|
|
186
|
+
const shapeCtx = own ? {
|
|
187
|
+
...ctx,
|
|
188
|
+
backgroundFill: own
|
|
189
|
+
} : ctx;
|
|
164
190
|
const out = [];
|
|
165
191
|
if (bg) out.push(backdropElement(bg, pageW, pageH));
|
|
166
|
-
|
|
192
|
+
out.push(...inheritedShapes.map(asBackdrop));
|
|
193
|
+
if (spTree) out.push(...parseSlideShapes(spTree, shapeCtx));
|
|
167
194
|
return out;
|
|
168
195
|
}
|
|
169
|
-
function partBackground(tree, root, colors) {
|
|
196
|
+
function partBackground(tree, root, colors, resolveImage, themeFills) {
|
|
170
197
|
const sld = tree.find((n) => poIs(n, root));
|
|
171
198
|
const cSld = sld ? poChildren(sld).find((c) => poIs(c, "p:cSld")) : void 0;
|
|
172
199
|
const bg = cSld ? poChildren(cSld).find((c) => poIs(c, "p:bg")) : void 0;
|
|
173
|
-
return bg ? parseBackgroundFill(bg, colors) : void 0;
|
|
200
|
+
return bg ? parseBackgroundFill(bg, colors, resolveImage, themeFills) : void 0;
|
|
174
201
|
}
|
|
175
202
|
function makeSlideImageResolver(pkg, slidePath, resources) {
|
|
176
203
|
const cache = /* @__PURE__ */ new Map();
|
|
@@ -183,19 +210,77 @@ function makeSlideImageResolver(pkg, slidePath, resources) {
|
|
|
183
210
|
return id;
|
|
184
211
|
};
|
|
185
212
|
}
|
|
213
|
+
/**
|
|
214
|
+
* The preview picture resolver for one slide's embedded objects: a `p:oleObj`
|
|
215
|
+
* `@spid` → the media the slide's legacy VML drawing hangs off that shape.
|
|
216
|
+
*
|
|
217
|
+
* Two relationship hops, and neither is the slide's own: the slide names the
|
|
218
|
+
* VML part, and the VML part names the picture. The whole part is read once,
|
|
219
|
+
* lazily — most slides have no embedded object at all.
|
|
220
|
+
*/
|
|
221
|
+
function makeOlePreviewResolver(pkg, slidePath, resources) {
|
|
222
|
+
let byShape;
|
|
223
|
+
let vmlPath;
|
|
224
|
+
const cache = /* @__PURE__ */ new Map();
|
|
225
|
+
return (spid) => {
|
|
226
|
+
const key = normalizeSpid(spid);
|
|
227
|
+
if (cache.has(key)) return cache.get(key);
|
|
228
|
+
if (byShape === void 0) {
|
|
229
|
+
const rel = pkg.getPartRelationships(slidePath).find((r) => r.type.endsWith("/vmlDrawing") || r.type.endsWith("/legacyDrawing"));
|
|
230
|
+
const part = rel ? pkg.resolveRelatedPart(slidePath, rel) : void 0;
|
|
231
|
+
byShape = part ? parseVmlImageRels(part.data) : /* @__PURE__ */ new Map();
|
|
232
|
+
vmlPath = part?.path;
|
|
233
|
+
}
|
|
234
|
+
const relId = byShape.get(key);
|
|
235
|
+
const imgRel = relId !== void 0 && vmlPath !== void 0 ? pkg.getPartRelationships(vmlPath).find((r) => r.id === relId) : void 0;
|
|
236
|
+
const media = imgRel && vmlPath !== void 0 ? pkg.resolveRelatedPart(vmlPath, imgRel) : void 0;
|
|
237
|
+
const id = media ? resources.put(media.data) : void 0;
|
|
238
|
+
cache.set(key, id);
|
|
239
|
+
return id;
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* §20.1.4.2.24 — the deck's table styles, by the GUID a table names.
|
|
244
|
+
*
|
|
245
|
+
* The list's own `@def` is NOT a fallback: it is the style PowerPoint applies
|
|
246
|
+
* when a table is INSERTED, and the table then records that GUID itself. A
|
|
247
|
+
* table that names none wears none — table-with-no-theme's two rows are bare
|
|
248
|
+
* text in a plain frame, not the blue banding `@def` points at.
|
|
249
|
+
*
|
|
250
|
+
* The part is read once, on the first table in the deck.
|
|
251
|
+
*/
|
|
252
|
+
function makeTableStyleResolver(pkg, presPath) {
|
|
253
|
+
let byId;
|
|
254
|
+
return (styleId) => {
|
|
255
|
+
if (byId === void 0) {
|
|
256
|
+
byId = /* @__PURE__ */ new Map();
|
|
257
|
+
const rel = pkg.getPartRelationships(presPath).find((r) => r.type.endsWith("/tableStyles"));
|
|
258
|
+
const part = rel ? pkg.resolveRelatedPart(presPath, rel) : void 0;
|
|
259
|
+
for (const root of part ? parseXml(part.data) : []) {
|
|
260
|
+
const list = poIs(root, "a:tblStyleLst") ? root : poFindDescendant(root, "a:tblStyleLst");
|
|
261
|
+
if (!list) continue;
|
|
262
|
+
for (const style of poChildren(list)) {
|
|
263
|
+
const id = poIs(style, "a:tblStyle") ? poAttr(style, "styleId") : void 0;
|
|
264
|
+
if (id !== void 0) byId.set(id, style);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return styleId === void 0 ? void 0 : byId.get(styleId);
|
|
269
|
+
};
|
|
270
|
+
}
|
|
186
271
|
function makeHyperlinkResolver(pkg, slidePath) {
|
|
187
272
|
return (relId) => {
|
|
188
273
|
const rel = pkg.getPartRelationships(slidePath).find((r) => r.id === relId);
|
|
189
274
|
return rel && rel.targetMode === "External" ? rel.target : void 0;
|
|
190
275
|
};
|
|
191
276
|
}
|
|
192
|
-
function makeSlideChartResolver(pkg, slidePath, charts, colors) {
|
|
277
|
+
function makeSlideChartResolver(pkg, slidePath, charts, colors, resources) {
|
|
193
278
|
const cache = /* @__PURE__ */ new Map();
|
|
194
279
|
return (relId) => {
|
|
195
280
|
if (cache.has(relId)) return cache.get(relId);
|
|
196
281
|
const rel = pkg.getPartRelationships(slidePath).find((r) => r.id === relId);
|
|
197
282
|
const resolved = rel ? pkg.resolveRelatedPart(slidePath, rel) : void 0;
|
|
198
|
-
const chart = resolved ? parseChart(resolved.data, colors) : null;
|
|
283
|
+
const chart = resolved ? parseChart(resolved.data, colors, makeSlideImageResolver(pkg, resolved.path, resources)) : null;
|
|
199
284
|
let key;
|
|
200
285
|
if (chart && resolved) {
|
|
201
286
|
key = `${slidePath}!${relId}`;
|
|
@@ -212,49 +297,172 @@ function makeSlideDiagramResolver(pkg, slidePath) {
|
|
|
212
297
|
let spTree;
|
|
213
298
|
const dataRel = pkg.getPartRelationships(slidePath).find((r) => r.id === relId);
|
|
214
299
|
const data = dataRel ? pkg.resolveRelatedPart(slidePath, dataRel) : void 0;
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
const
|
|
218
|
-
if (
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
spTree = found;
|
|
222
|
-
break;
|
|
223
|
-
}
|
|
300
|
+
const draw = data ? drawingPart(pkg, slidePath, data) : void 0;
|
|
301
|
+
if (draw) for (const root of parseXml(draw.data)) {
|
|
302
|
+
const found = poFindDescendant(root, "dsp:spTree");
|
|
303
|
+
if (found) {
|
|
304
|
+
spTree = found;
|
|
305
|
+
break;
|
|
224
306
|
}
|
|
225
307
|
}
|
|
226
308
|
cache.set(relId, spTree);
|
|
227
309
|
return spTree;
|
|
228
310
|
};
|
|
229
311
|
}
|
|
230
|
-
|
|
312
|
+
/**
|
|
313
|
+
* The pre-rendered drawing a diagram's data part points at.
|
|
314
|
+
*
|
|
315
|
+
* PowerPoint names it from INSIDE the data: `<dsp:dataModelExt relId>` in the
|
|
316
|
+
* data's extension list, and that id is a relationship of the SLIDE, not of the
|
|
317
|
+
* data part. Looked for on the data part alone — where some producers do put it
|
|
318
|
+
* — two corpus decks with a `drawing1.xml` sitting right there reported having
|
|
319
|
+
* no drawing at all and rendered nothing (smartart-missing-bullet,
|
|
320
|
+
* tdf145528_SmartArt_Matrix).
|
|
321
|
+
*
|
|
322
|
+
* @param pkg The package.
|
|
323
|
+
* @param slidePath The slide the diagram is on.
|
|
324
|
+
* @param data The resolved `dgm:relIds@r:dm` data part.
|
|
325
|
+
* @returns The drawing part, or undefined when the deck ships none.
|
|
326
|
+
*/
|
|
327
|
+
function drawingPart(pkg, slidePath, data) {
|
|
328
|
+
const extRelId = parseXml(data.data).map((root) => poFindDescendant(root, "dsp:dataModelExt")).map((ext) => ext ? poAttr(ext, "relId") : void 0).find((id) => id !== void 0);
|
|
329
|
+
const bySlide = extRelId !== void 0 ? pkg.getPartRelationships(slidePath).find((r) => r.id === extRelId) : void 0;
|
|
330
|
+
if (bySlide) {
|
|
331
|
+
const part = pkg.resolveRelatedPart(slidePath, bySlide);
|
|
332
|
+
if (part) return part;
|
|
333
|
+
}
|
|
334
|
+
const own = pkg.getPartRelationships(data.path).find((r) => r.type.endsWith("/diagramDrawing"));
|
|
335
|
+
if (own) return pkg.resolveRelatedPart(data.path, own);
|
|
336
|
+
const onSlide = pkg.getPartRelationships(slidePath).filter((r) => r.type.endsWith("/diagramDrawing"));
|
|
337
|
+
return onSlide.length === 1 && onSlide[0] ? pkg.resolveRelatedPart(slidePath, onSlide[0]) : void 0;
|
|
338
|
+
}
|
|
339
|
+
function slideStylesFor(pkg, slidePath, cache, resources, charts, onLoss, deckDefaultTextStyle, slideSize, slideAlias) {
|
|
231
340
|
const layoutRel = pkg.getPartRelationships(slidePath).find((r) => r.type.endsWith("/slideLayout"));
|
|
232
341
|
const layout = layoutRel ? pkg.resolveRelatedPart(slidePath, layoutRel) : void 0;
|
|
233
342
|
if (!layout) return { colors: defaultColorResolver };
|
|
234
|
-
const
|
|
343
|
+
const key = slideAlias ? `${layout.path}|${aliasKey(slideAlias)}` : layout.path;
|
|
344
|
+
const cached = cache.get(key);
|
|
235
345
|
if (cached) return cached;
|
|
236
346
|
const masterRel = pkg.getPartRelationships(layout.path).find((r) => r.type.endsWith("/slideMaster"));
|
|
237
347
|
const master = masterRel ? pkg.resolveRelatedPart(layout.path, masterRel) : void 0;
|
|
238
|
-
const colors = master ? deckColorResolver(pkg, master.path) : defaultColorResolver;
|
|
239
348
|
const layoutTree = parseXml(layout.data);
|
|
240
349
|
const masterTree = master ? parseXml(master.data) : void 0;
|
|
241
|
-
const
|
|
242
|
-
const
|
|
350
|
+
const inheritedAlias = overrideAlias(layoutTree, "p:sldLayout") ?? (masterTree ? masterAlias(masterTree) : void 0);
|
|
351
|
+
const alias = slideAlias ?? inheritedAlias;
|
|
352
|
+
const theme = master ? themePart(pkg, master.path) : void 0;
|
|
353
|
+
const colors = master ? deckColorResolver(theme?.data, alias) : defaultColorResolver;
|
|
354
|
+
const inheritedColors = slideAlias === void 0 || !master ? colors : deckColorResolver(theme?.data, inheritedAlias);
|
|
355
|
+
const themeFills = theme ? {
|
|
356
|
+
fills: parseThemeFillStyles(theme.data),
|
|
357
|
+
backgrounds: parseThemeBgFillStyles(theme.data),
|
|
358
|
+
resolveImage: makeSlideImageResolver(pkg, theme.path, resources)
|
|
359
|
+
} : void 0;
|
|
360
|
+
const themeLineWidths = theme ? parseThemeLineWidths(theme.data) : void 0;
|
|
361
|
+
const cascade = buildPlaceholderCascade(layoutTree, masterTree, colors, parseLevelStyles(deckDefaultTextStyle, colors));
|
|
362
|
+
const background = partBackground(layoutTree, "p:sldLayout", inheritedColors, makeSlideImageResolver(pkg, layout.path, resources), themeFills) ?? (masterTree && master ? partBackground(masterTree, "p:sldMaster", inheritedColors, makeSlideImageResolver(pkg, master.path, resources), themeFills) : void 0);
|
|
363
|
+
const deps = {
|
|
364
|
+
colors: inheritedColors,
|
|
365
|
+
resources,
|
|
366
|
+
charts,
|
|
367
|
+
onLoss,
|
|
368
|
+
slideSize,
|
|
369
|
+
...themeFills ? { themeFills } : {},
|
|
370
|
+
...themeLineWidths && themeLineWidths.length > 0 ? { themeLineWidths } : {},
|
|
371
|
+
...background ? { background } : {}
|
|
372
|
+
};
|
|
373
|
+
const inheritedShapes = [];
|
|
374
|
+
if (masterTree && master && showMasterShapes(layoutTree, "p:sldLayout")) inheritedShapes.push(...partShapes(pkg, master.path, masterTree, "p:sldMaster", deps));
|
|
375
|
+
inheritedShapes.push(...partShapes(pkg, layout.path, layoutTree, "p:sldLayout", deps));
|
|
243
376
|
const styles = {
|
|
244
377
|
cascade,
|
|
245
378
|
colors,
|
|
246
|
-
...
|
|
379
|
+
...themeFills ? { themeFills } : {},
|
|
380
|
+
...themeLineWidths && themeLineWidths.length > 0 ? { themeLineWidths } : {},
|
|
381
|
+
...background ? { background } : {},
|
|
382
|
+
...inheritedShapes.length > 0 ? { inheritedShapes } : {}
|
|
247
383
|
};
|
|
248
|
-
cache.set(
|
|
384
|
+
cache.set(key, styles);
|
|
249
385
|
return styles;
|
|
250
386
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
387
|
+
/**
|
|
388
|
+
* A master's or layout's own drawn shapes — everything in its `p:spTree` that
|
|
389
|
+
* is not a placeholder, read with resolvers bound to THAT part: a logo's image
|
|
390
|
+
* relationship, a chart's, a hyperlink's are all scoped to the part that names
|
|
391
|
+
* them.
|
|
392
|
+
*/
|
|
393
|
+
function partShapes(pkg, path, tree, root, deps) {
|
|
394
|
+
const part = tree.find((n) => poIs(n, root));
|
|
395
|
+
const cSld = part ? poChildren(part).find((c) => poIs(c, "p:cSld")) : void 0;
|
|
396
|
+
const spTree = cSld ? poChildren(cSld).find((c) => poIs(c, "p:spTree")) : void 0;
|
|
397
|
+
if (!spTree) return [];
|
|
398
|
+
return parseSlideShapes(spTree, {
|
|
399
|
+
colors: deps.colors,
|
|
400
|
+
...deps.themeFills ? { themeFills: deps.themeFills } : {},
|
|
401
|
+
...deps.themeLineWidths ? { themeLineWidths: deps.themeLineWidths } : {},
|
|
402
|
+
...deps.background ? { backgroundFill: deps.background } : {},
|
|
403
|
+
slideSize: deps.slideSize,
|
|
404
|
+
resolveImage: makeSlideImageResolver(pkg, path, deps.resources),
|
|
405
|
+
resolveChart: makeSlideChartResolver(pkg, path, deps.charts, deps.colors, deps.resources),
|
|
406
|
+
resolveHyperlink: makeHyperlinkResolver(pkg, path),
|
|
407
|
+
resolveDiagram: makeSlideDiagramResolver(pkg, path),
|
|
408
|
+
onLoss: deps.onLoss
|
|
409
|
+
}, void 0, true);
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* §19.3.1.38/§19.3.1.39 `@showMasterSp` — whether this part draws the shapes it
|
|
413
|
+
* inherits. Absent, it does.
|
|
414
|
+
*/
|
|
415
|
+
function showMasterShapes(tree, root) {
|
|
416
|
+
const part = tree.find((n) => poIs(n, root));
|
|
417
|
+
return part === void 0 || poAttr(part, "showMasterSp") !== "0";
|
|
418
|
+
}
|
|
419
|
+
/** The master's `p:clrMap` (§19.3.1.6) as a scheme-alias table. */
|
|
420
|
+
function masterAlias(masterTree) {
|
|
421
|
+
const master = masterTree.find((n) => poIs(n, "p:sldMaster"));
|
|
422
|
+
const map = master ? poChildren(master).find((c) => poIs(c, "p:clrMap")) : void 0;
|
|
423
|
+
return map ? aliasFromAttrs(map) : void 0;
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* A layout's or slide's `p:clrMapOvr` (§19.3.1.7) as a scheme-alias table, or
|
|
427
|
+
* `undefined` when it holds `a:masterClrMapping` — which says "the master's",
|
|
428
|
+
* i.e. nothing of its own.
|
|
429
|
+
*/
|
|
430
|
+
function overrideAlias(tree, root) {
|
|
431
|
+
const part = tree.find((n) => poIs(n, root));
|
|
432
|
+
const ovr = part ? poChildren(part).find((c) => poIs(c, "p:clrMapOvr")) : void 0;
|
|
433
|
+
const own = ovr ? poChildren(ovr).find((c) => poIs(c, "a:overrideClrMapping")) : void 0;
|
|
434
|
+
return own ? aliasFromAttrs(own) : void 0;
|
|
435
|
+
}
|
|
436
|
+
function aliasFromAttrs(node) {
|
|
437
|
+
const alias = {};
|
|
438
|
+
for (const name of [
|
|
439
|
+
"bg1",
|
|
440
|
+
"tx1",
|
|
441
|
+
"bg2",
|
|
442
|
+
"tx2"
|
|
443
|
+
]) {
|
|
444
|
+
const slot = poAttr(node, name);
|
|
445
|
+
if (slot !== void 0) alias[name] = slot;
|
|
446
|
+
}
|
|
447
|
+
return alias;
|
|
448
|
+
}
|
|
449
|
+
/** A stable key for an alias table, so the per-layout cache can include it. */
|
|
450
|
+
function aliasKey(alias) {
|
|
451
|
+
return Object.entries(alias).sort(([a], [b]) => a < b ? -1 : 1).map(([k, v]) => `${k}=${v}`).join(",");
|
|
452
|
+
}
|
|
453
|
+
function deckColorResolver(theme, alias) {
|
|
255
454
|
const palette = new Map(DEFAULT_THEME_PALETTE);
|
|
256
|
-
for (const [slot, hex] of parseTheme(theme
|
|
257
|
-
|
|
455
|
+
if (theme) for (const [slot, hex] of parseTheme(theme)) palette.set(slot, hex);
|
|
456
|
+
if (!theme && !alias) return defaultColorResolver;
|
|
457
|
+
return makeColorResolver(palette, {
|
|
458
|
+
...DEFAULT_SCHEME_ALIAS,
|
|
459
|
+
...alias
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
/** The master's theme part, if it has one — its path names its own pictures. */
|
|
463
|
+
function themePart(pkg, masterPath) {
|
|
464
|
+
const rel = pkg.getPartRelationships(masterPath).find((r) => r.type.endsWith("/theme"));
|
|
465
|
+
return rel ? pkg.resolveRelatedPart(masterPath, rel) : void 0;
|
|
258
466
|
}
|
|
259
467
|
/**
|
|
260
468
|
* The {@link DocumentReader} for PresentationML (`.pptx`): sniffs the OPC ZIP for
|
|
@@ -271,7 +479,7 @@ var pptxReader = {
|
|
|
271
479
|
FEATURES.charts,
|
|
272
480
|
FEATURES.tables
|
|
273
481
|
]),
|
|
274
|
-
sniff: (bytes) => bytes[0] === 80 && bytes[1] === 75 &&
|
|
482
|
+
sniff: (bytes) => bytes[0] === 80 && bytes[1] === 75 && packageHasPart(bytes, "ppt/presentation.xml"),
|
|
275
483
|
read: (bytes) => readPptx(bytes)
|
|
276
484
|
};
|
|
277
485
|
//#endregion
|
|
@@ -15,6 +15,30 @@ export interface SlideContext {
|
|
|
15
15
|
readonly cascade?: PlaceholderCascade;
|
|
16
16
|
/** A slide-scoped blip relationship id (`a:blip @r:embed`) → a stored resource (PX3a). */
|
|
17
17
|
readonly resolveImage?: (relId: string) => ResourceId | undefined;
|
|
18
|
+
/** The deck theme's fill style lists, for a `p:bgRef` on this slide. */
|
|
19
|
+
readonly themeFills?: ThemeFillStyles;
|
|
20
|
+
/** §20.1.4.1.21 `a:lnStyleLst` — the widths an `a:lnRef` indexes, in points. */
|
|
21
|
+
readonly themeLineWidths?: ReadonlyArray<number>;
|
|
22
|
+
/**
|
|
23
|
+
* §19.3.1.43 — the slide's own background fill, which a shape marked
|
|
24
|
+
* `useBgFill` is painted with.
|
|
25
|
+
*/
|
|
26
|
+
readonly backgroundFill?: ShapeFill;
|
|
27
|
+
/** The slide's size, which says WHERE that background lies under a shape. */
|
|
28
|
+
readonly slideSize?: {
|
|
29
|
+
readonly widthPt: Pt;
|
|
30
|
+
readonly heightPt: Pt;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* §19.3.2.4 — the picture an embedded object shows, by the `@spid` of its
|
|
34
|
+
* shape in the slide's legacy VML drawing.
|
|
35
|
+
*/
|
|
36
|
+
readonly resolveOlePreview?: (spid: string) => ResourceId | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* §20.1.4.2.24 — the `a:tblStyle` a table names by GUID, from the deck's
|
|
39
|
+
* `tableStyles.xml`. A table that names none wears none.
|
|
40
|
+
*/
|
|
41
|
+
readonly resolveTableStyle?: (styleId: string | undefined) => PoNode | undefined;
|
|
18
42
|
/** A chart relationship id (`c:chart @r:id`) → its document-unique key (PX4a). */
|
|
19
43
|
readonly resolveChart?: (relId: string) => string | undefined;
|
|
20
44
|
/**
|
|
@@ -50,7 +74,7 @@ type GroupTransform = (box: ShapeBoxEmu) => ShapeBoxEmu;
|
|
|
50
74
|
* @param transform Maps child-space boxes to the slide (identity at the top level).
|
|
51
75
|
* @returns The container's shapes as positioned {@link BodyElement}s.
|
|
52
76
|
*/
|
|
53
|
-
export declare function parseSlideShapes(container: PoNode, ctx?: SlideContext, transform?: GroupTransform): Array<BodyElement>;
|
|
77
|
+
export declare function parseSlideShapes(container: PoNode, ctx?: SlideContext, transform?: GroupTransform, skipPlaceholders?: boolean): Array<BodyElement>;
|
|
54
78
|
/**
|
|
55
79
|
* The diagram's child shapes live in the spTree's own coordinate space
|
|
56
80
|
* (`dsp:grpSpPr/a:xfrm` `chOff`/`chExt`); map that onto a target box (the frame on
|
|
@@ -106,13 +130,43 @@ export declare function parseDiagramNodes(spTree: PoNode, transform: GroupTransf
|
|
|
106
130
|
*/
|
|
107
131
|
export declare function parseDiagramDrawing(spTree: PoNode, transform: GroupTransform, makeFloat: (box: ShapeBoxEmu) => FloatAnchor, colors: ColorResolver, resolveLink: LinkResolver): Array<ShapeBlock>;
|
|
108
132
|
/**
|
|
109
|
-
* `p:
|
|
110
|
-
*
|
|
111
|
-
|
|
112
|
-
|
|
133
|
+
* The theme fill styles a `p:bgRef` indexes into (§19.3.1.2), as the raw nodes
|
|
134
|
+
* the fill readers take.
|
|
135
|
+
*/
|
|
136
|
+
export interface ThemeFillStyles {
|
|
137
|
+
/** `a:fillStyleLst` — what an index of 1…999 names. */
|
|
138
|
+
readonly fills: ReadonlyArray<PoNode>;
|
|
139
|
+
/** `a:bgFillStyleLst` — what an index past 1000 names, 1001 being the first. */
|
|
140
|
+
readonly backgrounds: ReadonlyArray<PoNode>;
|
|
141
|
+
/**
|
|
142
|
+
* A picture named inside a style belongs to the THEME part: the Office
|
|
143
|
+
* "Berlin" background is a photograph the theme carries and its `r:embed`
|
|
144
|
+
* means nothing in the master's relationships (corpus: tdf123684, where it
|
|
145
|
+
* resolved to a different image entirely).
|
|
146
|
+
*/
|
|
147
|
+
readonly resolveImage?: (relId: string) => ResourceId | undefined;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* `p:bg` → the background fill, or `undefined` when it declares none.
|
|
151
|
+
*
|
|
152
|
+
* Two spellings. `p:bgPr` carries the fill itself — solid, gradient, or a
|
|
153
|
+
* PICTURE, which needs the owning part's image resolver since the blip's
|
|
154
|
+
* relationship is scoped to the part the background is written in. `p:bgRef`
|
|
155
|
+
* (§19.3.1.2) carries no fill at all: an index into the theme's style lists and
|
|
156
|
+
* the colour to put wherever that style says `phClr`. Read as its colour alone
|
|
157
|
+
* — which is all this did — a deck whose theme opens with a black-to-grey
|
|
158
|
+
* gradient came out flat, and one whose first background slot is a picture came
|
|
159
|
+
* out a single colour.
|
|
160
|
+
*
|
|
113
161
|
* Used for the slide's own background and the inherited layout/master one (PX5b).
|
|
162
|
+
*
|
|
163
|
+
* @param bg The `p:bg` node.
|
|
164
|
+
* @param colors The deck's colour resolver.
|
|
165
|
+
* @param resolveImage Resolver for a picture background's relationship, scoped
|
|
166
|
+
* to the part this `p:bg` is written in.
|
|
167
|
+
* @param theme The theme's fill style lists, for a `p:bgRef`.
|
|
114
168
|
*/
|
|
115
|
-
export declare function parseBackgroundFill(bg: PoNode, colors: ColorResolver): ShapeFill | undefined;
|
|
169
|
+
export declare function parseBackgroundFill(bg: PoNode, colors: ColorResolver, resolveImage?: (relId: string) => ResourceId | undefined, theme?: ThemeFillStyles): ShapeFill | undefined;
|
|
116
170
|
/**
|
|
117
171
|
* A full-slide backdrop element for a background fill: a rectangle covering the
|
|
118
172
|
* page, anchored behind the content (PX5b).
|
|
@@ -123,10 +177,18 @@ export declare function parseBackgroundFill(bg: PoNode, colors: ColorResolver):
|
|
|
123
177
|
*/
|
|
124
178
|
export declare function backdropElement(fill: ShapeFill, widthPt: Pt, heightPt: Pt): BodyElement;
|
|
125
179
|
/**
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
180
|
+
* The same element, painted BEHIND the slide's own content.
|
|
181
|
+
*
|
|
182
|
+
* §19.3.1 — a slide's shape tree is drawn over its layout's, and that over the
|
|
183
|
+
* master's; nothing a deck states once can bury what a slide puts on it. Our
|
|
184
|
+
* page paints by KIND (every image, then every shape), so without this a
|
|
185
|
+
* layout's white card landed on top of the photograph the slide is made of —
|
|
186
|
+
* themes.pptx's fifth slide is one picture and it vanished under the card.
|
|
187
|
+
*
|
|
188
|
+
* @param el The inherited element.
|
|
189
|
+
* @returns The element with its float sunk to the backdrop layer.
|
|
129
190
|
*/
|
|
191
|
+
export declare function asBackdrop(el: BodyElement): BodyElement;
|
|
130
192
|
export declare function parseGeometry(spPr: PoNode | undefined): ShapeGeometry;
|
|
131
193
|
/**
|
|
132
194
|
* `p:txBody` → {@link ShapeTextBody}. `a:bodyPr` carries the insets and the
|
|
@@ -141,5 +203,5 @@ export declare function parseGeometry(spPr: PoNode | undefined): ShapeGeometry;
|
|
|
141
203
|
* @param resolveLink A run hyperlink resolver, or `undefined`.
|
|
142
204
|
* @returns The text body, or `undefined` when it holds no paragraphs.
|
|
143
205
|
*/
|
|
144
|
-
export declare function parseTxBody(txBody: PoNode, ph: PlaceholderRef | undefined, cascade: PlaceholderCascade | undefined, colors: ColorResolver, resolveLink: LinkResolver): ShapeTextBody | undefined;
|
|
206
|
+
export declare function parseTxBody(txBody: PoNode, ph: PlaceholderRef | undefined, cascade: PlaceholderCascade | undefined, colors: ColorResolver, resolveLink: LinkResolver, styleColor?: string): ShapeTextBody | undefined;
|
|
145
207
|
export {};
|