@pptx-studio/cli 0.1.0 → 0.3.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/CHANGELOG.md CHANGED
@@ -1,5 +1,154 @@
1
1
  # @pptx-studio/cli
2
2
 
3
+ ## 0.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 3622457: `render` on macOS lays text out on the box CoreText reads: `hhea` whatever `fsSelection` bit 7 says, rounded half up from the em ratio held as 16.16 fixed point, measured 248/248 on `macos-latest`. `FontBackend` gains `coretext` and `FaceMetrics` says which backend it was read for.
8
+ - 55f3073: `pptx-studio render` writes the face it measured a run in into the markup, and reads the face box
9
+ the way the browser reports it.
10
+
11
+ The SVG said `font-family="Calibri Light"` and nothing else, so a viewer picked its own face while
12
+ the line breaks and origins had been computed for whatever stood in — the one place the two
13
+ renderers could still disagree about what was drawn, open since ADR 0044. Every run now carries a
14
+ list: the face this machine drew it in, then the face the deck asked for, then the substitution
15
+ table's entry, then Calibri and Carlito, then `sans-serif`. `Calibri Light` drawn in Carlito reads
16
+ `"Carlito", "Calibri Light", "Calibri", sans-serif`; a face the machine has leads its own list.
17
+
18
+ `FontMeasurer` gains `cssFamilyFor`, answered from the resolved-face cache the measurer already
19
+ filled, so it cannot name a face other than the one that measured. A face whose name cannot be
20
+ written into a CSS shorthand is no longer claimed by the index, as a blank name already was not.
21
+
22
+ The face box is rounded half up to a whole pixel at the size the browser reads it, and the
23
+ ideographic baseline of a face with no `BASE` table is that rounded descent: T13 on a 2048 and a
24
+ 2000 em, 28 of 28 and 36 of 36, where the exact fraction scores 25 and 34. ADR 0052.
25
+
26
+ ### Patch Changes
27
+
28
+ - 55f3073: The help text spells `this platform's own font directories` with its apostrophe, and the
29
+ `render-dom` tarball carries `CHANGELOG.md` like the other eleven.
30
+ - Updated dependencies [55f3073]
31
+ - @pptx-studio/render-svg@0.2.0
32
+ - @pptx-studio/text@0.2.0
33
+
34
+ ## 0.2.0
35
+
36
+ ### Minor Changes
37
+
38
+ - 725ad6d: `renderDeck` takes only what it draws.
39
+
40
+ Its options were the `render` verb's own, so a caller that wanted SVG strings passed
41
+ `out`, `json` and `quiet` — three fields the function ignores — and five more it had no
42
+ opinion about. `RenderDeckOptions` is the shape now: `slide`, `width`, `fontDirs`,
43
+ `systemFonts` and `text`, all optional. `renderDeck(bytes)` is a whole call, and
44
+ `renderDeck(bytes, { slide: 1, width: 640 })` is a thumbnail.
45
+
46
+ `RenderOptions` is the verb's: it extends `RenderDeckOptions` with `out`, `json` and
47
+ `quiet`, and `runRender` is what takes it. `RENDER_DEFAULTS` is gone, because the
48
+ defaults are in `renderDeck` and `DEFAULT_WIDTH` is still exported. A width that is not
49
+ a positive whole number now throws `CLI_WIDTH` instead of drawing an empty picture.
50
+
51
+ Breaking: a call written against 0.1.0 passes three properties this shape does not have.
52
+ Delete them, and delete any field you were only passing to satisfy the type.
53
+
54
+ - c1d7d7d: The face box is read from the table this machine's rasteriser reads.
55
+
56
+ `pptx-studio render` took a face's ascent and descent from `OS/2.usWinAscent`/`usWinDescent`
57
+ everywhere, or `sTypo` where `fsSelection` bit 7 is set. That is what Chromium answers through
58
+ DirectWrite and it is not what Chromium answers through FreeType, which reads
59
+ `hhea.ascender`/`descender`. Neither reading fits both: the first scores 12/12 against Windows and
60
+ 76/79 against Linux, the second 79/79 against Linux and 7/12 against Windows, and the misses are
61
+ 75.8 px and 100 px on a 1000 px em rather than roundings.
62
+
63
+ On a Linux server — which is where this verb runs — the old reading put the IPA Gothic descent at
64
+ 195.8 px where the browser puts it at 120, 7.6% of the em on every line of Japanese text, moving
65
+ every line break and every autofit decision.
66
+
67
+ `indexFonts` now resolves a `FontBackend` from its platform, and `metricsOf` reads `hhea` under
68
+ FreeType and `usWin` under DirectWrite, with bit 7 moving both onto `sTypo`. `FaceMetrics.source`
69
+ gains `hhea`, which is also what a face carrying no `OS/2` now reports rather than claiming `usWin`
70
+ while returning `hhea`'s numbers. macOS takes the DirectWrite reading and is unmeasured.
71
+
72
+ **Breaking:** `facesIn` and `faceOf` take the backend as a third argument. There is no defensible
73
+ default — a silent one would be a guess about the host — and `backendFor(platform)` is exported for
74
+ callers that want the local answer.
75
+
76
+ The rule is measured, not assumed: 79 real faces on a Linux runner against the 12 probe fonts T13
77
+ built to disagree with themselves, both scored in
78
+ `docs/adr/phase-3-text/0045-the-face-box-belongs-to-the-rasteriser.md`.
79
+
80
+ ### Patch Changes
81
+
82
+ - 725ad6d: The ideographic baseline comes out of the font's `BASE` table.
83
+
84
+ `pptx-studio render` placed every upright East Asian glyph on the face's box descent,
85
+ which is right only for a face carrying no `BASE` table. Yu Gothic reports a box descent
86
+ of 0.302 em and an ideographic baseline of 0.1201 em, so a vertical `eaVert` frame was
87
+ drawn 0.18 em out of place on it — and the browser renderer, which asks Chromium, was
88
+ never wrong about the same face.
89
+
90
+ `sfnt.ts` now reads the `BASE` horizontal axis' `ideo` coordinate under the `DFLT`
91
+ script, and `FaceMetrics` carries it as `ideographic`. Where there is none the box
92
+ descent stands, and a coordinate outside the em answers zero, which is what
93
+ `@pptx-studio/text`'s own probe does with an unusable one.
94
+
95
+ The rule is measured, not assumed: four probe fonts whose `DFLT`, `latn` and `hani`
96
+ coordinates all disagree settle it at 30 of 30 in `corpus/ground-truth/font-metrics.json`.
97
+ Chromium reads `DFLT` and no other script — a `BASE` table naming only `latn`, `hani`
98
+ and `kana` is ignored whole — and it reads the same coordinate for a Latin run as for a
99
+ Han one, so the answer is a property of the face rather than of the text.
100
+
101
+ A coordinate outside the em is handed over as written rather than clamped — Chromium
102
+ reported 1.2 em for a font that says so — so both engines see the same unusable number
103
+ and both answer zero.
104
+
105
+ - cec9ef2: Kerning is read through a type 9 GPOS Extension lookup.
106
+
107
+ `pptx-studio render` measured every face whose `kern` feature sits behind an
108
+ `ExtensionPosFormat1` subtable as having no kerning at all — no error, no diagnostic, just
109
+ lines about a twelfth too wide, which moves every break and misfires autofit. Lato is such
110
+ a face, in all eighteen of the styles a Linux runner carries, and so is most of what a
111
+ modern font compiler emits: an extension is how a lookup reaches a subtable past the 64 KB
112
+ a 16-bit offset can address, and compilers wrap unconditionally rather than only when they
113
+ must.
114
+
115
+ `sfnt.ts` read `if (u16(r, lookup) !== 2) continue`, so lookup type 9 was skipped along
116
+ with mark attachment and cursive positioning, which genuinely do not move an advance. It
117
+ now follows a type 9 lookup one level, to the type its `ExtensionPosFormat1` names at the
118
+ 32-bit offset from its own start, and reads the `PairPos` there. Exactly one level: the
119
+ specification forbids an extension targeting another, so nothing recurses, and a subtable
120
+ naming any other type is skipped as before.
121
+
122
+ The rule is measured, not assumed. A twelfth probe font wraps the same `PairPos` the
123
+ eleventh carries plainly, and Chromium drew the two identically at all six sizes and on
124
+ all six strings — so the browser honours the wrapper and the reader was wrong rather than
125
+ strict. Following one extension fits 72 of 72 in
126
+ `corpus/ground-truth/font-metrics.json`, alone at the top; the reading that skipped it
127
+ fits 66, exactly the six rows of the wrapped probe.
128
+
129
+ - cec9ef2: `renderDeck` substitutes a typeface nothing stands in for rather than refusing to draw.
130
+
131
+ A deck naming `Calibri Light` on a Linux server holding 53 perfectly good faces threw
132
+ `CLI_NO_FACE` and rendered nothing. The chain ran exact family, the substitution table,
133
+ Calibri, Carlito — and then gave up, which is the one place the font guard's design was
134
+ not applied: `FaceUse` carries `asked`, `drawn` and `substituted` so the answer can be
135
+ "Calibri Light was drawn in DejaVu Sans" rather than an exception.
136
+
137
+ Two steps now follow the measured chain. The shorter forms of the asked-for name, so
138
+ `Calibri Light` draws in Calibri and `Segoe UI Semilight` in Segoe UI where the machine
139
+ has them — DrawingML has no weight axis, so a style word is part of the typeface name.
140
+ Then, past every named candidate, the first family by name draws the run. Both are
141
+ reported as substitutions under the name the deck asked for, and neither displaces the
142
+ measured chain: ADR 0033 scored PowerPoint's own last resort at 22 of 22 and a guess must
143
+ not override a measurement.
144
+
145
+ The choice is by family name, not by the order `readdir` returned, and the font walk now
146
+ sorts its entries — so two machines holding the same faces draw the same picture, where
147
+ before the answer was the filesystem's own.
148
+
149
+ `CLI_NO_FACE` still throws, and now means exactly one thing: no font was found at all,
150
+ which is nothing to draw with rather than an unusual typeface.
151
+
3
152
  ## 0.1.0
4
153
 
5
154
  ### Minor Changes
package/README.md CHANGED
@@ -200,14 +200,12 @@ cannot drift apart.
200
200
 
201
201
  ## Not built yet
202
202
 
203
- The plan gives this package three more verbs. Asking for one says which sub-phase
204
- brings it rather than "unknown command":
203
+ The plan gives this package one more verb. Asking for it says which sub-phase brings
204
+ it rather than "unknown command":
205
205
 
206
- | verb | what it will do | sub-phase |
207
- | ---------- | --------------------------------------------- | --------- |
208
- | `fidelity` | score a render against a reference | 3.9 |
209
- | `render` | render slides to SVG or PNG without a browser | 3.10 |
210
- | `resolve` | show where a resolved property came from | 7.x |
206
+ | verb | what it will do | sub-phase |
207
+ | --------- | ---------------------------------------- | --------- |
208
+ | `resolve` | show where a resolved property came from | 7.x |
211
209
 
212
210
  ## `render`
213
211
 
@@ -226,12 +224,39 @@ the same document, and there is no external reference of any kind to resolve.
226
224
  face's own `cmap`, `hmtx`, `GPOS` and `OS/2` tables instead. That is a second
227
225
  measurement engine, and the risk of a second engine is that it quietly disagrees
228
226
  with the first. Experiment T13 settled the arithmetic rather than assuming it:
229
- seven fonts built so their tables disagree on purpose, 252 widths measured in
230
- Chromium, and the reader reproduces **all 252 exactly**. The rules it found are
227
+ fifteen fonts built so their tables disagree on purpose, 540 widths measured in
228
+ Chromium, and the reader reproduces **all 540 exactly**. It also settled where
229
+ an upright East Asian glyph sits: on the `BASE` table's `ideo` coordinate for
230
+ the `DFLT` script, and on the face box descent only where there is none — and
231
+ that the box itself is reported in whole pixels, each side rounded half up at
232
+ the size it is read, which three probes on a 2048, a 2000 and a 2560 em are the
233
+ only ones able to show. The rules it found are
231
234
  in [`corpus/ground-truth/font-metrics.json`](../../corpus/ground-truth/font-metrics.json)
232
235
  and the reasoning is in
233
236
  [ADR 0042](../../docs/adr/phase-3-text/0042-rendering-without-a-browser.md).
234
237
 
238
+ **The face box depends on the rasteriser**, so the reader takes the answer
239
+ belonging to the platform it runs on. Chromium reports a face's ascent and
240
+ descent from `OS/2.usWinAscent`/`usWinDescent` through DirectWrite and from
241
+ `hhea.ascender`/`descender` through FreeType, with `fsSelection` bit 7 moving
242
+ both onto `sTypo`; through CoreText it reports `hhea` whatever bit 7 says. No
243
+ one reading fits two of them: T13's probes score 15/15, 7/15 and 6/15 on
244
+ Windows, where 94 faces score 94/94 on Linux and 248 score 248/248 on macOS,
245
+ the rivals missing by up to 100 px on a 1000 px em. CoreText also holds the em
246
+ ratio as 16.16 fixed point before it rounds, which moves a box that sits exactly
247
+ on the half; DirectWrite and FreeType do not. See
248
+ [ADR 0045](../../docs/adr/phase-3-text/0045-the-face-box-belongs-to-the-rasteriser.md)
249
+ and [ADR 0053](../../docs/adr/phase-3-text/0053-what-linux-and-macos-said.md).
250
+
251
+ Each reading is measured on its own runner, so a slide is laid out for the
252
+ machine that renders it. Line breaks, line origins and word spacing are
253
+ written into the SVG with that machine's advances, and a viewer flows each
254
+ line's glyphs with its own, so a deck rendered on a Linux server and opened on a
255
+ Windows desktop differs by whatever the two rasterisers disagree by — a rounding
256
+ per glyph on the same face, and the whole difference between two faces where
257
+ the viewer picks another from the list. Opened on the machine that made it, the
258
+ file draws exactly what was measured.
259
+
235
260
  Fonts are found in this platform's own directories, plus any `--font-dir` you
236
261
  name, which are searched first so you can override a face without installing
237
262
  one. `--no-system-fonts` limits it to what you named; `--no-text` draws geometry
@@ -239,8 +264,36 @@ only and asks no font questions at all.
239
264
 
240
265
  A typeface the machine does not have is substituted through the same table
241
266
  `@pptx-studio/text` uses in the browser, so the two renderers cannot fall back
242
- differently, and the substitution is reported rather than hidden. A code point
243
- no indexed face can draw is reported too.
267
+ differently, and the substitution is reported rather than hidden. The chain is
268
+ that table's entry for the name, then Calibri and Carlito — what PowerPoint
269
+ itself falls back to, measured 22 of 22 in
270
+ [ADR 0033](../../docs/adr/phase-3-text/0033-font-substitution-and-the-guard.md) —
271
+ then the family the asked-for name is a variation of, so `Calibri Light` draws
272
+ in Calibri where the machine has it.
273
+
274
+ Past all of those the first family by name draws the run. The browser's stack
275
+ ends in a generic and this has none, so something has to be chosen, and it is
276
+ chosen by name rather than by the order the files were read in: two machines
277
+ holding the same faces answer identically. It is still reported as a
278
+ substitution, under the name the deck asked for. **`CLI_NO_FACE` is thrown only
279
+ when no font was found at all** — an empty library is nothing to draw with,
280
+ which is a different thing from an unusual typeface. A code point no indexed
281
+ face can draw is reported too.
282
+
283
+ **The markup names the face that measured it.** Every run's `font-family` is a
284
+ list, not a name: the face this machine drew the run in, then the face the deck
285
+ asked for, then the substitution table's entry, then Calibri and Carlito, then
286
+ `sans-serif`. `Calibri Light` drawn in Carlito comes out as
287
+ `"Carlito", "Calibri Light", "Calibri", sans-serif`; a face the machine has
288
+ leads its own list, so on a machine holding the deck's fonts the markup reads as
289
+ the deck does. The order is the point. Line breaks and line origins are written
290
+ into the SVG with the first face's advances, so a viewer that has it draws
291
+ exactly what was measured; one that has only the face the deck named draws the
292
+ author's face on positions computed for a stand-in, which is right where the two
293
+ are metric-compatible and approximate where they are not; and one that has
294
+ neither lands where PowerPoint would have rather than on the browser's own
295
+ default. `--json` pairs each `asked` with its `drawn`: the drawn face leads that
296
+ run's list, and the asked one follows it wherever the two differ.
244
297
 
245
298
  | flag | |
246
299
  | ------------------- | ------------------------------------------------------------------- |
@@ -251,6 +304,37 @@ no indexed face can draw is reported too.
251
304
  | `--no-system-fonts` | do not look in this platform's own font directories |
252
305
  | `--no-text` | geometry only |
253
306
  | `--json` | what was drawn, and which face drew each typeface |
307
+ | `--quiet` | no summary after writing |
308
+
309
+ ### From a program
310
+
311
+ `renderDeck` is what the verb runs, without the file handling: it takes bytes and
312
+ returns the markup. Every option has a default, so the smallest call is the deck and
313
+ nothing else.
314
+
315
+ ```ts
316
+ import { renderDeck } from '@pptx-studio/cli';
317
+
318
+ const deck = renderDeck(bytes); // every slide, 1920 wide
319
+ const thumb = renderDeck(bytes, { slide: 1, width: 640 }).slides[0]?.svg;
320
+ const shape = renderDeck(bytes, { text: false }); // geometry only, no fonts read
321
+ ```
322
+
323
+ | option | default | |
324
+ | ------------- | ----------- | ----------------------------------------------------------- |
325
+ | `slide` | every slide | 1-based; `null` and omitted both mean every slide |
326
+ | `width` | `1920` | the `width` attribute; the height follows the deck's aspect |
327
+ | `fontDirs` | none | searched before the platform's own |
328
+ | `systemFonts` | `true` | also look in this platform's font directories |
329
+ | `text` | `true` | `false` draws geometry only and asks no font questions |
330
+
331
+ `--out`, `--json` and `--quiet` are the command's, not the library's: they say where
332
+ the markup goes and what is printed about it. `runRender` takes those, reads the deck
333
+ off the disk and writes the files. `renderDeck` does neither, and a width that is not
334
+ a positive whole number throws `CLI_WIDTH` rather than drawing an empty picture.
335
+
336
+ Fonts are indexed per call, so a server rendering many decks pays for the scan every
337
+ time.
254
338
 
255
339
  ### What it does not do
256
340
 
package/dist/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { t as main } from "./main-DLx2onii.js";
2
+ import { t as main } from "./main-3sNR_Xlp.js";
3
3
  //#region src/cli.ts
4
4
  /**
5
5
  * The bin.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { PackageCensus } from "@pptx-studio/census";
2
- import { FaceBoxProbe, TextMeasurer } from "@pptx-studio/text";
2
+ import { FaceBoxProbe, RunFont, TextMeasurer } from "@pptx-studio/text";
3
3
  //#region src/main.d.ts
4
4
  interface Streams {
5
5
  readonly out: (text: string) => void;
@@ -60,6 +60,30 @@ declare function runInspect(path: string, options: InspectOptions, write: (text:
60
60
  * against Chromium in experiment T13 rather than taken from the specification.
61
61
  * ADR 0042.
62
62
  */
63
+ /**
64
+ * The rasteriser a Chromium reads a face's vertical metrics through.
65
+ *
66
+ * T13 scored `usWin` 30/30 against DirectWrite on fonts built to disagree; T14
67
+ * scored `hhea` 94/94 against FreeType and 248/248 against CoreText on real
68
+ * faces. One reader cannot answer for all three. ADR 0045, ADR 0053.
69
+ */
70
+ type FontBackend = 'directwrite' | 'freetype' | 'coretext';
71
+ /** FreeType on Linux, CoreText on macOS, DirectWrite elsewhere. ADR 0045, ADR 0053. */
72
+ declare function backendFor(platform: string): FontBackend;
73
+ /** One ascent and descent in font units, the descent positive below the baseline. */
74
+ interface MetricPair {
75
+ readonly ascent: number;
76
+ readonly descent: number;
77
+ }
78
+ /** Every pair a browser could report a face box from, each as its table wrote it. */
79
+ interface MetricCandidates {
80
+ readonly hhea: MetricPair;
81
+ /** `undefined` on a face with no `OS/2` table long enough to hold version 0. */
82
+ readonly usWin: MetricPair | undefined;
83
+ readonly sTypo: MetricPair | undefined;
84
+ /** `OS/2.fsSelection` bit 7, USE_TYPO_METRICS. */
85
+ readonly useTypoMetrics: boolean;
86
+ }
63
87
  interface FaceMetrics {
64
88
  /** `head.unitsPerEm`, the denominator of every number here. */
65
89
  readonly unitsPerEm: number;
@@ -68,7 +92,13 @@ interface FaceMetrics {
68
92
  /** Below the baseline, in font units, positive. */
69
93
  readonly descent: number;
70
94
  /** Which table `ascent` and `descent` came out of, for the diagnostics. */
71
- readonly source: 'usWin' | 'sTypo';
95
+ readonly source: 'hhea' | 'usWin' | 'sTypo';
96
+ /** The rasteriser `source` was chosen for, which also fixes how the box rounds. */
97
+ readonly backend: FontBackend;
98
+ /** The `BASE` `ideo` coordinate under `DFLT`, in font units below the baseline. */
99
+ readonly ideographic: number | undefined;
100
+ /** The pairs `ascent` and `descent` were chosen from, so a rival reading is scorable. */
101
+ readonly candidates: MetricCandidates;
72
102
  }
73
103
  interface Face {
74
104
  /** `name` ID 1, which is what PowerPoint matches a typeface on. */
@@ -86,7 +116,7 @@ interface Face {
86
116
  kernBetween(left: number, right: number): number;
87
117
  }
88
118
  /** Every face in a file, which is one unless the file is a collection. */
89
- declare function facesIn(bytes: Uint8Array, subject: string): readonly Face[];
119
+ declare function facesIn(bytes: Uint8Array, subject: string, backend: FontBackend): readonly Face[];
90
120
  //#endregion
91
121
  //#region src/render/faces.d.ts
92
122
  /** Where fonts live on this platform, whether or not the directories exist. */
@@ -138,6 +168,8 @@ interface FaceUse {
138
168
  interface FontMeasurer {
139
169
  readonly measurer: TextMeasurer;
140
170
  readonly faceBox: FaceBoxProbe;
171
+ /** The CSS family list a run is drawn in: the face that measured it, then the deck's own stack. */
172
+ readonly cssFamilyFor: (font: RunFont) => string;
141
173
  /** Every typeface asked for, and what it was drawn in. */
142
174
  used(): readonly FaceUse[];
143
175
  /** Code points no face in the library could draw. */
@@ -154,23 +186,26 @@ declare function createFontMeasurer(library: FontLibrary): FontMeasurer;
154
186
  //#region src/render/render.d.ts
155
187
  /** What a slide is drawn at when the caller says nothing. PowerPoint's own. */
156
188
  declare const DEFAULT_WIDTH = 1920;
157
- interface RenderOptions {
158
- /** 1-based, or `null` for every slide. */
159
- readonly slide: number | null;
160
- readonly width: number;
189
+ /** What to draw. Every field has a default, so `renderDeck(bytes)` is a whole call. */
190
+ interface RenderDeckOptions {
191
+ /** 1-based. Omitted, or `null`, is every slide. */
192
+ readonly slide?: number | null;
193
+ /** The `width` attribute in CSS pixels; the height follows the deck's aspect. */
194
+ readonly width?: number;
195
+ /** Searched before the platform's own, so a face can be overridden without installing it. */
196
+ readonly fontDirs?: readonly string[];
197
+ /** Also look in this platform's font directories. Default true. */
198
+ readonly systemFonts?: boolean;
199
+ /** Draw text. `false` draws geometry only and asks no font questions. Default true. */
200
+ readonly text?: boolean;
201
+ }
202
+ /** What the verb adds: where the markup goes, and what is said about it. */
203
+ interface RenderOptions extends RenderDeckOptions {
161
204
  /** A directory for many slides, a file for one, or `null` for stdout. */
162
205
  readonly out: string | null;
163
- readonly fontDirs: readonly string[];
164
- readonly systemFonts: boolean;
165
- readonly text: boolean;
166
206
  readonly json: boolean;
167
207
  readonly quiet: boolean;
168
208
  }
169
- declare const RENDER_DEFAULTS: {
170
- readonly width: 1920;
171
- readonly systemFonts: true;
172
- readonly text: true;
173
- };
174
209
  interface RenderedSlide {
175
210
  /** 1-based, as the flag and the file name spell it. */
176
211
  readonly number: number;
@@ -190,10 +225,10 @@ interface RenderResult {
190
225
  /**
191
226
  * Render a deck that is already in memory.
192
227
  *
193
- * Separate from `runRender` so that the whole pipeline is exercised by the test
194
- * suite without a file system, a process or a captured stdout.
228
+ * The library entry point: no file system, no process, no stdout. `runRender` is
229
+ * the verb wrapped around it, and the three fields it adds are its own.
195
230
  */
196
- declare function renderDeck(bytes: Uint8Array, options: RenderOptions): RenderResult;
231
+ declare function renderDeck(bytes: Uint8Array, options?: RenderDeckOptions): RenderResult;
197
232
  /** Read, render, write, and return an exit code. Never calls `process.exit`. */
198
233
  declare function runRender(file: string, options: RenderOptions, out: (text: string) => void): number;
199
234
  //#endregion
@@ -216,6 +251,8 @@ type RenderErrorCode =
216
251
  'CLI_FONT_SIZE' |
217
252
  /** A slide index outside the deck. */
218
253
  'CLI_NO_SLIDE' |
254
+ /** A width that is not a positive whole number of pixels. */
255
+ 'CLI_WIDTH' |
219
256
  /** An output path that names no directory, or a directory that is a file. */
220
257
  'CLI_OUTPUT_PATH';
221
258
  declare const RENDER_ERROR_CODES: readonly RenderErrorCode[];
@@ -228,5 +265,5 @@ declare class RenderError extends Error {
228
265
  }
229
266
  declare function isRenderError(error: unknown): error is RenderError;
230
267
  //#endregion
231
- export { DEFAULT_WIDTH, type Face, type FaceUse, type FontLibrary, type FontMeasurer, INSPECT_DEFAULTS, type InspectOptions, type InspectResult, RENDER_DEFAULTS, RENDER_ERROR_CODES, RenderError, type RenderErrorCode, type RenderOptions, type RenderResult, type RenderedSlide, type Streams, createFontMeasurer, facesIn, indexFonts, inspectFile, isRenderError, main, renderDeck, runInspect, runRender, systemFontDirectories };
268
+ export { DEFAULT_WIDTH, type Face, type FaceUse, type FontBackend, type FontLibrary, type FontMeasurer, INSPECT_DEFAULTS, type InspectOptions, type InspectResult, RENDER_ERROR_CODES, type RenderDeckOptions, RenderError, type RenderErrorCode, type RenderOptions, type RenderResult, type RenderedSlide, type Streams, backendFor, createFontMeasurer, facesIn, indexFonts, inspectFile, isRenderError, main, renderDeck, runInspect, runRender, systemFontDirectories };
232
269
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/main.ts","../src/inspect.ts","../src/render/sfnt.ts","../src/render/faces.ts","../src/render/measure.ts","../src/render/render.ts","../src/render/errors.ts"],"mappings":";;;UA0HiB;WACN,MAAM;WACN,MAAM;;;iBASD,KAAK,yBAAyB,UAAS;;;;;;;;;;;;;;;UCrHtC;WACN;WACA;WACA;WACA;;WAEA;;cAGE,kBAAkB;UAQd;WACN,QAAQ;WACR;;;;;;;;;;WAUA;;;iBAIK,YACd,cACA,UAAS,iBACR;;iBAiBa,WACd,cACA,SAAS,gBACT,QAAQ;;;;;;;;;;;;;UCpDO;;WAEN;;WAEA;;WAEA;;WAEA;;UAGM;;WAEN;;WAEA;;WAEA;WACA,SAAS;WACT;WACA;;EAET,UAAU;;EAEV,YAAY,cAAc;;;iBAqdZ,QAAQ,OAAO,YAAY,2BAA2B;;;;iBCnetD,sBAAsB;UAuCrB;WACN,MAAM;WACN;;;UAIM;WACN,MAAM;;WAEN;;WAEA;WACA;WACA;;UAGM;;WAEN,kBAAkB;;WAElB;EACT,QAAQ,gBAAgB,eAAe,kBAAkB;;UAG1C;;WAEN;;WAEA;WACA;;;;;;;;;iBAoBK,WAAW,UAAS,eAAoB;;;UCxEvC;WACN;WACA;WACA;WACA;;UAGM;WACN,UAAU;WACV,SAAS;;EAElB,iBAAiB;;EAEjB;;;;;;;;iBASc,mBAAmB,SAAS,cAAc;;;;cC9C7C;UAEI;;WAEN;WACA;;WAEA;WACA;WACA;WACA;WACA;WACA;;cAGE;;;;;UAMI;;WAEN;WACA;;UAGM;WACN,iBAAiB;WACjB;WACA;;WAEA,gBAAgB;;WAEhB;WACA;WACA;;;;;;;;iBAoBK,WAAW,OAAO,YAAY,SAAS,gBAAgB;;iBAuIvD,UACd,cACA,SAAS,eACT,MAAM;;;;;;;;;;KCjNI;;;;;;;;;;;;;cAcC,6BAA6B;cAS7B,oBAAoB;WACb;WACT,MAAM;;WAEN;EAEG,YAAA,MAAM,iBAAiB,iBAAiB;;iBAOtC,cAAc,iBAAiB,SAAS"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/main.ts","../src/inspect.ts","../src/render/sfnt.ts","../src/render/faces.ts","../src/render/measure.ts","../src/render/render.ts","../src/render/errors.ts"],"mappings":";;;UAyHiB;WACN,MAAM;WACN,MAAM;;;iBASD,KAAK,yBAAyB,UAAS;;;;;;;;;;;;;;;UCpHtC;WACN;WACA;WACA;WACA;;WAEA;;cAGE,kBAAkB;UAQd;WACN,QAAQ;WACR;;;;;;;;;;WAUA;;;iBAIK,YACd,cACA,UAAS,iBACR;;iBAiBa,WACd,cACA,SAAS,gBACT,QAAQ;;;;;;;;;;;;;;;;;;;;KC7CE;;iBAGI,WAAW,mBAAmB;;UAO7B;WACN;WACA;;;UAIM;WACN,MAAM;;WAEN,OAAO;WACP,OAAO;;WAEP;;UAGM;;WAEN;;WAEA;;WAEA;;WAEA;;WAEA,SAAS;;WAET;;WAEA,YAAY;;UAGN;;WAEN;;WAEA;;WAEA;WACA,SAAS;WACT;WACA;;EAET,UAAU;;EAEV,YAAY,cAAc;;;iBAyjBZ,QAAQ,OAAO,YAAY,iBAAiB,SAAS,uBAAuB;;;;iBC5lB5E,sBAAsB;UAyCrB;WACN,MAAM;WACN;;;UAIM;WACN,MAAM;;WAEN;;WAEA;WACA;WACA;;UAGM;;WAEN,kBAAkB;;WAElB;EACT,QAAQ,gBAAgB,eAAe,kBAAkB;;UAG1C;;WAEN;;WAEA;WACA;;;;;;;;;iBAuDK,WAAW,UAAS,eAAoB;;;UC9GvC;WACN;WACA;WACA;WACA;;UAGM;WACN,UAAU;WACV,SAAS;;WAET,eAAe,MAAM;;EAE9B,iBAAiB;;EAEjB;;;;;;;;iBASc,mBAAmB,SAAS,cAAc;;;;cChE7C;;UAGI;;WAEN;;WAEA;;WAEA;;WAEA;;WAEA;;;UAIM,sBAAsB;;WAE5B;WACA;WACA;;UAQM;;WAEN;WACA;;UAGM;WACN,iBAAiB;WACjB;WACA;;WAEA,gBAAgB;;WAEhB;WACA;WACA;;;;;;;;iBAoBK,WAAW,OAAO,YAAY,UAAS,oBAAyB;;iBAqJhE,UACd,cACA,SAAS,eACT,MAAM;;;;;;;;;;KCvOI;;;;;;;;;;;;;;;cAgBC,6BAA6B;cAU7B,oBAAoB;WACb;WACT,MAAM;;WAEN;EAEG,YAAA,MAAM,iBAAiB,iBAAiB;;iBAOtC,cAAc,iBAAiB,SAAS"}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as runRender, c as systemFontDirectories, d as RenderError, f as isRenderError, h as runInspect, i as renderDeck, l as facesIn, m as inspectFile, n as DEFAULT_WIDTH, o as createFontMeasurer, p as INSPECT_DEFAULTS, r as RENDER_DEFAULTS, s as indexFonts, t as main, u as RENDER_ERROR_CODES } from "./main-DLx2onii.js";
2
- export { DEFAULT_WIDTH, INSPECT_DEFAULTS, RENDER_DEFAULTS, RENDER_ERROR_CODES, RenderError, createFontMeasurer, facesIn, indexFonts, inspectFile, isRenderError, main, renderDeck, runInspect, runRender, systemFontDirectories };
1
+ import { a as createFontMeasurer, c as backendFor, d as RenderError, f as isRenderError, h as runInspect, i as runRender, l as facesIn, m as inspectFile, n as DEFAULT_WIDTH, o as indexFonts, p as INSPECT_DEFAULTS, r as renderDeck, s as systemFontDirectories, t as main, u as RENDER_ERROR_CODES } from "./main-3sNR_Xlp.js";
2
+ export { DEFAULT_WIDTH, INSPECT_DEFAULTS, RENDER_ERROR_CODES, RenderError, backendFor, createFontMeasurer, facesIn, indexFonts, inspectFile, isRenderError, main, renderDeck, runInspect, runRender, systemFontDirectories };