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.
- package/dist/esm/core/bmp.d.ts +33 -0
- package/dist/esm/core/bmp.js +276 -0
- package/dist/esm/core/converter/ream.d.ts +16 -0
- package/dist/esm/core/converter/ream.js +59 -9
- package/dist/esm/core/document-model/types.d.ts +55 -0
- package/dist/esm/core/drawingml/chart-geometry.js +14 -7
- package/dist/esm/core/drawingml/colors.d.ts +4 -2
- package/dist/esm/core/drawingml/colors.js +15 -0
- package/dist/esm/core/drawingml/diagram/colors.d.ts +52 -0
- package/dist/esm/core/drawingml/diagram/colors.js +125 -0
- package/dist/esm/core/drawingml/diagram/data-model.d.ts +47 -0
- package/dist/esm/core/drawingml/diagram/data-model.js +119 -0
- package/dist/esm/core/drawingml/diagram/layout-engine.d.ts +46 -0
- package/dist/esm/core/drawingml/diagram/layout-engine.js +948 -0
- package/dist/esm/core/drawingml/diagram/run.d.ts +37 -0
- package/dist/esm/core/drawingml/diagram/run.js +50 -0
- package/dist/esm/core/drawingml/diagram/to-drawing.d.ts +16 -0
- package/dist/esm/core/drawingml/diagram/to-drawing.js +86 -0
- package/dist/esm/core/drawingml/preset-geometry.js +116 -6
- package/dist/esm/core/drawingml/text-warp.d.ts +58 -0
- package/dist/esm/core/drawingml/text-warp.js +355 -0
- package/dist/esm/core/drawingml/theme-parser.d.ts +38 -0
- package/dist/esm/core/drawingml/theme-parser.js +73 -4
- package/dist/esm/core/font/measure.d.ts +12 -0
- package/dist/esm/core/font/measure.js +36 -0
- package/dist/esm/core/fonts/families.d.ts +10 -0
- package/dist/esm/core/fonts/families.js +44 -0
- package/dist/esm/core/fonts/index.d.ts +3 -2
- package/dist/esm/core/fonts/remote-fonts.d.ts +50 -0
- package/dist/esm/core/fonts/remote-fonts.js +114 -8
- package/dist/esm/core/fonts/scripts.d.ts +26 -0
- package/dist/esm/core/fonts/scripts.js +177 -0
- package/dist/esm/core/images.d.ts +30 -2
- package/dist/esm/core/images.js +121 -5
- package/dist/esm/core/metafile/blit.d.ts +33 -0
- package/dist/esm/core/metafile/blit.js +67 -0
- package/dist/esm/core/metafile/dib.d.ts +61 -0
- package/dist/esm/core/metafile/dib.js +205 -0
- package/dist/esm/core/metafile/emf.js +280 -38
- package/dist/esm/core/metafile/picture.d.ts +61 -1
- package/dist/esm/core/metafile/picture.js +70 -1
- package/dist/esm/core/metafile/wmf.js +202 -13
- package/dist/esm/core/ole/escher-blip.d.ts +12 -0
- package/dist/esm/core/ole/escher-blip.js +98 -0
- package/dist/esm/{pdf-reader → core}/png-encode.js +1 -1
- package/dist/esm/excel/print-model.js +5 -3
- package/dist/esm/excel/sheet-drawing.js +1 -1
- package/dist/esm/excel/sheet-to-flow.js +16 -2
- package/dist/esm/excel/styles-parser.js +1 -1
- package/dist/esm/excel/xls/biff-reader.js +53 -18
- package/dist/esm/excel/xls/biff-styles.d.ts +5 -2
- package/dist/esm/excel/xls/biff-styles.js +9 -7
- package/dist/esm/excel/xls/escher.js +90 -24
- package/dist/esm/html/html-writer.js +2 -1
- package/dist/esm/layout/page-doc.d.ts +74 -0
- package/dist/esm/layout/page-doc.js +14 -1
- package/dist/esm/layout/styled-layout.d.ts +2 -2
- package/dist/esm/layout/styled-layout.js +475 -48
- package/dist/esm/pdf/shading.js +8 -6
- package/dist/esm/pdf/styled-page-emitter.js +77 -5
- package/dist/esm/pdf/vector-graphics.js +1 -1
- package/dist/esm/pdf-reader/image-decode.js +1 -1
- package/dist/esm/pptx/embedded-fonts.d.ts +31 -0
- package/dist/esm/pptx/embedded-fonts.js +104 -0
- package/dist/esm/pptx/placeholder-cascade.d.ts +73 -6
- package/dist/esm/pptx/placeholder-cascade.js +114 -18
- package/dist/esm/pptx/ppt/ppt-reader.js +191 -13
- package/dist/esm/pptx/ppt/ppt-text.d.ts +107 -1
- package/dist/esm/pptx/ppt/ppt-text.js +873 -144
- package/dist/esm/pptx/pptx-reader.d.ts +8 -0
- package/dist/esm/pptx/pptx-reader.js +117 -15
- package/dist/esm/pptx/preset-table-styles.d.ts +9 -0
- package/dist/esm/pptx/preset-table-styles.js +27 -0
- package/dist/esm/pptx/slide-parser.d.ts +11 -2
- package/dist/esm/pptx/slide-parser.js +203 -44
- package/dist/esm/pptx/sp-helpers.d.ts +9 -4
- package/dist/esm/pptx/sp-helpers.js +48 -9
- package/dist/esm/pptx/table-style.d.ts +16 -1
- package/dist/esm/pptx/table-style.js +104 -10
- package/dist/esm/svg/svg-writer.js +1 -0
- package/dist/esm/word/document-parser.d.ts +11 -2
- package/dist/esm/word/document-parser.js +10 -7
- package/dist/esm/word/docx-reader.js +32 -16
- package/dist/esm/word/docx-to-pdf.d.ts +8 -7
- package/dist/esm/word/docx-to-pdf.js +25 -7
- package/dist/esm/word/docx-writer.js +4 -0
- package/dist/esm/word/drawing-parser.d.ts +20 -0
- package/dist/esm/word/drawing-parser.js +67 -22
- package/dist/esm/word/numbering-parser.d.ts +2 -1
- package/dist/esm/word/numbering-parser.js +6 -6
- package/dist/esm/word/paragraph-properties.d.ts +2 -1
- package/dist/esm/word/paragraph-properties.js +2 -2
- package/dist/esm/word/run-properties.d.ts +5 -2
- package/dist/esm/word/run-properties.js +13 -8
- package/dist/esm/word/styles-parser.d.ts +2 -1
- package/dist/esm/word/styles-parser.js +12 -12
- package/dist/esm/word/table-parser.js +6 -3
- package/dist/esm/word/theme-fonts.d.ts +10 -0
- package/dist/esm/word/theme-fonts.js +28 -0
- package/package.json +1 -1
- /package/dist/esm/{pdf-reader → core}/png-encode.d.ts +0 -0
|
@@ -55,11 +55,13 @@ function categoryOf(type) {
|
|
|
55
55
|
* @param layoutTree The parsed `p:sldLayout` part.
|
|
56
56
|
* @param masterTree The parsed `p:sldMaster` part, when present.
|
|
57
57
|
* @param colors The deck's colour resolver, for scheme colours in the text styles.
|
|
58
|
+
* @param deckDefaults The presentation's own default text style, as the floor.
|
|
59
|
+
* @param themeFonts The theme's font scheme, for the `+mn-lt` tokens.
|
|
58
60
|
*/
|
|
59
|
-
function buildPlaceholderCascade(layoutTree, masterTree, colors, deckDefaults = []) {
|
|
60
|
-
const layoutPhs = collectPlaceholders(layoutTree, "p:sldLayout", colors);
|
|
61
|
-
const masterPhs = masterTree ? collectPlaceholders(masterTree, "p:sldMaster", colors) : [];
|
|
62
|
-
const txStyles = masterTree ? collectTxStyles(masterTree, colors) : {
|
|
61
|
+
function buildPlaceholderCascade(layoutTree, masterTree, colors, deckDefaults = [], themeFonts) {
|
|
62
|
+
const layoutPhs = collectPlaceholders(layoutTree, "p:sldLayout", colors, themeFonts);
|
|
63
|
+
const masterPhs = masterTree ? collectPlaceholders(masterTree, "p:sldMaster", colors, themeFonts) : [];
|
|
64
|
+
const txStyles = masterTree ? collectTxStyles(masterTree, colors, themeFonts) : {
|
|
63
65
|
title: [],
|
|
64
66
|
body: [],
|
|
65
67
|
other: []
|
|
@@ -67,7 +69,8 @@ function buildPlaceholderCascade(layoutTree, masterTree, colors, deckDefaults =
|
|
|
67
69
|
const styleAt = (ph, level) => {
|
|
68
70
|
const layers = [at(deckDefaults, level)];
|
|
69
71
|
if (ph) layers.push(at(txStyles[categoryOf(ph.type)], level), at(matchPlaceholder(masterPhs, ph)?.levels ?? [], level), at(matchPlaceholder(layoutPhs, ph)?.levels ?? [], level));
|
|
70
|
-
|
|
72
|
+
const merged = layers.reduce(mergeLevels, EMPTY_LEVEL);
|
|
73
|
+
return merged.spacingPct === void 0 ? merged : withResolvedSpacing(merged);
|
|
71
74
|
};
|
|
72
75
|
return {
|
|
73
76
|
geometryFor(ph) {
|
|
@@ -86,7 +89,7 @@ function buildPlaceholderCascade(layoutTree, masterTree, colors, deckDefaults =
|
|
|
86
89
|
return matchPlaceholder(layoutPhs, ph)?.anchor ?? matchPlaceholder(masterPhs, ph)?.anchor;
|
|
87
90
|
},
|
|
88
91
|
shapePropsFor(ph) {
|
|
89
|
-
return matchPlaceholder(layoutPhs, ph)?.spPr
|
|
92
|
+
return [matchPlaceholder(layoutPhs, ph)?.spPr, matchPlaceholder(masterPhs, ph)?.spPr].filter((n) => n !== void 0);
|
|
90
93
|
}
|
|
91
94
|
};
|
|
92
95
|
}
|
|
@@ -94,6 +97,39 @@ var EMPTY_LEVEL = {
|
|
|
94
97
|
run: {},
|
|
95
98
|
paragraph: {}
|
|
96
99
|
};
|
|
100
|
+
/**
|
|
101
|
+
* §21.1.2.2.9/.10 — the space a paragraph states as a FRACTION of a line, in
|
|
102
|
+
* points.
|
|
103
|
+
*
|
|
104
|
+
* A "line" here is the paragraph's own text at its natural height, which is the
|
|
105
|
+
* size times the same 1.2 the layout gives an unstated line. A level that
|
|
106
|
+
* states the fraction and leaves the size to another level is resolved once
|
|
107
|
+
* they have merged, which is why this is not read where the fraction is.
|
|
108
|
+
*
|
|
109
|
+
* @param pct The fraction, `0..n` (20% arrives as 0.2).
|
|
110
|
+
* @param sizePt The paragraph's resolved font size.
|
|
111
|
+
* @returns The distance, or `undefined` when the size is not known.
|
|
112
|
+
*/
|
|
113
|
+
function spacingFromLineFraction(pct, sizePt) {
|
|
114
|
+
if (pct === void 0 || sizePt === void 0) return void 0;
|
|
115
|
+
return pt(pct * sizePt * NATURAL_LINE);
|
|
116
|
+
}
|
|
117
|
+
/** What the layout gives a line of text with nothing said about its height. */
|
|
118
|
+
var NATURAL_LINE = 1.2;
|
|
119
|
+
function withResolvedSpacing(level) {
|
|
120
|
+
const size = level.run.fontSizePt;
|
|
121
|
+
const before = spacingFromLineFraction(level.spacingPct?.before, size);
|
|
122
|
+
const after = spacingFromLineFraction(level.spacingPct?.after, size);
|
|
123
|
+
if (before === void 0 && after === void 0) return level;
|
|
124
|
+
return {
|
|
125
|
+
...level,
|
|
126
|
+
paragraph: {
|
|
127
|
+
...level.paragraph,
|
|
128
|
+
...before !== void 0 ? { spacingBefore: before } : {},
|
|
129
|
+
...after !== void 0 ? { spacingAfter: after } : {}
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
}
|
|
97
133
|
/** The style at `level`, clamped to the list — a deeper level keeps the last. */
|
|
98
134
|
function at(levels, level) {
|
|
99
135
|
if (levels.length === 0) return EMPTY_LEVEL;
|
|
@@ -105,6 +141,10 @@ function mergeLevels(base, next) {
|
|
|
105
141
|
...base.bullet,
|
|
106
142
|
...next.bullet
|
|
107
143
|
} : void 0;
|
|
144
|
+
const spacingPct = base.spacingPct || next.spacingPct ? {
|
|
145
|
+
...base.spacingPct,
|
|
146
|
+
...next.spacingPct
|
|
147
|
+
} : void 0;
|
|
108
148
|
return {
|
|
109
149
|
run: {
|
|
110
150
|
...base.run,
|
|
@@ -114,7 +154,8 @@ function mergeLevels(base, next) {
|
|
|
114
154
|
...base.paragraph,
|
|
115
155
|
...next.paragraph
|
|
116
156
|
},
|
|
117
|
-
...bullet ? { bullet } : {}
|
|
157
|
+
...bullet ? { bullet } : {},
|
|
158
|
+
...spacingPct ? { spacingPct } : {}
|
|
118
159
|
};
|
|
119
160
|
}
|
|
120
161
|
/**
|
|
@@ -127,17 +168,19 @@ function mergeLevels(base, next) {
|
|
|
127
168
|
* @param prefix The level element prefix: `a:lvl` here, always.
|
|
128
169
|
* @returns The nine levels, or an empty list when there is no such node.
|
|
129
170
|
*/
|
|
130
|
-
function parseLevelStyles(list, colors) {
|
|
171
|
+
function parseLevelStyles(list, colors, themeFonts) {
|
|
131
172
|
if (!list) return [];
|
|
132
173
|
const out = [];
|
|
133
174
|
for (let lvl = 1; lvl <= 9; lvl++) {
|
|
134
175
|
const lvlPr = poChildren(list).find((c) => poIs(c, `a:lvl${String(lvl)}pPr`));
|
|
135
176
|
const defRPr = lvlPr ? poChildren(lvlPr).find((c) => poIs(c, "a:defRPr")) : void 0;
|
|
136
177
|
const bullet = parseBullet(lvlPr, colors);
|
|
178
|
+
const spacingPct = spacingFractions(lvlPr);
|
|
137
179
|
out.push({
|
|
138
|
-
run: rPrToRunProps(defRPr, colors),
|
|
180
|
+
run: rPrToRunProps(defRPr, colors, themeFonts),
|
|
139
181
|
paragraph: pPrToParagraphProps(lvlPr),
|
|
140
|
-
...bullet ? { bullet } : {}
|
|
182
|
+
...bullet ? { bullet } : {},
|
|
183
|
+
...spacingPct ? { spacingPct } : {}
|
|
141
184
|
});
|
|
142
185
|
}
|
|
143
186
|
return out;
|
|
@@ -151,8 +194,12 @@ var ALGN = {
|
|
|
151
194
|
};
|
|
152
195
|
/**
|
|
153
196
|
* A level's paragraph shape — §21.1.2.2.7 `@algn`, `@marL`/`@indent`, and the
|
|
154
|
-
* space around
|
|
155
|
-
*
|
|
197
|
+
* space around and between its lines.
|
|
198
|
+
*
|
|
199
|
+
* Both spacings come in two spellings: `a:spcPts` is a distance (hundredths of
|
|
200
|
+
* a point) and `a:spcPct` a FRACTION of a line (thousandths of a percent). Only
|
|
201
|
+
* the distance was read, so a deck that spaces its bullets the usual way — by
|
|
202
|
+
* fraction — set them solid.
|
|
156
203
|
*/
|
|
157
204
|
function pPrToParagraphProps(lvlPr) {
|
|
158
205
|
if (!lvlPr) return {};
|
|
@@ -164,7 +211,56 @@ function pPrToParagraphProps(lvlPr) {
|
|
|
164
211
|
...marL !== void 0 ? { indentLeft: emuToPt(marL) } : {},
|
|
165
212
|
...indent !== void 0 ? { indentFirstLine: emuToPt(indent) } : {},
|
|
166
213
|
...spacingPt(lvlPr, "a:spcBef", "spacingBefore"),
|
|
167
|
-
...spacingPt(lvlPr, "a:spcAft", "spacingAfter")
|
|
214
|
+
...spacingPt(lvlPr, "a:spcAft", "spacingAfter"),
|
|
215
|
+
...lineSpacing(lvlPr)
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* §21.1.2.2.5 `a:lnSpc` — the height of each line: a fraction of the natural
|
|
220
|
+
* one (`a:spcPct`) or a distance (`a:spcPts`).
|
|
221
|
+
*
|
|
222
|
+
* The model states a multiple the way §17.3.1.33 does — 12pt under the `auto`
|
|
223
|
+
* rule IS single — so a fraction needs no font size to express, which is why
|
|
224
|
+
* this resolves here and the paragraph SPACING has to wait for the size.
|
|
225
|
+
*
|
|
226
|
+
* @param pPr The paragraph properties (a level's or a paragraph's own).
|
|
227
|
+
* @returns The line spacing, or nothing when the node states none.
|
|
228
|
+
*/
|
|
229
|
+
function lineSpacing(pPr) {
|
|
230
|
+
const holder = pPr ? poChildren(pPr).find((c) => poIs(c, "a:lnSpc")) : void 0;
|
|
231
|
+
if (!holder) return {};
|
|
232
|
+
const pctVal = poIntAttr(poChildren(holder).find((c) => poIs(c, "a:spcPct")), "val");
|
|
233
|
+
if (pctVal !== void 0 && pctVal > 0) return {
|
|
234
|
+
spacingLine: pt(pctVal / 1e5 * 12),
|
|
235
|
+
spacingLineRule: "auto"
|
|
236
|
+
};
|
|
237
|
+
const ptsVal = poIntAttr(poChildren(holder).find((c) => poIs(c, "a:spcPts")), "val");
|
|
238
|
+
if (ptsVal !== void 0 && ptsVal > 0) return {
|
|
239
|
+
spacingLine: pt(ptsVal / 100),
|
|
240
|
+
spacingLineRule: "exact"
|
|
241
|
+
};
|
|
242
|
+
return {};
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* §21.1.2.2.9/.10 — the fraction of a line a paragraph puts before and after
|
|
246
|
+
* itself, when it states one. The distance form is read beside it; this is what
|
|
247
|
+
* the caller must still resolve against the size.
|
|
248
|
+
*
|
|
249
|
+
* @param pPr The paragraph properties.
|
|
250
|
+
* @returns The two fractions (`0..n`), each present only when stated.
|
|
251
|
+
*/
|
|
252
|
+
function spacingFractions(pPr) {
|
|
253
|
+
const frac = (tag) => {
|
|
254
|
+
const holder = pPr ? poChildren(pPr).find((c) => poIs(c, tag)) : void 0;
|
|
255
|
+
const pctNode = holder ? poChildren(holder).find((c) => poIs(c, "a:spcPct")) : void 0;
|
|
256
|
+
const val = pctNode ? poIntAttr(pctNode, "val") : void 0;
|
|
257
|
+
return val === void 0 || val < 0 ? void 0 : val / 1e5;
|
|
258
|
+
};
|
|
259
|
+
const [before, after] = [frac("a:spcBef"), frac("a:spcAft")];
|
|
260
|
+
if (before === void 0 && after === void 0) return void 0;
|
|
261
|
+
return {
|
|
262
|
+
...before !== void 0 ? { before } : {},
|
|
263
|
+
...after !== void 0 ? { after } : {}
|
|
168
264
|
};
|
|
169
265
|
}
|
|
170
266
|
function spacingPt(lvlPr, tag, key) {
|
|
@@ -173,7 +269,7 @@ function spacingPt(lvlPr, tag, key) {
|
|
|
173
269
|
const val = pts ? poIntAttr(pts, "val") : void 0;
|
|
174
270
|
return val === void 0 ? {} : { [key]: pt(val / 100) };
|
|
175
271
|
}
|
|
176
|
-
function collectPlaceholders(tree, root, colors) {
|
|
272
|
+
function collectPlaceholders(tree, root, colors, themeFonts) {
|
|
177
273
|
const sld = tree.find((n) => poIs(n, root));
|
|
178
274
|
const cSld = sld ? poChildren(sld).find((c) => poIs(c, "p:cSld")) : void 0;
|
|
179
275
|
const spTree = cSld ? poChildren(cSld).find((c) => poIs(c, "p:spTree")) : void 0;
|
|
@@ -194,7 +290,7 @@ function collectPlaceholders(tree, root, colors) {
|
|
|
194
290
|
ref,
|
|
195
291
|
...box ? { box } : {},
|
|
196
292
|
...spPr ? { spPr } : {},
|
|
197
|
-
levels: parseLevelStyles(lstStyle, colors),
|
|
293
|
+
levels: parseLevelStyles(lstStyle, colors, themeFonts),
|
|
198
294
|
...anchor ? { anchor } : {}
|
|
199
295
|
});
|
|
200
296
|
}
|
|
@@ -210,10 +306,10 @@ function matchPlaceholder(list, ph) {
|
|
|
210
306
|
const cat = categoryOf(ph.type);
|
|
211
307
|
return list.find((p) => categoryOf(p.ref.type) === cat);
|
|
212
308
|
}
|
|
213
|
-
function collectTxStyles(masterTree, colors) {
|
|
309
|
+
function collectTxStyles(masterTree, colors, themeFonts) {
|
|
214
310
|
const sld = masterTree.find((n) => poIs(n, "p:sldMaster"));
|
|
215
311
|
const txStyles = sld ? poChildren(sld).find((c) => poIs(c, "p:txStyles")) : void 0;
|
|
216
|
-
const family = (tag) => parseLevelStyles(txStyles ? poChildren(txStyles).find((c) => poIs(c, tag)) : void 0, colors);
|
|
312
|
+
const family = (tag) => parseLevelStyles(txStyles ? poChildren(txStyles).find((c) => poIs(c, tag)) : void 0, colors, themeFonts);
|
|
217
313
|
return {
|
|
218
314
|
title: family("p:titleStyle"),
|
|
219
315
|
body: family("p:bodyStyle"),
|
|
@@ -221,4 +317,4 @@ function collectTxStyles(masterTree, colors) {
|
|
|
221
317
|
};
|
|
222
318
|
}
|
|
223
319
|
//#endregion
|
|
224
|
-
export { buildPlaceholderCascade, parseBullet, parseLevelStyles };
|
|
320
|
+
export { buildPlaceholderCascade, lineSpacing, parseBullet, parseLevelStyles, spacingFractions, spacingFromLineFraction };
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { pt } from "../../core/ir/units.js";
|
|
2
2
|
import { ResourceStore } from "../../core/ir/resources.js";
|
|
3
3
|
import { FEATURES } from "../../core/ir/features.js";
|
|
4
|
+
import { knockOutColor } from "../../core/images.js";
|
|
5
|
+
import { isEmf } from "../../core/metafile/emf.js";
|
|
6
|
+
import { isWmf } from "../../core/metafile/wmf.js";
|
|
4
7
|
import { EMPTY_STYLE_SHEET, resolveBodyStyles } from "../../core/style-cascade/resolver.js";
|
|
5
8
|
import "../../core/style-cascade/index.js";
|
|
6
9
|
import { isCfb, openCfb } from "../../core/ole/cfb.js";
|
|
@@ -48,7 +51,7 @@ function readPpt(bytes) {
|
|
|
48
51
|
return {
|
|
49
52
|
doc: {
|
|
50
53
|
kind: "flow",
|
|
51
|
-
body: resolveBodyStyles(buildBody(content, resources), EMPTY_STYLE_SHEET),
|
|
54
|
+
body: resolveBodyStyles(buildBody(content, resources, width, height), EMPTY_STYLE_SHEET),
|
|
52
55
|
sections: [],
|
|
53
56
|
section: {
|
|
54
57
|
pageSize: {
|
|
@@ -70,19 +73,23 @@ function readPpt(bytes) {
|
|
|
70
73
|
losses: [content.encrypted ? PPT_ENCRYPTED_LOSS : PPT_TEXT_LOSS]
|
|
71
74
|
};
|
|
72
75
|
}
|
|
73
|
-
function buildBody(content, resources) {
|
|
76
|
+
function buildBody(content, resources, pageW, pageH) {
|
|
74
77
|
const body = [];
|
|
75
78
|
content.slides.forEach((slide, slideIndex) => {
|
|
76
79
|
const inFlowParas = [];
|
|
77
80
|
const inFlowImages = [];
|
|
78
81
|
const floats = [];
|
|
82
|
+
if (slide.background) {
|
|
83
|
+
const backdrop = slideBackdrop(slide.background, resources, pageW, pageH);
|
|
84
|
+
if (backdrop) floats.push(backdrop);
|
|
85
|
+
}
|
|
79
86
|
for (const shape of slide.shapes) if (shape.rectPt) {
|
|
80
|
-
if (shape.
|
|
87
|
+
if (shape.autoShape) floats.push(positionedAutoShape(shape.rectPt, shape.autoShape, resources));
|
|
81
88
|
if (shape.image) {
|
|
82
89
|
const block = positionedImage(shape.rectPt, shape.image, resources);
|
|
83
90
|
if (block) floats.push(block);
|
|
84
91
|
}
|
|
85
|
-
if (shape.
|
|
92
|
+
if (shape.paragraphs?.some((p) => paragraphText(p).length > 0)) floats.push(positionedTextShape(shape.rectPt, shape.paragraphs, shape.wordArt === true));
|
|
86
93
|
} else {
|
|
87
94
|
for (const para of shape.paragraphs ?? []) if (paragraphText(para).length > 0) inFlowParas.push(flowParagraph(para));
|
|
88
95
|
if (shape.image) {
|
|
@@ -122,10 +129,78 @@ function flowParagraph(para) {
|
|
|
122
129
|
kind: "paragraph",
|
|
123
130
|
paragraph: {
|
|
124
131
|
properties: toParaProperties(para, false),
|
|
125
|
-
runs: para
|
|
132
|
+
runs: bulletedRuns(para)
|
|
126
133
|
}
|
|
127
134
|
};
|
|
128
135
|
}
|
|
136
|
+
function bulletedRuns(para) {
|
|
137
|
+
const runs = para.runs.map(toRun);
|
|
138
|
+
if (para.bullet === void 0) return runs;
|
|
139
|
+
const { bold: _b, italic: _i, ...rest } = runs[0]?.properties ?? {};
|
|
140
|
+
const gap = hangs(para) ? " " : " ";
|
|
141
|
+
return [{
|
|
142
|
+
text: `${para.bullet}${gap}`,
|
|
143
|
+
properties: rest
|
|
144
|
+
}, ...runs];
|
|
145
|
+
}
|
|
146
|
+
function slideBackdrop(bg, resources, pageW, pageH) {
|
|
147
|
+
const fill = backdropFill(bg, resources);
|
|
148
|
+
if (!fill) return void 0;
|
|
149
|
+
return {
|
|
150
|
+
kind: "shape",
|
|
151
|
+
shape: {
|
|
152
|
+
float: {
|
|
153
|
+
wrap: "none",
|
|
154
|
+
behind: true,
|
|
155
|
+
posH: {
|
|
156
|
+
relativeFrom: "page",
|
|
157
|
+
offsetPt: pt(0)
|
|
158
|
+
},
|
|
159
|
+
posV: {
|
|
160
|
+
relativeFrom: "page",
|
|
161
|
+
offsetPt: pt(0)
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
width: pageW,
|
|
165
|
+
height: pageH,
|
|
166
|
+
geometry: {
|
|
167
|
+
kind: "preset",
|
|
168
|
+
preset: "rect",
|
|
169
|
+
adjust: /* @__PURE__ */ new Map()
|
|
170
|
+
},
|
|
171
|
+
fill,
|
|
172
|
+
paragraphProperties: {}
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
function backdropFill(bg, resources) {
|
|
177
|
+
if (bg.image) return {
|
|
178
|
+
kind: "picture",
|
|
179
|
+
imageResource: resources.put(bg.image.bytes),
|
|
180
|
+
...bg.imageTiled ? {
|
|
181
|
+
tiled: true,
|
|
182
|
+
tileFromCentre: true
|
|
183
|
+
} : {}
|
|
184
|
+
};
|
|
185
|
+
if (bg.gradient) {
|
|
186
|
+
const stops = gradientStops(bg.gradient);
|
|
187
|
+
return {
|
|
188
|
+
kind: "gradient",
|
|
189
|
+
gradient: bg.gradient.radial ? {
|
|
190
|
+
kind: "radial",
|
|
191
|
+
stops
|
|
192
|
+
} : {
|
|
193
|
+
kind: "linear",
|
|
194
|
+
angle: bg.gradient.angleDeg,
|
|
195
|
+
stops
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
return bg.fillColorHex ? {
|
|
200
|
+
kind: "solid",
|
|
201
|
+
colorHex: bg.fillColorHex
|
|
202
|
+
} : void 0;
|
|
203
|
+
}
|
|
129
204
|
function floatAt(rect) {
|
|
130
205
|
return {
|
|
131
206
|
wrap: "none",
|
|
@@ -139,7 +214,7 @@ function floatAt(rect) {
|
|
|
139
214
|
}
|
|
140
215
|
};
|
|
141
216
|
}
|
|
142
|
-
function positionedTextShape(rect, paragraphs) {
|
|
217
|
+
function positionedTextShape(rect, paragraphs, centred = false) {
|
|
143
218
|
return {
|
|
144
219
|
kind: "shape",
|
|
145
220
|
shape: {
|
|
@@ -154,21 +229,22 @@ function positionedTextShape(rect, paragraphs) {
|
|
|
154
229
|
fill: { kind: "none" },
|
|
155
230
|
text: {
|
|
156
231
|
content: paragraphs.filter((p) => paragraphText(p).length > 0).map(flowParagraph),
|
|
157
|
-
anchor: "t"
|
|
232
|
+
anchor: centred ? "ctr" : "t"
|
|
158
233
|
},
|
|
159
234
|
paragraphProperties: {}
|
|
160
235
|
}
|
|
161
236
|
};
|
|
162
237
|
}
|
|
163
238
|
function positionedImage(rect, image, resources) {
|
|
164
|
-
if (!imagePixelSize(image.bytes)) return void 0;
|
|
239
|
+
if (!isMetafile(image.bytes) && !imagePixelSize(image.bytes)) return void 0;
|
|
165
240
|
return {
|
|
166
241
|
kind: "image",
|
|
167
242
|
image: {
|
|
168
243
|
float: floatAt(rect),
|
|
169
|
-
resource: resources.put(image
|
|
244
|
+
resource: resources.put(drawnBytes(image)),
|
|
170
245
|
width: pt(rect.w),
|
|
171
246
|
height: pt(rect.h),
|
|
247
|
+
...image.crop ? { crop: image.crop } : {},
|
|
172
248
|
paragraphProperties: {}
|
|
173
249
|
}
|
|
174
250
|
};
|
|
@@ -214,9 +290,74 @@ function toCustomGeometry(g) {
|
|
|
214
290
|
commands
|
|
215
291
|
};
|
|
216
292
|
}
|
|
217
|
-
|
|
293
|
+
/**
|
|
294
|
+
* §2.3.7.6 `fillFocus` — the stops a shaded fill's two colours make.
|
|
295
|
+
*
|
|
296
|
+
* A focus of zero is the plain ramp everyone expects: the first colour at one
|
|
297
|
+
* end, the second at the other. Any other value means the sweep runs OUT from
|
|
298
|
+
* one of them — a focus of 50 puts the first colour halfway along with the
|
|
299
|
+
* second at BOTH ends, which is what 23884's every slide asks for and why its
|
|
300
|
+
* background read as a flat wash into violet where the reference is blue
|
|
301
|
+
* across the middle and dark only at the corners.
|
|
302
|
+
*
|
|
303
|
+
* @param g The gradient as the `.ppt` states it.
|
|
304
|
+
* @returns The stops, in order.
|
|
305
|
+
*/
|
|
306
|
+
function gradientStops(g) {
|
|
307
|
+
const focus = g.focusPct ?? 0;
|
|
308
|
+
if (focus === 0) return [{
|
|
309
|
+
offset: 0,
|
|
310
|
+
colorHex: g.fromHex
|
|
311
|
+
}, {
|
|
312
|
+
offset: 1,
|
|
313
|
+
colorHex: g.toHex
|
|
314
|
+
}];
|
|
315
|
+
if (Math.abs(focus) >= 100) return [{
|
|
316
|
+
offset: 0,
|
|
317
|
+
colorHex: g.toHex
|
|
318
|
+
}, {
|
|
319
|
+
offset: 1,
|
|
320
|
+
colorHex: g.fromHex
|
|
321
|
+
}];
|
|
322
|
+
const peak = focus > 0 ? g.fromHex : g.toHex;
|
|
323
|
+
const ends = focus > 0 ? g.toHex : g.fromHex;
|
|
324
|
+
const at = focus > 0 ? focus / 100 : 1 + focus / 100;
|
|
325
|
+
return [
|
|
326
|
+
{
|
|
327
|
+
offset: 0,
|
|
328
|
+
colorHex: ends
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
offset: at,
|
|
332
|
+
colorHex: peak
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
offset: 1,
|
|
336
|
+
colorHex: ends
|
|
337
|
+
}
|
|
338
|
+
];
|
|
339
|
+
}
|
|
340
|
+
function positionedAutoShape(rect, auto, resources) {
|
|
218
341
|
const line = isLineShape(auto.shapeType);
|
|
219
|
-
const fill = auto.
|
|
342
|
+
const fill = line ? { kind: "none" } : auto.image ? {
|
|
343
|
+
kind: "picture",
|
|
344
|
+
imageResource: resources.put(auto.image.bytes),
|
|
345
|
+
...auto.imageTiled ? {
|
|
346
|
+
tiled: true,
|
|
347
|
+
tileFromCentre: true
|
|
348
|
+
} : {},
|
|
349
|
+
...auto.tileSizePt ? { tileSizePt: auto.tileSizePt } : {}
|
|
350
|
+
} : auto.gradient ? {
|
|
351
|
+
kind: "gradient",
|
|
352
|
+
gradient: auto.gradient.radial ? {
|
|
353
|
+
kind: "radial",
|
|
354
|
+
stops: gradientStops(auto.gradient)
|
|
355
|
+
} : {
|
|
356
|
+
kind: "linear",
|
|
357
|
+
angle: auto.gradient.angleDeg,
|
|
358
|
+
stops: gradientStops(auto.gradient)
|
|
359
|
+
}
|
|
360
|
+
} : auto.fillColorHex ? {
|
|
220
361
|
kind: "solid",
|
|
221
362
|
colorHex: auto.fillColorHex
|
|
222
363
|
} : { kind: "none" };
|
|
@@ -250,13 +391,33 @@ function inFlowImage(image, resources) {
|
|
|
250
391
|
return {
|
|
251
392
|
kind: "image",
|
|
252
393
|
image: {
|
|
253
|
-
resource: resources.put(image
|
|
394
|
+
resource: resources.put(drawnBytes(image)),
|
|
254
395
|
width: pt(size.w * .75),
|
|
255
396
|
height: pt(size.h * .75),
|
|
397
|
+
...image.crop ? { crop: image.crop } : {},
|
|
256
398
|
paragraphProperties: {}
|
|
257
399
|
}
|
|
258
400
|
};
|
|
259
401
|
}
|
|
402
|
+
/**
|
|
403
|
+
* The bytes a picture is actually DRAWN from.
|
|
404
|
+
*
|
|
405
|
+
* §2.3.23 `pictureTransparent` names a colour the picture is drawn without, and
|
|
406
|
+
* a raster carries no alpha channel to say so — so the knock-out is baked into
|
|
407
|
+
* bytes of its own. The resource store hashes content, so two shapes knocking
|
|
408
|
+
* different colours out of the same blip stay two resources by themselves, and
|
|
409
|
+
* one that knocks out nothing keeps the bytes it arrived with.
|
|
410
|
+
*
|
|
411
|
+
* @param image The picture as the shape states it.
|
|
412
|
+
* @returns The bytes to store, knocked out where the shape asks for it.
|
|
413
|
+
*/
|
|
414
|
+
function drawnBytes(image) {
|
|
415
|
+
if (image.transparentHex === void 0 || isMetafile(image.bytes)) return image.bytes;
|
|
416
|
+
return knockOutColor(image.bytes, image.transparentHex) ?? image.bytes;
|
|
417
|
+
}
|
|
418
|
+
function isMetafile(d) {
|
|
419
|
+
return isEmf(d) || isWmf(d);
|
|
420
|
+
}
|
|
260
421
|
function imagePixelSize(d) {
|
|
261
422
|
if (d.length >= 24 && d[0] === 137 && d[1] === 80 && d[2] === 78 && d[3] === 71) {
|
|
262
423
|
const w = u32be(d, 16);
|
|
@@ -298,6 +459,10 @@ function toRun(r) {
|
|
|
298
459
|
...r.italic ? { italic: true } : {},
|
|
299
460
|
...underline ? { underline } : {},
|
|
300
461
|
...r.sizePt ? { fontSizePt: pt(r.sizePt) } : {},
|
|
462
|
+
...r.fontFamily ? { fontFamily: {
|
|
463
|
+
ascii: r.fontFamily,
|
|
464
|
+
hAnsi: r.fontFamily
|
|
465
|
+
} } : {},
|
|
301
466
|
...r.colorHex ? { colorHex: r.colorHex } : {}
|
|
302
467
|
};
|
|
303
468
|
return {
|
|
@@ -308,12 +473,25 @@ function toRun(r) {
|
|
|
308
473
|
function toParaProperties(p, breakBefore) {
|
|
309
474
|
const alignment = p.align !== void 0 ? alignmentFrom(p.align) : void 0;
|
|
310
475
|
const level = p.level ?? 0;
|
|
476
|
+
const leftPt = p.leftMarginPt ?? (level > 0 ? level * LEVEL_INDENT_PT : void 0);
|
|
477
|
+
const firstPt = p.indentPt !== void 0 ? p.indentPt - (leftPt ?? 0) : void 0;
|
|
311
478
|
return {
|
|
312
479
|
...breakBefore ? { pageBreakBefore: true } : {},
|
|
313
480
|
...alignment ? { alignment } : {},
|
|
314
|
-
...
|
|
481
|
+
...leftPt !== void 0 ? { indentLeft: pt(leftPt) } : {},
|
|
482
|
+
...firstPt !== void 0 && firstPt !== 0 ? { indentFirstLine: pt(firstPt) } : {},
|
|
483
|
+
...p.spaceBeforePt !== void 0 ? { spacingBefore: pt(p.spaceBeforePt) } : {},
|
|
484
|
+
...p.spaceAfterPt !== void 0 ? { spacingAfter: pt(p.spaceAfterPt) } : {},
|
|
485
|
+
...p.lineSpacing !== void 0 && p.lineSpacing > 0 ? {
|
|
486
|
+
spacingLineRule: "auto",
|
|
487
|
+
spacingLine: pt(p.lineSpacing / 100 * 12)
|
|
488
|
+
} : {}
|
|
315
489
|
};
|
|
316
490
|
}
|
|
491
|
+
/** Whether the paragraph's first line starts LEFT of its body — a hanging bullet. */
|
|
492
|
+
function hangs(p) {
|
|
493
|
+
return p.indentPt !== void 0 && p.leftMarginPt !== void 0 && p.indentPt < p.leftMarginPt;
|
|
494
|
+
}
|
|
317
495
|
function alignmentFrom(a) {
|
|
318
496
|
switch (a) {
|
|
319
497
|
case 1: return "center";
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/** A run of uniformly-formatted text within a paragraph (PPT-2). */
|
|
2
2
|
export interface PptRun {
|
|
3
3
|
readonly text: string;
|
|
4
|
+
/** The typeface the run names, resolved through the deck's font collection. */
|
|
5
|
+
readonly fontFamily?: string;
|
|
4
6
|
readonly bold?: boolean;
|
|
5
7
|
readonly italic?: boolean;
|
|
6
8
|
readonly underline?: boolean;
|
|
@@ -20,6 +22,24 @@ export interface PptParagraph {
|
|
|
20
22
|
readonly align?: number;
|
|
21
23
|
/** The 0-based outline/indent level. */
|
|
22
24
|
readonly level?: number;
|
|
25
|
+
/**
|
|
26
|
+
* §2.9.20 — the bullet character this paragraph is marked with, already
|
|
27
|
+
* translated out of whatever symbol font stated it. Absent when the paragraph
|
|
28
|
+
* carries none.
|
|
29
|
+
*/
|
|
30
|
+
readonly bullet?: string;
|
|
31
|
+
/**
|
|
32
|
+
* §2.9.20 `leftMargin` — where the paragraph's BODY sits, in points from the
|
|
33
|
+
* text box's own left edge.
|
|
34
|
+
*/
|
|
35
|
+
readonly leftMarginPt?: number;
|
|
36
|
+
/** §2.9.20 `indent` — where its FIRST line starts. Left of the body ⇒ hanging. */
|
|
37
|
+
readonly indentPt?: number;
|
|
38
|
+
/** §2.9.32 `lineSpacing`, as a PERCENTAGE of the line's height — 100 is single. */
|
|
39
|
+
readonly lineSpacing?: number;
|
|
40
|
+
/** §2.9.32 `spaceBefore` / `spaceAfter`, in points. */
|
|
41
|
+
readonly spaceBeforePt?: number;
|
|
42
|
+
readonly spaceAfterPt?: number;
|
|
23
43
|
}
|
|
24
44
|
/**
|
|
25
45
|
* An embedded picture referenced by a slide shape — the raw image bytes pulled
|
|
@@ -27,6 +47,22 @@ export interface PptParagraph {
|
|
|
27
47
|
*/
|
|
28
48
|
export interface PptImage {
|
|
29
49
|
readonly bytes: Uint8Array;
|
|
50
|
+
/**
|
|
51
|
+
* §2.3.23 `cropFrom*` — the fraction of each edge of the SOURCE cut away
|
|
52
|
+
* before it is fitted to the shape's box. Absent ⇒ the whole picture.
|
|
53
|
+
*/
|
|
54
|
+
readonly crop?: {
|
|
55
|
+
readonly left: number;
|
|
56
|
+
readonly top: number;
|
|
57
|
+
readonly right: number;
|
|
58
|
+
readonly bottom: number;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* §2.3.23 `pictureTransparent` — the colour the picture is drawn WITHOUT,
|
|
62
|
+
* 6-hex and no leading `#`. Clip art of this age states its ground here
|
|
63
|
+
* rather than carrying an alpha channel.
|
|
64
|
+
*/
|
|
65
|
+
readonly transparentHex?: string;
|
|
30
66
|
}
|
|
31
67
|
/** A shape's rectangle on the slide, in points (from the OfficeArtClientAnchor). */
|
|
32
68
|
export interface PptRect {
|
|
@@ -80,6 +116,41 @@ export interface PptAutoShape {
|
|
|
80
116
|
readonly fillColorHex?: string;
|
|
81
117
|
/** The resolved line colour as 6-hex RGB, when present. */
|
|
82
118
|
readonly lineColorHex?: string;
|
|
119
|
+
/**
|
|
120
|
+
* MS-ODRAW §2.3.7.1 — the two-colour sweep a `fillType` of 4..8 asks for.
|
|
121
|
+
* `fillColor` is one end and `fillBackColor` the other; `fillAngle` is where
|
|
122
|
+
* it runs. Read as its fillColor alone, 41246-2's title slide came out a flat
|
|
123
|
+
* teal where every reader fades it to white.
|
|
124
|
+
*/
|
|
125
|
+
readonly gradient?: {
|
|
126
|
+
readonly fromHex: string;
|
|
127
|
+
readonly toHex: string;
|
|
128
|
+
readonly angleDeg: number;
|
|
129
|
+
readonly radial: boolean;
|
|
130
|
+
/**
|
|
131
|
+
* §2.3.7.6 `fillFocus` — where along the sweep the FIRST colour peaks, as a
|
|
132
|
+
* percentage. Zero is a plain ramp; 50 puts it in the middle with the
|
|
133
|
+
* second colour at both ends, which is a different picture entirely.
|
|
134
|
+
*/
|
|
135
|
+
readonly focusPct?: number;
|
|
136
|
+
};
|
|
137
|
+
/**
|
|
138
|
+
* §2.3.7.1 MSOFILLTYPE 3 — a picture stretched over the shape, its blip named
|
|
139
|
+
* by `fillBlip`. A `.ppt` table is a group of cell rectangles, and a cell with
|
|
140
|
+
* a picture background states it exactly this way.
|
|
141
|
+
*/
|
|
142
|
+
readonly image?: PptImage;
|
|
143
|
+
/** §2.3.7.1 MSOFILLTYPE 2 — the picture REPEATS at its own size, not stretched. */
|
|
144
|
+
readonly imageTiled?: boolean;
|
|
145
|
+
/**
|
|
146
|
+
* §2.3.7.11/.12 `fillWidth` / `fillHeight` — the size one copy occupies, in
|
|
147
|
+
* points, when the shape states it rather than leaving the tile at the
|
|
148
|
+
* picture's own size.
|
|
149
|
+
*/
|
|
150
|
+
readonly tileSizePt?: {
|
|
151
|
+
readonly widthPt: number;
|
|
152
|
+
readonly heightPt: number;
|
|
153
|
+
};
|
|
83
154
|
readonly geometry?: PptCustomGeometry;
|
|
84
155
|
}
|
|
85
156
|
/**
|
|
@@ -89,13 +160,48 @@ export interface PptAutoShape {
|
|
|
89
160
|
*/
|
|
90
161
|
export interface PptShape {
|
|
91
162
|
readonly rectPt?: PptRect;
|
|
163
|
+
/**
|
|
164
|
+
* §2.3.22 — the shape IS a piece of WordArt: its text is the shape, centred
|
|
165
|
+
* in its box rather than flowed from the top. Drawn as an autoshape it was a
|
|
166
|
+
* coloured rectangle where the reference has a word.
|
|
167
|
+
*/
|
|
168
|
+
readonly wordArt?: boolean;
|
|
169
|
+
/**
|
|
170
|
+
* Whether the shape is a placeholder (§2.9.24). On a MASTER that means it is
|
|
171
|
+
* a prototype, not decoration: drawn on the slides that follow it, every one
|
|
172
|
+
* of them would carry "Click to edit Master title style".
|
|
173
|
+
*/
|
|
174
|
+
readonly placeholder?: boolean;
|
|
175
|
+
/**
|
|
176
|
+
* §2.9.51 `OEPlaceholderAtom.placeholderId` — WHICH placeholder it is. The
|
|
177
|
+
* three a master keeps for the slide's furniture — 7 the date, 8 the slide
|
|
178
|
+
* number, 9 the footer — are the only ones whose text does not live in the
|
|
179
|
+
* shape at all (§2.4.15).
|
|
180
|
+
*/
|
|
181
|
+
readonly placeholderId?: number;
|
|
92
182
|
readonly paragraphs?: ReadonlyArray<PptParagraph>;
|
|
93
183
|
readonly image?: PptImage;
|
|
94
184
|
readonly autoShape?: PptAutoShape;
|
|
95
185
|
}
|
|
96
|
-
/**
|
|
186
|
+
/**
|
|
187
|
+
* A slide's background (PPT-12) — the fill on the shape MS-ODRAW marks with
|
|
188
|
+
* `fBackground`. A `.ppt` states it as a shape like any other; drawn as one it
|
|
189
|
+
* would be a rectangle among the content, and dropped it leaves a black slide
|
|
190
|
+
* white.
|
|
191
|
+
*/
|
|
192
|
+
export interface PptBackground {
|
|
193
|
+
/** A solid fill's colour, as 6-hex RGB. */
|
|
194
|
+
readonly fillColorHex?: string;
|
|
195
|
+
/** A shaded fill, in the same terms an autoshape's is (PPT-9). */
|
|
196
|
+
readonly gradient?: PptAutoShape['gradient'];
|
|
197
|
+
/** A picture fill, stretched over the slide (or tiled across it). */
|
|
198
|
+
readonly image?: PptImage;
|
|
199
|
+
readonly imageTiled?: boolean;
|
|
200
|
+
}
|
|
201
|
+
/** One slide: its shapes in document order, over its background. */
|
|
97
202
|
export interface PptSlide {
|
|
98
203
|
readonly shapes: ReadonlyArray<PptShape>;
|
|
204
|
+
readonly background?: PptBackground;
|
|
99
205
|
}
|
|
100
206
|
/** The extracted content of a `.ppt`: its slides, deck page size and encryption flag. */
|
|
101
207
|
export interface PptContent {
|