@openpresentation/opf-render 0.17.1 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +75 -66
- package/dist/deck-runtime.js +4 -4
- package/dist/element.d.ts +12 -9
- package/dist/element.js +14 -12
- package/dist/export-browser.d.ts +21 -11
- package/dist/export-browser.js +33 -20
- package/dist/font-subset.js +1 -1
- package/dist/fonts-browser.d.ts +24 -24
- package/dist/fonts-browser.js +12 -12
- package/dist/fonts-node.d.ts +9 -9
- package/dist/fonts-node.js +4 -4
- package/dist/fonts.d.ts +6 -6
- package/dist/index.d.ts +51 -30
- package/dist/index.js +1 -1
- package/dist/lazy-fonts.js +10 -10
- package/dist/pdf-fonts.js +1 -1
- package/dist/pdf-vector.js +2 -2
- package/dist/pdf.d.ts +2 -2
- package/dist/pdf.js +3 -3
- package/dist/player.d.ts +3 -3
- package/dist/player.js +1 -1
- package/dist/png.d.ts +2 -2
- package/dist/png.js +2 -2
- package/dist/raster.js +33 -28
- package/dist/script-font-pack.js +5 -5
- package/dist/slide-sources.js +47 -0
- package/dist/svg.d.ts +24 -29
- package/dist/svg.js +45 -30
- package/dist/text-paths.js +3 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
# OPF Render
|
|
2
2
|
|
|
3
|
+
**OPF 0.18 (RR-73, RR-74, unreleased; requires core 0.18).** One shape for every engine: `toX(deck, slides?, options?)`. The second argument is a slide number (one result), a selection (`"1-3"`, `"1,3-5"`, `"2-"`, `[1, 3]`; a list of results) or the options, told apart by type, and slides count from 1. Renamed and removed outright (no aliases); an old option fails with `invalid-render-options` or `invalid-conversion-option` and names its replacement:
|
|
4
|
+
|
|
5
|
+
| 0.17 | 0.18 |
|
|
6
|
+
| --- | --- |
|
|
7
|
+
| `renderSvg(deck, options)` | `toSvg(deck, options)` |
|
|
8
|
+
| `renderSlideSvg(deck, index, options)` (from 0) | `toSvg(deck, index + 1, options)` (from 1; `slide-out-of-range`) |
|
|
9
|
+
| `svgToPng(svg, options)`, `svgToPdf(svgs, options)` | `toPng` and `toPdf`: they take a deck (and draw it with `toSvg`) or SVG |
|
|
10
|
+
| `renderDeckHtml(deck, { slides })` | `toHtml(deck, slides?, options?)` (`"1-"` for every slide) |
|
|
11
|
+
| `embedFonts: false`, `textAsPaths: true` | `text: "system"`, `text: "paths"` (default `"fonts"`) |
|
|
12
|
+
| `mode: "raster"` | `raster: true` (vector is the default) |
|
|
13
|
+
| `fontDirs` | `fonts`: the handle, or font folders (a path or a list) for SVG input |
|
|
14
|
+
|
|
3
15
|
**OPF 0.15 (FA-23, unreleased; requires core 0.15).** Catalogs are registered by the host, and every picture is an image background or an image block. The breaking changes are listed in `changes/fa-23-opf-0-15.md` (the next CHANGELOG section); the [0.15 design](https://github.com/OpenPresentation/opf/blob/main/docs/programs/format-audit/0.15-design.md) explains them.
|
|
4
16
|
|
|
5
|
-
- The renderer bundles, looks up and fetches no catalog. Every entry point (`
|
|
17
|
+
- The renderer bundles, looks up and fetches no catalog. Every entry point (`toSvg`, `resolvePresentation`, the font loaders' `renderOptions`, `/player`, `<opf-deck>`) takes core's `catalogs: Catalog[]` and passes it unchanged to core resolution. Register the gallery snapshot yourself: `import { defaultCatalog } from '@openpresentation/opf/catalog'` and `toSvg(deck, { catalogs: [defaultCatalog] })`. `strictReferences: true` fails with `unresolved-reference` instead of falling back.
|
|
6
18
|
- What resolves nowhere draws with core's engine defaults (`engineDefaults` is `{ theme, colorScheme, fontScheme, chartType }`: core's `ENGINE_DEFAULT_THEME`, `ENGINE_DEFAULT_COLOR_SCHEME`, `ENGINE_DEFAULT_FONT_SCHEME`) and is reported once per reference as `unresolved-reference`.
|
|
7
19
|
- An image background (`design.background: { type: "image", src, alt, fit, focus, opacity, recolor, overlay }`, or an image source string) draws from core's `geometry.backgroundImage`: the canvas colour, the picture (cover, contain, stretch or tile; recolor and opacity on the pixels only), then the overlay (the whole slide or an edge band). `alt` is the picture's accessible name; without it the picture is decorative.
|
|
8
20
|
- Every content picture is an image block drawn from `item.image`: frame, fit (`cover`, `contain`, `stretch`; default `design.imageFit`, else `cover`), focus, shape mask, border, opacity, recolor and overlay, and a placed block (`placement`) at its edge band.
|
|
@@ -19,16 +31,16 @@
|
|
|
19
31
|
|
|
20
32
|
```js
|
|
21
33
|
import { loadFonts } from '@openpresentation/opf-render/fonts-node';
|
|
22
|
-
import {
|
|
34
|
+
import { toSvg, toPng, toPdf } from '@openpresentation/opf-render';
|
|
23
35
|
import { paginate } from '@openpresentation/opf/pagination';
|
|
24
36
|
import { toPptx } from '@openpresentation/opf-pptx';
|
|
25
37
|
|
|
26
38
|
const fonts = await loadFonts({ pack: 'office', substitutionPolicy: 'visual' });
|
|
27
39
|
const { presentation } = paginate(opf, { fonts });
|
|
28
|
-
const slides =
|
|
29
|
-
const first =
|
|
30
|
-
const png = await
|
|
31
|
-
const pdf = await
|
|
40
|
+
const slides = toSvg(presentation, { fonts }); // every slide
|
|
41
|
+
const first = toSvg(presentation, 1, { fonts }); // one slide
|
|
42
|
+
const png = await toPng(slides[0], { fonts });
|
|
43
|
+
const pdf = await toPdf(slides, { fonts });
|
|
32
44
|
const pptx = await toPptx(presentation, { fonts });
|
|
33
45
|
```
|
|
34
46
|
|
|
@@ -36,9 +48,9 @@ A slide's canvas, layout, theme, colour scheme and font scheme come from core's
|
|
|
36
48
|
|
|
37
49
|
An option a function does not know is not read: a top-level `textMeasurement` or `embeddedFonts` is ignored, so pass `{ fonts }`.
|
|
38
50
|
|
|
39
|
-
**Aptos previews with Intos.** The Office pack includes Intos, Intos Display, Intos Narrow and Intos Serif (16 faces, about 12 MB, vendored under `fonts/intos/`, SIL OFL 1.1, pinned to upstream commit fef9315c14da9e4b23b4c3cac8e718998d4e4736 and per-file SHA-256, unmodified from the upstream files). They are the metric-compatible previews for Aptos, Aptos Display, Aptos Narrow and Aptos Serif, the default `aptos` font scheme: 0.000% mean and maximum width difference against Aptos 2.01 in all four styles, with equal vertical metrics. The letter shapes are Intos's own, not Aptos's. The exported PPTX still names Aptos; no Aptos file is bundled or embedded. A registry built without these faces (the base pack) has no Aptos substitute: visual policy falls back to Roboto or Carlito. Like the open families, Intos is `embed: "used"`: it is not in `registry.embeddedFonts` (the 33 eager npm faces), the `loadFonts()` handle's `embeddedFonts` supplies it, and an SVG embeds only the Intos faces its text draws. `registry.lazyFonts` lists the 51 vendored faces (35 open, 16 Intos) with package-relative file and sha256, and `loadFonts({ faces, lazyFontsBaseUrl })` from `/fonts-browser` loads them on demand: `await fonts.ensure(presentation)` (the registry's `ensureLazyFonts` and `ensureScripts` are the lower-level calls) fetches and verifies only the faces the document draws, by family, weight and style (a plain Aptos deck: Intos Display Bold and Intos Regular, 2 files, 1.5 MB; an italic run adds Intos Italic, a bold run Intos Bold; the code face only when a slide has code), then adds them to the document and the registry together so measurement and painting never disagree. Faces a host serves itself load the same way: `loadFonts({ faces: startup, extraLazyFonts: [{ family, weight, italic, url, sha256 }] })` adds them to the lazy list (`registry.lazyFonts`, `package: "host"`), so the registry can start with Roboto Regular only (`splitStartupFaces(faces)` splits a manifest into the startup face and the rest) and a document draws, fetches and verifies just the faces it needs, vendored and host faces in one `ensureLazyFonts` call. `sha256` is mandatory, loads are all or nothing, `dispose()` removes the faces, and, like the vendored ones, host faces are `embed: "used"`: they are not in `registry.embeddedFonts` (only the startup faces are), and a standalone SVG embeds one only when passed explicitly through `registry.selectEmbeddedFonts` and the slide's text uses its family. `fonts.pending(presentation)` (and the registry's `pendingLazyFonts`) is the synchronous check hosts gate rendering on, and after an edit it reports just the newly needed faces. The faces are those the renderer itself measures and draws (`presentationFaces(presentation, options, registry)`, one layout-and-paint run with a recording measurement), resolved by the registry's own face selection over the faces it holds plus the vendored ones, so the browser loads exactly what Node draws with every vendored face loaded. A document resolves with the `
|
|
51
|
+
**Aptos previews with Intos.** The Office pack includes Intos, Intos Display, Intos Narrow and Intos Serif (16 faces, about 12 MB, vendored under `fonts/intos/`, SIL OFL 1.1, pinned to upstream commit fef9315c14da9e4b23b4c3cac8e718998d4e4736 and per-file SHA-256, unmodified from the upstream files). They are the metric-compatible previews for Aptos, Aptos Display, Aptos Narrow and Aptos Serif, the default `aptos` font scheme: 0.000% mean and maximum width difference against Aptos 2.01 in all four styles, with equal vertical metrics. The letter shapes are Intos's own, not Aptos's. The exported PPTX still names Aptos; no Aptos file is bundled or embedded. A registry built without these faces (the base pack) has no Aptos substitute: visual policy falls back to Roboto or Carlito. Like the open families, Intos is `embed: "used"`: it is not in `registry.embeddedFonts` (the 33 eager npm faces), the `loadFonts()` handle's `embeddedFonts` supplies it, and an SVG embeds only the Intos faces its text draws. `registry.lazyFonts` lists the 51 vendored faces (35 open, 16 Intos) with package-relative file and sha256, and `loadFonts({ faces, lazyFontsBaseUrl })` from `/fonts-browser` loads them on demand: `await fonts.ensure(presentation)` (the registry's `ensureLazyFonts` and `ensureScripts` are the lower-level calls) fetches and verifies only the faces the document draws, by family, weight and style (a plain Aptos deck: Intos Display Bold and Intos Regular, 2 files, 1.5 MB; an italic run adds Intos Italic, a bold run Intos Bold; the code face only when a slide has code), then adds them to the document and the registry together so measurement and painting never disagree. Faces a host serves itself load the same way: `loadFonts({ faces: startup, extraLazyFonts: [{ family, weight, italic, url, sha256 }] })` adds them to the lazy list (`registry.lazyFonts`, `package: "host"`), so the registry can start with Roboto Regular only (`splitStartupFaces(faces)` splits a manifest into the startup face and the rest) and a document draws, fetches and verifies just the faces it needs, vendored and host faces in one `ensureLazyFonts` call. `sha256` is mandatory, loads are all or nothing, `dispose()` removes the faces, and, like the vendored ones, host faces are `embed: "used"`: they are not in `registry.embeddedFonts` (only the startup faces are), and a standalone SVG embeds one only when passed explicitly through `registry.selectEmbeddedFonts` and the slide's text uses its family. `fonts.pending(presentation)` (and the registry's `pendingLazyFonts`) is the synchronous check hosts gate rendering on, and after an edit it reports just the newly needed faces. The faces are those the renderer itself measures and draws (`presentationFaces(presentation, options, registry)`, one layout-and-paint run with a recording measurement), resolved by the registry's own face selection over the faces it holds plus the vendored ones, so the browser loads exactly what Node draws with every vendored face loaded. A document resolves with the `toSvg` options the host renders with: pass them as `loadFonts({ faces, renderOptions: { catalogs } })`, or per call (`pendingLazyFonts(presentation, { catalogs })`, `ensureLazyFonts(presentation, { signal, catalogs })`), so a layout or font scheme id that only the host's catalogs know resolves here too; a document that does not resolve throws (rejects) what `toSvg` throws for it instead of reporting nothing. Node's `loadFonts` keeps loading the whole open pack and Intos eagerly, so nothing there is face level; with `scripts: 'auto'` they accept `renderOptions: { catalogs }` too. Hosts copy the vendored directories next to the page.
|
|
40
52
|
|
|
41
|
-
Version 0.12.0 requires `@openpresentation/opf` ^0.12.0 (composed font sizes on PowerPoint's 0.01 pt grid, hanging wrap whitespace, promoted regions in reading order, right-to-left decks composed mirrored) and draws what that core composes, plus the preview changes listed in the changelog; use it with opf-pptx 0.12.0 and opf-editor 0.11.0 so preview and export resolve one core. Version 0.11.9 requires `@openpresentation/opf` ^0.11.4 and draws the design fields (deck and organization logos on covers and section slides, header and footer `logo` parts, `design.listBullet: image` picture bullets at the size PowerPoint draws them, the accent font, `contentDirection` and `chartPrimary` through core composition), and the slide tag falls back to the text colour when the scheme primary is under 4.5:1 against the background; furniture images sit on their zone edge. Use it with opf-pptx 0.11.7 and opf-editor 0.10.6 so preview and export resolve one core (no API change; the preview of covers, list slides with picture bullets, chart slides with a primary chart and slides with furniture images changes). Version 0.11.8 draws the slide tag in the scheme primary colour, as opf-pptx 0.11.5 writes it (no API change; the preview of slides with a tag changes). Version 0.11.7 lets a browser registry load the host's own faces on demand (`extraLazyFonts`, `splitStartupFaces`: a registry can start with Roboto Regular only; additive, `registry.lazyFonts` still lists the 94 vendored faces plus the host's). Version 0.11.6 makes the category-axis labels of chart previews rotate and skip instead of wrapping mid-word (no API change; the preview of dense-axis chart slides changes) and requires `@openpresentation/opf` ^0.11.3 (the 70 legacy gallery layout ids and their geometry); use it with PPTX 0.11.4 and editor 0.10.4 so preview and export resolve the same core. Version 0.11.5 loads vendored preview fonts by face, not by family, and lets the font loaders resolve documents with the host's render options (`presentationFaces`, `lazyFacesNeeded`; `pendingLazyFonts`, `ensureLazyFonts`, `pendingScripts` and `ensureScripts` take `catalogs` and throw or reject with the `
|
|
53
|
+
Version 0.12.0 requires `@openpresentation/opf` ^0.12.0 (composed font sizes on PowerPoint's 0.01 pt grid, hanging wrap whitespace, promoted regions in reading order, right-to-left decks composed mirrored) and draws what that core composes, plus the preview changes listed in the changelog; use it with opf-pptx 0.12.0 and opf-editor 0.11.0 so preview and export resolve one core. Version 0.11.9 requires `@openpresentation/opf` ^0.11.4 and draws the design fields (deck and organization logos on covers and section slides, header and footer `logo` parts, `design.listBullet: image` picture bullets at the size PowerPoint draws them, the accent font, `contentDirection` and `chartPrimary` through core composition), and the slide tag falls back to the text colour when the scheme primary is under 4.5:1 against the background; furniture images sit on their zone edge. Use it with opf-pptx 0.11.7 and opf-editor 0.10.6 so preview and export resolve one core (no API change; the preview of covers, list slides with picture bullets, chart slides with a primary chart and slides with furniture images changes). Version 0.11.8 draws the slide tag in the scheme primary colour, as opf-pptx 0.11.5 writes it (no API change; the preview of slides with a tag changes). Version 0.11.7 lets a browser registry load the host's own faces on demand (`extraLazyFonts`, `splitStartupFaces`: a registry can start with Roboto Regular only; additive, `registry.lazyFonts` still lists the 94 vendored faces plus the host's). Version 0.11.6 makes the category-axis labels of chart previews rotate and skip instead of wrapping mid-word (no API change; the preview of dense-axis chart slides changes) and requires `@openpresentation/opf` ^0.11.3 (the 70 legacy gallery layout ids and their geometry); use it with PPTX 0.11.4 and editor 0.10.4 so preview and export resolve the same core. Version 0.11.5 loads vendored preview fonts by face, not by family, and lets the font loaders resolve documents with the host's render options (`presentationFaces`, `lazyFacesNeeded`; `pendingLazyFonts`, `ensureLazyFonts`, `pendingScripts` and `ensureScripts` take `catalogs` and throw or reject with the `toSvg` error for a document that does not resolve; `registry.lazyFonts` still lists 94 faces). Version 0.11.4 previews the seven chartex chart types natively (the world map as a non-geographic tile grid), keeps the Latin Noto Sans replacement for script schemes under `scripts: 'auto'` in Node, shapes Noto Sans Mongolian again and bundles Raleway and Playfair Display (`registry.lazyFonts` lists 94 faces; no API change). Version 0.11.3 previews the classic chart types natively, draws deprecated chart ids as their replacement and scales value axes like Office (no API change; the preview of chart slides changes). Version 0.11.2 makes `scripts: 'auto'` load the script faces a font scheme names and adds `details.loadedFaceHasGlyph` to `missing-glyph` (no export change). Version 0.11.1 adds the open replacement font families the policy routes to and complete Red Hat styles (no API change). Version 0.11.0 requires `@openpresentation/opf` ^0.11.2 (cover centering, Intos Aptos previews, lazy font loading, automatic script fonts and glyph fallback); use it with PPTX 0.11.0 and editor 0.10.0 so preview and export resolve the same core. Version 0.10.0 required `@openpresentation/opf` ^0.11.1 (font policy table, script fonts and right-to-left paragraphs, socials, image treatments, formatted slide-number and date furniture with the host `date` option, per-item alignment). See the changelog for the intentional preview-output changes.
|
|
42
54
|
|
|
43
55
|
Version 0.9.0 required `@openpresentation/opf` ^0.11.0 and resolved content ColorRef / `variables` through core `resolveColorRef()`. Authored `#RRGGBB` paint stays authored. It retains the existing rendering APIs.
|
|
44
56
|
|
|
@@ -64,7 +76,7 @@ Citations, footnotes and captions (core RR-34 fields `cite`, `footnote`, `refere
|
|
|
64
76
|
|
|
65
77
|
```js
|
|
66
78
|
import { loadFonts } from '@openpresentation/opf-render/fonts-node';
|
|
67
|
-
import {
|
|
79
|
+
import { toSvg, toPng } from '@openpresentation/opf-render';
|
|
68
80
|
import { paginate } from '@openpresentation/opf/pagination';
|
|
69
81
|
import { toPptx } from '@openpresentation/opf-pptx';
|
|
70
82
|
|
|
@@ -72,8 +84,8 @@ const fonts = await loadFonts({
|
|
|
72
84
|
pack: 'office', substitutionPolicy: 'visual',
|
|
73
85
|
});
|
|
74
86
|
const { presentation } = paginate(opf, { fonts });
|
|
75
|
-
const slides =
|
|
76
|
-
const png = await
|
|
87
|
+
const slides = toSvg(presentation, { fonts });
|
|
88
|
+
const png = await toPng(slides[0], { fonts });
|
|
77
89
|
const pptx = await toPptx(presentation, { fonts });
|
|
78
90
|
console.log(fonts.substitutions);
|
|
79
91
|
```
|
|
@@ -97,8 +109,8 @@ Code strings that [XML 1.0 cannot represent](https://www.w3.org/TR/xml/#charsets
|
|
|
97
109
|
| SVG in Node with exact text measurement | `/svg` and `loadFonts` from `/fonts-node` | the font packages of the pack (below) |
|
|
98
110
|
| PNG in Node | `/png` (or the root) | `npm install @resvg/resvg-js` (`sharp` too for WebP and rotated JPEG pictures) and the fonts of the pack |
|
|
99
111
|
| PDF in Node (vector, the default) | `/pdf` (or the root) | the fonts of the pack; `sharp` for pictures; `@resvg/resvg-js` for the rare element drawn as an image (a filter, a mask) |
|
|
100
|
-
| PDF in Node, `
|
|
101
|
-
| PNG and PDF in a browser | `/export-browser` | nothing (`
|
|
112
|
+
| PDF in Node, `raster: true` | `/pdf` (or the root) | `pdf-lib`, `@resvg/resvg-js`, `sharp` and the fonts of the pack |
|
|
113
|
+
| PNG and PDF in a browser | `/export-browser` | nothing (`raster: true` needs `pdf-lib`, see below) |
|
|
102
114
|
| Slideshow, `<opf-deck>`, server markup | `/player`, `/element`, `/element/define` | nothing |
|
|
103
115
|
|
|
104
116
|
The font packages are pinned exactly (`@expo-google-fonts/*`, each a pinned optional peer; what each pack holds is described under `pack` above and in [Script fonts](#script-fonts-lang-and-right-to-left-text-ff-19)). `loadFonts()` (pack `base`) needs `@expo-google-fonts/roboto@0.4.3` and `roboto-mono@0.4.2`; `loadFonts({ pack: 'office' })` also needs `arimo`, `caladea`, `cousine`, `gelasio`, `tinos` and `noto-sans`. A script face (`scripts: ['Jpan']`, `scripts: 'auto'`) needs its own `@expo-google-fonts/noto-*` package. The `fonts/` directory (the vendored Carlito, Intos and open families, about 28 MB) ships inside the package.
|
|
@@ -109,30 +121,30 @@ Converter ranges: `@resvg/resvg-js@^2.6.2`, `sharp@^0.35.5`, `pdf-lib@^1.17.1`.
|
|
|
109
121
|
|
|
110
122
|
| Entry | What it is | Runs in |
|
|
111
123
|
| --- | --- | --- |
|
|
112
|
-
| `@openpresentation/opf-render/svg` | `
|
|
113
|
-
| `@openpresentation/opf-render/png` | `
|
|
114
|
-
| `@openpresentation/opf-render/pdf` | `
|
|
115
|
-
| `@openpresentation/opf-render/export-browser` | `
|
|
116
|
-
| `@openpresentation/opf-render/element`, `/element/define`, `/player` | `
|
|
117
|
-
| `@openpresentation/opf-render` | all of `/svg`, plus `
|
|
124
|
+
| `@openpresentation/opf-render/svg` | `toSvg`, `resolvePresentation`, `OPFRenderError` and the types. No converter, no Node module. | browser and Node |
|
|
125
|
+
| `@openpresentation/opf-render/png` | `toPng` | Node |
|
|
126
|
+
| `@openpresentation/opf-render/pdf` | `toPdf` | Node |
|
|
127
|
+
| `@openpresentation/opf-render/export-browser` | `toPng` and `toPdf` for a page (canvas) | browser |
|
|
128
|
+
| `@openpresentation/opf-render/element`, `/element/define`, `/player` | `toHtml`, `<opf-deck>`, `present` (the HTML output) | browser (`toHtml` also on a server) |
|
|
129
|
+
| `@openpresentation/opf-render` | all of `/svg`, plus `toPng` and `toPdf` | Node (a browser bundler picks `/svg`) |
|
|
118
130
|
|
|
119
|
-
There is no `/html` entry: it would only repeat `/element` (`
|
|
131
|
+
There is no `/html` entry: it would only repeat `/element` (`toHtml`, `defineOpfDeck`) and `/player` (`present`) under a second name. A bundler that bundles Node code (a server framework) sees the converters' dynamic `import()` in the root and in `/png` and `/pdf`; an app that only draws SVG should import `/svg`, which has none, and an app that exports should list the converters as installed (or external) in its bundler.
|
|
120
132
|
|
|
121
133
|
### A missing converter or font package
|
|
122
134
|
|
|
123
135
|
An export that needs a converter that is not installed rejects with `OPFRenderError` code `converter-missing`. `details` holds `package`, `range`, `install` (the command), `purpose` and `installed` (`false` when the package is absent; `true` when it is installed but cannot load, for example a native binary missing for the platform):
|
|
124
136
|
|
|
125
137
|
```js
|
|
126
|
-
try { await
|
|
138
|
+
try { await toPng(svg); }
|
|
127
139
|
catch (error) {
|
|
128
140
|
// error.code === 'converter-missing'
|
|
129
141
|
// error.message: '@resvg/resvg-js is not installed. It is an optional peer dependency of @openpresentation/opf-render, used for PNG output, ...: run `npm install @resvg/resvg-js@^2.6.2`.'
|
|
130
142
|
}
|
|
131
143
|
```
|
|
132
144
|
|
|
133
|
-
`
|
|
145
|
+
`toPng` needs `@resvg/resvg-js`; a WebP or rotated JPEG picture in it also needs `sharp`. `toPdf` (vector) needs no converter for text and shapes, `sharp` for pictures and `@resvg/resvg-js` for an element it has to draw as an image (reported as `pdf-raster-fallback`); `raster: true` needs `pdf-lib` and `@resvg/resvg-js`. A picture is never silently dropped from a PDF because `sharp` is absent: the export rejects instead.
|
|
134
146
|
|
|
135
|
-
A font pack whose `@expo-google-fonts/*` packages are not all installed rejects `loadFonts` with `OPFFontError` code `font-resource-unavailable`; `details.packages` and the message name every missing package with the `npm install` command. `scripts: 'auto'` still reports a missing script package as the `script-font-not-installed` diagnostic instead of failing. In a browser, `export-browser` imports no converter:
|
|
147
|
+
A font pack whose `@expo-google-fonts/*` packages are not all installed rejects `loadFonts` with `OPFFontError` code `font-resource-unavailable`; `details.packages` and the message name every missing package with the `npm install` command. `scripts: 'auto'` still reports a missing script package as the `script-font-not-installed` diagnostic instead of failing. In a browser, `export-browser` imports no converter: a raster PDF takes the module as an option (`toPdf(svgs, { raster: true, pdfLib })` with `import * as pdfLib from 'pdf-lib'`), so a bundle of the entry holds no PDF library; without it a raster PDF rejects with `converter-missing`.
|
|
136
148
|
|
|
137
149
|
Installed size, measured on Windows with `npm install --ignore-scripts`, unpacked. sharp brings its 19 MiB libvips build on each platform; of the SVG-only install, 28 MiB is the vendored font files under `fonts/`, 13 MiB core and 6 MiB fontkit:
|
|
138
150
|
|
|
@@ -149,23 +161,23 @@ Installed size, measured on Windows with `npm install --ignore-scripts`, unpacke
|
|
|
149
161
|
- License: MIT
|
|
150
162
|
- Compatibility target: `@openpresentation/opf`
|
|
151
163
|
- Entry points: root, `/svg`, `/png`, `/pdf`, `/export-browser`, `/fonts-node`, `/fonts-browser`, `/fonts`, `/player`, `/element`, `/element/define`, `/preview-fonts`, `/preview-fonts-node` (see [Install](#install-what-to-add-for-what-rr-63))
|
|
152
|
-
- Public API: `
|
|
164
|
+
- Public API: `toSvg(opf, slides?, opts)` (every slide, one slide or a selection), `resolvePresentation(opf, opts)`, `toPng(opf or svg, slides?, opts)`, `toPdf(opf or svgs, slides?, opts)` and `loadFonts(opts)` (`/fonts-node`, `/fonts-browser`)
|
|
153
165
|
- Player and embedding (RR-28): `<opf-deck>` and a slideshow with a speaker view, see [Player and `<opf-deck>`](#player-and-opf-deck-rr-28)
|
|
154
166
|
|
|
155
|
-
`
|
|
167
|
+
`toSvg(deck)` returns one SVG string per slide (`skipHidden: true` leaves out slides marked `hidden`, the player's sequence, so the result is then shorter than the deck); `toSvg(deck, 3)` returns the SVG of the third slide (slides count from 1; out of range throws `slide-out-of-range`), and `toSvg(deck, "1-3")` or `toSvg(deck, [1, 3])` the selected slides, hidden or not (`invalid-slide-selection` for a malformed one). Every form checks the format at the boundary (core `validate(deck, { only: ['format'] })`; a failure throws `OPFRenderError` `invalid-opf` whose `findings` are the error findings), resolve references from the document's embedded records and the host's `catalogs` (core `Catalog[]`, never fetched), and emit byte-stable SVG for the same input. With a `fonts` handle, each SVG embeds as `@font-face` data only the faces of `embeddedFonts` that its own text draws (by family, weight and style; a face flagged `embed: "always"` goes into every SVG), so the handle is safe to pass to every preview: over the 127 core example decks, an office-pack slide carries 2.4 MB on average (4.1 MB at most) instead of every eager face (15 MB), a base-pack slide 0.53 MB instead of 1.76 MB. Each embedded face is also cut to the glyphs the slide draws (RR-65): the Node handle (and a browser handle given `subsetWasm`, the URL of `harfbuzzjs/dist/harfbuzz-subset.wasm` the host serves, or its bytes or compiled module) subsets each face with HarfBuzz's own subsetter (hb-subset from the pinned harfbuzzjs, MIT), keeping every layout feature, so the browser shapes and draws it exactly like the whole face (147 example slides with 384 embedded faces are pixel-identical in a browser) and the bytes are the same for the same slide. Over the 127 core example decks an office-pack slide falls from 2.4 MB to 59 KB on average (2.85 MB to 59 KB at the median, 1.95 GB to 48 MB for all 807 slides), a base-pack slide from 530 KB to 73 KB. Only a face whose license allows a modified version is cut: a bundled face (by sha256 against the pinned manifest) under a permitted license whose family and file names do not contain a Reserved Font Name of its package (a subset is a modified version, owner decision 2026-09-29) and whose OS/2 fsType allows subsetting; Carlito, Raleway, Lora, Playfair Display, PT Serif, Merriweather Sans, Source Sans 3 and every face a host supplies are embedded whole. `subsetFonts: false` embeds whole faces (for an SVG whose text will be edited outside the renderer). A face whose OS/2 fsType forbids embedding (Restricted License 0x0002, or bitmap-only 0x0200, since an SVG carries outlines) is never embedded (RR-76): the SVG names its family without the data, so a viewer without the font draws the generic family, and a `font-embedding-restricted` diagnostic lists the faces left out. `renderDeckHtml` with `fontMode: "shared"` embeds each face once for the page, cut to the characters all of its slides draw (a three-slide Roboto page: 53 KB, against 101 KB with per-slide subsets and 442 KB with whole shared faces). `text: "system"` writes no `@font-face` data at all (the handle still measures), for a browser host whose `loadFonts` handle already added the faces to the page; keep the default where an SVG must stand alone (a file, the browser PDF export). Slide background colours (solid, gradient stops, pattern colours) accept the same colour references as text and table colours: a hex value, a `var:` variable, or a colour scheme slot or role such as `accent2` or `primary`.
|
|
156
168
|
|
|
157
|
-
Accessibility of the SVG (FA-30): the slide root is a labelled container, `role="group"` with `aria-roledescription="slide"` and `aria-label` set to the slide title, never `role="img"`, which would make every text node inside presentational. Titles, body text, list entries, quotes, metrics, table cells, captions, footnotes and header or footer text stay live text a screen reader reaches, in the order the renderer paints them. Purely decorative drawing (the background and its overlay, card frames, table cell fills and borders, dividers, timeline markers, watermarks, and an image whose `alt` is `""`) carries `aria-hidden="true"`. A picture with `alt` is `role="img"` with that label (a header or footer picture without `alt` is hidden); a chart with `alt` is a `role="img"` group, and one with `alt: ""` is hidden. `<opf-deck>`, the player and `
|
|
169
|
+
Accessibility of the SVG (FA-30): the slide root is a labelled container, `role="group"` with `aria-roledescription="slide"` and `aria-label` set to the slide title, never `role="img"`, which would make every text node inside presentational. Titles, body text, list entries, quotes, metrics, table cells, captions, footnotes and header or footer text stay live text a screen reader reaches, in the order the renderer paints them. Purely decorative drawing (the background and its overlay, card frames, table cell fills and borders, dividers, timeline markers, watermarks, and an image whose `alt` is `""`) carries `aria-hidden="true"`. A picture with `alt` is `role="img"` with that label (a header or footer picture without `alt` is hidden); a chart with `alt` is a `role="img"` group, and one with `alt: ""` is hidden. `<opf-deck>`, the player and `toHtml` remove the root's `role`, `aria-roledescription` and `aria-label` (the slide section or figure around the drawing carries the one name), so a slide is announced once.
|
|
158
170
|
|
|
159
|
-
Text as outlines (RR-64): `
|
|
171
|
+
Text as outlines (RR-64): `toSvg(deck, { fonts, text: "paths" })` draws every `<text>` as glyph outlines, so the SVG needs no font and looks the same in every browser, image viewer and design tool. Each glyph is a `<use>` of an outline kept once per slide in `<defs>` (in font units, under an id made of the face's content hash and the glyph id, so SVGs inlined on one page never mix up glyphs); positions and widths are the vector PDF's layout of the renderer's pinned lines, and the glyphs are shaped by HarfBuzz, the shaper browsers use (the Node handle always; a browser handle given `shapeWasm`, the host's copy of `harfbuzzjs/dist/harfbuzz.wasm`; fontkit otherwise). Over the 30 script corpora every outlined glyph has HarfBuzz's id and position (fontkit, which the layout measures with, picks other glyphs on 10 samples: Bengali, Thai, Lao, Khmer, Myanmar, Syriac and Japanese combining marks); a run inside a pinned width is scaled to it, as the browser scales text. Over the core example decks resvg draws an outlined slide like its text (mean channel difference at most 0.006 of 255) and an outlined slide is about 40 KB at the median (60 KB at p90, 106 KB at most) against 0.5 to 4 MB with whole embedded faces. It needs the fonts handle `loadFonts()` returns, which carries the outline engine as `fonts.outlines` (`text-as-paths-needs-fonts` otherwise); the handle's faces are parsed for outlining once, on the first outlined slide. Each outlined element is a group that keeps the element's attributes and `data-opf-*` trace (a tspan's trace stays on a nested group); its glyphs are hidden from assistive technology and each outlined line is also real text, invisible (`fill="none"`, the generic family, so no face is embedded for it) and pinned to the drawn width, in reading order: a screen reader reads the words as text (the FA-30 tree, checked with axe), and selection, copy and find-in-page work. Links stay `<a>`; underline and line-through are rectangles from the font's own metrics. A run stays text where outlines would not be faithful, reported as `text-as-paths-fallback` with its `reason`: a colour or bitmap font (`colour-font`, emoji), a face whose fsType restricts embedding (`restricted`), or a run with no pinned width on which HarfBuzz and the layout's measurement disagree by more than 0.1 px (`shaping`); the SVG embeds just those runs' faces. The trade-offs, which make it the choice for thumbnails, previews and portable SVG files and not for an editing surface: the drawn text is not editable (a caret and an input method need live text in its own font); a vector PDF made from an outlined SVG has paths instead of selectable text, so `toPdf` should get the `<text>` SVG; browsers draw outlines without the hinting they give text, so small text looks a little lighter than browser text (resvg already draws text as outlines); and in `/fonts-browser` the outline engine adds about 85 KB (minified) to the bundle. Plan and later phases: [opf-render#164](https://github.com/OpenPresentation/opf-render/issues/164).
|
|
160
172
|
|
|
161
173
|
The preview draws three accepted spec fields from tables shared with opf-pptx through core (`@openpresentation/opf`): `code.language` colours code (comments, strings, numbers, keywords, names and types, in theme-derived colours kept at 4.5:1 or more on the code panel; an unknown language stays plain and the text is never changed), `metric.trend` draws an arrow beside the trend word (green up, red down, neutral flat, with "Trend: up" as its text alternative) and colours the delta and trend text, and every one of the 54 DrawingML preset pattern backgrounds draws from its 8 x 8 bitmap (one pixel per 1/96 inch from the slide's top-left). With a core that lacks these exports the preview draws plain, without a new diagnostic. `scripts/derive-pattern-bitmaps.mjs` compares a PowerPoint export of the pattern slides with core's tiles (ECMA-376 names the presets without defining their pixels; core's tiles were measured with it from desktop PowerPoint, Office 365, Windows, 2026-10-01).
|
|
162
174
|
|
|
163
175
|
```js
|
|
164
|
-
import {
|
|
176
|
+
import { toSvg } from "@openpresentation/opf-render";
|
|
165
177
|
import { loadFonts } from "@openpresentation/opf-render/fonts-node";
|
|
166
178
|
|
|
167
179
|
const fonts = await loadFonts({ pack: "office", substitutionPolicy: "visual" });
|
|
168
|
-
const svgs =
|
|
180
|
+
const svgs = toSvg(opf, { trace: true, fonts });
|
|
169
181
|
console.log(fonts.substitutions);
|
|
170
182
|
```
|
|
171
183
|
|
|
@@ -192,24 +204,24 @@ A placed block (`placement`) arrives with its edge band as its region, and headi
|
|
|
192
204
|
PNG and PDF conversion APIs are async because they load the local raster/PDF engines on demand:
|
|
193
205
|
|
|
194
206
|
```js
|
|
195
|
-
import {
|
|
207
|
+
import { toSvg, toPdf, toPng } from "@openpresentation/opf-render";
|
|
196
208
|
import { loadFonts } from "@openpresentation/opf-render/fonts-node";
|
|
197
209
|
|
|
198
210
|
const fonts = await loadFonts({ pack: "office", substitutionPolicy: "visual" });
|
|
199
|
-
const svgs =
|
|
200
|
-
const png = await
|
|
201
|
-
const pdf = await
|
|
211
|
+
const svgs = toSvg(opf, { fonts });
|
|
212
|
+
const png = await toPng(svgs[0], { fonts, scale: 1 });
|
|
213
|
+
const pdf = await toPdf(svgs, { fonts });
|
|
202
214
|
```
|
|
203
215
|
|
|
204
|
-
`
|
|
216
|
+
`toPng` returns PNG bytes for one slide or one SVG, and a list for a deck, a selection or a list of SVGs. `toPdf` takes a deck (every slide, or a selection: `toPdf(deck, "2-4")`), one SVG or a list of SVGs and returns PDF bytes with one slide per page. Given a deck, both draw it with `toSvg` and the same options (the fonts handle measures it); SVG input takes no selection. The SVG page `width`/`height` or `viewBox` determines the PDF page size. **Units: one SVG pixel is one PDF point (1/72 inch), in both modes**, so a 1280 x 720 slide is a 1280 x 720 pt page (17.8 x 10 in, not the 13.33 x 7.5 in PowerPoint prints); a viewer or printer scales it to the paper; `scale` controls raster density only. `toPdf` is vector by default (see below); `raster: true` draws each slide as an image, the output of earlier releases.
|
|
205
217
|
|
|
206
218
|
### Vector PDF with selectable text
|
|
207
219
|
|
|
208
|
-
`
|
|
220
|
+
`toPdf(svgs)` converts the same SVG the preview draws, without a second layout pass: every line, position and width comes from the SVG.
|
|
209
221
|
|
|
210
222
|
- Shapes, lines, polylines, paths and rounded rectangles are PDF paths; linear and radial gradients are PDF shadings and hatch/tile `<pattern>`s are tiling patterns; `clip-path`, stroke dashes, group `opacity` (a transparency-group form) and per-element opacity are native. Pictures are image XObjects (PNG with alpha as an SMask, unoriented JPEG passed through, WebP and oriented JPEG decoded as in raster mode; identical pictures are stored once).
|
|
211
223
|
- Text is real text: TrueType subsets (the font program, a `ToUnicode` map and a `CIDToGIDMap`) of the same font files the PNG preview draws with, positioned glyph by glyph (kerning, ligatures, combining marks and mixed scripts as fontkit shapes them), with the SVG's `textLength` and `text-anchor`, underline and strike-through. The Unicode bidirectional algorithm orders right-to-left and mixed-direction lines. Text is selectable, searchable and copies as the authored text. The encoding is the one Chromium writes, so PDFium (Chrome, Edge), poppler and pdf.js read it back the way they read a Chrome-printed page: runs are drawn in visual order, right-to-left runs are marked `/ReversedChars`, and a glyph or cluster the glyph map cannot give (an Arabic ligature or mirrored bracket, a reordered Indic or Khmer syllable, a no-break space) carries its logical text as `/ActualText`, one span per glyph or cluster. A mark the font split off a letter (Arabic dots) is drawn as a filled outline, so no extractor sees an extra character. There is no hidden text layer and no outline-only text. Known reader limits, shared with Chrome's own PDFs: PDFium duplicates some Thai and Burmese marks, PDFium reorders the runs of a mixed-direction line, and pdf.js ignores `/ActualText` (it reports reordered Indic and Khmer clusters in drawing order).
|
|
212
|
-
- Fonts: only the bundled pack (unless the handle says `useBundledFonts: false`), the handle's `fontFiles
|
|
224
|
+
- Fonts: only the bundled pack (unless the handle says `useBundledFonts: false`), the handle's `fontFiles` (or the font folders given as `fonts`) and the SVG's own `@font-face` data are used; a handle with `loadSystemFonts: true` is rejected for a vector PDF because system fonts could be proprietary. A face whose OS/2 `fsType` forbids embedding is never embedded (a diagnostic says so); one that forbids subsetting is embedded whole. A requested family that has no face is drawn with the family the PNG preview draws (`defaultFontFamily`, `sansSerifFamily`, `monospaceFamily`, `serifFamily`) and reported.
|
|
213
225
|
- Document metadata: `metadata: { title, author, subject, keywords, language, creator, creationDate }`. The language defaults to the first SVG's `lang`. No date is written unless you supply one, there is no random data, and the file identifier is a hash of the content, so identical input gives identical bytes on every machine.
|
|
214
226
|
- Accessibility basics (not a conformance claim): the catalog carries `/Lang`, `/MarkInfo`, `/DisplayDocTitle` (with a title) and XMP metadata; with `tagged` (default) the structure tree lists, per slide in source order, headings (the `.title` placeholder), paragraphs, figures with their `aria-label` as `/Alt` and link elements bound to their link annotations, and decoration (backgrounds, rules, bullets) is marked as an artifact. Not done: PDF/UA or PDF/A claims, list and table structure, per-span languages; text inside a translucent group is not in the structure tree.
|
|
215
227
|
- Links: `<a href>` with an http, https, mailto or tel target becomes a link annotation on each run of its text (other schemes are refused with a diagnostic).
|
|
@@ -219,24 +231,24 @@ const pdf = await svgToPdf(svgs, { fonts });
|
|
|
219
231
|
`onDiagnostic` also reports each embedded face (`pdf-font-embedded`: family, weight, glyph count, size, subset or full, `fsType`, license text), font substitution and per-character fallback. Output is byte-identical across runs and operating systems for the same SVG, font files and options.
|
|
220
232
|
|
|
221
233
|
```js
|
|
222
|
-
const pdf = await
|
|
234
|
+
const pdf = await toPdf(svgs, {
|
|
223
235
|
fontFiles: fonts.fontFiles, useBundledFonts: false,
|
|
224
236
|
metadata: { title: "Quarterly review", author: "Finance", language: "en-GB" },
|
|
225
237
|
onDiagnostic: (d) => d.code === "pdf-raster-fallback" && console.warn(d.path, d.reason),
|
|
226
238
|
});
|
|
227
239
|
```
|
|
228
240
|
|
|
229
|
-
The default changed from raster to vector in the release that added this section; callers that need the previous output pass `
|
|
241
|
+
The default changed from raster to vector in the release that added this section; callers that need the previous output pass `raster: true`. A vector PDF ignores `scale` and `dpi`. The page is painted white by default, as a raster PDF composites on white; `background: "none"` leaves it unpainted and any other colour paints that.
|
|
230
242
|
|
|
231
243
|
## PNG and PDF in a browser
|
|
232
244
|
|
|
233
|
-
`@openpresentation/opf-render/export-browser` exports `
|
|
245
|
+
`@openpresentation/opf-render/export-browser` exports `toPdf` and `toPng` for a page, with the arguments of the Node functions. They take a deck (drawn with the browser fonts handle) or the SVG the preview draws, and need no Node module, no network and no system font (a bundle of this entry contains no sharp, resvg, fs or crypto, and the vector converter's SHA-256 is plain JavaScript).
|
|
234
246
|
|
|
235
|
-
- **Vector PDF** (default) is the same converter the Node export uses (selectable real text in embedded font subsets, paths, gradients, patterns, clips, opacity, links, tagged structure, byte-identical output for the same SVG). Fonts come from the SVG's own `@font-face` data (pass a `fonts` handle with `embeddedFonts` to `
|
|
247
|
+
- **Vector PDF** (default) is the same converter the Node export uses (selectable real text in embedded font subsets, paths, gradients, patterns, clips, opacity, links, tagged structure, byte-identical output for the same SVG). Fonts come from the SVG's own `@font-face` data (pass a `fonts` handle with `embeddedFonts` to `toSvg`; each face is embedded only on the slides that draw it, so the PDF gets every face its pages draw), from the faces of the `fonts` handle you pass to `toPdf` (script faces an SVG does not carry reach the PDF too) or from `fontData: [{ data, family? }]`; `fontFiles` and font folders do not exist here and system fonts cannot be loaded. A face the handle never loaded is never embedded.
|
|
236
248
|
- **Pictures** are decoded by the browser (PNG, JPEG, WebP, GIF through `createImageBitmap`, EXIF orientation applied); an upright JPEG is passed through compressed, as in Node. An effect with no PDF form (filter, mask, a nested SVG picture) rasterizes only that element on a canvas and reports `pdf-raster-fallback`.
|
|
237
|
-
- **Raster PDF** (`
|
|
249
|
+
- **Raster PDF** (`raster: true`, `scale` default 2) draws each slide on a canvas as an image.
|
|
238
250
|
- **PNG** is drawn by the browser's SVG renderer on a canvas (`scale`, `background`, up to 40 megapixels). With the fonts embedded in the SVG it agrees with the Node (resvg) PNG to anti-aliasing (mean channel error 0.43 of 255 on a text slide).
|
|
239
|
-
- `signal` (an `AbortSignal`, checked between pages) and `onProgress({ page, pages })` serve large decks; the same two options also work in the Node `
|
|
251
|
+
- `signal` (an `AbortSignal`, checked between pages) and `onProgress({ page, pages })` serve large decks; the same two options also work in the Node `toPdf`. The browser export yields to the page between slides.
|
|
240
252
|
|
|
241
253
|
Verified in Chromium by `test/export-browser.mjs` (`npm run test:export-browser`), which also checks the text pdf.js extracts, the eight JPEG orientations, offline operation and determinism. Safari and Firefox are not exercised by this repository's CI.
|
|
242
254
|
Complex scripts in raster output: resvg draws a HarfBuzz cluster with the advance of its widest glyph, so Indic, Thai, Lao, Khmer and Myanmar text lost the advance of vowel signs and ran together, and it ignores the SVG `lang` (Korean spacing). The raster path therefore rewrites its private copy of such text cluster by cluster at fontkit's positions (`src/raster-text.js`): Devanagari, Gujarati, Oriya, Tamil, Kannada and Sinhala as fontkit glyph outlines, the other scripts and Korean as single clusters resvg shapes in isolation. The emitted SVG is unchanged, text in other scripts is rasterized exactly as before, and `test/script-corpora-raster.mjs` holds every script to a HarfBuzz outline reference (the fixture's `rasterLimits` records what still differs: the KOR punctuation forms).
|
|
@@ -246,26 +258,26 @@ Complex scripts in raster output: resvg draws a HarfBuzz cluster with the advanc
|
|
|
246
258
|
Use `@openpresentation/opf-render/svg` for browser rendering without Node dependencies. Browser-aware bundlers also select this shared SVG implementation for the root import; Node's root import retains PNG/PDF conversion.
|
|
247
259
|
|
|
248
260
|
```js
|
|
249
|
-
import {
|
|
261
|
+
import { toSvg } from '@openpresentation/opf-render/svg';
|
|
250
262
|
import { loadFonts } from '@openpresentation/opf-render/fonts-browser';
|
|
251
263
|
|
|
252
264
|
const fonts = await loadFonts({ faces: fontFileEntries });
|
|
253
|
-
container.innerHTML =
|
|
265
|
+
container.innerHTML = toSvg(presentation, 1, { fonts });
|
|
254
266
|
// fonts.dispose() when its canvases are unmounted.
|
|
255
267
|
```
|
|
256
268
|
|
|
257
269
|
Each entry of `faces` contains `url` or `data: Uint8Array`, with optional `family`, `weight`, `italic` and `license`. The loader registers browser FontFaces using the same bytes used for measurement. It fetches only URLs supplied by the host, supports an AbortSignal and custom fetch, and awaits font loading. Use pinned static faces and retain their licenses. A standalone SVG embeds the faces of the handle's `embeddedFonts` that its text draws (the same `{ fonts }` option); embedding is unnecessary for each live draft after browser fonts are loaded.
|
|
258
270
|
|
|
259
|
-
Subset embedded faces in the browser (RR-65): pass `subsetWasm` to `loadFonts` to cut each face a standalone SVG embeds to the glyphs its slide draws, as the Node handle always does. It is the `harfbuzz-subset.wasm` file of the `harfbuzzjs` dependency (`harfbuzzjs/dist/harfbuzz-subset.wasm`, MIT), served by the host like the font files: its URL, its bytes or a compiled `WebAssembly.Module`. The loader instantiates it asynchronously and fetches nothing else; without it a browser handle embeds whole faces. Live previews in a page that already holds the faces should use `
|
|
271
|
+
Subset embedded faces in the browser (RR-65): pass `subsetWasm` to `loadFonts` to cut each face a standalone SVG embeds to the glyphs its slide draws, as the Node handle always does. It is the `harfbuzz-subset.wasm` file of the `harfbuzzjs` dependency (`harfbuzzjs/dist/harfbuzz-subset.wasm`, MIT), served by the host like the font files: its URL, its bytes or a compiled `WebAssembly.Module`. The loader instantiates it asynchronously and fetches nothing else; without it a browser handle embeds whole faces. Live previews in a page that already holds the faces should use `text: "system"` instead, which embeds nothing.
|
|
260
272
|
|
|
261
273
|
```js
|
|
262
274
|
const fonts = await loadFonts({ faces: fontFileEntries, subsetWasm: '/vendor/harfbuzz-subset.wasm' });
|
|
263
|
-
const standalone =
|
|
275
|
+
const standalone = toSvg(presentation, 1, { fonts }); // each @font-face is a glyph subset
|
|
264
276
|
```
|
|
265
277
|
|
|
266
278
|
## Player and `<opf-deck>` (RR-28)
|
|
267
279
|
|
|
268
|
-
A slideshow player and an embeddable web component, both built on `
|
|
280
|
+
A slideshow player and an embeddable web component, both built on `toSvg`: the slide a page shows is the slide the preview, the editor and the PDF show, with no second layout engine. They are plain ES modules, typed, framework-free and tree-shakeable, and importing them touches no DOM, so they are safe in Next.js and other server renderers.
|
|
269
281
|
|
|
270
282
|
```html
|
|
271
283
|
<script type="module">
|
|
@@ -283,7 +295,7 @@ useEffect(() => { defineOpfDeck(); }, []);
|
|
|
283
295
|
// ...and render <opf-deck src="/deck.opf.json" fonts="/opf-fonts/" />.
|
|
284
296
|
```
|
|
285
297
|
|
|
286
|
-
Entry points (package `exports`): `/element` (`defineOpfDeck`, `getOpfDeckElement`, `
|
|
298
|
+
Entry points (package `exports`): `/element` (`defineOpfDeck`, `getOpfDeckElement`, `toHtml`, `loadPreviewFonts`), `/element/define` (importing it registers the tag; the only file with a side effect), `/player` (`present`), `/preview-fonts` (the font root layout and `loadPreviewFonts`) and `/preview-fonts-node` (`copyPreviewFonts`, also the `opf-preview-fonts` command). The element loads the player on first use, so a page that only embeds decks does not carry slideshow code.
|
|
287
299
|
|
|
288
300
|
### Fonts: one self-hosted directory
|
|
289
301
|
|
|
@@ -305,7 +317,7 @@ It is the layout the editor playground and the OpenPresentation sites serve, and
|
|
|
305
317
|
|
|
306
318
|
### `<opf-deck>`
|
|
307
319
|
|
|
308
|
-
Attributes: `src` (OPF JSON; the other request the element makes), `slide` (1-based; counts the slides that play), `fonts`, `thumbnails` (a strip of slide thumbnails), `controls="none"`, `present` (a Present button), `include-hidden`, `label`, `keyboard="off"`. Instead of `src` set the `document` property (an object or JSON text), or put the document in a child `<script type="application/opf+json">`. Properties and methods: `document`, `slide`, `total`, `fonts` (the font root URL, or a handle that wins over the attribute), `renderOptions` (extra `
|
|
320
|
+
Attributes: `src` (OPF JSON; the other request the element makes), `slide` (1-based; counts the slides that play), `fonts`, `thumbnails` (a strip of slide thumbnails), `controls="none"`, `present` (a Present button), `include-hidden`, `label`, `keyboard="off"`. Instead of `src` set the `document` property (an object or JSON text), or put the document in a child `<script type="application/opf+json">`. Properties and methods: `document`, `slide`, `total`, `fonts` (the font root URL, or a handle that wins over the attribute), `renderOptions` (extra `toSvg` options such as `catalogs` and `imageResolver`), `currentSlide` (`{ slide, total, index, id, title, notes, section }`; `notes` is plain text), `ready`, `next()`, `previous()`, `first()`, `last()`, `goto(n)`, `reload()` and `present(options)`.
|
|
309
321
|
|
|
310
322
|
Events: `ready`, `slidechange` (the same detail as `currentSlide`; bubbles and is composed), `error` (`{ code, message, fatal }`, not bubbling), `presentstart` and `presentend`. Style it with custom properties (`--opf-deck-fg`, `--opf-deck-border`, `--opf-deck-radius`, `--opf-deck-focus`, `--opf-deck-accent`, `--opf-deck-stage`) and the parts `deck`, `viewport`, `slide`, `bar`, `button`, `previous`, `next`, `present`, `counter`, `thumbnails` and `thumbnail`.
|
|
311
323
|
|
|
@@ -315,13 +327,13 @@ Accessibility: the element is a labelled region (the deck name) holding a focusa
|
|
|
315
327
|
|
|
316
328
|
### Server markup
|
|
317
329
|
|
|
318
|
-
`
|
|
330
|
+
`toHtml(deck, slides?, options?)` returns the tag with the deck's slides as inline SVG inside it. A visitor without JavaScript, a crawler or a reader sees the slides; when the element upgrades its shadow DOM replaces them. `toHtml(deck)` draws the first slide and a list of titles; `toHtml(deck, '1-')` every slide, and `toHtml(deck, 3)`, `'1-3'` or `[1, 3]` those slides of the presented sequence; `embed: true` adds the document as an `application/opf+json` child so the upgrade needs no request (it includes hidden slides and notes, as the `src` file does); `fonts` (an object) takes a handle, or any object with a `textMeasurement`, for exact widths; a string is the font root URL for the `fonts` attribute. In Next.js, render the string from a server component with `dangerouslySetInnerHTML` and call `defineOpfDeck()` from a client component. A strict `style-src` Content-Security-Policy needs `style-src-attr 'unsafe-inline'` for the renderer's `style="white-space:pre"` attributes; the element's own styles use constructable stylesheets.
|
|
319
331
|
|
|
320
|
-
Each slide's SVG embeds only the resolved faces it draws (see `
|
|
332
|
+
Each slide's SVG embeds only the resolved faces it draws (see `toSvg` above), including bold, italic and glyph fallback, so loading a whole pack for measurement does not put that pack into every slide. `toHtml` accepts `fontMode: 'standalone' | 'shared' | 'external'`:
|
|
321
333
|
|
|
322
334
|
- `standalone` (default) embeds fonts in each slide, so its SVG remains self-contained when extracted.
|
|
323
335
|
- `shared` emits the drawn font rules once inside the returned tag, retaining license metadata in the SVGs. Keep the returned markup together; an extracted SVG needs those shared rules to travel with it.
|
|
324
|
-
- `external` emits no font rules (the slides render with `
|
|
336
|
+
- `external` emits no font rules (the slides render with `text: "system"`). Supply page CSS with the exact pinned, licensed faces (including replacements and fallback faces) used by the handle, from your own origin. Keep the same handle for layout; omitting it changes layout to estimates. Copy license notices with the served files. An offline page needs those local files available too.
|
|
325
337
|
|
|
326
338
|
Shared and external rules apply at page scope. A strict CSP must permit their inline style or self-hosted stylesheet and the matching `font-src` (`data:` for embedded fonts). These modes change delivery, while measurement, text positions and font selection stay the same. The Node loader's large script faces still require `embedScriptFonts: true` for self-contained SVG or shared SSR; otherwise supply them through external CSS.
|
|
327
339
|
|
|
@@ -330,12 +342,9 @@ For a lightweight initial page, pre-render measured markup on the server and ena
|
|
|
330
342
|
```js
|
|
331
343
|
// Server/build step: write this HTML into your page, followed by the upgrade button.
|
|
332
344
|
import {loadFonts} from '@openpresentation/opf-render/fonts-node';
|
|
333
|
-
import {
|
|
345
|
+
import {toHtml} from '@openpresentation/opf-render/element';
|
|
334
346
|
const fonts = await loadFonts({pack: 'office', scripts: 'auto', presentation: deck, embedScriptFonts: true});
|
|
335
|
-
const html =
|
|
336
|
-
fonts, slides: 'all', fontMode: 'shared', embed: true,
|
|
337
|
-
attributes: {id: 'deck', fonts: '/opf-fonts/'},
|
|
338
|
-
});
|
|
347
|
+
const html = toHtml(deck, '1-', {fonts, fontMode: 'shared', embed: true, attributes: {id: 'deck', fonts: '/opf-fonts/'}});
|
|
339
348
|
// <button id="upgrade" type="button">Enable slide controls</button>
|
|
340
349
|
```
|
|
341
350
|
|
|
@@ -413,7 +422,7 @@ Source Sans Pro was renamed Source Sans 3. A request for the old name draws the
|
|
|
413
422
|
|
|
414
423
|
The 70 vendored faces are 12.0 MiB (FF-43 added 35 faces, 4.6 MiB uncompressed and about 2.4 MB in the tarball; the first 35 were 7.4 MiB) and are the only bytes added; there are no new dependencies. Browser hosts fetch them lazily by family, so the eager list stays the 33 Office and base faces. Every face and notice is checked against its manifest sha256 when loaded (`font-integrity-mismatch`, `font-resource-unavailable`), and `npm run test:packed` verifies the packed copies. `node scripts/update-font-manifest.mjs --vendor` re-downloads each recorded commit (or npm version), reads the license from the shipped notice, refuses a non-permissive one (only OFL-1.1, Apache-2.0, MIT and UFL-1.0 are allowed), copies only the listed faces and rewrites the hashes and provenance; `.gitattributes` keeps the binaries byte-exact.
|
|
415
424
|
|
|
416
|
-
Embedding: open faces are flagged `embed: "used"`. `registry.embeddedFonts` stays the 33 Office and base faces, while the `loadFonts()` handle's `embeddedFonts` (or `registry.selectEmbeddedFonts`) supplies every face and `
|
|
425
|
+
Embedding: open faces are flagged `embed: "used"`. `registry.embeddedFonts` stays the 33 Office and base faces, while the `loadFonts()` handle's `embeddedFonts` (or `registry.selectEmbeddedFonts`) supplies every face and `toSvg` embeds an open face only when the slide's text names its family, so a Montserrat slide carries Montserrat and not the whole pack. Raster output reads the files from `fontFiles`. `includeOpenFonts: false` leaves the open families out of the office pack entirely.
|
|
417
426
|
|
|
418
427
|
## Script fonts, lang and right-to-left text (FF-19)
|
|
419
428
|
|
|
@@ -423,12 +432,12 @@ The replacement faces are an optional, hash-pinned font pack: 70 static faces fr
|
|
|
423
432
|
|
|
424
433
|
```js
|
|
425
434
|
import { loadFonts } from '@openpresentation/opf-render/fonts-node';
|
|
426
|
-
import {
|
|
435
|
+
import { toSvg, toPng } from '@openpresentation/opf-render';
|
|
427
436
|
|
|
428
437
|
// npm install @expo-google-fonts/noto-sans-jp@0.4.3 @expo-google-fonts/noto-naskh-arabic@0.4.5
|
|
429
438
|
const fonts = await loadFonts({ pack: 'office', substitutionPolicy: 'visual', scripts: ['Jpan', 'Arab'] });
|
|
430
|
-
const slides =
|
|
431
|
-
const png = await
|
|
439
|
+
const slides = toSvg(presentation, { fonts });
|
|
440
|
+
const png = await toPng(slides[0], { fonts });
|
|
432
441
|
```
|
|
433
442
|
|
|
434
443
|
`scripts` accepts ISO 15924 codes (`Jpan`, `Hans`, `Hant`, `Kore`, `Arab`, `Hebr`, `Deva`, `Beng`, `Thai` and others; see `scriptFontPackages('all')`) or `'all'`. `detectScripts(presentation)` from `/fonts` lists the scripts a document's text needs. Every face and license notice is checked against `BUNDLED_FONT_MANIFEST`. A missing package fails with `font-resource-unavailable` and names the exact version to install. Script faces are left out of `fonts.embeddedFonts` unless you pass `embedScriptFonts: true`, because a CJK face is 5 to 10 MB. Raster output reads them from `fontFiles`. In a browser, serve the installed packages and load `scriptFontEntries(scripts, { baseUrl })` from `/fonts-browser` with `loadFonts({ faces })`. The loader verifies each entry's SHA-256 with Web Crypto before use.
|
|
@@ -464,7 +473,7 @@ The SVG root carries `lang` and `xml:lang` from the document's `language`. Measu
|
|
|
464
473
|
|
|
465
474
|
If core's `resolveScriptFonts` throws for the document, the preview uses the design font for every script, sets no `lang`, lays out every paragraph left to right and reports `language-preview-unresolved` once through `onDiagnostic`.
|
|
466
475
|
|
|
467
|
-
A face that lacks a character never fails a preview. As in a browser or PowerPoint font linking, each character the resolved face lacks is measured and drawn with the first loaded face that has it, along a fixed chain (`glyphFallbackFamilies(character, profile)`): the character's own script face, the deck language's script face, Noto Sans (Latin, Cyrillic and Greek), the other CJK faces (Japanese, Simplified, Traditional, Korean), then every other Noto script face. A Greek or Cyrillic word under Georgia (Gelasio) or a script scheme's face (Constantia previews with the open PT Serif, which has Cyrillic, so only its Greek text falls back), Greek under Meiryo, Yu Gothic, Microsoft YaHei or Malgun Gothic, Japanese-only kanji beside Hangul, and Simplified-only hanzi in a Japanese deck therefore draw with Noto Sans or the CJK face that has them, and each word stays in one face when one has all of it. Each substitution is reported once per family pair and path as a `font-glyph-fallback` diagnostic through `onDiagnostic` (`fontFamily`, `fallbackFamily`, `scripts`, `characters`); it is a note, not an error. Pass `glyphFallback: 'none'` to `
|
|
476
|
+
A face that lacks a character never fails a preview. As in a browser or PowerPoint font linking, each character the resolved face lacks is measured and drawn with the first loaded face that has it, along a fixed chain (`glyphFallbackFamilies(character, profile)`): the character's own script face, the deck language's script face, Noto Sans (Latin, Cyrillic and Greek), the other CJK faces (Japanese, Simplified, Traditional, Korean), then every other Noto script face. A Greek or Cyrillic word under Georgia (Gelasio) or a script scheme's face (Constantia previews with the open PT Serif, which has Cyrillic, so only its Greek text falls back), Greek under Meiryo, Yu Gothic, Microsoft YaHei or Malgun Gothic, Japanese-only kanji beside Hangul, and Simplified-only hanzi in a Japanese deck therefore draw with Noto Sans or the CJK face that has them, and each word stays in one face when one has all of it. Each substitution is reported once per family pair and path as a `font-glyph-fallback` diagnostic through `onDiagnostic` (`fontFamily`, `fallbackFamily`, `scripts`, `characters`); it is a note, not an error. Pass `glyphFallback: 'none'` to `toSvg` or `createScriptTextMeasurement` to keep exact faces, so a missing glyph raises `missing-glyph` again. Coverage is checked per grapheme cluster and per word: a base letter and the combining marks after it (NFD Vietnamese, Cyrillic U+0306) move together to the first face that has the whole cluster, and only their word moves, not the sentence. Without a registry, a Greek or Cyrillic run names `Noto Sans` after the design font in its font stack. With `scripts: 'auto'`, the CJK fallback faces are loaded for you: the language's face plus at most one fallback face (opf-render#55's cap). Greek and Cyrillic need no package, because the office registry always carries Noto Sans. Serif decks prefer the serif face of each script where one is pinned (Noto Serif Hebrew, Tibetan); no Noto Serif is bundled for Latin, Cyrillic, Greek or CJK, so their fallback text draws in the sans face. A character that no loaded face has still raises `missing-glyph`. The PPTX export is unchanged: it names the chosen font and PowerPoint links its own fallback fonts.
|
|
468
477
|
|
|
469
478
|
Characters are assigned to slots following PowerPoint where its rules are known:
|
|
470
479
|
|
|
@@ -491,9 +500,9 @@ These browser entrypoints are included in the published package. For coordinated
|
|
|
491
500
|
A deck that declares content variables, or is marked `"template": true`, is resolved by core `resolveVariables` before it is composed, so the preview and the PPTX exporter agree. Pass the values as `variables`:
|
|
492
501
|
|
|
493
502
|
```js
|
|
494
|
-
import {
|
|
503
|
+
import { toSvg } from '@openpresentation/opf-render';
|
|
495
504
|
|
|
496
|
-
|
|
505
|
+
toSvg(template, { variables: { client: 'Globex', revenue: 1250000 } });
|
|
497
506
|
```
|
|
498
507
|
|
|
499
508
|
A template previews with each unfilled variable's `example` and reports `variable-example-used` through `onDiagnostic` (a built-in variable such as `{{speaker.name}}` whose document field is missing reports `variable-builtin-missing`; built-ins read the document's own `speaker`, `organization` and `name`, and a template preview keeps an absent one visible); a variable with no example keeps its `{{id}}` text. A normal deck with an unfilled required variable throws `OPFRenderError` with code `unfilled-variables`, and a value of the wrong kind throws `invalid-variables`. `resolvePresentation(...).presentation` is the concrete deck. `variables: false` draws the document as authored, with tokens and `var:` references visible (the editor canvas's view of a template, so inline edits never overwrite a token). Decks without content variables are untouched. See [templates and variables](https://github.com/OpenPresentation/opf/blob/main/docs/templates-and-variables.md).
|
|
@@ -530,9 +539,9 @@ Dependency policy:
|
|
|
530
539
|
- `pdf-lib` (optional peer, RR-63) assembles raster-mode PDF bytes locally. Metadata timestamps are disabled so repeated PDF output is byte-stable for the same SVG input and options.
|
|
531
540
|
- Vector PDF output is written by a small deterministic PDF writer in this package, with `pako` for Flate compression (pure JavaScript, so independent of the platform zlib build), `fontkit` for shaping and font metrics and `bidi-js` for the Unicode bidirectional algorithm. No hosted service, network call or system font is involved.
|
|
532
541
|
- Bundled OFL Roboto and Roboto Mono TTF files (the optional peers `@expo-google-fonts/roboto` and `roboto-mono`, which Node `loadFonts()` and the PNG/PDF default read) provide the default deterministic font fallback.
|
|
533
|
-
- `
|
|
542
|
+
- `toPng` and `toPdf` disable system-font loading by default. Hosts that require branded fonts should pass a handle with explicit `fontFiles` (or font folders as `fonts`); `fonts: { loadSystemFonts: true }` is an opt-in escape hatch for PNG and raster PDF output and can make it environment-dependent. A vector PDF rejects it (`pdf-system-fonts-unsupported`): it embeds only fonts you supply, so a system font can never be embedded by accident.
|
|
534
543
|
|
|
535
|
-
Browser support boundary: `
|
|
544
|
+
Browser support boundary: `toSvg`, `toSvg`, and `resolvePresentation` are browser-importable pure JavaScript APIs. The root `toPng` and `toPdf` (also `/png` and `/pdf`) are Node APIs because they depend on the Node builds of resvg and sharp, which are optional peers loaded on first use (`converter-missing` when absent). For a page, `@openpresentation/opf-render/export-browser` has the same two names (see below).
|
|
536
545
|
|
|
537
546
|
Chartex chart previews (FF-22b) draw the constructs opf-pptx exports as Office 2016 chartex parts: `treemap` (squarified tiles of the first series, one colour per tile, category labels), `histogram` (a lone value column binned like PowerPoint with Scott's rule count and right-closed bins, or one column per category), `pareto` (columns sorted descending with the cumulative-percentage line on a 0-100% axis), `box-and-whisker` (rows grouped by category, one box per series, exclusive quartiles, whiskers within 1.5 IQR, mean markers, outlier points), `waterfall` (floating bars from the running total, increases and decreases in the first two palette colours, connector lines) and `funnel` (centred bars with value labels). `world` is an honest non-geographic preview: one tile per region shaded by value with its name and value. No geography data is shipped; PowerPoint draws the real map from Bing geodata it fetches itself, so the preview and the native map agree on labels, values and the series colour, not on shapes. Each chartex kind also accepts a lone value column (row numbers as categories; histogram and pareto bin the values). Every mark and label keeps a `data-opf-path` (bins and boxes trace to their value column).
|
|
538
547
|
|
package/dist/deck-runtime.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// RR-28: the part of the slideshow player and the <opf-deck> element that has no DOM of its own. It reads an OPF document,
|
|
2
|
-
// decides which slides play (hidden ones do not), renders each slide once with the renderer's own SVG output (
|
|
2
|
+
// decides which slides play (hidden ones do not), renders each slide once with the renderer's own SVG output (toSvg:
|
|
3
3
|
// there is no second layout engine) behind a face-level font gate, and synchronizes windows over a BroadcastChannel.
|
|
4
4
|
// Nothing here fetches anything but the font files the host's font root serves.
|
|
5
5
|
import { resolveSlideVariables } from "@openpresentation/opf";
|
|
6
|
-
import {
|
|
6
|
+
import { toSvg } from "./svg.js";
|
|
7
7
|
|
|
8
8
|
/** Error raised for a deck that cannot be read, rendered or loaded. */
|
|
9
9
|
export class DeckError extends Error {
|
|
@@ -206,7 +206,7 @@ export function createFontGate(fonts) {
|
|
|
206
206
|
|
|
207
207
|
/**
|
|
208
208
|
* One deck's rendering, shared by the element, the full-screen player and the speaker view: font loading once, each slide
|
|
209
|
-
* rendered once by `
|
|
209
|
+
* rendered once by `toSvg` and kept, so moving between slides never draws twice and every surface shows the same markup.
|
|
210
210
|
*
|
|
211
211
|
* `fonts` is a browser fonts handle (or nothing: layout then uses estimated widths and the visitor's system sans-serif).
|
|
212
212
|
*/
|
|
@@ -237,7 +237,7 @@ export function createDeckStore({ document, fonts, renderOptions = {}, date } =
|
|
|
237
237
|
let svg = cache.get(index);
|
|
238
238
|
if (svg === undefined) {
|
|
239
239
|
try {
|
|
240
|
-
svg =
|
|
240
|
+
svg = toSvg(deck, index + 1, { ...options(), validate: !validated });
|
|
241
241
|
} catch (cause) {
|
|
242
242
|
if (cause instanceof DeckError) throw cause;
|
|
243
243
|
// A document the schema rejects says where: the first finding's path and message.
|
package/dist/element.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { BrowserFontsHandle } from "./fonts-browser.js";
|
|
2
2
|
import type { RenderFonts } from "./fonts.js";
|
|
3
|
-
import type {
|
|
3
|
+
import type { SlideSelection, ToSvgOptions } from "./svg.js";
|
|
4
4
|
import type { PlayerSession, PresentOptions, PlayerSlideChange } from "./player.js";
|
|
5
5
|
export { DeckError } from "./player.js";
|
|
6
6
|
export { loadPreviewFonts, previewBaseFaces, previewFontLayout } from "./preview-fonts.js";
|
|
@@ -43,8 +43,8 @@ export interface OpfDeckElement extends HTMLElement {
|
|
|
43
43
|
* attribute's URL (an empty string without either).
|
|
44
44
|
*/
|
|
45
45
|
fonts: string | BrowserFontsHandle;
|
|
46
|
-
/** Extra `
|
|
47
|
-
renderOptions: Partial<
|
|
46
|
+
/** Extra `toSvg` options (catalogs, imageResolver, date, ...). Set before the deck loads, or call `reload()`. */
|
|
47
|
+
renderOptions: Partial<ToSvgOptions>;
|
|
48
48
|
includeHidden: boolean;
|
|
49
49
|
thumbnails: boolean;
|
|
50
50
|
readonly ready: Promise<void>;
|
|
@@ -66,10 +66,8 @@ export declare function getOpfDeckElement(): { new (): OpfDeckElement; readonly
|
|
|
66
66
|
/** Register `<opf-deck>` (or another tag name). Safe to call twice and on a server, where it does nothing. */
|
|
67
67
|
export declare function defineOpfDeck(tagName?: string): CustomElementConstructor | undefined;
|
|
68
68
|
|
|
69
|
-
export interface
|
|
69
|
+
export interface ToHtmlOptions {
|
|
70
70
|
tagName?: string;
|
|
71
|
-
/** `"first"` (default: the first slide and a list of titles), `"all"`, or 1-based slide numbers. */
|
|
72
|
-
slides?: "first" | "all" | readonly number[];
|
|
73
71
|
includeHidden?: boolean;
|
|
74
72
|
src?: string;
|
|
75
73
|
slide?: number;
|
|
@@ -86,11 +84,16 @@ export interface RenderDeckHtmlOptions {
|
|
|
86
84
|
embed?: boolean;
|
|
87
85
|
/** Today's date (ISO) for `date: true` furniture. */
|
|
88
86
|
date?: string;
|
|
89
|
-
renderOptions?: Partial<
|
|
87
|
+
renderOptions?: Partial<ToSvgOptions>;
|
|
90
88
|
}
|
|
91
89
|
|
|
92
|
-
/**
|
|
93
|
-
|
|
90
|
+
/**
|
|
91
|
+
* Server-side markup (RR-73): the deck's slides as inline SVG inside the tag, shown as is without JavaScript and replaced when the
|
|
92
|
+
* element upgrades. `toHtml(deck)` draws the first slide and a list of titles; `toHtml(deck, 3)`, `toHtml(deck, "1-3")` (`"1-"` for
|
|
93
|
+
* every slide) or `toHtml(deck, [1, 3])` draw those slides of the presented sequence, counting from 1.
|
|
94
|
+
*/
|
|
95
|
+
export declare function toHtml(document: unknown, options?: ToHtmlOptions): string;
|
|
96
|
+
export declare function toHtml(document: unknown, slides: SlideSelection, options?: ToHtmlOptions): string;
|
|
94
97
|
|
|
95
98
|
declare global {
|
|
96
99
|
interface HTMLElementTagNameMap { "opf-deck": OpfDeckElement }
|