reamkit 1.21.0 → 1.23.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 (90) 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/converter/ream.d.ts +16 -0
  4. package/dist/esm/core/converter/ream.js +59 -9
  5. package/dist/esm/core/document-model/types.d.ts +78 -0
  6. package/dist/esm/core/drawingml/chart-geometry.js +11 -5
  7. package/dist/esm/core/drawingml/chart-parser.d.ts +2 -1
  8. package/dist/esm/core/drawingml/chart-parser.js +23 -1
  9. package/dist/esm/core/drawingml/colors.d.ts +30 -4
  10. package/dist/esm/core/drawingml/colors.js +45 -6
  11. package/dist/esm/core/drawingml/preset-geometry.js +236 -0
  12. package/dist/esm/core/drawingml/theme-parser.d.ts +38 -0
  13. package/dist/esm/core/drawingml/theme-parser.js +64 -1
  14. package/dist/esm/core/fonts/families.d.ts +10 -0
  15. package/dist/esm/core/fonts/families.js +44 -0
  16. package/dist/esm/core/fonts/index.d.ts +3 -2
  17. package/dist/esm/core/fonts/remote-fonts.d.ts +50 -0
  18. package/dist/esm/core/fonts/remote-fonts.js +114 -8
  19. package/dist/esm/core/fonts/scripts.d.ts +26 -0
  20. package/dist/esm/core/fonts/scripts.js +177 -0
  21. package/dist/esm/core/metafile/blit.d.ts +33 -0
  22. package/dist/esm/core/metafile/blit.js +67 -0
  23. package/dist/esm/core/metafile/dib.d.ts +61 -0
  24. package/dist/esm/core/metafile/dib.js +205 -0
  25. package/dist/esm/core/metafile/emf.js +139 -24
  26. package/dist/esm/core/metafile/picture.d.ts +12 -1
  27. package/dist/esm/core/metafile/symbol-fonts.d.ts +42 -0
  28. package/dist/esm/core/metafile/symbol-fonts.js +154 -0
  29. package/dist/esm/core/metafile/wmf.js +183 -10
  30. package/dist/esm/core/ole/escher-blip.d.ts +12 -0
  31. package/dist/esm/core/ole/escher-blip.js +88 -0
  32. package/dist/esm/{pdf-reader → core}/png-encode.js +1 -1
  33. package/dist/esm/core/vector.d.ts +5 -0
  34. package/dist/esm/excel/print-model.js +3 -1
  35. package/dist/esm/excel/sheet-shape-parser.js +1 -12
  36. package/dist/esm/excel/styles-parser.js +1 -1
  37. package/dist/esm/excel/xls/biff-reader.js +53 -18
  38. package/dist/esm/excel/xls/biff-styles.d.ts +5 -2
  39. package/dist/esm/excel/xls/biff-styles.js +9 -7
  40. package/dist/esm/excel/xls/escher.js +90 -24
  41. package/dist/esm/excel/xlsx-reader.d.ts +1 -1
  42. package/dist/esm/excel/xlsx-reader.js +3 -3
  43. package/dist/esm/layout/page-doc.d.ts +77 -0
  44. package/dist/esm/layout/page-doc.js +34 -18
  45. package/dist/esm/layout/styled-layout.d.ts +2 -2
  46. package/dist/esm/layout/styled-layout.js +467 -76
  47. package/dist/esm/pdf/shading.d.ts +19 -0
  48. package/dist/esm/pdf/shading.js +84 -11
  49. package/dist/esm/pdf/styled-page-emitter.js +647 -444
  50. package/dist/esm/pdf-reader/image-decode.js +1 -1
  51. package/dist/esm/pptx/embedded-fonts.d.ts +31 -0
  52. package/dist/esm/pptx/embedded-fonts.js +104 -0
  53. package/dist/esm/pptx/ole-preview.d.ts +10 -0
  54. package/dist/esm/pptx/ole-preview.js +52 -0
  55. package/dist/esm/pptx/placeholder-cascade.d.ts +136 -5
  56. package/dist/esm/pptx/placeholder-cascade.js +260 -27
  57. package/dist/esm/pptx/ppt/ppt-reader.js +120 -10
  58. package/dist/esm/pptx/ppt/ppt-text.d.ts +66 -1
  59. package/dist/esm/pptx/ppt/ppt-text.js +576 -137
  60. package/dist/esm/pptx/pptx-reader.d.ts +8 -0
  61. package/dist/esm/pptx/pptx-reader.js +271 -41
  62. package/dist/esm/pptx/preset-table-styles.d.ts +9 -0
  63. package/dist/esm/pptx/preset-table-styles.js +27 -0
  64. package/dist/esm/pptx/slide-parser.d.ts +78 -10
  65. package/dist/esm/pptx/slide-parser.js +396 -95
  66. package/dist/esm/pptx/sp-helpers.d.ts +2 -1
  67. package/dist/esm/pptx/sp-helpers.js +22 -6
  68. package/dist/esm/pptx/table-style.d.ts +64 -0
  69. package/dist/esm/pptx/table-style.js +203 -0
  70. package/dist/esm/svg/svg-writer.js +53 -5
  71. package/dist/esm/word/document-parser.d.ts +7 -1
  72. package/dist/esm/word/document-parser.js +6 -6
  73. package/dist/esm/word/docx-reader.js +8 -5
  74. package/dist/esm/word/docx-to-pdf.d.ts +8 -7
  75. package/dist/esm/word/docx-to-pdf.js +25 -7
  76. package/dist/esm/word/drawing-parser.d.ts +34 -0
  77. package/dist/esm/word/drawing-parser.js +173 -15
  78. package/dist/esm/word/numbering-parser.d.ts +2 -1
  79. package/dist/esm/word/numbering-parser.js +6 -6
  80. package/dist/esm/word/paragraph-properties.d.ts +2 -1
  81. package/dist/esm/word/paragraph-properties.js +2 -2
  82. package/dist/esm/word/run-properties.d.ts +5 -2
  83. package/dist/esm/word/run-properties.js +13 -8
  84. package/dist/esm/word/styles-parser.d.ts +2 -1
  85. package/dist/esm/word/styles-parser.js +12 -12
  86. package/dist/esm/word/table-parser.js +3 -3
  87. package/dist/esm/word/theme-fonts.d.ts +10 -0
  88. package/dist/esm/word/theme-fonts.js +28 -0
  89. package/package.json +1 -1
  90. /package/dist/esm/{pdf-reader → core}/png-encode.d.ts +0 -0
@@ -1,11 +1,14 @@
1
1
  import { emuToPt, pt } from "../core/ir/units.js";
2
2
  import { FEATURES } from "../core/ir/features.js";
3
3
  import { poAttr, poChildren, poFindDescendant, poIntAttr, poIs, poTag, poText } from "../core/po-helpers.js";
4
- import { defaultColorResolver, resolveColorNode } from "../core/drawingml/colors.js";
4
+ import { defaultColorResolver, placeholderColors, resolveColorNode } from "../core/drawingml/colors.js";
5
5
  import { boxFromXfrm, parsePh, parseXfrmBox, rPrToRunProps } from "./sp-helpers.js";
6
- import { parseCustGeom, parseFill, parseLine, parsePrstGeom, parseShadow, parseXfrm } from "../word/drawing-parser.js";
6
+ import { lineSpacing, parseBullet, spacingFractions, spacingFromLineFraction } from "./placeholder-cascade.js";
7
+ import { colorChangeOf, parseCustGeom, parseFill, parseLine, parsePrstGeom, parseShadow, parseXfrm, statesFill, styleRefFill, styleRefFontColor, styleRefLine } from "../word/drawing-parser.js";
8
+ import { cellStyle, lineBorder, tableStyleFlags, tableStyleId, withCellStyle, withoutFill } from "./table-style.js";
7
9
  //#region src/pptx/slide-parser.ts
8
10
  var CHART_URI = "http://schemas.openxmlformats.org/drawingml/2006/chart";
11
+ var OLE_URI = "http://schemas.openxmlformats.org/presentationml/2006/ole";
9
12
  var TABLE_URI = "http://schemas.openxmlformats.org/drawingml/2006/table";
10
13
  var DIAGRAM_URI = "http://schemas.openxmlformats.org/drawingml/2006/diagram";
11
14
  var ALGN_TO_ALIGNMENT = {
@@ -32,24 +35,37 @@ var IDENTITY_TRANSFORM = (box) => box;
32
35
  * @param transform Maps child-space boxes to the slide (identity at the top level).
33
36
  * @returns The container's shapes as positioned {@link BodyElement}s.
34
37
  */
35
- function parseSlideShapes(container, ctx = {}, transform = IDENTITY_TRANSFORM) {
38
+ function parseSlideShapes(container, ctx = {}, transform = IDENTITY_TRANSFORM, skipPlaceholders = false) {
36
39
  const out = [];
37
- for (const child of poChildren(container)) if (poIs(child, "p:sp")) {
38
- const shape = parseSp(child, ctx, transform);
39
- if (shape) out.push({
40
- kind: "shape",
41
- shape
42
- });
43
- } else if (poIs(child, "p:pic")) {
44
- const image = parsePic(child, ctx, transform);
45
- if (image) out.push({
46
- kind: "image",
47
- image
48
- });
49
- } else if (poIs(child, "p:graphicFrame")) out.push(...parseGraphicFrame(child, ctx, transform));
50
- else if (poIs(child, "p:grpSp")) out.push(...parseSlideShapes(child, ctx, composeGroupTransform(child, transform)));
40
+ for (const child of poChildren(container)) {
41
+ if (skipPlaceholders && isPlaceholder(child)) continue;
42
+ if (poIs(child, "p:sp")) {
43
+ const shape = parseSp(child, ctx, transform);
44
+ if (shape) out.push({
45
+ kind: "shape",
46
+ shape
47
+ });
48
+ } else if (poIs(child, "p:pic")) {
49
+ const image = parsePic(child, ctx, transform);
50
+ if (image) out.push({
51
+ kind: "image",
52
+ image
53
+ });
54
+ } else if (poIs(child, "p:graphicFrame")) out.push(...parseGraphicFrame(child, ctx, transform));
55
+ else if (poIs(child, "p:grpSp")) out.push(...parseSlideShapes(child, ctx, composeGroupTransform(child, transform), skipPlaceholders));
56
+ }
51
57
  return out;
52
58
  }
59
+ /**
60
+ * Whether a shape is a placeholder — `p:ph` in its OWN non-visual properties.
61
+ * Read as "anywhere below", a group holding one would take the whole group
62
+ * with it.
63
+ */
64
+ function isPlaceholder(shape) {
65
+ const nv = poChildren(shape).find((c) => poTag(c)?.startsWith("p:nv") === true);
66
+ const nvPr = nv ? poChildren(nv).find((c) => poIs(c, "p:nvPr")) : void 0;
67
+ return nvPr !== void 0 && poChildren(nvPr).some((c) => poIs(c, "p:ph"));
68
+ }
53
69
  function composeGroupTransform(grpSp, parent) {
54
70
  const grpSpPr = poChildren(grpSp).find((c) => poIs(c, "p:grpSpPr"));
55
71
  const xfrm = grpSpPr ? poChildren(grpSpPr).find((c) => poIs(c, "a:xfrm")) : void 0;
@@ -97,20 +113,50 @@ function parseSp(sp, ctx, transform) {
97
113
  if (!own && ph && ctx.cascade) own = ctx.cascade.geometryFor(ph);
98
114
  if (!own) return void 0;
99
115
  const box = transform(own);
116
+ const style = poChildren(sp).find((c) => poIs(c, "p:style"));
100
117
  const txBody = poChildren(sp).find((c) => poIs(c, "p:txBody"));
101
- const text = txBody ? parseTxBody(txBody, ph, ctx.cascade, colors, ctx.resolveHyperlink) : void 0;
102
- const geometry = parseGeometry(spPr);
103
- const fill = spPr ? parseFill(spPr, colors) : { kind: "none" };
104
- const line = spPr ? parseLine(spPr, colors) : void 0;
118
+ const styleColor = style ? styleRefFontColor(style, colors) : void 0;
119
+ const text = txBody ? parseTxBody(txBody, ph, ctx.cascade, colors, ctx.resolveHyperlink, styleColor, ctx.themeFonts) : void 0;
120
+ const protos = ph && ctx.cascade ? ctx.cascade.shapePropsFor(ph) : [];
121
+ const from = (states) => spPr && states(spPr) ? spPr : protos.find(states) ?? spPr;
122
+ /** What the shape states ITSELF, before anything is inherited. */
123
+ const stated = (states) => spPr && states(spPr) ? spPr : void 0;
124
+ /** …and what a prototype lends it, nearest first. */
125
+ const lent = (states) => protos.find(states);
126
+ const geometry = parseGeometry(from(statesGeometry));
127
+ const useBgFill = poAttr(sp, "useBgFill") === "1";
128
+ const themeStyles = ctx.themeFills ? {
129
+ fills: ctx.themeFills.fills,
130
+ bgFills: ctx.themeFills.backgrounds
131
+ } : void 0;
132
+ const ownFill = stated(statesFill);
133
+ const styleFill = style ? styleRefFill(style, colors, themeStyles) : void 0;
134
+ const lentFill = lent(statesFill);
135
+ const styled = useBgFill ? backgroundThrough(ctx.backgroundFill, box, ctx.slideSize) : ownFill ? parseFill(ownFill, colors, ctx.resolveImage) : styleFill && styleFill.kind !== "none" ? styleFill : lentFill ? parseFill(lentFill, colors, ctx.resolveImage) : spPr ? parseFill(spPr, colors, ctx.resolveImage) : { kind: "none" };
136
+ const lineFrom = from((n) => poChildren(n).some((c) => poIs(c, "a:ln")));
137
+ let line = lineFrom ? parseLine(lineFrom, colors) : void 0;
138
+ if (style) {
139
+ const fromStyle = styleRefLine(style, colors, ctx.themeLineWidths);
140
+ if (fromStyle) line = line ? {
141
+ ...fromStyle,
142
+ ...Object.fromEntries(Object.entries(line).filter(([, v]) => v !== void 0))
143
+ } : fromStyle;
144
+ }
145
+ const shadowFrom = from((n) => poChildren(n).some((c) => poIs(c, "a:effectLst")));
146
+ const shadow = shadowFrom ? parseShadow(shadowFrom, colors) : void 0;
105
147
  const visibleLine = line !== void 0 && line.fill !== "none";
106
- if (!text && fill.kind === "none" && !visibleLine) return void 0;
148
+ if (!text && styled.kind === "none" && !visibleLine) return void 0;
149
+ const xfrm = spPr ? poChildren(spPr).find((c) => poIs(c, "a:xfrm")) : void 0;
150
+ const spin = xfrm ? parseXfrm(xfrm) : void 0;
107
151
  return {
108
152
  float: floatAt(box),
109
153
  width: emuToPt(box.cx),
110
154
  height: emuToPt(box.cy),
111
155
  geometry,
112
- fill,
156
+ fill: styled,
113
157
  ...line ? { line } : {},
158
+ ...shadow ? { shadow } : {},
159
+ ...spin && Object.keys(spin).length > 0 ? { transform: spin } : {},
114
160
  ...text ? { text } : {},
115
161
  paragraphProperties: {}
116
162
  };
@@ -139,10 +185,53 @@ function parseGraphicFrame(gf, ctx, transform) {
139
185
  }
140
186
  if (uri === TABLE_URI) {
141
187
  const tbl = poFindDescendant(gf, "a:tbl");
142
- return tbl ? [{
188
+ if (!tbl) return [];
189
+ const table = parseTable(tbl, ctx.colors ?? defaultColorResolver, ctx.resolveTableStyle, {
190
+ ...ctx.themeFills ? { fills: ctx.themeFills.fills } : {},
191
+ ...ctx.themeLineWidths ? { lineWidths: ctx.themeLineWidths } : {}
192
+ });
193
+ return [{
143
194
  kind: "table",
144
- table: parseTable(tbl, ctx.colors ?? defaultColorResolver)
145
- }] : [];
195
+ table: {
196
+ ...table,
197
+ properties: {
198
+ ...table.properties,
199
+ float: floatAt(box)
200
+ }
201
+ }
202
+ }];
203
+ }
204
+ if (uri === OLE_URI) {
205
+ const oleObj = poFindDescendant(gf, "p:oleObj");
206
+ if (!oleObj) return [];
207
+ const pic = poChildren(oleObj).find((c) => poIs(c, "p:pic"));
208
+ if (pic) {
209
+ const image = parsePic(pic, ctx, transform);
210
+ return image ? [{
211
+ kind: "image",
212
+ image
213
+ }] : [];
214
+ }
215
+ const spid = poAttr(oleObj, "spid");
216
+ const resource = spid !== void 0 ? ctx.resolveOlePreview?.(spid) : void 0;
217
+ if (resource === void 0) {
218
+ ctx.onLoss?.({
219
+ severity: "dropped",
220
+ feature: FEATURES.images,
221
+ detail: "embedded object with no preview picture — the object is not drawn"
222
+ });
223
+ return [];
224
+ }
225
+ return [{
226
+ kind: "image",
227
+ image: {
228
+ float: floatAt(box),
229
+ resource,
230
+ width: emuToPt(box.cx),
231
+ height: emuToPt(box.cy),
232
+ paragraphProperties: {}
233
+ }
234
+ }];
146
235
  }
147
236
  if (uri === DIAGRAM_URI) {
148
237
  const relIds = poFindDescendant(gf, "dgm:relIds");
@@ -152,7 +241,9 @@ function parseGraphicFrame(gf, ctx, transform) {
152
241
  if (dmRelId !== void 0) ctx.onLoss?.(noDiagramOverrideLoss());
153
242
  return [];
154
243
  }
155
- return parseDiagramDrawing(spTree, diagramTransform(spTree, box), floatAt, ctx.colors ?? defaultColorResolver, ctx.resolveHyperlink).map((shape) => ({
244
+ const drawn = parseDiagramDrawing(spTree, diagramTransform(spTree, box), floatAt, ctx.colors ?? defaultColorResolver, ctx.resolveHyperlink);
245
+ if (drawn.length === 0) ctx.onLoss?.(noDiagramOverrideLoss());
246
+ return drawn.map((shape) => ({
156
247
  kind: "shape",
157
248
  shape
158
249
  }));
@@ -229,9 +320,9 @@ function parseDiagramNodes(spTree, transform, colors, resolveLink, resolveImage)
229
320
  const box = transform(own);
230
321
  const txBody = poChildren(sp).find((c) => poIs(c, "dsp:txBody"));
231
322
  const parsed = txBody ? parseTxBody(txBody, void 0, void 0, colors, resolveLink) : void 0;
232
- const text = parsed ? withDiagramFontColor(parsed, sp, colors) : void 0;
233
323
  const geometry = parseGeometry(spPr);
234
324
  const fill = spPr ? parseFill(spPr, colors, resolveImage) : { kind: "none" };
325
+ const text = parsed ? withDiagramFontColor(parsed, sp, colors, fill) : void 0;
235
326
  const line = spPr ? parseLine(spPr, colors) : void 0;
236
327
  const shadow = spPr ? parseShadow(spPr, colors) : void 0;
237
328
  const visibleLine = line !== void 0 && line.fill !== "none";
@@ -287,12 +378,13 @@ function parseDiagramDrawing(spTree, transform, makeFloat, colors, resolveLink)
287
378
  float: makeFloat(box)
288
379
  }));
289
380
  }
290
- function withDiagramFontColor(text, sp, colors) {
381
+ function withDiagramFontColor(text, sp, colors, fill) {
291
382
  const style = poChildren(sp).find((c) => poIs(c, "dsp:style"));
292
383
  const ref = style ? poChildren(style).find((c) => poIs(c, "a:fontRef")) : void 0;
293
384
  const child = ref ? poChildren(ref).find((c) => poTag(c) !== void 0) : void 0;
294
385
  const colorHex = child ? resolveColorNode(child, colors) : void 0;
295
386
  if (colorHex === void 0) return text;
387
+ if (fill.kind === "solid" && fill.colorHex === colorHex) return text;
296
388
  return {
297
389
  ...text,
298
390
  content: text.content.map((block) => block.kind === "paragraph" ? {
@@ -311,26 +403,45 @@ function withDiagramFontColor(text, sp, colors) {
311
403
  };
312
404
  }
313
405
  /**
314
- * `p:bg` → the background fill, or `undefined` when none/unsupported. `p:bgPr`
315
- * carries the fill directly (`a:solidFill`/`a:gradFill` — the same children
316
- * `parseFill` reads; a picture background is not yet supported); `p:bgRef` (a
317
- * theme fill-style index) is approximated by its colour child as a solid fill.
406
+ * `p:bg` → the background fill, or `undefined` when it declares none.
407
+ *
408
+ * Two spellings. `p:bgPr` carries the fill itself — solid, gradient, or a
409
+ * PICTURE, which needs the owning part's image resolver since the blip's
410
+ * relationship is scoped to the part the background is written in. `p:bgRef`
411
+ * (§19.3.1.2) carries no fill at all: an index into the theme's style lists and
412
+ * the colour to put wherever that style says `phClr`. Read as its colour alone
413
+ * — which is all this did — a deck whose theme opens with a black-to-grey
414
+ * gradient came out flat, and one whose first background slot is a picture came
415
+ * out a single colour.
416
+ *
318
417
  * Used for the slide's own background and the inherited layout/master one (PX5b).
418
+ *
419
+ * @param bg The `p:bg` node.
420
+ * @param colors The deck's colour resolver.
421
+ * @param resolveImage Resolver for a picture background's relationship, scoped
422
+ * to the part this `p:bg` is written in.
423
+ * @param theme The theme's fill style lists, for a `p:bgRef`.
319
424
  */
320
- function parseBackgroundFill(bg, colors) {
425
+ function parseBackgroundFill(bg, colors, resolveImage, theme) {
321
426
  const bgPr = poChildren(bg).find((c) => poIs(c, "p:bgPr"));
322
427
  if (bgPr) {
323
- const fill = parseFill(bgPr, colors);
428
+ const fill = parseFill(bgPr, colors, resolveImage);
324
429
  return fill.kind !== "none" ? fill : void 0;
325
430
  }
326
431
  const bgRef = poChildren(bg).find((c) => poIs(c, "p:bgRef"));
327
- if (bgRef) for (const c of poChildren(bgRef)) {
328
- const hex = resolveColorNode(c, colors);
329
- if (hex) return {
330
- kind: "solid",
331
- colorHex: hex
332
- };
432
+ if (!bgRef) return void 0;
433
+ const child = poChildren(bgRef).find((c) => poTag(c) !== void 0);
434
+ const hex = child ? resolveColorNode(child, colors) : void 0;
435
+ const idx = poIntAttr(bgRef, "idx");
436
+ const slot = idx === void 0 ? void 0 : idx > 1e3 ? theme?.backgrounds[idx - 1001] : theme?.fills[idx - 1];
437
+ if (slot) {
438
+ const themed = parseFill({ "a:spPr": [slot] }, hex === void 0 ? colors : placeholderColors(colors, hex), theme?.resolveImage ?? resolveImage);
439
+ if (themed.kind !== "none") return themed;
333
440
  }
441
+ return hex === void 0 ? void 0 : {
442
+ kind: "solid",
443
+ colorHex: hex
444
+ };
334
445
  }
335
446
  /**
336
447
  * A full-slide backdrop element for a background fill: a rectangle covering the
@@ -364,11 +475,73 @@ function backdropElement(fill, widthPt, heightPt) {
364
475
  }
365
476
  };
366
477
  }
478
+ function backgroundThrough(bg, box, slide) {
479
+ if (!bg) return { kind: "none" };
480
+ if (bg.kind !== "picture" || !slide || box.cx <= 0 || box.cy <= 0) return bg;
481
+ const [x, y] = [emuToPt(box.x), emuToPt(box.y)];
482
+ const [w, h] = [emuToPt(box.cx), emuToPt(box.cy)];
483
+ return {
484
+ ...bg,
485
+ imageFillRect: {
486
+ left: -x / w,
487
+ top: -y / h,
488
+ right: -(slide.widthPt - x - w) / w,
489
+ bottom: -(slide.heightPt - y - h) / h
490
+ }
491
+ };
492
+ }
493
+ /**
494
+ * The same element, painted BEHIND the slide's own content.
495
+ *
496
+ * §19.3.1 — a slide's shape tree is drawn over its layout's, and that over the
497
+ * master's; nothing a deck states once can bury what a slide puts on it. Our
498
+ * page paints by KIND (every image, then every shape), so without this a
499
+ * layout's white card landed on top of the photograph the slide is made of —
500
+ * themes.pptx's fifth slide is one picture and it vanished under the card.
501
+ *
502
+ * @param el The inherited element.
503
+ * @returns The element with its float sunk to the backdrop layer.
504
+ */
505
+ function asBackdrop(el) {
506
+ const sink = (item) => item.float ? {
507
+ ...item,
508
+ float: {
509
+ ...item.float,
510
+ behind: true
511
+ }
512
+ } : item;
513
+ switch (el.kind) {
514
+ case "shape": return {
515
+ ...el,
516
+ shape: sink(el.shape)
517
+ };
518
+ case "image": return {
519
+ ...el,
520
+ image: sink(el.image)
521
+ };
522
+ case "table": return {
523
+ ...el,
524
+ table: {
525
+ ...el.table,
526
+ properties: sink(el.table.properties)
527
+ }
528
+ };
529
+ case "chart": return {
530
+ ...el,
531
+ chart: sink(el.chart)
532
+ };
533
+ default: return el;
534
+ }
535
+ }
367
536
  /**
368
537
  * `p:spPr` geometry: `a:prstGeom` (preset) or `a:custGeom` (custom path), default
369
538
  * rect. Exported for sheet shapes (E-SHEET W2), whose `xdr:spPr` carries the same
370
539
  * `a:` children.
371
540
  */
541
+ /** Whether an `spPr` states a geometry of its own, rather than inheriting one. */
542
+ function statesGeometry(spPr) {
543
+ return poChildren(spPr).some((c) => poIs(c, "a:prstGeom") || poIs(c, "a:custGeom"));
544
+ }
372
545
  function parseGeometry(spPr) {
373
546
  if (!spPr) return RECT_GEOMETRY;
374
547
  const prst = poChildren(spPr).find((c) => poIs(c, "a:prstGeom"));
@@ -385,10 +558,16 @@ function parsePic(pic, ctx, transform) {
385
558
  const blip = blipFill ? poChildren(blipFill).find((c) => poIs(c, "a:blip")) : void 0;
386
559
  const relId = blip ? poAttr(blip, "embed") : void 0;
387
560
  const resource = relId !== void 0 ? ctx.resolveImage?.(relId) : void 0;
561
+ const colorChange = blip ? colorChangeOf(blip, ctx.colors ?? defaultColorResolver) : void 0;
562
+ const fixed = blip ? poChildren(blip).find((c) => poIs(c, "a:alphaModFix")) : void 0;
563
+ const amt = fixed ? poIntAttr(fixed, "amt") : void 0;
564
+ const alpha = amt === void 0 ? void 0 : Math.min(1, Math.max(0, amt / 1e5));
388
565
  const altText = picAltText(pic);
389
566
  return {
390
567
  float: floatAt(box),
391
568
  ...resource !== void 0 ? { resource } : {},
569
+ ...colorChange ? { colorChange } : {},
570
+ ...alpha !== void 0 && alpha < 1 ? { alpha } : {},
392
571
  width: emuToPt(box.cx),
393
572
  height: emuToPt(box.cy),
394
573
  paragraphProperties: {},
@@ -402,14 +581,14 @@ function picAltText(pic) {
402
581
  const title = cNvPr ? poAttr(cNvPr, "title") : void 0;
403
582
  return (descr ?? title)?.trim() || void 0;
404
583
  }
405
- function txBodyParagraphs(txBody, ph, cascade, colors, resolveLink) {
584
+ function txBodyParagraphs(txBody, ph, cascade, colors, resolveLink, styleColor, themeFonts) {
406
585
  const content = [];
407
586
  const counters = [];
408
587
  for (const child of poChildren(txBody)) {
409
588
  if (!poIs(child, "a:p")) continue;
410
589
  content.push({
411
590
  kind: "paragraph",
412
- paragraph: parseSlideParagraph(child, ph, cascade, colors, resolveLink, counters)
591
+ paragraph: parseSlideParagraph(child, ph, cascade, colors, resolveLink, counters, styleColor, themeFonts)
413
592
  });
414
593
  }
415
594
  return content;
@@ -427,18 +606,19 @@ function txBodyParagraphs(txBody, ph, cascade, colors, resolveLink) {
427
606
  * @param resolveLink A run hyperlink resolver, or `undefined`.
428
607
  * @returns The text body, or `undefined` when it holds no paragraphs.
429
608
  */
430
- function parseTxBody(txBody, ph, cascade, colors, resolveLink) {
431
- const content = txBodyParagraphs(txBody, ph, cascade, colors, resolveLink);
609
+ function parseTxBody(txBody, ph, cascade, colors, resolveLink, styleColor, themeFonts) {
610
+ const content = txBodyParagraphs(txBody, ph, cascade, colors, resolveLink, styleColor, themeFonts);
432
611
  if (content.length === 0) return void 0;
433
612
  const bodyPr = poChildren(txBody).find((c) => poIs(c, "a:bodyPr"));
613
+ const fitted = fitToBody(content, bodyPr);
434
614
  const lIns = bodyPr ? poIntAttr(bodyPr, "lIns") : void 0;
435
615
  const tIns = bodyPr ? poIntAttr(bodyPr, "tIns") : void 0;
436
616
  const rIns = bodyPr ? poIntAttr(bodyPr, "rIns") : void 0;
437
617
  const bIns = bodyPr ? poIntAttr(bodyPr, "bIns") : void 0;
438
618
  const a = bodyPr ? poAttr(bodyPr, "anchor") : void 0;
439
- const anchor = a === "ctr" ? "ctr" : a === "b" ? "b" : a === "t" ? "t" : void 0;
619
+ const anchor = a === "ctr" || a === "b" || a === "t" ? a : ph && cascade ? cascade.anchorFor(ph) : void 0;
440
620
  return {
441
- content,
621
+ content: fitted,
442
622
  ...lIns !== void 0 ? { insetLeft: emuToPt(lIns) } : {},
443
623
  ...tIns !== void 0 ? { insetTop: emuToPt(tIns) } : {},
444
624
  ...rIns !== void 0 ? { insetRight: emuToPt(rIns) } : {},
@@ -446,67 +626,142 @@ function parseTxBody(txBody, ph, cascade, colors, resolveLink) {
446
626
  ...anchor ? { anchor } : {}
447
627
  };
448
628
  }
449
- function parseSlideParagraph(aP, ph, cascade, colors, resolveLink, counters) {
629
+ /**
630
+ * §21.1.2.1.2 — the body's text at the size the autofit settled on.
631
+ *
632
+ * The scale is a property of the BODY that reaches every run in it, so it is
633
+ * applied here rather than carried down: a run in the model already holds the
634
+ * size it inherited, and the shrink multiplies exactly that. Unread, the text
635
+ * PowerPoint squeezed to 62% of its style overflowed the placeholder it was
636
+ * squeezed to fit.
637
+ *
638
+ * @param content The body's paragraphs.
639
+ * @param bodyPr The body's `a:bodyPr`, which carries the autofit.
640
+ * @returns The paragraphs, scaled; the same array when nothing is stated.
641
+ */
642
+ function fitToBody(content, bodyPr) {
643
+ const fit = bodyPr ? poChildren(bodyPr).find((c) => poIs(c, "a:normAutofit")) : void 0;
644
+ const scale = fit ? poIntAttr(fit, "fontScale") : void 0;
645
+ const reduction = fit ? poIntAttr(fit, "lnSpcReduction") : void 0;
646
+ const fontScale = scale !== void 0 && scale > 0 ? scale / 1e5 : void 0;
647
+ const lineScale = reduction !== void 0 && reduction > 0 ? 1 - Math.min(reduction, 1e5) / 1e5 : void 0;
648
+ if (fontScale === void 0 && lineScale === void 0) return content;
649
+ return content.map((el) => {
650
+ if (el.kind !== "paragraph") return el;
651
+ const p = el.paragraph;
652
+ const line = lineScale === void 0 ? void 0 : pt((p.properties.spacingLine ?? 12) * lineScale);
653
+ return {
654
+ ...el,
655
+ paragraph: {
656
+ ...p,
657
+ properties: {
658
+ ...p.properties,
659
+ ...line !== void 0 ? {
660
+ spacingLine: line,
661
+ spacingLineRule: "auto"
662
+ } : {}
663
+ },
664
+ runs: fontScale === void 0 ? p.runs : p.runs.map((run) => run.properties.fontSizePt === void 0 ? run : {
665
+ ...run,
666
+ properties: {
667
+ ...run.properties,
668
+ fontSizePt: pt(run.properties.fontSizePt * fontScale)
669
+ }
670
+ })
671
+ }
672
+ };
673
+ });
674
+ }
675
+ function parseSlideParagraph(aP, ph, cascade, colors, resolveLink, counters, styleColor, themeFonts) {
450
676
  const pPr = poChildren(aP).find((c) => poIs(c, "a:pPr"));
451
677
  const level = (pPr ? poIntAttr(pPr, "lvl") : void 0) ?? 0;
452
- const defaults = ph && cascade ? cascade.defaultsFor(ph, level) : {};
678
+ const defaults = {
679
+ ...cascade ? cascade.defaultsFor(ph, level) : {},
680
+ ...styleColor !== void 0 ? { colorHex: styleColor } : {}
681
+ };
682
+ const inherited = cascade ? cascade.paragraphDefaultsFor(ph, level) : {};
453
683
  const algn = pPr ? poAttr(pPr, "algn") : void 0;
454
684
  const alignment = algn !== void 0 ? ALGN_TO_ALIGNMENT[algn] : void 0;
455
685
  const runs = [];
456
- const marker = bulletMarker(pPr, level, counters);
457
- if (marker !== void 0) runs.push({
458
- text: marker,
459
- properties: defaults,
460
- listMarker: true
461
- });
462
686
  for (const child of poChildren(aP)) if (poIs(child, "a:r") || poIs(child, "a:fld")) {
463
- const run = parseSlideRun(child, defaults, colors, resolveLink);
687
+ const run = parseSlideRun(child, defaults, colors, resolveLink, themeFonts);
464
688
  if (run) runs.push(run);
465
689
  }
466
- if (runs.length === 0) {
467
- const endRPr = poChildren(aP).find((c) => poIs(c, "a:endParaRPr"));
468
- const sz = endRPr ? poIntAttr(endRPr, "sz") : void 0;
469
- if (sz !== void 0 && sz > 0) runs.push({
470
- text: "",
471
- properties: {
472
- ...defaults,
473
- fontSizePt: pt(sz / 100)
474
- }
475
- });
476
- }
477
690
  const marL = pPr ? poIntAttr(pPr, "marL") : void 0;
478
691
  const indent = pPr ? poIntAttr(pPr, "indent") : void 0;
479
692
  const indentLeft = marL !== void 0 ? emuToPt(marL) : level > 0 ? emuToPt(level * 457200) : void 0;
693
+ const hanging = (indent !== void 0 ? emuToPt(indent) : inherited.indentFirstLine ?? 0) < 0;
694
+ const bullet = {
695
+ ...cascade?.bulletFor(ph, level),
696
+ ...parseBullet(pPr, colors)
697
+ };
698
+ const marker = bulletMarker(bullet, level, counters);
699
+ if (marker !== void 0) {
700
+ const base = runs[0]?.properties ?? defaults;
701
+ runs.unshift({
702
+ text: marker + (hanging ? " " : " "),
703
+ properties: bulletProps(base, bullet),
704
+ listMarker: true
705
+ });
706
+ }
707
+ const endRPr = poChildren(aP).find((c) => poIs(c, "a:endParaRPr"));
708
+ const endSz = endRPr ? poIntAttr(endRPr, "sz") : void 0;
709
+ const markProps = runs.length > 0 ? void 0 : {
710
+ ...defaults,
711
+ ...endSz !== void 0 && endSz > 0 ? { fontSizePt: pt(endSz / 100) } : {}
712
+ };
480
713
  return {
481
714
  properties: {
715
+ ...inherited,
482
716
  ...alignment ? { alignment } : {},
483
717
  ...indentLeft !== void 0 ? { indentLeft } : {},
484
- ...indent !== void 0 ? { indentFirstLine: emuToPt(indent) } : {}
718
+ ...indent !== void 0 ? { indentFirstLine: emuToPt(indent) } : {},
719
+ ...lineSpacing(pPr),
720
+ ...ownSpacing(pPr, runs[0]?.properties.fontSizePt ?? defaults.fontSizePt),
721
+ ...markProps && markProps.fontSizePt !== void 0 ? { runProperties: markProps } : {}
485
722
  },
486
723
  runs
487
724
  };
488
725
  }
489
- function bulletMarker(pPr, level, counters) {
490
- if (!pPr) return void 0;
491
- if (poChildren(pPr).some((c) => poIs(c, "a:buNone"))) return void 0;
492
- const buChar = poChildren(pPr).find((c) => poIs(c, "a:buChar"));
493
- if (buChar) return `${poAttr(buChar, "char") ?? "•"} `;
494
- const buAuto = poChildren(pPr).find((c) => poIs(c, "a:buAutoNum"));
495
- if (!buAuto) return void 0;
496
- const type = poAttr(buAuto, "type") ?? "arabicPeriod";
497
- const startAt = poIntAttr(buAuto, "startAt") ?? 1;
726
+ function ownSpacing(pPr, sizePt) {
727
+ const fractions = spacingFractions(pPr);
728
+ const before = spacingFromLineFraction(fractions?.before, sizePt);
729
+ const after = spacingFromLineFraction(fractions?.after, sizePt);
730
+ const points = (tag) => {
731
+ const holder = pPr ? poChildren(pPr).find((c) => poIs(c, tag)) : void 0;
732
+ const node = holder ? poChildren(holder).find((c) => poIs(c, "a:spcPts")) : void 0;
733
+ const val = node ? poIntAttr(node, "val") : void 0;
734
+ return val === void 0 ? void 0 : pt(val / 100);
735
+ };
736
+ const [beforePt, afterPt] = [points("a:spcBef") ?? before, points("a:spcAft") ?? after];
737
+ return {
738
+ ...beforePt !== void 0 ? { spacingBefore: beforePt } : {},
739
+ ...afterPt !== void 0 ? { spacingAfter: afterPt } : {}
740
+ };
741
+ }
742
+ function bulletProps(base, bullet) {
743
+ const sizePt = bullet.sizePts ?? (bullet.sizePct !== void 0 && base.fontSizePt !== void 0 ? base.fontSizePt * bullet.sizePct : void 0);
744
+ return {
745
+ ...base,
746
+ ...sizePt !== void 0 ? { fontSizePt: pt(sizePt) } : {},
747
+ ...bullet.colorHex !== void 0 ? { colorHex: bullet.colorHex } : {}
748
+ };
749
+ }
750
+ function bulletMarker(bullet, level, counters) {
751
+ if (!bullet || bullet.kind === "none" || bullet.kind === void 0) return void 0;
752
+ if (bullet.kind === "char") return bullet.char ?? "•";
498
753
  const prev = counters[level];
499
- const n = (prev === void 0 ? startAt - 1 : prev) + 1;
754
+ const n = (prev === void 0 ? (bullet.startAt ?? 1) - 1 : prev) + 1;
500
755
  counters[level] = n;
501
756
  counters.length = level + 1;
502
- return `${n}${autoNumSuffix(type)} `;
757
+ return `${n}${autoNumSuffix(bullet.type ?? "arabicPeriod")}`;
503
758
  }
504
759
  function autoNumSuffix(type) {
505
760
  if (type.endsWith("ParenR") || type.endsWith("ParenBoth")) return ")";
506
761
  if (type.endsWith("Period")) return ".";
507
762
  return "";
508
763
  }
509
- function parseSlideRun(node, defaults, colors, resolveLink) {
764
+ function parseSlideRun(node, defaults, colors, resolveLink, themeFonts) {
510
765
  const t = poChildren(node).find((c) => poIs(c, "a:t"));
511
766
  const text = t ? poText(t) : "";
512
767
  if (text.length === 0) return void 0;
@@ -518,36 +773,62 @@ function parseSlideRun(node, defaults, colors, resolveLink) {
518
773
  text,
519
774
  properties: {
520
775
  ...defaults,
521
- ...rPrToRunProps(rPr, colors)
776
+ ...rPrToRunProps(rPr, colors, themeFonts)
522
777
  },
523
778
  ...href ? { href } : {}
524
779
  };
525
780
  }
526
- function parseTable(tbl, colors) {
781
+ function parseTable(tbl, colors, resolveTableStyle, theme) {
527
782
  const grid = [];
528
783
  const tblGrid = poChildren(tbl).find((c) => poIs(c, "a:tblGrid"));
529
784
  if (tblGrid) {
530
785
  for (const col of poChildren(tblGrid)) if (poIs(col, "a:gridCol")) grid.push(emuToPt(poIntAttr(col, "w") ?? 0));
531
786
  }
532
787
  const rows = [];
533
- for (const tr of poChildren(tbl)) if (poIs(tr, "a:tr")) rows.push(parseTableRow(tr, colors));
534
- return {
788
+ const sources = [];
789
+ for (const tr of poChildren(tbl)) {
790
+ if (!poIs(tr, "a:tr")) continue;
791
+ const cells = rowCells(tr);
792
+ sources.push(cells);
793
+ rows.push(parseTableRow(tr, cells, colors));
794
+ }
795
+ const tblPr = poChildren(tbl).find((c) => poIs(c, "a:tblPr"));
796
+ const style = resolveTableStyle?.(tableStyleId(tblPr));
797
+ if (!style) return {
535
798
  properties: {},
536
799
  grid,
537
800
  rows
538
801
  };
802
+ const flags = tableStyleFlags(tblPr);
803
+ return {
804
+ properties: {},
805
+ grid,
806
+ rows: rows.map((row, r) => ({
807
+ ...row,
808
+ cells: row.cells.map((cell, c) => {
809
+ const part = cellStyle(style, flags, {
810
+ row: r,
811
+ rowCount: rows.length,
812
+ col: c,
813
+ colCount: grid.length
814
+ }, colors, theme);
815
+ const tc = sources[r]?.[c];
816
+ return withCellStyle(cell, tc && cellSaysNoFill(tc) ? withoutFill(part) : part);
817
+ })
818
+ }))
819
+ };
820
+ }
821
+ function rowCells(tr) {
822
+ return poChildren(tr).filter((tc) => poIs(tc, "a:tc") && poAttr(tc, "hMerge") !== "1");
539
823
  }
540
- function parseTableRow(tr, colors) {
824
+ function parseTableRow(tr, cells, colors) {
541
825
  const h = poIntAttr(tr, "h");
542
- const cells = [];
543
- for (const tc of poChildren(tr)) {
544
- if (!poIs(tc, "a:tc")) continue;
545
- if (poAttr(tc, "hMerge") === "1") continue;
546
- cells.push(parseTableCell(tc, colors));
547
- }
548
826
  return {
549
- properties: { ...h !== void 0 ? { height: emuToPt(h) } : {} },
550
- cells
827
+ properties: { ...h !== void 0 ? {
828
+ height: emuToPt(h),
829
+ heightRule: "atLeast"
830
+ } : {} },
831
+ cells: cells.map((tc) => parseTableCell(tc, colors))
551
832
  };
552
833
  }
553
834
  function parseTableCell(tc, colors) {
@@ -558,15 +839,35 @@ function parseTableCell(tc, colors) {
558
839
  const merge = rowSpan !== void 0 && rowSpan > 1 ? "start" : poAttr(tc, "vMerge") === "1" ? "middle" : void 0;
559
840
  const tcPr = poChildren(tc).find((c) => poIs(c, "a:tcPr"));
560
841
  const shadingHex = tcPr ? cellFillHex(tcPr, colors) : void 0;
842
+ const borders = tcPr ? cellOwnBorders(tcPr, colors) : void 0;
561
843
  return {
562
844
  properties: {
563
845
  ...gridSpan !== void 0 && gridSpan > 1 ? { colSpan: gridSpan } : {},
564
846
  ...merge ? { merge } : {},
565
- ...shadingHex ? { shading: { colorHex: shadingHex } } : {}
847
+ ...shadingHex ? { shading: { colorHex: shadingHex } } : {},
848
+ ...borders ? { borders } : {}
566
849
  },
567
850
  content
568
851
  };
569
852
  }
853
+ var CELL_LINES = [
854
+ ["a:lnL", "left"],
855
+ ["a:lnR", "right"],
856
+ ["a:lnT", "top"],
857
+ ["a:lnB", "bottom"]
858
+ ];
859
+ function cellOwnBorders(tcPr, colors) {
860
+ const out = {};
861
+ for (const [tag, side] of CELL_LINES) {
862
+ const ln = poChildren(tcPr).find((c) => poIs(c, tag));
863
+ if (ln) out[side] = lineBorder(ln, colors);
864
+ }
865
+ return Object.keys(out).length > 0 ? out : void 0;
866
+ }
867
+ function cellSaysNoFill(tc) {
868
+ const tcPr = poChildren(tc).find((c) => poIs(c, "a:tcPr"));
869
+ return tcPr !== void 0 && poChildren(tcPr).some((c) => poIs(c, "a:noFill"));
870
+ }
570
871
  function cellFillHex(tcPr, colors) {
571
872
  const solidFill = poChildren(tcPr).find((c) => poIs(c, "a:solidFill"));
572
873
  if (!solidFill) return void 0;
@@ -576,4 +877,4 @@ function cellFillHex(tcPr, colors) {
576
877
  }
577
878
  }
578
879
  //#endregion
579
- export { backdropElement, diagramTransform, noDiagramOverrideLoss, parseBackgroundFill, parseDiagramNodes, parseGeometry, parseSlideShapes, parseTxBody };
880
+ export { asBackdrop, backdropElement, diagramTransform, noDiagramOverrideLoss, parseBackgroundFill, parseDiagramNodes, parseGeometry, parseSlideShapes, parseTxBody };