@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/element.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// RR-28: <opf-deck>, a framework-free web component that embeds an OPF deck. It draws the renderer's own SVG (
|
|
1
|
+
// RR-28: <opf-deck>, a framework-free web component that embeds an OPF deck. It draws the renderer's own SVG (toSvg), so
|
|
2
2
|
// the slide a page shows is the slide the preview, the editor and the PDF show. Importing this module touches no DOM, so it
|
|
3
3
|
// is safe on a server (Next.js); `defineOpfDeck()` registers the tag in a browser.
|
|
4
4
|
import {
|
|
@@ -6,8 +6,9 @@ import {
|
|
|
6
6
|
prepareSlideSvg, sanitizeSvgTree, slideInfo, slideLabel, svgDimensions, plainText,
|
|
7
7
|
} from "./deck-runtime.js";
|
|
8
8
|
import { loadPreviewFonts } from "./preview-fonts.js";
|
|
9
|
-
import {
|
|
9
|
+
import { toSvg } from "./svg.js";
|
|
10
10
|
import { drawnFaces } from "./drawn-faces.js";
|
|
11
|
+
import { selectSlides, slideArguments } from "./slide-sources.js";
|
|
11
12
|
|
|
12
13
|
export { DeckError } from "./deck-runtime.js";
|
|
13
14
|
export { loadPreviewFonts, previewBaseFaces, previewFontLayout } from "./preview-fonts.js";
|
|
@@ -140,7 +141,7 @@ function createElementClass() {
|
|
|
140
141
|
if (had && before === this.getAttribute("fonts") && this.isConnected && this.#built) this.#start();
|
|
141
142
|
}
|
|
142
143
|
|
|
143
|
-
/** Extra `
|
|
144
|
+
/** Extra `toSvg` options (catalogs, imageResolver, date, ...). Set before the deck loads, or call `reload()`. */
|
|
144
145
|
get renderOptions() { return this.#renderOptions; }
|
|
145
146
|
set renderOptions(value) { this.#renderOptions = value && typeof value === "object" ? value : {}; }
|
|
146
147
|
|
|
@@ -513,21 +514,22 @@ const escapeHtml = (value) => String(value).replace(/&/g, "&").replace(/</g,
|
|
|
513
514
|
* `/fonts-browser`, or one with a `textMeasurement` and `embeddedFonts`). A `fonts` string is the font root URL written to the
|
|
514
515
|
* element's `fonts` attribute.
|
|
515
516
|
*
|
|
516
|
-
* `
|
|
517
|
-
* `
|
|
517
|
+
* `toHtml(deck)` draws the first slide plus a list of titles; `toHtml(deck, 3)`, `toHtml(deck, "1-3")` (`"1-"` for every slide) or
|
|
518
|
+
* `toHtml(deck, [1, 3])` draw the selected slides of the presented sequence (counting from 1); the second argument may be the
|
|
519
|
+
* options instead, told apart by type (RR-73). `embed` puts the document in an `application/opf+json` script child, so the element upgrades without a request.
|
|
518
520
|
* `fontMode`: `"standalone"` (default, embeds per slide), `"shared"` (one set of font rules in the returned tag), or
|
|
519
521
|
* `"external"` (no font rules; the host must supply CSS with the exact pinned faces the handle measures).
|
|
520
522
|
*/
|
|
521
|
-
export function
|
|
523
|
+
export function toHtml(input, slides, options) {
|
|
524
|
+
({ slides, options } = slideArguments(slides, options));
|
|
522
525
|
const deck = parseDeckDocument(input);
|
|
523
526
|
const tag = options.tagName ?? OPF_DECK_TAG;
|
|
524
527
|
const sequence = presentableIndexes(deck, { includeHidden: options.includeHidden });
|
|
525
|
-
const
|
|
526
|
-
const shown = wanted === "all" ? sequence.map((_, position) => position) : wanted === "first" ? [0] : wanted.map((number) => number - 1).filter((position) => position >= 0 && position < sequence.length);
|
|
528
|
+
const shown = slides === undefined ? [0] : selectSlides(slides, sequence.length).map((number) => number - 1);
|
|
527
529
|
const handle = options.fonts !== null && typeof options.fonts === "object" ? options.fonts : undefined;
|
|
528
530
|
const fontMode = options.fontMode ?? "standalone";
|
|
529
531
|
if (!["standalone", "shared", "external"].includes(fontMode)) throw new DeckError("invalid-font-mode", "Choose standalone, shared or external SSR fonts.");
|
|
530
|
-
// Every mode measures with the same handle; external writes no @font-face data (
|
|
532
|
+
// Every mode measures with the same handle; external writes no @font-face data (`text: "system"`).
|
|
531
533
|
const renderFonts = handle ?? options.renderOptions?.fonts;
|
|
532
534
|
const sharedRules = new Set(), sharedCharacters = new Map();
|
|
533
535
|
const attributes = { src: options.src, slide: options.slide, fonts: handle ? undefined : options.fonts, label: options.label, ...options.attributes };
|
|
@@ -538,11 +540,11 @@ export function renderDeckHtml(input, options = {}) {
|
|
|
538
540
|
const index = sequence[position];
|
|
539
541
|
// Shared rules are deduplicated across slides, so the slides embed whole faces and the shared set is cut below to what
|
|
540
542
|
// every slide draws (RR-65); per-slide subsets would differ and repeat each face once per slide.
|
|
541
|
-
let svg =
|
|
543
|
+
let svg = toSvg(deck, index + 1, { ...options.renderOptions, fonts: renderFonts, ...(fontMode === "external" ? { text: "system" } : {}), ...(fontMode === "shared" ? { subsetFonts: false } : {}), ...(date ? { date } : {}) });
|
|
542
544
|
if (fontMode === "shared") {
|
|
543
545
|
drawnFaces(svg, sharedCharacters);
|
|
544
546
|
svg = svg.replace(/<style>(@font-face[\s\S]*?)<\/style>/g, (_, css) => {
|
|
545
|
-
// These rules are produced by
|
|
547
|
+
// These rules are produced by toSvg after its used-face selection and validation.
|
|
546
548
|
for (const rule of css.split("\n")) sharedRules.add(rule);
|
|
547
549
|
return "";
|
|
548
550
|
});
|
|
@@ -552,7 +554,7 @@ export function renderDeckHtml(input, options = {}) {
|
|
|
552
554
|
const label = slideLabel(slideInfo(deck, index), position + 1, sequence.length);
|
|
553
555
|
return `<figure role="group" aria-roledescription="slide" aria-label="${escapeHtml(label)}" style="margin:0 0 8px">${prepared}</figure>`;
|
|
554
556
|
});
|
|
555
|
-
const titles =
|
|
557
|
+
const titles = slides === undefined && sequence.length > 1
|
|
556
558
|
? `<nav aria-label="Slides"><ol>${sequence.map((index) => `<li>${escapeHtml(slideInfo(deck, index).title)}</li>`).join("")}</ol></nav>` : "";
|
|
557
559
|
const embedded = options.embed ? `<script type="application/opf+json">${JSON.stringify(deck).replace(/</g, "\\u003c").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029")}</script>` : "";
|
|
558
560
|
const subsets = options.renderOptions?.subsetFonts === false ? undefined : renderFonts?.subsets;
|
package/dist/export-browser.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import type { PdfDiagnostic, PdfMetadata,
|
|
1
|
+
import type { PdfDiagnostic, PdfMetadata, SlideSelection, SvgSlide, ToPdfOptions, ToSvgOptions } from "./index.js";
|
|
2
2
|
import type { FontsHandle } from "./fonts.js";
|
|
3
3
|
export type { PdfDiagnostic, PdfMetadata } from "./index.js";
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
/** The options of `toPng` in a browser: the canvas's own, and the `toSvg` options that draw a deck (`fonts` is the browser handle). */
|
|
6
|
+
export interface BrowserToPngOptions extends ToSvgOptions {
|
|
6
7
|
/** Multiplies the SVG's own size (default 1). The result is limited to 40 megapixels. */
|
|
7
8
|
scale?: number;
|
|
8
9
|
/** A CSS colour painted first (default white); `"transparent"` keeps the alpha channel. */
|
|
@@ -10,18 +11,19 @@ export interface BrowserSvgToPngOptions {
|
|
|
10
11
|
signal?: AbortSignal;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
/** The options of `toPdf` in a browser: the PDF's own, and the `toSvg` options that draw a deck. */
|
|
15
|
+
export interface BrowserToPdfOptions extends Omit<ToSvgOptions, "fonts" | "onDiagnostic">, Pick<ToPdfOptions, "raster" | "background" | "serifFamily" | "metadata" | "tagged" | "compress" | "strict" | "rasterFallbackScale" | "defaultFontFamily" | "sansSerifFamily" | "monospaceFamily" | "onDiagnostic"> {
|
|
16
|
+
/** `raster: true`: pixel density of each page image (default 2). */
|
|
15
17
|
scale?: number;
|
|
16
18
|
/**
|
|
17
|
-
*
|
|
18
|
-
* bundle of it holds no PDF library. Without it raster
|
|
19
|
-
* when the page cannot. The default vector
|
|
19
|
+
* `raster: true` only: the pdf-lib module (`import * as pdfLib from "pdf-lib"`), an optional peer of the renderer that this entry never imports itself, so a
|
|
20
|
+
* bundle of it holds no PDF library. Without it a raster PDF tries to import "pdf-lib" by name and rejects with `OPFRenderError` `converter-missing`
|
|
21
|
+
* when the page cannot. The default vector PDF needs no option.
|
|
20
22
|
*/
|
|
21
23
|
pdfLib?: { PDFDocument: { create(options?: { updateMetadata?: boolean }): Promise<any> } };
|
|
22
24
|
/**
|
|
23
|
-
* The browser fonts handle (`loadFonts` from `/fonts-browser`): every face it holds can be embedded in the PDF, including
|
|
24
|
-
* a standalone SVG does not carry. Faces an SVG embeds as `@font-face` data (the `embeddedFonts` of the handle `
|
|
25
|
+
* The browser fonts handle (`loadFonts` from `/fonts-browser`): it draws a deck, and every face it holds can be embedded in the PDF, including
|
|
26
|
+
* script faces a standalone SVG does not carry. Faces an SVG embeds as `@font-face` data (the `embeddedFonts` of the handle `toSvg` was given) need no entry.
|
|
25
27
|
*/
|
|
26
28
|
fonts?: FontsHandle;
|
|
27
29
|
/** Extra font faces as bytes (TrueType outlines) when there is no handle. */
|
|
@@ -32,7 +34,15 @@ export interface BrowserSvgToPdfOptions extends Pick<SvgToPdfOptions, "mode" | "
|
|
|
32
34
|
onProgress?: (progress: { page: number; pages: number }) => void;
|
|
33
35
|
}
|
|
34
36
|
|
|
35
|
-
|
|
36
|
-
export declare function
|
|
37
|
+
/** PNG with a canvas (RR-73): the arguments and results of the Node `toPng`. */
|
|
38
|
+
export declare function toPng(svg: Uint8Array | `<${string}`, options?: BrowserToPngOptions): Promise<Uint8Array>;
|
|
39
|
+
export declare function toPng(svgs: readonly SvgSlide[], options?: BrowserToPngOptions): Promise<Uint8Array[]>;
|
|
40
|
+
export declare function toPng(deck: unknown, slide: number, options?: BrowserToPngOptions): Promise<Uint8Array>;
|
|
41
|
+
export declare function toPng(deck: unknown, slides: Exclude<SlideSelection, number>, options?: BrowserToPngOptions): Promise<Uint8Array[]>;
|
|
42
|
+
export declare function toPng(deck: object, options?: BrowserToPngOptions): Promise<Uint8Array[]>;
|
|
43
|
+
export declare function toPng(source: string, options?: BrowserToPngOptions): Promise<Uint8Array | Uint8Array[]>;
|
|
44
|
+
/** One PDF (RR-73), a page per slide, of a deck drawn with `toSvg` (every slide or a selection) or of SVG slides. */
|
|
45
|
+
export declare function toPdf(source: unknown, options?: BrowserToPdfOptions): Promise<Uint8Array>;
|
|
46
|
+
export declare function toPdf(deck: unknown, slides: SlideSelection, options?: BrowserToPdfOptions): Promise<Uint8Array>;
|
|
37
47
|
/** Format of an embedded picture and, for a JPEG, its size, component count and EXIF orientation. */
|
|
38
48
|
export declare function sniffImage(bytes: Uint8Array): { format: "png" | "webp" | "gif" | "jpeg" | undefined; width?: number; height?: number; channels?: number; orientation?: number; space?: string };
|
package/dist/export-browser.js
CHANGED
|
@@ -1,22 +1,35 @@
|
|
|
1
1
|
import { svgsToVectorPdf } from "./pdf-vector.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
|
|
|
4
|
-
// RR-23: PNG and PDF output in a browser. `
|
|
5
|
+
// RR-23: PNG and PDF output in a browser. `toPng` and `toPdf` of the root entry need Node (resvg, sharp); this entry
|
|
5
6
|
// has the same two names for a page. It uses the same vector PDF converter as Node (fontkit, bidi-js and pako, all pure
|
|
6
7
|
// JavaScript) over the SVG the preview draws, so the text stays real text in the same embedded subsets. What differs from
|
|
7
8
|
// Node is only how pixels are made: a canvas decodes pictures and draws PNGs. No system font is read (a browser has no way
|
|
8
9
|
// to hand one over) and nothing is fetched: faces come from the SVG's own @font-face data (the `embeddedFonts` of the fonts handle
|
|
9
|
-
// `
|
|
10
|
+
// `toSvg` was given), from the faces the `fonts` handle holds (`loadFonts` from `/fonts-browser`, so script faces the SVG does not
|
|
10
11
|
// embed reach the PDF too), or from `fontData`.
|
|
11
12
|
//
|
|
12
|
-
// RR-63: this entry imports no converter. The one optional piece is pdf-lib, for `
|
|
13
|
+
// RR-63: this entry imports no converter. The one optional piece is pdf-lib, for `raster: true` only (the default vector PDF
|
|
13
14
|
// needs nothing): the host imports it and passes it as `options.pdfLib`, so a bundler never has to resolve it.
|
|
14
15
|
|
|
15
16
|
const DEFAULT_DIMENSIONS = { width: 1280, height: 720 };
|
|
16
17
|
const MAX_PIXELS = 40_000_000;
|
|
17
18
|
|
|
18
|
-
/**
|
|
19
|
-
|
|
19
|
+
/**
|
|
20
|
+
* PNG with a canvas (RR-73): a deck drawn with `toSvg` (all slides, a slide number or a selection, as for the Node `toPng`) or SVG
|
|
21
|
+
* the renderer drew; one PNG for a slide number or one SVG, a list otherwise. `scale` multiplies the SVG's own size; `background`
|
|
22
|
+
* is a CSS colour (default white, `"transparent"` for none).
|
|
23
|
+
*/
|
|
24
|
+
export async function toPng(source, slides, options) {
|
|
25
|
+
({ slides, options } = slideArguments(slides, options));
|
|
26
|
+
const { svgs, one } = slideSources(source, slides, options, toSvg);
|
|
27
|
+
const pngs = [];
|
|
28
|
+
for (const svg of svgs) pngs.push(await svgPng(svg, options));
|
|
29
|
+
return one ? pngs[0] : pngs;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function svgPng(svg, options = {}) {
|
|
20
33
|
const text = svgText(svg);
|
|
21
34
|
const size = pageSize(text);
|
|
22
35
|
const scale = positive(options.scale, "scale", 1);
|
|
@@ -32,19 +45,19 @@ export async function svgToPng(svg, options = {}) {
|
|
|
32
45
|
}
|
|
33
46
|
|
|
34
47
|
/**
|
|
35
|
-
*
|
|
36
|
-
* real text, paths, gradients and images; `
|
|
37
|
-
* the Node `
|
|
38
|
-
* names, `rasterFallbackScale`), `pdfLib` (raster
|
|
48
|
+
* One PDF (RR-73) of a deck drawn with `toSvg` (all slides or a selection) or of SVG slides, one slide per page (1 SVG pixel is 1
|
|
49
|
+
* PDF point, as in Node). Vector by default (real text, paths, gradients and images); `raster: true` draws each slide as an image
|
|
50
|
+
* (`scale`, default 2). Takes the options of the Node `toPdf` that make sense here (`metadata`, `tagged`, `strict`, `compress`,
|
|
51
|
+
* `onDiagnostic`, the generic family names, `rasterFallbackScale`), `pdfLib` (`raster: true` only: `import * as pdfLib from "pdf-lib"`), `fonts` (the handle `loadFonts()` returns: every face it holds can be embedded), `fontData`
|
|
39
52
|
* (`[{ data, family? }]`, extra face bytes without a handle), `signal` (an AbortSignal, checked between pages) and
|
|
40
53
|
* `onProgress({ page, pages })`.
|
|
41
54
|
*/
|
|
42
|
-
export async function
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (
|
|
47
|
-
if (
|
|
55
|
+
export async function toPdf(source, slides, options) {
|
|
56
|
+
({ slides, options } = slideArguments(slides, options));
|
|
57
|
+
const inputs = slideSources(source, slides, options, toSvg).svgs.map(svgText);
|
|
58
|
+
if (!inputs.length) throw new OPFRenderError("empty-pdf", "toPdf needs at least one slide.");
|
|
59
|
+
if (options.raster !== undefined && typeof options.raster !== "boolean") throw new OPFRenderError("invalid-conversion-option", "raster must be true or false.", { option: "raster", value: options.raster });
|
|
60
|
+
if (options.raster === true) return rasterPdf(inputs, options);
|
|
48
61
|
const scale = positive(options.rasterFallbackScale, "rasterFallbackScale", 2);
|
|
49
62
|
const fontCss = fontFaceCss(inputs);
|
|
50
63
|
return svgsToVectorPdf(inputs, {
|
|
@@ -68,7 +81,7 @@ export async function svgToPdf(svgs, options = {}) {
|
|
|
68
81
|
producer: packageName,
|
|
69
82
|
ErrorClass: OPFRenderError,
|
|
70
83
|
// The element's own text has no fonts in a standalone SVG image: give it the faces the slides embed.
|
|
71
|
-
rasterize: async (svg, factor) => ({ png: await
|
|
84
|
+
rasterize: async (svg, factor) => ({ png: await svgPng(fontCss && /<text[\s>]/.test(svg) ? svg.replace(/(<svg\b[^>]*>)/, `$1<style>${fontCss}</style>`) : svg, { scale: factor, background: "transparent", signal: options.signal }) }),
|
|
72
85
|
});
|
|
73
86
|
}
|
|
74
87
|
|
|
@@ -81,7 +94,7 @@ async function rasterPdf(inputs, options) {
|
|
|
81
94
|
for (const [index, svg] of inputs.entries()) {
|
|
82
95
|
options.signal?.throwIfAborted?.();
|
|
83
96
|
const size = pageSize(svg);
|
|
84
|
-
const png = await
|
|
97
|
+
const png = await svgPng(svg, { scale, background: options.background ?? "#FFFFFF", signal: options.signal });
|
|
85
98
|
const image = await pdf.embedPng(png);
|
|
86
99
|
pdf.addPage([size.width, size.height]).drawImage(image, { x: 0, y: 0, width: size.width, height: size.height });
|
|
87
100
|
options.onProgress?.({ page: index + 1, pages: inputs.length });
|
|
@@ -90,14 +103,14 @@ async function rasterPdf(inputs, options) {
|
|
|
90
103
|
return pdf.save({ addDefaultPage: false, useObjectStreams: false });
|
|
91
104
|
}
|
|
92
105
|
|
|
93
|
-
// pdf-lib for raster
|
|
106
|
+
// pdf-lib for `raster: true` when the host did not pass it. The specifier is not a literal, so a browser bundler leaves it alone (and
|
|
94
107
|
// never fails for a host that does not install pdf-lib); it resolves where the page can import it by name, for example with an import map.
|
|
95
108
|
async function importPdfLib() {
|
|
96
109
|
const name = "pdf-lib";
|
|
97
110
|
try {
|
|
98
111
|
return await import(/* webpackIgnore: true */ /* @vite-ignore */ name);
|
|
99
112
|
} catch (error) {
|
|
100
|
-
throw new OPFRenderError("converter-missing", '
|
|
113
|
+
throw new OPFRenderError("converter-missing", 'A raster PDF (raster: true) needs pdf-lib, an optional peer dependency of @openpresentation/opf-render: run `npm install pdf-lib@^1.17.1` and pass it as the pdfLib option (import * as pdfLib from "pdf-lib"). The default vector PDF needs nothing.', { package: "pdf-lib", range: "^1.17.1", install: "npm install pdf-lib@^1.17.1", cause: error instanceof Error ? error.message : String(error) });
|
|
101
114
|
}
|
|
102
115
|
}
|
|
103
116
|
|
package/dist/font-subset.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// `harfbuzz-subset.wasm` of the pinned harfbuzzjs package, MIT) keeps the glyphs a slide's characters reach through the
|
|
3
3
|
// font's layout tables (every GSUB and GPOS feature is kept, so the browser shapes the subset exactly as the whole face),
|
|
4
4
|
// renumbers them and trims cmap, hmtx, GPOS and the rest to them. The module has no imports, so it is instantiated
|
|
5
|
-
// synchronously from its bytes and `
|
|
5
|
+
// synchronously from its bytes and `toSvg` stays synchronous; the same input always gives the same bytes.
|
|
6
6
|
//
|
|
7
7
|
// Only a face whose license allows it is subset: a bundled face (matched by the sha256 of its bytes against the pinned
|
|
8
8
|
// manifest) under an allowed license, whose family and file names do not contain one of its package's Reserved Font Names
|
package/dist/fonts-browser.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type {
|
|
|
6
6
|
FontsHandle,
|
|
7
7
|
} from "./fonts.js";
|
|
8
8
|
import type { AutoScriptSelection, BundledFontPackage, LazyFont, ScriptSelection } from "./fonts-node.js";
|
|
9
|
-
import type {
|
|
9
|
+
import type { ToSvgOptions } from "./svg.js";
|
|
10
10
|
export type { LazyFont } from "./fonts-node.js";
|
|
11
11
|
export type { AutoScriptSelection } from "./fonts-node.js";
|
|
12
12
|
export { detectPresentationScripts, autoScriptSelection } from "./fonts-node.js";
|
|
@@ -26,17 +26,17 @@ export interface BrowserFontRegistry extends FontRegistry {
|
|
|
26
26
|
* family the policy would not resolve, nor for a weight or style nothing draws), once each, from `lazyFontsBaseUrl`.
|
|
27
27
|
* Fetches and verifies every file, then adds the faces to the document and the registry together; on failure nothing
|
|
28
28
|
* changes and the call can be retried. Call it before measuring a document, and again after edits: an edit that adds a
|
|
29
|
-
* bold or italic run loads just that face. Besides `signal`, the call takes the `
|
|
29
|
+
* bold or italic run loads just that face. Besides `signal`, the call takes the `toSvg` options the document resolves
|
|
30
30
|
* with (`catalogs`, ...) over the loader's `renderOptions`. A document that does not resolve rejects with the error
|
|
31
|
-
* `
|
|
31
|
+
* `toSvg` throws for it. After `dispose()` it rejects with `font-registry-disposed`.
|
|
32
32
|
*/
|
|
33
|
-
ensureLazyFonts(presentation: unknown, options?: { signal?: AbortSignal } & Partial<
|
|
33
|
+
ensureLazyFonts(presentation: unknown, options?: { signal?: AbortSignal } & Partial<ToSvgOptions>): Promise<LazyFont[]>;
|
|
34
34
|
/**
|
|
35
35
|
* Synchronous: the vendored faces the presentation draws under the registry's policy that are not loaded yet. Empty means
|
|
36
|
-
* `ensureLazyFonts` fetches nothing. `renderOptions` are the `
|
|
37
|
-
* over the loader's `renderOptions`. Throws what `
|
|
36
|
+
* `ensureLazyFonts` fetches nothing. `renderOptions` are the `toSvg` options the document resolves with (`catalogs`, ...)
|
|
37
|
+
* over the loader's `renderOptions`. Throws what `toSvg` throws for a document that does not resolve.
|
|
38
38
|
*/
|
|
39
|
-
pendingLazyFonts(presentation: unknown, renderOptions?: Partial<
|
|
39
|
+
pendingLazyFonts(presentation: unknown, renderOptions?: Partial<ToSvgOptions>): LazyFont[];
|
|
40
40
|
|
|
41
41
|
/** Load script faces for ISO 15924 codes (or "all") from `scriptBaseUrl`. Resolves with the newly loaded package names. */
|
|
42
42
|
loadScripts(scripts: ScriptSelection, options?: { signal?: AbortSignal }): Promise<string[]>;
|
|
@@ -49,15 +49,15 @@ export interface BrowserFontRegistry extends FontRegistry {
|
|
|
49
49
|
* OPFFontError whose `details` are `{ loaded: string[]; failed: {package, code, message}[] }`. A failed call (fetch, hash, FontFace load) leaves nothing loaded and can be retried; after
|
|
50
50
|
* `dispose()` it rejects with `font-registry-disposed`.
|
|
51
51
|
*/
|
|
52
|
-
ensureScripts(presentation: unknown, options?: { signal?: AbortSignal } & Partial<
|
|
52
|
+
ensureScripts(presentation: unknown, options?: { signal?: AbortSignal } & Partial<ToSvgOptions>): Promise<AutoScriptSelection & { loaded: string[]; uncovered: string[] }>;
|
|
53
53
|
/** Synchronous: package names the presentation needs that are not loaded yet. Empty means `ensureScripts` fetches nothing, so a host can render immediately. Text decides, so a document is analyzed without resolving its layouts; `renderOptions.catalogs` matter for font schemes only the host's catalogs have (FF-41). */
|
|
54
|
-
pendingScripts(presentation: unknown, renderOptions?: Partial<
|
|
54
|
+
pendingScripts(presentation: unknown, renderOptions?: Partial<ToSvgOptions>): string[];
|
|
55
55
|
/** Names of the script-pack packages loaded so far. */
|
|
56
56
|
readonly loadedScriptPackages: string[];
|
|
57
57
|
}
|
|
58
58
|
/**
|
|
59
59
|
* The fonts handle of a browser: the faces you list, registered with the document, and on demand the script and vendored faces a deck
|
|
60
|
-
* draws. Pass it as `{ fonts }` to `
|
|
60
|
+
* draws. Pass it as `{ fonts }` to `toSvg`, `<opf-deck>` and the player, core `paginate` and `validate`, and the editor.
|
|
61
61
|
* The registry behind it keeps the lower-level loaders (`ensureLazyFonts`, `ensureScripts`, `loadScripts`, `pendingLazyFonts`, `pendingScripts`).
|
|
62
62
|
*/
|
|
63
63
|
export interface BrowserFontsHandle extends FontsHandle {
|
|
@@ -66,13 +66,13 @@ export interface BrowserFontsHandle extends FontsHandle {
|
|
|
66
66
|
dispose(): void;
|
|
67
67
|
/**
|
|
68
68
|
* Load the vendored and script faces the presentation draws (each hash-verified, all or nothing), repeating while loading changes what
|
|
69
|
-
* is needed. Cheap when nothing is needed. Besides `signal`, the call takes the `
|
|
70
|
-
* (`catalogs`, ...) over the loader's `renderOptions`. A document that does not resolve rejects with what `
|
|
69
|
+
* is needed. Cheap when nothing is needed. Besides `signal`, the call takes the `toSvg` options the document resolves with
|
|
70
|
+
* (`catalogs`, ...) over the loader's `renderOptions`. A document that does not resolve rejects with what `toSvg` throws for it; after
|
|
71
71
|
* `dispose()` it rejects with `font-registry-disposed`.
|
|
72
72
|
*/
|
|
73
|
-
ensure(presentation: unknown, options?: { signal?: AbortSignal } & Partial<
|
|
74
|
-
/** Synchronous: the vendored files and script packages `ensure` would fetch. Empty means a render can start now. Throws what `
|
|
75
|
-
pending(presentation: unknown, renderOptions?: Partial<
|
|
73
|
+
ensure(presentation: unknown, options?: { signal?: AbortSignal } & Partial<ToSvgOptions>): Promise<EnsureResult>;
|
|
74
|
+
/** Synchronous: the vendored files and script packages `ensure` would fetch. Empty means a render can start now. Throws what `toSvg` throws for a document that does not resolve. */
|
|
75
|
+
pending(presentation: unknown, renderOptions?: Partial<ToSvgOptions>): string[];
|
|
76
76
|
}
|
|
77
77
|
export declare function loadFonts(
|
|
78
78
|
options?: FontRegistryOptions & {
|
|
@@ -83,12 +83,12 @@ export declare function loadFonts(
|
|
|
83
83
|
signal?: AbortSignal;
|
|
84
84
|
/**
|
|
85
85
|
* RR-65: harfbuzzjs's `harfbuzz-subset.wasm` (the URL the host serves it from, its bytes or a compiled WebAssembly.Module). With
|
|
86
|
-
* it the handle carries `subsets`, and every SVG `
|
|
86
|
+
* it the handle carries `subsets`, and every SVG `toSvg` draws with this handle embeds each face cut to the characters the
|
|
87
87
|
* slide draws. Without it a browser handle embeds whole faces (the Node handle always subsets).
|
|
88
88
|
*/
|
|
89
89
|
subsetWasm?: string | URL | ArrayBuffer | ArrayBufferView | WebAssembly.Module;
|
|
90
90
|
/**
|
|
91
|
-
* RR-64: harfbuzzjs's `harfbuzz.wasm` (its URL, bytes or a compiled WebAssembly.Module). With it `
|
|
91
|
+
* RR-64: harfbuzzjs's `harfbuzz.wasm` (its URL, bytes or a compiled WebAssembly.Module). With it `text: "paths"` shapes outlines with
|
|
92
92
|
* HarfBuzz, as the browser shapes text; without it a browser handle shapes them with fontkit (the Node handle always uses HarfBuzz).
|
|
93
93
|
*/
|
|
94
94
|
shapeWasm?: string | URL | ArrayBuffer | ArrayBufferView | WebAssembly.Module;
|
|
@@ -111,11 +111,11 @@ export declare function loadFonts(
|
|
|
111
111
|
*/
|
|
112
112
|
extraLazyFonts?: readonly ExtraLazyFont[];
|
|
113
113
|
/**
|
|
114
|
-
* FF-41: the `
|
|
114
|
+
* FF-41: the `toSvg` options the documents resolve with (`catalogs` above all), the default for `pendingLazyFonts`,
|
|
115
115
|
* `ensureLazyFonts`, `pendingScripts` and `ensureScripts`. A layout or font scheme id that only the host's catalogs have
|
|
116
116
|
* resolves the same way here as it does when the host renders. A call's own options win.
|
|
117
117
|
*/
|
|
118
|
-
renderOptions?: Partial<
|
|
118
|
+
renderOptions?: Partial<ToSvgOptions>;
|
|
119
119
|
},
|
|
120
120
|
): Promise<BrowserFontsHandle>;
|
|
121
121
|
export declare function scriptFontPackages(scripts: ScriptSelection): BundledFontPackage[];
|
|
@@ -138,10 +138,10 @@ export interface ExtraLazyFont { family: string; weight: number; italic?: boolea
|
|
|
138
138
|
export declare function splitStartupFaces<T extends { family: string; weight: number; italic?: boolean }>(faces: readonly T[], options?: { startup?: (face: T) => boolean }): { startup: T[]; rest: T[] };
|
|
139
139
|
/**
|
|
140
140
|
* The font families a presentation's slides resolve (heading, body and code roles of every slide). `options` are the
|
|
141
|
-
* `
|
|
141
|
+
* `toSvg` options the document resolves with (`catalogs`, ...). A document that does not resolve throws what `toSvg`
|
|
142
142
|
* throws for it (FF-41: it no longer returns an empty set). This is the role families, not what is drawn: see `presentationFaces`.
|
|
143
143
|
*/
|
|
144
|
-
export declare function presentationFamilies(presentation: unknown, options?: Partial<
|
|
144
|
+
export declare function presentationFamilies(presentation: unknown, options?: Partial<ToSvgOptions>): Set<string>;
|
|
145
145
|
/** A face request or a drawn face: a family, a weight and a style. */
|
|
146
146
|
export interface FaceRequest { family: string; weight: number; italic: boolean }
|
|
147
147
|
/**
|
|
@@ -151,16 +151,16 @@ export interface FaceRequest { family: string; weight: number; italic: boolean }
|
|
|
151
151
|
* faces are the styles as the document names them. With `registry` (`{faces, policy, aliases, fallbackFamily}`: the faces a
|
|
152
152
|
* registry holds or could hold and its substitution options) every style resolves as that registry resolves it, in the two
|
|
153
153
|
* steps drawing takes (role family, then weight within it), and the result is the faces the registry paints.
|
|
154
|
-
* `options` are the `
|
|
154
|
+
* `options` are the `toSvg` options the document resolves with; a document that does not resolve throws what `toSvg`
|
|
155
155
|
* throws for it.
|
|
156
156
|
*/
|
|
157
|
-
export declare function presentationFaces(presentation: unknown, options?: Partial<
|
|
157
|
+
export declare function presentationFaces(presentation: unknown, options?: Partial<ToSvgOptions>, registry?: { faces: Iterable<FaceRequest>; policy?: "none" | "metric" | "visual"; aliases?: ReadonlyMap<string, string>; fallbackFamily?: string }): FaceRequest[];
|
|
158
158
|
/**
|
|
159
159
|
* The vendored faces (of `lazy`) a presentation draws that the registry does not hold. `held` is `registry.describeFaces()`,
|
|
160
160
|
* `loaded` the lazy files already loaded; `policy`, `aliases` and `fallbackFamily` are the registry's. Face level: only the
|
|
161
161
|
* drawn faces, so an edit adding a bold run adds one face.
|
|
162
162
|
*/
|
|
163
|
-
export declare function lazyFacesNeeded(presentation: unknown, renderOptions: Partial<
|
|
163
|
+
export declare function lazyFacesNeeded(presentation: unknown, renderOptions: Partial<ToSvgOptions> | undefined, context: { lazy: readonly LazyFont[]; held: Iterable<FaceRequest>; loaded?: ReadonlySet<string>; policy?: "none" | "metric" | "visual"; aliases?: ReadonlyMap<string, string>; fallbackFamily?: string }): LazyFont[];
|
|
164
164
|
/**
|
|
165
165
|
* The vendored faces a list of requests needs that the registry does not hold, following the registry's own order and
|
|
166
166
|
* `policy` (default "visual"): the family itself, an alias target, the declared replacement, then its alternates.
|
package/dist/fonts-browser.js
CHANGED
|
@@ -97,7 +97,7 @@ async function loadRegistry(entries, options = {}) {
|
|
|
97
97
|
// Script faces (FF-19) are loaded lazily, once a document needs them, and only for the scripts it uses.
|
|
98
98
|
const scriptPackages = new Set();
|
|
99
99
|
let queue = Promise.resolve(), disposed = false;
|
|
100
|
-
// FF-41: the `
|
|
100
|
+
// FF-41: the `toSvg` options a document resolves with (`catalogs`, ...). `options.renderOptions` are the defaults; a call's own
|
|
101
101
|
// options (everything but `signal`) are added over them, so a host that passes its canvas options gets the same resolution here.
|
|
102
102
|
const renderOptionsFor = (callOptions) => { const { signal: _signal, ...own } = callOptions ?? {}; return { ...options.renderOptions, ...own }; };
|
|
103
103
|
const gone = () => new OPFFontError("font-registry-disposed", "The font registry was disposed.");
|
|
@@ -151,7 +151,7 @@ async function loadRegistry(entries, options = {}) {
|
|
|
151
151
|
* fallback needs for characters the loaded faces lack. Cheap when nothing new is needed; call it after edits and
|
|
152
152
|
* render again afterwards. Resolves with the detected scripts, the packages loaded by this call, the scripts no
|
|
153
153
|
* pinned font serves and `uncovered`, drawn CJK characters no loaded face covers (the renderer reports
|
|
154
|
-
* `missing-glyph` for them). Besides `signal`, the call takes the `
|
|
154
|
+
* `missing-glyph` for them). Besides `signal`, the call takes the `toSvg` options the document resolves with
|
|
155
155
|
* (`catalogs`, ...) over the loader's `renderOptions`. Each package loads all or nothing. If some package fails, the others still load: the
|
|
156
156
|
* call then rejects with an OPFFontError (the first failure's code) whose `details` hold `loaded` (packages this
|
|
157
157
|
* call did load) and `failed` (`{package, code, message}` per failed package); nothing is lost and a later call
|
|
@@ -176,7 +176,7 @@ async function loadRegistry(entries, options = {}) {
|
|
|
176
176
|
}
|
|
177
177
|
return { ...selection, loaded: loadedNow, uncovered: uncoveredCjkCharacters(analysis, { covers }) };
|
|
178
178
|
},
|
|
179
|
-
/** Synchronous: script-pack packages the presentation needs that are not loaded yet. Empty means `ensureScripts` would fetch nothing. `renderOptions` are the `
|
|
179
|
+
/** Synchronous: script-pack packages the presentation needs that are not loaded yet. Empty means `ensureScripts` would fetch nothing. `renderOptions` are the `toSvg` options the document resolves with (`catalogs`, ...). */
|
|
180
180
|
pendingScripts(presentation, renderOptions) {
|
|
181
181
|
const analysis = analyzePresentationScripts(presentation, undefined, renderOptionsFor(renderOptions));
|
|
182
182
|
const primary = scriptFontPackages(scriptSelectionOf(analysis).scripts).map((item) => item.name).filter((name) => !scriptPackages.has(name));
|
|
@@ -194,7 +194,7 @@ async function loadRegistry(entries, options = {}) {
|
|
|
194
194
|
const policy = options.substitutionPolicy ?? "none";
|
|
195
195
|
const aliasTargets = new Map(Object.entries(options.aliases ?? {}).map(([from, to]) => [from.toLowerCase(), to]));
|
|
196
196
|
// Face level (FF-41): the faces the document draws, resolved as the registry resolves them with every vendored face loaded.
|
|
197
|
-
// A document that does not resolve throws what `
|
|
197
|
+
// A document that does not resolve throws what `toSvg` throws for it.
|
|
198
198
|
const neededLazy = (presentation, callOptions) => lazyFacesNeeded(presentation, renderOptionsFor(callOptions), { lazy, held: registry.describeFaces(), loaded: lazyLoaded, policy, aliases: aliasTargets, fallbackFamily: options.fallbackFamily });
|
|
199
199
|
const lazyBaseUrl = () => {
|
|
200
200
|
if (typeof options.lazyFontsBaseUrl !== "string" || !options.lazyFontsBaseUrl)
|
|
@@ -210,8 +210,8 @@ async function loadRegistry(entries, options = {}) {
|
|
|
210
210
|
* policy (nothing is downloaded for a family the policy would not resolve), once each. All or nothing: on any failure
|
|
211
211
|
* (fetch, hash, FontFace.load, registry) the document and registry are unchanged and the call can be retried. Cheap when
|
|
212
212
|
* nothing is needed. Call it before measuring a document, and again after edits that change fonts. Resolves with the faces
|
|
213
|
-
* added. Besides `signal`, the call takes the `
|
|
214
|
-
* loader's `renderOptions`; a document that does not resolve rejects with what `
|
|
213
|
+
* added. Besides `signal`, the call takes the `toSvg` options the document resolves with (`catalogs`, ...) over the
|
|
214
|
+
* loader's `renderOptions`; a document that does not resolve rejects with what `toSvg` throws for it.
|
|
215
215
|
*/
|
|
216
216
|
ensureLazyFonts(presentation, callOptions = {}) {
|
|
217
217
|
const result = queue.then(async () => {
|
|
@@ -247,7 +247,7 @@ async function loadRegistry(entries, options = {}) {
|
|
|
247
247
|
queue = result.catch(() => {});
|
|
248
248
|
return result;
|
|
249
249
|
},
|
|
250
|
-
/** Synchronous: the vendored faces the presentation draws under the registry's policy that are not loaded yet. Empty means `ensureLazyFonts` fetches nothing. `renderOptions` are the `
|
|
250
|
+
/** Synchronous: the vendored faces the presentation draws under the registry's policy that are not loaded yet. Empty means `ensureLazyFonts` fetches nothing. `renderOptions` are the `toSvg` options the document resolves with (`catalogs`, ...). */
|
|
251
251
|
pendingLazyFonts: (presentation, renderOptions) => neededLazy(presentation, renderOptions),
|
|
252
252
|
});
|
|
253
253
|
/** Names of the script-pack packages loaded so far. */
|
|
@@ -277,7 +277,7 @@ const MAX_ENSURE_ROUNDS = 4;
|
|
|
277
277
|
/**
|
|
278
278
|
* The fonts handle for a browser: the faces you list (`faces`, each `{ url | data, family, weight, italic, sha256 }`, fetched and
|
|
279
279
|
* hash-verified, then registered with the document) and, on demand, the script and vendored faces a deck draws. Pass it as `{ fonts }` to
|
|
280
|
-
* `
|
|
280
|
+
* `toSvg`, `<opf-deck>` and the player, core `paginate` and `validate`, and the editor. `scripts`, `scriptBaseUrl`,
|
|
281
281
|
* `lazyFontsBaseUrl`, `extraLazyFonts`, `renderOptions`, `signal`, `document`, `fetch`, `crypto` and the registry options
|
|
282
282
|
* (`substitutionPolicy`, `aliases`, `fallbackFamily`, `themeFonts`, `strictGlyphs`) are as for the registry (see `fonts-browser.d.ts`).
|
|
283
283
|
* `dispose()` removes every face from the document.
|
|
@@ -320,7 +320,7 @@ export async function loadFonts({ faces = [], subsetWasm, shapeWasm, ...options
|
|
|
320
320
|
textMeasurement: registry.textMeasurement,
|
|
321
321
|
get embeddedFonts() { if (stale) { embedded = registry.embeddedFonts; stale = false; } return embedded; },
|
|
322
322
|
registry,
|
|
323
|
-
// RR-64: the outline engine `
|
|
323
|
+
// RR-64: the outline engine `toSvg(deck, { fonts, text: "paths" })` draws text with, over this registry's faces.
|
|
324
324
|
outlines: textOutlines({ registry, shaper }),
|
|
325
325
|
// RR-65: with `subsetWasm`, the subset engine that cuts each face an SVG embeds to the characters the slide draws.
|
|
326
326
|
...(subsetter ? { subsets: fontSubsets(registry, subsetter) } : {}),
|
|
@@ -329,8 +329,8 @@ export async function loadFonts({ faces = [], subsetWasm, shapeWasm, ...options
|
|
|
329
329
|
/**
|
|
330
330
|
* Load the vendored and script faces the presentation draws, each hash-verified, all or nothing, and repeat while loading
|
|
331
331
|
* changes what is needed (a script face can need a vendored one). Cheap when nothing is needed. Besides `signal`, the call
|
|
332
|
-
* takes the `
|
|
333
|
-
* does not resolve rejects with what `
|
|
332
|
+
* takes the `toSvg` options the document resolves with (`catalogs`, ...) over the loader's `renderOptions`. A document that
|
|
333
|
+
* does not resolve rejects with what `toSvg` throws for it. After `dispose()` it rejects with `font-registry-disposed`.
|
|
334
334
|
*/
|
|
335
335
|
async ensure(presentation, callOptions = {}) {
|
|
336
336
|
const lazy = [], scripts = [];
|
|
@@ -344,7 +344,7 @@ export async function loadFonts({ faces = [], subsetWasm, shapeWasm, ...options
|
|
|
344
344
|
}
|
|
345
345
|
return { scripts, lazy, uncovered };
|
|
346
346
|
},
|
|
347
|
-
/** Synchronous: the files and script packages `ensure` would fetch. Empty means a render can start now. Throws what `
|
|
347
|
+
/** Synchronous: the files and script packages `ensure` would fetch. Empty means a render can start now. Throws what `toSvg` throws for a document that does not resolve. */
|
|
348
348
|
pending,
|
|
349
349
|
dispose: () => registry.dispose(),
|
|
350
350
|
};
|
package/dist/fonts-node.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type {FontRegistry,FontRegistryOptions,FontFaceInput,FontsHandle,EnsureResult,ScriptFontProfile} from "./fonts.js";
|
|
2
|
-
import type {
|
|
2
|
+
import type {ToSvgOptions} from "./svg.js";
|
|
3
3
|
/** A caller-supplied face (FF-31), for example a licensed copy of the real font. Node callers may pass a file path. */
|
|
4
4
|
export type CallerFontFace = FontFaceInput | (Omit<FontFaceInput, "data"> & {path: string});
|
|
5
5
|
/** "all" or ISO 15924 codes (`Jpan`, `Hans`, `Hant`, `Kore`, `Arab`, `Hebr`, `Deva`, `Thai`, ...). */
|
|
@@ -16,9 +16,9 @@ export interface AutoScriptSelection {
|
|
|
16
16
|
/** Script-pack packages that `scripts: "auto"` loaded or found not installed. */
|
|
17
17
|
export interface AppliedScriptSelection extends AutoScriptSelection { packages: string[]; notInstalled: string[]; /** Drawn CJK characters no loaded face covers (glyph fallback stopped at its cap). */ uncovered?: string[] }
|
|
18
18
|
/** Script keys whose faces a preview of the presentation needs: text decides, the document language only tells Han scripts apart. */
|
|
19
|
-
/** `options` may also carry the `
|
|
20
|
-
export declare function detectPresentationScripts(presentation: unknown, options?: { profile?: ScriptFontProfile } & Partial<
|
|
21
|
-
export declare function autoScriptSelection(presentation: unknown, options?: { profile?: ScriptFontProfile } & Partial<
|
|
19
|
+
/** `options` may also carry the `toSvg` options the document resolves with (`catalogs`): a font scheme that exists only in the host's catalogs and names a script font selects that font's script (FF-41). */
|
|
20
|
+
export declare function detectPresentationScripts(presentation: unknown, options?: { profile?: ScriptFontProfile } & Partial<ToSvgOptions>): string[];
|
|
21
|
+
export declare function autoScriptSelection(presentation: unknown, options?: { profile?: ScriptFontProfile } & Partial<ToSvgOptions>): AutoScriptSelection;
|
|
22
22
|
export interface ScriptPackOptions {
|
|
23
23
|
/** Caller-supplied faces, loaded first so a licensed real font resolves as an exact face (FF-31). */
|
|
24
24
|
faces?: readonly CallerFontFace[];
|
|
@@ -30,8 +30,8 @@ export interface ScriptPackOptions {
|
|
|
30
30
|
scripts?: ScriptSelection | "auto";
|
|
31
31
|
/** The presentation whose text decides `scripts: "auto"`. */
|
|
32
32
|
presentation?: unknown;
|
|
33
|
-
/** The `
|
|
34
|
-
renderOptions?: Partial<
|
|
33
|
+
/** The `toSvg` options the presentation resolves with (`catalogs`, ...), for the font schemes `scripts: "auto"` reads (FF-41). */
|
|
34
|
+
renderOptions?: Partial<ToSvgOptions>;
|
|
35
35
|
/** Receives `script-font-unavailable` and `script-font-not-installed` for `scripts: "auto"`. */
|
|
36
36
|
onDiagnostic?: (diagnostic: {code: string; message: string; script?: string; package?: string; scripts?: string[]}) => void;
|
|
37
37
|
}
|
|
@@ -74,7 +74,7 @@ export declare function scriptFontPackages(scripts: ScriptSelection): BundledFon
|
|
|
74
74
|
export interface NodeFontsHandle extends FontsHandle {
|
|
75
75
|
readonly registry: NodeFontRegistry;
|
|
76
76
|
readonly manifest: BundledFontManifest;
|
|
77
|
-
/** Every font file the handle holds, for `
|
|
77
|
+
/** Every font file the handle holds, for `toPng` and `toPdf`; includes the script faces `ensure` loaded. */
|
|
78
78
|
readonly fontFiles: string[];
|
|
79
79
|
/** The files are already in `fontFiles`, so a conversion adds no bundled faces. */
|
|
80
80
|
readonly useBundledFonts: false;
|
|
@@ -86,9 +86,9 @@ export interface NodeFontsHandle extends FontsHandle {
|
|
|
86
86
|
* the new faces. A package that is not installed or a script no pinned font serves is reported once through `onDiagnostic`.
|
|
87
87
|
* Resolves with the packages this call added (`scripts`; `lazy` is empty: Node loads every vendored face with its pack).
|
|
88
88
|
*/
|
|
89
|
-
ensure(presentation: unknown, options?: { onDiagnostic?: ScriptPackOptions["onDiagnostic"]; renderOptions?: Partial<
|
|
89
|
+
ensure(presentation: unknown, options?: { onDiagnostic?: ScriptPackOptions["onDiagnostic"]; renderOptions?: Partial<ToSvgOptions> }): Promise<EnsureResult>;
|
|
90
90
|
/** Synchronous: the script packages the presentation needs that are not loaded yet. */
|
|
91
|
-
pending(presentation: unknown, renderOptions?: Partial<
|
|
91
|
+
pending(presentation: unknown, renderOptions?: Partial<ToSvgOptions>): string[];
|
|
92
92
|
}
|
|
93
93
|
export interface LoadFontsOptions extends FontRegistryOptions, ScriptPackOptions {
|
|
94
94
|
/** `base` (default): the bundled Roboto faces. `office`: the metric and visual substitutes for the Office families plus the open families font schemes select. `none`: only the `faces` you supply. */
|
package/dist/fonts-node.js
CHANGED
|
@@ -95,7 +95,7 @@ const loadPack = pack => loadPackages(BUNDLED_FONT_MANIFEST.packages.filter(item
|
|
|
95
95
|
/**
|
|
96
96
|
* Adds the script pack. `scripts` is 'all', ISO 15924 codes, or 'auto' (FF-19): detect the scripts the
|
|
97
97
|
* `presentation` draws and load only their faces. Auto never fails on a missing optional package or a
|
|
98
|
-
* script no pinned font serves; it reports them through `onDiagnostic` and `selection`. `renderOptions` are the host's `
|
|
98
|
+
* script no pinned font serves; it reports them through `onDiagnostic` and `selection`. `renderOptions` are the host's `toSvg`
|
|
99
99
|
* options (see `analyzePresentationScripts`).
|
|
100
100
|
*/
|
|
101
101
|
async function withScripts(loaded, scripts, {presentation, onDiagnostic, renderOptions} = {}) {
|
|
@@ -250,7 +250,7 @@ async function ensureFonts(registry, loaded, presentation, {onDiagnostic, render
|
|
|
250
250
|
}
|
|
251
251
|
|
|
252
252
|
// RR-65: hb-subset from the pinned harfbuzzjs package (MIT), compiled once per process. The module has no imports, so it is
|
|
253
|
-
// instantiated synchronously and
|
|
253
|
+
// instantiated synchronously and toSvg stays synchronous. A copy that cannot be loaded leaves the handle without `subsets`
|
|
254
254
|
// (whole faces, as before RR-65): a byte saving never stops fonts from loading.
|
|
255
255
|
let subsetterPromise;
|
|
256
256
|
function nodeSubsetter() {
|
|
@@ -268,7 +268,7 @@ function nodeShaper() {
|
|
|
268
268
|
|
|
269
269
|
/**
|
|
270
270
|
* The fonts handle: one set of verified font inputs for layout, SVG, editor, PPTX and Node raster export. Pass it as `{ fonts }` to
|
|
271
|
-
* `
|
|
271
|
+
* `toSvg`, `toPng`, `toPdf`, core `paginate` and `validate`, and `toPptx`.
|
|
272
272
|
*
|
|
273
273
|
* Bundled, openly licensed faces only: no system font discovery and no network requests. `pack`: `base` (default, Roboto),
|
|
274
274
|
* `office` (the Office substitutes and the open families) or `none` (only the `faces` you supply). Everything else
|
|
@@ -293,7 +293,7 @@ export async function loadFonts({pack = "base", embedScriptFonts = false, ...opt
|
|
|
293
293
|
useBundledFonts: false,
|
|
294
294
|
loadSystemFonts: false,
|
|
295
295
|
registry,
|
|
296
|
-
// RR-64: the outline engine `
|
|
296
|
+
// RR-64: the outline engine `toSvg(deck, { fonts, text: "paths" })` draws text with, over this registry's faces.
|
|
297
297
|
outlines: textOutlines({ registry, shaper }),
|
|
298
298
|
// RR-65: the subset engine that cuts each face an SVG embeds to the characters the slide draws.
|
|
299
299
|
...(subsetter ? { subsets: fontSubsets(registry, subsetter) } : {}),
|