ppt-codec 1.6.0 → 1.7.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 (42) hide show
  1. package/README.md +44 -40
  2. package/dist/document/master-write.cjs +1 -1
  3. package/dist/document/master-write.js +1 -1
  4. package/dist/document/notes-write.cjs +1 -1
  5. package/dist/document/notes-write.js +1 -1
  6. package/dist/drawing/properties.cjs +8 -0
  7. package/dist/drawing/properties.d.cts +5 -1
  8. package/dist/drawing/properties.d.ts +5 -1
  9. package/dist/drawing/properties.js +5 -1
  10. package/dist/drawing/shapes-write.cjs +37 -7
  11. package/dist/drawing/shapes-write.d.cts +1 -0
  12. package/dist/drawing/shapes-write.d.ts +1 -0
  13. package/dist/drawing/shapes-write.js +38 -8
  14. package/dist/index.cjs +10 -2
  15. package/dist/index.d.cts +6 -6
  16. package/dist/index.d.ts +6 -6
  17. package/dist/index.js +6 -6
  18. package/dist/ole/embedded-write.cjs +66 -0
  19. package/dist/ole/embedded-write.d.cts +12 -0
  20. package/dist/ole/embedded-write.d.ts +12 -0
  21. package/dist/ole/embedded-write.js +63 -0
  22. package/dist/ole/embedded.cjs +66 -0
  23. package/dist/ole/embedded.d.cts +12 -0
  24. package/dist/ole/embedded.d.ts +12 -0
  25. package/dist/ole/embedded.js +63 -0
  26. package/dist/read.cjs +52 -11
  27. package/dist/read.d.cts +12 -5
  28. package/dist/read.d.ts +12 -5
  29. package/dist/read.js +53 -12
  30. package/dist/stream/current-user.cjs +1 -0
  31. package/dist/stream/current-user.d.cts +2 -1
  32. package/dist/stream/current-user.d.ts +2 -1
  33. package/dist/stream/current-user.js +1 -1
  34. package/dist/units.cjs +10 -0
  35. package/dist/units.d.cts +4 -1
  36. package/dist/units.d.ts +4 -1
  37. package/dist/units.js +8 -1
  38. package/dist/write.cjs +41 -5
  39. package/dist/write.d.cts +6 -2
  40. package/dist/write.d.ts +6 -2
  41. package/dist/write.js +41 -5
  42. package/package.json +2 -2
@@ -0,0 +1,63 @@
1
+ import { PptFormatError } from "../errors.js";
2
+ import { childRecords, findChild, readRecordAt } from "../record/tree.js";
3
+ import { RT_ExternalObjectList, RT_ExternalObjectRefAtom, RT_ExternalOleObjectAtom } from "../record/types.js";
4
+ import { decodeUtf16Le } from "../stream/current-user.js";
5
+ import { inflate } from "byte-codec";
6
+ //#region src/ole/embedded.ts
7
+ const EX_OLE_OBJ_ATOM_LEN = 24;
8
+ function readExOleObjAtom(record) {
9
+ if (record.data.length < EX_OLE_OBJ_ATOM_LEN) throw new PptFormatError(`ExOleObjAtom at offset ${record.offset} carries ${record.data.length} bytes, fewer than the ${EX_OLE_OBJ_ATOM_LEN} its fields need`);
10
+ const view = new DataView(record.data.buffer, record.data.byteOffset, record.data.byteLength);
11
+ return {
12
+ exObjId: view.getUint32(8, true),
13
+ persistIdRef: view.getUint32(16, true)
14
+ };
15
+ }
16
+ const PROG_ID_ATOM_INSTANCE = 2;
17
+ function readExOleEmbedContainer(container) {
18
+ const children = childRecords(container);
19
+ const objAtom = findChild(children, RT_ExternalOleObjectAtom);
20
+ if (objAtom === void 0) return;
21
+ const progIdAtom = children.find((child) => child.header.recType === 4026 && child.header.recInstance === PROG_ID_ATOM_INSTANCE);
22
+ return {
23
+ ...readExOleObjAtom(objAtom),
24
+ progId: progIdAtom === void 0 ? void 0 : decodeUtf16Le(progIdAtom.data)
25
+ };
26
+ }
27
+ function readExternalOleEmbeds(documentChildren) {
28
+ const embeds = /* @__PURE__ */ new Map();
29
+ const objList = findChild(documentChildren, RT_ExternalObjectList);
30
+ if (objList === void 0) return embeds;
31
+ for (const child of childRecords(objList)) {
32
+ if (child.header.recType !== 4044) continue;
33
+ const embed = readExOleEmbedContainer(child);
34
+ if (embed !== void 0) embeds.set(embed.exObjId, embed);
35
+ }
36
+ return embeds;
37
+ }
38
+ function readExObjIdRef(clientData) {
39
+ const record = findChild(childRecords(clientData), RT_ExternalObjectRefAtom);
40
+ if (record === void 0 || record.data.length < 4) return;
41
+ return new DataView(record.data.buffer, record.data.byteOffset, record.data.byteLength).getUint32(0, true);
42
+ }
43
+ const EX_OLE_OBJ_STG_INSTANCE_COMPRESSED = 1;
44
+ function resolveOleObjectStorage(streamBytes, directory, persistIdRef) {
45
+ const offset = directory.get(persistIdRef);
46
+ if (offset === void 0) return;
47
+ let record;
48
+ try {
49
+ record = readRecordAt(streamBytes, offset);
50
+ } catch {
51
+ return;
52
+ }
53
+ if (record.header.recType !== 4113) return;
54
+ if (record.header.recInstance !== EX_OLE_OBJ_STG_INSTANCE_COMPRESSED) return record.data;
55
+ if (record.data.length < 4) return;
56
+ try {
57
+ return inflate(record.data.subarray(4));
58
+ } catch {
59
+ return;
60
+ }
61
+ }
62
+ //#endregion
63
+ export { readExObjIdRef, readExternalOleEmbeds, resolveOleObjectStorage };
package/dist/read.cjs CHANGED
@@ -19,6 +19,7 @@ const require_drawing_shapes = require("./drawing/shapes.cjs");
19
19
  const require_document_notes = require("./document/notes.cjs");
20
20
  const require_document_slide_list = require("./document/slide-list.cjs");
21
21
  const require_stream_current_user = require("./stream/current-user.cjs");
22
+ const require_ole_embedded = require("./ole/embedded.cjs");
22
23
  const require_stream_persist = require("./stream/persist.cjs");
23
24
  let archive_codec = require("archive-codec");
24
25
  let document_schema_js = require("document-schema.js");
@@ -30,6 +31,20 @@ const PICTURES_STREAM = "Pictures";
30
31
  const SUMMARY_INFORMATION_STREAM = "SummaryInformation";
31
32
  const DEFAULT_INSET_LEFT_RIGHT_PT = 7.2;
32
33
  const DEFAULT_INSET_TOP_BOTTOM_PT = 3.6;
34
+ function insetsForShape(properties, isPicture) {
35
+ const defaultLeftRight = isPicture ? 0 : DEFAULT_INSET_LEFT_RIGHT_PT;
36
+ const defaultTopBottom = isPicture ? 0 : DEFAULT_INSET_TOP_BOTTOM_PT;
37
+ const emuOrDefault = (opid, fallback) => {
38
+ const property = properties.get(opid);
39
+ return property === void 0 ? fallback : require_units.emuToPoints(property.value);
40
+ };
41
+ return {
42
+ insetLeftPt: emuOrDefault(129, defaultLeftRight),
43
+ insetTopPt: emuOrDefault(130, defaultTopBottom),
44
+ insetRightPt: emuOrDefault(131, defaultLeftRight),
45
+ insetBottomPt: emuOrDefault(132, defaultTopBottom)
46
+ };
47
+ }
33
48
  const NO_STYLE = {
34
49
  paragraphRuns: [],
35
50
  characterRuns: []
@@ -80,6 +95,23 @@ function imageBlocksFor(pibProperty, context, widthPt, heightPt) {
80
95
  heightPt
81
96
  }];
82
97
  }
98
+ function embeddedObjectBlocksFor(clientData, context, frame) {
99
+ if (clientData === void 0 || context.decodeEmbeddedObject === void 0) return [];
100
+ const exObjId = require_ole_embedded.readExObjIdRef(clientData);
101
+ if (exObjId === void 0) return [];
102
+ const embed = context.externalOleEmbeds.get(exObjId);
103
+ if (embed === void 0) return [];
104
+ const storageBytes = require_ole_embedded.resolveOleObjectStorage(context.streamBytes, context.directory, embed.persistIdRef);
105
+ if (storageBytes === void 0) return [];
106
+ const decoded = context.decodeEmbeddedObject(storageBytes, embed.progId);
107
+ if (decoded === void 0) return [];
108
+ return [{
109
+ kind: "embeddedObject",
110
+ objectKind: decoded.objectKind,
111
+ document: decoded.document,
112
+ frame
113
+ }];
114
+ }
83
115
  function tableBlockFor(table, context) {
84
116
  const placed = table.cells.flatMap((cell) => cell.anchor === void 0 || cell.anchor.right <= cell.anchor.left || cell.anchor.bottom <= cell.anchor.top ? [] : [{
85
117
  cell,
@@ -194,11 +226,17 @@ function readSlide(base, size, notes, mastersById) {
194
226
  heightPt
195
227
  },
196
228
  ...shape.rotationDeg === void 0 ? {} : { rotationDeg: shape.rotationDeg },
197
- insetLeftPt: isPicture ? 0 : DEFAULT_INSET_LEFT_RIGHT_PT,
198
- insetTopPt: isPicture ? 0 : DEFAULT_INSET_TOP_BOTTOM_PT,
199
- insetRightPt: isPicture ? 0 : DEFAULT_INSET_LEFT_RIGHT_PT,
200
- insetBottomPt: isPicture ? 0 : DEFAULT_INSET_TOP_BOTTOM_PT,
201
- blocks: [...imageBlocksFor(shape.properties.get(260), context, widthPt, heightPt), ...blocksFor(shape.clientTextbox, context)]
229
+ ...insetsForShape(shape.properties, isPicture),
230
+ blocks: [
231
+ ...imageBlocksFor(shape.properties.get(260), context, widthPt, heightPt),
232
+ ...blocksFor(shape.clientTextbox, context),
233
+ ...embeddedObjectBlocksFor(shape.clientData, context, {
234
+ xPt: left,
235
+ yPt: top,
236
+ widthPt,
237
+ heightPt
238
+ })
239
+ ]
202
240
  });
203
241
  }
204
242
  return {
@@ -207,7 +245,7 @@ function readSlide(base, size, notes, mastersById) {
207
245
  notes
208
246
  };
209
247
  }
210
- function readPptStreams(currentUserStream, powerPointDocumentStream, password, picturesStream) {
248
+ function readPptStreams(currentUserStream, powerPointDocumentStream, password, picturesStream, options) {
211
249
  const currentUser = require_stream_current_user.readCurrentUserAtom(currentUserStream);
212
250
  const { directory, currentEdit } = require_stream_persist.buildPersistDirectory(powerPointDocumentStream, currentUser.offsetToCurrentEdit);
213
251
  let streamBytes = powerPointDocumentStream;
@@ -236,6 +274,7 @@ function readPptStreams(currentUserStream, powerPointDocumentStream, password, p
236
274
  const persists = slideList === void 0 ? [] : require_document_slide_list.readSlideListWithText(slideList);
237
275
  const notesBySlideId = readNotesBySlideId(streamBytes, directory, listWithInstance(2));
238
276
  const blips = require_drawing_blips.readBlipStore(documentContainer, currentUser.encrypted ? void 0 : picturesStream);
277
+ const externalOleEmbeds = require_ole_embedded.readExternalOleEmbeds(children);
239
278
  return {
240
279
  metadata: {},
241
280
  slides: persists.map((persist) => readSlide({
@@ -243,14 +282,16 @@ function readPptStreams(currentUserStream, powerPointDocumentStream, password, p
243
282
  directory,
244
283
  persist,
245
284
  fontNames,
246
- blips
285
+ blips,
286
+ externalOleEmbeds,
287
+ decodeEmbeddedObject: options?.decodeEmbeddedObject
247
288
  }, size, notesBySlideId.get(persist.slideId) ?? "", mastersById))
248
289
  };
249
290
  }
250
- function readPptContent(bytes, password) {
291
+ function readPptContent(bytes, password, options) {
251
292
  const streams = (0, archive_codec.readCompoundFile)(bytes);
252
293
  const pictures = streams.find((stream) => stream.path === PICTURES_STREAM);
253
- const document = readPptStreams(requireStream(streams, CURRENT_USER_STREAM), requireStream(streams, POWERPOINT_DOCUMENT_STREAM), password, pictures === void 0 ? void 0 : pictures.bytes);
294
+ const document = readPptStreams(requireStream(streams, CURRENT_USER_STREAM), requireStream(streams, POWERPOINT_DOCUMENT_STREAM), password, pictures === void 0 ? void 0 : pictures.bytes, options);
254
295
  const metadataStream = streams.find((stream) => stream.path === SUMMARY_INFORMATION_STREAM);
255
296
  if (metadataStream === void 0) return document;
256
297
  return {
@@ -258,8 +299,8 @@ function readPptContent(bytes, password) {
258
299
  metadata: (0, archive_codec.summaryInformationToLayoutMetadata)((0, archive_codec.readSummaryInformation)(metadataStream.bytes))
259
300
  };
260
301
  }
261
- function readPpt(bytes, password) {
262
- const { metadata, slides } = readPptContent(bytes, password);
302
+ function readPpt(bytes, password, options) {
303
+ const { metadata, slides } = readPptContent(bytes, password, options);
263
304
  const document = {
264
305
  kind: "presentation",
265
306
  metadata,
package/dist/read.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { ContentSlide, DocumentTree, LayoutMetadata } from "document-schema.js";
1
+ import { ContentDocument, ContentEmbeddedObjectKind, ContentSlide, DocumentTree, LayoutMetadata } from "document-schema.js";
2
2
  //#region src/read.d.ts
3
3
  declare const CURRENT_USER_STREAM = "Current User";
4
4
  declare const POWERPOINT_DOCUMENT_STREAM = "PowerPoint Document";
@@ -7,12 +7,19 @@ declare const PICTURES_STREAM = "Pictures";
7
7
  declare const SUMMARY_INFORMATION_STREAM = "SummaryInformation";
8
8
  declare const DEFAULT_INSET_LEFT_RIGHT_PT: number;
9
9
  declare const DEFAULT_INSET_TOP_BOTTOM_PT: number;
10
+ type DecodeEmbeddedObjectPort = (storageBytes: Uint8Array<ArrayBuffer>, progId: string | undefined) => {
11
+ readonly objectKind: ContentEmbeddedObjectKind;
12
+ readonly document: ContentDocument;
13
+ } | undefined;
14
+ interface ReadPptOptions {
15
+ readonly decodeEmbeddedObject?: DecodeEmbeddedObjectPort;
16
+ }
10
17
  interface PptDocument {
11
18
  readonly metadata: LayoutMetadata;
12
19
  readonly slides: readonly ContentSlide[];
13
20
  }
14
- declare function readPptStreams(currentUserStream: Uint8Array<ArrayBuffer>, powerPointDocumentStream: Uint8Array<ArrayBuffer>, password?: string, picturesStream?: Uint8Array<ArrayBuffer>): PptDocument;
15
- declare function readPptContent(bytes: Uint8Array<ArrayBuffer>, password?: string): PptDocument;
16
- declare function readPpt(bytes: Uint8Array<ArrayBuffer>, password?: string): DocumentTree;
21
+ declare function readPptStreams(currentUserStream: Uint8Array<ArrayBuffer>, powerPointDocumentStream: Uint8Array<ArrayBuffer>, password?: string, picturesStream?: Uint8Array<ArrayBuffer>, options?: ReadPptOptions): PptDocument;
22
+ declare function readPptContent(bytes: Uint8Array<ArrayBuffer>, password?: string, options?: ReadPptOptions): PptDocument;
23
+ declare function readPpt(bytes: Uint8Array<ArrayBuffer>, password?: string, options?: ReadPptOptions): DocumentTree;
17
24
  //#endregion
18
- export { CURRENT_USER_STREAM, DEFAULT_INSET_LEFT_RIGHT_PT, DEFAULT_INSET_TOP_BOTTOM_PT, PICTURES_STREAM, POWERPOINT_DOCUMENT_STREAM, PptDocument, SUMMARY_INFORMATION_STREAM, readPpt, readPptContent, readPptStreams };
25
+ export { CURRENT_USER_STREAM, DEFAULT_INSET_LEFT_RIGHT_PT, DEFAULT_INSET_TOP_BOTTOM_PT, DecodeEmbeddedObjectPort, PICTURES_STREAM, POWERPOINT_DOCUMENT_STREAM, PptDocument, ReadPptOptions, SUMMARY_INFORMATION_STREAM, readPpt, readPptContent, readPptStreams };
package/dist/read.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ContentSlide, DocumentTree, LayoutMetadata } from "document-schema.js";
1
+ import { ContentDocument, ContentEmbeddedObjectKind, ContentSlide, DocumentTree, LayoutMetadata } from "document-schema.js";
2
2
  //#region src/read.d.ts
3
3
  declare const CURRENT_USER_STREAM = "Current User";
4
4
  declare const POWERPOINT_DOCUMENT_STREAM = "PowerPoint Document";
@@ -7,12 +7,19 @@ declare const PICTURES_STREAM = "Pictures";
7
7
  declare const SUMMARY_INFORMATION_STREAM = "SummaryInformation";
8
8
  declare const DEFAULT_INSET_LEFT_RIGHT_PT: number;
9
9
  declare const DEFAULT_INSET_TOP_BOTTOM_PT: number;
10
+ type DecodeEmbeddedObjectPort = (storageBytes: Uint8Array<ArrayBuffer>, progId: string | undefined) => {
11
+ readonly objectKind: ContentEmbeddedObjectKind;
12
+ readonly document: ContentDocument;
13
+ } | undefined;
14
+ interface ReadPptOptions {
15
+ readonly decodeEmbeddedObject?: DecodeEmbeddedObjectPort;
16
+ }
10
17
  interface PptDocument {
11
18
  readonly metadata: LayoutMetadata;
12
19
  readonly slides: readonly ContentSlide[];
13
20
  }
14
- declare function readPptStreams(currentUserStream: Uint8Array<ArrayBuffer>, powerPointDocumentStream: Uint8Array<ArrayBuffer>, password?: string, picturesStream?: Uint8Array<ArrayBuffer>): PptDocument;
15
- declare function readPptContent(bytes: Uint8Array<ArrayBuffer>, password?: string): PptDocument;
16
- declare function readPpt(bytes: Uint8Array<ArrayBuffer>, password?: string): DocumentTree;
21
+ declare function readPptStreams(currentUserStream: Uint8Array<ArrayBuffer>, powerPointDocumentStream: Uint8Array<ArrayBuffer>, password?: string, picturesStream?: Uint8Array<ArrayBuffer>, options?: ReadPptOptions): PptDocument;
22
+ declare function readPptContent(bytes: Uint8Array<ArrayBuffer>, password?: string, options?: ReadPptOptions): PptDocument;
23
+ declare function readPpt(bytes: Uint8Array<ArrayBuffer>, password?: string, options?: ReadPptOptions): DocumentTree;
17
24
  //#endregion
18
- export { CURRENT_USER_STREAM, DEFAULT_INSET_LEFT_RIGHT_PT, DEFAULT_INSET_TOP_BOTTOM_PT, PICTURES_STREAM, POWERPOINT_DOCUMENT_STREAM, PptDocument, SUMMARY_INFORMATION_STREAM, readPpt, readPptContent, readPptStreams };
25
+ export { CURRENT_USER_STREAM, DEFAULT_INSET_LEFT_RIGHT_PT, DEFAULT_INSET_TOP_BOTTOM_PT, DecodeEmbeddedObjectPort, PICTURES_STREAM, POWERPOINT_DOCUMENT_STREAM, PptDocument, ReadPptOptions, SUMMARY_INFORMATION_STREAM, readPpt, readPptContent, readPptStreams };
package/dist/read.js CHANGED
@@ -4,7 +4,7 @@ import { childRecords, findChild } from "./record/tree.js";
4
4
  import { RT_Document, RT_DocumentAtom, RT_Drawing, RT_Environment, RT_MainMaster, RT_OutlineTextRefAtom, RT_Slide, RT_SlideAtom, RT_StyleTextPropAtom, RT_TextHeaderAtom, RT_TextMasterStyleAtom } from "./record/types.js";
5
5
  import { readStyleTextPropAtom, readTextMasterStyleAtom } from "./text/style.js";
6
6
  import { characterCountOf, readTextBody, readTextHeaderAtom } from "./text/atoms.js";
7
- import { masterUnitsToPoints } from "./units.js";
7
+ import { emuToPoints, masterUnitsToPoints } from "./units.js";
8
8
  import { findSlideSchemeColorSchemeAtom, readSlideSchemeColorSchemeAtom } from "./document/color-scheme.js";
9
9
  import { buildMasterStyleTable, readSlideAtom } from "./document/master.js";
10
10
  import { buildParagraphs } from "./content.js";
@@ -18,6 +18,7 @@ import { readDrawingShapes } from "./drawing/shapes.js";
18
18
  import { readNotesContainerAtom, readNotesText } from "./document/notes.js";
19
19
  import { readSlideListWithText } from "./document/slide-list.js";
20
20
  import { readCurrentUserAtom } from "./stream/current-user.js";
21
+ import { readExObjIdRef, readExternalOleEmbeds, resolveOleObjectStorage } from "./ole/embedded.js";
21
22
  import { buildPersistDirectory, resolvePersistObject } from "./stream/persist.js";
22
23
  import { readCompoundFile, readSummaryInformation, summaryInformationToLayoutMetadata } from "archive-codec";
23
24
  import { assembleTree } from "document-schema.js";
@@ -29,6 +30,20 @@ const PICTURES_STREAM = "Pictures";
29
30
  const SUMMARY_INFORMATION_STREAM = "SummaryInformation";
30
31
  const DEFAULT_INSET_LEFT_RIGHT_PT = 7.2;
31
32
  const DEFAULT_INSET_TOP_BOTTOM_PT = 3.6;
33
+ function insetsForShape(properties, isPicture) {
34
+ const defaultLeftRight = isPicture ? 0 : DEFAULT_INSET_LEFT_RIGHT_PT;
35
+ const defaultTopBottom = isPicture ? 0 : DEFAULT_INSET_TOP_BOTTOM_PT;
36
+ const emuOrDefault = (opid, fallback) => {
37
+ const property = properties.get(opid);
38
+ return property === void 0 ? fallback : emuToPoints(property.value);
39
+ };
40
+ return {
41
+ insetLeftPt: emuOrDefault(129, defaultLeftRight),
42
+ insetTopPt: emuOrDefault(130, defaultTopBottom),
43
+ insetRightPt: emuOrDefault(131, defaultLeftRight),
44
+ insetBottomPt: emuOrDefault(132, defaultTopBottom)
45
+ };
46
+ }
32
47
  const NO_STYLE = {
33
48
  paragraphRuns: [],
34
49
  characterRuns: []
@@ -79,6 +94,23 @@ function imageBlocksFor(pibProperty, context, widthPt, heightPt) {
79
94
  heightPt
80
95
  }];
81
96
  }
97
+ function embeddedObjectBlocksFor(clientData, context, frame) {
98
+ if (clientData === void 0 || context.decodeEmbeddedObject === void 0) return [];
99
+ const exObjId = readExObjIdRef(clientData);
100
+ if (exObjId === void 0) return [];
101
+ const embed = context.externalOleEmbeds.get(exObjId);
102
+ if (embed === void 0) return [];
103
+ const storageBytes = resolveOleObjectStorage(context.streamBytes, context.directory, embed.persistIdRef);
104
+ if (storageBytes === void 0) return [];
105
+ const decoded = context.decodeEmbeddedObject(storageBytes, embed.progId);
106
+ if (decoded === void 0) return [];
107
+ return [{
108
+ kind: "embeddedObject",
109
+ objectKind: decoded.objectKind,
110
+ document: decoded.document,
111
+ frame
112
+ }];
113
+ }
82
114
  function tableBlockFor(table, context) {
83
115
  const placed = table.cells.flatMap((cell) => cell.anchor === void 0 || cell.anchor.right <= cell.anchor.left || cell.anchor.bottom <= cell.anchor.top ? [] : [{
84
116
  cell,
@@ -193,11 +225,17 @@ function readSlide(base, size, notes, mastersById) {
193
225
  heightPt
194
226
  },
195
227
  ...shape.rotationDeg === void 0 ? {} : { rotationDeg: shape.rotationDeg },
196
- insetLeftPt: isPicture ? 0 : DEFAULT_INSET_LEFT_RIGHT_PT,
197
- insetTopPt: isPicture ? 0 : DEFAULT_INSET_TOP_BOTTOM_PT,
198
- insetRightPt: isPicture ? 0 : DEFAULT_INSET_LEFT_RIGHT_PT,
199
- insetBottomPt: isPicture ? 0 : DEFAULT_INSET_TOP_BOTTOM_PT,
200
- blocks: [...imageBlocksFor(shape.properties.get(260), context, widthPt, heightPt), ...blocksFor(shape.clientTextbox, context)]
228
+ ...insetsForShape(shape.properties, isPicture),
229
+ blocks: [
230
+ ...imageBlocksFor(shape.properties.get(260), context, widthPt, heightPt),
231
+ ...blocksFor(shape.clientTextbox, context),
232
+ ...embeddedObjectBlocksFor(shape.clientData, context, {
233
+ xPt: left,
234
+ yPt: top,
235
+ widthPt,
236
+ heightPt
237
+ })
238
+ ]
201
239
  });
202
240
  }
203
241
  return {
@@ -206,7 +244,7 @@ function readSlide(base, size, notes, mastersById) {
206
244
  notes
207
245
  };
208
246
  }
209
- function readPptStreams(currentUserStream, powerPointDocumentStream, password, picturesStream) {
247
+ function readPptStreams(currentUserStream, powerPointDocumentStream, password, picturesStream, options) {
210
248
  const currentUser = readCurrentUserAtom(currentUserStream);
211
249
  const { directory, currentEdit } = buildPersistDirectory(powerPointDocumentStream, currentUser.offsetToCurrentEdit);
212
250
  let streamBytes = powerPointDocumentStream;
@@ -235,6 +273,7 @@ function readPptStreams(currentUserStream, powerPointDocumentStream, password, p
235
273
  const persists = slideList === void 0 ? [] : readSlideListWithText(slideList);
236
274
  const notesBySlideId = readNotesBySlideId(streamBytes, directory, listWithInstance(2));
237
275
  const blips = readBlipStore(documentContainer, currentUser.encrypted ? void 0 : picturesStream);
276
+ const externalOleEmbeds = readExternalOleEmbeds(children);
238
277
  return {
239
278
  metadata: {},
240
279
  slides: persists.map((persist) => readSlide({
@@ -242,14 +281,16 @@ function readPptStreams(currentUserStream, powerPointDocumentStream, password, p
242
281
  directory,
243
282
  persist,
244
283
  fontNames,
245
- blips
284
+ blips,
285
+ externalOleEmbeds,
286
+ decodeEmbeddedObject: options?.decodeEmbeddedObject
246
287
  }, size, notesBySlideId.get(persist.slideId) ?? "", mastersById))
247
288
  };
248
289
  }
249
- function readPptContent(bytes, password) {
290
+ function readPptContent(bytes, password, options) {
250
291
  const streams = readCompoundFile(bytes);
251
292
  const pictures = streams.find((stream) => stream.path === PICTURES_STREAM);
252
- const document = readPptStreams(requireStream(streams, CURRENT_USER_STREAM), requireStream(streams, POWERPOINT_DOCUMENT_STREAM), password, pictures === void 0 ? void 0 : pictures.bytes);
293
+ const document = readPptStreams(requireStream(streams, CURRENT_USER_STREAM), requireStream(streams, POWERPOINT_DOCUMENT_STREAM), password, pictures === void 0 ? void 0 : pictures.bytes, options);
253
294
  const metadataStream = streams.find((stream) => stream.path === SUMMARY_INFORMATION_STREAM);
254
295
  if (metadataStream === void 0) return document;
255
296
  return {
@@ -257,8 +298,8 @@ function readPptContent(bytes, password) {
257
298
  metadata: summaryInformationToLayoutMetadata(readSummaryInformation(metadataStream.bytes))
258
299
  };
259
300
  }
260
- function readPpt(bytes, password) {
261
- const { metadata, slides } = readPptContent(bytes, password);
301
+ function readPpt(bytes, password, options) {
302
+ const { metadata, slides } = readPptContent(bytes, password, options);
262
303
  const document = {
263
304
  kind: "presentation",
264
305
  metadata,
@@ -48,4 +48,5 @@ exports.CURRENT_USER_DOC_FILE_VERSION = CURRENT_USER_DOC_FILE_VERSION;
48
48
  exports.CURRENT_USER_FIXED_SIZE = CURRENT_USER_FIXED_SIZE;
49
49
  exports.CURRENT_USER_HEADER_TOKEN_ENCRYPTED = CURRENT_USER_HEADER_TOKEN_ENCRYPTED;
50
50
  exports.CURRENT_USER_HEADER_TOKEN_PLAIN = CURRENT_USER_HEADER_TOKEN_PLAIN;
51
+ exports.decodeUtf16Le = decodeUtf16Le;
51
52
  exports.readCurrentUserAtom = readCurrentUserAtom;
@@ -8,6 +8,7 @@ interface CurrentUser {
8
8
  readonly encrypted: boolean;
9
9
  readonly userName: string;
10
10
  }
11
+ declare function decodeUtf16Le(bytes: Uint8Array<ArrayBuffer>): string;
11
12
  declare function readCurrentUserAtom(streamBytes: Uint8Array<ArrayBuffer>): CurrentUser;
12
13
  //#endregion
13
- export { CURRENT_USER_DOC_FILE_VERSION, CURRENT_USER_FIXED_SIZE, CURRENT_USER_HEADER_TOKEN_ENCRYPTED, CURRENT_USER_HEADER_TOKEN_PLAIN, CurrentUser, readCurrentUserAtom };
14
+ export { CURRENT_USER_DOC_FILE_VERSION, CURRENT_USER_FIXED_SIZE, CURRENT_USER_HEADER_TOKEN_ENCRYPTED, CURRENT_USER_HEADER_TOKEN_PLAIN, CurrentUser, decodeUtf16Le, readCurrentUserAtom };
@@ -8,6 +8,7 @@ interface CurrentUser {
8
8
  readonly encrypted: boolean;
9
9
  readonly userName: string;
10
10
  }
11
+ declare function decodeUtf16Le(bytes: Uint8Array<ArrayBuffer>): string;
11
12
  declare function readCurrentUserAtom(streamBytes: Uint8Array<ArrayBuffer>): CurrentUser;
12
13
  //#endregion
13
- export { CURRENT_USER_DOC_FILE_VERSION, CURRENT_USER_FIXED_SIZE, CURRENT_USER_HEADER_TOKEN_ENCRYPTED, CURRENT_USER_HEADER_TOKEN_PLAIN, CurrentUser, readCurrentUserAtom };
14
+ export { CURRENT_USER_DOC_FILE_VERSION, CURRENT_USER_FIXED_SIZE, CURRENT_USER_HEADER_TOKEN_ENCRYPTED, CURRENT_USER_HEADER_TOKEN_PLAIN, CurrentUser, decodeUtf16Le, readCurrentUserAtom };
@@ -43,4 +43,4 @@ function readCurrentUserAtom(streamBytes) {
43
43
  };
44
44
  }
45
45
  //#endregion
46
- export { CURRENT_USER_DOC_FILE_VERSION, CURRENT_USER_FIXED_SIZE, CURRENT_USER_HEADER_TOKEN_ENCRYPTED, CURRENT_USER_HEADER_TOKEN_PLAIN, readCurrentUserAtom };
46
+ export { CURRENT_USER_DOC_FILE_VERSION, CURRENT_USER_FIXED_SIZE, CURRENT_USER_HEADER_TOKEN_ENCRYPTED, CURRENT_USER_HEADER_TOKEN_PLAIN, decodeUtf16Le, readCurrentUserAtom };
package/dist/units.cjs CHANGED
@@ -9,8 +9,18 @@ function masterUnitsToPoints(masterUnits) {
9
9
  function pointsToMasterUnits(points) {
10
10
  return Math.round(points * 8);
11
11
  }
12
+ const EMU_PER_POINT = 12700;
13
+ function emuToPoints(emu) {
14
+ return emu / EMU_PER_POINT;
15
+ }
16
+ function pointsToEmu(points) {
17
+ return Math.round(points * EMU_PER_POINT);
18
+ }
12
19
  //#endregion
20
+ exports.EMU_PER_POINT = EMU_PER_POINT;
13
21
  exports.MASTER_UNITS_PER_POINT = MASTER_UNITS_PER_POINT;
14
22
  exports.POINTS_PER_INCH = POINTS_PER_INCH;
23
+ exports.emuToPoints = emuToPoints;
15
24
  exports.masterUnitsToPoints = masterUnitsToPoints;
25
+ exports.pointsToEmu = pointsToEmu;
16
26
  exports.pointsToMasterUnits = pointsToMasterUnits;
package/dist/units.d.cts CHANGED
@@ -3,5 +3,8 @@ declare const POINTS_PER_INCH = 72;
3
3
  declare const MASTER_UNITS_PER_POINT: number;
4
4
  declare function masterUnitsToPoints(masterUnits: number): number;
5
5
  declare function pointsToMasterUnits(points: number): number;
6
+ declare const EMU_PER_POINT: number;
7
+ declare function emuToPoints(emu: number): number;
8
+ declare function pointsToEmu(points: number): number;
6
9
  //#endregion
7
- export { MASTER_UNITS_PER_POINT, POINTS_PER_INCH, masterUnitsToPoints, pointsToMasterUnits };
10
+ export { EMU_PER_POINT, MASTER_UNITS_PER_POINT, POINTS_PER_INCH, emuToPoints, masterUnitsToPoints, pointsToEmu, pointsToMasterUnits };
package/dist/units.d.ts CHANGED
@@ -3,5 +3,8 @@ declare const POINTS_PER_INCH = 72;
3
3
  declare const MASTER_UNITS_PER_POINT: number;
4
4
  declare function masterUnitsToPoints(masterUnits: number): number;
5
5
  declare function pointsToMasterUnits(points: number): number;
6
+ declare const EMU_PER_POINT: number;
7
+ declare function emuToPoints(emu: number): number;
8
+ declare function pointsToEmu(points: number): number;
6
9
  //#endregion
7
- export { MASTER_UNITS_PER_POINT, POINTS_PER_INCH, masterUnitsToPoints, pointsToMasterUnits };
10
+ export { EMU_PER_POINT, MASTER_UNITS_PER_POINT, POINTS_PER_INCH, emuToPoints, masterUnitsToPoints, pointsToEmu, pointsToMasterUnits };
package/dist/units.js CHANGED
@@ -8,5 +8,12 @@ function masterUnitsToPoints(masterUnits) {
8
8
  function pointsToMasterUnits(points) {
9
9
  return Math.round(points * 8);
10
10
  }
11
+ const EMU_PER_POINT = 12700;
12
+ function emuToPoints(emu) {
13
+ return emu / EMU_PER_POINT;
14
+ }
15
+ function pointsToEmu(points) {
16
+ return Math.round(points * EMU_PER_POINT);
17
+ }
11
18
  //#endregion
12
- export { MASTER_UNITS_PER_POINT, POINTS_PER_INCH, masterUnitsToPoints, pointsToMasterUnits };
19
+ export { EMU_PER_POINT, MASTER_UNITS_PER_POINT, POINTS_PER_INCH, emuToPoints, masterUnitsToPoints, pointsToEmu, pointsToMasterUnits };
package/dist/write.cjs CHANGED
@@ -8,8 +8,8 @@ const require_record_write = require("./record/write.cjs");
8
8
  const require_document_document_atom_write = require("./document/document-atom-write.cjs");
9
9
  const require_document_fonts_write = require("./document/fonts-write.cjs");
10
10
  const require_drawing_blips = require("./drawing/blips.cjs");
11
- const require_drawing_shapes_write = require("./drawing/shapes-write.cjs");
12
11
  const require_read = require("./read.cjs");
12
+ const require_drawing_shapes_write = require("./drawing/shapes-write.cjs");
13
13
  const require_document_master_write = require("./document/master-write.cjs");
14
14
  const require_document_notes_list_write = require("./document/notes-list-write.cjs");
15
15
  const require_document_notes_write = require("./document/notes-write.cjs");
@@ -17,6 +17,7 @@ const require_document_slide_list_write = require("./document/slide-list-write.c
17
17
  const require_metadata = require("./metadata.cjs");
18
18
  const require_stream_current_user_write = require("./stream/current-user-write.cjs");
19
19
  const require_stream_persist_write = require("./stream/persist-write.cjs");
20
+ const require_ole_embedded_write = require("./ole/embedded-write.cjs");
20
21
  let archive_codec = require("archive-codec");
21
22
  let document_schema_js = require("document-schema.js");
22
23
  //#region src/write.ts
@@ -35,10 +36,10 @@ function requireOneSlideSize(slides) {
35
36
  for (const slide of slides) if (slide.size.widthPt !== first.widthPt || slide.size.heightPt !== first.heightPt) throw new require_errors.PptUnsupportedContentError(`ppt-codec's writer cannot express per-slide sizes: slide sizes ${JSON.stringify(first)} and ${JSON.stringify(slide.size)} both appear, but [MS-PPT]'s DocumentAtom states exactly one slide size for the whole presentation`);
36
37
  return first;
37
38
  }
38
- function writeSlideContainer(shapes, notesIdRef, context) {
39
+ function writeSlideContainer(shapes, notesIdRef, context, clientDataFor) {
39
40
  const drawing = require_drawing_shapes_write.writeSlideDrawing(shapes.map((shape) => ({
40
41
  shape,
41
- clientData: void 0
42
+ clientData: clientDataFor(shape)
42
43
  })), context);
43
44
  return {
44
45
  bytes: require_record_write.writeContainer(require_record_types.RT_Slide, [require_document_master_write.writeSlideAtomForSlide(notesIdRef), drawing.bytes]),
@@ -46,6 +47,34 @@ function writeSlideContainer(shapes, notesIdRef, context) {
46
47
  maxSpid: drawing.maxSpid
47
48
  };
48
49
  }
50
+ function planOleEmbeds(slides, serialise, firstPersistId) {
51
+ const embeds = [];
52
+ const persistObjects = [];
53
+ const clientDataByShape = /* @__PURE__ */ new Map();
54
+ if (serialise !== void 0) for (const slide of slides) for (const shape of slide.shapes) {
55
+ const embedBlock = shape.blocks.find((block) => block.kind === "embeddedObject");
56
+ if (embedBlock === void 0) continue;
57
+ const storageBytes = serialise(embedBlock.document);
58
+ if (storageBytes === void 0) continue;
59
+ const exObjId = embeds.length + 1;
60
+ const persistId = firstPersistId + persistObjects.length;
61
+ embeds.push({
62
+ exObjId,
63
+ persistIdRef: persistId,
64
+ objectKind: embedBlock.objectKind
65
+ });
66
+ persistObjects.push({
67
+ persistId,
68
+ bytes: require_ole_embedded_write.writeExOleObjStg(storageBytes)
69
+ });
70
+ clientDataByShape.set(shape, require_ole_embedded_write.writeOleClientData(exObjId));
71
+ }
72
+ return {
73
+ embeds,
74
+ persistObjects,
75
+ clientDataFor: (shape) => clientDataByShape.get(shape)
76
+ };
77
+ }
49
78
  function planBlipStore(slides) {
50
79
  const blips = [];
51
80
  const pibByKey = /* @__PURE__ */ new Map();
@@ -81,10 +110,12 @@ function writePptStreams(document, options = {}) {
81
110
  return index;
82
111
  };
83
112
  const store = planBlipStore(slides);
113
+ const strict = options.onUnwritableBlock === "throw";
84
114
  const contextFor = (location) => ({
85
115
  fontIndexOf,
86
116
  blipIndexOf: store.pibOf,
87
117
  sink,
118
+ strict,
88
119
  location
89
120
  });
90
121
  const slidePersistRefs = slides.map((_slide, index) => ({
@@ -92,6 +123,8 @@ function writePptStreams(document, options = {}) {
92
123
  slideId: FIRST_SLIDE_ID + index
93
124
  }));
94
125
  const notesIdRefs = slides.map((slide, index) => slide.notes.length === 0 ? NO_NOTES_ID_REF : FIRST_NOTES_ID + slides.slice(0, index).filter((earlier) => earlier.notes.length > 0).length);
126
+ const notesCount = notesIdRefs.filter((id) => id !== NO_NOTES_ID_REF).length;
127
+ const oleEmbeds = planOleEmbeds(slides, options.serialiseEmbeddedObject, FIRST_SLIDE_PERSIST_ID + slides.length + notesCount);
95
128
  let shapeCount = 0;
96
129
  let maxSpid = 0;
97
130
  let drawingCount = 0;
@@ -106,7 +139,7 @@ function writePptStreams(document, options = {}) {
106
139
  const ref = slidePersistRefs[index];
107
140
  const notesIdRef = notesIdRefs[index];
108
141
  if (ref === void 0 || notesIdRef === void 0) throw new require_errors.PptUnsupportedContentError("internal error: slide persist reference missing for a slide being written");
109
- const container = writeSlideContainer(slide.shapes, notesIdRef, contextFor(`slide ${index + 1}`));
142
+ const container = writeSlideContainer(slide.shapes, notesIdRef, contextFor(`slide ${index + 1}`), oleEmbeds.clientDataFor);
110
143
  account(container);
111
144
  return {
112
145
  persistId: ref.persistIdRef,
@@ -132,6 +165,8 @@ function writePptStreams(document, options = {}) {
132
165
  });
133
166
  const environment = require_document_fonts_write.writeEnvironment(fontNames);
134
167
  const documentChildren = [require_document_document_atom_write.writeDocumentAtom(size)];
168
+ const exObjList = require_ole_embedded_write.writeExObjListContainer(oleEmbeds.embeds);
169
+ if (exObjList !== void 0) documentChildren.push(exObjList);
135
170
  if (environment !== void 0) documentChildren.push(environment);
136
171
  documentChildren.push(require_drawing_blips.writeDrawingGroupContainer(store.blips, {
137
172
  spidMax: maxSpid,
@@ -152,7 +187,8 @@ function writePptStreams(document, options = {}) {
152
187
  bytes: mainMaster.bytes
153
188
  },
154
189
  ...slideContainers,
155
- ...notesContainers
190
+ ...notesContainers,
191
+ ...oleEmbeds.persistObjects
156
192
  ];
157
193
  const persistEntries = [];
158
194
  let offset = 0;
package/dist/write.d.cts CHANGED
@@ -1,10 +1,14 @@
1
1
  import { a as PptDiagnosticSink } from "./diagnostics-CqxAnubw.cjs";
2
2
  import { PptDocument } from "./read.cjs";
3
- import { DocumentTree } from "document-schema.js";
3
+ import { ContentDocument, DocumentTree } from "document-schema.js";
4
4
  //#region src/write.d.ts
5
+ type EmbeddedObjectSerialiser = (document: ContentDocument) => Uint8Array<ArrayBuffer> | undefined;
6
+ type PptUnwritableBlockPolicy = "drop" | "throw";
5
7
  interface WritePptOptions {
6
8
  readonly signal?: AbortSignal;
7
9
  readonly sink?: PptDiagnosticSink;
10
+ readonly serialiseEmbeddedObject?: EmbeddedObjectSerialiser;
11
+ readonly onUnwritableBlock?: PptUnwritableBlockPolicy;
8
12
  }
9
13
  declare function writePptStreams(document: PptDocument, options?: WritePptOptions): {
10
14
  readonly currentUserStream: Uint8Array<ArrayBuffer>;
@@ -13,4 +17,4 @@ declare function writePptStreams(document: PptDocument, options?: WritePptOption
13
17
  declare function writePptContent(document: PptDocument, options?: WritePptOptions): Uint8Array<ArrayBuffer>;
14
18
  declare function writePpt(tree: DocumentTree, options?: WritePptOptions): Uint8Array<ArrayBuffer>;
15
19
  //#endregion
16
- export { WritePptOptions, writePpt, writePptContent, writePptStreams };
20
+ export { EmbeddedObjectSerialiser, PptUnwritableBlockPolicy, WritePptOptions, writePpt, writePptContent, writePptStreams };
package/dist/write.d.ts CHANGED
@@ -1,10 +1,14 @@
1
1
  import { a as PptDiagnosticSink } from "./diagnostics-CqxAnubw.js";
2
2
  import { PptDocument } from "./read.js";
3
- import { DocumentTree } from "document-schema.js";
3
+ import { ContentDocument, DocumentTree } from "document-schema.js";
4
4
  //#region src/write.d.ts
5
+ type EmbeddedObjectSerialiser = (document: ContentDocument) => Uint8Array<ArrayBuffer> | undefined;
6
+ type PptUnwritableBlockPolicy = "drop" | "throw";
5
7
  interface WritePptOptions {
6
8
  readonly signal?: AbortSignal;
7
9
  readonly sink?: PptDiagnosticSink;
10
+ readonly serialiseEmbeddedObject?: EmbeddedObjectSerialiser;
11
+ readonly onUnwritableBlock?: PptUnwritableBlockPolicy;
8
12
  }
9
13
  declare function writePptStreams(document: PptDocument, options?: WritePptOptions): {
10
14
  readonly currentUserStream: Uint8Array<ArrayBuffer>;
@@ -13,4 +17,4 @@ declare function writePptStreams(document: PptDocument, options?: WritePptOption
13
17
  declare function writePptContent(document: PptDocument, options?: WritePptOptions): Uint8Array<ArrayBuffer>;
14
18
  declare function writePpt(tree: DocumentTree, options?: WritePptOptions): Uint8Array<ArrayBuffer>;
15
19
  //#endregion
16
- export { WritePptOptions, writePpt, writePptContent, writePptStreams };
20
+ export { EmbeddedObjectSerialiser, PptUnwritableBlockPolicy, WritePptOptions, writePpt, writePptContent, writePptStreams };