@openpresentation/opf-render 0.13.1 → 0.14.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 +106 -76
- package/dist/chart-options.js +26 -21
- package/dist/charts.js +204 -117
- package/dist/deck-runtime.js +21 -34
- package/dist/element.d.ts +11 -6
- package/dist/element.js +28 -18
- package/dist/export-browser.d.ts +7 -1
- package/dist/export-browser.js +7 -6
- package/dist/font-compatibility.js +4 -4
- package/dist/font-registry.js +324 -0
- package/dist/fonts-browser.d.ts +25 -3
- package/dist/fonts-browser.js +54 -3
- package/dist/fonts-node.d.ts +32 -16
- package/dist/fonts-node.js +110 -50
- package/dist/fonts.d.ts +48 -27
- package/dist/fonts.js +7 -320
- package/dist/index.d.ts +36 -16
- package/dist/lazy-font-list.js +1 -1
- package/dist/lazy-fonts.js +7 -7
- package/dist/pdf-fonts.js +1 -1
- package/dist/player.d.ts +4 -4
- package/dist/player.js +5 -5
- package/dist/preview-fonts.d.ts +4 -4
- package/dist/preview-fonts.js +6 -5
- package/dist/raster.js +24 -9
- package/dist/script-font-pack.js +19 -26
- package/dist/script-fonts.js +6 -17
- package/dist/svg.d.ts +30 -14
- package/dist/svg.js +286 -266
- package/dist/symbol-fonts.js +22 -55
- package/package.json +2 -2
- package/dist/font-policy.js +0 -2734
- package/dist/symbol-encodings.js +0 -7
package/dist/raster.js
CHANGED
|
@@ -10,11 +10,24 @@ const DEFAULT_RASTER_BACKGROUND = "#FFFFFF";
|
|
|
10
10
|
const DEFAULT_PDF_MODE = "vector";
|
|
11
11
|
let bundledFontFilesCache=null;
|
|
12
12
|
|
|
13
|
+
// The faces a raster or PDF conversion draws with, from the fonts handle (`loadFonts()` from `/fonts-node`): its `fontFiles`, and
|
|
14
|
+
// whether the bundled base faces are added (`useBundledFonts`, default true; a Node handle already holds its own, so it says false) and
|
|
15
|
+
// whether system fonts load (`loadSystemFonts`, default false). Without a handle the bundled base faces draw.
|
|
16
|
+
function fontSettings(options) {
|
|
17
|
+
const fonts = options.fonts ?? {};
|
|
18
|
+
return { fontFiles: stringArray(fonts.fontFiles), useBundledFonts: fonts.useBundledFonts !== false, loadSystemFonts: fonts.loadSystemFonts === true };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Convert one SVG (the output of `renderSvg` or `renderSlideSvg`) to PNG bytes. `fonts` is the handle `loadFonts()` returns: the raster draws
|
|
23
|
+
* with its font files, so the preview and the PNG use the same faces. Without it the bundled base faces draw.
|
|
24
|
+
*/
|
|
13
25
|
export async function svgToPng(svg, options = {}) {
|
|
14
26
|
const rendered = await rasterizeSvg(svg, options);
|
|
15
27
|
return rendered.png;
|
|
16
28
|
}
|
|
17
29
|
|
|
30
|
+
/** Convert SVG slides (the output of `renderSvg`) to a PDF, one page each. `fonts` is as for `svgToPng`; `mode` is `"vector"` (default) or `"raster"`. */
|
|
18
31
|
export async function svgToPdf(svgs, options = {}) {
|
|
19
32
|
const pdfInputs = normalizeSvgList(svgs);
|
|
20
33
|
if (!pdfInputs.length) {
|
|
@@ -49,13 +62,14 @@ export async function svgToPdf(svgs, options = {}) {
|
|
|
49
62
|
}
|
|
50
63
|
|
|
51
64
|
async function vectorPdf(inputs, options) {
|
|
52
|
-
|
|
53
|
-
|
|
65
|
+
const settings = fontSettings(options);
|
|
66
|
+
if (settings.loadSystemFonts) {
|
|
67
|
+
throw new OPFRenderError("pdf-system-fonts-unsupported", 'Vector PDF output embeds only the font files you supply: fonts.loadSystemFonts is not supported with mode "vector". Pass a fonts handle with fontFiles (and fontDirs), or use mode "raster".', { option: "fonts.loadSystemFonts" });
|
|
54
68
|
}
|
|
55
69
|
const scale = positiveNumber(options.rasterFallbackScale, "rasterFallbackScale", 2);
|
|
56
70
|
const fontFiles = [
|
|
57
|
-
...(
|
|
58
|
-
...
|
|
71
|
+
...(settings.useBundledFonts ? await bundledFontFiles() : []),
|
|
72
|
+
...settings.fontFiles
|
|
59
73
|
];
|
|
60
74
|
const svgs = [];
|
|
61
75
|
for (const input of inputs) svgs.push(await prepareRasterImages(normalizeSvgInput(input)));
|
|
@@ -100,12 +114,13 @@ async function rasterizeSvg(svgInput, options) {
|
|
|
100
114
|
const { Resvg } = await loadResvg();
|
|
101
115
|
const scale = positiveNumber(options.scale, "scale", DEFAULT_RASTER_SCALE);
|
|
102
116
|
// FF-45: resvg draws no COLRv1 or OT-SVG colour glyphs; the colour faces stay out of its font list (see color-fonts.js).
|
|
117
|
+
const settings = fontSettings(options);
|
|
103
118
|
const fontFiles = rasterFontFiles([
|
|
104
|
-
...(
|
|
105
|
-
...
|
|
119
|
+
...(settings.useBundledFonts ? await bundledFontFiles() : []),
|
|
120
|
+
...settings.fontFiles
|
|
106
121
|
]);
|
|
107
122
|
const font = {
|
|
108
|
-
loadSystemFonts:
|
|
123
|
+
loadSystemFonts: settings.loadSystemFonts,
|
|
109
124
|
fontFiles,
|
|
110
125
|
fontDirs: stringArray(options.fontDirs),
|
|
111
126
|
defaultFontFamily: options.defaultFontFamily ?? "Roboto",
|
|
@@ -178,8 +193,8 @@ async function bundledFontFiles() {
|
|
|
178
193
|
}
|
|
179
194
|
|
|
180
195
|
async function resolveBundledFontFiles() {
|
|
181
|
-
const {
|
|
182
|
-
return (await
|
|
196
|
+
const {loadFonts} = await import('./fonts-node.js');
|
|
197
|
+
return (await loadFonts()).fontFiles;
|
|
183
198
|
}
|
|
184
199
|
|
|
185
200
|
function normalizeSvgList(value) {
|
package/dist/script-font-pack.js
CHANGED
|
@@ -2,11 +2,9 @@
|
|
|
2
2
|
// stand in for proprietary script fonts in previews. The packages are optional
|
|
3
3
|
// peers, so the renderer install stays small; hosts install only what they use.
|
|
4
4
|
import { BUNDLED_FONT_MANIFEST } from "./font-manifest.js";
|
|
5
|
-
import { OPFFontError } from "./
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
// Optional core exports are read from the namespace so an older published core still loads.
|
|
9
|
-
import * as opfCore from "@openpresentation/opf";
|
|
5
|
+
import { OPFFontError } from "./font-registry.js";
|
|
6
|
+
import { SCRIPT_FONT_REPLACEMENTS, glyphFallbackFamilies, scriptOfCharacter, scriptsOfText } from "./script-fonts.js";
|
|
7
|
+
import { resolveScriptFonts } from "@openpresentation/opf/composition";
|
|
10
8
|
import { presentationFamilies } from "./lazy-fonts.js";
|
|
11
9
|
import { SYMBOL_SCRIPT, isSymbolEncodedFamily } from "./symbol-fonts.js";
|
|
12
10
|
|
|
@@ -33,7 +31,7 @@ export function scriptFontPackages(scripts) {
|
|
|
33
31
|
* Browser entries for the script pack. `baseUrl` is where the host serves the
|
|
34
32
|
* installed `@expo-google-fonts/*` packages (for example a copy of
|
|
35
33
|
* `node_modules/@expo-google-fonts`). Each entry carries the reviewed SHA-256,
|
|
36
|
-
* which `
|
|
34
|
+
* which `loadFonts` (browser) verifies before use.
|
|
37
35
|
*/
|
|
38
36
|
export function scriptFontEntries(scripts, {baseUrl}) {
|
|
39
37
|
return scriptPackageEntries(scriptFontPackages(scripts), {baseUrl});
|
|
@@ -55,17 +53,17 @@ export function scriptPackageEntries(packages, {baseUrl}) {
|
|
|
55
53
|
// Fields a preview never draws (checked against what the renderer and core composition draw).
|
|
56
54
|
// Everywhere: the schema URL, embedded assets, catalog records, speaker notes, ids, image alt text and sources,
|
|
57
55
|
// links, metadata and typed `extensions` passthrough. On the presentation: name (aria-label fallback), description,
|
|
58
|
-
// filename, author,
|
|
59
|
-
// On a slide: beat. The organization (name) and a slide's section are drawn only as
|
|
60
|
-
// furniture (`organization: true` / `section: true` in a design), so they count
|
|
61
|
-
// them. Everything else is drawn text: titles, text blocks, list items, runs, table cells, chart labels,
|
|
56
|
+
// filename, author, audience, purpose, tone, takeaway, duration, tags, narrative, language and version.
|
|
57
|
+
// On a slide: beat. The organization (name), the speaker (name and title) and a slide's section are drawn only as
|
|
58
|
+
// generated header/footer furniture (`organization: true` / `speaker: true` / `section: true` in a design), so they count
|
|
59
|
+
// only when a design asks for them; built-in variables copy their values into slide strings before this runs. Everything else is drawn text: titles, text blocks, list items, runs, table cells, chart labels,
|
|
62
60
|
// categories and series names, code, quotes, metrics, timelines, furniture text.
|
|
63
61
|
const UNDRAWN_KEYS = Object.freeze(["$schema", "assets", "catalogs", "notes", "id", "alt", "altText", "src", "url", "href", "link", "metadata", "extensions"]);
|
|
64
|
-
const UNDRAWN_ROOT_KEYS = Object.freeze(["name", "description", "filename", "author", "authors", "creator", "
|
|
62
|
+
const UNDRAWN_ROOT_KEYS = Object.freeze(["name", "description", "filename", "author", "authors", "creator", "audience", "purpose", "tone", "takeaway", "duration", "tags", "narrative", "language", "license", "version", "keywords"]);
|
|
65
63
|
const UNDRAWN_SLIDE_KEYS = Object.freeze(["beat"]);
|
|
66
64
|
const UNDRAWN_VALUE = /^(?:https?|data|blob|pkg|file|mailto):\S*$/i;
|
|
67
65
|
|
|
68
|
-
/** True when a design in the presentation turns on generated `field` furniture (`organization` or `section`). */
|
|
66
|
+
/** True when a design in the presentation turns on generated `field` furniture (`organization`, `speaker` or `section`). */
|
|
69
67
|
function furnitureUses(presentation, field) {
|
|
70
68
|
const designs = [presentation?.design, ...(Array.isArray(presentation?.slides) ? presentation.slides.map(slide => slide?.design) : [])];
|
|
71
69
|
const pattern = new RegExp(`"${field}"\\s*:\\s*true`);
|
|
@@ -76,6 +74,7 @@ function furnitureUses(presentation, field) {
|
|
|
76
74
|
export function* drawnStrings(presentation) {
|
|
77
75
|
const undrawn = new Set(UNDRAWN_KEYS), undrawnRoot = new Set(UNDRAWN_ROOT_KEYS), undrawnSlide = new Set(UNDRAWN_SLIDE_KEYS);
|
|
78
76
|
if (!furnitureUses(presentation, "organization")) undrawnRoot.add("organization");
|
|
77
|
+
if (!furnitureUses(presentation, "speaker")) undrawnRoot.add("speaker");
|
|
79
78
|
if (!furnitureUses(presentation, "section")) undrawnSlide.add("section");
|
|
80
79
|
function* visit(item, level) {
|
|
81
80
|
if (typeof item === "string") { if (!UNDRAWN_VALUE.test(item)) yield item; }
|
|
@@ -92,21 +91,17 @@ export function* drawnStrings(presentation) {
|
|
|
92
91
|
|
|
93
92
|
/**
|
|
94
93
|
* The script profile of a presentation: core `resolveScriptFonts` output, exactly what the renderer plans
|
|
95
|
-
* with. When the
|
|
96
|
-
*
|
|
94
|
+
* with. When it throws, the renderer ignores the document language, so the profile is empty and Han text is
|
|
95
|
+
* Simplified Chinese, as drawn.
|
|
97
96
|
*/
|
|
98
97
|
export function presentationScriptProfile(presentation) {
|
|
99
|
-
|
|
100
|
-
try { return opfCore.resolveScriptFonts(presentation); } catch { /* the renderer falls back the same way */ }
|
|
101
|
-
}
|
|
98
|
+
try { return resolveScriptFonts(presentation); } catch { /* the renderer falls back the same way */ }
|
|
102
99
|
return {};
|
|
103
100
|
}
|
|
104
101
|
|
|
105
102
|
const servedScripts = () => new Set(BUNDLED_FONT_MANIFEST.packages.filter(item => item.pack === "scripts").flatMap(item => item.scripts));
|
|
106
103
|
const cjkKeys = ["Jpan", "Hans", "Hant", "Kore"];
|
|
107
104
|
const cjkCharacters = new Set(["Hani", "Hira", "Kana", "Hang", "Bopo"]);
|
|
108
|
-
/** True when the renderer has per-character glyph fallback (FF-19 glyphFallbackFamilies). */
|
|
109
|
-
const hasGlyphFallback = () => typeof scriptFontModule.glyphFallbackFamilies === "function";
|
|
110
105
|
|
|
111
106
|
/**
|
|
112
107
|
* ISO 15924 script whose pinned face a family resolves to: a proprietary script font (Yu Gothic: Jpan), a pinned face itself
|
|
@@ -116,7 +111,7 @@ function scriptOfFamily(family) {
|
|
|
116
111
|
const name = String(family ?? "").toLowerCase();
|
|
117
112
|
if (!name) return undefined;
|
|
118
113
|
if (isSymbolEncodedFamily(name)) return SYMBOL_SCRIPT;
|
|
119
|
-
const rule =
|
|
114
|
+
const rule = SCRIPT_FONT_REPLACEMENTS.find(item => item.requestedFamily.toLowerCase() === name);
|
|
120
115
|
if (rule) return rule.script;
|
|
121
116
|
return BUNDLED_FONT_MANIFEST.packages.find(item => item.pack === "scripts" && item.faces.some(face => face.family.toLowerCase() === name))?.scripts[0];
|
|
122
117
|
}
|
|
@@ -144,10 +139,10 @@ function designScripts(presentation, profile, renderOptions) {
|
|
|
144
139
|
}
|
|
145
140
|
};
|
|
146
141
|
note(profile);
|
|
147
|
-
if (
|
|
142
|
+
if (Array.isArray(presentation?.slides)) {
|
|
148
143
|
presentation.slides.forEach((slide, slideIndex) => {
|
|
149
144
|
if (!slide || typeof slide !== "object" || !slide.design || typeof slide.design !== "object") return;
|
|
150
|
-
try { note(
|
|
145
|
+
try { note(resolveScriptFonts(presentation, { slideIndex })); } catch { /* the renderer reports it when it draws the slide */ }
|
|
151
146
|
});
|
|
152
147
|
}
|
|
153
148
|
if (renderOptions?.catalogs) {
|
|
@@ -230,13 +225,12 @@ export function autoScriptSelection(presentation, options) {
|
|
|
230
225
|
* renderer reports `missing-glyph` for them.
|
|
231
226
|
*/
|
|
232
227
|
export function nextFallbackPackage(analysis, { covers, loaded }) {
|
|
233
|
-
if (!hasGlyphFallback()) return undefined;
|
|
234
228
|
const packages = BUNDLED_FONT_MANIFEST.packages.filter(item => item.pack === "scripts" && item.scripts.some(script => cjkKeys.includes(script)));
|
|
235
229
|
const primary = new Set([...analysis.detected, ...(analysis.design ?? [])].filter(script => cjkKeys.includes(script))).size;
|
|
236
230
|
if (packages.filter(item => loaded.has(item.name)).length >= primary + 1) return undefined;
|
|
237
231
|
for (const character of analysis.cjk) {
|
|
238
232
|
if (covers(character)) continue;
|
|
239
|
-
for (const family of
|
|
233
|
+
for (const family of glyphFallbackFamilies(character, analysis.profile, analysis.profile?.serif === true)) {
|
|
240
234
|
const pkg = packages.find(item => !loaded.has(item.name) && item.faces.some(face => face.family === family));
|
|
241
235
|
if (pkg) return pkg;
|
|
242
236
|
}
|
|
@@ -244,8 +238,7 @@ export function nextFallbackPackage(analysis, { covers, loaded }) {
|
|
|
244
238
|
return undefined;
|
|
245
239
|
}
|
|
246
240
|
|
|
247
|
-
/** Drawn Han, kana or Hangul characters (at most `limit`) that no loaded script face covers.
|
|
241
|
+
/** Drawn Han, kana or Hangul characters (at most `limit`) that no loaded script face covers. */
|
|
248
242
|
export function uncoveredCjkCharacters(analysis, { covers, limit = 16 }) {
|
|
249
|
-
if (!hasGlyphFallback()) return [];
|
|
250
243
|
return [...analysis.cjk].filter(character => !covers(character)).slice(0, limit);
|
|
251
244
|
}
|
package/dist/script-fonts.js
CHANGED
|
@@ -16,8 +16,10 @@
|
|
|
16
16
|
// is reported as a note. `glyphFallback: "none"` (strict mode) keeps the exact
|
|
17
17
|
// faces and lets a missing glyph raise `missing-glyph`.
|
|
18
18
|
|
|
19
|
-
import { fontPolicyFor } from "
|
|
20
|
-
import {
|
|
19
|
+
import { fontPolicyFor } from "@openpresentation/opf/font-policy";
|
|
20
|
+
import { scriptFontRole } from "@openpresentation/opf/composition";
|
|
21
|
+
import { SYMBOL_PLACEHOLDER, SYMBOL_SCRIPT, mapSymbolAdvances, symbolEncodingFamily, symbolPreviewFaces } from "./symbol-fonts.js";
|
|
22
|
+
export { scriptFontRole };
|
|
21
23
|
|
|
22
24
|
const freeze = value => { if (value && typeof value === "object") { for (const child of Object.values(value)) freeze(child); Object.freeze(value); } return value; };
|
|
23
25
|
|
|
@@ -171,23 +173,10 @@ export function adjustedFontSize(size, adjust) {
|
|
|
171
173
|
export const EMOJI_FONT_FAMILIES = SCRIPT_FONT_REPLACEMENTS.find(rule => rule.script === "Zsye").substitutes;
|
|
172
174
|
const emojiFaces = new Set(EMOJI_FONT_FAMILIES);
|
|
173
175
|
|
|
174
|
-
const eastAsianScripts = new Set(["Hani", "Hans", "Hant", "Hanb", "Jpan", "Kore", "Hang", "Jamo", "Hira", "Kana", "Hrkt", "Bopo", "Yiii"]);
|
|
175
|
-
const complexScripts = new Set([
|
|
176
|
-
"Arab", "Hebr", "Syrc", "Thaa", "Nkoo", "Adlm", "Rohg", "Mand", "Samr",
|
|
177
|
-
"Deva", "Beng", "Guru", "Gujr", "Orya", "Taml", "Telu", "Knda", "Mlym", "Sinh",
|
|
178
|
-
"Thai", "Laoo", "Tibt", "Mymr", "Khmr", "Mong", "Bali", "Java", "Lana", "Tale", "Talu", "Cakm", "Olck",
|
|
179
|
-
]);
|
|
180
176
|
const rtlScripts = new Set(["Arab", "Hebr", "Syrc", "Thaa", "Nkoo", "Adlm", "Rohg", "Mand", "Samr"]);
|
|
181
177
|
/** Scripts the latin slot covers directly; never split from the surrounding Latin run. */
|
|
182
178
|
const latinGroup = new Set(["Latn", "Cyrl", "Grek", "Zyyy", "Zinh", "Zzzz"]);
|
|
183
179
|
|
|
184
|
-
/** OOXML script slot for an ISO 15924 script code (the same table as core `scriptFontRole`). */
|
|
185
|
-
export function scriptFontRole(script) {
|
|
186
|
-
if (eastAsianScripts.has(script)) return "eastAsian";
|
|
187
|
-
if (complexScripts.has(script)) return "complexScript";
|
|
188
|
-
return "latin";
|
|
189
|
-
}
|
|
190
|
-
|
|
191
180
|
const detected = ["Latn", "Cyrl", "Grek", "Hani", "Hira", "Kana", "Hang", "Bopo", "Yiii", "Arab", "Hebr", "Syrc", "Thaa", "Nkoo", "Adlm", "Rohg", "Mand", "Samr",
|
|
192
181
|
"Deva", "Beng", "Guru", "Gujr", "Orya", "Taml", "Telu", "Knda", "Mlym", "Sinh", "Thai", "Laoo", "Tibt", "Mymr", "Khmr", "Mong", "Bali", "Java", "Lana",
|
|
193
182
|
"Tale", "Talu", "Cakm", "Olck", "Armn", "Geor", "Ethi", "Cher", "Tfng", "Vaii", "Zinh", "Zyyy"].map(code => [code, new RegExp(String.raw`^\p{Script=${code}}$`, "u")]);
|
|
@@ -564,7 +553,7 @@ export function createScriptFonts(profile = {}, measurement, options = {}) {
|
|
|
564
553
|
const hex = item.code.toString(16).toUpperCase().padStart(2, "0");
|
|
565
554
|
if (!entry.codes.includes(hex) && entry.codes.length < 32) { entry.codes.push(hex); if (entry.characters.length < 16) entry.characters.push(item.source); }
|
|
566
555
|
};
|
|
567
|
-
for (const item of
|
|
556
|
+
for (const item of mapSymbolAdvances(encoding, text)) {
|
|
568
557
|
if (item.code === null) { foreign += item.source; continue; }
|
|
569
558
|
flushForeign();
|
|
570
559
|
let drawn = item.unicode, family = null, placeholder = false;
|
|
@@ -600,7 +589,7 @@ export function createScriptFonts(profile = {}, measurement, options = {}) {
|
|
|
600
589
|
text = String(text ?? "");
|
|
601
590
|
// A symbol-encoded family (resolved styles carry `symbolEncoding`; an unresolved style names the family itself) is mapped code by
|
|
602
591
|
// code; `symbolEncoding: null` is the planner's own request for ordinary runs (characters that are not codes).
|
|
603
|
-
const encoding = style.symbolEncoding === null ? undefined : style.symbolEncoding ??
|
|
592
|
+
const encoding = style.symbolEncoding === null ? undefined : style.symbolEncoding ?? symbolEncodingFamily(style.fontFamily);
|
|
604
593
|
if (encoding) return text ? planSymbols(text, style, encoding) : [{text, family: style.fontFamily, own: true}];
|
|
605
594
|
// An emoji face (Noto Color Emoji for a Segoe UI Emoji run) draws emoji-presentation clusters only: its Latin text and digits
|
|
606
595
|
// are planned per cluster below, where they take a text face (FF-45).
|
package/dist/svg.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { RenderFonts, ScriptFonts } from "./fonts.js";
|
|
2
|
+
import type { Finding } from "@openpresentation/opf";
|
|
2
3
|
import type { SlideComposition, LayoutDiagnostic, TextMeasurement } from "@openpresentation/opf/composition";
|
|
3
4
|
export declare const packageName = "@openpresentation/opf-render";
|
|
4
5
|
|
|
@@ -28,7 +29,7 @@ export declare const engineDefaults: Readonly<{
|
|
|
28
29
|
pptx: Readonly<{ latin: "aptos"; ea: "microsoft-yahei"; cs: "nirmala-ui" }>;
|
|
29
30
|
google: Readonly<{ latin: "roboto"; ea: "noto-sans-sc"; cs: "noto-sans" }>;
|
|
30
31
|
}>;
|
|
31
|
-
chartTypes: readonly ["stacked-column
|
|
32
|
+
chartTypes: readonly ["stacked-column", "stacked-area", "line-with-markers"];
|
|
32
33
|
}>;
|
|
33
34
|
|
|
34
35
|
export type RenderDiagnostic = LayoutDiagnostic | {
|
|
@@ -41,7 +42,7 @@ export type RenderDiagnostic = LayoutDiagnostic | {
|
|
|
41
42
|
scripts: string[];
|
|
42
43
|
characters: string[];
|
|
43
44
|
} | {
|
|
44
|
-
code: "unsupported-pattern" | "variable-example-used" | "
|
|
45
|
+
code: "unsupported-pattern" | "variable-example-used" | "variable-builtin-missing" | "date-needs-value" | "language-preview-unresolved";
|
|
45
46
|
path: string;
|
|
46
47
|
message: string;
|
|
47
48
|
} | {
|
|
@@ -51,6 +52,12 @@ export type RenderDiagnostic = LayoutDiagnostic | {
|
|
|
51
52
|
message: string;
|
|
52
53
|
id: string;
|
|
53
54
|
fallback: string;
|
|
55
|
+
} | {
|
|
56
|
+
/** A layout, theme or colour-scheme id matched no record: the slide composed with no layout record, the `minimal` theme or the `cool-horizon` colour scheme. Never an error. */
|
|
57
|
+
code: "unresolved-layout" | "unresolved-theme" | "unresolved-color-scheme";
|
|
58
|
+
path: string;
|
|
59
|
+
message: string;
|
|
60
|
+
id: string;
|
|
54
61
|
} | {
|
|
55
62
|
code: "unresolved-asset";
|
|
56
63
|
path: string;
|
|
@@ -63,12 +70,18 @@ export type RenderDiagnostic = LayoutDiagnostic | {
|
|
|
63
70
|
};
|
|
64
71
|
|
|
65
72
|
export interface RenderSvgOptions {
|
|
66
|
-
|
|
73
|
+
/** Leave out slides marked `hidden: true`, as the player does. Default false: one SVG per slide. With true the result holds only the visible slides, in order, so an index no longer names the slide at that index. Read by the deck-level `renderSvg`; `renderSlideSvg` draws the slide it is given. */
|
|
74
|
+
skipHidden?: boolean;
|
|
75
|
+
/**
|
|
76
|
+
* The fonts the deck is laid out and drawn with: the handle `loadFonts()` returns (from `@openpresentation/opf-render/fonts-node` or
|
|
77
|
+
* `/fonts-browser`), or any object with a `textMeasurement` and, to embed faces in each SVG, an `embeddedFonts` list. Without it layout uses
|
|
78
|
+
* core's portable width estimate and the SVG names the design fonts without embedding them.
|
|
79
|
+
*/
|
|
80
|
+
fonts?: RenderFonts;
|
|
67
81
|
/** `"chain"` (default): a character the resolved face lacks is drawn with the first bundled face that has it, and reported as `font-glyph-fallback`. `"none"`: exact faces, a missing glyph raises `missing-glyph`. */
|
|
68
82
|
glyphFallback?: "chain" | "none";
|
|
69
83
|
/** Unscaled reference-pixel clearance around supplied vector text outlines; default 1. */
|
|
70
84
|
textRasterPadding?: number;
|
|
71
|
-
embeddedFonts?: EmbeddedFont[];
|
|
72
85
|
strictAssets?: boolean;
|
|
73
86
|
imageResolver?: (src: string | undefined, context: { asset: unknown; path: string }) => string | null | undefined;
|
|
74
87
|
onDiagnostic?: (diagnostic: RenderDiagnostic) => void;
|
|
@@ -77,12 +90,11 @@ export interface RenderSvgOptions {
|
|
|
77
90
|
/**
|
|
78
91
|
* Values for the deck's template variables, keyed by variable id (core `resolveVariables`). A deck that uses
|
|
79
92
|
* content variables, or is marked `template: true`, is resolved to a concrete deck first. A template previews with
|
|
80
|
-
* each unfilled variable's example (reported as `variable-example-used`); a normal deck with an unfilled required
|
|
93
|
+
* each unfilled variable's example (reported as `variable-example-used`; a built-in such as `{{speaker.name}}` with no source value is reported as `variable-builtin-missing`); a normal deck with an unfilled required
|
|
81
94
|
* variable throws `unfilled-variables`. `false` draws the document as authored, with `{{id}}` tokens and
|
|
82
95
|
* `var:id` references visible and nothing resolved: the view an editor uses while the template itself is edited.
|
|
83
96
|
*/
|
|
84
97
|
variables?: Record<string, unknown> | false;
|
|
85
|
-
slideIndex?: number;
|
|
86
98
|
/**
|
|
87
99
|
* Today's calendar date (ISO YYYY-MM-DD) for `date: true` header/footer furniture. The renderer
|
|
88
100
|
* never reads a clock; without it a current date is reported as unresolved content.
|
|
@@ -99,12 +111,12 @@ export interface RenderSvgOptions {
|
|
|
99
111
|
}
|
|
100
112
|
|
|
101
113
|
export interface SvgToPngOptions {
|
|
114
|
+
/** The fonts the conversion draws with (Node): see `SvgToPngOptions` in the main entry. */
|
|
115
|
+
fonts?: RenderFonts;
|
|
102
116
|
scale?: number;
|
|
103
117
|
background?: string;
|
|
104
118
|
dpi?: number;
|
|
105
|
-
|
|
106
|
-
loadSystemFonts?: boolean;
|
|
107
|
-
fontFiles?: string[];
|
|
119
|
+
/** Extra directories of font files to draw with. */
|
|
108
120
|
fontDirs?: string[];
|
|
109
121
|
defaultFontFamily?: string;
|
|
110
122
|
sansSerifFamily?: string;
|
|
@@ -128,7 +140,8 @@ export interface ResolvedSlide {
|
|
|
128
140
|
index: number;
|
|
129
141
|
path: string;
|
|
130
142
|
slide: unknown;
|
|
131
|
-
layout
|
|
143
|
+
/** The layout record the slide names; absent when it names none or an id no catalog has (the slide then composes with no layout). */
|
|
144
|
+
layout?: unknown;
|
|
132
145
|
design: {
|
|
133
146
|
theme: unknown;
|
|
134
147
|
colorScheme: unknown;
|
|
@@ -157,15 +170,18 @@ export interface RenderBinding {
|
|
|
157
170
|
export declare class OPFRenderError extends Error {
|
|
158
171
|
readonly code: string;
|
|
159
172
|
readonly details: Record<string, unknown>;
|
|
160
|
-
|
|
173
|
+
/** `invalid-opf`: the error findings of core `validate(presentation, { only: ["format"] })` (also `details.findings`; `details.report` is the whole report). */
|
|
174
|
+
readonly findings?: Finding[];
|
|
161
175
|
readonly path?: string;
|
|
162
176
|
constructor(code: string, message: string, details?: Record<string, unknown>);
|
|
163
177
|
}
|
|
164
178
|
|
|
165
179
|
export declare function resolvePresentation(input: unknown, options?: RenderSvgOptions): ResolvedPresentation;
|
|
166
180
|
|
|
167
|
-
|
|
181
|
+
/** The SVG of every slide of the deck, in order. */
|
|
182
|
+
export declare function renderSvg(input: unknown, options?: RenderSvgOptions): string[];
|
|
168
183
|
|
|
169
|
-
|
|
184
|
+
/** The SVG of one slide of the deck (`index` is zero-based; out of range throws `slide-index-out-of-range`). */
|
|
185
|
+
export declare function renderSlideSvg(input: unknown, index: number, options?: RenderSvgOptions): string;
|
|
170
186
|
|
|
171
187
|
|