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.
Files changed (37) hide show
  1. package/dist/esm/core/bytes.d.ts +22 -4
  2. package/dist/esm/core/bytes.js +73 -5
  3. package/dist/esm/core/document-model/types.d.ts +60 -0
  4. package/dist/esm/core/drawingml/chart-parser.d.ts +2 -1
  5. package/dist/esm/core/drawingml/chart-parser.js +23 -1
  6. package/dist/esm/core/drawingml/colors.d.ts +27 -3
  7. package/dist/esm/core/drawingml/colors.js +30 -6
  8. package/dist/esm/core/drawingml/preset-geometry.js +236 -0
  9. package/dist/esm/core/metafile/emf.js +2 -1
  10. package/dist/esm/core/metafile/symbol-fonts.d.ts +42 -0
  11. package/dist/esm/core/metafile/symbol-fonts.js +154 -0
  12. package/dist/esm/core/metafile/wmf.js +35 -2
  13. package/dist/esm/core/vector.d.ts +5 -0
  14. package/dist/esm/excel/sheet-shape-parser.js +1 -12
  15. package/dist/esm/excel/xlsx-reader.d.ts +1 -1
  16. package/dist/esm/excel/xlsx-reader.js +3 -3
  17. package/dist/esm/layout/page-doc.d.ts +38 -0
  18. package/dist/esm/layout/page-doc.js +34 -18
  19. package/dist/esm/layout/styled-layout.js +174 -49
  20. package/dist/esm/pdf/shading.d.ts +19 -0
  21. package/dist/esm/pdf/shading.js +84 -11
  22. package/dist/esm/pdf/styled-page-emitter.js +614 -444
  23. package/dist/esm/pptx/ole-preview.d.ts +10 -0
  24. package/dist/esm/pptx/ole-preview.js +52 -0
  25. package/dist/esm/pptx/placeholder-cascade.d.ts +69 -5
  26. package/dist/esm/pptx/placeholder-cascade.js +162 -25
  27. package/dist/esm/pptx/pptx-reader.js +247 -39
  28. package/dist/esm/pptx/slide-parser.d.ts +72 -10
  29. package/dist/esm/pptx/slide-parser.js +310 -82
  30. package/dist/esm/pptx/sp-helpers.js +19 -4
  31. package/dist/esm/pptx/table-style.d.ts +56 -0
  32. package/dist/esm/pptx/table-style.js +161 -0
  33. package/dist/esm/svg/svg-writer.js +53 -5
  34. package/dist/esm/word/docx-reader.js +2 -2
  35. package/dist/esm/word/drawing-parser.d.ts +34 -0
  36. package/dist/esm/word/drawing-parser.js +159 -13
  37. 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 { bytesIncludePartName } from "../core/bytes.js";
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 { backdropElement, parseBackgroundFill, parseSlideShapes } from "./slide-parser.js";
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 styles = slideStylesFor(pkg, part.path, stylesByLayout);
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
- body.push(...parseSlide(part.data, ctx, styles.background, pageW, pageH));
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(data, ctx, inheritedBg, pageW, pageH) {
158
- const sld = parseXml(data).find((n) => poIs(n, "p: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 bg = (bgNode ? parseBackgroundFill(bgNode, colors) : void 0) ?? inheritedBg;
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
- if (spTree) out.push(...parseSlideShapes(spTree, ctx));
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
- if (data) {
216
- const drawRel = pkg.getPartRelationships(data.path).find((r) => r.type.endsWith("/diagramDrawing"));
217
- const draw = drawRel ? pkg.resolveRelatedPart(data.path, drawRel) : void 0;
218
- if (draw) for (const root of parseXml(draw.data)) {
219
- const found = poFindDescendant(root, "dsp:spTree");
220
- if (found) {
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
- function slideStylesFor(pkg, slidePath, cache) {
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 cached = cache.get(layout.path);
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 cascade = buildPlaceholderCascade(layoutTree, masterTree, colors);
242
- const background = partBackground(layoutTree, "p:sldLayout", colors) ?? (masterTree ? partBackground(masterTree, "p:sldMaster", colors) : void 0);
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
- ...background ? { background } : {}
379
+ ...themeFills ? { themeFills } : {},
380
+ ...themeLineWidths && themeLineWidths.length > 0 ? { themeLineWidths } : {},
381
+ ...background ? { background } : {},
382
+ ...inheritedShapes.length > 0 ? { inheritedShapes } : {}
247
383
  };
248
- cache.set(layout.path, styles);
384
+ cache.set(key, styles);
249
385
  return styles;
250
386
  }
251
- function deckColorResolver(pkg, masterPath) {
252
- const themeRel = pkg.getPartRelationships(masterPath).find((r) => r.type.endsWith("/theme"));
253
- const theme = themeRel ? pkg.resolveRelatedPart(masterPath, themeRel) : void 0;
254
- if (!theme) return defaultColorResolver;
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.data)) palette.set(slot, hex);
257
- return makeColorResolver(palette);
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 && bytesIncludePartName(bytes, "ppt/presentation.xml"),
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:bg` → the background fill, or `undefined` when none/unsupported. `p:bgPr`
110
- * carries the fill directly (`a:solidFill`/`a:gradFill` — the same children
111
- * `parseFill` reads; a picture background is not yet supported); `p:bgRef` (a
112
- * theme fill-style index) is approximated by its colour child as a solid fill.
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
- * `p:spPr` geometry: `a:prstGeom` (preset) or `a:custGeom` (custom path), default
127
- * rect. Exported for sheet shapes (E-SHEET W2), whose `xdr:spPr` carries the same
128
- * `a:` children.
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 {};