reamkit 1.23.0 → 1.25.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 (102) hide show
  1. package/README.md +22 -11
  2. package/dist/esm/core/bmp.d.ts +33 -0
  3. package/dist/esm/core/bmp.js +276 -0
  4. package/dist/esm/core/converter/facade.d.ts +3 -3
  5. package/dist/esm/core/converter/facade.js +12 -0
  6. package/dist/esm/core/converter/ream.d.ts +48 -4
  7. package/dist/esm/core/converter/ream.js +25 -4
  8. package/dist/esm/core/document-model/index.d.ts +1 -1
  9. package/dist/esm/core/document-model/types.d.ts +54 -0
  10. package/dist/esm/core/drawingml/chart-geometry.js +3 -2
  11. package/dist/esm/core/drawingml/diagram/colors.d.ts +52 -0
  12. package/dist/esm/core/drawingml/diagram/colors.js +125 -0
  13. package/dist/esm/core/drawingml/diagram/data-model.d.ts +47 -0
  14. package/dist/esm/core/drawingml/diagram/data-model.js +119 -0
  15. package/dist/esm/core/drawingml/diagram/layout-engine.d.ts +46 -0
  16. package/dist/esm/core/drawingml/diagram/layout-engine.js +948 -0
  17. package/dist/esm/core/drawingml/diagram/run.d.ts +37 -0
  18. package/dist/esm/core/drawingml/diagram/run.js +50 -0
  19. package/dist/esm/core/drawingml/diagram/to-drawing.d.ts +16 -0
  20. package/dist/esm/core/drawingml/diagram/to-drawing.js +86 -0
  21. package/dist/esm/core/drawingml/preset-geometry.js +116 -6
  22. package/dist/esm/core/drawingml/text-warp.d.ts +58 -0
  23. package/dist/esm/core/drawingml/text-warp.js +355 -0
  24. package/dist/esm/core/drawingml/theme-parser.js +9 -3
  25. package/dist/esm/core/font/measure.d.ts +12 -0
  26. package/dist/esm/core/font/measure.js +36 -0
  27. package/dist/esm/core/images.d.ts +30 -2
  28. package/dist/esm/core/images.js +121 -5
  29. package/dist/esm/core/metafile/emf.js +144 -16
  30. package/dist/esm/core/metafile/picture.d.ts +49 -0
  31. package/dist/esm/core/metafile/picture.js +70 -1
  32. package/dist/esm/core/metafile/wmf.js +53 -4
  33. package/dist/esm/core/ole/escher-blip.js +11 -1
  34. package/dist/esm/core/outline.d.ts +17 -0
  35. package/dist/esm/core/outline.js +30 -0
  36. package/dist/esm/core/style-cascade/resolver.js +1 -0
  37. package/dist/esm/core/style-cascade/types.d.ts +3 -1
  38. package/dist/esm/excel/print-model.js +2 -2
  39. package/dist/esm/excel/sheet-drawing.js +1 -1
  40. package/dist/esm/excel/sheet-to-flow.d.ts +10 -0
  41. package/dist/esm/excel/sheet-to-flow.js +30 -3
  42. package/dist/esm/html/html-writer.js +5 -3
  43. package/dist/esm/index.d.ts +3 -0
  44. package/dist/esm/index.js +2 -1
  45. package/dist/esm/layout/page-doc.d.ts +35 -0
  46. package/dist/esm/layout/page-doc.js +14 -1
  47. package/dist/esm/layout/styled-layout.js +217 -30
  48. package/dist/esm/markdown/markdown-writer.d.ts +41 -0
  49. package/dist/esm/markdown/markdown-writer.js +733 -0
  50. package/dist/esm/pdf/shading.js +8 -6
  51. package/dist/esm/pdf/styled-page-emitter.js +62 -4
  52. package/dist/esm/pdf/vector-graphics.js +1 -1
  53. package/dist/esm/pdf-reader/annots.d.ts +24 -0
  54. package/dist/esm/pdf-reader/annots.js +126 -0
  55. package/dist/esm/pdf-reader/content.d.ts +131 -5
  56. package/dist/esm/pdf-reader/content.js +169 -12
  57. package/dist/esm/pdf-reader/display.d.ts +56 -0
  58. package/dist/esm/pdf-reader/display.js +162 -0
  59. package/dist/esm/pdf-reader/document.d.ts +36 -1
  60. package/dist/esm/pdf-reader/document.js +92 -25
  61. package/dist/esm/pdf-reader/embedded-fonts.d.ts +31 -0
  62. package/dist/esm/pdf-reader/embedded-fonts.js +94 -0
  63. package/dist/esm/pdf-reader/flow-build.d.ts +61 -6
  64. package/dist/esm/pdf-reader/flow-build.js +128 -22
  65. package/dist/esm/pdf-reader/font.js +185 -4
  66. package/dist/esm/pdf-reader/image-decode.js +56 -5
  67. package/dist/esm/pdf-reader/images.d.ts +6 -0
  68. package/dist/esm/pdf-reader/images.js +25 -5
  69. package/dist/esm/pdf-reader/jpeg.d.ts +18 -0
  70. package/dist/esm/pdf-reader/jpeg.js +419 -0
  71. package/dist/esm/pdf-reader/layout.d.ts +1 -1
  72. package/dist/esm/pdf-reader/layout.js +221 -32
  73. package/dist/esm/pdf-reader/pattern-tint.d.ts +17 -0
  74. package/dist/esm/pdf-reader/pattern-tint.js +181 -0
  75. package/dist/esm/pdf-reader/reader.d.ts +9 -1
  76. package/dist/esm/pdf-reader/reader.js +22 -6
  77. package/dist/esm/pdf-reader/shading.d.ts +14 -0
  78. package/dist/esm/pdf-reader/shading.js +27 -1
  79. package/dist/esm/pdf-reader/tagged.js +156 -17
  80. package/dist/esm/pdf-reader/text.d.ts +13 -1
  81. package/dist/esm/pdf-reader/text.js +70 -3
  82. package/dist/esm/pdf-reader/vector.d.ts +25 -1
  83. package/dist/esm/pdf-reader/vector.js +168 -12
  84. package/dist/esm/pptx/ppt/ppt-reader.js +95 -27
  85. package/dist/esm/pptx/ppt/ppt-text.d.ts +41 -0
  86. package/dist/esm/pptx/ppt/ppt-text.js +327 -37
  87. package/dist/esm/pptx/pptx-reader.js +90 -10
  88. package/dist/esm/pptx/slide-parser.d.ts +4 -1
  89. package/dist/esm/pptx/slide-parser.js +104 -13
  90. package/dist/esm/pptx/sp-helpers.d.ts +7 -3
  91. package/dist/esm/pptx/sp-helpers.js +45 -7
  92. package/dist/esm/pptx/table-style.d.ts +7 -0
  93. package/dist/esm/pptx/table-style.js +59 -7
  94. package/dist/esm/svg/svg-writer.js +1 -0
  95. package/dist/esm/word/document-parser.d.ts +4 -1
  96. package/dist/esm/word/document-parser.js +4 -1
  97. package/dist/esm/word/docx-reader.js +26 -13
  98. package/dist/esm/word/docx-writer.js +15 -1
  99. package/dist/esm/word/drawing-parser.d.ts +20 -0
  100. package/dist/esm/word/drawing-parser.js +44 -5
  101. package/dist/esm/word/table-parser.js +3 -0
  102. package/package.json +1 -1
@@ -4,6 +4,7 @@ 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 { cachedDiagramTree, laidOutDiagramTree } from "../core/drawingml/diagram/run.js";
7
8
  import { packageHasPart } from "../core/bytes.js";
8
9
  import { DEFAULT_SCHEME_ALIAS, DEFAULT_THEME_PALETTE, defaultColorResolver, makeColorResolver } from "../core/drawingml/colors.js";
9
10
  import { parseChart, withChartColorStyle } from "../core/drawingml/chart-parser.js";
@@ -207,7 +208,81 @@ function parseSlide(tree, ctx, inheritedBg, pageW, pageH, inheritedShapes = [])
207
208
  if (bg) out.push(backdropElement(bg, pageW, pageH));
208
209
  out.push(...inheritedShapes.map(asBackdrop));
209
210
  if (spTree) out.push(...parseSlideShapes(spTree, shapeCtx));
210
- return out;
211
+ out.push(...parseSlideControls(cSld, shapeCtx));
212
+ return inPaintOrder(out);
213
+ }
214
+ /**
215
+ * §19.3.1 — a slide's shape tree IS its z-order: what stands later in it is
216
+ * drawn over what stands earlier, whatever KIND either of them is.
217
+ *
218
+ * The page otherwise paints kind by kind — every image, then every shape — and
219
+ * on a slide that is simply wrong. 54542_cropped_bitmap.pptx is six logos each
220
+ * standing on its own coloured panel, written panel-then-logo six times over,
221
+ * and painted by kind all six logos went down first and all six panels covered
222
+ * them.
223
+ *
224
+ * @param elements The slide's elements, in the order the tree gives them.
225
+ * @returns The same elements, each float carrying its place in that order.
226
+ */
227
+ function inPaintOrder(elements) {
228
+ return elements.map((el, z) => {
229
+ if (el.kind === "shape") return {
230
+ ...el,
231
+ shape: withZ(el.shape, z)
232
+ };
233
+ if (el.kind === "image") return {
234
+ ...el,
235
+ image: withZ(el.image, z)
236
+ };
237
+ if (el.kind === "table") {
238
+ const anchor = el.table.properties.float;
239
+ return anchor ? {
240
+ ...el,
241
+ table: {
242
+ ...el.table,
243
+ properties: {
244
+ ...el.table.properties,
245
+ float: {
246
+ ...anchor,
247
+ zOrder: z
248
+ }
249
+ }
250
+ }
251
+ } : el;
252
+ }
253
+ return el;
254
+ });
255
+ }
256
+ /** The same block with its float carrying `z`, when it floats at all. */
257
+ function withZ(block, z) {
258
+ return block.float ? {
259
+ ...block,
260
+ float: {
261
+ ...block.float,
262
+ zOrder: z
263
+ }
264
+ } : block;
265
+ }
266
+ /**
267
+ * §19.3.1.15 `p:controls` — the ActiveX controls a slide carries.
268
+ *
269
+ * They sit BESIDE the shape tree rather than in it, so a reader that walks
270
+ * `p:spTree` alone never sees them. Each one's `mc:Fallback` is a `p:pic` of
271
+ * what the control looks like — the picture PowerPoint cached precisely so that
272
+ * a reader which cannot run the control still draws it — and by the time the
273
+ * slide is parsed the alternate content is already resolved to that fallback.
274
+ * activex_picture.pptx is seventeen of them over an EMPTY `p:spTree`, and it
275
+ * rendered as a blank page.
276
+ *
277
+ * @param cSld The slide's `p:cSld`.
278
+ * @param ctx The slide's parsing context.
279
+ * @returns The controls' cached pictures as ordinary floating pictures.
280
+ */
281
+ function parseSlideControls(cSld, ctx) {
282
+ const controls = cSld ? poChildren(cSld).find((c) => poIs(c, "p:controls")) : void 0;
283
+ if (!controls) return [];
284
+ const pics = poChildren(controls).flatMap((c) => poIs(c, "p:control") ? poChildren(c).filter((k) => poIs(k, "p:pic")) : []);
285
+ return pics.length === 0 ? [] : parseSlideShapes({ "p:spTree": pics }, ctx);
211
286
  }
212
287
  function partBackground(tree, root, colors, resolveImage, themeFills) {
213
288
  const sld = tree.find((n) => poIs(n, root));
@@ -312,23 +387,28 @@ function makeSlideChartResolver(pkg, slidePath, charts, colors, resources) {
312
387
  }
313
388
  function makeSlideDiagramResolver(pkg, slidePath) {
314
389
  const cache = /* @__PURE__ */ new Map();
315
- return (relId) => {
390
+ return (relId, frame) => {
316
391
  if (cache.has(relId)) return cache.get(relId);
317
- let spTree;
318
392
  const dataRel = pkg.getPartRelationships(slidePath).find((r) => r.id === relId);
319
393
  const data = dataRel ? pkg.resolveRelatedPart(slidePath, dataRel) : void 0;
320
394
  const draw = data ? drawingPart(pkg, slidePath, data) : void 0;
321
- if (draw) for (const root of parseXml(draw.data)) {
322
- const found = poFindDescendant(root, "dsp:spTree");
323
- if (found) {
324
- spTree = found;
325
- break;
326
- }
327
- }
395
+ let spTree = draw ? cachedDiagramTree(draw.data, parseXml) : void 0;
396
+ if (!spTree && data) spTree = laidOutDiagram(pkg, slidePath, data, frame);
328
397
  cache.set(relId, spTree);
329
398
  return spTree;
330
399
  };
331
400
  }
401
+ function laidOutDiagram(pkg, slidePath, data, frame) {
402
+ const related = (type) => {
403
+ const rel = pkg.getPartRelationships(slidePath).find((r) => r.type.endsWith(type));
404
+ return rel ? pkg.resolveRelatedPart(slidePath, rel)?.data : void 0;
405
+ };
406
+ return laidOutDiagramTree({
407
+ data: data.data,
408
+ layout: related("/diagramLayout"),
409
+ colors: related("/diagramColors")
410
+ }, frame, parseXml);
411
+ }
332
412
  /**
333
413
  * The pre-rendered drawing a diagram's data part points at.
334
414
  *
@@ -59,7 +59,10 @@ export interface SlideContext {
59
59
  * drawing override (its `dsp:spTree`), or `undefined` when the file ships no
60
60
  * override (E-SMARTART SA0).
61
61
  */
62
- readonly resolveDiagram?: (relId: string) => PoNode | undefined;
62
+ readonly resolveDiagram?: (relId: string, frame: {
63
+ readonly cx: number;
64
+ readonly cy: number;
65
+ }) => PoNode | undefined;
63
66
  /**
64
67
  * Sink for graceful-degradation notices (E-SMARTART SA3): a SmartArt that
65
68
  * declares a diagram but ships no drawing override records a dropped-feature
@@ -1,10 +1,11 @@
1
1
  import { emuToPt, pt } from "../core/ir/units.js";
2
2
  import { FEATURES } from "../core/ir/features.js";
3
+ import { isTextWarp } from "../core/drawingml/text-warp.js";
3
4
  import { poAttr, poChildren, poFindDescendant, poIntAttr, poIs, poTag, poText } from "../core/po-helpers.js";
4
5
  import { defaultColorResolver, placeholderColors, resolveColorNode } from "../core/drawingml/colors.js";
5
6
  import { boxFromXfrm, parsePh, parseXfrmBox, rPrToRunProps } from "./sp-helpers.js";
6
7
  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 { colorChangeOf, parseCustGeom, parseFill, parseLine, parsePrstGeom, parseShadow, parseSrcRect, parseXfrm, statesFill, styleRefFill, styleRefFontColor, styleRefLine, withStatedDirection } from "../word/drawing-parser.js";
8
9
  import { cellStyle, lineBorder, tableStyleFlags, tableStyleId, withCellStyle, withoutFill } from "./table-style.js";
9
10
  //#region src/pptx/slide-parser.ts
10
11
  var CHART_URI = "http://schemas.openxmlformats.org/drawingml/2006/chart";
@@ -46,17 +47,49 @@ function parseSlideShapes(container, ctx = {}, transform = IDENTITY_TRANSFORM, s
46
47
  shape
47
48
  });
48
49
  } else if (poIs(child, "p:pic")) {
49
- const image = parsePic(child, ctx, transform);
50
- if (image) out.push({
51
- kind: "image",
52
- image
50
+ const clipped = pictureAsShape(child);
51
+ const shape = clipped ? parseSp(clipped, ctx, transform) : void 0;
52
+ if (shape) out.push({
53
+ kind: "shape",
54
+ shape
53
55
  });
56
+ else {
57
+ const image = parsePic(child, ctx, transform);
58
+ if (image) out.push({
59
+ kind: "image",
60
+ image
61
+ });
62
+ }
54
63
  } else if (poIs(child, "p:graphicFrame")) out.push(...parseGraphicFrame(child, ctx, transform));
55
64
  else if (poIs(child, "p:grpSp")) out.push(...parseSlideShapes(child, ctx, composeGroupTransform(child, transform), skipPlaceholders));
56
65
  }
57
66
  return out;
58
67
  }
59
68
  /**
69
+ * A `p:pic` that names a geometry of its own, rewritten as the `p:sp` it is.
70
+ *
71
+ * A picture holds its `p:blipFill` BESIDE `p:spPr`; a shape holds its fill
72
+ * INSIDE it, under the drawing namespace. Moving the one into the other is the
73
+ * whole difference, and it buys the shape path entire — the geometry, the
74
+ * outline, the crop, the recolour — instead of a second clipper that would
75
+ * drift from it.
76
+ *
77
+ * @param pic The `p:pic` node.
78
+ * @returns The equivalent `p:sp`, or undefined when the picture is a plain
79
+ * rectangle and wants no clipping at all.
80
+ */
81
+ function pictureAsShape(pic) {
82
+ const spPr = poChildren(pic).find((c) => poIs(c, "p:spPr"));
83
+ const prst = spPr ? poChildren(spPr).find((c) => poIs(c, "a:prstGeom")) : void 0;
84
+ const custom = spPr ? poChildren(spPr).find((c) => poIs(c, "a:custGeom")) : void 0;
85
+ const shape = poAttr(prst, "prst");
86
+ if (custom === void 0 && (shape === void 0 || shape === "rect")) return void 0;
87
+ const blipFill = poChildren(pic).find((c) => poIs(c, "p:blipFill"));
88
+ if (!blipFill || !spPr) return void 0;
89
+ const nv = poChildren(pic).find((c) => poIs(c, "p:nvPicPr"));
90
+ return { "p:sp": [...nv ? [{ "p:nvSpPr": poChildren(nv) }] : [], { "p:spPr": [{ "a:blipFill": poChildren(blipFill) }, ...poChildren(spPr)] }] };
91
+ }
92
+ /**
60
93
  * Whether a shape is a placeholder — `p:ph` in its OWN non-visual properties.
61
94
  * Read as "anywhere below", a group holding one would take the whole group
62
95
  * with it.
@@ -132,7 +165,7 @@ function parseSp(sp, ctx, transform) {
132
165
  const ownFill = stated(statesFill);
133
166
  const styleFill = style ? styleRefFill(style, colors, themeStyles) : void 0;
134
167
  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" };
168
+ const styled = withStatedDirection(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" }, spPr);
136
169
  const lineFrom = from((n) => poChildren(n).some((c) => poIs(c, "a:ln")));
137
170
  let line = lineFrom ? parseLine(lineFrom, colors) : void 0;
138
171
  if (style) {
@@ -236,7 +269,10 @@ function parseGraphicFrame(gf, ctx, transform) {
236
269
  if (uri === DIAGRAM_URI) {
237
270
  const relIds = poFindDescendant(gf, "dgm:relIds");
238
271
  const dmRelId = relIds ? poAttr(relIds, "dm") : void 0;
239
- const spTree = dmRelId !== void 0 ? ctx.resolveDiagram?.(dmRelId) : void 0;
272
+ const spTree = dmRelId !== void 0 ? ctx.resolveDiagram?.(dmRelId, {
273
+ cx: box.cx,
274
+ cy: box.cy
275
+ }) : void 0;
240
276
  if (!spTree) {
241
277
  if (dmRelId !== void 0) ctx.onLoss?.(noDiagramOverrideLoss());
242
278
  return [];
@@ -551,7 +587,10 @@ function parseGeometry(spPr) {
551
587
  return RECT_GEOMETRY;
552
588
  }
553
589
  function parsePic(pic, ctx, transform) {
554
- const own = parseXfrmBox(poChildren(pic).find((c) => poIs(c, "p:spPr")));
590
+ const spPr = poChildren(pic).find((c) => poIs(c, "p:spPr"));
591
+ const ph = parsePh(pic);
592
+ let own = parseXfrmBox(spPr);
593
+ if (!own && ph && ctx.cascade) own = ctx.cascade.geometryFor(ph);
555
594
  if (!own) return void 0;
556
595
  const box = transform(own);
557
596
  const blipFill = poChildren(pic).find((c) => poIs(c, "p:blipFill"));
@@ -562,12 +601,19 @@ function parsePic(pic, ctx, transform) {
562
601
  const fixed = blip ? poChildren(blip).find((c) => poIs(c, "a:alphaModFix")) : void 0;
563
602
  const amt = fixed ? poIntAttr(fixed, "amt") : void 0;
564
603
  const alpha = amt === void 0 ? void 0 : Math.min(1, Math.max(0, amt / 1e5));
604
+ const crop = parseSrcRect(blipFill ? poFindDescendant(blipFill, "a:srcRect") : void 0);
605
+ const xfrm = spPr ? poChildren(spPr).find((c) => poIs(c, "a:xfrm")) : void 0;
606
+ const rot = xfrm ? poIntAttr(xfrm, "rot") : void 0;
565
607
  const altText = picAltText(pic);
566
608
  return {
567
609
  float: floatAt(box),
568
610
  ...resource !== void 0 ? { resource } : {},
569
611
  ...colorChange ? { colorChange } : {},
570
612
  ...alpha !== void 0 && alpha < 1 ? { alpha } : {},
613
+ ...crop ? { crop } : {},
614
+ ...rot !== void 0 && rot !== 0 ? { rotation60k: rot } : {},
615
+ ...poAttr(xfrm, "flipH") === "1" ? { flipH: true } : {},
616
+ ...poAttr(xfrm, "flipV") === "1" ? { flipV: true } : {},
571
617
  width: emuToPt(box.cx),
572
618
  height: emuToPt(box.cy),
573
619
  paragraphProperties: {},
@@ -616,6 +662,12 @@ function parseTxBody(txBody, ph, cascade, colors, resolveLink, styleColor, theme
616
662
  const rIns = bodyPr ? poIntAttr(bodyPr, "rIns") : void 0;
617
663
  const bIns = bodyPr ? poIntAttr(bodyPr, "bIns") : void 0;
618
664
  const a = bodyPr ? poAttr(bodyPr, "anchor") : void 0;
665
+ const autofit = bodyPr ? poChildren(bodyPr).find((c) => poIs(c, "a:normAutofit")) : void 0;
666
+ const shrink = autofit !== void 0 && poIntAttr(autofit, "fontScale") === void 0;
667
+ const warp = bodyPr ? textWarp(bodyPr) : void 0;
668
+ const v = bodyPr ? poAttr(bodyPr, "vert") : void 0;
669
+ const vertical = v === "vert270" ? "vert270" : v !== void 0 && v !== "horz" ? "vert" : void 0;
670
+ const upright = bodyPr ? poAttr(bodyPr, "upright") === "1" : false;
619
671
  const anchor = a === "ctr" || a === "b" || a === "t" ? a : ph && cascade ? cascade.anchorFor(ph) : void 0;
620
672
  return {
621
673
  content: fitted,
@@ -623,7 +675,33 @@ function parseTxBody(txBody, ph, cascade, colors, resolveLink, styleColor, theme
623
675
  ...tIns !== void 0 ? { insetTop: emuToPt(tIns) } : {},
624
676
  ...rIns !== void 0 ? { insetRight: emuToPt(rIns) } : {},
625
677
  ...bIns !== void 0 ? { insetBottom: emuToPt(bIns) } : {},
626
- ...anchor ? { anchor } : {}
678
+ ...anchor ? { anchor } : {},
679
+ ...vertical ? { vertical } : {},
680
+ ...upright ? { upright } : {},
681
+ ...shrink ? { shrinkToFit: true } : {},
682
+ ...warp ? { warp } : {}
683
+ };
684
+ }
685
+ /**
686
+ * §20.1.9.10 `a:prstTxWarp` — the WordArt curve a body's text is bent through,
687
+ * with the `a:avLst` `adj` guide when it states one. Unread, tdf114848's eight
688
+ * pieces of WordArt were set as eight ordinary paragraphs, each wrapped onto
689
+ * three lines of upright type where both references draw one bent line.
690
+ *
691
+ * @param bodyPr The body's `a:bodyPr`.
692
+ * @returns The preset and its adjustment, or `undefined` when the body states
693
+ * no warp or states the enumeration's `textNoShape`.
694
+ */
695
+ function textWarp(bodyPr) {
696
+ const node = poChildren(bodyPr).find((c) => poIs(c, "a:prstTxWarp"));
697
+ const preset = node ? poAttr(node, "prst") : void 0;
698
+ if (node === void 0 || preset === void 0 || !isTextWarp(preset)) return void 0;
699
+ const avLst = poChildren(node).find((c) => poIs(c, "a:avLst"));
700
+ const adj = avLst ? poChildren(avLst).find((c) => poIs(c, "a:gd") && poAttr(c, "name") === "adj") : void 0;
701
+ const value = adj ? /^val\s+(-?\d+)$/u.exec(poAttr(adj, "fmla") ?? "")?.[1] : void 0;
702
+ return {
703
+ preset,
704
+ ...value !== void 0 ? { adjust: Number(value) } : {}
627
705
  };
628
706
  }
629
707
  /**
@@ -683,9 +761,19 @@ function parseSlideParagraph(aP, ph, cascade, colors, resolveLink, counters, sty
683
761
  const algn = pPr ? poAttr(pPr, "algn") : void 0;
684
762
  const alignment = algn !== void 0 ? ALGN_TO_ALIGNMENT[algn] : void 0;
685
763
  const runs = [];
686
- for (const child of poChildren(aP)) if (poIs(child, "a:r") || poIs(child, "a:fld")) {
687
- const run = parseSlideRun(child, defaults, colors, resolveLink, themeFonts);
688
- if (run) runs.push(run);
764
+ for (const child of poChildren(aP)) {
765
+ if (poIs(child, "a:br")) {
766
+ const last = runs[runs.length - 1];
767
+ if (last) runs[runs.length - 1] = {
768
+ ...last,
769
+ text: `${last.text}\n`
770
+ };
771
+ continue;
772
+ }
773
+ if (poIs(child, "a:r") || poIs(child, "a:fld")) {
774
+ const run = parseSlideRun(child, defaults, colors, resolveLink, themeFonts);
775
+ if (run) runs.push(run);
776
+ }
689
777
  }
690
778
  const marL = pPr ? poIntAttr(pPr, "marL") : void 0;
691
779
  const indent = pPr ? poIntAttr(pPr, "indent") : void 0;
@@ -840,12 +928,15 @@ function parseTableCell(tc, colors) {
840
928
  const tcPr = poChildren(tc).find((c) => poIs(c, "a:tcPr"));
841
929
  const shadingHex = tcPr ? cellFillHex(tcPr, colors) : void 0;
842
930
  const borders = tcPr ? cellOwnBorders(tcPr, colors) : void 0;
931
+ const vert = tcPr ? poAttr(tcPr, "vert") : void 0;
932
+ const textDirection = vert === "vert" || vert === "eaVert" || vert === "mongolianVert" ? "vert" : vert === "vert270" ? "vert270" : void 0;
843
933
  return {
844
934
  properties: {
845
935
  ...gridSpan !== void 0 && gridSpan > 1 ? { colSpan: gridSpan } : {},
846
936
  ...merge ? { merge } : {},
847
937
  ...shadingHex ? { shading: { colorHex: shadingHex } } : {},
848
- ...borders ? { borders } : {}
938
+ ...borders ? { borders } : {},
939
+ ...textDirection ? { textDirection } : {}
849
940
  },
850
941
  content
851
942
  };
@@ -19,9 +19,13 @@ export interface ShapeBoxEmu {
19
19
  readonly cy: number;
20
20
  }
21
21
  /**
22
- * `p:nvSpPr/p:nvPr/p:ph` → the placeholder reference, or `undefined` for an
23
- * ordinary (non-placeholder) shape. A bare `<p:ph/>` returns an empty ref (still
24
- * a placeholder: `type` defaults to `'obj'`).
22
+ * `p:nvPr/p:ph` → the placeholder reference, or `undefined` for an ordinary
23
+ * (non-placeholder) shape. A bare `<p:ph/>` returns an empty ref (still a
24
+ * placeholder: `type` defaults to `'obj'`).
25
+ *
26
+ * A PICTURE is a placeholder as readily as a shape is — a content placeholder
27
+ * filled with a photograph writes `p:nvPicPr/p:nvPr/p:ph` and an EMPTY `p:spPr`,
28
+ * leaving its whole geometry to the layout (customshape-bitmapfill-srcrect).
25
29
  */
26
30
  export declare function parsePh(sp: PoNode): PlaceholderRef | undefined;
27
31
  /**
@@ -4,14 +4,24 @@ import { resolveColorNode } from "../core/drawingml/colors.js";
4
4
  import { resolveThemeFont } from "../core/drawingml/theme-parser.js";
5
5
  //#region src/pptx/sp-helpers.ts
6
6
  var isTrue = (v) => v === "1" || v === "true" || v === "on";
7
+ var NON_VISUAL = [
8
+ "p:nvSpPr",
9
+ "p:nvPicPr",
10
+ "p:nvGraphicFramePr",
11
+ "p:nvCxnSpPr"
12
+ ];
7
13
  /**
8
- * `p:nvSpPr/p:nvPr/p:ph` → the placeholder reference, or `undefined` for an
9
- * ordinary (non-placeholder) shape. A bare `<p:ph/>` returns an empty ref (still
10
- * a placeholder: `type` defaults to `'obj'`).
14
+ * `p:nvPr/p:ph` → the placeholder reference, or `undefined` for an ordinary
15
+ * (non-placeholder) shape. A bare `<p:ph/>` returns an empty ref (still a
16
+ * placeholder: `type` defaults to `'obj'`).
17
+ *
18
+ * A PICTURE is a placeholder as readily as a shape is — a content placeholder
19
+ * filled with a photograph writes `p:nvPicPr/p:nvPr/p:ph` and an EMPTY `p:spPr`,
20
+ * leaving its whole geometry to the layout (customshape-bitmapfill-srcrect).
11
21
  */
12
22
  function parsePh(sp) {
13
- const nvSpPr = poChildren(sp).find((c) => poIs(c, "p:nvSpPr"));
14
- const nvPr = nvSpPr ? poChildren(nvSpPr).find((c) => poIs(c, "p:nvPr")) : void 0;
23
+ const nonVisual = poChildren(sp).find((c) => NON_VISUAL.some((n) => poIs(c, n)));
24
+ const nvPr = nonVisual ? poChildren(nonVisual).find((c) => poIs(c, "p:nvPr")) : void 0;
15
25
  const ph = nvPr ? poChildren(nvPr).find((c) => poIs(c, "p:ph")) : void 0;
16
26
  if (!ph) return void 0;
17
27
  const type = poAttr(ph, "type");
@@ -88,8 +98,36 @@ function capsOf(cap) {
88
98
  }
89
99
  function solidFillColor(rPr, colors) {
90
100
  const solidFill = poChildren(rPr).find((c) => poIs(c, "a:solidFill"));
91
- if (!solidFill) return void 0;
92
- for (const c of poChildren(solidFill)) {
101
+ if (solidFill) {
102
+ for (const c of poChildren(solidFill)) {
103
+ const hex = resolveColorNode(c, colors);
104
+ if (hex) return hex;
105
+ }
106
+ return;
107
+ }
108
+ return gradientFillColor(rPr, colors);
109
+ }
110
+ /**
111
+ * §20.1.8.33 — a run may be filled with a GRADIENT, and WordArt always is: the
112
+ * text of tdf114848's second page runs through five stops of accent1. A run
113
+ * here wears one colour, so the gradient gives up the stop nearest its middle —
114
+ * the one most of the glyph is painted in. Unread, the run had no colour at all
115
+ * and every word came out in the default black.
116
+ */
117
+ function gradientFillColor(rPr, colors) {
118
+ const grad = poChildren(rPr).find((c) => poIs(c, "a:gradFill"));
119
+ const list = grad ? poChildren(grad).find((c) => poIs(c, "a:gsLst")) : void 0;
120
+ const stops = list ? poChildren(list).filter((c) => poIs(c, "a:gs")) : [];
121
+ let best;
122
+ for (const gs of stops) {
123
+ const at = Math.abs((poIntAttr(gs, "pos") ?? 0) - 5e4);
124
+ if (!best || at < best.at) best = {
125
+ at,
126
+ node: gs
127
+ };
128
+ }
129
+ if (!best) return void 0;
130
+ for (const c of poChildren(best.node)) {
93
131
  const hex = resolveColorNode(c, colors);
94
132
  if (hex) return hex;
95
133
  }
@@ -13,6 +13,13 @@ export interface TableStyleFlags {
13
13
  /** What one part of a table style says about a cell. */
14
14
  export interface TableStylePart {
15
15
  readonly shadingHex?: string;
16
+ /**
17
+ * §20.1.2.3.1 — how opaque that shading is, when the part asks for less than
18
+ * all of it. A cell's fill is a layer over the table's background, not over
19
+ * the page, so the two have to be composed rather than each flattened to
20
+ * white on its own.
21
+ */
22
+ readonly shadingAlpha?: number;
16
23
  readonly borders?: CellBorders;
17
24
  readonly bold?: boolean;
18
25
  readonly italic?: boolean;
@@ -1,6 +1,6 @@
1
1
  import { pt } from "../core/ir/units.js";
2
2
  import { poAttr, poChildren, poIntAttr, poIs, poTag, poText } from "../core/po-helpers.js";
3
- import { readColorMods, resolveColorNode } from "../core/drawingml/colors.js";
3
+ import { placeholderColors, readColorMods, resolveColorNode } from "../core/drawingml/colors.js";
4
4
  //#region src/pptx/table-style.ts
5
5
  /** The `a:tblPr` flags, all off unless the table says otherwise. */
6
6
  function tableStyleFlags(tblPr) {
@@ -40,12 +40,57 @@ function cellStyle(style, flags, at, colors, theme) {
40
40
  let out = tableBackground(style, colors, theme);
41
41
  for (const name of names) {
42
42
  const part = poChildren(style).find((c) => poIs(c, name));
43
- if (part) out = {
43
+ if (!part) continue;
44
+ const next = partStyle(part, colors, theme);
45
+ out = {
44
46
  ...out,
45
- ...partStyle(part, colors, theme)
47
+ ...next,
48
+ ...overFill(out.shadingHex, next)
46
49
  };
47
50
  }
48
- return out;
51
+ const { shadingAlpha: _drop, ...flat } = out;
52
+ return flat;
53
+ }
54
+ /**
55
+ * A part's fill laid OVER what is already under it.
56
+ *
57
+ * A colour resolves flattened against the page, because that is what a shape's
58
+ * fill sits on; a table cell's sits on the table's background. Undoing the one
59
+ * and redoing the other needs only the alpha: bnc480256's banding is `accent1`
60
+ * at 40% over a background the theme's gradient makes pale, and taken against
61
+ * white instead it came out as the flat accent with every second row white.
62
+ */
63
+ function overFill(under, part) {
64
+ const a = part.shadingAlpha;
65
+ if (a === void 0 || a >= 1 || part.shadingHex === void 0 || under === void 0) return {};
66
+ const flat = rgb(part.shadingHex);
67
+ const back = rgb(under);
68
+ if (!flat || !back) return {};
69
+ return { shadingHex: toHex(flat.map((v, i) => v - (1 - a) * (1 - (back[i] ?? 1)))) };
70
+ }
71
+ function alphaOf(fill) {
72
+ const walk = (node) => {
73
+ for (const child of poChildren(node)) {
74
+ if (poIs(child, "a:alpha")) {
75
+ const v = poIntAttr(child, "val");
76
+ if (v !== void 0) return Math.max(0, Math.min(1, v / 1e5));
77
+ }
78
+ const deeper = walk(child);
79
+ if (deeper !== void 0) return deeper;
80
+ }
81
+ };
82
+ return walk(fill) ?? 1;
83
+ }
84
+ function rgb(h) {
85
+ const m = /^([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$/u.exec(h);
86
+ return m ? [
87
+ 1,
88
+ 2,
89
+ 3
90
+ ].map((i) => parseInt(m[i] ?? "0", 16) / 255) : void 0;
91
+ }
92
+ function toHex(v) {
93
+ return v.map((c) => Math.round(Math.max(0, Math.min(1, c)) * 255).toString(16).padStart(2, "0").toUpperCase()).join("");
49
94
  }
50
95
  function tableBackground(style, colors, theme) {
51
96
  const bg = poChildren(style).find((c) => poIs(c, "a:tblBg"));
@@ -68,9 +113,14 @@ function refFillColor(ref, colors, theme) {
68
113
  const idx = poIntAttr(ref, "idx");
69
114
  const slot = idx !== void 0 && idx > 0 ? theme?.fills?.[idx - 1] : void 0;
70
115
  if (!slot) return own;
71
- const solid = poChildren(slot).find((c) => poIs(c, "a:solidFill"));
72
- const slotHex = solid ? colorOf(solid, colors) : void 0;
73
- return slotHex && slotHex !== "PHCLR" ? own ?? slotHex : own;
116
+ const named = own === void 0 ? colors : placeholderColors(colors, own);
117
+ const solid = poIs(slot, "a:solidFill") ? slot : void 0;
118
+ if (solid) return colorOf(solid, named) ?? own;
119
+ const grad = poIs(slot, "a:gradFill") ? slot : void 0;
120
+ const list = grad ? poChildren(grad).find((c) => poIs(c, "a:gsLst")) : void 0;
121
+ const stops = list ? poChildren(list).filter((c) => poIs(c, "a:gs")) : [];
122
+ const last = stops[stops.length - 1];
123
+ return (last ? colorOf(last, named) : void 0) ?? own;
74
124
  }
75
125
  function bandName(index, edge, axis) {
76
126
  return (edge ? index - 1 : index) % 2 === 0 ? `a:band1${axis}` : `a:band2${axis}`;
@@ -81,12 +131,14 @@ function partStyle(part, colors, theme) {
81
131
  const fill = tcStyle ? poChildren(tcStyle).find((c) => poIs(c, "a:fill")) : void 0;
82
132
  const solid = fill ? poChildren(fill).find((c) => poIs(c, "a:solidFill")) : void 0;
83
133
  const shadingHex = solid ? colorOf(solid, colors) : void 0;
134
+ const shadingAlpha = solid ? alphaOf(solid) : void 0;
84
135
  const bdr = tcStyle ? poChildren(tcStyle).find((c) => poIs(c, "a:tcBdr")) : void 0;
85
136
  const borders = bdr ? partBorders(bdr, colors, theme) : void 0;
86
137
  const on = (name) => poAttr(txStyle, name) === "on";
87
138
  const colorHex = txStyle ? colorOf(txStyle, colors) : void 0;
88
139
  return {
89
140
  ...shadingHex ? { shadingHex } : {},
141
+ ...shadingAlpha !== void 0 && shadingAlpha < 1 ? { shadingAlpha } : {},
90
142
  ...borders ? { borders } : {},
91
143
  ...txStyle && on("b") ? { bold: true } : {},
92
144
  ...txStyle && on("i") ? { italic: true } : {},
@@ -88,6 +88,7 @@ function emitPage(out, page, laid, losses, idc) {
88
88
  }
89
89
  for (const sh of plan.shapes) emitShape(out, sh.shape, idc);
90
90
  for (const picture of plan.pictures) for (const item of picture) emitPageItem(out, item, laid, losses, idc);
91
+ for (const run of plan.ordered) for (const item of run) emitPageItem(out, item, laid, losses, idc);
91
92
  for (const t of plan.lines) emitTextLine(out, t, losses, idc);
92
93
  }
93
94
  /**
@@ -39,7 +39,10 @@ export interface ParseContext {
39
39
  * pre-rendered drawing override, or `undefined` when the file ships none
40
40
  * (E-SMARTART SA2).
41
41
  */
42
- readonly resolveDiagram?: (relId: string) => ResolvedDiagram | undefined;
42
+ readonly resolveDiagram?: (relId: string, frame: {
43
+ readonly cx: number;
44
+ readonly cy: number;
45
+ }) => ResolvedDiagram | undefined;
43
46
  /**
44
47
  * §21.2 a `c:chart` `@r:id` → the chart part's path, the key the reader files
45
48
  * parsed charts under. Relationship ids are scoped to their owning part, so a
@@ -484,7 +484,10 @@ function blocksForDrawing(content, paragraphProperties, ctx) {
484
484
  }
485
485
  }];
486
486
  if (content.kind === "diagram") {
487
- const diagram = ctx.resolveDiagram?.(content.dmRelId);
487
+ const diagram = ctx.resolveDiagram?.(content.dmRelId, {
488
+ cx: content.widthEmu,
489
+ cy: content.heightEmu
490
+ });
488
491
  if (!diagram) {
489
492
  ctx.onLoss?.(noDiagramOverrideLoss());
490
493
  return null;
@@ -5,7 +5,7 @@ import { resolveTableStyles } from "../core/style-cascade/table.js";
5
5
  import "../core/style-cascade/index.js";
6
6
  import { applyNumbering, applyNumberingToHeadersFooters } from "../core/numbering/apply.js";
7
7
  import "../core/numbering/index.js";
8
- import { poFindDescendant } from "../core/po-helpers.js";
8
+ import { cachedDiagramTree, laidOutDiagramTree } from "../core/drawingml/diagram/run.js";
9
9
  import { packageHasPart } from "../core/bytes.js";
10
10
  import { DEFAULT_THEME_PALETTE, makeColorResolver } from "../core/drawingml/colors.js";
11
11
  import { parseChart, withChartColorStyle } from "../core/drawingml/chart-parser.js";
@@ -185,29 +185,42 @@ function infoFromCore(core) {
185
185
  }
186
186
  function makeDiagramResolver(pkg, partName, store) {
187
187
  const cache = /* @__PURE__ */ new Map();
188
- return (relId) => {
189
- if (cache.has(relId)) return cache.get(relId);
188
+ return (relId, frame) => {
189
+ const key = `${relId}|${frame.cx}x${frame.cy}`;
190
+ if (cache.has(key)) return cache.get(key);
190
191
  let resolved;
191
192
  const dataRel = pkg.getPartRelationships(partName).find((r) => r.id === relId);
192
193
  const data = dataRel ? pkg.resolveRelatedPart(partName, dataRel) : void 0;
193
194
  if (data) {
194
195
  const own = pkg.getPartRelationships(data.path).find((r) => r.type.endsWith("/diagramDrawing"));
195
196
  const draw = own ? pkg.resolveRelatedPart(data.path, own) : drawingFromOwner(pkg, partName, data.path);
196
- if (draw) for (const root of parseXml(draw.data)) {
197
- const spTree = poFindDescendant(root, "dsp:spTree");
198
- if (spTree) {
199
- resolved = {
200
- spTree,
201
- resolveImage: makeImageResolver(pkg, store, draw.path)
202
- };
203
- break;
204
- }
197
+ const cached = draw ? cachedDiagramTree(draw.data, parseXml) : void 0;
198
+ if (cached && draw) resolved = {
199
+ spTree: cached,
200
+ resolveImage: makeImageResolver(pkg, store, draw.path)
201
+ };
202
+ else {
203
+ const spTree = laidOutDiagramTree({
204
+ data: data.data,
205
+ layout: siblingPart(pkg, partName, data.path, "/diagramLayout"),
206
+ colors: siblingPart(pkg, partName, data.path, "/diagramColors")
207
+ }, frame, parseXml);
208
+ if (spTree) resolved = { spTree };
205
209
  }
206
210
  }
207
- cache.set(relId, resolved);
211
+ cache.set(key, resolved);
208
212
  return resolved;
209
213
  };
210
214
  }
215
+ function siblingPart(pkg, ownerPart, dataPart, type) {
216
+ const own = pkg.getPartRelationships(dataPart).find((r) => r.type.endsWith(type));
217
+ if (own) return pkg.resolveRelatedPart(dataPart, own)?.data;
218
+ const index = (path) => /(\d*)\.[^.]+$/u.exec(path)?.[1] ?? "";
219
+ const want = index(dataPart);
220
+ const rels = pkg.getPartRelationships(ownerPart).filter((r) => r.type.endsWith(type));
221
+ const rel = rels.find((r) => index(r.target) === want) ?? (rels.length === 1 ? rels[0] : void 0);
222
+ return rel ? pkg.resolveRelatedPart(ownerPart, rel)?.data : void 0;
223
+ }
211
224
  function drawingFromOwner(pkg, ownerPart, dataPart) {
212
225
  const drawings = pkg.getPartRelationships(ownerPart).filter((r) => r.type.endsWith("/diagramDrawing"));
213
226
  if (drawings.length === 0) return void 0;