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.
Files changed (58) hide show
  1. package/README.md +70 -58
  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 +20 -15
  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 +14 -6
  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 +14 -6
  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 +94 -0
  31. package/dist/drawing/properties.d.cts +25 -0
  32. package/dist/drawing/properties.d.ts +25 -0
  33. package/dist/drawing/properties.js +83 -0
  34. package/dist/drawing/shapes-write.cjs +204 -17
  35. package/dist/drawing/shapes-write.d.cts +15 -4
  36. package/dist/drawing/shapes-write.d.ts +15 -4
  37. package/dist/drawing/shapes-write.js +206 -18
  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 +38 -1
  43. package/dist/index.d.cts +10 -6
  44. package/dist/index.d.ts +10 -6
  45. package/dist/index.js +8 -4
  46. package/dist/read.cjs +101 -19
  47. package/dist/read.d.cts +3 -2
  48. package/dist/read.d.ts +3 -2
  49. package/dist/read.js +103 -22
  50. package/dist/record/types.cjs +28 -0
  51. package/dist/record/types.d.cts +15 -1
  52. package/dist/record/types.d.ts +15 -1
  53. package/dist/record/types.js +15 -1
  54. package/dist/write.cjs +100 -37
  55. package/dist/write.d.cts +9 -4
  56. package/dist/write.d.ts +9 -4
  57. package/dist/write.js +100 -37
  58. package/package.json +2 -1
package/README.md CHANGED
@@ -8,7 +8,7 @@ Created for [documents.js#817](https://github.com/ExaDev/documents.js/issues/817
8
8
 
9
9
  ## Status
10
10
 
11
- **Under active development. The read path for slide text, geometry and speaker notes is built and tested. A narrower write path now exists too: one slide per input slide, with plain text-box shapes and their speaker notes (basic character formatting, no images/tables/layouts) — genuinely conformant [MS-PPT], verified by writing then reading every fixture back through this package's own reader, and, for speaker notes, against LibreOffice in both directions, but not full read/write parity.** What that means concretely is set out in [What it reads](#what-it-reads)/[What it does not read yet](#what-it-does-not-read-yet) and [What it writes](#what-it-writes)/[What it does not write yet](#what-it-does-not-write-yet) below — every one of those four lists is exhaustive rather than illustrative, so a caller can tell from this page alone whether the format's own feature it cares about is covered.
11
+ **Under active development. The read path for slide text, geometry, pictures, tables, rotation and speaker notes is built and tested. A narrower write path now exists too: one slide per input slide, with text-box, picture, and table shapes (basic character formatting, rotation, no layouts) plus their speaker notes — genuinely conformant [MS-PPT], verified by writing then reading every fixture back through this package's own reader, and, for speaker notes, against LibreOffice in both directions, but not full read/write parity.** What that means concretely is set out in [What it reads](#what-it-reads)/[What it does not read yet](#what-it-does-not-read-yet) and [What it writes](#what-it-writes)/[What it does not write yet](#what-it-does-not-write-yet) below — every one of those four lists is exhaustive rather than illustrative, so a caller can tell from this page alone whether the format's own feature it cares about is covered.
12
12
 
13
13
  ## Why the format is shaped the way it is
14
14
 
@@ -113,11 +113,16 @@ const pptBytes = writePpt(tree);
113
113
 
114
114
  // The flat form: metadata plus ContentSlide[] in -- title/author/dates are
115
115
  // written to a real "\x05SummaryInformation" stream when metadata carries
116
- // any of them (see Metadata).
117
- const bytes = writePptContent({ metadata: {}, slides });
116
+ // any of them (see Metadata). An optional sink hears every block this
117
+ // writer had to drop (an OLE embed, an unblippable image format, a second
118
+ // table on one shape) instead of losing that information silently.
119
+ const bytes = writePptContent(
120
+ { metadata: {}, slides },
121
+ { sink: (diagnostic) => console.warn(diagnostic.code, diagnostic.message) },
122
+ );
118
123
  ```
119
124
 
120
- `writePptStreams(document)` is the same write one level down, returning the two [MS-PPT] streams without wrapping them in a compound file — the mirror of `readPptStreams`, for a caller assembling its own container. Every function throws `PptUnsupportedContentError` (not `PptFormatError`, which is reserved for malformed bytes on the read side) when asked to write content outside this writer's scope: a document that is not a presentation, or slides that do not all share one size (`[MS-PPT]`'s `DocumentAtom` states exactly one slide size for the whole presentation). A block kind this writer does not represent (an image, a table, a construct marker) is not an error — it is silently excluded from the written text body, the same documented-gap convention [What it does not read yet](#what-it-does-not-read-yet) already uses for the reader's own unsupported constructs.
125
+ `writePptStreams(document)` is the same write one level down, returning the two [MS-PPT] streams without wrapping them in a compound file — the mirror of `readPptStreams`, for a caller assembling its own container. Every function throws `PptUnsupportedContentError` (not `PptFormatError`, which is reserved for malformed bytes on the read side) when asked to write content outside this writer's scope: a document that is not a presentation, or slides that do not all share one size (`[MS-PPT]`'s `DocumentAtom` states exactly one slide size for the whole presentation). A block kind this writer does not represent (an embedded object, a construct marker, an image in a format with no blip token) is not an error — it is dropped from the written text body with a diagnostic naming it (see [`src/diagnostics.ts`](src/diagnostics.ts)), the same documented-gap convention [What it does not read yet](#what-it-does-not-read-yet) already uses for the reader's own unsupported constructs.
121
126
 
122
127
  ## What it reads
123
128
 
@@ -133,7 +138,9 @@ The whole path from a file's first byte to a slide's text, record by record:
133
138
  | Masters | `MasterListWithTextContainer` → `MasterPersistAtom` → the persist directory → each `MainMasterContainer`'s own `TextMasterStyleAtom` items and `SlideSchemeColorSchemeAtom` — a real file can carry more than one master, and `SlideAtom.masterIdRef` decides which one a given slide actually follows. |
134
139
  | Slides | `SlidePersistAtom` → the persist directory → each `SlideContainer`'s own `SlideAtom` (`masterIdRef`, `notesIdRef`) and drawing, and the placeholder texts the slide list carries for it. |
135
140
  | Speaker notes | `NotesListWithTextContainer` (the third of the three containers sharing `RT_SlideListWithText`) → `NotesPersistAtom` → the persist directory → each `NotesContainer`, and the `NotesAtom.slideIdRef` naming the presentation slide those notes belong to. The text comes from the notes slide's own drawing, since the notes list — unlike the slide list — carries no texts for an `OutlineTextRefAtom` to reach into. |
136
- | Drawing | `DrawingContainer` → `OfficeArtDgContainer` → the `OfficeArtSpgrContainer`/`OfficeArtSpContainer` tree, `OfficeArtFSP`'s group/patriarch/deleted flags, `OfficeArtClientAnchor` in both its 8-byte `SmallRectStruct` and 16-byte `RectStruct` spellings, and `OfficeArtChildAnchor` mapped through nested `OfficeArtFSPGR` group coordinate systems. |
141
+ | Drawing | `DrawingContainer` → `OfficeArtDgContainer` → the `OfficeArtSpgrContainer`/`OfficeArtSpContainer` tree, `OfficeArtFSP`'s group/patriarch/deleted flags, `OfficeArtClientAnchor` in both its 8-byte `SmallRectStruct` and 16-byte `RectStruct` spellings, `OfficeArtChildAnchor` mapped through nested `OfficeArtFSPGR` group coordinate systems, and a shape's own `OfficeArtFOPT` rotation property (`PROPERTY_ROTATION`, an [MS-OSHARED] 2.2.1.6 Fixed Point). |
142
+ | Pictures | The document-wide `OfficeArtBStoreContainer` (`OfficeArtFBSE` entries, each an inline or `Pictures`-stream-offset blip), resolved through a picture shape's own `pib` property; only the two `MSOBLIPTYPE` tokens `document-schema.js`'s `ContentImageBlock` can hold losslessly (`0x05` JPEG, `0x06` PNG) decode to an image block, sized to the shape's own frame. An unresolvable pib (past the store's end, an empty slot, or a WMF/EMF/TIFF/DIB blip this package does not decode) keeps the shape with empty content rather than dropping the shape. |
143
+ | Tables | A table group's own grid, recovered from its cells' rectangles rather than from any row/column record — the format states none: row and column boundaries are the cells' own distinct tops and lefts, a cell lands at the intersection of its own top and left, and a real producer's degenerate zero-width/zero-height gridline shapes are excluded from the grid by that same geometry check rather than treated as cells. |
137
144
  | Text | `OfficeArtClientTextbox`, `TextHeaderAtom`, `TextCharsAtom` (UTF-16) and `TextBytesAtom` (one byte per character), `OutlineTextRefAtom` indirection into the slide list, and the paragraph split on the stored `\r`. |
138
145
  | Formatting | `StyleTextPropAtom`: `TextPFRun`/`TextPFException` (indent level, alignment, line spacing, space before/after, left margin, and first-line indent) and `TextCFRun`/`TextCFException` (bold, italic, underline, shadow, emboss, typeface reference, size in points, and a `ColorIndexStruct` colour — literal sRGB or a colour-scheme slot reference), each read in the spec's **declared field order** rather than its mask-bit order — the two differ, and following the mask-bit order desynchronises every field after the first divergence. A field a run states neither directly nor at all resolves against the applicable master's own cascade and colour scheme — see [Master and colour inheritance](#master-and-colour-inheritance). |
139
146
 
@@ -145,7 +152,9 @@ Each of these is a real construct of the format that this package currently igno
145
152
 
146
153
  - **`DocumentSummaryInformation`'s extended and user-defined properties** (company, manager, custom properties) — a genuinely different stream from the one [Metadata](#metadata) covers, not attempted at all.
147
154
  - **Per-shape text insets.** Every shape reports PowerPoint's own defaults (0.1 inch left and right, 0.05 inch top and bottom); a per-shape override lives in the shape's `OfficeArtFOPT` property table, which is not read.
148
- - **Images, tables, and OLE embeddings.** A picture shape, a table object, and an embedded or linked OLE object all read as a shape with geometry and no blocks. `ExObjListContainer` and the `ExOleObjStg` persist objects are not walked.
155
+ - **OLE embeddings.** An embedded or linked OLE object still reads as a shape with geometry and no blocks `ExObjListContainer` and the `ExOleObjStg` persist objects are not walked. Pictures and tables are read (see [Pictures](#what-it-reads) and [Tables](#what-it-reads) in the table above); only OLE remains geometry-only.
156
+ - **Image formats beyond PNG and JPEG.** A blip in any other `MSOBLIPTYPE` (WMF/EMF metafile, PICT, a raw DIB, TIFF) reads as no image at all, keeping the shape's geometry with empty content — the same convention an unresolvable pib already uses.
157
+ - **Cell merges in a read table.** [MS-PPT]'s own table shapes are a strict grid of one shape per cell with no merge record at all (merged cells arrived only with the 2010 XML format), so a read table never states `colSpan`/`rowSpan`.
149
158
  - **Shapes with no anchor.** A shape carrying neither an `OfficeArtClientAnchor` nor an `OfficeArtChildAnchor` is dropped, because `ContentShape` has no way to say "positioned, but unknown where".
150
159
  - **Hyperlinks and bullets.** `InteractiveInfo`/`TextInteractiveInfoAtom` and `TextPFException`'s bullet fields are parsed past correctly but not surfaced.
151
160
  - **Animations, transitions, comments, headers and footers, and the metacharacter atoms** (slide number, date, header, footer).
@@ -157,18 +166,20 @@ Each of these is a real construct of the format that this package currently igno
157
166
 
158
167
  The whole path from a `ContentSlide[]` to a real `.ppt` file's bytes, mirroring the read-side table above in the opposite direction:
159
168
 
160
- | Layer | Records |
161
- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
162
- | Container | The `Current User` and `PowerPoint Document` streams, wrapped in a real [MS-CFB] compound file through `archive-codec`'s conformant writer. |
163
- | Record framing | The generic 8-byte `RecordHeader`, atom and container builders — `record/write.ts`, shared by every writer module below and by this package's own test fixtures. |
164
- | Edit resolution | A single-edit persist layer: one `CurrentUserAtom` pointing at one `UserEditAtom` pointing at one `PersistDirectoryAtom` whose entries name the stream offset of the document container, the master, every slide container and every notes container — never an incremental append, since nothing about this writer's own output needs a second generation of any object. |
165
- | Document | `DocumentContainer` → `DocumentAtom` (one slide size, in master units, taken from the input's own first slide and required to match every other slide — see below), an `Environment`/`FontCollectionContainer` built from every distinct `fontFamily` a run names, a `MasterListWithTextContainer` naming the one master, a `SlideListWithTextContainer` carrying one `SlidePersistAtom` per slide with no placeholder texts, and — only when some slide has notes — a `NotesListWithTextContainer`. |
166
- | Master | One minimal `MainMasterContainer`: its own `SlideAtom`, the title/body/notes `TextMasterStyleAtom` items [MS-PPT] 2.5.3 requires (each stating `cLevels` 0, so every level falls through to the document's own text styles), the five `SL_TitleBody` placeholder shapes a main master must carry, and a default `SlideSchemeColorSchemeAtom`. It exists because speaker notes need it — see below. |
167
- | Slides | One `SlideContainer` per input slide, each opening with a `SlideAtom` that names the master it follows and, when the slide has notes, the notes slide holding them, then its own `DrawingContainer`. |
168
- | Speaker notes | One `NotesContainer` per slide that actually has notes — a `NotesAtom` naming that slide, then a `DrawingContainer` whose single text box carries the notes, one paragraph per line, then the `SlideSchemeColorSchemeAtom` [MS-PPT] 2.5.6 requires of one — the notes slide's own `NotesAtom.slideFlags` leaves `fMasterScheme` clear, so it inherits no scheme and has to state one. A slide with no notes gets no notes slide at all rather than an empty one. |
169
- | Drawing | `OfficeArtDgContainer` → one `OfficeArtSpgrContainer` (the patriarch group every real drawing carries) → one plain `OfficeArtSpContainer` per shape, each anchored in slide coordinates via a 32-bit `OfficeArtClientAnchor` (`RectStruct`, never the 16-bit `SmallRectStruct`) — no grouping, no `OfficeArtChildAnchor` nesting. |
170
- | Text | Every shape carries its own text directly on its `OfficeArtClientTextbox` (`TextHeaderAtom` + a UTF-16 `TextCharsAtom`) rather than through the `OutlineTextRefAtom` placeholder indirection into the slide list a plain text box is all this writer produces, so there is no separate placeholder text to route through the document's own slide list. |
171
- | Formatting | `StyleTextPropAtom`: one `TextPFRun` per paragraph (indent level, alignment, line spacing, space before/after, left margin, and first-line indent) and one `TextCFRun` per character run (bold, italic, underline, a font-collection reference, size in points, and a literal sRGB `ColorIndexStruct` colour), fields written in the identical spec-declared order `readTextPFException`/`readTextCFException` parse them in. |
169
+ | Layer | Records |
170
+ | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
171
+ | Container | The `Current User` and `PowerPoint Document` streams, wrapped in a real [MS-CFB] compound file through `archive-codec`'s conformant writer. |
172
+ | Record framing | The generic 8-byte `RecordHeader`, atom and container builders — `record/write.ts`, shared by every writer module below and by this package's own test fixtures. |
173
+ | Edit resolution | A single-edit persist layer: one `CurrentUserAtom` pointing at one `UserEditAtom` pointing at one `PersistDirectoryAtom` whose entries name the stream offset of the document container, the master, every slide container and every notes container — never an incremental append, since nothing about this writer's own output needs a second generation of any object. |
174
+ | Document | `DocumentContainer` → `DocumentAtom` (one slide size, in master units, taken from the input's own first slide and required to match every other slide — see below), an `Environment`/`FontCollectionContainer` built from every distinct `fontFamily` a run names, a `MasterListWithTextContainer` naming the one master, a `SlideListWithTextContainer` carrying one `SlidePersistAtom` per slide with no placeholder texts, and — only when some slide has notes — a `NotesListWithTextContainer`. |
175
+ | Master | One minimal `MainMasterContainer`: its own `SlideAtom`, the title/body/notes `TextMasterStyleAtom` items [MS-PPT] 2.5.3 requires (each stating `cLevels` 0, so every level falls through to the document's own text styles), the five `SL_TitleBody` placeholder shapes a main master must carry, and a default `SlideSchemeColorSchemeAtom`. It exists because speaker notes need it — see below. |
176
+ | Slides | One `SlideContainer` per input slide, each opening with a `SlideAtom` that names the master it follows and, when the slide has notes, the notes slide holding them, then its own `DrawingContainer`. |
177
+ | Speaker notes | One `NotesContainer` per slide that actually has notes — a `NotesAtom` naming that slide, then a `DrawingContainer` whose single text box carries the notes, one paragraph per line, then the `SlideSchemeColorSchemeAtom` [MS-PPT] 2.5.6 requires of one — the notes slide's own `NotesAtom.slideFlags` leaves `fMasterScheme` clear, so it inherits no scheme and has to state one. A slide with no notes gets no notes slide at all rather than an empty one. |
178
+ | Drawing | `OfficeArtDgContainer` → one `OfficeArtSpgrContainer` (the patriarch group every real drawing carries) → one plain `OfficeArtSpContainer` per shape, each anchored in slide coordinates via a 32-bit `OfficeArtClientAnchor` (`RectStruct`, never the 16-bit `SmallRectStruct`), and a shape's own `rotationDeg` as an `OfficeArtFOPT` `PROPERTY_ROTATION` entry — no grouping otherwise, beyond the table group below. |
179
+ | Pictures | The first `png`/`jpeg` image block on a shape becomes that shape's one blip-store reference (`blipIndexOf`, feeding the document-wide `OfficeArtBStoreContainer` every picture shares); an image in any other format, or a second image on a shape whose single blip reference an earlier one already claimed, is dropped with a diagnostic (`ppt/image-dropped`) rather than silently discarded. |
180
+ | Tables | A table block turns its whole shape into a table group in the spelling a real PowerPoint-authored file carries (confirmed against Microsoft Office PowerPoint's own output and Apache POI's `table_test.ppt` fixture): an `OfficeArtFSPGR` child coordinate system identical to the shape's own client anchor, `fIsTable`/`tableRowProperties` in the tertiary property table, and one plain text-box shape per cell at its own `OfficeArtChildAnchor` grid position the same grid `tableBlockFor` reads back. A cell's `colSpan`/`rowSpan` is dropped with a diagnostic (`ppt/table-span-dropped`), since the format has no merge record to state it in. |
181
+ | Text | Every shape carries its own text directly on its `OfficeArtClientTextbox` (`TextHeaderAtom` + a UTF-16 `TextCharsAtom`) rather than through the `OutlineTextRefAtom` placeholder indirection into the slide list — a plain text box is all this writer produces, so there is no separate placeholder text to route through the document's own slide list. |
182
+ | Formatting | `StyleTextPropAtom`: one `TextPFRun` per paragraph (indent level, alignment, line spacing, space before/after, left margin, and first-line indent) and one `TextCFRun` per character run (bold, italic, underline, a font-collection reference, size in points, and a literal sRGB `ColorIndexStruct` colour), fields written in the identical spec-declared order `readTextPFException`/`readTextCFException` parse them in. |
172
183
 
173
184
  Geometry is converted from points to master units on the way in, rounding to the nearest whole master unit (1/576 inch) — the format's own smallest unit of length.
174
185
 
@@ -194,9 +205,9 @@ The round trip above proves the reader and writer agree with each other. Speaker
194
205
 
195
206
  Each of these is either a real construct this writer deliberately does not attempt (a smaller, genuinely correct core rather than a larger, unreliable one — see the two tables above for exactly what it does write), or a `ContentShape`/`ContentParagraph`/`ContentRun` field this writer's own OfficeArt shape tree has nowhere to carry:
196
207
 
197
- - **Images, tables, and OLE embeddings.** A shape whose blocks include an `image`, `table`, or `embeddedObject` block silently drops that block from the written text body — see [Writing a document](#writing-a-document) — rather than attempting a picture, table, or OLE object shape.
208
+ - **OLE embeddings.** A shape whose blocks include an `embeddedObject` block drops it from the written text body, with a `ppt/block-dropped` diagnostic naming it — see [Writing a document](#writing-a-document) — rather than attempting an OLE object shape. Pictures and tables are written (see [Pictures](#what-it-writes) and [Tables](#what-it-writes) in the table above).
198
209
  - **Shapes with no text.** Written with a client anchor and no `OfficeArtClientTextbox` at all, matching how the reader represents one (`blocks: []`); nothing is lost, since there was nothing to write.
199
- - **Grouped shapes, rotation, and any coordinate system beyond a plain `OfficeArtClientAnchor`.** Every shape this writer emits is an ungrouped, unrotated rectangle in slide coordinates; `ContentShape.rotationDeg` is not written, and there is no `OfficeArtChildAnchor`/`OfficeArtFSPGR` group nesting.
210
+ - **Grouped shapes beyond a table, and any coordinate system beyond a plain `OfficeArtClientAnchor` or the table group's own `OfficeArtFSPGR`.** Every non-table shape this writer emits is an ungrouped rectangle in slide coordinates; there is no general `OfficeArtChildAnchor`/`OfficeArtFSPGR` group nesting outside the one a table block itself produces. `ContentShape.rotationDeg` is written (see [Drawing](#what-it-writes) in the table above).
200
211
  - **Per-shape text insets, autofit, and paint order.** `ContentShape.insetLeftPt`/`insetTopPt`/`insetRightPt`/`insetBottomPt`, `fontScale`, `lineSpacingReduction`, and `paintOrder` have no `OfficeArtFOPT` property table to land in, since this writer does not build one.
201
212
  - **Master content, layouts, and scheme colours.** A `MainMasterContainer` and its `MasterListWithTextContainer` are written, but only as the minimum [MS-PPT] requires of one (see [Why a writer of plain text-box slides writes a master slide](#why-a-writer-of-plain-text-box-slides-writes-a-master-slide)): its five placeholder shapes carry no text, its `TextMasterStyleAtom` items state no style level of their own, and its `SlideSchemeColorSchemeAtom` is a fixed default rather than anything the input chose. There are still no slide layouts, and every character run's colour must already be a literal, since no scheme is there to resolve one against.
202
213
  - **Notes masters, and a notes page geometry of its own.** No `NotesContainer` is written for the notes master, and `DocumentAtom.notesMasterPersistIdRef` stays 0, so each notes slide inherits nothing (its `NotesAtom.slideFlags` is clear) and states the same fixed default `SlideSchemeColorSchemeAtom` the master does rather than a scheme of the input's choosing. The notes page is the same size as the slide, because `ContentSlide` carries no notes-page geometry to state a different one from, and the notes text box is placed in the lower half of it.
@@ -205,7 +216,7 @@ Each of these is either a real construct this writer deliberately does not attem
205
216
  - **Construct markers.** A `constructStart`/`constructEnd` pair (or any other non-`paragraph` block kind) is excluded from the written text body exactly like an image or table block, per [Writing a document](#writing-a-document).
206
217
  - **Alignment values the shared schema has no name for.** The mirror of the read-side gap: `Tx_ALIGNDistributed`, `Tx_ALIGNThaiDistributed`, and `Tx_ALIGNJustifyLow` are never written, since `Alignment` has no member naming them.
207
218
  - **Fractional character sizes.** `ContentRun.sizePt` is rounded to the nearest whole point, since `TextCFException`'s size field is a plain 16-bit integer.
208
- - **Fonts, tables, animations, transitions, comments, and the metacharacter atoms.** Nothing here is written for the same reason none of it is read yet — see the corresponding entries in [What it does not read yet](#what-it-does-not-read-yet).
219
+ - **Fonts (custom embedding), animations, transitions, comments, and the metacharacter atoms.** Nothing here is written for the same reason none of it is read yet — see the corresponding entries in [What it does not read yet](#what-it-does-not-read-yet).
209
220
 
210
221
  ## Metadata
211
222
 
@@ -231,43 +242,44 @@ import { readRecordAt } from "ppt-codec/record/tree";
231
242
  import { readStyleTextPropAtom } from "ppt-codec/text/style";
232
243
  ```
233
244
 
234
- | Module | What it owns |
235
- | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
236
- | `record/header` | The generic 8-byte record header and the container/atom distinction. |
237
- | `record/types` | The `RecordType` values this reader dispatches on, plus the [MS-ODRAW] types the drawing walk crosses into. |
238
- | `record/tree` | Offset-addressed records, sibling sequences, child walks, typed-descendant search. |
239
- | `record/write` | Byte primitives and the atom/container builders every writer module below composes records from -- the write-side mirror of `record/header`/`record/tree`, and what this package's own test fixtures build on too. |
240
- | `stream/current-user` | `CurrentUserAtom`: where the live edit is, and whether the file is encrypted. |
241
- | `stream/current-user-write` | Writes a real `CurrentUserAtom` pointing at the single edit this writer always produces. |
242
- | `stream/persist` | `UserEditAtom`, `PersistDirectoryAtom`, and the persist directory the edit chain builds. |
243
- | `stream/persist-write` | Writes a single-edit `UserEditAtom`/`PersistDirectoryAtom` pair covering the document container and every slide container. |
244
- | `encryption` | `readDocumentEncryptionAtom`, `decryptPptDocumentStream` — [MS-OFFCRYPTO] 2.3.5 RC4 CryptoAPI decryption, wired against `archive-codec`'s own key derivation (see [Encryption](#encryption)). |
245
- | `document/document-atom` | `DocumentAtom`: slide and notes sizes, master persist references. |
246
- | `document/document-atom-write` | Writes a `DocumentAtom` for the one slide size every slide must share. |
247
- | `document/fonts` | The font collection, resolved to typeface names a `FontIndexRef` indexes. |
248
- | `document/fonts-write` | Writes an `Environment`/`FontCollectionContainer` from a document's own distinct font families. |
249
- | `document/slide-list` | `SlideListWithTextContainer`: each slide's persist reference and its placeholder texts. |
250
- | `document/slide-list-write` | Writes a `SlideListWithTextContainer` naming each slide's persist reference, with no placeholder texts. |
251
- | `document/notes-list` | `NotesListWithTextContainer`: each notes slide's persist reference and its notes identifier. Its own module rather than a parameter of `slide-list`, because the container holds no texts and `NotesPersistAtom` spends on a reserved field what `SlidePersistAtom` spends on `cTexts`. |
252
- | `document/notes-list-write` | Writes that container from the same `NotesPersist` shape the reader produces. |
253
- | `document/notes` | A `NotesContainer`: its `NotesAtom` (which slide the notes belong to) and the notes text its drawing carries. |
254
- | `document/notes-write` | Writes a `NotesContainer` for one slide's notes, through the same drawing writer a slide's own shapes go through. |
255
- | `document/master` | `readSlideAtom` (`masterIdRef`/`notesIdRef`), `buildMasterStyleTable`, and `resolveCharacterProperties`/`resolveParagraphProperties` — the master text-formatting cascade a run whose own fields are absent resolves against (see [Master and colour inheritance](#master-and-colour-inheritance)). |
256
- | `document/master-write` | The minimal `MainMasterContainer` and `MasterListWithTextContainer`, plus the `SlideAtom` every slide needs in order to name that master and its own notes slide. |
257
- | `document/color-scheme` | `readSlideSchemeColorSchemeAtom`, `resolveSchemeColor` — resolves a `ColorIndexStruct`'s scheme-slot reference against the slide's (or its master's) own colour scheme. |
258
- | `document/color-scheme-write` | The `SlideSchemeColorSchemeAtom` [MS-PPT] 2.9.51 gives four different containers, two of which this writer produces — the main master and every notes slide — so it belongs to neither of them. |
259
- | `drawing/shapes` | The OfficeArt shape tree, flattened, with every anchor resolved into slide coordinates through its enclosing groups. |
260
- | `drawing/shapes-write` | Writes the patriarch group and one plain, anchored `OfficeArtSpContainer` per shape. |
261
- | `text/atoms` | The two text-body spellings, the text-type enumeration, and the paragraph split. |
262
- | `text/style` | `StyleTextPropAtom`'s two run arrays and their mask-driven exception structures. |
263
- | `text/style-write` | Writes a `StyleTextPropAtom` from the same `StyleRun`/`ParagraphProperties`/`CharacterProperties` shapes `text/style` reads into. |
264
- | `content` | The mapping of PowerPoint's character-counted runs onto the schema's paragraph-owned runs. |
265
- | `content-write` | The inverse: a shape's `ContentBlock[]` to the flat character-counted text body and `StyleTextProps` `text/style-write` needs. |
266
- | `metadata` | Wraps `archive-codec`'s own `SummaryInformationProperties` <-> `LayoutMetadata` mapping with this package's `createdIso`/`modifiedIso` date validation, throwing `PptUnsupportedContentError` for a malformed one rather than letting an opaque `RangeError` escape the FILETIME conversion (see [Metadata](#metadata)). |
267
- | `read` | The whole read pipeline, and the `readPpt`/`readPptContent`/`readPptStreams` surface. |
268
- | `write` | The whole write pipeline, and the `writePpt`/`writePptContent`/`writePptStreams` surface. |
269
- | `units` | Master units to points, and points to master units. |
270
- | `errors` | `PptFormatError` for malformed input, `PptEncryptedError` for encrypted input given no password, an incorrect one, or an encryption scheme this package does not implement (anything other than RC4 CryptoAPI), `PptUnsupportedContentError` for well-formed content this package's writer cannot express. |
245
+ | Module | What it owns |
246
+ | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
247
+ | `record/header` | The generic 8-byte record header and the container/atom distinction. |
248
+ | `record/types` | The `RecordType` values this reader dispatches on, plus the [MS-ODRAW] types the drawing walk crosses into. |
249
+ | `record/tree` | Offset-addressed records, sibling sequences, child walks, typed-descendant search. |
250
+ | `record/write` | Byte primitives and the atom/container builders every writer module below composes records from -- the write-side mirror of `record/header`/`record/tree`, and what this package's own test fixtures build on too. |
251
+ | `stream/current-user` | `CurrentUserAtom`: where the live edit is, and whether the file is encrypted. |
252
+ | `stream/current-user-write` | Writes a real `CurrentUserAtom` pointing at the single edit this writer always produces. |
253
+ | `stream/persist` | `UserEditAtom`, `PersistDirectoryAtom`, and the persist directory the edit chain builds. |
254
+ | `stream/persist-write` | Writes a single-edit `UserEditAtom`/`PersistDirectoryAtom` pair covering the document container and every slide container. |
255
+ | `encryption` | `readDocumentEncryptionAtom`, `decryptPptDocumentStream` — [MS-OFFCRYPTO] 2.3.5 RC4 CryptoAPI decryption, wired against `archive-codec`'s own key derivation (see [Encryption](#encryption)). |
256
+ | `document/document-atom` | `DocumentAtom`: slide and notes sizes, master persist references. |
257
+ | `document/document-atom-write` | Writes a `DocumentAtom` for the one slide size every slide must share. |
258
+ | `document/fonts` | The font collection, resolved to typeface names a `FontIndexRef` indexes. |
259
+ | `document/fonts-write` | Writes an `Environment`/`FontCollectionContainer` from a document's own distinct font families. |
260
+ | `document/slide-list` | `SlideListWithTextContainer`: each slide's persist reference and its placeholder texts. |
261
+ | `document/slide-list-write` | Writes a `SlideListWithTextContainer` naming each slide's persist reference, with no placeholder texts. |
262
+ | `document/notes-list` | `NotesListWithTextContainer`: each notes slide's persist reference and its notes identifier. Its own module rather than a parameter of `slide-list`, because the container holds no texts and `NotesPersistAtom` spends on a reserved field what `SlidePersistAtom` spends on `cTexts`. |
263
+ | `document/notes-list-write` | Writes that container from the same `NotesPersist` shape the reader produces. |
264
+ | `document/notes` | A `NotesContainer`: its `NotesAtom` (which slide the notes belong to) and the notes text its drawing carries. |
265
+ | `document/notes-write` | Writes a `NotesContainer` for one slide's notes, through the same drawing writer a slide's own shapes go through. |
266
+ | `document/master` | `readSlideAtom` (`masterIdRef`/`notesIdRef`), `buildMasterStyleTable`, and `resolveCharacterProperties`/`resolveParagraphProperties` — the master text-formatting cascade a run whose own fields are absent resolves against (see [Master and colour inheritance](#master-and-colour-inheritance)). |
267
+ | `document/master-write` | The minimal `MainMasterContainer` and `MasterListWithTextContainer`, plus the `SlideAtom` every slide needs in order to name that master and its own notes slide. |
268
+ | `document/color-scheme` | `readSlideSchemeColorSchemeAtom`, `resolveSchemeColor` — resolves a `ColorIndexStruct`'s scheme-slot reference against the slide's (or its master's) own colour scheme. |
269
+ | `document/color-scheme-write` | The `SlideSchemeColorSchemeAtom` [MS-PPT] 2.9.51 gives four different containers, two of which this writer produces — the main master and every notes slide — so it belongs to neither of them. |
270
+ | `drawing/shapes` | The OfficeArt shape tree, flattened, with every anchor resolved into slide coordinates through its enclosing groups. |
271
+ | `drawing/shapes-write` | Writes the patriarch group and one plain, anchored `OfficeArtSpContainer` per shape. |
272
+ | `text/atoms` | The two text-body spellings, the text-type enumeration, and the paragraph split. |
273
+ | `text/style` | `StyleTextPropAtom`'s two run arrays and their mask-driven exception structures. |
274
+ | `text/style-write` | Writes a `StyleTextPropAtom` from the same `StyleRun`/`ParagraphProperties`/`CharacterProperties` shapes `text/style` reads into. |
275
+ | `content` | The mapping of PowerPoint's character-counted runs onto the schema's paragraph-owned runs. |
276
+ | `content-write` | The inverse: a shape's `ContentBlock[]` to the flat character-counted text body and `StyleTextProps` `text/style-write` needs. |
277
+ | `metadata` | Wraps `archive-codec`'s own `SummaryInformationProperties` <-> `LayoutMetadata` mapping with this package's `createdIso`/`modifiedIso` date validation, throwing `PptUnsupportedContentError` for a malformed one rather than letting an opaque `RangeError` escape the FILETIME conversion (see [Metadata](#metadata)). |
278
+ | `read` | The whole read pipeline, and the `readPpt`/`readPptContent`/`readPptStreams` surface. |
279
+ | `write` | The whole write pipeline, and the `writePpt`/`writePptContent`/`writePptStreams` surface. |
280
+ | `units` | Master units to points, and points to master units. |
281
+ | `errors` | `PptFormatError` for malformed input, `PptEncryptedError` for encrypted input given no password, an incorrect one, or an encryption scheme this package does not implement (anything other than RC4 CryptoAPI), `PptUnsupportedContentError` for well-formed content this package's writer cannot express. |
282
+ | `diagnostics` | `PptDiagnostic`/`PptDiagnosticSink`/`NOOP_PPT_DIAGNOSTIC_SINK` and the stable `PptDiagnosticCodes` a caller branches on — the write-side channel a dropped image, block, or table span fires through, matching the shape markdown-codec's, pdf-codec's, epub-codec's, and rtf-codec's own diagnostic channels already use. |
271
283
 
272
284
  ### Every fixture is built from the specification, not captured
273
285
 
@@ -0,0 +1,48 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/base64.ts
3
+ const TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4
+ const DECODE = (() => {
5
+ const map = (/* @__PURE__ */ new Uint8Array(256)).fill(255);
6
+ for (let index = 0; index < 64; index += 1) map[TABLE.charCodeAt(index)] = index;
7
+ return map;
8
+ })();
9
+ function bytesToBase64(bytes) {
10
+ let out = "";
11
+ const len = bytes.length;
12
+ for (let index = 0; index < len; index += 3) {
13
+ const b0 = bytes[index] ?? 0;
14
+ const b1 = index + 1 < len ? bytes[index + 1] ?? 0 : 0;
15
+ const b2 = index + 2 < len ? bytes[index + 2] ?? 0 : 0;
16
+ out += TABLE.charAt(b0 >> 2);
17
+ out += TABLE.charAt((b0 & 3) << 4 | b1 >> 4);
18
+ out += index + 1 < len ? TABLE.charAt((b1 & 15) << 2 | b2 >> 6) : "=";
19
+ out += index + 2 < len ? TABLE.charAt(b2 & 63) : "=";
20
+ }
21
+ return out;
22
+ }
23
+ function base64ToBytes(base64) {
24
+ const clean = base64.replace(/[^A-Za-z0-9+/=]/g, "");
25
+ const len = clean.length;
26
+ const out = new Uint8Array(len * 3 / 4 | 0);
27
+ let position = 0;
28
+ for (let index = 0; index < len; index += 4) {
29
+ const c0 = DECODE[clean.charCodeAt(index)] ?? 255;
30
+ const c1 = DECODE[clean.charCodeAt(index + 1)] ?? 255;
31
+ const c2 = clean.charCodeAt(index + 2);
32
+ const c3 = clean.charCodeAt(index + 3);
33
+ if (c0 === 255 || c1 === 255) throw new Error("invalid base64 input");
34
+ out[position++] = c0 << 2 | c1 >> 4;
35
+ if (c2 !== 61) {
36
+ const d2 = DECODE[c2] ?? 255;
37
+ out[position++] = (c1 & 15) << 4 | d2 >> 2;
38
+ if (c3 !== 61) {
39
+ const d3 = DECODE[c3] ?? 255;
40
+ out[position++] = (d2 & 3) << 6 | d3;
41
+ }
42
+ }
43
+ }
44
+ return out.subarray(0, position);
45
+ }
46
+ //#endregion
47
+ exports.base64ToBytes = base64ToBytes;
48
+ exports.bytesToBase64 = bytesToBase64;
@@ -0,0 +1,5 @@
1
+ //#region src/base64.d.ts
2
+ declare function bytesToBase64(bytes: Uint8Array): string;
3
+ declare function base64ToBytes(base64: string): Uint8Array<ArrayBuffer>;
4
+ //#endregion
5
+ export { base64ToBytes, bytesToBase64 };
@@ -0,0 +1,5 @@
1
+ //#region src/base64.d.ts
2
+ declare function bytesToBase64(bytes: Uint8Array): string;
3
+ declare function base64ToBytes(base64: string): Uint8Array<ArrayBuffer>;
4
+ //#endregion
5
+ export { base64ToBytes, bytesToBase64 };
package/dist/base64.js ADDED
@@ -0,0 +1,46 @@
1
+ //#region src/base64.ts
2
+ const TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
3
+ const DECODE = (() => {
4
+ const map = (/* @__PURE__ */ new Uint8Array(256)).fill(255);
5
+ for (let index = 0; index < 64; index += 1) map[TABLE.charCodeAt(index)] = index;
6
+ return map;
7
+ })();
8
+ function bytesToBase64(bytes) {
9
+ let out = "";
10
+ const len = bytes.length;
11
+ for (let index = 0; index < len; index += 3) {
12
+ const b0 = bytes[index] ?? 0;
13
+ const b1 = index + 1 < len ? bytes[index + 1] ?? 0 : 0;
14
+ const b2 = index + 2 < len ? bytes[index + 2] ?? 0 : 0;
15
+ out += TABLE.charAt(b0 >> 2);
16
+ out += TABLE.charAt((b0 & 3) << 4 | b1 >> 4);
17
+ out += index + 1 < len ? TABLE.charAt((b1 & 15) << 2 | b2 >> 6) : "=";
18
+ out += index + 2 < len ? TABLE.charAt(b2 & 63) : "=";
19
+ }
20
+ return out;
21
+ }
22
+ function base64ToBytes(base64) {
23
+ const clean = base64.replace(/[^A-Za-z0-9+/=]/g, "");
24
+ const len = clean.length;
25
+ const out = new Uint8Array(len * 3 / 4 | 0);
26
+ let position = 0;
27
+ for (let index = 0; index < len; index += 4) {
28
+ const c0 = DECODE[clean.charCodeAt(index)] ?? 255;
29
+ const c1 = DECODE[clean.charCodeAt(index + 1)] ?? 255;
30
+ const c2 = clean.charCodeAt(index + 2);
31
+ const c3 = clean.charCodeAt(index + 3);
32
+ if (c0 === 255 || c1 === 255) throw new Error("invalid base64 input");
33
+ out[position++] = c0 << 2 | c1 >> 4;
34
+ if (c2 !== 61) {
35
+ const d2 = DECODE[c2] ?? 255;
36
+ out[position++] = (c1 & 15) << 4 | d2 >> 2;
37
+ if (c3 !== 61) {
38
+ const d3 = DECODE[c3] ?? 255;
39
+ out[position++] = (d2 & 3) << 6 | d3;
40
+ }
41
+ }
42
+ }
43
+ return out.subarray(0, position);
44
+ }
45
+ //#endregion
46
+ export { base64ToBytes, bytesToBase64 };
@@ -0,0 +1,16 @@
1
+ //#region src/diagnostics.d.ts
2
+ type PptDiagnosticSeverity = "info" | "warning";
3
+ interface PptDiagnostic {
4
+ readonly code: string;
5
+ readonly severity: PptDiagnosticSeverity;
6
+ readonly message: string;
7
+ }
8
+ type PptDiagnosticSink = (diagnostic: PptDiagnostic) => void;
9
+ declare const NOOP_PPT_DIAGNOSTIC_SINK: PptDiagnosticSink;
10
+ declare const PptDiagnosticCodes: {
11
+ readonly IMAGE_DROPPED: "ppt/image-dropped";
12
+ readonly BLOCK_DROPPED: "ppt/block-dropped";
13
+ readonly TABLE_SPAN_DROPPED: "ppt/table-span-dropped";
14
+ };
15
+ //#endregion
16
+ export { PptDiagnosticSink as a, PptDiagnosticSeverity as i, PptDiagnostic as n, PptDiagnosticCodes as r, NOOP_PPT_DIAGNOSTIC_SINK as t };
@@ -0,0 +1,16 @@
1
+ //#region src/diagnostics.d.ts
2
+ type PptDiagnosticSeverity = "info" | "warning";
3
+ interface PptDiagnostic {
4
+ readonly code: string;
5
+ readonly severity: PptDiagnosticSeverity;
6
+ readonly message: string;
7
+ }
8
+ type PptDiagnosticSink = (diagnostic: PptDiagnostic) => void;
9
+ declare const NOOP_PPT_DIAGNOSTIC_SINK: PptDiagnosticSink;
10
+ declare const PptDiagnosticCodes: {
11
+ readonly IMAGE_DROPPED: "ppt/image-dropped";
12
+ readonly BLOCK_DROPPED: "ppt/block-dropped";
13
+ readonly TABLE_SPAN_DROPPED: "ppt/table-span-dropped";
14
+ };
15
+ //#endregion
16
+ export { PptDiagnosticSink as a, PptDiagnosticSeverity as i, PptDiagnostic as n, PptDiagnosticCodes as r, NOOP_PPT_DIAGNOSTIC_SINK as t };
@@ -0,0 +1,11 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/diagnostics.ts
3
+ const NOOP_PPT_DIAGNOSTIC_SINK = () => {};
4
+ const PptDiagnosticCodes = {
5
+ IMAGE_DROPPED: "ppt/image-dropped",
6
+ BLOCK_DROPPED: "ppt/block-dropped",
7
+ TABLE_SPAN_DROPPED: "ppt/table-span-dropped"
8
+ };
9
+ //#endregion
10
+ exports.NOOP_PPT_DIAGNOSTIC_SINK = NOOP_PPT_DIAGNOSTIC_SINK;
11
+ exports.PptDiagnosticCodes = PptDiagnosticCodes;
@@ -0,0 +1,2 @@
1
+ import { a as PptDiagnosticSink, i as PptDiagnosticSeverity, n as PptDiagnostic, r as PptDiagnosticCodes, t as NOOP_PPT_DIAGNOSTIC_SINK } from "./diagnostics-CqxAnubw.cjs";
2
+ export { NOOP_PPT_DIAGNOSTIC_SINK, PptDiagnostic, PptDiagnosticCodes, PptDiagnosticSeverity, PptDiagnosticSink };
@@ -0,0 +1,2 @@
1
+ import { a as PptDiagnosticSink, i as PptDiagnosticSeverity, n as PptDiagnostic, r as PptDiagnosticCodes, t as NOOP_PPT_DIAGNOSTIC_SINK } from "./diagnostics-CqxAnubw.js";
2
+ export { NOOP_PPT_DIAGNOSTIC_SINK, PptDiagnostic, PptDiagnosticCodes, PptDiagnosticSeverity, PptDiagnosticSink };
@@ -0,0 +1,9 @@
1
+ //#region src/diagnostics.ts
2
+ const NOOP_PPT_DIAGNOSTIC_SINK = () => {};
3
+ const PptDiagnosticCodes = {
4
+ IMAGE_DROPPED: "ppt/image-dropped",
5
+ BLOCK_DROPPED: "ppt/block-dropped",
6
+ TABLE_SPAN_DROPPED: "ppt/table-span-dropped"
7
+ };
8
+ //#endregion
9
+ export { NOOP_PPT_DIAGNOSTIC_SINK, PptDiagnosticCodes };
@@ -32,6 +32,10 @@ function resolveSchemeColor(schemeIndex, colorScheme) {
32
32
  if (color === void 0) throw new require_errors.PptFormatError(`colour scheme slot ${schemeIndex} has no entry in a ${colorScheme.length}-entry colour scheme`);
33
33
  return color;
34
34
  }
35
+ function findSlideSchemeColorSchemeAtom(records) {
36
+ return records.find((record) => record.header.recType === 2032 && record.header.recInstance === SLIDE_SCHEME_REC_INSTANCE);
37
+ }
35
38
  //#endregion
39
+ exports.findSlideSchemeColorSchemeAtom = findSlideSchemeColorSchemeAtom;
36
40
  exports.readSlideSchemeColorSchemeAtom = readSlideSchemeColorSchemeAtom;
37
41
  exports.resolveSchemeColor = resolveSchemeColor;
@@ -4,5 +4,6 @@ import { RgbColor } from "../text/style.cjs";
4
4
  declare function readSlideSchemeColorSchemeAtom(record: PptRecord): readonly RgbColor[];
5
5
  /** Resolves a scheme-slot index (0-7, see text/style.ts's own ColorIndexStruct table) against a resolved 8-entry colour scheme. Throws rather than returning undefined for an out-of-range index: readColorIndexStruct already rejects any index outside 0x00-0x07/0xFE/0xFF at parse time, so a RunColor of kind "scheme" reaching this function always carries a genuinely valid slot. */
6
6
  declare function resolveSchemeColor(schemeIndex: number, colorScheme: readonly RgbColor[]): RgbColor;
7
+ declare function findSlideSchemeColorSchemeAtom(records: readonly PptRecord[]): PptRecord | undefined;
7
8
  //#endregion
8
- export { readSlideSchemeColorSchemeAtom, resolveSchemeColor };
9
+ export { findSlideSchemeColorSchemeAtom, readSlideSchemeColorSchemeAtom, resolveSchemeColor };
@@ -4,5 +4,6 @@ import { RgbColor } from "../text/style.js";
4
4
  declare function readSlideSchemeColorSchemeAtom(record: PptRecord): readonly RgbColor[];
5
5
  /** Resolves a scheme-slot index (0-7, see text/style.ts's own ColorIndexStruct table) against a resolved 8-entry colour scheme. Throws rather than returning undefined for an out-of-range index: readColorIndexStruct already rejects any index outside 0x00-0x07/0xFE/0xFF at parse time, so a RunColor of kind "scheme" reaching this function always carries a genuinely valid slot. */
6
6
  declare function resolveSchemeColor(schemeIndex: number, colorScheme: readonly RgbColor[]): RgbColor;
7
+ declare function findSlideSchemeColorSchemeAtom(records: readonly PptRecord[]): PptRecord | undefined;
7
8
  //#endregion
8
- export { readSlideSchemeColorSchemeAtom, resolveSchemeColor };
9
+ export { findSlideSchemeColorSchemeAtom, readSlideSchemeColorSchemeAtom, resolveSchemeColor };
@@ -31,5 +31,8 @@ function resolveSchemeColor(schemeIndex, colorScheme) {
31
31
  if (color === void 0) throw new PptFormatError(`colour scheme slot ${schemeIndex} has no entry in a ${colorScheme.length}-entry colour scheme`);
32
32
  return color;
33
33
  }
34
+ function findSlideSchemeColorSchemeAtom(records) {
35
+ return records.find((record) => record.header.recType === 2032 && record.header.recInstance === SLIDE_SCHEME_REC_INSTANCE);
36
+ }
34
37
  //#endregion
35
- export { readSlideSchemeColorSchemeAtom, resolveSchemeColor };
38
+ export { findSlideSchemeColorSchemeAtom, readSlideSchemeColorSchemeAtom, resolveSchemeColor };
@@ -86,7 +86,7 @@ function writeSlideAtomForSlide(notesIdRef) {
86
86
  function writeTextMasterStyleAtom(textType) {
87
87
  return require_record_write.writeAtom(require_record_types.RT_TextMasterStyleAtom, require_record_write.u16le(0), { recInstance: textType });
88
88
  }
89
- function writeMainMaster(size, fontIndexOf) {
89
+ function writeMainMaster(size, context) {
90
90
  const placeholders = MASTER_PLACEHOLDER_TYPES.map((placementId, index) => {
91
91
  const frame = placeholderFrames(size)[index];
92
92
  if (frame === void 0) throw new Error("internal error: the main master states more placeholder types than it has rectangles for");
@@ -102,20 +102,25 @@ function writeMainMaster(size, fontIndexOf) {
102
102
  clientData: placeholderClientData(index, placementId)
103
103
  };
104
104
  });
105
- return require_record_write.writeContainer(require_record_types.RT_MainMaster, [
106
- writeSlideAtom({
107
- geom: SL_TITLE_BODY,
108
- placeholderTypes: MASTER_PLACEHOLDER_TYPES,
109
- masterIdRef: 0,
110
- notesIdRef: 0,
111
- slideFlags: 0
112
- }),
113
- writeTextMasterStyleAtom(0),
114
- writeTextMasterStyleAtom(1),
115
- writeTextMasterStyleAtom(2),
116
- require_drawing_shapes_write.writeDrawingWithClientData(placeholders, fontIndexOf),
117
- require_document_color_scheme_write.writeSlideSchemeColorSchemeAtom()
118
- ]);
105
+ const drawing = require_drawing_shapes_write.writeSlideDrawing(placeholders, context);
106
+ return {
107
+ bytes: require_record_write.writeContainer(require_record_types.RT_MainMaster, [
108
+ writeSlideAtom({
109
+ geom: SL_TITLE_BODY,
110
+ placeholderTypes: MASTER_PLACEHOLDER_TYPES,
111
+ masterIdRef: 0,
112
+ notesIdRef: 0,
113
+ slideFlags: 0
114
+ }),
115
+ writeTextMasterStyleAtom(0),
116
+ writeTextMasterStyleAtom(1),
117
+ writeTextMasterStyleAtom(2),
118
+ drawing.bytes,
119
+ require_document_color_scheme_write.writeSlideSchemeColorSchemeAtom()
120
+ ]),
121
+ shapeCount: drawing.shapeCount,
122
+ maxSpid: drawing.maxSpid
123
+ };
119
124
  }
120
125
  function writeMasterListWithText(persistIdRef) {
121
126
  return require_record_write.writeContainer(require_record_types.RT_SlideListWithText, [require_record_write.writeAtom(require_record_types.RT_SlidePersistAtom, require_record_write.concatBytes(require_record_write.u32le(persistIdRef), require_record_write.u32le(0), require_record_write.i32le(0), require_record_write.u32le(MASTER_SLIDE_ID), require_record_write.u32le(0)))], { recInstance: 1 });
@@ -1,3 +1,4 @@
1
+ import { DrawingWriteContext, DrawingWritten } from "../drawing/shapes-write.cjs";
1
2
  import { PageSize } from "document-schema.js";
2
3
  //#region src/document/master-write.d.ts
3
4
  declare const MASTER_SLIDE_ID = 2147483648;
@@ -9,7 +10,7 @@ declare function writeSlideAtom(options: {
9
10
  readonly slideFlags: number;
10
11
  }): Uint8Array<ArrayBuffer>;
11
12
  declare function writeSlideAtomForSlide(notesIdRef: number): Uint8Array<ArrayBuffer>;
12
- declare function writeMainMaster(size: PageSize, fontIndexOf: (family: string) => number): Uint8Array<ArrayBuffer>;
13
+ declare function writeMainMaster(size: PageSize, context: DrawingWriteContext): DrawingWritten;
13
14
  declare function writeMasterListWithText(persistIdRef: number): Uint8Array<ArrayBuffer>;
14
15
  //#endregion
15
16
  export { MASTER_SLIDE_ID, writeMainMaster, writeMasterListWithText, writeSlideAtom, writeSlideAtomForSlide };
@@ -1,3 +1,4 @@
1
+ import { DrawingWriteContext, DrawingWritten } from "../drawing/shapes-write.js";
1
2
  import { PageSize } from "document-schema.js";
2
3
  //#region src/document/master-write.d.ts
3
4
  declare const MASTER_SLIDE_ID = 2147483648;
@@ -9,7 +10,7 @@ declare function writeSlideAtom(options: {
9
10
  readonly slideFlags: number;
10
11
  }): Uint8Array<ArrayBuffer>;
11
12
  declare function writeSlideAtomForSlide(notesIdRef: number): Uint8Array<ArrayBuffer>;
12
- declare function writeMainMaster(size: PageSize, fontIndexOf: (family: string) => number): Uint8Array<ArrayBuffer>;
13
+ declare function writeMainMaster(size: PageSize, context: DrawingWriteContext): DrawingWritten;
13
14
  declare function writeMasterListWithText(persistIdRef: number): Uint8Array<ArrayBuffer>;
14
15
  //#endregion
15
16
  export { MASTER_SLIDE_ID, writeMainMaster, writeMasterListWithText, writeSlideAtom, writeSlideAtomForSlide };