@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/dist/fonts.d.ts
CHANGED
|
@@ -34,14 +34,14 @@ export interface FontRegistryOptions {
|
|
|
34
34
|
export declare const FONT_COMPATIBILITY: readonly Readonly<{requestedFamily:string;substitutes:readonly string[];compatibility:"metric"|"visual";weights?:readonly number[];weight?:number;source?:string;measured?:FontReplacementMeasurement;decision?:string;metricModeFallback?:true;licenseClass?:FontPolicyEntry['licenseClass'];note:string}>[];
|
|
35
35
|
export declare const EXPERIMENTAL_FONT_CANDIDATES: readonly Readonly<{requestedFamily:string;substitute:string;source:string;note:string}>[];
|
|
36
36
|
/**
|
|
37
|
-
* What the deck-level functions read from their `fonts` option: `
|
|
38
|
-
* the faces to embed; `
|
|
37
|
+
* What the deck-level functions read from their `fonts` option: `toSvg` and `<opf-deck>` take the measurement and
|
|
38
|
+
* the faces to embed; `toPng` and `toPdf` (Node) take the font files; core `paginate`, `validate` and `resolveSlideContext` take the
|
|
39
39
|
* measurement. The object `loadFonts()` returns is a `FontsHandle`, which extends this; any object with these fields works.
|
|
40
40
|
*/
|
|
41
41
|
export interface RenderFonts {
|
|
42
42
|
/** Measures text with the real faces. Without it layout uses core's portable estimate. */
|
|
43
43
|
textMeasurement?: TextMeasurement;
|
|
44
|
-
/** Faces `
|
|
44
|
+
/** Faces `toSvg` may write into an SVG as @font-face data: each only into the SVGs whose text draws it (its family, weight and style), unless flagged `embed: "always"` (RR-61). */
|
|
45
45
|
embeddedFonts?: readonly EmbeddedFont[];
|
|
46
46
|
/** Font files the Node raster and PDF conversions draw with. */
|
|
47
47
|
fontFiles?: readonly string[];
|
|
@@ -49,14 +49,14 @@ export interface RenderFonts {
|
|
|
49
49
|
useBundledFonts?: boolean;
|
|
50
50
|
/** Whether the raster conversion loads system fonts. Default false (the output never depends on the machine). */
|
|
51
51
|
loadSystemFonts?: boolean;
|
|
52
|
-
/** The outline engine `
|
|
52
|
+
/** The outline engine `text: "paths"` draws text with (RR-64); a `loadFonts` handle carries one over its registry's faces. */
|
|
53
53
|
outlines?: TextOutlines;
|
|
54
54
|
/** The subset engine (RR-65): each face an SVG embeds is cut to the characters the slide draws. The Node `loadFonts` handle carries one; a browser handle with `subsetWasm`. */
|
|
55
55
|
subsets?: FontSubsets;
|
|
56
56
|
}
|
|
57
57
|
/** Cuts an embedded face to code points (RR-65), with hb-subset; a face whose license, Reserved Font Name or fsType does not allow it keeps its own data URL. */
|
|
58
58
|
export interface FontSubsets { subsetDataUrl(font: EmbeddedFont, codePoints: Iterable<number>): string }
|
|
59
|
-
/** Draws a slide's text as glyph outlines (RR-64). Read by `
|
|
59
|
+
/** Draws a slide's text as glyph outlines (RR-64). Read by `toSvg`; hosts pass the handle and `text: "paths"`. */
|
|
60
60
|
export interface TextOutlines { outlineSlideText(content: string[], options: object): { content: string[]; defs: string } }
|
|
61
61
|
/** What `fonts.ensure(presentation)` loaded: the script packages and vendored faces that were missing, and drawn CJK characters no face covers. */
|
|
62
62
|
export interface EnsureResult { scripts: string[]; lazy: LazyFont[]; uncovered: string[] }
|
|
@@ -66,7 +66,7 @@ export interface FontsHandle extends RenderFonts {
|
|
|
66
66
|
readonly embeddedFonts: EmbeddedFont[];
|
|
67
67
|
/** The face registry behind the handle (shaping, resolution, lazy and script loading). */
|
|
68
68
|
readonly registry: FontRegistry;
|
|
69
|
-
/** The outline engine for `
|
|
69
|
+
/** The outline engine for `text: "paths"` (RR-64), over this registry's faces, including faces `ensure` loads later. */
|
|
70
70
|
readonly outlines: TextOutlines;
|
|
71
71
|
/** The pinned manifest of the bundled font packages. */
|
|
72
72
|
readonly manifest: { readonly version: number; readonly packages: readonly object[] };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { RenderFonts, ScriptFonts } from "./fonts.js";
|
|
2
|
-
import type { Catalog, Finding, UnresolvedReferenceDiagnostic } from "@openpresentation/opf";
|
|
2
|
+
import type { Catalog, Finding, SlideSelection, UnresolvedReferenceDiagnostic } from "@openpresentation/opf";
|
|
3
|
+
export type { SlideSelection } from "@openpresentation/opf";
|
|
3
4
|
import type { SlideComposition, LayoutDiagnostic, TextMeasurement } from "@openpresentation/opf/composition";
|
|
4
5
|
export declare const packageName = "@openpresentation/opf-render";
|
|
5
6
|
|
|
@@ -49,8 +50,8 @@ export type RenderDiagnostic = LayoutDiagnostic | {
|
|
|
49
50
|
placeholder: "label" | "icon";
|
|
50
51
|
};
|
|
51
52
|
|
|
52
|
-
export interface
|
|
53
|
-
/** Leave out slides marked `hidden: true
|
|
53
|
+
export interface ToSvgOptions {
|
|
54
|
+
/** Leave out slides marked `hidden: true` when drawing the whole deck, as the player does. Default false: one SVG per slide. A slide number or selection draws exactly the slides it names. */
|
|
54
55
|
skipHidden?: boolean;
|
|
55
56
|
/**
|
|
56
57
|
* The fonts the deck is laid out and drawn with: the handle `loadFonts()` returns (from `@openpresentation/opf-render/fonts-node` or
|
|
@@ -58,10 +59,12 @@ export interface RenderSvgOptions {
|
|
|
58
59
|
* core's portable width estimate and the SVG names the design fonts without embedding them.
|
|
59
60
|
*/
|
|
60
61
|
fonts?: RenderFonts;
|
|
61
|
-
/** `false` writes no `@font-face` data into the SVG (RR-61): the fonts handle still measures and the SVG still names the families, for a host whose page already has the faces (a browser `loadFonts` handle adds them to the document). Default true: each SVG embeds the faces of `fonts.embeddedFonts` its own text draws. */
|
|
62
|
-
embedFonts?: boolean;
|
|
63
62
|
/**
|
|
64
|
-
*
|
|
63
|
+
* How the SVG draws text (RR-74). `"fonts"` (default): each SVG embeds, as `@font-face` data, the faces of `fonts.embeddedFonts` its
|
|
64
|
+
* own text draws (RR-61). `"system"`: no `@font-face` data; the fonts handle still measures and the SVG still names the families,
|
|
65
|
+
* for a host whose page already has the faces (a browser `loadFonts` handle adds them to the document).
|
|
66
|
+
*
|
|
67
|
+
* `"paths"`: every `<text>` drawn as glyph outlines (RR-64): `<use>` of outlines kept once per slide in `<defs>`, so the SVG needs
|
|
65
68
|
* no font and looks the same in every viewer (about 40 KB a slide over the core example decks, against 0.5 to 4 MB of embedded
|
|
66
69
|
* faces). Needs the fonts handle `loadFonts()` returns (`text-as-paths-needs-fonts` otherwise). The text is no longer text: it
|
|
67
70
|
* cannot be edited in place. The glyphs are shaped by HarfBuzz (the browser's shaper; the Node handle always, a browser handle
|
|
@@ -70,9 +73,9 @@ export interface RenderSvgOptions {
|
|
|
70
73
|
* A run stays text, reported as `text-as-paths-fallback` with a `reason`, when its font is a colour or bitmap font
|
|
71
74
|
* (`"colour-font"`), its face's fsType restricts embedding (`"restricted"`), or it has no pinned width and HarfBuzz and the
|
|
72
75
|
* layout's measurement disagree on it (`"shaping"`). Use it for thumbnails, previews and portable SVG files, not for an editing
|
|
73
|
-
* surface or the vector PDF (which keeps real text from `<text>` SVG).
|
|
76
|
+
* surface or the vector PDF (which keeps real text from `<text>` SVG).
|
|
74
77
|
*/
|
|
75
|
-
|
|
78
|
+
text?: "fonts" | "system" | "paths";
|
|
76
79
|
/**
|
|
77
80
|
* `false` embeds whole faces (RR-65). By default, with a fonts handle that carries `subsets` (the Node `loadFonts` handle, a browser
|
|
78
81
|
* handle given `subsetWasm`), each face an SVG embeds is cut to the characters the slide draws, keeping every layout feature, so the
|
|
@@ -118,18 +121,18 @@ export interface RenderSvgOptions {
|
|
|
118
121
|
strictReferences?: boolean;
|
|
119
122
|
}
|
|
120
123
|
|
|
121
|
-
|
|
124
|
+
/** The options of `toPng`: the conversion's own, and the `toSvg` options that draw a deck. */
|
|
125
|
+
export interface ToPngOptions extends Omit<ToSvgOptions, "fonts"> {
|
|
122
126
|
/**
|
|
123
|
-
* The fonts the
|
|
124
|
-
* `loadSystemFonts` say whether the bundled base faces are added, default true, and whether
|
|
125
|
-
*
|
|
127
|
+
* The fonts the deck is laid out and drawn with: the handle `loadFonts()` returns from `/fonts-node` (it measures the deck, and its
|
|
128
|
+
* `fontFiles` draw; `useBundledFonts` and `loadSystemFonts` say whether the bundled base faces are added, default true, and whether
|
|
129
|
+
* system fonts load, default false), so the preview and the PNG use the same faces. For SVG input it may instead be font folders
|
|
130
|
+
* (a path or a list of paths), whose faces are added to the bundled base faces. Without it the bundled base faces draw.
|
|
126
131
|
*/
|
|
127
|
-
fonts?: RenderFonts;
|
|
132
|
+
fonts?: RenderFonts | string | readonly string[];
|
|
128
133
|
scale?: number;
|
|
129
134
|
background?: string;
|
|
130
135
|
dpi?: number;
|
|
131
|
-
/** Extra directories of font files to draw with. */
|
|
132
|
-
fontDirs?: string[];
|
|
133
136
|
defaultFontFamily?: string;
|
|
134
137
|
sansSerifFamily?: string;
|
|
135
138
|
monospaceFamily?: string;
|
|
@@ -198,14 +201,14 @@ export interface PdfMetadata {
|
|
|
198
201
|
modificationDate?: Date | string;
|
|
199
202
|
}
|
|
200
203
|
|
|
201
|
-
export interface
|
|
204
|
+
export interface ToPdfOptions extends Omit<ToPngOptions, "onDiagnostic"> {
|
|
202
205
|
/**
|
|
203
|
-
* `
|
|
204
|
-
* with embedded font subsets (selectable, searchable, correct copy and paste); the fonts are
|
|
205
|
-
* `fontFiles` and the
|
|
206
|
+
* `true` draws each slide as an image (`scale`). Default false, a vector PDF: shapes, gradients and patterns as PDF vector graphics,
|
|
207
|
+
* pictures as images, text as real text with embedded font subsets (selectable, searchable, correct copy and paste); the fonts are
|
|
208
|
+
* the bundled files, the `fonts` handle's `fontFiles` and the font folders you supply, never system fonts.
|
|
206
209
|
*/
|
|
207
|
-
|
|
208
|
-
/**
|
|
210
|
+
raster?: boolean;
|
|
211
|
+
/** A vector PDF paints the page this colour first (default white, as a raster PDF composites on white); `"none"` leaves it unpainted. */
|
|
209
212
|
background?: string;
|
|
210
213
|
/** Vector only. Family drawn for the generic `serif`; default `defaultFontFamily`. */
|
|
211
214
|
serifFamily?: string;
|
|
@@ -219,8 +222,8 @@ export interface SvgToPdfOptions extends SvgToPngOptions {
|
|
|
219
222
|
strict?: boolean;
|
|
220
223
|
/** Vector only. Pixel density of the rare element rasterized because it has no vector form; default 2. */
|
|
221
224
|
rasterFallbackScale?: number;
|
|
222
|
-
/** Vector only
|
|
223
|
-
onDiagnostic?: (diagnostic: PdfDiagnostic) => void;
|
|
225
|
+
/** Vector only: font embedding reports, substitutions, fallbacks and unsupported features; given a deck, also the diagnostics of drawing it. */
|
|
226
|
+
onDiagnostic?: (diagnostic: PdfDiagnostic | RenderDiagnostic) => void;
|
|
224
227
|
/** Vector only. Checked between pages; an abort rejects with the signal's reason. */
|
|
225
228
|
signal?: AbortSignal;
|
|
226
229
|
/** Vector only. Called after each page is written. */
|
|
@@ -278,14 +281,32 @@ export declare class OPFRenderError extends Error {
|
|
|
278
281
|
constructor(code: string, message: string, details?: Record<string, unknown>);
|
|
279
282
|
}
|
|
280
283
|
|
|
281
|
-
export declare function resolvePresentation(input: unknown, options?:
|
|
284
|
+
export declare function resolvePresentation(input: unknown, options?: ToSvgOptions): ResolvedPresentation;
|
|
282
285
|
|
|
283
|
-
/**
|
|
284
|
-
export
|
|
286
|
+
/** An SVG slide the renderer drew: its text, or its bytes. */
|
|
287
|
+
export type SvgSlide = string | Uint8Array;
|
|
285
288
|
|
|
286
|
-
/**
|
|
287
|
-
|
|
289
|
+
/**
|
|
290
|
+
* The deck as SVG (RR-73). `toSvg(deck)`: every slide, in order (without the hidden ones under `skipHidden`). `toSvg(deck, 3)`: the
|
|
291
|
+
* third slide (slides count from 1; out of range throws `slide-out-of-range`). `toSvg(deck, "1-3")` or `toSvg(deck, [1, 3])`: the
|
|
292
|
+
* selected slides (a malformed selection throws `invalid-slide-selection`). The second argument may be the options instead.
|
|
293
|
+
*/
|
|
294
|
+
export declare function toSvg(input: unknown, options?: ToSvgOptions): string[];
|
|
295
|
+
export declare function toSvg(input: unknown, slide: number, options?: ToSvgOptions): string;
|
|
296
|
+
export declare function toSvg(input: unknown, slides: Exclude<SlideSelection, number>, options?: ToSvgOptions): string[];
|
|
288
297
|
|
|
289
|
-
|
|
298
|
+
/**
|
|
299
|
+
* PNG (RR-73) of a deck, drawn with `toSvg` (the slide arguments are `toSvg`'s: one PNG for a slide number, a list otherwise), or of
|
|
300
|
+
* SVG the renderer drew (one SVG gives one PNG, a list a list). A slide selection with SVG input throws `invalid-conversion-option`.
|
|
301
|
+
*/
|
|
302
|
+
export declare function toPng(svg: Uint8Array | `<${string}`, options?: ToPngOptions): Promise<Uint8Array>;
|
|
303
|
+
export declare function toPng(svgs: readonly SvgSlide[], options?: ToPngOptions): Promise<Uint8Array[]>;
|
|
304
|
+
export declare function toPng(deck: unknown, slide: number, options?: ToPngOptions): Promise<Uint8Array>;
|
|
305
|
+
export declare function toPng(deck: unknown, slides: Exclude<SlideSelection, number>, options?: ToPngOptions): Promise<Uint8Array[]>;
|
|
306
|
+
export declare function toPng(deck: object, options?: ToPngOptions): Promise<Uint8Array[]>;
|
|
307
|
+
/** A string is SVG when it starts with `<`, and the deck's JSON text otherwise. */
|
|
308
|
+
export declare function toPng(source: string, options?: ToPngOptions): Promise<Uint8Array | Uint8Array[]>;
|
|
290
309
|
|
|
291
|
-
|
|
310
|
+
/** One PDF (RR-73), a page per slide: of a deck drawn with `toSvg` (every slide, or a selection: `toPdf(deck, "2-4")`), or of SVG slides. */
|
|
311
|
+
export declare function toPdf(source: unknown, options?: ToPdfOptions): Promise<Uint8Array>;
|
|
312
|
+
export declare function toPdf(deck: unknown, slides: SlideSelection, options?: ToPdfOptions): Promise<Uint8Array>;
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export * from './svg.js';
|
|
2
|
-
export {
|
|
2
|
+
export {toPng,toPdf} from './raster.js';
|
package/dist/lazy-fonts.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { fontPolicyFor } from "@openpresentation/opf/font-policy";
|
|
2
2
|
import { pickFace } from "./font-registry.js";
|
|
3
|
-
import {
|
|
3
|
+
import { resolvePresentation, toSvg } from "./svg.js";
|
|
4
4
|
export { lazyFontEntries, lazyFontList } from "./lazy-font-list.js";
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -17,7 +17,7 @@ const lc = value => String(value).trim().toLowerCase();
|
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* Render options that decide how a document resolves (catalogs, validate, date, ...) are forwarded from the host's
|
|
20
|
-
* `
|
|
20
|
+
* `toSvg` options. The analysis supplies its own measurement and reports nothing: callbacks, the host's fonts handle
|
|
21
21
|
* (measurement and embedded fonts), asset resolution and tracing are dropped.
|
|
22
22
|
*/
|
|
23
23
|
const NOT_RESOLVE_OPTIONS = new Set(["fonts", "onDiagnostic", "trace", "glyphFallback", "imageResolver", "strictAssets", "signal"]);
|
|
@@ -27,10 +27,10 @@ function resolveOptionsOf(options) {
|
|
|
27
27
|
|
|
28
28
|
/**
|
|
29
29
|
* The font families a presentation's slides resolve (heading, body and code roles of every slide, including per-slide
|
|
30
|
-
* design overrides), as `
|
|
30
|
+
* design overrides), as `toSvg` resolves them with the same `options` (`catalogs`, ...). This is the role families,
|
|
31
31
|
* not what is drawn: use `presentationFaces` for that.
|
|
32
32
|
*
|
|
33
|
-
* A document that does not resolve throws the error `
|
|
33
|
+
* A document that does not resolve throws the error `toSvg` throws for it (an OPFRenderError such as
|
|
34
34
|
* `catalog-resolution-failed` for a layout id no catalog has, or `invalid-opf`), never an empty set: a document whose layout comes only from
|
|
35
35
|
* `options.catalogs` needs those catalogs here too.
|
|
36
36
|
*/
|
|
@@ -57,7 +57,7 @@ function registryView({ faces, policy = "none", aliases = new Map(), fallbackFam
|
|
|
57
57
|
|
|
58
58
|
/**
|
|
59
59
|
* The faces a preview of the presentation draws, as `[{family, weight, italic}]`, sorted by family, style and weight. It is
|
|
60
|
-
* the renderer's own layout and painting run with a recording measurement, so it follows exactly what `
|
|
60
|
+
* the renderer's own layout and painting run with a recording measurement, so it follows exactly what `toSvg` measures
|
|
61
61
|
* and draws: the heading and body roles of every slide that draws them, bold and italic runs of rich text, table and cell
|
|
62
62
|
* styles, header and footer furniture, chart labels, metrics, quotes and timelines, the code role only where code is
|
|
63
63
|
* drawn, per-slide design overrides, font scheme and theme resolution, and script slots (a script run is requested in its
|
|
@@ -73,8 +73,8 @@ function registryView({ faces, policy = "none", aliases = new Map(), fallbackFam
|
|
|
73
73
|
* family found. The result is the faces the registry paints, for example `Intos 700` for a 600-weight label of an Aptos
|
|
74
74
|
* deck. A style the registry cannot resolve is left as named (drawing reports it).
|
|
75
75
|
*
|
|
76
|
-
* `options` are the `
|
|
77
|
-
* does not resolve throws what `
|
|
76
|
+
* `options` are the `toSvg` options the document resolves with (`catalogs`, `date`, `validate`, ...). A document that
|
|
77
|
+
* does not resolve throws what `toSvg` throws for it.
|
|
78
78
|
* @param {unknown} presentation
|
|
79
79
|
* @param {object} [options]
|
|
80
80
|
* @param {{faces: Iterable<{family: string, weight: number, italic: boolean}>, policy?: "none"|"metric"|"visual", aliases?: ReadonlyMap<string, string>, fallbackFamily?: string}} [registry]
|
|
@@ -98,7 +98,7 @@ export function presentationFaces(presentation, options = {}, registry) {
|
|
|
98
98
|
measure(text, size, style) { if (text !== "") record(settle(style)); return String(text).length * size * RECORDED_EM; },
|
|
99
99
|
resolveStyle: settle,
|
|
100
100
|
};
|
|
101
|
-
|
|
101
|
+
toSvg(presentation, { ...resolveOptionsOf(options), fonts: { textMeasurement } });
|
|
102
102
|
return [...seen.values()].sort((a, b) => a.family < b.family ? -1 : a.family > b.family ? 1 : Number(a.italic) - Number(b.italic) || a.weight - b.weight);
|
|
103
103
|
}
|
|
104
104
|
|
|
@@ -106,8 +106,8 @@ export function presentationFaces(presentation, options = {}, registry) {
|
|
|
106
106
|
* The vendored faces (of `lazy`) a presentation draws that the registry does not hold: what a registry loads before it can
|
|
107
107
|
* paint the document as Node paints it with every vendored face loaded. `held` lists the registry's faces
|
|
108
108
|
* (`registry.describeFaces()`), `loaded` the lazy files already loaded; `policy`, `aliases` and `fallbackFamily` are the
|
|
109
|
-
* registry's. `renderOptions` are the `
|
|
110
|
-
* does not resolve throws what `
|
|
109
|
+
* registry's. `renderOptions` are the `toSvg` options the document resolves with (`catalogs`, ...), and a document that
|
|
110
|
+
* does not resolve throws what `toSvg` throws for it. Face level: a bold or italic run added by an edit adds just that face.
|
|
111
111
|
*/
|
|
112
112
|
export function lazyFacesNeeded(presentation, renderOptions, { lazy, held, loaded = new Set(), policy = "none", aliases = new Map(), fallbackFamily }) {
|
|
113
113
|
const heldFaces = [...held], heldKeys = new Set(heldFaces.map(faceKeyOf));
|
package/dist/pdf-fonts.js
CHANGED
|
@@ -4,7 +4,7 @@ import { isTrueTypeOutlines, subsetTrueType } from "./pdf-subset.js";
|
|
|
4
4
|
import { hex, name, num, sha256, textString, utf16Hex } from "./pdf-writer.js";
|
|
5
5
|
|
|
6
6
|
// Font selection, shaping and embedding for the vector PDF export (RR-12). Fonts come only from the faces the
|
|
7
|
-
// caller supplies (the same bundled font files,
|
|
7
|
+
// caller supplies (the same bundled font files, fonts handle or font folders the PNG preview draws with, and the
|
|
8
8
|
// `@font-face` data of the SVG itself); nothing is read from the system and nothing is fetched. A face whose
|
|
9
9
|
// OS/2 embedding bits forbid embedding is never embedded.
|
|
10
10
|
|
package/dist/pdf-vector.js
CHANGED
|
@@ -89,7 +89,7 @@ class Converter {
|
|
|
89
89
|
this.reported.add(key);
|
|
90
90
|
this.unsupported(d.code, d.message, { fontFamily: d.fontFamily, codePoint: d.codePoint });
|
|
91
91
|
},
|
|
92
|
-
unavailable: (families) => this.error("pdf-font-unavailable", `No embeddable font face is available for ${families.length ? `'${families.join("', '")}'` : "the requested text"}.
|
|
92
|
+
unavailable: (families) => this.error("pdf-font-unavailable", `No embeddable font face is available for ${families.length ? `'${families.join("', '")}'` : "the requested text"}. Pass the fonts handle or font folders as fonts, or keep useBundledFonts enabled.`, {}),
|
|
93
93
|
};
|
|
94
94
|
}
|
|
95
95
|
|
|
@@ -1228,7 +1228,7 @@ async function listFonts(directory, { readdir, path }) {
|
|
|
1228
1228
|
}
|
|
1229
1229
|
|
|
1230
1230
|
/**
|
|
1231
|
-
* Convert SVG slides to a vector PDF. `options` carries the resolved conversion settings (see
|
|
1231
|
+
* Convert SVG slides to a vector PDF. `options` carries the resolved conversion settings (see toPdf in raster.js).
|
|
1232
1232
|
*/
|
|
1233
1233
|
export async function svgsToVectorPdf(svgs, options) {
|
|
1234
1234
|
const converter = new Converter(options);
|
package/dist/pdf.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export type {
|
|
1
|
+
export { toPdf } from "./index.js";
|
|
2
|
+
export type { ToPdfOptions, PdfDiagnostic, PdfMetadata } from "./index.js";
|
package/dist/pdf.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// RR-63: the PDF format entry (Node). The default vector `
|
|
2
|
-
// `sharp` for pictures and `@resvg/resvg-js` for the rare element it rasterizes, and `
|
|
1
|
+
// RR-63: the PDF format entry (Node). The default vector `toPdf` needs no converter for text and shapes; it loads the optional peer
|
|
2
|
+
// `sharp` for pictures and `@resvg/resvg-js` for the rare element it rasterizes, and `raster: true` also loads `pdf-lib`. A converter
|
|
3
3
|
// that is not installed rejects with `OPFRenderError` code `converter-missing`. For a page use `@openpresentation/opf-render/export-browser`.
|
|
4
|
-
export {
|
|
4
|
+
export { toPdf } from "./raster.js";
|
package/dist/player.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BrowserFontsHandle } from "./fonts-browser.js";
|
|
2
|
-
import type {
|
|
2
|
+
import type { ToSvgOptions } from "./svg.js";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Why a deck could not be loaded, drawn or presented. `code` is stable: `invalid-document`, `fetch-failed`, `fonts-unavailable`,
|
|
@@ -19,8 +19,8 @@ export type BlankMode = "none" | "black" | "white";
|
|
|
19
19
|
export interface PresentOptions {
|
|
20
20
|
/** The self-hosted font root URL (see `copyPreviewFonts`), or a browser fonts handle the page already has (`loadFonts` from `/fonts-browser`). Without it layout uses estimated widths and system fonts. */
|
|
21
21
|
fonts?: string | BrowserFontsHandle;
|
|
22
|
-
/** Extra `
|
|
23
|
-
renderOptions?: Partial<
|
|
22
|
+
/** Extra `toSvg` options (catalogs, imageResolver, date, ...). */
|
|
23
|
+
renderOptions?: Partial<ToSvgOptions>;
|
|
24
24
|
/** 1-based slide to start on, in the sequence that plays. Default 1. */
|
|
25
25
|
startSlide?: number;
|
|
26
26
|
/** Play hidden slides too. Default false. */
|
package/dist/player.js
CHANGED
|
@@ -632,7 +632,7 @@ async function readSource(source, signal) {
|
|
|
632
632
|
* player covers the page at once (and asks for full screen), then resolves with the running session when the first slide is
|
|
633
633
|
* drawn. Call it from a click or key handler: full screen and the speaker view both need a user gesture.
|
|
634
634
|
*
|
|
635
|
-
* Options: `fonts` (the self-hosted font root URL, or a browser fonts handle from `loadFonts`), `renderOptions` (extra `
|
|
635
|
+
* Options: `fonts` (the self-hosted font root URL, or a browser fonts handle from `loadFonts`), `renderOptions` (extra `toSvg` options),
|
|
636
636
|
* `startSlide` (1-based), `includeHidden`, `fullscreen` (default true), `presenterView` (open the speaker view too),
|
|
637
637
|
* `role: "presenter"` (this window is the speaker view: for a second tab or window of your page), `channel` (name, or `false`
|
|
638
638
|
* for no sync), `container`, `signal` and `now` (an injectable clock).
|
package/dist/png.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export type {
|
|
1
|
+
export { toPng } from "./index.js";
|
|
2
|
+
export type { ToPngOptions } from "./index.js";
|
package/dist/png.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// RR-63: the PNG format entry (Node). `
|
|
1
|
+
// RR-63: the PNG format entry (Node). `toPng` loads the optional peers `@resvg/resvg-js` (and `sharp` for WebP and rotated JPEG
|
|
2
2
|
// pictures) on first use and rejects with `OPFRenderError` code `converter-missing` when they are not installed. For a page use
|
|
3
3
|
// `@openpresentation/opf-render/export-browser`.
|
|
4
|
-
export {
|
|
4
|
+
export { toPng } from "./raster.js";
|
package/dist/raster.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {prepareRasterImages} from './raster-images.js';
|
|
2
|
-
import {OPFRenderError,packageName} from './svg.js';
|
|
2
|
+
import {OPFRenderError,packageName,toSvg} from './svg.js';
|
|
3
|
+
import {slideArguments,slideSources} from './slide-sources.js';
|
|
3
4
|
import {separateLigatures} from './font-compatibility.js';
|
|
4
5
|
import {monochromeColorFonts,rasterFontFiles} from './color-fonts.js';
|
|
5
6
|
import {pinScriptClusters} from './raster-text.js';
|
|
@@ -7,38 +8,47 @@ import {loadConverter} from './converters.js';
|
|
|
7
8
|
const DEFAULT_DIMENSIONS = { width: 1280, height: 720 };
|
|
8
9
|
const DEFAULT_RASTER_SCALE = 1;
|
|
9
10
|
const DEFAULT_RASTER_BACKGROUND = "#FFFFFF";
|
|
10
|
-
// RR-12: PDF output is vector (selectable text, vector drawing) unless a caller asks for the raster-backed compatibility mode.
|
|
11
|
-
const DEFAULT_PDF_MODE = "vector";
|
|
12
11
|
let bundledFontFilesCache=null;
|
|
13
12
|
|
|
14
|
-
// The faces a raster or PDF conversion draws with
|
|
15
|
-
// whether the bundled base faces are added (`useBundledFonts`, default true; a Node handle already holds its own, so it
|
|
16
|
-
// whether system fonts load (`loadSystemFonts`, default false).
|
|
13
|
+
// The faces a raster or PDF conversion draws with (RR-74: one `fonts`). The fonts handle (`loadFonts()` from `/fonts-node`) gives its
|
|
14
|
+
// `fontFiles`, whether the bundled base faces are added (`useBundledFonts`, default true; a Node handle already holds its own, so it
|
|
15
|
+
// says false) and whether system fonts load (`loadSystemFonts`, default false). Font folders (a path or a list of paths) add every
|
|
16
|
+
// face in them to the bundled base faces. Without either the bundled base faces draw.
|
|
17
17
|
function fontSettings(options) {
|
|
18
18
|
const fonts = options.fonts ?? {};
|
|
19
|
-
return { fontFiles: stringArray(fonts.
|
|
19
|
+
if (typeof fonts === "string" || Array.isArray(fonts)) return { fontFiles: [], fontDirs: stringArray([fonts].flat()), useBundledFonts: true, loadSystemFonts: false };
|
|
20
|
+
return { fontFiles: stringArray(fonts.fontFiles), fontDirs: [], useBundledFonts: fonts.useBundledFonts !== false, loadSystemFonts: fonts.loadSystemFonts === true };
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
24
|
+
* PNG (RR-73): a deck drawn with `toSvg` (`toPng(deck)` gives one PNG per slide, `toPng(deck, 3)` the third slide's PNG,
|
|
25
|
+
* `toPng(deck, "1-3")` those slides'), or SVG the renderer drew (one SVG gives one PNG, a list a list). `fonts` is the handle
|
|
26
|
+
* `loadFonts()` returns, so the preview and the PNG draw with the same faces, or font folders for SVG input. Without either the
|
|
27
|
+
* bundled base faces draw.
|
|
25
28
|
*/
|
|
26
|
-
export async function
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
export async function toPng(source, slides, options) {
|
|
30
|
+
({ slides, options } = slideArguments(slides, options));
|
|
31
|
+
const { svgs, one } = slideSources(source, slides, options, toSvg);
|
|
32
|
+
const pngs = [];
|
|
33
|
+
for (const svg of svgs) pngs.push((await rasterizeSvg(svg, options)).png);
|
|
34
|
+
return one ? pngs[0] : pngs;
|
|
29
35
|
}
|
|
30
36
|
|
|
31
|
-
/**
|
|
32
|
-
|
|
33
|
-
|
|
37
|
+
/**
|
|
38
|
+
* One PDF (RR-73), a page per slide, of a deck drawn with `toSvg` (all slides, or a selection: `toPdf(deck, "2-4")`) or of SVG
|
|
39
|
+
* slides the renderer drew. Vector by default (selectable text in embedded subsets); `raster: true` draws each slide as an image.
|
|
40
|
+
* `fonts` is as for `toPng`.
|
|
41
|
+
*/
|
|
42
|
+
export async function toPdf(source, slides, options) {
|
|
43
|
+
({ slides, options } = slideArguments(slides, options));
|
|
44
|
+
const pdfInputs = slideSources(source, slides, options, toSvg).svgs;
|
|
34
45
|
if (!pdfInputs.length) {
|
|
35
|
-
throw new OPFRenderError("empty-pdf", "
|
|
46
|
+
throw new OPFRenderError("empty-pdf", "toPdf needs at least one slide.");
|
|
36
47
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
throw new OPFRenderError("invalid-conversion-option", 'mode must be "vector" or "raster".', { option: "mode", value: mode });
|
|
48
|
+
if (options.raster !== undefined && typeof options.raster !== "boolean") {
|
|
49
|
+
throw new OPFRenderError("invalid-conversion-option", "raster must be true or false.", { option: "raster", value: options.raster });
|
|
40
50
|
}
|
|
41
|
-
if (
|
|
51
|
+
if (options.raster !== true) return vectorPdf(pdfInputs, options);
|
|
42
52
|
|
|
43
53
|
const { PDFDocument } = await loadPdfLib();
|
|
44
54
|
const pdf = await PDFDocument.create({ updateMetadata: false });
|
|
@@ -65,7 +75,7 @@ export async function svgToPdf(svgs, options = {}) {
|
|
|
65
75
|
async function vectorPdf(inputs, options) {
|
|
66
76
|
const settings = fontSettings(options);
|
|
67
77
|
if (settings.loadSystemFonts) {
|
|
68
|
-
throw new OPFRenderError("pdf-system-fonts-unsupported", 'Vector PDF output embeds only the font files you supply: fonts.loadSystemFonts
|
|
78
|
+
throw new OPFRenderError("pdf-system-fonts-unsupported", 'Vector PDF output embeds only the font files you supply: so fonts.loadSystemFonts does not apply. Pass a fonts handle with fontFiles, or font folders, or use raster: true.', { option: "fonts.loadSystemFonts" });
|
|
69
79
|
}
|
|
70
80
|
const scale = positiveNumber(options.rasterFallbackScale, "rasterFallbackScale", 2);
|
|
71
81
|
const fontFiles = [
|
|
@@ -77,7 +87,7 @@ async function vectorPdf(inputs, options) {
|
|
|
77
87
|
const {svgsToVectorPdf} = await import("./pdf-vector.js");
|
|
78
88
|
return svgsToVectorPdf(svgs, {
|
|
79
89
|
fontFiles,
|
|
80
|
-
fontDirs:
|
|
90
|
+
fontDirs: settings.fontDirs,
|
|
81
91
|
defaultFontFamily: options.defaultFontFamily ?? "Roboto",
|
|
82
92
|
sansSerifFamily: options.sansSerifFamily ?? options.defaultFontFamily ?? "Roboto",
|
|
83
93
|
monospaceFamily: options.monospaceFamily ?? "Roboto Mono",
|
|
@@ -123,7 +133,7 @@ async function rasterizeSvg(svgInput, options) {
|
|
|
123
133
|
const font = {
|
|
124
134
|
loadSystemFonts: settings.loadSystemFonts,
|
|
125
135
|
fontFiles,
|
|
126
|
-
fontDirs:
|
|
136
|
+
fontDirs: settings.fontDirs,
|
|
127
137
|
defaultFontFamily: options.defaultFontFamily ?? "Roboto",
|
|
128
138
|
sansSerifFamily: options.sansSerifFamily ?? options.defaultFontFamily ?? "Roboto",
|
|
129
139
|
monospaceFamily: options.monospaceFamily ?? "Roboto Mono"
|
|
@@ -181,11 +191,6 @@ async function resolveBundledFontFiles() {
|
|
|
181
191
|
return (await loadFonts()).fontFiles;
|
|
182
192
|
}
|
|
183
193
|
|
|
184
|
-
function normalizeSvgList(value) {
|
|
185
|
-
if (Array.isArray(value)) return value;
|
|
186
|
-
return [value];
|
|
187
|
-
}
|
|
188
|
-
|
|
189
194
|
function normalizeSvgInput(value) {
|
|
190
195
|
if (typeof value === "string") return value;
|
|
191
196
|
if (value instanceof Uint8Array) return new TextDecoder().decode(value);
|
package/dist/script-font-pack.js
CHANGED
|
@@ -65,7 +65,7 @@ const UNDRAWN_VALUE = /^(?:https?|data|blob|pkg|file|mailto):\S*$/i;
|
|
|
65
65
|
|
|
66
66
|
// The built-in variables that copy a document value into drawn text: the inline token and the whole-field reference
|
|
67
67
|
// (a logo or photo reference draws a picture, not text).
|
|
68
|
-
const ORGANIZATION_TOKEN = /\{\{\s*organization\.|var:organization\.(?!logo\b)/;
|
|
68
|
+
const ORGANIZATION_TOKEN = /\{\{\s*organization\.|var:organization\.(?!(?:[^.\s]+\.)?logo\b)/;
|
|
69
69
|
const SPEAKER_TOKEN = /\{\{\s*speaker\.|var:speaker\.(?!photo\b|image\b|avatar\b)/;
|
|
70
70
|
const SECTION_TOKEN = /\{\{\s*slide\.section\s*[|}]/;
|
|
71
71
|
|
|
@@ -130,7 +130,7 @@ function scriptOfFamily(family) {
|
|
|
130
130
|
* scheme (`slide.design`), so each such slide is resolved too. `han` is the CJK script the scheme names, which tells
|
|
131
131
|
* Han-only text apart when the language does not (a Yu Gothic deck whose language is English).
|
|
132
132
|
*
|
|
133
|
-
* `renderOptions` are the host's `
|
|
133
|
+
* `renderOptions` are the host's `toSvg` options: their `catalogs` (core `Catalog[]`) go to core's `resolveScriptFonts`
|
|
134
134
|
* unchanged, and the families the renderer resolves per slide count too, so a scheme that exists only in the host's catalogs
|
|
135
135
|
* and names a script font still loads that font.
|
|
136
136
|
*/
|
|
@@ -176,8 +176,8 @@ function* namedFontFamilies(value, key) {
|
|
|
176
176
|
* itemization, so language-dependent punctuation counts), the scripts its font schemes need (`design`, for example
|
|
177
177
|
* Jpan for a Yu Gothic scheme) and the CJK characters that a glyph fallback might have to draw with another CJK face.
|
|
178
178
|
* The text decides, so a document is analyzed without resolving its layouts and catalogs; `renderOptions` (the host's
|
|
179
|
-
* `
|
|
180
|
-
* like the renderer resolves them; a document that then does not resolve throws what `
|
|
179
|
+
* `toSvg` options) matter only for font schemes the host supplies in `renderOptions.catalogs`, which then resolve
|
|
180
|
+
* like the renderer resolves them; a document that then does not resolve throws what `toSvg` throws for it.
|
|
181
181
|
*/
|
|
182
182
|
export function analyzePresentationScripts(presentation, profile, renderOptions) {
|
|
183
183
|
profile ??= presentationScriptProfile(presentation, renderOptions);
|
|
@@ -198,7 +198,7 @@ export function analyzePresentationScripts(presentation, profile, renderOptions)
|
|
|
198
198
|
* (Japanese, Korean, Simplified or Traditional Chinese) and makes curly quotes, dashes and the ellipsis
|
|
199
199
|
* East Asian. Text the preview never draws (ids, alt text, sources, assets, catalogs, notes) is ignored.
|
|
200
200
|
* Greek and Cyrillic add nothing: the office registry always carries Noto Sans (the glyph-fallback face) and Roboto covers them.
|
|
201
|
-
* Pass `profile` to reuse a resolved profile. Other options are the host's `
|
|
201
|
+
* Pass `profile` to reuse a resolved profile. Other options are the host's `toSvg` options (`catalogs`, see `analyzePresentationScripts`).
|
|
202
202
|
*/
|
|
203
203
|
export function detectPresentationScripts(presentation, { profile, ...renderOptions } = {}) {
|
|
204
204
|
return analyzePresentationScripts(presentation, profile, renderOptions).detected;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// RR-73: what `toPng` and `toPdf` draw. They take a deck (an object, or JSON text) and draw it with `toSvg`, or SVG the renderer
|
|
2
|
+
// already drew (a string or bytes starting with `<`, or a list of them). The second argument is a slide selection for a deck (`3`
|
|
3
|
+
// or `"1-3"`, slides counting from 1) or the options, told apart by type, as for `toSvg`.
|
|
4
|
+
import { parseSlideSelection } from "@openpresentation/opf";
|
|
5
|
+
import { OPFRenderError } from "./svg.js";
|
|
6
|
+
|
|
7
|
+
/** The slide numbers (from 1) a selection names: a list of numbers or text such as "1,3-5"; core's parser, with the renderer's error. */
|
|
8
|
+
export function selectSlides(slides, count) {
|
|
9
|
+
try {
|
|
10
|
+
return parseSlideSelection(slides, count, "slides");
|
|
11
|
+
} catch (error) {
|
|
12
|
+
throw new OPFRenderError("invalid-slide-selection", error.message, { option: "slides", slideCount: count, cause: error });
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// The 0.17 option names (RR-73, RR-74): pre-v1 there is no alias, but a call that still passes one fails with the new name.
|
|
17
|
+
const RENAMED = { embedFonts: "text: \"system\" (embedFonts: false)", textAsPaths: "text: \"paths\"", mode: "raster: true (vector is the default)", fontDirs: "fonts: a font folder or a list of them" };
|
|
18
|
+
|
|
19
|
+
/** Throws for an option of 0.17 that 0.18 renamed, naming its replacement. */
|
|
20
|
+
export function rejectRenamedOptions(options, code) {
|
|
21
|
+
for (const name of Object.keys(RENAMED)) {
|
|
22
|
+
if (options?.[name] !== undefined) throw new OPFRenderError(code, `The ${name} option was replaced by ${RENAMED[name]}.`, { option: name });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** `(slides, options)` with the options moved into place when the second argument is the options object. */
|
|
27
|
+
export function slideArguments(slides, options) {
|
|
28
|
+
if (slides !== null && typeof slides === "object" && !Array.isArray(slides)) return { slides: undefined, options: slides };
|
|
29
|
+
return { slides, options: options ?? {} };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const isSvg = (value) => value instanceof Uint8Array || (typeof value === "string" && /^\s*</.test(value));
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The SVG slides to convert, and whether the caller asked for one (a slide number, or one SVG): `draw` is `toSvg`, called with the
|
|
36
|
+
* conversion options for a deck (they carry the fonts handle and the drawing options).
|
|
37
|
+
*/
|
|
38
|
+
export function slideSources(source, slides, options, draw) {
|
|
39
|
+
rejectRenamedOptions(options, "invalid-conversion-option");
|
|
40
|
+
if (Array.isArray(source) || isSvg(source)) {
|
|
41
|
+
if (slides !== undefined) throw new OPFRenderError("invalid-conversion-option", "A slide selection applies to a deck; SVG input is already drawn, so pass the slides you want.", { option: "slides" });
|
|
42
|
+
if (Array.isArray(source) && !source.every(isSvg)) throw new OPFRenderError("invalid-svg-input", "A list must hold SVG slides (strings or bytes starting with <).");
|
|
43
|
+
return { svgs: Array.isArray(source) ? source : [source], one: !Array.isArray(source) };
|
|
44
|
+
}
|
|
45
|
+
const drawn = draw(source, slides, options);
|
|
46
|
+
return typeof drawn === "string" ? { svgs: [drawn], one: true } : { svgs: drawn, one: false };
|
|
47
|
+
}
|