pptx-viewer-core 1.1.23 → 1.1.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,11 +4,13 @@
4
4
  [![license](https://img.shields.io/npm/l/pptx-viewer-core.svg)](https://github.com/ChristopherVR/pptx-viewer/blob/main/LICENSE)
5
5
  [![types](https://img.shields.io/npm/types/pptx-viewer-core.svg)](https://www.npmjs.com/package/pptx-viewer-core)
6
6
 
7
- > The framework-agnostic TypeScript engine to **parse, create, edit, serialise, and convert** PowerPoint (`.pptx`) files runs in the browser and Node.js with no native dependencies.
7
+ > A TypeScript library that **reads, creates, edits, and saves** PowerPoint (`.pptx`) files. It runs in the browser and in Node.js, with no native or system dependencies.
8
8
 
9
- This is the headless core SDK. Point it at a `.pptx` `ArrayBuffer` and get back a fully typed `PptxData` model you can read, mutate, and write straight back to a valid `.pptx`. It also builds presentations from scratch with a fluent API and converts decks to Markdown. It powers the [`pptx-react-viewer`](https://www.npmjs.com/package/pptx-react-viewer), `pptx-vue-viewer`, and `pptx-angular-viewer` UI components.
9
+ Hand it the bytes of a `.pptx` file and it gives you back a structured, fully typed object that describes every slide: text, shapes, images, charts, tables, and more. Change anything in that object and write it back to a valid `.pptx`. You can also build new presentations from scratch with a simple chainable API, or turn a deck into Markdown.
10
10
 
11
- <samp>**[📦 npm](https://www.npmjs.com/package/pptx-viewer-core)** · **[📖 Full docs](https://christophervr.github.io/pptx-viewer/)** · **[⚛️ React UI](https://www.npmjs.com/package/pptx-react-viewer)**</samp>
11
+ There is no UI here: this is the engine on its own. Use it directly when you need to process `.pptx` files without a screen, for example on a server, in a script, or in a build step. The same engine powers the [`pptx-react-viewer`](https://www.npmjs.com/package/pptx-react-viewer), `pptx-vue-viewer`, and `pptx-angular-viewer` UI components.
12
+
13
+ <samp>**[📦 npm](https://www.npmjs.com/package/pptx-viewer-core)** · **[📖 Full docs](https://christophervr.github.io/pptx-viewer/)** · **[▶️ Live demo](https://christophervr.github.io/pptx-viewer/demo/)** · **[⚛️ React UI](https://www.npmjs.com/package/pptx-react-viewer)**</samp>
12
14
 
13
15
  ---
14
16
 
@@ -16,67 +18,66 @@ This is the headless core SDK. Point it at a `.pptx` `ArrayBuffer` and get back
16
18
 
17
19
  ```bash
18
20
  npm install pptx-viewer-core
19
- # peer dependencies:
21
+ # required companions:
20
22
  npm install jszip fast-xml-parser
21
23
  ```
22
24
 
23
- > Only two required peers: **jszip** (ZIP handling) and **fast-xml-parser** (XML parse/build). Encryption and digital-signature features pull in optional peers (`node-forge`, `xml-crypto`, `@xmldom/xmldom`) only if you use them.
24
-
25
- ## Overview
25
+ > Two packages are always needed alongside it: **jszip** (a `.pptx` is a ZIP file, and this reads and writes that container) and **fast-xml-parser** (the slides inside are XML, and this reads and writes it). Password protection and digital signatures need a few extra packages (`node-forge`, `xml-crypto`, `@xmldom/xmldom`), but only if you actually use those features.
26
26
 
27
- PowerPoint files (.pptx) are ZIP archives containing XML documents conforming to the [Office Open XML (OOXML)](https://www.ecma-international.org/publications-and-standards/standards/ecma-376/) specification. This package provides a complete TypeScript SDK for working with those files:
27
+ ## What it does
28
28
 
29
- | Capability | Description |
30
- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
31
- | **Parse** | Unzip, parse XML, and extract slides, elements, themes, masters, layouts, media, charts, SmartArt, comments, animations, transitions, and document properties |
32
- | **Edit** | Mutate the in-memory data model (add/remove/reorder slides, insert elements, modify text, change styles, update themes) |
33
- | **Save** | Serialise the modified data model back into a valid .pptx ZIP archive with full round-trip fidelity |
34
- | **Convert** | Transform parsed PPTX data into Markdown with optional media extraction |
35
- | **Export** | Export individual slides as standalone .pptx files |
36
- | **Encrypt/Decrypt** | Handle password-protected PPTX files using AES-128/256 Agile encryption |
29
+ | Capability | Description |
30
+ | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
31
+ | **Read** | Open a `.pptx` and pull out slides, text, shapes, images, charts, tables, SmartArt, themes, comments, animations, transitions, and document info |
32
+ | **Edit** | Change the data in memory: add, remove, or reorder slides; insert elements; edit text; restyle; switch themes |
33
+ | **Save** | Write the changed data back to a valid `.pptx`, leaving everything you did not touch untouched |
34
+ | **Convert** | Turn a deck into Markdown, optionally pulling the images out alongside it |
35
+ | **Export** | Save individual slides as their own standalone `.pptx` files |
36
+ | **Protect** | Open and save password-protected files (AES-128/256 encryption) |
37
37
 
38
- The library has only two peer dependencies: **jszip** (ZIP handling) and **fast-xml-parser** (XML parse/build).
38
+ Positions and sizes use PowerPoint's own internal unit, the EMU (English Metric Unit): 1 inch = 914,400 EMU, 1 point = 12,700 EMU, and 1 pixel = 9,525 EMU at 96 DPI. You rarely deal with the raw numbers: helpers (`inches`, `cm`, `mm`, `pt`) let you work in familiar units instead.
39
39
 
40
40
  ---
41
41
 
42
- ## Quick Start
42
+ ## Quick start
43
43
 
44
44
  ```typescript
45
45
  import { PptxHandler } from 'pptx-viewer-core';
46
46
 
47
- // 1. Parse a PPTX file
47
+ // 1. Open a .pptx file
48
48
  const handler = new PptxHandler();
49
49
  const buffer = await fetch('presentation.pptx').then((r) => r.arrayBuffer());
50
50
  const data = await handler.load(buffer);
51
51
 
52
- console.log(`${data.slides.length} slides loaded`);
53
- console.log(`Canvas: ${data.canvasSize.width} x ${data.canvasSize.height}`);
52
+ console.log(
53
+ `${data.slides.length} slides, canvas ${data.canvasSize.width}×${data.canvasSize.height}`,
54
+ );
54
55
 
55
- // 2. Modify slides
56
+ // 2. Change a slide
56
57
  data.slides[0].elements[0].text = 'Updated title';
57
58
 
58
- // 3. Save back to .pptx
59
- const outputBytes = await handler.save(data.slides);
60
- // => Uint8Array of a valid .pptx file
59
+ // 3. Save it back to .pptx bytes
60
+ const outputBytes = await handler.save(data.slides); // => Uint8Array
61
61
 
62
- // 4. Export individual slides
63
- const exports = await handler.exportSlides(data.slides, {
64
- slideIndexes: [0, 2],
65
- });
66
- // => Map<number, Uint8Array>
62
+ // 4. Or pull out just a few slides as separate files
63
+ const exports = await handler.exportSlides(data.slides, { slideIndexes: [0, 2] }); // => Map<number, Uint8Array>
67
64
  ```
68
65
 
69
- ### Create from scratch (Fluent API)
66
+ `load()` gives you a `PptxData` object: a plain, fully typed description of the presentation. Read from it, change it, and pass its `slides` back to `save()` to get a valid `.pptx` file as bytes.
67
+
68
+ ### Build a presentation from scratch
69
+
70
+ The chainable API lets you create a deck step by step, without touching any file format details:
70
71
 
71
72
  ```typescript
72
- import { Presentation, ThemePresets, TextBuilder, ChartBuilder } from 'pptx-viewer-core';
73
+ import { Presentation, ThemePresets, ChartBuilder } from 'pptx-viewer-core';
73
74
 
74
75
  const pptx = await Presentation.create({
75
76
  title: 'Sales Report',
76
77
  theme: ThemePresets.MODERN_BLUE,
77
78
  });
78
79
 
79
- // Slides are auto-tracked no manual .build() or .push() needed
80
+ // Each slide is added to the deck automatically: no manual .build() or .push() needed
80
81
  pptx
81
82
  .addSlide('Title Slide')
82
83
  .addText('Q4 Sales Report', { fontSize: 44, bold: true, x: 100, y: 200, width: 800, height: 80 });
@@ -92,932 +93,91 @@ pptx
92
93
  .bounds(50, 100, 860, 420),
93
94
  );
94
95
 
95
- // Find and replace, merge, template all fluent
96
- pptx.replaceText('2026', 'FY2026');
96
+ pptx.replaceText('2026', 'FY2026'); // find/replace, merge, and templates all chain the same way
97
97
 
98
98
  const bytes = await pptx.save();
99
99
  ```
100
100
 
101
- ### PPTX to Markdown conversion
101
+ The builder API comes in three levels, from highest to lowest:
102
+
103
+ 1. **`Presentation`**: the whole deck at once (slides, text operations, sections, templates, merging, saving).
104
+ 2. **Element builders**: one per element type, for fine-grained control: `TextBuilder`, `ShapeBuilder`, `ChartBuilder`, `TableBuilder`, `ImageBuilder`, `ConnectorBuilder`, `MediaBuilder`, `GroupBuilder`.
105
+ 3. **`PptxXmlBuilder`**: raw XML, for the rare cases the higher levels do not cover.
106
+
107
+ It also ships unit helpers (`inches`, `cm`, `mm`, `pt`), common slide sizes (`SlideSizes`), and 8 ready-made themes (`ThemePresets`). The [full docs](https://christophervr.github.io/pptx-viewer/) cover every builder.
108
+
109
+ ### Turn a deck into Markdown
102
110
 
103
111
  ```typescript
104
112
  import { PptxMarkdownConverter } from 'pptx-viewer-core';
105
113
 
106
- const converter = new PptxMarkdownConverter({
107
- includeMetadata: true,
108
- includeSlideNumbers: true,
109
- imageHandling: 'extract',
110
- });
111
-
112
- const markdown = await converter.convert(
114
+ const converter = new PptxMarkdownConverter({ includeMetadata: true, imageHandling: 'extract' });
115
+ const result = await converter.convert(
113
116
  buffer,
114
- {
115
- outputPath: 'output.md',
116
- mediaFolderName: 'media',
117
- includeMetadata: true,
118
- },
117
+ { outputPath: 'output.md', mediaFolderName: 'media' },
119
118
  fileSystemAdapter,
120
119
  );
121
- // => ConversionResult with markdown string + extracted media stats
120
+ // => the Markdown text, plus stats on any images that were pulled out
122
121
  ```
123
122
 
124
- ---
125
-
126
- ## API Reference
127
-
128
- ### PptxHandler
129
-
130
- The primary facade for loading, editing, and saving PPTX files.
131
-
132
- | Method | Signature | Description |
133
- | -------------------------------- | --------------------------------------------------------------- | ------------------------------------------ |
134
- | `load` | `(data: ArrayBuffer, options?) => Promise<PptxData>` | Parse a .pptx buffer into structured data |
135
- | `save` | `(slides: PptxSlide[], options?) => Promise<Uint8Array>` | Serialise slides back to .pptx bytes |
136
- | `exportSlides` | `(slides, options) => Promise<Map<number, Uint8Array>>` | Export selected slides as standalone files |
137
- | `getImageData` | `(path: string) => Promise<string \| undefined>` | Get base64 data URL for an embedded image |
138
- | `getMediaArrayBuffer` | `(path: string) => Promise<ArrayBuffer \| undefined>` | Get raw bytes for an embedded media file |
139
- | `getChartDataForGraphicFrame` | `(slidePath, xmlObj) => Promise<PptxChartData \| undefined>` | Extract chart data from a graphic frame |
140
- | `getSmartArtDataForGraphicFrame` | `(slidePath, xmlObj) => Promise<PptxSmartArtData \| undefined>` | Extract SmartArt data from a graphic frame |
141
- | `getLayoutOptions` | `() => PptxLayoutOption[]` | Get available slide layout options |
142
- | `getCompatibilityWarnings` | `() => PptxCompatibilityWarning[]` | Get warnings about unsupported features |
143
- | `createXmlBuilder` / `Builder` | `(data: PptxData) => PptxXmlBuilder` | Create a fluent XML builder |
144
- | `applyTheme` | `(colors, fonts, name?) => Promise<void>` | Apply a complete theme |
145
- | `updateThemeColorScheme` | `(scheme) => Promise<void>` | Modify theme colours |
146
- | `updateThemeFontScheme` | `(scheme) => Promise<void>` | Modify theme fonts |
147
- | `setPresentationTheme` | `(path, applyToAll?) => Promise<void>` | Load a .thmx theme file |
148
-
149
- ### PptxMarkdownConverter
150
-
151
- Converts PPTX files to Markdown documents. Extends the abstract `DocumentConverter` base class.
152
-
153
- | Method | Signature | Description |
154
- | --------- | ----------------------------------------------------- | ------------------------------- |
155
- | `convert` | `(buffer, options, fs?) => Promise<ConversionResult>` | Convert PPTX buffer to Markdown |
156
-
157
- Requires a `FileSystemAdapter` for disk output:
158
-
159
- ```typescript
160
- interface FileSystemAdapter {
161
- writeFile(path: string, content: string): Promise<void>;
162
- writeBinaryFile(path: string, data: Uint8Array): Promise<void>;
163
- createFolder(path: string): Promise<void>;
164
- }
165
- ```
166
-
167
- ### PptxXmlBuilder (Fluent API)
168
-
169
- A chainable builder for constructing OpenXML nodes directly in the runtime's in-memory ZIP.
170
-
171
- ```typescript
172
- const builder = handler.Builder(data);
173
- // Use fluent methods to construct and insert XML elements
174
- ```
123
+ To write files to disk, pass a `FileSystemAdapter` (an object with `writeFile`, `writeBinaryFile`, and `createFolder` methods); this keeps the converter free of any assumptions about where it runs. By default it keeps each element where it sat on the slide (absolutely positioned HTML); set `semanticMode: true` to get clean headings, paragraphs, and lists instead.
175
124
 
176
125
  ---
177
126
 
178
- ## Architecture
179
-
180
- ### High-Level Architecture
181
-
182
- The package follows a layered architecture with clear separation of concerns:
183
-
184
- _See the [architecture diagrams on GitHub](https://github.com/ChristopherVR/pptx-viewer/blob/main/packages/core/README.md) for visual representations._
185
-
186
- ### Module Map
187
-
188
- _See the [architecture diagrams on GitHub](https://github.com/ChristopherVR/pptx-viewer/blob/main/packages/core/README.md) for visual representations._
127
+ ## `PptxHandler` API
189
128
 
190
- ### Load Pipeline
129
+ `PptxHandler` is the one class you use to open, change, and save files. Its main methods:
191
130
 
192
- When `handler.load(buffer)` is called, the following sequence occurs:
131
+ | Method | Signature | What it does |
132
+ | -------------------------- | ------------------------------------------------------- | ------------------------------------------------------ |
133
+ | `load` | `(data, options?) => Promise<PptxData>` | Open a `.pptx` and return the structured data |
134
+ | `save` | `(slides, options?) => Promise<Uint8Array>` | Write slides back to `.pptx` bytes |
135
+ | `exportSlides` | `(slides, options) => Promise<Map<number, Uint8Array>>` | Save chosen slides as standalone files |
136
+ | `getImageData` | `(path) => Promise<string \| undefined>` | Get an embedded image as a base64 data URL |
137
+ | `getMediaArrayBuffer` | `(path) => Promise<ArrayBuffer \| undefined>` | Get the raw bytes of an embedded media file |
138
+ | `getLayoutOptions` | `() => PptxLayoutOption[]` | List the slide layouts available |
139
+ | `getCompatibilityWarnings` | `() => PptxCompatibilityWarning[]` | List features in the file that are not fully supported |
140
+ | `applyTheme` | `(colors, fonts, name?) => Promise<void>` | Apply a complete theme |
141
+ | `setPresentationTheme` | `(path, applyToAll?) => Promise<void>` | Load a `.thmx` theme file |
193
142
 
194
- _See the [architecture diagrams on GitHub](https://github.com/ChristopherVR/pptx-viewer/blob/main/packages/core/README.md) for visual representations._
143
+ The `PptxData` you get from `load()` exposes `slides`, `canvasSize`, `theme`, `slideMasters`, `slideLayouts`, `sections`, `coreProperties`, `embeddedFonts`, and more. See the [full docs](https://christophervr.github.io/pptx-viewer/) for the complete `PptxHandler`, chart/SmartArt, and theme APIs.
195
144
 
196
- ### Save Pipeline
145
+ ## What's supported
197
146
 
198
- When `handler.save(slides)` is called:
147
+ | Category | Details |
148
+ | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
149
+ | **Element types** | 16: text, shape, connector, image, picture, table, chart, smartArt, ole, media, group, ink, contentPart, zoom, model3d, unknown |
150
+ | **Preset shapes** | 187+ PowerPoint shapes, including ones with adjustable handles |
151
+ | **Chart types** | 23, including waterfall, funnel, treemap, sunburst, box-whisker, region-map, and combo charts; with trendlines, error bars, and embedded Excel data |
152
+ | **Transitions** | 42 types (including morph, vortex, ripple, and shred) |
153
+ | **Animations** | 40+ presets, including colour animation, motion paths, and text that builds in by word, letter, or paragraph |
154
+ | **SmartArt** | 13 layout types, broken down into editable shapes |
155
+ | **Fills** | Solid, gradient (linear, radial, path), image, and 48 patterns |
156
+ | **Themes** | 8 built-in presets, switchable at runtime, with layout and placeholder remapping |
157
+ | **Security** | AES-128/256 encryption and decryption, modify-password (SHA), and detection of digital signatures |
158
+ | **Preserved** | VBA macros, custom XML, comment authors, and strict-format files are kept intact through a save |
199
159
 
200
- _See the [architecture diagrams on GitHub](https://github.com/ChristopherVR/pptx-viewer/blob/main/packages/core/README.md) for visual representations._
160
+ ## How it works
201
161
 
202
- ### Runtime Mixin Composition
162
+ You only ever work with one class, `PptxHandler`, and one data object, `PptxData`. The engine takes care of the rest: when you call `load()` it unzips the file, reads the XML, resolves the theme, masters, and layouts, and hands you a clean object. `save()` runs those same steps in reverse.
203
163
 
204
- The runtime is assembled from 50+ mixin modules using a linear inheritance chain. Each module adds a focused set of capabilities:
205
-
206
- _See the [architecture diagrams on GitHub](https://github.com/ChristopherVR/pptx-viewer/blob/main/packages/core/README.md) for visual representations._
207
-
208
- Each file exports a class named `PptxHandlerRuntime` that extends the previous module's export, adding its own methods. The final `PptxHandlerRuntimeImplementation` aggregates all functionality into the complete runtime.
209
-
210
- ---
211
-
212
- ## Deep Dive: How It Works
213
-
214
- ### 1. OpenXML ZIP Structure
215
-
216
- A .pptx file is a ZIP archive with this internal structure:
217
-
218
- ```
219
- presentation.pptx (ZIP)
220
- +-- [Content_Types].xml <- MIME type registry
221
- +-- _rels/.rels <- Root relationships
222
- +-- docProps/
223
- | +-- app.xml <- Application properties
224
- | +-- core.xml <- Dublin Core metadata
225
- | +-- custom.xml <- Custom properties
226
- +-- ppt/
227
- +-- presentation.xml <- Slide list, canvas size, slide master refs
228
- +-- presProps.xml <- Presentation properties (show type, loop, etc.)
229
- +-- viewProps.xml <- View state (zoom, grid, guides)
230
- +-- tableStyles.xml <- Table style definitions
231
- +-- _rels/presentation.xml.rels
232
- +-- theme/
233
- | +-- theme1.xml <- Colour scheme, fonts, format scheme
234
- +-- slideMasters/
235
- | +-- slideMaster1.xml <- Master slide (background, placeholders)
236
- +-- slideLayouts/
237
- | +-- slideLayout1.xml <- Layout templates
238
- +-- slides/
239
- | +-- slide1.xml <- Slide content (shape tree)
240
- | +-- _rels/slide1.xml.rels <- Per-slide relationships
241
- +-- media/
242
- | +-- image1.png <- Embedded images
243
- | +-- video1.mp4 <- Embedded media
244
- | +-- model1.glb <- 3D models
245
- +-- charts/
246
- | +-- chart1.xml <- Chart definitions
247
- +-- notesSlides/
248
- | +-- notesSlide1.xml <- Speaker notes
249
- +-- diagrams/ <- SmartArt data
250
- +-- embeddings/ <- OLE embedded files
251
- +-- customXml/ <- Custom XML parts
252
- +-- vbaProject.bin <- VBA macros (if present)
253
- ```
164
+ A few things worth knowing as you use it:
254
165
 
255
- The runtime uses **jszip** to read/write this archive and **fast-xml-parser** to parse/build the XML documents.
166
+ - **Every element has a `type` field** (`text`, `shape`, `image`, `chart`, `table`, and so on). Check it before reading element-specific properties, for example `if (element.type === 'image')`. TypeScript then knows exactly which fields exist.
167
+ - **Shapes are drawn from a built-in catalogue** of 187+ PowerPoint shapes, so curves, arrows, and callouts come out with the right outlines.
168
+ - **Colours follow PowerPoint's theme rules**, so a colour defined as "accent 1, but 20% lighter" resolves to the correct final value for the active theme.
256
169
 
257
- ### 2. Type System
170
+ Under the hood the engine is split into many small, focused modules. If you want the full load and save pipeline, the complete type system, and a module-by-module map, see the [full documentation](https://christophervr.github.io/pptx-viewer/).
258
171
 
259
- The type system is organised into 22 domain-specific modules with a discriminated union pattern for elements:
260
-
261
- _See the [architecture diagrams on GitHub](https://github.com/ChristopherVR/pptx-viewer/blob/main/packages/core/README.md) for visual representations._
262
-
263
- **Key type modules:**
264
-
265
- | Module | Types |
266
- | ----------------- | -------------------------------------------------------------------- |
267
- | `common.ts` | `XmlObject`, `PptxData`, `PptxSlide`, `PptxCanvasSize` |
268
- | `elements.ts` | `PptxElement` discriminated union (16 variants) |
269
- | `element-base.ts` | `PptxElementBase` shared properties |
270
- | `text.ts` | `TextStyle`, `ParagraphStyle`, `TextSegment`, `TextBody` |
271
- | `shape-style.ts` | `ShapeStyle`, `FillStyle`, `StrokeStyle`, `ShadowEffect` |
272
- | `table.ts` | `TableData`, `TableCell`, `TableRow`, `TableBorderStyle` |
273
- | `chart.ts` | `PptxChartData`, `ChartSeries`, `ChartAxis` (23 chart types) |
274
- | `theme.ts` | `PptxTheme`, `PptxThemeColorScheme`, `PptxThemeFontScheme` |
275
- | `animation.ts` | `PptxElementAnimation`, `PptxAnimationPreset` |
276
- | `transition.ts` | `PptxSlideTransition` (42 transition types) |
277
- | `masters.ts` | `PptxSlideMaster`, `PptxSlideLayout` |
278
- | `image.ts` | `ImageEffects`, `ImageCrop` |
279
- | `geometry.ts` | `PptxCustomGeometry`, `GeometryPath` |
280
- | `smart-art.ts` | `PptxSmartArtData`, `SmartArtNode` |
281
- | `media.ts` | `PptxMediaData`, `MediaTiming`, `MediaBookmark`, `MediaCaptionTrack` |
282
- | `metadata.ts` | `CoreProperties`, `AppProperties` |
283
- | `three-d.ts` | `ThreeDProperties`, `BevelType` |
284
- | `type-guards.ts` | Runtime type guard functions for PptxElement variants |
285
-
286
- ### 3. Theme Resolution Chain
287
-
288
- PowerPoint elements inherit visual styles through a multi-level chain. The runtime resolves styles in this order:
289
-
290
- _See the [architecture diagrams on GitHub](https://github.com/ChristopherVR/pptx-viewer/blob/main/packages/core/README.md) for visual representations._
291
-
292
- **Theme colour references** (e.g. `accent1`, `dk1`, `lt2`) are resolved through the theme's `a:clrScheme`, optionally overridden by the slide master's `p:clrMap` and the layout's `p:clrMapOvr`.
293
-
294
- The engine ships with **8 built-in theme presets** and supports runtime theme switching with layout switching and placeholder remapping.
295
-
296
- ### 4. Geometry Engine
297
-
298
- The geometry module (17 files) handles shape path generation and coordinate transforms:
299
-
300
- | Module | Purpose |
301
- | ----------------------------- | --------------------------------------------------------- |
302
- | `shape-geometry.ts` | Main entry -- resolves shape type, clip path, image masks |
303
- | `connector-geometry.ts` | Connector routing and path generation |
304
- | `guide-formula.ts` | OOXML DrawingML guide formula evaluator |
305
- | `guide-formula-eval.ts` | Mathematical expression evaluation engine |
306
- | `guide-formula-paths.ts` | SVG path generation from guide-computed coordinates |
307
- | `preset-shape-definitions.ts` | 187+ preset shape definitions (rect, arrow, star, etc.) |
308
- | `preset-shape-paths.ts` | Pre-computed SVG clip paths for all preset shapes |
309
- | `transform-utils.ts` | Element position/rotation/flip transforms |
310
- | `custom-geometry.ts` | Arbitrary OOXML `<a:custGeom>` path parsing |
311
-
312
- **Guide formula evaluation** implements the OOXML DrawingML formula language:
313
-
314
- ```
315
- +-----------------------------------------------------+
316
- | Guide Formula Language |
317
- | |
318
- | Operators: +/-, */div, val, abs, sqrt, sin, cos, |
319
- | tan, at2, min, max, mod, pin, if, ?: |
320
- | |
321
- | Built-in variables: |
322
- | w (shape width), h (shape height) |
323
- | l, t, r, b (left, top, right, bottom) |
324
- | wd2, hd2 (half width/height) |
325
- | cd2, cd4, cd8 (circle division constants) |
326
- | |
327
- | Adjustment handles: adj, adj1, adj2, ... |
328
- | (user-draggable shape parameters) |
329
- +-----------------------------------------------------+
330
- ```
331
-
332
- ### 5. Colour Processing
333
-
334
- The colour module (4 files) handles OOXML colour parsing and transforms:
335
-
336
- _See the [architecture diagrams on GitHub](https://github.com/ChristopherVR/pptx-viewer/blob/main/packages/core/README.md) for visual representations._
337
-
338
- Supported colour transform operations:
339
- | Transform | Effect |
340
- |-----------|--------|
341
- | `lumMod` / `lumOff` | Luminance modulate / offset |
342
- | `tint` / `shade` | Lighten / darken toward white/black |
343
- | `satMod` / `satOff` | Saturation modulate / offset |
344
- | `hueMod` / `hueOff` | Hue rotation |
345
- | `alpha` | Opacity (0--100000 = 0--100%) |
346
- | `comp` | Complementary colour |
347
- | `inv` | Invert colour |
348
- | `gray` | Grayscale conversion |
349
-
350
- ### 6. Converter System
351
-
352
- The PPTX-to-Markdown converter uses a registry pattern for element processing:
353
-
354
- _See the [architecture diagrams on GitHub](https://github.com/ChristopherVR/pptx-viewer/blob/main/packages/core/README.md) for visual representations._
355
-
356
- The converter supports two output modes:
357
-
358
- - **Positioned mode** (default): HTML `<div>` elements with absolute CSS positioning.
359
- - **Semantic mode** (`semanticMode: true`): Clean Markdown with headings, paragraphs, and lists.
360
-
361
- The `MediaContext` class manages image extraction during conversion, mapping data URLs to output file paths and deduplicating identical images.
362
-
363
- ### 7. Services Layer
364
-
365
- Nine specialised services handle cross-cutting concerns:
366
-
367
- | Service | Responsibility |
368
- | ------------------------------- | ------------------------------------------------------------- |
369
- | `PptxSlideLoaderService` | Coordinate slide XML parsing -- elements, notes, media timing |
370
- | `PptxNativeAnimationService` | Parse native OOXML animation timing trees (`p:timing`) |
371
- | `PptxEditorAnimationService` | Map between editor animation presets and OOXML sequences |
372
- | `PptxAnimationWriteService` | Serialise editor animations back to OOXML timing XML |
373
- | `PptxSlideTransitionService` | Parse and write slide transition effects (`p:transition`) |
374
- | `PptxCompatibilityService` | Detect unsupported features and generate warnings |
375
- | `PptxXmlLookupService` | Cached XML lookups across relationships and parts |
376
- | `PptxDocumentPropertiesUpdater` | Update `docProps/core.xml` and `docProps/app.xml` |
377
- | `PptxTemplateBackgroundService` | Manage template/layout background images |
378
-
379
- ### 8. Builder APIs (Fluent SDK)
380
-
381
- The SDK provides a comprehensive fluent API for creating and manipulating presentations programmatically. Three tiers are available, from highest to lowest level:
382
-
383
- #### Tier 1 — `Presentation` (highest level)
384
-
385
- The recommended entry point. Manages slides, text operations, sections, templates, merging, and saving — all with zero boilerplate.
386
-
387
- ```typescript
388
- import {
389
- Presentation,
390
- ThemePresets,
391
- inches,
392
- SlideSizes,
393
- TextBuilder,
394
- ShapeBuilder,
395
- ChartBuilder,
396
- TableBuilder,
397
- ImageBuilder,
398
- ConnectorBuilder,
399
- MediaBuilder,
400
- GroupBuilder,
401
- } from 'pptx-viewer-core';
402
-
403
- // Create a new presentation
404
- const pptx = await Presentation.create({
405
- title: 'Quarterly Report',
406
- creator: 'Sales Team',
407
- width: SlideSizes.WIDESCREEN_16_9.width,
408
- height: SlideSizes.WIDESCREEN_16_9.height,
409
- theme: ThemePresets.MODERN_BLUE,
410
- });
411
-
412
- // Add slides — they are auto-tracked, no manual push or .build() needed
413
- pptx
414
- .addSlide('Title Slide')
415
- .addText('Q4 2026 Results', { fontSize: 44, bold: true, x: 100, y: 200, width: 800, height: 80 })
416
- .addText('Confidential', {
417
- fontSize: 14,
418
- color: '#999999',
419
- x: 100,
420
- y: 300,
421
- width: 800,
422
- height: 30,
423
- })
424
- .setBackground({ type: 'solid', color: '#1B2A4A' })
425
- .setNotes('Open with the revenue highlight')
426
- .setTransition({ type: 'fade', duration: 500 });
427
-
428
- pptx
429
- .addSlide('Blank')
430
- .addText('Revenue grew 15% YoY', { fontSize: 24, x: 50, y: 50, width: 600, height: 40 })
431
- .addChart(
432
- 'bar',
433
- {
434
- series: [
435
- { name: '2025', values: [120, 145, 160, 180], color: '#93C5FD' },
436
- { name: '2026', values: [140, 170, 195, 210], color: '#2563EB' },
437
- ],
438
- categories: ['Q1', 'Q2', 'Q3', 'Q4'],
439
- title: 'Revenue ($M)',
440
- },
441
- { x: 50, y: 100, width: 600, height: 400 },
442
- )
443
- .addShape('roundRect', {
444
- fill: { type: 'solid', color: '#2563EB' },
445
- text: 'See appendix',
446
- x: 700,
447
- y: 450,
448
- width: 200,
449
- height: 40,
450
- });
451
-
452
- // Save to bytes
453
- const bytes = await pptx.save();
454
- ```
455
-
456
- **Full `Presentation` API reference:**
457
-
458
- | Category | Method | Description |
459
- | --------------- | ------------------------------------------------ | --------------------------------------------- |
460
- | **Create/Load** | `Presentation.create(options?)` | Create a new blank presentation |
461
- | | `Presentation.load(buffer)` | Load an existing .pptx file |
462
- | **Slides** | `addSlide(layoutName?)` | Add a slide (returns `SlideBuilder`) |
463
- | | `insertSlide(index, layoutName?)` | Insert a slide at position |
464
- | | `duplicateSlide(slideIndex)` | Deep-clone a slide with new IDs |
465
- | | `removeSlide(index)` | Remove a slide (chainable) |
466
- | | `moveSlide(from, to)` | Move a slide (chainable) |
467
- | | `swapSlides(indexA, indexB)` | Swap two slides (chainable) |
468
- | | `reorderSlides(newOrder)` | Reorder all slides by index array (chainable) |
469
- | | `clearSlides()` | Remove all slides (chainable) |
470
- | | `getSlide(index)` | Get a slide by index |
471
- | | `forEachSlide(callback)` | Iterate slides (chainable) |
472
- | | `findSlides(predicate)` | Find slide indices matching a predicate |
473
- | | `slideCount` | Number of slides |
474
- | **Text** | `findText(search)` | Search all slides for text (string or RegExp) |
475
- | | `replaceText(search, replacement)` | Replace text across all slides |
476
- | | `replaceTextOnSlide(index, search, replacement)` | Replace text on a single slide |
477
- | **Sections** | `addSection(name, slideIndices)` | Group slides into a section |
478
- | | `removeSection(sectionId)` | Remove a section |
479
- | | `reorderSections(sectionIds)` | Reorder sections (chainable) |
480
- | | `getSectionForSlide(slideIndex)` | Get the section a slide belongs to |
481
- | | `moveSlidesToSection(indices, targetId)` | Move slides between sections |
482
- | | `sections` | Get all sections |
483
- | **Template** | `applyTemplate(data)` | Replace `{{placeholders}}` (chainable) |
484
- | | `mailMerge(records)` | Generate multiple files from template data |
485
- | **Merge** | `merge(source, options?)` | Merge another presentation's slides |
486
- | **Diff** | `diff(other)` | Structured comparison of two presentations |
487
- | **Save** | `save()` | Serialize to `.pptx` bytes |
488
- | | `saveEncrypted(password)` | Save with password encryption |
489
- | **Metadata** | `title` | Presentation title |
490
- | | `creator` | Author name |
491
- | | `width` / `height` | Slide dimensions in EMU |
492
- | **Advanced** | `handler` | Underlying `PptxHandler` |
493
- | | `data` | Underlying `PptxData` (live reference) |
494
- | | `slides` | Live slides array |
495
- | | `xmlBuilder()` | Low-level `PptxXmlBuilder` for mutation |
496
- | | `dispose()` | Free resources |
497
-
498
- #### Tier 2 — Element Builders (fluent element construction)
499
-
500
- Eight builder classes for step-by-step element construction with method chaining. Each builder's `.build()` produces a standard `PptxElement`.
501
-
502
- **TextBuilder:**
503
-
504
- ```typescript
505
- const title = TextBuilder.create('Hello World')
506
- .fontSize(36)
507
- .bold()
508
- .italic()
509
- .underline()
510
- .strikethrough()
511
- .color('#2563EB')
512
- .fontFamily('Inter')
513
- .alignment('center')
514
- .verticalAlignment('middle')
515
- .lineSpacing(1.5)
516
- .fill({ type: 'solid', color: '#F0F4F8' })
517
- .stroke({ color: '#2563EB', width: 1 })
518
- .shadow({ blur: 4, offsetX: 2, offsetY: 2, opacity: 0.3 })
519
- .position(100, 100)
520
- .size(600, 80)
521
- .rotation(0)
522
- .opacity(1)
523
- .build();
524
-
525
- // Rich text with multiple segments
526
- const richText = TextBuilder.create([
527
- { text: 'Bold intro. ', style: { bold: true, fontSize: 18 } },
528
- { text: 'Normal body text.', style: { fontSize: 14 } },
529
- ])
530
- .position(50, 200)
531
- .size(800, 40)
532
- .build();
533
- ```
534
-
535
- **ShapeBuilder:**
536
-
537
- ```typescript
538
- const shape = ShapeBuilder.create('roundRect')
539
- .solidFill('#4472C4') // Convenience: solid fill
540
- .noFill() // Convenience: transparent
541
- .gradientFill(
542
- [
543
- // Convenience: gradient fill
544
- { color: '#2563EB', position: 0 },
545
- { color: '#60A5FA', position: 1 },
546
- ],
547
- 45,
548
- )
549
- .fill({ type: 'pattern', preset: 'dkDnDiag' }) // Full fill input
550
- .stroke({ color: '#000', width: 2, dash: 'dash' })
551
- .shadow({ blur: 8, offsetX: 3, offsetY: 3 })
552
- .text('Click me')
553
- .textStyle({ fontSize: 14, bold: true, color: '#FFF' })
554
- .adjustments({ adj1: 16667 }) // Geometry adjustment handles
555
- .position(200, 200)
556
- .size(300, 200)
557
- .rotation(15)
558
- .opacity(0.9)
559
- .build();
560
- ```
561
-
562
- **ImageBuilder:**
563
-
564
- ```typescript
565
- const logo = ImageBuilder.create('data:image/png;base64,iVBOR...')
566
- .altText('Company logo')
567
- .crop(0.1, 0.05, 0.1, 0.05) // Fractional crop from each edge
568
- .position(50, 50)
569
- .size(200, 100)
570
- .rotation(0)
571
- .opacity(1)
572
- .build();
573
- ```
574
-
575
- **TableBuilder:**
576
-
577
- ```typescript
578
- const table = TableBuilder.create()
579
- .headerRow(['Name', 'Q1', 'Q2', 'Q3', 'Q4'])
580
- .addRow(['North', '120', '145', '160', '180'])
581
- .addRow(['South', '90', '105', '130', '150'])
582
- .addRow([
583
- { text: 'Total', style: { bold: true } },
584
- { text: '210', style: { bold: true, color: '#2563EB' } },
585
- { text: '250' },
586
- { text: '290' },
587
- { text: '330' },
588
- ])
589
- .columnWidths([2, 1, 1, 1, 1]) // Proportional widths
590
- .bandRows()
591
- .bandColumns(false)
592
- .firstCol()
593
- .lastRow()
594
- .lastCol(false)
595
- .style('{5C22544A-7EE6-4342-B048-85BDC9FD1C3A}')
596
- .position(50, 150)
597
- .size(860, 250)
598
- .build();
599
- ```
600
-
601
- **ChartBuilder:**
602
-
603
- ```typescript
604
- const chart = ChartBuilder.create('line') // bar, line, pie, doughnut, area, scatter, ...
605
- .categories(['Jan', 'Feb', 'Mar', 'Apr'])
606
- .addSeries('Actual', [42, 58, 67, 73], '#2563EB')
607
- .addSeries('Target', [50, 55, 60, 65], '#E94560')
608
- .title('Monthly Performance')
609
- .legend(true, 'b') // Show legend at bottom
610
- .grouping('clustered') // clustered | stacked | percentStacked
611
- .position(100, 150)
612
- .size(600, 400)
613
- .build();
614
- ```
615
-
616
- **ConnectorBuilder:**
617
-
618
- ```typescript
619
- const line = ConnectorBuilder.create()
620
- .type('curved') // straight | bent | curved
621
- .stroke({ color: '#333', width: 2, dash: 'dashDot' })
622
- .startArrow('triangle')
623
- .endArrow('stealth')
624
- .from(shape1.id, 2) // Connect from shape1, site index 2
625
- .to(shape2.id, 0) // Connect to shape2, site index 0
626
- .position(100, 100)
627
- .size(300, 0)
628
- .rotation(0)
629
- .build();
630
- ```
631
-
632
- **MediaBuilder:**
633
-
634
- ```typescript
635
- const video = MediaBuilder.video('data:video/mp4;base64,...')
636
- .autoPlay()
637
- .loop()
638
- .volume(0.8)
639
- .trim(1000, 5000) // Trim: start at 1s, end at 5s
640
- .posterFrame('data:image/png;base64,...')
641
- .position(100, 100)
642
- .size(480, 270)
643
- .build();
644
-
645
- const audio = MediaBuilder.audio('path/to/audio.mp3')
646
- .autoPlay(false)
647
- .loop(false)
648
- .volume(1.0)
649
- .build();
650
- ```
651
-
652
- **GroupBuilder:**
653
-
654
- ```typescript
655
- const group = GroupBuilder.create()
656
- .addChild(TextBuilder.create('Label').position(0, 0).size(100, 30).build())
657
- .addChildBuilder(ShapeBuilder.create('rect').solidFill('#EEE').size(100, 100))
658
- .addChildren([element1, element2])
659
- .position(200, 200)
660
- .size(300, 300)
661
- .rotation(10)
662
- .build();
663
- ```
664
-
665
- #### SlideBuilder (returned by `Presentation.addSlide()`)
666
-
667
- Chainable API for adding elements and setting slide properties:
668
-
669
- ```typescript
670
- pptx
671
- .addSlide('Blank')
672
- // Add elements (all chainable)
673
- .addText('Title', { fontSize: 36, x: 50, y: 50, width: 860, height: 60 })
674
- .addShape('ellipse', {
675
- fill: { type: 'solid', color: '#FF0000' },
676
- x: 50,
677
- y: 150,
678
- width: 100,
679
- height: 100,
680
- })
681
- .addImage('data:image/png;base64,...', { x: 200, y: 150, width: 300, height: 200 })
682
- .addTable({ rows: [{ cells: [{ text: 'A' }, { text: 'B' }] }] })
683
- .addChart('pie', { series: [{ name: 'S1', values: [60, 40] }], categories: ['Yes', 'No'] })
684
- .addConnector({ type: 'straight', stroke: { color: '#000', width: 1 } })
685
- .addMedia('video', 'data:video/mp4;base64,...', { autoPlay: true })
686
- .addGroup([element1, element2], { x: 0, y: 0, width: 960, height: 540 })
687
- .addFreeform('M 0 0 L 100 50 L 50 100 Z', { stroke: { color: '#F00', width: 2 } })
688
- .addElement(anyPptxElement) // Add any pre-built element
689
- .addBuilderElement(TextBuilder.create('X').bold()) // Accept any builder
690
- // Slide properties
691
- .setBackground({
692
- type: 'gradient',
693
- angle: 135,
694
- stops: [
695
- { color: '#000', position: 0 },
696
- { color: '#333', position: 1 },
697
- ],
698
- })
699
- .setTransition({ type: 'morph', duration: 800 })
700
- .addAnimation(elementId, { preset: 'fadeIn', trigger: 'afterPrevious', duration: 500 })
701
- .setNotes('Speaker notes here')
702
- .setHidden(false)
703
- .setSection('Introduction')
704
- .setName('Intro Slide')
705
- // Query methods
706
- .getElements() // Readonly array of current elements
707
- .getLastElement() // Last element (for animation IDs)
708
- .elementCount // Number of elements
709
- .removeElement(elementId) // Remove by ID (chainable)
710
- .build(); // Get the PptxSlide object
711
- ```
712
-
713
- #### Unit Helpers and Theme Presets
714
-
715
- ```typescript
716
- import { inches, cm, mm, pt, inchesToEmu, SlideSizes, ThemePresets } from 'pptx-viewer-core';
717
-
718
- // Unit conversions (all return pixels at 96 DPI)
719
- inches(1); // => 96
720
- cm(2.54); // => 96
721
- mm(25.4); // => 96
722
- pt(72); // => 96
723
-
724
- // EMU conversions (for PresentationOptions width/height)
725
- inchesToEmu(10); // => 9144000
726
-
727
- // Standard slide sizes (EMU values)
728
- SlideSizes.WIDESCREEN_16_9; // { width: 12192000, height: 6858000 }
729
- SlideSizes.STANDARD_4_3; // { width: 9144000, height: 6858000 }
730
- SlideSizes.A4_LANDSCAPE; // { width: 10692000, height: 7560937 }
731
-
732
- // Theme presets (8 built-in themes)
733
- ThemePresets.OFFICE; // Default Office theme
734
- ThemePresets.MODERN_BLUE; // Clean blue professional
735
- ThemePresets.CORPORATE; // Professional corporate
736
- ThemePresets.DARK; // Dark mode
737
- ThemePresets.VIBRANT; // Energetic colours
738
- ThemePresets.EARTH; // Warm earth tones
739
- ThemePresets.MONOCHROME; // High contrast B&W
740
- ThemePresets.MINIMAL; // Soft pastels
741
- ```
742
-
743
- #### Tier 3 — Low-Level APIs
744
-
745
- **PptxXmlBuilder** — Fluent in-place mutation of an existing `PptxData`:
746
-
747
- ```typescript
748
- PptxXmlBuilder.from(data)
749
- .slide(0)
750
- .elements()
751
- .add(createTextElement('New text'))
752
- .removeById('old_id')
753
- .updateById('el_id', (el) => ({ ...el, x: 200 }))
754
- .done()
755
- .notes()
756
- .set('Updated notes')
757
- .done()
758
- .done()
759
- .project(); // => mutated PptxData
760
- ```
761
-
762
- **SDK Operations** — Pure functions for batch operations:
763
-
764
- | Category | Functions |
765
- | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
766
- | **Text** | `findText`, `replaceText`, `replaceTextInSlide` |
767
- | **Charts** | `setChartType`, `addChartSeries`, `removeChartSeries`, `setChartCategories`, `updateChartSeriesValues`, `setChartTitle`, `setChartGrouping`, `updateChartDataPoint`, `addChartCategory`, `removeChartCategory` |
768
- | **Shapes** | `replaceShapeGeometry`, `replaceWithCustomGeometry`, `interpolateShapeGeometry`, `parseSvgPath`, `serializeSvgPath` |
769
- | **Slides** | `duplicateSlide`, `duplicateElement` |
770
- | **Sections** | `addSection`, `removeSection`, `reorderSections`, `getSectionForSlide`, `moveSlidesToSection` |
771
- | **Merge** | `mergePresentation` |
772
- | **Diff** | `diffPresentations`, `diffSlides` |
773
- | **Template** | `applyTemplate`, `findPlaceholders`, `mailMerge` |
774
- | **Layout** | `createLayout`, `createLayouts`, `findLayoutByName`, `findLayoutByType`, `generateLayoutXml` |
775
-
776
- **PptxElementXmlBuilder** — Low-level element XML construction:
777
-
778
- - Builds `<p:sp>`, `<p:pic>`, `<p:cxnSp>`, `<p:graphicFrame>` nodes
779
- - Factory per element type: `TextShapeXmlFactory`, `PictureXmlFactory`, `ConnectorXmlFactory`, `MediaGraphicFrameXmlFactory`
780
-
781
- ### 9. Encryption and Security
782
-
783
- The engine handles several security-related PPTX features:
784
-
785
- | Feature | Description |
786
- | ------------------------------ | ------------------------------------------------------------------------------------------- |
787
- | **PPTX Encryption/Decryption** | AES-128/256 Agile encryption per [MS-OFFCRYPTO]. Reads and writes password-protected files. |
788
- | **Modify Password** | SHA-based hash verifier for write-protection (does not prevent opening). |
789
- | **Digital Signatures** | Detects and can strip XML digital signatures (`_xmlsignatures` parts). |
790
- | **Encrypted File Detection** | Identifies OLE compound file format (CFB) wrapping encrypted PPTX content. |
791
-
792
- ---
793
-
794
- ## Type System Reference
795
-
796
- The core type system uses **EMU (English Metric Units)** as the native coordinate system, matching PowerPoint's internal representation:
797
-
798
- ```
799
- 1 inch = 914,400 EMU
800
- 1 cm = 360,000 EMU
801
- 1 point = 12,700 EMU
802
- 1 pixel = 9,525 EMU (at 96 DPI)
803
- ```
804
-
805
- **PptxData** -- the top-level parsed result:
806
-
807
- ```typescript
808
- interface PptxData {
809
- slides: PptxSlide[];
810
- canvasSize: PptxCanvasSize;
811
- theme?: PptxTheme;
812
- slideMasters: PptxSlideMaster[];
813
- slideLayouts: PptxSlideLayout[];
814
- sections: PptxSection[];
815
- customShows: PptxCustomShow[];
816
- presentationProperties: PresentationProperties;
817
- coreProperties: CoreProperties;
818
- appProperties: AppProperties;
819
- customProperties: CustomProperty[];
820
- embeddedFonts: EmbeddedFont[];
821
- // ...
822
- }
823
- ```
824
-
825
- **PptxSlide** -- a single slide:
826
-
827
- ```typescript
828
- interface PptxSlide {
829
- id: string;
830
- elements: PptxElement[];
831
- background?: SlideBackground;
832
- transition?: PptxSlideTransition;
833
- notes?: string;
834
- hidden?: boolean;
835
- layoutPath?: string;
836
- // ...
837
- }
838
- ```
839
-
840
- ---
841
-
842
- ## Feature Summary
843
-
844
- | Category | Details |
845
- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
846
- | **Element Types** | 16: text, shape, connector, image, picture, table, chart, smartArt, ole, media, group, ink, contentPart, zoom, model3d, unknown |
847
- | **Preset Shapes** | 187+ with guide formula evaluation and adjustment handles |
848
- | **Chart Types** | 23: bar, column, line, area, pie, doughnut, scatter, bubble, radar, stock, surface/3D, histogram, waterfall, funnel, treemap, sunburst, boxWhisker, regionMap, combo |
849
- | **Chart Features** | Display units, logarithmic axes, chart color styles, embedded Excel data, pivot sources, trendlines, error bars, data tables |
850
- | **Transitions** | 42 types including morph, vortex, ripple, shred, and p14 extensions |
851
- | **Animations** | 40+ presets with color animations, motion path auto-rotation, text build (by word/letter/paragraph) |
852
- | **SmartArt** | 13 layout types (list, process, cycle, hierarchy, matrix, gear, etc.) |
853
- | **Fills** | Solid, gradient (linear/radial/path), image, 48 pattern presets |
854
- | **Text Features** | Warp (24+ presets), inline math (OMML to MathML), multi-column, text field substitution |
855
- | **Themes** | 8 built-in presets, runtime switching, layout/placeholder remapping |
856
- | **3D** | ThreeDProperties for shapes and text, extrusion, bevel, material, lighting |
857
- | **Security** | AES-128/256 encryption/decryption, modify password (SHA), digital signature detection |
858
- | **Preservation** | VBA macros, custom XML parts, comment authors, OOXML Strict namespaces |
859
- | **Other** | Kiosk mode, custom shows, sections, tags, print settings, photo album, guide lines, embedded font deobfuscation |
860
-
861
- ---
862
-
863
- ## File Structure Reference
172
+ ## Limitations
864
173
 
865
- ```
866
- src/
867
- +-- index.ts # Package entry -- re-exports core + converter
868
- |
869
- +-- core/ # Core PPTX engine (247 files)
870
- | +-- index.ts # Core barrel export
871
- | +-- PptxHandler.ts # Public facade class
872
- | +-- PptxHandlerCore.ts # Facade over IPptxHandlerRuntime
873
- | +-- constants.ts # EMU conversion, XML namespaces
874
- | +-- constants-colors.ts # Named colour constants
875
- | |
876
- | +-- types/ # Type system (22 files)
877
- | | +-- index.ts # Barrel re-export
878
- | | +-- common.ts # PptxData, PptxSlide, XmlObject
879
- | | +-- elements.ts # PptxElement discriminated union (16 variants)
880
- | | +-- element-base.ts # PptxElementBase shared props
881
- | | +-- text.ts # TextStyle, Paragraph, TextSegment
882
- | | +-- shape-style.ts # ShapeStyle, FillStyle, StrokeStyle
883
- | | +-- table.ts # TableData, TableCell, TableRow
884
- | | +-- chart.ts # PptxChartData, ChartSeries (23 types)
885
- | | +-- theme.ts # PptxTheme, colour/font schemes
886
- | | +-- animation.ts # PptxElementAnimation
887
- | | +-- transition.ts # PptxSlideTransition (42 types)
888
- | | +-- masters.ts # PptxSlideMaster, PptxSlideLayout
889
- | | +-- image.ts # ImageEffects, ImageCrop
890
- | | +-- geometry.ts # PptxCustomGeometry
891
- | | +-- smart-art.ts # PptxSmartArtData
892
- | | +-- media.ts # PptxMediaData, MediaTiming
893
- | | +-- metadata.ts # CoreProperties, AppProperties
894
- | | +-- presentation.ts # PresentationProperties
895
- | | +-- view-properties.ts # ViewProperties
896
- | | +-- three-d.ts # ThreeDProperties
897
- | | +-- actions.ts # ElementAction, hyperlinks
898
- | | +-- type-guards.ts # isShape(), isImage(), etc.
899
- | |
900
- | +-- core/ # Runtime engine (128 files)
901
- | | +-- index.ts # Runtime barrel export
902
- | | +-- PptxHandlerRuntime.ts # Sealed final class
903
- | | +-- PptxHandlerRuntimeFactory.ts # DI factory + interface
904
- | | +-- types.ts # IPptxHandlerRuntime interface
905
- | | |
906
- | | +-- runtime/ # Mixin modules (84 files)
907
- | | | +-- PptxHandlerRuntimeState.ts # Base state (fields, ZIP, parser)
908
- | | | +-- PptxHandlerRuntimeThemeLoading.ts
909
- | | | +-- PptxHandlerRuntimeThemeProcessing.ts
910
- | | | +-- PptxHandlerRuntimeSlideParsing.ts
911
- | | | +-- PptxHandlerRuntimeElementParsing.ts
912
- | | | +-- PptxHandlerRuntimeShapeParsing.ts
913
- | | | +-- PptxHandlerRuntimeShapeTextParsing.ts
914
- | | | +-- PptxHandlerRuntimeChartParsing.ts
915
- | | | +-- PptxHandlerRuntimeSmartArtParsing.ts
916
- | | | +-- PptxHandlerRuntimeLoadPipeline.ts # load() entry point
917
- | | | +-- PptxHandlerRuntimeSavePipeline.ts # save() entry point
918
- | | | +-- PptxHandlerRuntimeSaveElementWriter.ts
919
- | | | +-- PptxHandlerRuntimeSaveTextWriter.ts
920
- | | | +-- PptxHandlerRuntimeImplementation.ts # Top of chain
921
- | | | +-- ...40+ more mixin modules
922
- | | |
923
- | | +-- builders/ # Runtime builders (40 files)
924
- | | | +-- PptxColorStyleCodec.ts
925
- | | | +-- PptxConnectorParser.ts
926
- | | | +-- PptxContentTypesBuilder.ts
927
- | | | +-- PptxGraphicFrameParser.ts
928
- | | | +-- PptxTableDataParser.ts
929
- | | | +-- PptxShapeStyleExtractor.ts
930
- | | | +-- PptxShapeEffectXmlBuilder.ts
931
- | | | +-- ...33 more builders
932
- | | |
933
- | | +-- factories/ # DI factories (4 files)
934
- | | +-- PptxRuntimeDependencyFactory.ts
935
- | | +-- PptxSaveConstantsFactory.ts
936
- | | +-- types.ts
937
- | |
938
- | +-- geometry/ # Shape geometry (17 files)
939
- | | +-- shape-geometry.ts # Shape type -> clip path resolution
940
- | | +-- connector-geometry.ts # Connector path generation
941
- | | +-- guide-formula.ts # OOXML guide formula API
942
- | | +-- guide-formula-eval.ts # Expression evaluation
943
- | | +-- preset-shape-definitions.ts # 187+ preset shapes
944
- | | +-- preset-shape-paths.ts # Pre-computed clip paths
945
- | | +-- custom-geometry.ts # Custom geometry parsing
946
- | | +-- transform-utils.ts # Position/rotation transforms
947
- | |
948
- | +-- color/ # Colour processing (4 files)
949
- | | +-- color-utils.ts # Main API (parseDrawingColor, etc.)
950
- | | +-- color-primitives.ts # Hex <-> RGB <-> HSL conversions
951
- | | +-- color-transforms.ts # OOXML colour transform application
952
- | |
953
- | +-- builders/ # XML builder APIs (11 files)
954
- | | +-- PptxElementXmlBuilder.ts # Low-level element XML builder
955
- | | +-- fluent/
956
- | | | +-- PptxXmlBuilder.ts # Fluent chainable builder
957
- | | +-- factories/
958
- | | +-- TextShapeXmlFactory.ts
959
- | | +-- PictureXmlFactory.ts
960
- | | +-- ConnectorXmlFactory.ts
961
- | | +-- MediaGraphicFrameXmlFactory.ts
962
- | |
963
- | +-- services/ # Service classes (21 files)
964
- | | +-- PptxSlideLoaderService.ts
965
- | | +-- PptxNativeAnimationService.ts
966
- | | +-- PptxEditorAnimationService.ts
967
- | | +-- PptxAnimationWriteService.ts
968
- | | +-- PptxSlideTransitionService.ts
969
- | | +-- PptxCompatibilityService.ts
970
- | | +-- PptxXmlLookupService.ts
971
- | | +-- PptxDocumentPropertiesUpdater.ts
972
- | | +-- PptxTemplateBackgroundService.ts
973
- | |
974
- | +-- utils/ # Utility functions (32 files)
975
- | +-- clone-utils.ts # Deep clone for slides, elements, styles
976
- | +-- element-utils.ts # Element labels, text content, actions
977
- | +-- stroke-utils.ts # Dash styles, border rendering
978
- | +-- data-url-utils.ts # Data URL <-> byte conversions
979
- | +-- encryption-detection.ts # CFB/OLE format detection
980
- | +-- ooxml-crypto.ts # AES-128/256 encryption/decryption
981
- | +-- signature-detection.ts # Digital signature detection
982
- | +-- font-deobfuscation.ts # OOXML font deobfuscation
983
- | +-- smartart-decompose.ts # SmartArt -> individual shapes
984
- | +-- smartart-editing.ts # SmartArt node CRUD operations
985
- | +-- chart-advanced-parser.ts # Trendlines, error bars, data tables
986
- | +-- chart-axis-parser.ts # Axis parsing (value, category, date)
987
- | +-- chart-cx-parser.ts # ChartEx (cx:chart) parsing
988
- | +-- ole-utils.ts # OLE object type detection
989
- | +-- guide-utils.ts # Drawing guide EMU <-> px conversions
990
- | +-- theme-override-utils.ts # Theme colour map override handling
991
- | +-- vml-parser.ts # VML (Vector Markup Language) parsing
992
- | +-- strict-namespace-map.ts # Strict OOXML namespace normalisation
993
- |
994
- +-- converter/ # PPTX -> Markdown (20 files)
995
- +-- index.ts # Converter barrel export
996
- +-- PptxMarkdownConverter.ts # Main converter orchestrator
997
- +-- SlideProcessor.ts # Per-slide markdown generation
998
- +-- base.ts # Abstract DocumentConverter base
999
- +-- types.ts # FileSystemAdapter, ConversionOptions
1000
- +-- media-context.ts # Media extraction & deduplication
1001
- +-- elements/ # Element processors (11 files)
1002
- +-- ElementProcessor.ts # Abstract base processor
1003
- +-- TextElementProcessor.ts # Shapes -> markdown text
1004
- +-- ImageElementProcessor.ts # Images -> ![alt](path)
1005
- +-- TableElementProcessor.ts # Tables -> markdown tables
1006
- +-- ChartElementProcessor.ts # Charts -> data summaries
1007
- +-- SmartArtElementProcessor.ts # SmartArt -> structured text
1008
- +-- GroupElementProcessor.ts # Groups -> recursive processing
1009
- +-- MediaElementProcessor.ts # Audio/video -> link references
1010
- +-- OleElementProcessor.ts # OLE objects -> descriptions
1011
- +-- InkElementProcessor.ts # Ink annotations -> descriptions
1012
- +-- FallbackElementProcessor.ts # Unknown elements -> placeholder
1013
- ```
174
+ - **OLE objects** (embedded Word docs, spreadsheets, and similar) are read-only: you get their preview image, not their contents.
175
+ - **SmartArt** is broken into editable shapes using the drawing data PowerPoint already saved in the file. There is no engine that re-flows the layout if you change it.
176
+ - **Chart editing is data-only**: you can change series, data points, categories, and the chart type. Other chart properties are read for display but cannot be edited.
177
+ - **Strict-format files** (ISO/IEC 29500 Strict) are converted to the more common Transitional form when opened and converted back when saved.
1014
178
 
1015
- ---
179
+ See the [full docs](https://christophervr.github.io/pptx-viewer/) for the details behind each of these.
1016
180
 
1017
- ## Limitations
181
+ ## License
1018
182
 
1019
- - **Embedded OLE objects are read-only** -- OLE objects (embedded Excel, Word, etc.) are recognised and their preview images are displayed, but their internal content cannot be edited. OLE2 is an opaque binary container format -- deserialising and re-serialising the internal object structure (e.g. an embedded Excel workbook) would require embedding the full application runtime.
1020
- - **SmartArt uses static shape decomposition** -- SmartArt diagrams are decomposed into individual positioned shapes using PowerPoint's own pre-computed drawing data (13 layout types). The shapes are fully editable, but there is no live SmartArt reflow engine -- moving or reordering shapes won't automatically recalculate the layout the way PowerPoint's built-in SmartArt engine does.
1021
- - **3D effects** -- 3D properties are fully parsed into `ThreeDProperties` (extrusion, bevel, material, lighting). Rendering uses CSS 3D transforms in the React viewer. 3D model elements (GLB/GLTF) require Three.js as an optional peer dependency.
1022
- - **Chart editing is data-level only** -- You can add/remove series, edit data points, add/remove categories, and change chart type. However, structural chart properties (axis formatting, legend placement, data labels, trendlines, error bars) are parsed for display but not exposed for programmatic editing.
1023
- - **Strict OOXML conformance is normalised** -- Office 365 can save files in ISO/IEC 29500 Strict mode, which uses different namespace URIs than the more common Transitional (ECMA-376) format. The engine maps 46+ namespace URI pairs on load (Strict -> Transitional) and converts back on save. Features that rely on strict-only extensions outside these mapped namespaces may not round-trip.
183
+ [Apache-2.0](LICENSE). Please keep the [`NOTICE`](NOTICE) file with redistributions.