ppt-codec 1.5.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 (74) hide show
  1. package/README.md +91 -75
  2. package/dist/base64.cjs +48 -0
  3. package/dist/base64.d.cts +5 -0
  4. package/dist/base64.d.ts +5 -0
  5. package/dist/base64.js +46 -0
  6. package/dist/diagnostics-CqxAnubw.d.cts +16 -0
  7. package/dist/diagnostics-CqxAnubw.d.ts +16 -0
  8. package/dist/diagnostics.cjs +11 -0
  9. package/dist/diagnostics.d.cts +2 -0
  10. package/dist/diagnostics.d.ts +2 -0
  11. package/dist/diagnostics.js +9 -0
  12. package/dist/document/color-scheme.cjs +4 -0
  13. package/dist/document/color-scheme.d.cts +2 -1
  14. package/dist/document/color-scheme.d.ts +2 -1
  15. package/dist/document/color-scheme.js +4 -1
  16. package/dist/document/master-write.cjs +21 -16
  17. package/dist/document/master-write.d.cts +2 -1
  18. package/dist/document/master-write.d.ts +2 -1
  19. package/dist/document/master-write.js +21 -16
  20. package/dist/document/notes-write.cjs +15 -7
  21. package/dist/document/notes-write.d.cts +2 -1
  22. package/dist/document/notes-write.d.ts +2 -1
  23. package/dist/document/notes-write.js +15 -7
  24. package/dist/document/notes.cjs +4 -3
  25. package/dist/document/notes.js +4 -3
  26. package/dist/drawing/blips.cjs +81 -0
  27. package/dist/drawing/blips.d.cts +16 -0
  28. package/dist/drawing/blips.d.ts +16 -0
  29. package/dist/drawing/blips.js +77 -0
  30. package/dist/drawing/properties.cjs +102 -0
  31. package/dist/drawing/properties.d.cts +29 -0
  32. package/dist/drawing/properties.d.ts +29 -0
  33. package/dist/drawing/properties.js +87 -0
  34. package/dist/drawing/shapes-write.cjs +234 -17
  35. package/dist/drawing/shapes-write.d.cts +16 -4
  36. package/dist/drawing/shapes-write.d.ts +16 -4
  37. package/dist/drawing/shapes-write.js +237 -19
  38. package/dist/drawing/shapes.cjs +34 -4
  39. package/dist/drawing/shapes.d.cts +11 -2
  40. package/dist/drawing/shapes.d.ts +11 -2
  41. package/dist/drawing/shapes.js +35 -5
  42. package/dist/index.cjs +48 -3
  43. package/dist/index.d.cts +12 -8
  44. package/dist/index.d.ts +12 -8
  45. package/dist/index.js +11 -7
  46. package/dist/ole/embedded-write.cjs +66 -0
  47. package/dist/ole/embedded-write.d.cts +12 -0
  48. package/dist/ole/embedded-write.d.ts +12 -0
  49. package/dist/ole/embedded-write.js +63 -0
  50. package/dist/ole/embedded.cjs +66 -0
  51. package/dist/ole/embedded.d.cts +12 -0
  52. package/dist/ole/embedded.d.ts +12 -0
  53. package/dist/ole/embedded.js +63 -0
  54. package/dist/read.cjs +145 -22
  55. package/dist/read.d.cts +13 -5
  56. package/dist/read.d.ts +13 -5
  57. package/dist/read.js +148 -26
  58. package/dist/record/types.cjs +28 -0
  59. package/dist/record/types.d.cts +15 -1
  60. package/dist/record/types.d.ts +15 -1
  61. package/dist/record/types.js +15 -1
  62. package/dist/stream/current-user.cjs +1 -0
  63. package/dist/stream/current-user.d.cts +2 -1
  64. package/dist/stream/current-user.d.ts +2 -1
  65. package/dist/stream/current-user.js +1 -1
  66. package/dist/units.cjs +10 -0
  67. package/dist/units.d.cts +4 -1
  68. package/dist/units.d.ts +4 -1
  69. package/dist/units.js +8 -1
  70. package/dist/write.cjs +137 -38
  71. package/dist/write.d.cts +14 -5
  72. package/dist/write.d.ts +14 -5
  73. package/dist/write.js +137 -38
  74. package/package.json +2 -1
package/dist/write.js CHANGED
@@ -1,11 +1,14 @@
1
+ import { base64ToBytes } from "./base64.js";
1
2
  import { PptUnsupportedContentError } from "./errors.js";
2
3
  import { RT_Document, RT_Slide } from "./record/types.js";
3
4
  import { collectFontFamilies } from "./content-write.js";
5
+ import { NOOP_PPT_DIAGNOSTIC_SINK } from "./diagnostics.js";
4
6
  import { concatBytes, writeContainer } from "./record/write.js";
5
7
  import { writeDocumentAtom } from "./document/document-atom-write.js";
6
8
  import { writeEnvironment } from "./document/fonts-write.js";
7
- import { writeSlideDrawing } from "./drawing/shapes-write.js";
9
+ import { isBlipFormat, writeDrawingGroupContainer } from "./drawing/blips.js";
8
10
  import { CURRENT_USER_STREAM, POWERPOINT_DOCUMENT_STREAM, SUMMARY_INFORMATION_STREAM } from "./read.js";
11
+ import { writeSlideDrawing } from "./drawing/shapes-write.js";
9
12
  import { writeMainMaster, writeMasterListWithText, writeSlideAtomForSlide } from "./document/master-write.js";
10
13
  import { writeNotesListWithText } from "./document/notes-list-write.js";
11
14
  import { writeNotesContainer } from "./document/notes-write.js";
@@ -13,6 +16,7 @@ import { writeSlideListWithText } from "./document/slide-list-write.js";
13
16
  import { layoutMetadataToSummaryInformation as layoutMetadataToSummaryInformation$1 } from "./metadata.js";
14
17
  import { writeCurrentUserAtom } from "./stream/current-user-write.js";
15
18
  import { writePersistDirectoryAtom, writeUserEditAtom } from "./stream/persist-write.js";
19
+ import { writeExObjListContainer, writeExOleObjStg, writeOleClientData } from "./ole/embedded-write.js";
16
20
  import { hasSummaryInformationFields, writeCompoundFile, writeSummaryInformationStream } from "archive-codec";
17
21
  import { flattenTree } from "document-schema.js";
18
22
  //#region src/write.ts
@@ -31,65 +35,160 @@ function requireOneSlideSize(slides) {
31
35
  for (const slide of slides) if (slide.size.widthPt !== first.widthPt || slide.size.heightPt !== first.heightPt) throw new 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`);
32
36
  return first;
33
37
  }
34
- function writeSlideContainer(shapes, notesIdRef, fontIndexOf) {
35
- return writeContainer(RT_Slide, [writeSlideAtomForSlide(notesIdRef), writeSlideDrawing(shapes, fontIndexOf)]);
38
+ function writeSlideContainer(shapes, notesIdRef, context, clientDataFor) {
39
+ const drawing = writeSlideDrawing(shapes.map((shape) => ({
40
+ shape,
41
+ clientData: clientDataFor(shape)
42
+ })), context);
43
+ return {
44
+ bytes: writeContainer(RT_Slide, [writeSlideAtomForSlide(notesIdRef), drawing.bytes]),
45
+ shapeCount: drawing.shapeCount,
46
+ maxSpid: drawing.maxSpid
47
+ };
48
+ }
49
+ function planOleEmbeds(slides, serialise, firstPersistId) {
50
+ const embeds = [];
51
+ const persistObjects = [];
52
+ const clientDataByShape = /* @__PURE__ */ new Map();
53
+ if (serialise !== void 0) for (const slide of slides) for (const shape of slide.shapes) {
54
+ const embedBlock = shape.blocks.find((block) => block.kind === "embeddedObject");
55
+ if (embedBlock === void 0) continue;
56
+ const storageBytes = serialise(embedBlock.document);
57
+ if (storageBytes === void 0) continue;
58
+ const exObjId = embeds.length + 1;
59
+ const persistId = firstPersistId + persistObjects.length;
60
+ embeds.push({
61
+ exObjId,
62
+ persistIdRef: persistId,
63
+ objectKind: embedBlock.objectKind
64
+ });
65
+ persistObjects.push({
66
+ persistId,
67
+ bytes: writeExOleObjStg(storageBytes)
68
+ });
69
+ clientDataByShape.set(shape, writeOleClientData(exObjId));
70
+ }
71
+ return {
72
+ embeds,
73
+ persistObjects,
74
+ clientDataFor: (shape) => clientDataByShape.get(shape)
75
+ };
76
+ }
77
+ function planBlipStore(slides) {
78
+ const blips = [];
79
+ const pibByKey = /* @__PURE__ */ new Map();
80
+ for (const slide of slides) for (const shape of slide.shapes) for (const block of shape.blocks) {
81
+ if (block.kind !== "image" || !isBlipFormat(block.format)) continue;
82
+ const key = `${block.format}:${block.base64}`;
83
+ if (!pibByKey.has(key)) {
84
+ pibByKey.set(key, blips.length + 1);
85
+ blips.push({
86
+ format: block.format,
87
+ bytes: base64ToBytes(block.base64)
88
+ });
89
+ }
90
+ }
91
+ return {
92
+ blips,
93
+ pibOf: (image) => {
94
+ const pib = pibByKey.get(`${image.format}:${image.base64}`);
95
+ if (pib === void 0) throw new PptUnsupportedContentError("internal error: an image block reached the drawing writer without first being collected into the document's blip store");
96
+ return pib;
97
+ }
98
+ };
36
99
  }
37
- function writePptStreams(document) {
100
+ function writePptStreams(document, options = {}) {
101
+ options.signal?.throwIfAborted();
38
102
  const { slides } = document;
39
103
  const size = requireOneSlideSize(slides);
104
+ const sink = options.sink ?? NOOP_PPT_DIAGNOSTIC_SINK;
40
105
  const fontNames = collectFontFamilies(slides.map((slide) => slide.shapes.flatMap((shape) => shape.blocks)));
41
106
  const fontIndexOf = (family) => {
42
107
  const index = fontNames.indexOf(family);
43
108
  if (index === -1) throw new PptUnsupportedContentError(`font family '${family}' was not collected into the document's font table before writing`);
44
109
  return index;
45
110
  };
111
+ const store = planBlipStore(slides);
112
+ const strict = options.onUnwritableBlock === "throw";
113
+ const contextFor = (location) => ({
114
+ fontIndexOf,
115
+ blipIndexOf: store.pibOf,
116
+ sink,
117
+ strict,
118
+ location
119
+ });
46
120
  const slidePersistRefs = slides.map((_slide, index) => ({
47
121
  persistIdRef: FIRST_SLIDE_PERSIST_ID + index,
48
122
  slideId: FIRST_SLIDE_ID + index
49
123
  }));
124
+ 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);
125
+ const notesCount = notesIdRefs.filter((id) => id !== NO_NOTES_ID_REF).length;
126
+ const oleEmbeds = planOleEmbeds(slides, options.serialiseEmbeddedObject, FIRST_SLIDE_PERSIST_ID + slides.length + notesCount);
127
+ let shapeCount = 0;
128
+ let maxSpid = 0;
129
+ let drawingCount = 0;
130
+ const account = (drawing) => {
131
+ shapeCount += drawing.shapeCount;
132
+ maxSpid = Math.max(maxSpid, drawing.maxSpid);
133
+ drawingCount += 1;
134
+ };
135
+ const mainMaster = writeMainMaster(size, contextFor("the main master"));
136
+ account(mainMaster);
137
+ const slideContainers = slides.map((slide, index) => {
138
+ const ref = slidePersistRefs[index];
139
+ const notesIdRef = notesIdRefs[index];
140
+ if (ref === void 0 || notesIdRef === void 0) throw new PptUnsupportedContentError("internal error: slide persist reference missing for a slide being written");
141
+ const container = writeSlideContainer(slide.shapes, notesIdRef, contextFor(`slide ${index + 1}`), oleEmbeds.clientDataFor);
142
+ account(container);
143
+ return {
144
+ persistId: ref.persistIdRef,
145
+ bytes: container.bytes
146
+ };
147
+ });
50
148
  const notesPersists = [];
51
149
  const notesContainers = [];
52
- const notesIdRefs = slides.map((slide, index) => {
53
- if (slide.notes.length === 0) return NO_NOTES_ID_REF;
54
- const notesId = FIRST_NOTES_ID + notesPersists.length;
150
+ slides.forEach((slide, index) => {
151
+ const notesId = notesIdRefs[index];
152
+ if (notesId === void 0 || notesId === NO_NOTES_ID_REF) return;
153
+ const persistIdRef = FIRST_SLIDE_PERSIST_ID + slides.length + notesPersists.length;
55
154
  notesPersists.push({
56
- persistIdRef: FIRST_SLIDE_PERSIST_ID + slides.length + notesPersists.length,
155
+ persistIdRef,
57
156
  notesId
58
157
  });
59
- notesContainers.push(writeNotesContainer(FIRST_SLIDE_ID + index, slide.notes, size, fontIndexOf));
60
- return notesId;
158
+ const container = writeNotesContainer(FIRST_SLIDE_ID + index, slide.notes, size, contextFor(`slide ${index + 1}'s speaker notes`));
159
+ account(container);
160
+ notesContainers.push({
161
+ persistId: persistIdRef,
162
+ bytes: container.bytes
163
+ });
61
164
  });
62
165
  const environment = writeEnvironment(fontNames);
63
166
  const documentChildren = [writeDocumentAtom(size)];
167
+ const exObjList = writeExObjListContainer(oleEmbeds.embeds);
168
+ if (exObjList !== void 0) documentChildren.push(exObjList);
64
169
  if (environment !== void 0) documentChildren.push(environment);
170
+ documentChildren.push(writeDrawingGroupContainer(store.blips, {
171
+ spidMax: maxSpid,
172
+ shapeCount,
173
+ drawingCount
174
+ }));
65
175
  documentChildren.push(writeMasterListWithText(MASTER_PERSIST_ID));
66
176
  documentChildren.push(writeSlideListWithText(slidePersistRefs));
67
177
  if (notesPersists.length > 0) documentChildren.push(writeNotesListWithText(notesPersists));
68
178
  const documentContainer = writeContainer(RT_Document, documentChildren);
69
- const persistObjects = [{
70
- persistId: DOCUMENT_PERSIST_ID,
71
- bytes: documentContainer
72
- }, {
73
- persistId: MASTER_PERSIST_ID,
74
- bytes: writeMainMaster(size, fontIndexOf)
75
- }];
76
- slides.forEach((slide, index) => {
77
- const ref = slidePersistRefs[index];
78
- const notesIdRef = notesIdRefs[index];
79
- if (ref === void 0 || notesIdRef === void 0) throw new PptUnsupportedContentError("internal error: slide persist reference missing for a slide being written");
80
- persistObjects.push({
81
- persistId: ref.persistIdRef,
82
- bytes: writeSlideContainer(slide.shapes, notesIdRef, fontIndexOf)
83
- });
84
- });
85
- notesPersists.forEach((persist, index) => {
86
- const bytes = notesContainers[index];
87
- if (bytes === void 0) throw new PptUnsupportedContentError("internal error: notes container missing for a notes persist reference");
88
- persistObjects.push({
89
- persistId: persist.persistIdRef,
90
- bytes
91
- });
92
- });
179
+ const persistObjects = [
180
+ {
181
+ persistId: DOCUMENT_PERSIST_ID,
182
+ bytes: documentContainer
183
+ },
184
+ {
185
+ persistId: MASTER_PERSIST_ID,
186
+ bytes: mainMaster.bytes
187
+ },
188
+ ...slideContainers,
189
+ ...notesContainers,
190
+ ...oleEmbeds.persistObjects
191
+ ];
93
192
  const persistEntries = [];
94
193
  let offset = 0;
95
194
  for (const object of persistObjects) {
@@ -115,8 +214,8 @@ function writePptStreams(document) {
115
214
  powerPointDocumentStream: concatBytes(...persistObjects.map((object) => object.bytes), persistDirectory, userEdit)
116
215
  };
117
216
  }
118
- function writePptContent(document) {
119
- const { currentUserStream, powerPointDocumentStream } = writePptStreams(document);
217
+ function writePptContent(document, options = {}) {
218
+ const { currentUserStream, powerPointDocumentStream } = writePptStreams(document, options);
120
219
  const streams = [{
121
220
  path: CURRENT_USER_STREAM,
122
221
  bytes: currentUserStream
@@ -130,13 +229,13 @@ function writePptContent(document) {
130
229
  });
131
230
  return writeCompoundFile(streams);
132
231
  }
133
- function writePpt(tree) {
232
+ function writePpt(tree, options = {}) {
134
233
  const content = flattenTree(tree);
135
234
  if (content.kind !== "presentation") throw new PptUnsupportedContentError(`ppt-codec's writer only writes presentation documents; got a '${content.kind}' document`);
136
235
  return writePptContent({
137
236
  metadata: content.metadata,
138
237
  slides: content.slides
139
- });
238
+ }, options);
140
239
  }
141
240
  //#endregion
142
241
  export { writePpt, writePptContent, writePptStreams };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ppt-codec",
3
- "version": "1.5.0",
3
+ "version": "1.7.0",
4
4
  "description": "Hand-written PowerPoint 97-2003 binary (.ppt, [MS-PPT]) reader and writer against the shared document-schema.js content pivot.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -79,6 +79,7 @@
79
79
  "packageManager": "pnpm@11.6.0",
80
80
  "dependencies": {
81
81
  "archive-codec": "1.11.0",
82
+ "byte-codec": "1.5.0",
82
83
  "document-schema.js": "7.11.0"
83
84
  },
84
85
  "devDependencies": {