reamkit 1.22.0 → 1.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/dist/esm/core/bmp.d.ts +33 -0
  2. package/dist/esm/core/bmp.js +276 -0
  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 +55 -0
  6. package/dist/esm/core/drawingml/chart-geometry.js +14 -7
  7. package/dist/esm/core/drawingml/colors.d.ts +4 -2
  8. package/dist/esm/core/drawingml/colors.js +15 -0
  9. package/dist/esm/core/drawingml/diagram/colors.d.ts +52 -0
  10. package/dist/esm/core/drawingml/diagram/colors.js +125 -0
  11. package/dist/esm/core/drawingml/diagram/data-model.d.ts +47 -0
  12. package/dist/esm/core/drawingml/diagram/data-model.js +119 -0
  13. package/dist/esm/core/drawingml/diagram/layout-engine.d.ts +46 -0
  14. package/dist/esm/core/drawingml/diagram/layout-engine.js +948 -0
  15. package/dist/esm/core/drawingml/diagram/run.d.ts +37 -0
  16. package/dist/esm/core/drawingml/diagram/run.js +50 -0
  17. package/dist/esm/core/drawingml/diagram/to-drawing.d.ts +16 -0
  18. package/dist/esm/core/drawingml/diagram/to-drawing.js +86 -0
  19. package/dist/esm/core/drawingml/preset-geometry.js +116 -6
  20. package/dist/esm/core/drawingml/text-warp.d.ts +58 -0
  21. package/dist/esm/core/drawingml/text-warp.js +355 -0
  22. package/dist/esm/core/drawingml/theme-parser.d.ts +38 -0
  23. package/dist/esm/core/drawingml/theme-parser.js +73 -4
  24. package/dist/esm/core/font/measure.d.ts +12 -0
  25. package/dist/esm/core/font/measure.js +36 -0
  26. package/dist/esm/core/fonts/families.d.ts +10 -0
  27. package/dist/esm/core/fonts/families.js +44 -0
  28. package/dist/esm/core/fonts/index.d.ts +3 -2
  29. package/dist/esm/core/fonts/remote-fonts.d.ts +50 -0
  30. package/dist/esm/core/fonts/remote-fonts.js +114 -8
  31. package/dist/esm/core/fonts/scripts.d.ts +26 -0
  32. package/dist/esm/core/fonts/scripts.js +177 -0
  33. package/dist/esm/core/images.d.ts +30 -2
  34. package/dist/esm/core/images.js +121 -5
  35. package/dist/esm/core/metafile/blit.d.ts +33 -0
  36. package/dist/esm/core/metafile/blit.js +67 -0
  37. package/dist/esm/core/metafile/dib.d.ts +61 -0
  38. package/dist/esm/core/metafile/dib.js +205 -0
  39. package/dist/esm/core/metafile/emf.js +280 -38
  40. package/dist/esm/core/metafile/picture.d.ts +61 -1
  41. package/dist/esm/core/metafile/picture.js +70 -1
  42. package/dist/esm/core/metafile/wmf.js +202 -13
  43. package/dist/esm/core/ole/escher-blip.d.ts +12 -0
  44. package/dist/esm/core/ole/escher-blip.js +98 -0
  45. package/dist/esm/{pdf-reader → core}/png-encode.js +1 -1
  46. package/dist/esm/excel/print-model.js +5 -3
  47. package/dist/esm/excel/sheet-drawing.js +1 -1
  48. package/dist/esm/excel/sheet-to-flow.js +16 -2
  49. package/dist/esm/excel/styles-parser.js +1 -1
  50. package/dist/esm/excel/xls/biff-reader.js +53 -18
  51. package/dist/esm/excel/xls/biff-styles.d.ts +5 -2
  52. package/dist/esm/excel/xls/biff-styles.js +9 -7
  53. package/dist/esm/excel/xls/escher.js +90 -24
  54. package/dist/esm/html/html-writer.js +2 -1
  55. package/dist/esm/layout/page-doc.d.ts +74 -0
  56. package/dist/esm/layout/page-doc.js +14 -1
  57. package/dist/esm/layout/styled-layout.d.ts +2 -2
  58. package/dist/esm/layout/styled-layout.js +475 -48
  59. package/dist/esm/pdf/shading.js +8 -6
  60. package/dist/esm/pdf/styled-page-emitter.js +77 -5
  61. package/dist/esm/pdf/vector-graphics.js +1 -1
  62. package/dist/esm/pdf-reader/image-decode.js +1 -1
  63. package/dist/esm/pptx/embedded-fonts.d.ts +31 -0
  64. package/dist/esm/pptx/embedded-fonts.js +104 -0
  65. package/dist/esm/pptx/placeholder-cascade.d.ts +73 -6
  66. package/dist/esm/pptx/placeholder-cascade.js +114 -18
  67. package/dist/esm/pptx/ppt/ppt-reader.js +191 -13
  68. package/dist/esm/pptx/ppt/ppt-text.d.ts +107 -1
  69. package/dist/esm/pptx/ppt/ppt-text.js +873 -144
  70. package/dist/esm/pptx/pptx-reader.d.ts +8 -0
  71. package/dist/esm/pptx/pptx-reader.js +117 -15
  72. package/dist/esm/pptx/preset-table-styles.d.ts +9 -0
  73. package/dist/esm/pptx/preset-table-styles.js +27 -0
  74. package/dist/esm/pptx/slide-parser.d.ts +11 -2
  75. package/dist/esm/pptx/slide-parser.js +203 -44
  76. package/dist/esm/pptx/sp-helpers.d.ts +9 -4
  77. package/dist/esm/pptx/sp-helpers.js +48 -9
  78. package/dist/esm/pptx/table-style.d.ts +16 -1
  79. package/dist/esm/pptx/table-style.js +104 -10
  80. package/dist/esm/svg/svg-writer.js +1 -0
  81. package/dist/esm/word/document-parser.d.ts +11 -2
  82. package/dist/esm/word/document-parser.js +10 -7
  83. package/dist/esm/word/docx-reader.js +32 -16
  84. package/dist/esm/word/docx-to-pdf.d.ts +8 -7
  85. package/dist/esm/word/docx-to-pdf.js +25 -7
  86. package/dist/esm/word/docx-writer.js +4 -0
  87. package/dist/esm/word/drawing-parser.d.ts +20 -0
  88. package/dist/esm/word/drawing-parser.js +67 -22
  89. package/dist/esm/word/numbering-parser.d.ts +2 -1
  90. package/dist/esm/word/numbering-parser.js +6 -6
  91. package/dist/esm/word/paragraph-properties.d.ts +2 -1
  92. package/dist/esm/word/paragraph-properties.js +2 -2
  93. package/dist/esm/word/run-properties.d.ts +5 -2
  94. package/dist/esm/word/run-properties.js +13 -8
  95. package/dist/esm/word/styles-parser.d.ts +2 -1
  96. package/dist/esm/word/styles-parser.js +12 -12
  97. package/dist/esm/word/table-parser.js +6 -3
  98. package/dist/esm/word/theme-fonts.d.ts +10 -0
  99. package/dist/esm/word/theme-fonts.js +28 -0
  100. package/package.json +1 -1
  101. /package/dist/esm/{pdf-reader → core}/png-encode.d.ts +0 -0
@@ -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
- import { parseBullet } from "./placeholder-cascade.js";
7
- import { colorChangeOf, parseCustGeom, parseFill, parseLine, parsePrstGeom, parseShadow, parseXfrm, statesFill, styleRefFill, styleRefFontColor, styleRefLine } from "../word/drawing-parser.js";
7
+ import { lineSpacing, parseBullet, spacingFractions, spacingFromLineFraction } from "./placeholder-cascade.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.
@@ -116,19 +149,25 @@ function parseSp(sp, ctx, transform) {
116
149
  const style = poChildren(sp).find((c) => poIs(c, "p:style"));
117
150
  const txBody = poChildren(sp).find((c) => poIs(c, "p:txBody"));
118
151
  const styleColor = style ? styleRefFontColor(style, colors) : void 0;
119
- const text = txBody ? parseTxBody(txBody, ph, ctx.cascade, colors, ctx.resolveHyperlink, styleColor) : void 0;
120
- const proto = ph && ctx.cascade ? ctx.cascade.shapePropsFor(ph) : void 0;
121
- const geometry = parseGeometry(spPr && statesGeometry(spPr) ? spPr : proto ?? spPr);
152
+ const text = txBody ? parseTxBody(txBody, ph, ctx.cascade, colors, ctx.resolveHyperlink, styleColor, ctx.themeFonts) : void 0;
153
+ const protos = ph && ctx.cascade ? ctx.cascade.shapePropsFor(ph) : [];
154
+ const from = (states) => spPr && states(spPr) ? spPr : protos.find(states) ?? spPr;
155
+ /** What the shape states ITSELF, before anything is inherited. */
156
+ const stated = (states) => spPr && states(spPr) ? spPr : void 0;
157
+ /** …and what a prototype lends it, nearest first. */
158
+ const lent = (states) => protos.find(states);
159
+ const geometry = parseGeometry(from(statesGeometry));
122
160
  const useBgFill = poAttr(sp, "useBgFill") === "1";
123
- const fillFrom = statesFill(spPr) ? spPr : proto ?? spPr;
124
- const fill = useBgFill ? backgroundThrough(ctx.backgroundFill, box, ctx.slideSize) : fillFrom ? parseFill(fillFrom, colors, ctx.resolveImage) : { kind: "none" };
125
- const lineFrom = spPr && poChildren(spPr).some((c) => poIs(c, "a:ln")) ? spPr : proto ?? spPr;
126
- let line = lineFrom ? parseLine(lineFrom, colors) : void 0;
127
161
  const themeStyles = ctx.themeFills ? {
128
162
  fills: ctx.themeFills.fills,
129
163
  bgFills: ctx.themeFills.backgrounds
130
164
  } : void 0;
131
- const styled = style && fill.kind === "none" && !statesFill(fillFrom) ? styleRefFill(style, colors, themeStyles) : fill;
165
+ const ownFill = stated(statesFill);
166
+ const styleFill = style ? styleRefFill(style, colors, themeStyles) : void 0;
167
+ const lentFill = lent(statesFill);
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);
169
+ const lineFrom = from((n) => poChildren(n).some((c) => poIs(c, "a:ln")));
170
+ let line = lineFrom ? parseLine(lineFrom, colors) : void 0;
132
171
  if (style) {
133
172
  const fromStyle = styleRefLine(style, colors, ctx.themeLineWidths);
134
173
  if (fromStyle) line = line ? {
@@ -136,6 +175,8 @@ function parseSp(sp, ctx, transform) {
136
175
  ...Object.fromEntries(Object.entries(line).filter(([, v]) => v !== void 0))
137
176
  } : fromStyle;
138
177
  }
178
+ const shadowFrom = from((n) => poChildren(n).some((c) => poIs(c, "a:effectLst")));
179
+ const shadow = shadowFrom ? parseShadow(shadowFrom, colors) : void 0;
139
180
  const visibleLine = line !== void 0 && line.fill !== "none";
140
181
  if (!text && styled.kind === "none" && !visibleLine) return void 0;
141
182
  const xfrm = spPr ? poChildren(spPr).find((c) => poIs(c, "a:xfrm")) : void 0;
@@ -147,6 +188,7 @@ function parseSp(sp, ctx, transform) {
147
188
  geometry,
148
189
  fill: styled,
149
190
  ...line ? { line } : {},
191
+ ...shadow ? { shadow } : {},
150
192
  ...spin && Object.keys(spin).length > 0 ? { transform: spin } : {},
151
193
  ...text ? { text } : {},
152
194
  paragraphProperties: {}
@@ -177,7 +219,10 @@ function parseGraphicFrame(gf, ctx, transform) {
177
219
  if (uri === TABLE_URI) {
178
220
  const tbl = poFindDescendant(gf, "a:tbl");
179
221
  if (!tbl) return [];
180
- const table = parseTable(tbl, ctx.colors ?? defaultColorResolver, ctx.resolveTableStyle);
222
+ const table = parseTable(tbl, ctx.colors ?? defaultColorResolver, ctx.resolveTableStyle, {
223
+ ...ctx.themeFills ? { fills: ctx.themeFills.fills } : {},
224
+ ...ctx.themeLineWidths ? { lineWidths: ctx.themeLineWidths } : {}
225
+ });
181
226
  return [{
182
227
  kind: "table",
183
228
  table: {
@@ -224,7 +269,10 @@ function parseGraphicFrame(gf, ctx, transform) {
224
269
  if (uri === DIAGRAM_URI) {
225
270
  const relIds = poFindDescendant(gf, "dgm:relIds");
226
271
  const dmRelId = relIds ? poAttr(relIds, "dm") : void 0;
227
- 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;
228
276
  if (!spTree) {
229
277
  if (dmRelId !== void 0) ctx.onLoss?.(noDiagramOverrideLoss());
230
278
  return [];
@@ -539,7 +587,10 @@ function parseGeometry(spPr) {
539
587
  return RECT_GEOMETRY;
540
588
  }
541
589
  function parsePic(pic, ctx, transform) {
542
- 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);
543
594
  if (!own) return void 0;
544
595
  const box = transform(own);
545
596
  const blipFill = poChildren(pic).find((c) => poIs(c, "p:blipFill"));
@@ -550,12 +601,19 @@ function parsePic(pic, ctx, transform) {
550
601
  const fixed = blip ? poChildren(blip).find((c) => poIs(c, "a:alphaModFix")) : void 0;
551
602
  const amt = fixed ? poIntAttr(fixed, "amt") : void 0;
552
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;
553
607
  const altText = picAltText(pic);
554
608
  return {
555
609
  float: floatAt(box),
556
610
  ...resource !== void 0 ? { resource } : {},
557
611
  ...colorChange ? { colorChange } : {},
558
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 } : {},
559
617
  width: emuToPt(box.cx),
560
618
  height: emuToPt(box.cy),
561
619
  paragraphProperties: {},
@@ -569,14 +627,14 @@ function picAltText(pic) {
569
627
  const title = cNvPr ? poAttr(cNvPr, "title") : void 0;
570
628
  return (descr ?? title)?.trim() || void 0;
571
629
  }
572
- function txBodyParagraphs(txBody, ph, cascade, colors, resolveLink, styleColor) {
630
+ function txBodyParagraphs(txBody, ph, cascade, colors, resolveLink, styleColor, themeFonts) {
573
631
  const content = [];
574
632
  const counters = [];
575
633
  for (const child of poChildren(txBody)) {
576
634
  if (!poIs(child, "a:p")) continue;
577
635
  content.push({
578
636
  kind: "paragraph",
579
- paragraph: parseSlideParagraph(child, ph, cascade, colors, resolveLink, counters, styleColor)
637
+ paragraph: parseSlideParagraph(child, ph, cascade, colors, resolveLink, counters, styleColor, themeFonts)
580
638
  });
581
639
  }
582
640
  return content;
@@ -594,26 +652,100 @@ function txBodyParagraphs(txBody, ph, cascade, colors, resolveLink, styleColor)
594
652
  * @param resolveLink A run hyperlink resolver, or `undefined`.
595
653
  * @returns The text body, or `undefined` when it holds no paragraphs.
596
654
  */
597
- function parseTxBody(txBody, ph, cascade, colors, resolveLink, styleColor) {
598
- const content = txBodyParagraphs(txBody, ph, cascade, colors, resolveLink, styleColor);
655
+ function parseTxBody(txBody, ph, cascade, colors, resolveLink, styleColor, themeFonts) {
656
+ const content = txBodyParagraphs(txBody, ph, cascade, colors, resolveLink, styleColor, themeFonts);
599
657
  if (content.length === 0) return void 0;
600
658
  const bodyPr = poChildren(txBody).find((c) => poIs(c, "a:bodyPr"));
659
+ const fitted = fitToBody(content, bodyPr);
601
660
  const lIns = bodyPr ? poIntAttr(bodyPr, "lIns") : void 0;
602
661
  const tIns = bodyPr ? poIntAttr(bodyPr, "tIns") : void 0;
603
662
  const rIns = bodyPr ? poIntAttr(bodyPr, "rIns") : void 0;
604
663
  const bIns = bodyPr ? poIntAttr(bodyPr, "bIns") : void 0;
605
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;
606
668
  const anchor = a === "ctr" || a === "b" || a === "t" ? a : ph && cascade ? cascade.anchorFor(ph) : void 0;
607
669
  return {
608
- content,
670
+ content: fitted,
609
671
  ...lIns !== void 0 ? { insetLeft: emuToPt(lIns) } : {},
610
672
  ...tIns !== void 0 ? { insetTop: emuToPt(tIns) } : {},
611
673
  ...rIns !== void 0 ? { insetRight: emuToPt(rIns) } : {},
612
674
  ...bIns !== void 0 ? { insetBottom: emuToPt(bIns) } : {},
613
- ...anchor ? { anchor } : {}
675
+ ...anchor ? { anchor } : {},
676
+ ...shrink ? { shrinkToFit: true } : {},
677
+ ...warp ? { warp } : {}
678
+ };
679
+ }
680
+ /**
681
+ * §20.1.9.10 `a:prstTxWarp` — the WordArt curve a body's text is bent through,
682
+ * with the `a:avLst` `adj` guide when it states one. Unread, tdf114848's eight
683
+ * pieces of WordArt were set as eight ordinary paragraphs, each wrapped onto
684
+ * three lines of upright type where both references draw one bent line.
685
+ *
686
+ * @param bodyPr The body's `a:bodyPr`.
687
+ * @returns The preset and its adjustment, or `undefined` when the body states
688
+ * no warp or states the enumeration's `textNoShape`.
689
+ */
690
+ function textWarp(bodyPr) {
691
+ const node = poChildren(bodyPr).find((c) => poIs(c, "a:prstTxWarp"));
692
+ const preset = node ? poAttr(node, "prst") : void 0;
693
+ if (node === void 0 || preset === void 0 || !isTextWarp(preset)) return void 0;
694
+ const avLst = poChildren(node).find((c) => poIs(c, "a:avLst"));
695
+ const adj = avLst ? poChildren(avLst).find((c) => poIs(c, "a:gd") && poAttr(c, "name") === "adj") : void 0;
696
+ const value = adj ? /^val\s+(-?\d+)$/u.exec(poAttr(adj, "fmla") ?? "")?.[1] : void 0;
697
+ return {
698
+ preset,
699
+ ...value !== void 0 ? { adjust: Number(value) } : {}
614
700
  };
615
701
  }
616
- function parseSlideParagraph(aP, ph, cascade, colors, resolveLink, counters, styleColor) {
702
+ /**
703
+ * §21.1.2.1.2 — the body's text at the size the autofit settled on.
704
+ *
705
+ * The scale is a property of the BODY that reaches every run in it, so it is
706
+ * applied here rather than carried down: a run in the model already holds the
707
+ * size it inherited, and the shrink multiplies exactly that. Unread, the text
708
+ * PowerPoint squeezed to 62% of its style overflowed the placeholder it was
709
+ * squeezed to fit.
710
+ *
711
+ * @param content The body's paragraphs.
712
+ * @param bodyPr The body's `a:bodyPr`, which carries the autofit.
713
+ * @returns The paragraphs, scaled; the same array when nothing is stated.
714
+ */
715
+ function fitToBody(content, bodyPr) {
716
+ const fit = bodyPr ? poChildren(bodyPr).find((c) => poIs(c, "a:normAutofit")) : void 0;
717
+ const scale = fit ? poIntAttr(fit, "fontScale") : void 0;
718
+ const reduction = fit ? poIntAttr(fit, "lnSpcReduction") : void 0;
719
+ const fontScale = scale !== void 0 && scale > 0 ? scale / 1e5 : void 0;
720
+ const lineScale = reduction !== void 0 && reduction > 0 ? 1 - Math.min(reduction, 1e5) / 1e5 : void 0;
721
+ if (fontScale === void 0 && lineScale === void 0) return content;
722
+ return content.map((el) => {
723
+ if (el.kind !== "paragraph") return el;
724
+ const p = el.paragraph;
725
+ const line = lineScale === void 0 ? void 0 : pt((p.properties.spacingLine ?? 12) * lineScale);
726
+ return {
727
+ ...el,
728
+ paragraph: {
729
+ ...p,
730
+ properties: {
731
+ ...p.properties,
732
+ ...line !== void 0 ? {
733
+ spacingLine: line,
734
+ spacingLineRule: "auto"
735
+ } : {}
736
+ },
737
+ runs: fontScale === void 0 ? p.runs : p.runs.map((run) => run.properties.fontSizePt === void 0 ? run : {
738
+ ...run,
739
+ properties: {
740
+ ...run.properties,
741
+ fontSizePt: pt(run.properties.fontSizePt * fontScale)
742
+ }
743
+ })
744
+ }
745
+ };
746
+ });
747
+ }
748
+ function parseSlideParagraph(aP, ph, cascade, colors, resolveLink, counters, styleColor, themeFonts) {
617
749
  const pPr = poChildren(aP).find((c) => poIs(c, "a:pPr"));
618
750
  const level = (pPr ? poIntAttr(pPr, "lvl") : void 0) ?? 0;
619
751
  const defaults = {
@@ -624,9 +756,19 @@ function parseSlideParagraph(aP, ph, cascade, colors, resolveLink, counters, sty
624
756
  const algn = pPr ? poAttr(pPr, "algn") : void 0;
625
757
  const alignment = algn !== void 0 ? ALGN_TO_ALIGNMENT[algn] : void 0;
626
758
  const runs = [];
627
- for (const child of poChildren(aP)) if (poIs(child, "a:r") || poIs(child, "a:fld")) {
628
- const run = parseSlideRun(child, defaults, colors, resolveLink);
629
- if (run) runs.push(run);
759
+ for (const child of poChildren(aP)) {
760
+ if (poIs(child, "a:br")) {
761
+ const last = runs[runs.length - 1];
762
+ if (last) runs[runs.length - 1] = {
763
+ ...last,
764
+ text: `${last.text}\n`
765
+ };
766
+ continue;
767
+ }
768
+ if (poIs(child, "a:r") || poIs(child, "a:fld")) {
769
+ const run = parseSlideRun(child, defaults, colors, resolveLink, themeFonts);
770
+ if (run) runs.push(run);
771
+ }
630
772
  }
631
773
  const marL = pPr ? poIntAttr(pPr, "marL") : void 0;
632
774
  const indent = pPr ? poIntAttr(pPr, "indent") : void 0;
@@ -645,27 +787,41 @@ function parseSlideParagraph(aP, ph, cascade, colors, resolveLink, counters, sty
645
787
  listMarker: true
646
788
  });
647
789
  }
648
- if (runs.length === 0) {
649
- const endRPr = poChildren(aP).find((c) => poIs(c, "a:endParaRPr"));
650
- const sz = endRPr ? poIntAttr(endRPr, "sz") : void 0;
651
- if (sz !== void 0 && sz > 0) runs.push({
652
- text: "",
653
- properties: {
654
- ...defaults,
655
- fontSizePt: pt(sz / 100)
656
- }
657
- });
658
- }
790
+ const endRPr = poChildren(aP).find((c) => poIs(c, "a:endParaRPr"));
791
+ const endSz = endRPr ? poIntAttr(endRPr, "sz") : void 0;
792
+ const markProps = runs.length > 0 ? void 0 : {
793
+ ...defaults,
794
+ ...endSz !== void 0 && endSz > 0 ? { fontSizePt: pt(endSz / 100) } : {}
795
+ };
659
796
  return {
660
797
  properties: {
661
798
  ...inherited,
662
799
  ...alignment ? { alignment } : {},
663
800
  ...indentLeft !== void 0 ? { indentLeft } : {},
664
- ...indent !== void 0 ? { indentFirstLine: emuToPt(indent) } : {}
801
+ ...indent !== void 0 ? { indentFirstLine: emuToPt(indent) } : {},
802
+ ...lineSpacing(pPr),
803
+ ...ownSpacing(pPr, runs[0]?.properties.fontSizePt ?? defaults.fontSizePt),
804
+ ...markProps && markProps.fontSizePt !== void 0 ? { runProperties: markProps } : {}
665
805
  },
666
806
  runs
667
807
  };
668
808
  }
809
+ function ownSpacing(pPr, sizePt) {
810
+ const fractions = spacingFractions(pPr);
811
+ const before = spacingFromLineFraction(fractions?.before, sizePt);
812
+ const after = spacingFromLineFraction(fractions?.after, sizePt);
813
+ const points = (tag) => {
814
+ const holder = pPr ? poChildren(pPr).find((c) => poIs(c, tag)) : void 0;
815
+ const node = holder ? poChildren(holder).find((c) => poIs(c, "a:spcPts")) : void 0;
816
+ const val = node ? poIntAttr(node, "val") : void 0;
817
+ return val === void 0 ? void 0 : pt(val / 100);
818
+ };
819
+ const [beforePt, afterPt] = [points("a:spcBef") ?? before, points("a:spcAft") ?? after];
820
+ return {
821
+ ...beforePt !== void 0 ? { spacingBefore: beforePt } : {},
822
+ ...afterPt !== void 0 ? { spacingAfter: afterPt } : {}
823
+ };
824
+ }
669
825
  function bulletProps(base, bullet) {
670
826
  const sizePt = bullet.sizePts ?? (bullet.sizePct !== void 0 && base.fontSizePt !== void 0 ? base.fontSizePt * bullet.sizePct : void 0);
671
827
  return {
@@ -688,7 +844,7 @@ function autoNumSuffix(type) {
688
844
  if (type.endsWith("Period")) return ".";
689
845
  return "";
690
846
  }
691
- function parseSlideRun(node, defaults, colors, resolveLink) {
847
+ function parseSlideRun(node, defaults, colors, resolveLink, themeFonts) {
692
848
  const t = poChildren(node).find((c) => poIs(c, "a:t"));
693
849
  const text = t ? poText(t) : "";
694
850
  if (text.length === 0) return void 0;
@@ -700,12 +856,12 @@ function parseSlideRun(node, defaults, colors, resolveLink) {
700
856
  text,
701
857
  properties: {
702
858
  ...defaults,
703
- ...rPrToRunProps(rPr, colors)
859
+ ...rPrToRunProps(rPr, colors, themeFonts)
704
860
  },
705
861
  ...href ? { href } : {}
706
862
  };
707
863
  }
708
- function parseTable(tbl, colors, resolveTableStyle) {
864
+ function parseTable(tbl, colors, resolveTableStyle, theme) {
709
865
  const grid = [];
710
866
  const tblGrid = poChildren(tbl).find((c) => poIs(c, "a:tblGrid"));
711
867
  if (tblGrid) {
@@ -738,7 +894,7 @@ function parseTable(tbl, colors, resolveTableStyle) {
738
894
  rowCount: rows.length,
739
895
  col: c,
740
896
  colCount: grid.length
741
- }, colors);
897
+ }, colors, theme);
742
898
  const tc = sources[r]?.[c];
743
899
  return withCellStyle(cell, tc && cellSaysNoFill(tc) ? withoutFill(part) : part);
744
900
  })
@@ -767,12 +923,15 @@ function parseTableCell(tc, colors) {
767
923
  const tcPr = poChildren(tc).find((c) => poIs(c, "a:tcPr"));
768
924
  const shadingHex = tcPr ? cellFillHex(tcPr, colors) : void 0;
769
925
  const borders = tcPr ? cellOwnBorders(tcPr, colors) : void 0;
926
+ const vert = tcPr ? poAttr(tcPr, "vert") : void 0;
927
+ const textDirection = vert === "vert" || vert === "eaVert" || vert === "mongolianVert" ? "vert" : vert === "vert270" ? "vert270" : void 0;
770
928
  return {
771
929
  properties: {
772
930
  ...gridSpan !== void 0 && gridSpan > 1 ? { colSpan: gridSpan } : {},
773
931
  ...merge ? { merge } : {},
774
932
  ...shadingHex ? { shading: { colorHex: shadingHex } } : {},
775
- ...borders ? { borders } : {}
933
+ ...borders ? { borders } : {},
934
+ ...textDirection ? { textDirection } : {}
776
935
  },
777
936
  content
778
937
  };
@@ -1,5 +1,6 @@
1
1
  import { RunProperties } from '../core/document-model/index.js';
2
2
  import { ColorResolver } from '../core/drawingml/colors.js';
3
+ import { ThemeFonts } from '../core/drawingml/theme-parser.js';
3
4
  import { PoNode } from '../core/po-helpers.js';
4
5
  /**
5
6
  * §19.3.1.36 `p:ph` — a shape's placeholder reference. `type`/`idx` tie a slide
@@ -18,9 +19,13 @@ export interface ShapeBoxEmu {
18
19
  readonly cy: number;
19
20
  }
20
21
  /**
21
- * `p:nvSpPr/p:nvPr/p:ph` → the placeholder reference, or `undefined` for an
22
- * ordinary (non-placeholder) shape. A bare `<p:ph/>` returns an empty ref (still
23
- * 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).
24
29
  */
25
30
  export declare function parsePh(sp: PoNode): PlaceholderRef | undefined;
26
31
  /**
@@ -42,4 +47,4 @@ export declare function parseXfrmBox(spPr: PoNode | undefined): ShapeBoxEmu | un
42
47
  * (`sz`, hundredths of a point), bold/italic/underline, solid colour and the
43
48
  * latin typeface. Scheme colours and the theme font cascade come in PX5.
44
49
  */
45
- export declare function rPrToRunProps(rPr: PoNode | undefined, colors: ColorResolver): RunProperties;
50
+ export declare function rPrToRunProps(rPr: PoNode | undefined, colors: ColorResolver, themeFonts?: ThemeFonts): RunProperties;
@@ -1,16 +1,27 @@
1
1
  import { pt } from "../core/ir/units.js";
2
2
  import { poAttr, poChildren, poIntAttr, poIs } from "../core/po-helpers.js";
3
3
  import { resolveColorNode } from "../core/drawingml/colors.js";
4
+ import { resolveThemeFont } from "../core/drawingml/theme-parser.js";
4
5
  //#region src/pptx/sp-helpers.ts
5
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
+ ];
6
13
  /**
7
- * `p:nvSpPr/p:nvPr/p:ph` → the placeholder reference, or `undefined` for an
8
- * ordinary (non-placeholder) shape. A bare `<p:ph/>` returns an empty ref (still
9
- * 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).
10
21
  */
11
22
  function parsePh(sp) {
12
- const nvSpPr = poChildren(sp).find((c) => poIs(c, "p:nvSpPr"));
13
- 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;
14
25
  const ph = nvPr ? poChildren(nvPr).find((c) => poIs(c, "p:ph")) : void 0;
15
26
  if (!ph) return void 0;
16
27
  const type = poAttr(ph, "type");
@@ -54,13 +65,13 @@ function parseXfrmBox(spPr) {
54
65
  * (`sz`, hundredths of a point), bold/italic/underline, solid colour and the
55
66
  * latin typeface. Scheme colours and the theme font cascade come in PX5.
56
67
  */
57
- function rPrToRunProps(rPr, colors) {
68
+ function rPrToRunProps(rPr, colors, themeFonts) {
58
69
  if (!rPr) return {};
59
70
  const sz = poIntAttr(rPr, "sz");
60
71
  const u = poAttr(rPr, "u");
61
72
  const colorHex = solidFillColor(rPr, colors);
62
73
  const latin = poChildren(rPr).find((c) => poIs(c, "a:latin"));
63
- const typeface = latin ? poAttr(latin, "typeface")?.trim() : void 0;
74
+ const typeface = resolveThemeFont(latin ? poAttr(latin, "typeface")?.trim() : void 0, themeFonts);
64
75
  const flag = (name) => {
65
76
  const v = poAttr(rPr, name);
66
77
  return v === void 0 ? void 0 : isTrue(v);
@@ -87,8 +98,36 @@ function capsOf(cap) {
87
98
  }
88
99
  function solidFillColor(rPr, colors) {
89
100
  const solidFill = poChildren(rPr).find((c) => poIs(c, "a:solidFill"));
90
- if (!solidFill) return void 0;
91
- 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)) {
92
131
  const hex = resolveColorNode(c, colors);
93
132
  if (hex) return hex;
94
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;
@@ -29,6 +36,13 @@ export interface CellPosition {
29
36
  export declare function tableStyleFlags(tblPr: PoNode | undefined): TableStyleFlags;
30
37
  /** The GUID a table names, if it names one (`a:tblPr/a:tableStyleId`). */
31
38
  export declare function tableStyleId(tblPr: PoNode | undefined): string | undefined;
39
+ /** What the deck's theme lends a style that points at it instead of spelling it out. */
40
+ export interface TableStyleTheme {
41
+ /** §20.1.4.1.14 `a:fillStyleLst` — the fills an `a:fillRef` indexes. */
42
+ readonly fills?: ReadonlyArray<PoNode>;
43
+ /** §20.1.4.2.19 `a:lnStyleLst` — the widths an `a:lnRef` indexes, in points. */
44
+ readonly lineWidths?: ReadonlyArray<number>;
45
+ }
32
46
  /**
33
47
  * The style a cell wears, composed from every part that reaches it.
34
48
  *
@@ -36,9 +50,10 @@ export declare function tableStyleId(tblPr: PoNode | undefined): string | undefi
36
50
  * @param flags Which conditional parts the table asks for.
37
51
  * @param at Where the cell sits.
38
52
  * @param colors The deck's colour resolver.
53
+ * @param theme The theme's style lists, for the parts that point at them.
39
54
  * @returns The composed part, empty when the style says nothing.
40
55
  */
41
- export declare function cellStyle(style: PoNode, flags: TableStyleFlags, at: CellPosition, colors: ColorResolver): TableStylePart;
56
+ export declare function cellStyle(style: PoNode, flags: TableStyleFlags, at: CellPosition, colors: ColorResolver, theme?: TableStyleTheme): TableStylePart;
42
57
  /**
43
58
  * §20.1.2.1 `a:ln` → the rule it draws on one side of a cell.
44
59
  *