ppt-codec 1.5.0 → 1.6.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/README.md +70 -58
- package/dist/base64.cjs +48 -0
- package/dist/base64.d.cts +5 -0
- package/dist/base64.d.ts +5 -0
- package/dist/base64.js +46 -0
- package/dist/diagnostics-CqxAnubw.d.cts +16 -0
- package/dist/diagnostics-CqxAnubw.d.ts +16 -0
- package/dist/diagnostics.cjs +11 -0
- package/dist/diagnostics.d.cts +2 -0
- package/dist/diagnostics.d.ts +2 -0
- package/dist/diagnostics.js +9 -0
- package/dist/document/color-scheme.cjs +4 -0
- package/dist/document/color-scheme.d.cts +2 -1
- package/dist/document/color-scheme.d.ts +2 -1
- package/dist/document/color-scheme.js +4 -1
- package/dist/document/master-write.cjs +20 -15
- package/dist/document/master-write.d.cts +2 -1
- package/dist/document/master-write.d.ts +2 -1
- package/dist/document/master-write.js +21 -16
- package/dist/document/notes-write.cjs +14 -6
- package/dist/document/notes-write.d.cts +2 -1
- package/dist/document/notes-write.d.ts +2 -1
- package/dist/document/notes-write.js +14 -6
- package/dist/document/notes.cjs +4 -3
- package/dist/document/notes.js +4 -3
- package/dist/drawing/blips.cjs +81 -0
- package/dist/drawing/blips.d.cts +16 -0
- package/dist/drawing/blips.d.ts +16 -0
- package/dist/drawing/blips.js +77 -0
- package/dist/drawing/properties.cjs +94 -0
- package/dist/drawing/properties.d.cts +25 -0
- package/dist/drawing/properties.d.ts +25 -0
- package/dist/drawing/properties.js +83 -0
- package/dist/drawing/shapes-write.cjs +204 -17
- package/dist/drawing/shapes-write.d.cts +15 -4
- package/dist/drawing/shapes-write.d.ts +15 -4
- package/dist/drawing/shapes-write.js +206 -18
- package/dist/drawing/shapes.cjs +34 -4
- package/dist/drawing/shapes.d.cts +11 -2
- package/dist/drawing/shapes.d.ts +11 -2
- package/dist/drawing/shapes.js +35 -5
- package/dist/index.cjs +38 -1
- package/dist/index.d.cts +10 -6
- package/dist/index.d.ts +10 -6
- package/dist/index.js +8 -4
- package/dist/read.cjs +101 -19
- package/dist/read.d.cts +3 -2
- package/dist/read.d.ts +3 -2
- package/dist/read.js +103 -22
- package/dist/record/types.cjs +28 -0
- package/dist/record/types.d.cts +15 -1
- package/dist/record/types.d.ts +15 -1
- package/dist/record/types.js +15 -1
- package/dist/write.cjs +100 -37
- package/dist/write.d.cts +9 -4
- package/dist/write.d.ts +9 -4
- package/dist/write.js +100 -37
- package/package.json +2 -1
|
@@ -3,9 +3,13 @@ const require_record_types = require("../record/types.cjs");
|
|
|
3
3
|
const require_text_atoms = require("../text/atoms.cjs");
|
|
4
4
|
const require_units = require("../units.cjs");
|
|
5
5
|
const require_content_write = require("../content-write.cjs");
|
|
6
|
+
const require_diagnostics = require("../diagnostics.cjs");
|
|
6
7
|
const require_record_write = require("../record/write.cjs");
|
|
8
|
+
const require_drawing_blips = require("./blips.cjs");
|
|
9
|
+
const require_drawing_properties = require("./properties.cjs");
|
|
7
10
|
const require_text_style_write = require("../text/style-write.cjs");
|
|
8
11
|
//#region src/drawing/shapes-write.ts
|
|
12
|
+
const FSP_CHILD = 2;
|
|
9
13
|
const PATRIARCH_SPID = 1;
|
|
10
14
|
const FIRST_CONTENT_SPID = 2;
|
|
11
15
|
function writeFsp(spid, flags) {
|
|
@@ -21,9 +25,22 @@ function writeClientAnchor(xPt, yPt, widthPt, heightPt) {
|
|
|
21
25
|
function writeTextCharsAtom(text) {
|
|
22
26
|
return require_record_write.writeAtom(require_record_types.RT_TextCharsAtom, require_record_write.utf16le(text));
|
|
23
27
|
}
|
|
24
|
-
function
|
|
25
|
-
|
|
26
|
-
|
|
28
|
+
function writeShapeProperties(shape, pib) {
|
|
29
|
+
const entries = [];
|
|
30
|
+
if (shape.rotationDeg !== void 0) entries.push({
|
|
31
|
+
opid: 4,
|
|
32
|
+
op: require_drawing_properties.degreesToFixedPoint(shape.rotationDeg)
|
|
33
|
+
});
|
|
34
|
+
if (pib !== void 0) entries.push({
|
|
35
|
+
opid: 260,
|
|
36
|
+
op: pib,
|
|
37
|
+
fBid: true
|
|
38
|
+
});
|
|
39
|
+
return entries.length === 0 ? void 0 : require_drawing_properties.writeShapePropertyTable(require_record_types.OfficeArtFOPT, entries);
|
|
40
|
+
}
|
|
41
|
+
function writeClientTextbox(textBlocks, fontIndexOf) {
|
|
42
|
+
if (textBlocks.length === 0) return;
|
|
43
|
+
const { text, style } = require_content_write.buildTextBody(textBlocks, fontIndexOf);
|
|
27
44
|
const totalParagraphCount = style.paragraphRuns.reduce((sum, run) => sum + run.count, 0);
|
|
28
45
|
if (totalParagraphCount !== require_text_atoms.characterCountOf(text)) throw new Error(`internal error: built ${totalParagraphCount} characters of paragraph runs for a ${require_text_atoms.characterCountOf(text)}-character text body`);
|
|
29
46
|
return require_record_write.writeContainer(require_record_types.OfficeArtClientTextbox, [
|
|
@@ -32,9 +49,12 @@ function writeClientTextbox(shape, fontIndexOf) {
|
|
|
32
49
|
require_text_style_write.writeStyleTextPropAtom(style)
|
|
33
50
|
]);
|
|
34
51
|
}
|
|
35
|
-
function writeShape(spid, shape, fontIndexOf, clientData) {
|
|
36
|
-
const
|
|
37
|
-
const
|
|
52
|
+
function writeShape(spid, shape, pib, textBlocks, fontIndexOf, clientData) {
|
|
53
|
+
const properties = writeShapeProperties(shape, pib);
|
|
54
|
+
const clientTextbox = writeClientTextbox(textBlocks, fontIndexOf);
|
|
55
|
+
const children = [writeFsp(spid, 0)];
|
|
56
|
+
if (properties !== void 0) children.push(properties);
|
|
57
|
+
children.push(writeClientAnchor(shape.frame.xPt, shape.frame.yPt, shape.frame.widthPt, shape.frame.heightPt));
|
|
38
58
|
if (clientData !== void 0) children.push(clientData);
|
|
39
59
|
if (clientTextbox !== void 0) children.push(clientTextbox);
|
|
40
60
|
return require_record_write.writeContainer(require_record_types.OfficeArtSpContainer, children);
|
|
@@ -42,19 +62,186 @@ function writeShape(spid, shape, fontIndexOf, clientData) {
|
|
|
42
62
|
function writePatriarch() {
|
|
43
63
|
return require_record_write.writeContainer(require_record_types.OfficeArtSpContainer, [require_record_write.writeAtom(require_record_types.OfficeArtFSPGR, /* @__PURE__ */ new Uint8Array(16), { recVer: 1 }), writeFsp(PATRIARCH_SPID, 5)]);
|
|
44
64
|
}
|
|
45
|
-
function
|
|
46
|
-
const
|
|
47
|
-
|
|
65
|
+
function planShapeBlocks(blocks, context) {
|
|
66
|
+
const textBlocks = [];
|
|
67
|
+
let pib;
|
|
68
|
+
let table;
|
|
69
|
+
const drop = (block, reason) => {
|
|
70
|
+
context.sink({
|
|
71
|
+
code: require_diagnostics.PptDiagnosticCodes.BLOCK_DROPPED,
|
|
72
|
+
severity: "warning",
|
|
73
|
+
message: `${context.location}: ${reason}`
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
for (const block of blocks) {
|
|
77
|
+
if (block.kind === "paragraph") {
|
|
78
|
+
textBlocks.push(block);
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (block.kind === "image") {
|
|
82
|
+
if (!require_drawing_blips.isBlipFormat(block.format)) {
|
|
83
|
+
context.sink({
|
|
84
|
+
code: require_diagnostics.PptDiagnosticCodes.IMAGE_DROPPED,
|
|
85
|
+
severity: "warning",
|
|
86
|
+
message: `${context.location}: an image block in format '${block.format}' is dropped; MSOBLIPTYPE gives this writer a blip record for PNG and JPEG only`
|
|
87
|
+
});
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (pib !== void 0) {
|
|
91
|
+
context.sink({
|
|
92
|
+
code: require_diagnostics.PptDiagnosticCodes.IMAGE_DROPPED,
|
|
93
|
+
severity: "warning",
|
|
94
|
+
message: `${context.location}: a second image block is dropped; a shape carries exactly one blip-store reference, and an earlier image already consumed it`
|
|
95
|
+
});
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
pib = context.blipIndexOf(block);
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if (block.kind === "table") {
|
|
102
|
+
if (table !== void 0) {
|
|
103
|
+
drop(block, "a second 'table' block is dropped; a shape becomes one table group, and an earlier table already did");
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
table = block;
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
drop(block, `a '${block.kind}' block is dropped; this writer produces no [MS-PPT] spelling for it`);
|
|
110
|
+
}
|
|
111
|
+
if (table !== void 0) {
|
|
112
|
+
for (const block of textBlocks) drop(block, "a 'paragraph' block is dropped; a shape carrying a table becomes a table group, which holds its text in cells rather than a text body of its own");
|
|
113
|
+
if (pib !== void 0) context.sink({
|
|
114
|
+
code: require_diagnostics.PptDiagnosticCodes.IMAGE_DROPPED,
|
|
115
|
+
severity: "warning",
|
|
116
|
+
message: `${context.location}: an image block is dropped; a shape carrying a table becomes a table group, which has no blip reference of its own`
|
|
117
|
+
});
|
|
118
|
+
return {
|
|
119
|
+
pib: void 0,
|
|
120
|
+
textBlocks: [],
|
|
121
|
+
table
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
pib,
|
|
126
|
+
textBlocks,
|
|
127
|
+
table
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function tableRowHeights(table, frameHeightMasterUnits) {
|
|
131
|
+
const stated = table.rows.map((row) => row.heightPt === void 0 ? void 0 : require_units.pointsToMasterUnits(row.heightPt));
|
|
132
|
+
const unstatedCount = stated.filter((height) => height === void 0).length;
|
|
133
|
+
if (unstatedCount === 0) return stated.map((height) => {
|
|
134
|
+
if (height === void 0) throw new Error("internal error: a stated row height became unstated in the same pass");
|
|
135
|
+
return height;
|
|
136
|
+
});
|
|
137
|
+
const remaining = frameHeightMasterUnits - stated.reduce((sum, height) => sum + (height ?? 0), 0);
|
|
138
|
+
const shared = Math.max(1, Math.round(remaining / unstatedCount));
|
|
139
|
+
return stated.map((height) => height ?? shared);
|
|
140
|
+
}
|
|
141
|
+
function writeTableGroup(spid, shape, table, context) {
|
|
142
|
+
const { frame } = shape;
|
|
143
|
+
const rowHeights = tableRowHeights(table, require_units.pointsToMasterUnits(frame.heightPt));
|
|
144
|
+
const declaredWidths = table.columnWidthsPt.map(require_units.pointsToMasterUnits);
|
|
145
|
+
const cellCount = Math.max(1, ...table.rows.map((row) => row.cells.length), declaredWidths.length);
|
|
146
|
+
const lastDeclared = declaredWidths.at(-1);
|
|
147
|
+
const equalShare = Math.max(1, Math.round(require_units.pointsToMasterUnits(frame.widthPt) / cellCount));
|
|
148
|
+
const columnWidthsMasterUnits = Array.from({ length: cellCount }, (_, index) => declaredWidths[index] ?? lastDeclared ?? equalShare);
|
|
149
|
+
const columnBoundaries = [];
|
|
150
|
+
let columnEdge = require_units.pointsToMasterUnits(frame.xPt);
|
|
151
|
+
for (const width of columnWidthsMasterUnits) {
|
|
152
|
+
columnBoundaries.push(columnEdge);
|
|
153
|
+
columnEdge += width;
|
|
154
|
+
}
|
|
155
|
+
columnBoundaries.push(columnEdge);
|
|
156
|
+
const rowBoundaries = [];
|
|
157
|
+
let rowEdge = require_units.pointsToMasterUnits(frame.yPt);
|
|
158
|
+
for (const height of rowHeights) {
|
|
159
|
+
rowBoundaries.push(rowEdge);
|
|
160
|
+
rowEdge += height;
|
|
161
|
+
}
|
|
162
|
+
rowBoundaries.push(rowEdge);
|
|
163
|
+
const rowHeightsPayload = require_drawing_properties.writeIMsoArray(rowHeights, 4);
|
|
164
|
+
const tableLeft = require_units.pointsToMasterUnits(frame.xPt);
|
|
165
|
+
const tableTop = require_units.pointsToMasterUnits(frame.yPt);
|
|
166
|
+
const tableRight = require_units.pointsToMasterUnits(frame.xPt + frame.widthPt);
|
|
167
|
+
const tableBottom = require_units.pointsToMasterUnits(frame.yPt + frame.heightPt);
|
|
168
|
+
const groupShape = require_record_write.writeContainer(require_record_types.OfficeArtSpContainer, [
|
|
169
|
+
require_record_write.writeAtom(require_record_types.OfficeArtFSPGR, require_record_write.concatBytes(require_record_write.i32le(tableLeft), require_record_write.i32le(tableTop), require_record_write.i32le(tableRight), require_record_write.i32le(tableBottom)), { recVer: 1 }),
|
|
170
|
+
writeFsp(spid, 513),
|
|
171
|
+
...shape.rotationDeg === void 0 ? [] : [require_drawing_properties.writeShapePropertyTable(require_record_types.OfficeArtFOPT, [{
|
|
172
|
+
opid: 4,
|
|
173
|
+
op: require_drawing_properties.degreesToFixedPoint(shape.rotationDeg)
|
|
174
|
+
}])],
|
|
175
|
+
require_drawing_properties.writeShapePropertyTable(require_record_types.OfficeArtTertiaryFOPT, [{
|
|
176
|
+
opid: 927,
|
|
177
|
+
op: 1
|
|
178
|
+
}, {
|
|
179
|
+
opid: 928,
|
|
180
|
+
op: rowHeightsPayload.length,
|
|
181
|
+
fBid: true,
|
|
182
|
+
complex: rowHeightsPayload
|
|
183
|
+
}]),
|
|
184
|
+
writeClientAnchor(frame.xPt, frame.yPt, frame.widthPt, frame.heightPt)
|
|
185
|
+
]);
|
|
186
|
+
let cellSpid = spid + 1;
|
|
187
|
+
const cellShapes = table.rows.flatMap((row, rowIndex) => row.cells.map((cell, columnIndex) => {
|
|
188
|
+
const cellLeft = columnBoundaries[columnIndex];
|
|
189
|
+
const cellRight = columnBoundaries[columnIndex + 1];
|
|
190
|
+
const cellTop = rowBoundaries[rowIndex];
|
|
191
|
+
const cellBottom = rowBoundaries[rowIndex + 1];
|
|
192
|
+
if (cellLeft === void 0 || cellRight === void 0 || cellTop === void 0 || cellBottom === void 0) throw new Error("internal error: a table cell sits outside the grid boundaries derived from its own table");
|
|
193
|
+
if (cell.colSpan !== void 0 && cell.colSpan > 1) context.sink({
|
|
194
|
+
code: require_diagnostics.PptDiagnosticCodes.TABLE_SPAN_DROPPED,
|
|
195
|
+
severity: "warning",
|
|
196
|
+
message: `${context.location}: a table cell's colSpan ${String(cell.colSpan)} is dropped; a PowerPoint 97-2003 table is a strict grid of shapes with no merge records, so the cell is written one column wide`
|
|
197
|
+
});
|
|
198
|
+
if (cell.rowSpan !== void 0 && cell.rowSpan > 1) context.sink({
|
|
199
|
+
code: require_diagnostics.PptDiagnosticCodes.TABLE_SPAN_DROPPED,
|
|
200
|
+
severity: "warning",
|
|
201
|
+
message: `${context.location}: a table cell's rowSpan ${String(cell.rowSpan)} is dropped; a PowerPoint 97-2003 table is a strict grid of shapes with no merge records, so the cell is written one row tall`
|
|
202
|
+
});
|
|
203
|
+
const paragraphs = cell.blocks.filter((block) => block.kind === "paragraph");
|
|
204
|
+
for (const block of cell.blocks) if (block.kind !== "paragraph") context.sink({
|
|
205
|
+
code: require_diagnostics.PptDiagnosticCodes.BLOCK_DROPPED,
|
|
206
|
+
severity: "warning",
|
|
207
|
+
message: `${context.location}: a '${block.kind}' block inside a table cell is dropped; a table cell in this format is a plain text-box shape with no property table or object reference of its own`
|
|
208
|
+
});
|
|
209
|
+
const textbox = writeClientTextbox(paragraphs, context.fontIndexOf);
|
|
210
|
+
const children = [writeFsp(cellSpid, FSP_CHILD), require_record_write.writeAtom(require_record_types.OfficeArtChildAnchor, require_record_write.concatBytes(require_record_write.i32le(cellLeft), require_record_write.i32le(cellTop), require_record_write.i32le(cellRight), require_record_write.i32le(cellBottom)))];
|
|
211
|
+
cellSpid += 1;
|
|
212
|
+
if (textbox !== void 0) children.push(textbox);
|
|
213
|
+
return require_record_write.writeContainer(require_record_types.OfficeArtSpContainer, children);
|
|
214
|
+
}));
|
|
215
|
+
return {
|
|
216
|
+
bytes: require_record_write.writeContainer(require_record_types.OfficeArtSpgrContainer, [groupShape, ...cellShapes]),
|
|
217
|
+
shapeCount: 1 + table.rows.reduce((sum, row) => sum + row.cells.length, 0)
|
|
218
|
+
};
|
|
48
219
|
}
|
|
49
|
-
function
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
220
|
+
function writeDrawing(shapes, context) {
|
|
221
|
+
let nextSpid = FIRST_CONTENT_SPID;
|
|
222
|
+
let shapeCount = 1;
|
|
223
|
+
const shapeContainers = [];
|
|
224
|
+
for (const entry of shapes) {
|
|
225
|
+
const plan = planShapeBlocks(entry.shape.blocks, context);
|
|
226
|
+
if (plan.table !== void 0) {
|
|
227
|
+
const group = writeTableGroup(nextSpid, entry.shape, plan.table, context);
|
|
228
|
+
nextSpid += group.shapeCount;
|
|
229
|
+
shapeCount += group.shapeCount;
|
|
230
|
+
shapeContainers.push(group.bytes);
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
shapeContainers.push(writeShape(nextSpid, entry.shape, plan.pib, plan.textBlocks, context.fontIndexOf, entry.clientData));
|
|
234
|
+
nextSpid += 1;
|
|
235
|
+
shapeCount += 1;
|
|
236
|
+
}
|
|
237
|
+
return {
|
|
238
|
+
bytes: require_record_write.writeContainer(require_record_types.RT_Drawing, [require_record_write.writeContainer(require_record_types.OfficeArtDgContainer, [require_record_write.writeContainer(require_record_types.OfficeArtSpgrContainer, [writePatriarch(), ...shapeContainers])])]),
|
|
239
|
+
shapeCount,
|
|
240
|
+
maxSpid: Math.max(PATRIARCH_SPID, nextSpid - 1)
|
|
241
|
+
};
|
|
54
242
|
}
|
|
55
|
-
function
|
|
56
|
-
return writeDrawing(shapes,
|
|
243
|
+
function writeSlideDrawing(shapes, context) {
|
|
244
|
+
return writeDrawing(shapes, context);
|
|
57
245
|
}
|
|
58
246
|
//#endregion
|
|
59
|
-
exports.writeDrawingWithClientData = writeDrawingWithClientData;
|
|
60
247
|
exports.writeSlideDrawing = writeSlideDrawing;
|
|
@@ -1,10 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as PptDiagnosticSink } from "../diagnostics-CqxAnubw.cjs";
|
|
2
|
+
import { ContentImageBlock, ContentShape } from "document-schema.js";
|
|
2
3
|
//#region src/drawing/shapes-write.d.ts
|
|
3
4
|
interface DrawingShape {
|
|
4
5
|
readonly shape: ContentShape;
|
|
5
6
|
readonly clientData: Uint8Array<ArrayBuffer> | undefined;
|
|
6
7
|
}
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
interface DrawingWritten {
|
|
9
|
+
readonly bytes: Uint8Array<ArrayBuffer>;
|
|
10
|
+
readonly shapeCount: number;
|
|
11
|
+
readonly maxSpid: number;
|
|
12
|
+
}
|
|
13
|
+
interface DrawingWriteContext {
|
|
14
|
+
readonly fontIndexOf: (family: string) => number;
|
|
15
|
+
readonly blipIndexOf: (image: ContentImageBlock) => number;
|
|
16
|
+
readonly sink: PptDiagnosticSink;
|
|
17
|
+
readonly location: string;
|
|
18
|
+
}
|
|
19
|
+
declare function writeSlideDrawing(shapes: readonly DrawingShape[], context: DrawingWriteContext): DrawingWritten;
|
|
9
20
|
//#endregion
|
|
10
|
-
export { DrawingShape,
|
|
21
|
+
export { DrawingShape, DrawingWriteContext, DrawingWritten, writeSlideDrawing };
|
|
@@ -1,10 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as PptDiagnosticSink } from "../diagnostics-CqxAnubw.js";
|
|
2
|
+
import { ContentImageBlock, ContentShape } from "document-schema.js";
|
|
2
3
|
//#region src/drawing/shapes-write.d.ts
|
|
3
4
|
interface DrawingShape {
|
|
4
5
|
readonly shape: ContentShape;
|
|
5
6
|
readonly clientData: Uint8Array<ArrayBuffer> | undefined;
|
|
6
7
|
}
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
interface DrawingWritten {
|
|
9
|
+
readonly bytes: Uint8Array<ArrayBuffer>;
|
|
10
|
+
readonly shapeCount: number;
|
|
11
|
+
readonly maxSpid: number;
|
|
12
|
+
}
|
|
13
|
+
interface DrawingWriteContext {
|
|
14
|
+
readonly fontIndexOf: (family: string) => number;
|
|
15
|
+
readonly blipIndexOf: (image: ContentImageBlock) => number;
|
|
16
|
+
readonly sink: PptDiagnosticSink;
|
|
17
|
+
readonly location: string;
|
|
18
|
+
}
|
|
19
|
+
declare function writeSlideDrawing(shapes: readonly DrawingShape[], context: DrawingWriteContext): DrawingWritten;
|
|
9
20
|
//#endregion
|
|
10
|
-
export { DrawingShape,
|
|
21
|
+
export { DrawingShape, DrawingWriteContext, DrawingWritten, writeSlideDrawing };
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import { OfficeArtClientAnchor, OfficeArtClientTextbox, OfficeArtDgContainer, OfficeArtFSP, OfficeArtFSPGR, OfficeArtSpContainer, OfficeArtSpgrContainer, RT_Drawing, RT_TextCharsAtom, RT_TextHeaderAtom } from "../record/types.js";
|
|
1
|
+
import { OfficeArtChildAnchor, OfficeArtClientAnchor, OfficeArtClientTextbox, OfficeArtDgContainer, OfficeArtFOPT, OfficeArtFSP, OfficeArtFSPGR, OfficeArtSpContainer, OfficeArtSpgrContainer, OfficeArtTertiaryFOPT, RT_Drawing, RT_TextCharsAtom, RT_TextHeaderAtom } from "../record/types.js";
|
|
2
2
|
import { characterCountOf } from "../text/atoms.js";
|
|
3
3
|
import { pointsToMasterUnits } from "../units.js";
|
|
4
4
|
import { buildTextBody } from "../content-write.js";
|
|
5
|
+
import { PptDiagnosticCodes } from "../diagnostics.js";
|
|
5
6
|
import { concatBytes, i32le, u32le, utf16le, writeAtom, writeContainer } from "../record/write.js";
|
|
7
|
+
import { isBlipFormat } from "./blips.js";
|
|
8
|
+
import { degreesToFixedPoint, writeIMsoArray, writeShapePropertyTable } from "./properties.js";
|
|
6
9
|
import { writeStyleTextPropAtom } from "../text/style-write.js";
|
|
7
10
|
//#region src/drawing/shapes-write.ts
|
|
11
|
+
const FSP_CHILD = 2;
|
|
8
12
|
const PATRIARCH_SPID = 1;
|
|
9
13
|
const FIRST_CONTENT_SPID = 2;
|
|
10
14
|
function writeFsp(spid, flags) {
|
|
@@ -20,9 +24,22 @@ function writeClientAnchor(xPt, yPt, widthPt, heightPt) {
|
|
|
20
24
|
function writeTextCharsAtom(text) {
|
|
21
25
|
return writeAtom(RT_TextCharsAtom, utf16le(text));
|
|
22
26
|
}
|
|
23
|
-
function
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
function writeShapeProperties(shape, pib) {
|
|
28
|
+
const entries = [];
|
|
29
|
+
if (shape.rotationDeg !== void 0) entries.push({
|
|
30
|
+
opid: 4,
|
|
31
|
+
op: degreesToFixedPoint(shape.rotationDeg)
|
|
32
|
+
});
|
|
33
|
+
if (pib !== void 0) entries.push({
|
|
34
|
+
opid: 260,
|
|
35
|
+
op: pib,
|
|
36
|
+
fBid: true
|
|
37
|
+
});
|
|
38
|
+
return entries.length === 0 ? void 0 : writeShapePropertyTable(OfficeArtFOPT, entries);
|
|
39
|
+
}
|
|
40
|
+
function writeClientTextbox(textBlocks, fontIndexOf) {
|
|
41
|
+
if (textBlocks.length === 0) return;
|
|
42
|
+
const { text, style } = buildTextBody(textBlocks, fontIndexOf);
|
|
26
43
|
const totalParagraphCount = style.paragraphRuns.reduce((sum, run) => sum + run.count, 0);
|
|
27
44
|
if (totalParagraphCount !== characterCountOf(text)) throw new Error(`internal error: built ${totalParagraphCount} characters of paragraph runs for a ${characterCountOf(text)}-character text body`);
|
|
28
45
|
return writeContainer(OfficeArtClientTextbox, [
|
|
@@ -31,9 +48,12 @@ function writeClientTextbox(shape, fontIndexOf) {
|
|
|
31
48
|
writeStyleTextPropAtom(style)
|
|
32
49
|
]);
|
|
33
50
|
}
|
|
34
|
-
function writeShape(spid, shape, fontIndexOf, clientData) {
|
|
35
|
-
const
|
|
36
|
-
const
|
|
51
|
+
function writeShape(spid, shape, pib, textBlocks, fontIndexOf, clientData) {
|
|
52
|
+
const properties = writeShapeProperties(shape, pib);
|
|
53
|
+
const clientTextbox = writeClientTextbox(textBlocks, fontIndexOf);
|
|
54
|
+
const children = [writeFsp(spid, 0)];
|
|
55
|
+
if (properties !== void 0) children.push(properties);
|
|
56
|
+
children.push(writeClientAnchor(shape.frame.xPt, shape.frame.yPt, shape.frame.widthPt, shape.frame.heightPt));
|
|
37
57
|
if (clientData !== void 0) children.push(clientData);
|
|
38
58
|
if (clientTextbox !== void 0) children.push(clientTextbox);
|
|
39
59
|
return writeContainer(OfficeArtSpContainer, children);
|
|
@@ -41,18 +61,186 @@ function writeShape(spid, shape, fontIndexOf, clientData) {
|
|
|
41
61
|
function writePatriarch() {
|
|
42
62
|
return writeContainer(OfficeArtSpContainer, [writeAtom(OfficeArtFSPGR, /* @__PURE__ */ new Uint8Array(16), { recVer: 1 }), writeFsp(PATRIARCH_SPID, 5)]);
|
|
43
63
|
}
|
|
44
|
-
function
|
|
45
|
-
const
|
|
46
|
-
|
|
64
|
+
function planShapeBlocks(blocks, context) {
|
|
65
|
+
const textBlocks = [];
|
|
66
|
+
let pib;
|
|
67
|
+
let table;
|
|
68
|
+
const drop = (block, reason) => {
|
|
69
|
+
context.sink({
|
|
70
|
+
code: PptDiagnosticCodes.BLOCK_DROPPED,
|
|
71
|
+
severity: "warning",
|
|
72
|
+
message: `${context.location}: ${reason}`
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
for (const block of blocks) {
|
|
76
|
+
if (block.kind === "paragraph") {
|
|
77
|
+
textBlocks.push(block);
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (block.kind === "image") {
|
|
81
|
+
if (!isBlipFormat(block.format)) {
|
|
82
|
+
context.sink({
|
|
83
|
+
code: PptDiagnosticCodes.IMAGE_DROPPED,
|
|
84
|
+
severity: "warning",
|
|
85
|
+
message: `${context.location}: an image block in format '${block.format}' is dropped; MSOBLIPTYPE gives this writer a blip record for PNG and JPEG only`
|
|
86
|
+
});
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (pib !== void 0) {
|
|
90
|
+
context.sink({
|
|
91
|
+
code: PptDiagnosticCodes.IMAGE_DROPPED,
|
|
92
|
+
severity: "warning",
|
|
93
|
+
message: `${context.location}: a second image block is dropped; a shape carries exactly one blip-store reference, and an earlier image already consumed it`
|
|
94
|
+
});
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
pib = context.blipIndexOf(block);
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (block.kind === "table") {
|
|
101
|
+
if (table !== void 0) {
|
|
102
|
+
drop(block, "a second 'table' block is dropped; a shape becomes one table group, and an earlier table already did");
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
table = block;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
drop(block, `a '${block.kind}' block is dropped; this writer produces no [MS-PPT] spelling for it`);
|
|
109
|
+
}
|
|
110
|
+
if (table !== void 0) {
|
|
111
|
+
for (const block of textBlocks) drop(block, "a 'paragraph' block is dropped; a shape carrying a table becomes a table group, which holds its text in cells rather than a text body of its own");
|
|
112
|
+
if (pib !== void 0) context.sink({
|
|
113
|
+
code: PptDiagnosticCodes.IMAGE_DROPPED,
|
|
114
|
+
severity: "warning",
|
|
115
|
+
message: `${context.location}: an image block is dropped; a shape carrying a table becomes a table group, which has no blip reference of its own`
|
|
116
|
+
});
|
|
117
|
+
return {
|
|
118
|
+
pib: void 0,
|
|
119
|
+
textBlocks: [],
|
|
120
|
+
table
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
pib,
|
|
125
|
+
textBlocks,
|
|
126
|
+
table
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function tableRowHeights(table, frameHeightMasterUnits) {
|
|
130
|
+
const stated = table.rows.map((row) => row.heightPt === void 0 ? void 0 : pointsToMasterUnits(row.heightPt));
|
|
131
|
+
const unstatedCount = stated.filter((height) => height === void 0).length;
|
|
132
|
+
if (unstatedCount === 0) return stated.map((height) => {
|
|
133
|
+
if (height === void 0) throw new Error("internal error: a stated row height became unstated in the same pass");
|
|
134
|
+
return height;
|
|
135
|
+
});
|
|
136
|
+
const remaining = frameHeightMasterUnits - stated.reduce((sum, height) => sum + (height ?? 0), 0);
|
|
137
|
+
const shared = Math.max(1, Math.round(remaining / unstatedCount));
|
|
138
|
+
return stated.map((height) => height ?? shared);
|
|
139
|
+
}
|
|
140
|
+
function writeTableGroup(spid, shape, table, context) {
|
|
141
|
+
const { frame } = shape;
|
|
142
|
+
const rowHeights = tableRowHeights(table, pointsToMasterUnits(frame.heightPt));
|
|
143
|
+
const declaredWidths = table.columnWidthsPt.map(pointsToMasterUnits);
|
|
144
|
+
const cellCount = Math.max(1, ...table.rows.map((row) => row.cells.length), declaredWidths.length);
|
|
145
|
+
const lastDeclared = declaredWidths.at(-1);
|
|
146
|
+
const equalShare = Math.max(1, Math.round(pointsToMasterUnits(frame.widthPt) / cellCount));
|
|
147
|
+
const columnWidthsMasterUnits = Array.from({ length: cellCount }, (_, index) => declaredWidths[index] ?? lastDeclared ?? equalShare);
|
|
148
|
+
const columnBoundaries = [];
|
|
149
|
+
let columnEdge = pointsToMasterUnits(frame.xPt);
|
|
150
|
+
for (const width of columnWidthsMasterUnits) {
|
|
151
|
+
columnBoundaries.push(columnEdge);
|
|
152
|
+
columnEdge += width;
|
|
153
|
+
}
|
|
154
|
+
columnBoundaries.push(columnEdge);
|
|
155
|
+
const rowBoundaries = [];
|
|
156
|
+
let rowEdge = pointsToMasterUnits(frame.yPt);
|
|
157
|
+
for (const height of rowHeights) {
|
|
158
|
+
rowBoundaries.push(rowEdge);
|
|
159
|
+
rowEdge += height;
|
|
160
|
+
}
|
|
161
|
+
rowBoundaries.push(rowEdge);
|
|
162
|
+
const rowHeightsPayload = writeIMsoArray(rowHeights, 4);
|
|
163
|
+
const tableLeft = pointsToMasterUnits(frame.xPt);
|
|
164
|
+
const tableTop = pointsToMasterUnits(frame.yPt);
|
|
165
|
+
const tableRight = pointsToMasterUnits(frame.xPt + frame.widthPt);
|
|
166
|
+
const tableBottom = pointsToMasterUnits(frame.yPt + frame.heightPt);
|
|
167
|
+
const groupShape = writeContainer(OfficeArtSpContainer, [
|
|
168
|
+
writeAtom(OfficeArtFSPGR, concatBytes(i32le(tableLeft), i32le(tableTop), i32le(tableRight), i32le(tableBottom)), { recVer: 1 }),
|
|
169
|
+
writeFsp(spid, 513),
|
|
170
|
+
...shape.rotationDeg === void 0 ? [] : [writeShapePropertyTable(OfficeArtFOPT, [{
|
|
171
|
+
opid: 4,
|
|
172
|
+
op: degreesToFixedPoint(shape.rotationDeg)
|
|
173
|
+
}])],
|
|
174
|
+
writeShapePropertyTable(OfficeArtTertiaryFOPT, [{
|
|
175
|
+
opid: 927,
|
|
176
|
+
op: 1
|
|
177
|
+
}, {
|
|
178
|
+
opid: 928,
|
|
179
|
+
op: rowHeightsPayload.length,
|
|
180
|
+
fBid: true,
|
|
181
|
+
complex: rowHeightsPayload
|
|
182
|
+
}]),
|
|
183
|
+
writeClientAnchor(frame.xPt, frame.yPt, frame.widthPt, frame.heightPt)
|
|
184
|
+
]);
|
|
185
|
+
let cellSpid = spid + 1;
|
|
186
|
+
const cellShapes = table.rows.flatMap((row, rowIndex) => row.cells.map((cell, columnIndex) => {
|
|
187
|
+
const cellLeft = columnBoundaries[columnIndex];
|
|
188
|
+
const cellRight = columnBoundaries[columnIndex + 1];
|
|
189
|
+
const cellTop = rowBoundaries[rowIndex];
|
|
190
|
+
const cellBottom = rowBoundaries[rowIndex + 1];
|
|
191
|
+
if (cellLeft === void 0 || cellRight === void 0 || cellTop === void 0 || cellBottom === void 0) throw new Error("internal error: a table cell sits outside the grid boundaries derived from its own table");
|
|
192
|
+
if (cell.colSpan !== void 0 && cell.colSpan > 1) context.sink({
|
|
193
|
+
code: PptDiagnosticCodes.TABLE_SPAN_DROPPED,
|
|
194
|
+
severity: "warning",
|
|
195
|
+
message: `${context.location}: a table cell's colSpan ${String(cell.colSpan)} is dropped; a PowerPoint 97-2003 table is a strict grid of shapes with no merge records, so the cell is written one column wide`
|
|
196
|
+
});
|
|
197
|
+
if (cell.rowSpan !== void 0 && cell.rowSpan > 1) context.sink({
|
|
198
|
+
code: PptDiagnosticCodes.TABLE_SPAN_DROPPED,
|
|
199
|
+
severity: "warning",
|
|
200
|
+
message: `${context.location}: a table cell's rowSpan ${String(cell.rowSpan)} is dropped; a PowerPoint 97-2003 table is a strict grid of shapes with no merge records, so the cell is written one row tall`
|
|
201
|
+
});
|
|
202
|
+
const paragraphs = cell.blocks.filter((block) => block.kind === "paragraph");
|
|
203
|
+
for (const block of cell.blocks) if (block.kind !== "paragraph") context.sink({
|
|
204
|
+
code: PptDiagnosticCodes.BLOCK_DROPPED,
|
|
205
|
+
severity: "warning",
|
|
206
|
+
message: `${context.location}: a '${block.kind}' block inside a table cell is dropped; a table cell in this format is a plain text-box shape with no property table or object reference of its own`
|
|
207
|
+
});
|
|
208
|
+
const textbox = writeClientTextbox(paragraphs, context.fontIndexOf);
|
|
209
|
+
const children = [writeFsp(cellSpid, FSP_CHILD), writeAtom(OfficeArtChildAnchor, concatBytes(i32le(cellLeft), i32le(cellTop), i32le(cellRight), i32le(cellBottom)))];
|
|
210
|
+
cellSpid += 1;
|
|
211
|
+
if (textbox !== void 0) children.push(textbox);
|
|
212
|
+
return writeContainer(OfficeArtSpContainer, children);
|
|
213
|
+
}));
|
|
214
|
+
return {
|
|
215
|
+
bytes: writeContainer(OfficeArtSpgrContainer, [groupShape, ...cellShapes]),
|
|
216
|
+
shapeCount: 1 + table.rows.reduce((sum, row) => sum + row.cells.length, 0)
|
|
217
|
+
};
|
|
47
218
|
}
|
|
48
|
-
function
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
219
|
+
function writeDrawing(shapes, context) {
|
|
220
|
+
let nextSpid = FIRST_CONTENT_SPID;
|
|
221
|
+
let shapeCount = 1;
|
|
222
|
+
const shapeContainers = [];
|
|
223
|
+
for (const entry of shapes) {
|
|
224
|
+
const plan = planShapeBlocks(entry.shape.blocks, context);
|
|
225
|
+
if (plan.table !== void 0) {
|
|
226
|
+
const group = writeTableGroup(nextSpid, entry.shape, plan.table, context);
|
|
227
|
+
nextSpid += group.shapeCount;
|
|
228
|
+
shapeCount += group.shapeCount;
|
|
229
|
+
shapeContainers.push(group.bytes);
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
shapeContainers.push(writeShape(nextSpid, entry.shape, plan.pib, plan.textBlocks, context.fontIndexOf, entry.clientData));
|
|
233
|
+
nextSpid += 1;
|
|
234
|
+
shapeCount += 1;
|
|
235
|
+
}
|
|
236
|
+
return {
|
|
237
|
+
bytes: writeContainer(RT_Drawing, [writeContainer(OfficeArtDgContainer, [writeContainer(OfficeArtSpgrContainer, [writePatriarch(), ...shapeContainers])])]),
|
|
238
|
+
shapeCount,
|
|
239
|
+
maxSpid: Math.max(PATRIARCH_SPID, nextSpid - 1)
|
|
240
|
+
};
|
|
53
241
|
}
|
|
54
|
-
function
|
|
55
|
-
return writeDrawing(shapes,
|
|
242
|
+
function writeSlideDrawing(shapes, context) {
|
|
243
|
+
return writeDrawing(shapes, context);
|
|
56
244
|
}
|
|
57
245
|
//#endregion
|
|
58
|
-
export {
|
|
246
|
+
export { writeSlideDrawing };
|
package/dist/drawing/shapes.cjs
CHANGED
|
@@ -2,6 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
|
2
2
|
const require_errors = require("../errors.cjs");
|
|
3
3
|
const require_record_tree = require("../record/tree.cjs");
|
|
4
4
|
const require_record_types = require("../record/types.cjs");
|
|
5
|
+
const require_drawing_properties = require("./properties.cjs");
|
|
5
6
|
//#region src/drawing/shapes.ts
|
|
6
7
|
const FSP_GROUP = 1;
|
|
7
8
|
const FSP_PATRIARCH = 4;
|
|
@@ -44,7 +45,7 @@ function readClientAnchor(record) {
|
|
|
44
45
|
if (recLen === 16) return readRectFields(record, 4, "top-left");
|
|
45
46
|
throw new require_errors.PptFormatError(`OfficeArtClientAnchor declares recLen 0x${recLen.toString(16)}, neither the 0x8 of a SmallRectStruct nor the 0x10 of a RectStruct`);
|
|
46
47
|
}
|
|
47
|
-
function
|
|
48
|
+
function readShapeIdentity(shape) {
|
|
48
49
|
const fsp = require_record_tree.findChild(require_record_tree.childRecords(shape), require_record_types.OfficeArtFSP);
|
|
49
50
|
if (fsp === void 0 || fsp.data.length < 8) throw new require_errors.PptFormatError(`OfficeArtSpContainer at offset ${shape.offset} has no readable OfficeArtFSP, so the shape has neither an identity nor its flags`);
|
|
50
51
|
const view = new DataView(fsp.data.buffer, fsp.data.byteOffset, 8);
|
|
@@ -60,8 +61,18 @@ function resolveAnchor(shape, transform) {
|
|
|
60
61
|
const child = require_record_tree.findChild(children, require_record_types.OfficeArtChildAnchor);
|
|
61
62
|
if (child !== void 0) return applyTransform(transform, readRectFields(child, 4, "left-top"));
|
|
62
63
|
}
|
|
64
|
+
function rotationDegOf(properties) {
|
|
65
|
+
const rotation = properties.get(4);
|
|
66
|
+
if (rotation === void 0) return;
|
|
67
|
+
const degrees = require_drawing_properties.fixedPointToDegrees(rotation.value);
|
|
68
|
+
return degrees === 0 ? void 0 : degrees;
|
|
69
|
+
}
|
|
70
|
+
function isTableGroup(properties) {
|
|
71
|
+
const tableProperties = properties.get(927);
|
|
72
|
+
return tableProperties !== void 0 && (tableProperties.value & 1) !== 0;
|
|
73
|
+
}
|
|
63
74
|
function groupTransform(groupShape, parent) {
|
|
64
|
-
const { spid, flags } =
|
|
75
|
+
const { spid, flags } = readShapeIdentity(groupShape);
|
|
65
76
|
if ((flags & FSP_PATRIARCH) !== 0) return parent;
|
|
66
77
|
const children = require_record_tree.childRecords(groupShape);
|
|
67
78
|
const fspgr = require_record_tree.findChild(children, require_record_types.OfficeArtFSPGR);
|
|
@@ -81,17 +92,36 @@ function groupTransform(groupShape, parent) {
|
|
|
81
92
|
};
|
|
82
93
|
}
|
|
83
94
|
function collectShape(shape, transform, into) {
|
|
84
|
-
const { spid, flags } =
|
|
95
|
+
const { spid, flags } = readShapeIdentity(shape);
|
|
85
96
|
if ((flags & FSP_DELETED) !== 0 || (flags & FSP_GROUP) !== 0) return;
|
|
97
|
+
const children = require_record_tree.childRecords(shape);
|
|
98
|
+
const properties = require_drawing_properties.readShapeProperties(shape);
|
|
86
99
|
into.push({
|
|
87
100
|
spid,
|
|
88
101
|
anchor: resolveAnchor(shape, transform),
|
|
89
|
-
|
|
102
|
+
rotationDeg: rotationDegOf(properties),
|
|
103
|
+
clientTextbox: require_record_tree.findChild(children, require_record_types.OfficeArtClientTextbox),
|
|
104
|
+
clientData: require_record_tree.findChild(children, require_record_types.OfficeArtClientData),
|
|
105
|
+
properties
|
|
90
106
|
});
|
|
91
107
|
}
|
|
92
108
|
function collectGroup(group, parent, into) {
|
|
93
109
|
const [groupShape, ...rest] = require_record_tree.childRecords(group);
|
|
94
110
|
if (groupShape === void 0) return;
|
|
111
|
+
const groupProperties = require_drawing_properties.readShapeProperties(groupShape);
|
|
112
|
+
if (isTableGroup(groupProperties)) {
|
|
113
|
+
const anchor = resolveAnchor(groupShape, parent);
|
|
114
|
+
if (anchor === void 0) throw new require_errors.PptFormatError(`table group shape ${readShapeIdentity(groupShape).spid} carries no anchor, so the table cannot be placed on the slide`);
|
|
115
|
+
const tableTransform = groupTransform(groupShape, parent);
|
|
116
|
+
const cells = [];
|
|
117
|
+
for (const child of rest) if (child.header.recType === 61444) collectShape(child, tableTransform, cells);
|
|
118
|
+
into.push({
|
|
119
|
+
anchor,
|
|
120
|
+
rotationDeg: rotationDegOf(groupProperties),
|
|
121
|
+
cells
|
|
122
|
+
});
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
95
125
|
const transform = groupTransform(groupShape, parent);
|
|
96
126
|
for (const child of rest) if (child.header.recType === 61443) collectGroup(child, transform, into);
|
|
97
127
|
else if (child.header.recType === 61444) collectShape(child, transform, into);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { t as PptRecord } from "../tree-Du_LXAF0.cjs";
|
|
2
|
+
import { ShapeProperty } from "./properties.cjs";
|
|
2
3
|
//#region src/drawing/shapes.d.ts
|
|
3
4
|
interface ShapeRect {
|
|
4
5
|
readonly left: number;
|
|
@@ -9,8 +10,16 @@ interface ShapeRect {
|
|
|
9
10
|
interface PptShape {
|
|
10
11
|
readonly spid: number;
|
|
11
12
|
readonly anchor: ShapeRect | undefined;
|
|
13
|
+
readonly rotationDeg: number | undefined;
|
|
12
14
|
readonly clientTextbox: PptRecord | undefined;
|
|
15
|
+
readonly clientData: PptRecord | undefined;
|
|
16
|
+
readonly properties: ReadonlyMap<number, ShapeProperty>;
|
|
13
17
|
}
|
|
14
|
-
|
|
18
|
+
interface PptTable {
|
|
19
|
+
readonly anchor: ShapeRect;
|
|
20
|
+
readonly rotationDeg: number | undefined;
|
|
21
|
+
readonly cells: readonly PptShape[];
|
|
22
|
+
}
|
|
23
|
+
declare function readDrawingShapes(drawing: PptRecord): readonly (PptShape | PptTable)[];
|
|
15
24
|
//#endregion
|
|
16
|
-
export { PptShape, ShapeRect, readDrawingShapes };
|
|
25
|
+
export { PptShape, PptTable, ShapeRect, readDrawingShapes };
|