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
@@ -0,0 +1,37 @@
1
+ import { PoNode } from '../../po-helpers.js';
2
+ /** The parts a diagram is run from, as the reader resolved them. */
3
+ export interface DiagramParts {
4
+ readonly data: Uint8Array;
5
+ readonly layout?: Uint8Array | undefined;
6
+ readonly colors?: Uint8Array | undefined;
7
+ }
8
+ /**
9
+ * The picture a drawing part caches, when it caches one at all.
10
+ *
11
+ * A generator may write the drawing part and put nothing in it — the group
12
+ * properties and no `dsp:sp` at all. That is a placeholder the generator never
13
+ * got round to filling, not a diagram drawn as empty, and taking it at its word
14
+ * paints a blank frame over a diagram whose data, layout and colours are all
15
+ * present. So an empty tree reads as no tree, and the caller runs the layout
16
+ * exactly as it does for a file that ships no drawing part in the first place.
17
+ *
18
+ * @param drawing The drawing part's bytes.
19
+ * @param parse The reader's XML parser.
20
+ * @returns The cached `dsp:spTree`, or undefined when there is none to use.
21
+ */
22
+ export declare function cachedDiagramTree(drawing: Uint8Array, parse: (bytes: Uint8Array) => Array<PoNode>): PoNode | undefined;
23
+ /**
24
+ * The `dsp:spTree` a diagram's own parts describe, for a file that ships no
25
+ * cached drawing.
26
+ *
27
+ * @param parts The diagram's data, layout and colours parts.
28
+ * @param frame The extent the drawing gives the diagram, in EMU.
29
+ * @param parse The reader's XML parser (the same tree shape either way).
30
+ * @returns The shape tree, or undefined when there is no layout part or the
31
+ * layout uses an algorithm this engine does not run — the caller then
32
+ * reports the diagram as a loss exactly as before.
33
+ */
34
+ export declare function laidOutDiagramTree(parts: DiagramParts, frame: {
35
+ readonly cx: number;
36
+ readonly cy: number;
37
+ }, parse: (bytes: Uint8Array) => Array<PoNode>): PoNode | undefined;
@@ -0,0 +1,50 @@
1
+ import { poChildren, poFindDescendant, poIs } from "../../po-helpers.js";
2
+ import { DiagramColors } from "./colors.js";
3
+ import { DiagramData } from "./data-model.js";
4
+ import { layoutDiagram } from "./layout-engine.js";
5
+ import { diagramDrawingXml } from "./to-drawing.js";
6
+ //#region src/core/drawingml/diagram/run.ts
7
+ /**
8
+ * The picture a drawing part caches, when it caches one at all.
9
+ *
10
+ * A generator may write the drawing part and put nothing in it — the group
11
+ * properties and no `dsp:sp` at all. That is a placeholder the generator never
12
+ * got round to filling, not a diagram drawn as empty, and taking it at its word
13
+ * paints a blank frame over a diagram whose data, layout and colours are all
14
+ * present. So an empty tree reads as no tree, and the caller runs the layout
15
+ * exactly as it does for a file that ships no drawing part in the first place.
16
+ *
17
+ * @param drawing The drawing part's bytes.
18
+ * @param parse The reader's XML parser.
19
+ * @returns The cached `dsp:spTree`, or undefined when there is none to use.
20
+ */
21
+ function cachedDiagramTree(drawing, parse) {
22
+ for (const root of parse(drawing)) {
23
+ const found = poFindDescendant(root, "dsp:spTree");
24
+ if (found && poChildren(found).some((c) => poIs(c, "dsp:sp"))) return found;
25
+ }
26
+ }
27
+ /**
28
+ * The `dsp:spTree` a diagram's own parts describe, for a file that ships no
29
+ * cached drawing.
30
+ *
31
+ * @param parts The diagram's data, layout and colours parts.
32
+ * @param frame The extent the drawing gives the diagram, in EMU.
33
+ * @param parse The reader's XML parser (the same tree shape either way).
34
+ * @returns The shape tree, or undefined when there is no layout part or the
35
+ * layout uses an algorithm this engine does not run — the caller then
36
+ * reports the diagram as a loss exactly as before.
37
+ */
38
+ function laidOutDiagramTree(parts, frame, parse) {
39
+ if (!parts.layout) return void 0;
40
+ const data = new DiagramData(parse(parts.data));
41
+ const nodes = layoutDiagram(parse(parts.layout), data, frame.cx, frame.cy);
42
+ if (nodes.length === 0) return void 0;
43
+ const xml = diagramDrawingXml(nodes, frame, parts.colors ? new DiagramColors(parse(parts.colors)) : void 0, data.background);
44
+ for (const root of parse(new TextEncoder().encode(xml))) {
45
+ const found = poFindDescendant(root, "dsp:spTree");
46
+ if (found) return found;
47
+ }
48
+ }
49
+ //#endregion
50
+ export { cachedDiagramTree, laidOutDiagramTree };
@@ -0,0 +1,16 @@
1
+ import { DiagramColors } from './colors.js';
2
+ import { LaidNode } from './layout-engine.js';
3
+ import { PoNode } from '../../po-helpers.js';
4
+ /**
5
+ * A `dsp:drawing` for boxes the engine laid out.
6
+ *
7
+ * @param nodes The laid-out boxes, in the diagram's own EMU frame.
8
+ * @param frame The frame the slide gives the diagram.
9
+ * @param colors The colours part, when the file carries one.
10
+ * @param bg §21.4.2.4 `dgm:bg` — the fill behind the whole diagram.
11
+ * @returns The XML text of the drawing part.
12
+ */
13
+ export declare function diagramDrawingXml(nodes: ReadonlyArray<LaidNode>, frame: {
14
+ readonly cx: number;
15
+ readonly cy: number;
16
+ }, colors?: DiagramColors, bg?: PoNode): string;
@@ -0,0 +1,86 @@
1
+ import { poAttr, poChildren, poIs, poText } from "../../po-helpers.js";
2
+ import { pointPaint } from "./colors.js";
3
+ //#region src/core/drawingml/diagram/to-drawing.ts
4
+ var NS = "xmlns:dsp=\"http://schemas.microsoft.com/office/drawing/2008/diagram\" xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\"";
5
+ /**
6
+ * A `dsp:drawing` for boxes the engine laid out.
7
+ *
8
+ * @param nodes The laid-out boxes, in the diagram's own EMU frame.
9
+ * @param frame The frame the slide gives the diagram.
10
+ * @param colors The colours part, when the file carries one.
11
+ * @param bg §21.4.2.4 `dgm:bg` — the fill behind the whole diagram.
12
+ * @returns The XML text of the drawing part.
13
+ */
14
+ function diagramDrawingXml(nodes, frame, colors, bg) {
15
+ const back = pointPaint(bg).fill;
16
+ const panel = back === void 0 ? "" : `<dsp:sp><dsp:spPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="${r(frame.cx)}" cy="${r(frame.cy)}"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom>${back}<a:ln><a:noFill/></a:ln></dsp:spPr><dsp:txBody><a:bodyPr/><a:lstStyle/><a:p/></dsp:txBody></dsp:sp>`;
17
+ const shapes = nodes.map((n) => {
18
+ const off = `<a:off x="${r(n.x)}" y="${r(n.y)}"/><a:ext cx="${r(n.cx)}" cy="${r(n.cy)}"/>`;
19
+ const own = pointPaint(n.point.spPr);
20
+ const paint = n.hideGeom === true ? "<a:noFill/><a:ln><a:noFill/></a:ln>" : (own.fill ?? colors?.fill(n.styleLbl, n.index) ?? (colors?.knows(n.styleLbl) === true ? "<a:noFill/>" : "<a:solidFill><a:schemeClr val=\"accent1\"/></a:solidFill>")) + (own.line ?? colors?.line(n.styleLbl, n.index) ?? "");
21
+ const text = colors?.textFill(n.styleLbl, n.index);
22
+ return `<dsp:sp><dsp:spPr><a:xfrm${n.rotation60k !== void 0 ? ` rot="${r(n.rotation60k)}"` : ""}>${off}</a:xfrm><a:prstGeom prst="${esc(n.shapeType)}"><a:avLst/></a:prstGeom>${paint}</dsp:spPr><dsp:style><a:fontRef idx="minor"><a:schemeClr val="lt1"/></a:fontRef></dsp:style><dsp:txBody>${bodyXml(n, text)}</dsp:txBody></dsp:sp>`;
23
+ }).join("");
24
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
25
+ <dsp:drawing ${NS}><dsp:spTree>${`<dsp:grpSpPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="${r(frame.cx)}" cy="${r(frame.cy)}"/><a:chOff x="0" y="0"/><a:chExt cx="${r(frame.cx)}" cy="${r(frame.cy)}"/></a:xfrm></dsp:grpSpPr>`}${panel}${shapes}</dsp:spTree></dsp:drawing>`;
26
+ }
27
+ function bodyXml(node, textFill) {
28
+ const paragraphs = [];
29
+ for (const p of node.point.text ? poChildren(node.point.text) : []) {
30
+ if (!poIs(p, "a:p")) continue;
31
+ let runs = "";
32
+ for (const r of poChildren(p)) {
33
+ if (poIs(r, "a:br")) {
34
+ runs += "<a:br/>";
35
+ continue;
36
+ }
37
+ if (!poIs(r, "a:r")) continue;
38
+ const text = poText(poChildren(r).find((c) => poIs(c, "a:t")));
39
+ if (text !== "") {
40
+ const src = poChildren(r).find((c) => poIs(c, "a:rPr"));
41
+ const stated = poAttr(src, "sz");
42
+ const sz = stated !== void 0 ? ` sz="${esc(stated)}"` : node.fontSizePt === void 0 ? "" : ` sz="${Math.round(node.fontSizePt * 100)}"`;
43
+ const emph = [
44
+ "b",
45
+ "i",
46
+ "u"
47
+ ].map((a) => {
48
+ const v = poAttr(src, a);
49
+ return v === void 0 ? "" : ` ${a}="${esc(v)}"`;
50
+ }).join("");
51
+ const rPr = textFill === void 0 ? `<a:rPr lang="en-US"${sz}${emph}/>` : `<a:rPr lang="en-US"${sz}${emph}>${textFill}</a:rPr>`;
52
+ runs += `<a:r>${rPr}<a:t>${esc(text)}</a:t></a:r>`;
53
+ }
54
+ }
55
+ if (runs !== "") paragraphs.push(`<a:p>${paraPr(node, p)}${runs}</a:p>`);
56
+ }
57
+ const body = `<a:bodyPr anchor="${node.anchor === void 0 ? "ctr" : esc(node.anchor)}"${node.bulleted === true ? " anchorCtr=\"0\"" : ""}><a:normAutofit/></a:bodyPr><a:lstStyle/>`;
58
+ return paragraphs.length > 0 ? body + paragraphs.join("") : `${body}<a:p/>`;
59
+ }
60
+ /**
61
+ * One paragraph's properties. `bulletEnabled` on a layout node says only that
62
+ * bullets are ALLOWED here; which bullet a paragraph actually takes — or that it
63
+ * takes none — is the data part's to state, and smartart-missing-bullet is a
64
+ * file of exactly two paragraphs, one `a:buNone` and one `a:buChar`, that came
65
+ * out with the same marker on both. So a paragraph that states its own bullet or
66
+ * its own alignment keeps them, and only one that states neither falls back to
67
+ * the layout's answer: ranged left behind a bullet where the layout allows one,
68
+ * centred where it does not.
69
+ */
70
+ function paraPr(node, para) {
71
+ const src = poChildren(para).find((c) => poIs(c, "a:pPr"));
72
+ const bullet = poChildren(src).find((c) => poIs(c, "a:buNone") || poIs(c, "a:buChar") || poIs(c, "a:buAutoNum"));
73
+ const listed = bullet === void 0 ? node.bulleted === true : !poIs(bullet, "a:buNone");
74
+ const algn = poAttr(src, "algn") ?? node.align ?? (listed ? "l" : "ctr");
75
+ if (!listed) return `<a:pPr algn="${esc(algn)}"/>`;
76
+ const marL = poAttr(src, "marL") ?? "171450";
77
+ const indent = poAttr(src, "indent") ?? "-171450";
78
+ const char = bullet !== void 0 && poIs(bullet, "a:buChar") ? poAttr(bullet, "char") : void 0;
79
+ return `<a:pPr algn="${esc(algn)}" marL="${esc(marL)}" indent="${esc(indent)}"><a:buChar char="${esc(char ?? "•")}"/></a:pPr>`;
80
+ }
81
+ var r = (v) => Math.round(v);
82
+ function esc(s) {
83
+ return s.replace(/&/gu, "&amp;").replace(/</gu, "&lt;").replace(/>/gu, "&gt;").replace(/"/gu, "&quot;");
84
+ }
85
+ //#endregion
86
+ export { diagramDrawingXml };
@@ -75,6 +75,94 @@ function presetPaths(preset, w, h, adjust) {
75
75
  ])];
76
76
  }
77
77
  case "pentagon": return [regularPolygon(w, h, 5)];
78
+ case "heptagon": return [regularPolygon(w, h, 7)];
79
+ case "octagon": return [regularPolygon(w, h, 8, Math.PI / 8)];
80
+ case "decagon": return [regularPolygon(w, h, 10, Math.PI / 10)];
81
+ case "dodecagon": return [regularPolygon(w, h, 12, Math.PI / 12)];
82
+ case "donut": {
83
+ const t = clamp(frac(adjust, "adj", 25e3), 0, .5) * Math.min(w, h);
84
+ const b = new PathBuilder().append(ellipseSegments(w, h));
85
+ const [ix, iy] = [w / 2 - t, h / 2 - t];
86
+ if (ix > 0 && iy > 0) {
87
+ b.moveTo(w / 2 + ix, h / 2).append(arcToBeziers(w / 2, h / 2, ix, iy, 0, 2 * Math.PI));
88
+ b.close();
89
+ }
90
+ return [b.build("evenodd")];
91
+ }
92
+ case "frame": {
93
+ const t = clamp(frac(adjust, "adj", 12500), 0, .5) * Math.min(w, h);
94
+ return [new PathBuilder().moveTo(0, 0).lineTo(w, 0).lineTo(w, h).lineTo(0, h).close().moveTo(t, t).lineTo(w - t, t).lineTo(w - t, h - t).lineTo(t, h - t).close().build("evenodd")];
95
+ }
96
+ case "diagStripe": {
97
+ const a = clamp(frac(adjust, "adj", 5e4), 0, 1);
98
+ return [polygon([
99
+ [0, h - h * a],
100
+ [w * a, h],
101
+ [w, h],
102
+ [0, 0]
103
+ ])];
104
+ }
105
+ case "teardrop": {
106
+ const a = clamp(frac(adjust, "adj", 1e5), 0, 2);
107
+ const [rx, ry] = [w / 2, h / 2];
108
+ return [new PathBuilder().moveTo(rx, h).append(arcToBeziers(rx, ry, rx, ry, Math.PI / 2, 3 * Math.PI / 2)).lineTo(w * (.5 + a / 2), h * (.5 + a / 2)).close().build()];
109
+ }
110
+ case "can": return cylinder(w, h, clamp(frac(adjust, "adj", 25e3), 0, .5) * h / 2);
111
+ case "halfFrame": {
112
+ const ss = Math.min(w, h);
113
+ const x1 = clamp(frac(adjust, "adj2", 33333), 0, 1) * ss;
114
+ const y1 = clamp(frac(adjust, "adj1", 33333), 0, 1) * ss;
115
+ const x2 = w - (h === 0 ? 0 : y1 * w / h);
116
+ const y2 = h - (w === 0 ? 0 : x1 * h / w);
117
+ return [polygon([
118
+ [0, 0],
119
+ [0, h],
120
+ [w, h],
121
+ [x2, h - y1],
122
+ [x1, h - y1],
123
+ [x1, h - y2]
124
+ ])];
125
+ }
126
+ case "bevel": {
127
+ const t = clamp(frac(adjust, "adj", 12500), 0, .5) * Math.min(w, h);
128
+ const face = (pts) => polygon(pts);
129
+ return [
130
+ face([
131
+ [0, h],
132
+ [w, h],
133
+ [w - t, h - t],
134
+ [t, h - t]
135
+ ]),
136
+ face([
137
+ [0, h],
138
+ [t, h - t],
139
+ [t, t],
140
+ [0, 0]
141
+ ]),
142
+ face([
143
+ [w, 0],
144
+ [0, 0],
145
+ [t, t],
146
+ [w - t, t]
147
+ ]),
148
+ face([
149
+ [w, 0],
150
+ [w - t, t],
151
+ [w - t, h - t],
152
+ [w, h]
153
+ ]),
154
+ polygon([
155
+ [t, t],
156
+ [w - t, t],
157
+ [w - t, h - t],
158
+ [t, h - t]
159
+ ])
160
+ ];
161
+ }
162
+ case "plaque": {
163
+ const t = clamp(frac(adjust, "adj", 16667), 0, .5) * Math.min(w, h);
164
+ return [new PathBuilder().moveTo(t, 0).lineTo(w - t, 0).append(arcToBeziers(w, 0, t, t, Math.PI, -Math.PI / 2)).lineTo(w, h - t).append(arcToBeziers(w, h, t, t, 3 * Math.PI / 2, -Math.PI / 2)).lineTo(t, h).append(arcToBeziers(0, h, t, t, 0, -Math.PI / 2)).lineTo(0, t).append(arcToBeziers(0, 0, t, t, Math.PI / 2, -Math.PI / 2)).close().build()];
165
+ }
78
166
  case "hexagon": {
79
167
  const inset = clamp(frac(adjust, "adj", 25e3) * w, 0, w / 2);
80
168
  return [polygon([
@@ -227,6 +315,7 @@ function presetPaths(preset, w, h, adjust) {
227
315
  [0, h]
228
316
  ])];
229
317
  }
318
+ case "pieWedge": return [new PathBuilder().moveTo(0, 0).append(arcToBeziers(w, 0, w, h, Math.PI, -Math.PI / 2)).lineTo(w, 0).close().build()];
230
319
  case "pie":
231
320
  case "blockArc": {
232
321
  const [rx, ry] = [w / 2, h / 2];
@@ -306,10 +395,8 @@ function presetPaths(preset, w, h, adjust) {
306
395
  [w / 2, h]
307
396
  ])];
308
397
  case "flowChartDelay": return [new PathBuilder().moveTo(0, 0).lineTo(w / 2, 0).append(arcToBeziers(w / 2, h / 2, w / 2, h / 2, -Math.PI / 2, Math.PI)).lineTo(0, h).close().build()];
309
- case "flowChartMagneticDisk": {
310
- const ry = h / 6;
311
- return [new PathBuilder().moveTo(0, h - ry).append(arcToBeziers(w / 2, h - ry, w / 2, ry, Math.PI, -2 * Math.PI)).moveTo(0, h - ry).lineTo(0, ry).append(arcToBeziers(w / 2, ry, w / 2, ry, Math.PI, -Math.PI)).lineTo(w, h - ry).build()];
312
- }
398
+ case "flowChartMagneticDisk": return cylinder(w, h, h / 6);
399
+ case "flowChartMagneticDrum": return drum(w, h, w / 6);
313
400
  case "flowChartMagneticTape": {
314
401
  const foot = h / 8;
315
402
  return [{ segments: ellipseSegments(w, h) }, polygon([
@@ -626,14 +713,37 @@ function star(w, h, preset, adjust) {
626
713
  }
627
714
  return polygon(pts);
628
715
  }
629
- function regularPolygon(w, h, n) {
716
+ /**
717
+ * A cylinder standing on its base: the body under its lid, and the lid drawn
718
+ * again on top so its near edge shows.
719
+ *
720
+ * Both paths are wound the SAME way round. Wound against each other a nonzero
721
+ * fill cancels the two and the top comes out hollow, which is how the flowchart
722
+ * disk of tdf114848's fifth page had been drawn all along; and the base bulges
723
+ * DOWN, which the same shape had going up.
724
+ */
725
+ function cylinder(w, h, ry) {
726
+ const [rx, cx] = [w / 2, w / 2];
727
+ return [new PathBuilder().moveTo(0, ry).lineTo(0, h - ry).append(arcToBeziers(cx, h - ry, rx, ry, Math.PI, -Math.PI)).lineTo(w, ry).append(arcToBeziers(cx, ry, rx, ry, 0, -Math.PI)).close().build(), new PathBuilder().moveTo(w, h - ry).append(arcToBeziers(cx, h - ry, rx, ry, 0, -2 * Math.PI)).close().build()];
728
+ }
729
+ /**
730
+ * A cylinder lying on its side: the body with a rounded end at each side, and
731
+ * the near cap drawn again over the right one. Wound like {@link cylinder}, and
732
+ * for the same reason — the two paths must turn the same way or a nonzero fill
733
+ * cancels them.
734
+ */
735
+ function drum(w, h, rx) {
736
+ const [ry, cy] = [h / 2, h / 2];
737
+ return [new PathBuilder().moveTo(w - rx, h).lineTo(rx, h).append(arcToBeziers(rx, cy, rx, ry, Math.PI / 2, Math.PI)).lineTo(w - rx, 0).append(arcToBeziers(w - rx, cy, rx, ry, -Math.PI / 2, Math.PI)).close().build(), new PathBuilder().moveTo(w, cy).append(arcToBeziers(w - rx, cy, rx, ry, 0, 2 * Math.PI)).close().build()];
738
+ }
739
+ function regularPolygon(w, h, n, turn = 0) {
630
740
  const cx = w / 2;
631
741
  const cy = h / 2;
632
742
  const rx = w / 2;
633
743
  const ry = h / 2;
634
744
  const pts = [];
635
745
  for (let i = 0; i < n; i++) {
636
- const a = Math.PI / 2 + i * 2 * Math.PI / n;
746
+ const a = Math.PI / 2 + turn + i * 2 * Math.PI / n;
637
747
  pts.push([cx + rx * Math.cos(a), cy + ry * Math.sin(a)]);
638
748
  }
639
749
  return polygon(pts);
@@ -0,0 +1,58 @@
1
+ /** The two edges of a warp at one horizontal position, `0`…`1` down the box. */
2
+ export interface WarpEdges {
3
+ readonly top: number;
4
+ readonly bottom: number;
5
+ }
6
+ /**
7
+ * Whether a preset bends text at all. `textNoShape` is the "no warp" member of
8
+ * the enumeration and by far its most common value — two thirds of the decks
9
+ * that mention a warp state only this one — and a body carrying it is an
10
+ * ordinary text box, NOT WordArt stretched to its shape.
11
+ *
12
+ * @param preset The `a:prstTxWarp @prst` value.
13
+ * @returns Whether {@link textWarpEdges} can bend text through this preset.
14
+ */
15
+ export declare function isTextWarp(preset: string): boolean;
16
+ /**
17
+ * Where a warped body's two frames sit on the page: the shape's box, which the
18
+ * warped text is stretched onto, and the box the UN-warped block occupies.
19
+ * Both are in the page's top-left frame, y growing down.
20
+ */
21
+ export interface WarpFrame {
22
+ readonly preset: string;
23
+ readonly adjust?: number;
24
+ readonly boxX: number;
25
+ readonly boxY: number;
26
+ readonly boxWidth: number;
27
+ readonly boxHeight: number;
28
+ readonly srcX: number;
29
+ readonly srcWidth: number;
30
+ readonly srcTop: number;
31
+ readonly srcHeight: number;
32
+ }
33
+ /**
34
+ * The matrix that places one glyph of a warped body.
35
+ *
36
+ * Maps the glyph's own text space — x along its advance, y UP from its
37
+ * baseline — into the page's top-left frame, as `[a, b, c, d, e, f]` with
38
+ * `px = a·x + c·y + e` and `py = b·x + d·y + f`. Upright text therefore has a
39
+ * negative `d`: the glyph's y runs against the page's.
40
+ *
41
+ * @param frame The two frames, from the laid-out line.
42
+ * @param glyphX The glyph's left edge in the un-warped block.
43
+ * @param advance How wide the glyph is there.
44
+ * @param baselineY The line's baseline in the un-warped block.
45
+ * @returns The six numbers, or `undefined` where the warp leaves no room to
46
+ * draw — the pinched end of a fade, or a preset this file cannot bend.
47
+ */
48
+ export declare function warpGlyphMatrix(frame: WarpFrame, glyphX: number, advance: number, baselineY: number): readonly [number, number, number, number, number, number] | undefined;
49
+ /**
50
+ * The two edges of a warp at one position across its box.
51
+ *
52
+ * @param preset The `a:prstTxWarp @prst` value.
53
+ * @param u Position across the box, `0` at its left edge and `1` at its right.
54
+ * @param adj The `a:avLst` `adj` guide in hundred-thousandths, when the file states one.
55
+ * @returns The top and bottom edges, `0`…`1` down the box, or `undefined` for a
56
+ * preset this file does not bend (an unknown name, or `textNoShape`).
57
+ */
58
+ export declare function textWarpEdges(preset: string, u: number, adj?: number): WarpEdges | undefined;