@otisk/preview 1.1.0 → 1.1.1

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 CHANGED
@@ -1,96 +1,113 @@
1
- # `engine-wasm` — WASM bindings for otisk
2
-
3
- Thin `wasm-bindgen` wrapper around `otisk::Engine`. Exposes a single
4
- JS-callable entry point so browser (and other `wasm32-unknown-unknown`)
5
- hosts can drive the otisk pipeline:
6
-
7
- ```rust
8
- // Issue 30 baseline + Issue 115 widening: an **optional** 4th argument
9
- // crosses a JS-side `AssetResolver` into the engine. The 3-arg call
10
- // `render_pdf(html, css, margin)` remains byte-identical to the
11
- // Issue 31 parity baseline; passing `null` / `undefined` for the 4th
12
- // arg is equivalent. When present, `assets` must be either a bare
13
- // `function(url): Uint8Array` callable or an object with a synchronous
14
- // `fetch(url): Uint8Array` method — every engine-side `@font-face`,
15
- // `<img>`, `background-image`, `@color-profile` lookup is funneled
16
- // through it.
17
- #[wasm_bindgen]
18
- pub fn render_pdf(
19
- html: &str,
20
- css: &str,
21
- margin_mm: f32,
22
- assets: Option<JsValue>, // bindgen-side: omittable in JS
23
- ) -> Result<Vec<u8>, JsValue>;
1
+ # @otisk/preview
2
+
3
+ Raster **print-preview** for the [otisk](https://www.npmjs.com/org/otisk)
4
+ typesetting engine, compiled to WebAssembly. Render HTML/CSS pages to RGBA
5
+ bitmaps in the browser (or Bun/Node) and paint them onto an HTML5 canvas —
6
+ the preview shares the **same layout engine** as otisk's PDF output, so what
7
+ you see on screen matches the print geometry pixel-for-pixel; only the
8
+ rasteriser differs (tiny-skia here, the press RIP for the PDF).
9
+
10
+ The same bundle also exposes the full `render_pdf` entry point, so you can
11
+ generate the final PDF from the exact bytes you previewed.
12
+
13
+ ```
14
+ npm i @otisk/preview
24
15
  ```
25
16
 
26
- JS call sites:
17
+ ## Quick start — paint a page to a canvas
27
18
 
28
19
  ```js
29
- // 3-arg legacy form unchanged, empty resolver.
30
- const pdf = render_pdf(html, css, 10);
31
-
32
- // 4-arg widened form — supply a resolver. `null` / `undefined` are
33
- // equivalent to omitting the arg.
34
- const pdf = render_pdf(html, css, 10, {
35
- fetch(url) { /* return Uint8Array */ }
36
- });
37
- ```
20
+ import init, { render_page_rgba } from "@otisk/preview";
38
21
 
39
- See `src/lib.rs` and the issue specs at
40
- `.plans/pdfx4-engine/issues/30-wasm-bindings-crate.md` (baseline) and
41
- `.plans/pdfx4-engine/issues/115-wasm-asset-resolver-crossing.md`
42
- (resolver crossing) for the full rationale.
22
+ await init(); // load the wasm module (once)
43
23
 
44
- ## Build (browser bundle)
24
+ const html = "<h1>Náhled sazby</h1><p>Příliš žluťoučký kůň…</p>";
25
+ const css = "@page { size: A6 } body { font-family: serif }";
45
26
 
46
- ```sh
47
- wasm-pack build crates/engine-wasm --target web --out-dir ../../examples/web-ui/pkg --release
27
+ const dpi = 96;
28
+ const page = render_page_rgba(html, css, /*marginMm*/ 0, null, null, /*pageIndex*/ 0, dpi / 72);
29
+
30
+ const canvas = document.querySelector("canvas");
31
+ canvas.width = page.width;
32
+ canvas.height = page.height;
33
+ canvas
34
+ .getContext("2d")
35
+ .putImageData(new ImageData(new Uint8ClampedArray(page.rgba), page.width, page.height), 0, 0);
48
36
  ```
49
37
 
50
- This produces `examples/web-ui/pkg/engine_wasm_bg.wasm` plus the
51
- `engine_wasm.js` glue module. Serve the demo UI with any static server:
38
+ `rgba` is straight (non-premultiplied) RGBA8, row-major, top-down — exactly
39
+ the layout `ImageData` / `createImageBitmap` expect, so there's no per-pixel
40
+ rework.
52
41
 
53
- ```sh
54
- python3 -m http.server 4173 --directory examples/web-ui
55
- ```
42
+ ## Recommended — render off the main thread
56
43
 
57
- The `pkg/` output directory is git-ignored.
44
+ Rasterising a page will jank the UI thread. For a live preview (re-rendering
45
+ on every edit), run the wasm in a **Web Worker** that owns an
46
+ `OffscreenCanvas`, so pixels never cross back to the main thread. A complete,
47
+ copy-paste consumer — worker + a `PreviewClient` with latest-wins coalescing —
48
+ lives in the repo at
49
+ [`examples/preview-canvas/`](https://github.com/otisk-engine/otisk/tree/main/examples/preview-canvas).
58
50
 
59
- ## Build (raw `.wasm`, no JS glue)
51
+ ## API
60
52
 
61
- For CI gate parity with the issue specno `wasm-pack` required:
53
+ The default export is the wasm initialiser`await init()` (or
54
+ `init(customWasmUrl)`) once before calling anything else.
62
55
 
63
- ```sh
64
- cargo build -p engine-wasm --target wasm32-unknown-unknown --locked --release
65
- ```
56
+ ### `render_page_rgba(html, css, marginMm, assets?, outputIntent?, pageIndex, scale) → RasterResult`
57
+
58
+ Render one page to an RGBA bitmap. `scale` is pixels-per-point (`dpi / 72`);
59
+ `pageIndex` is 0-based. Throws a string error on a layout failure, an
60
+ out-of-range page, or degenerate dimensions.
66
61
 
67
- Artefact at `target/wasm32-unknown-unknown/release/engine_wasm.wasm`.
62
+ ### `page_count(html, css, marginMm, assets?, outputIntent?) → number`
68
63
 
69
- ## Size budget
64
+ How many pages the `(html, css)` pair lays out — for preview navigation.
70
65
 
71
- `SPECIFICATION.md` §4.2: **5 MB compressed** for the full engine. Phase 2
72
- ships the raw bundle without `wasm-opt`; binary-size optimization lands in
73
- Issue 31 / Phase 6. The commit that introduces this crate records the
74
- current unoptimized `.wasm` size as a baseline.
66
+ ### `render_pdf(html, css, marginMm, assets?, outputIntent?) Uint8Array`
75
67
 
76
- ## Host-target build
68
+ Render the whole document to a PDF (the production print artefact). Same
69
+ inputs as the preview, so the PDF matches what you previewed.
77
70
 
78
- The crate is also exposed as an `rlib` so `cargo build -p engine-wasm`
79
- on the host triple works (useful for `cargo doc`, future host-side
80
- integration tests, and IDE indexing). The `cdylib` artefact only matters
81
- for the `wasm32-unknown-unknown` target.
71
+ ### `RasterResult`
82
72
 
83
- ## `parity_export` feature (Issue 31)
73
+ | Member | Type | Notes |
74
+ | ---------- | ------------ | -------------------------------------- |
75
+ | `width` | `number` | Device width in pixels. |
76
+ | `height` | `number` | Device height in pixels. |
77
+ | `rgba` | `Uint8Array` | `4 · width · height` bytes, RGBA8. |
84
78
 
85
- The crate ships a second WASM entry point — a raw C-ABI
86
- `render_pdf_raw` — gated behind the `parity_export` feature. The Phase 2
87
- parity harness (`crates/otisk/tests/wasm_parity.rs`) builds the artefact
88
- with `--no-default-features --features parity_export` and drives it
89
- through `wasmtime` without the `wasm-bindgen` JS glue. This surface is
90
- **internal** — the wire format is not a stability contract, and browser
91
- hosts should always use the default `render_pdf`.
79
+ ### Asset resolver (`assets`)
92
80
 
93
- ```sh
94
- cargo build -p engine-wasm --target wasm32-unknown-unknown \
95
- --no-default-features --features parity_export --release
81
+ Fonts, images, and color profiles referenced by the CSS/HTML
82
+ (`@font-face`, `<img>`, `background-image`, `@color-profile`) are pulled
83
+ through an optional **synchronous** resolver. Pass `null`/`undefined` to
84
+ disable it, or an object with a `fetch` method (or a bare function):
85
+
86
+ ```js
87
+ const assets = {
88
+ fetch(url) {
89
+ return fontBytes.get(url); // must return a Uint8Array, synchronously
90
+ },
91
+ };
92
+ render_page_rgba(html, css, 0, assets, null, 0, dpi / 72);
96
93
  ```
94
+
95
+ ### Output intent (`outputIntent`)
96
+
97
+ Optional color target for the render: `"srgb"` (default), `"fogra39"`, or
98
+ `"swop_v2"`. Pass `null` for sRGB.
99
+
100
+ ## Notes
101
+
102
+ - **Module format.** This is the `--target web` build — native ESM that
103
+ runs in browsers, Bun, and bundlers (Vite/webpack). It is not a CommonJS
104
+ Node build.
105
+ - **Bundle size.** ~4.8 MB gzipped — fetch it lazily / behind a route split
106
+ rather than in your initial bundle.
107
+ - **No OffscreenCanvas?** On engines without `transferControlToOffscreen`
108
+ (older Safari), run `render_page_rgba` on the main thread and
109
+ `putImageData` as in the quick start.
110
+
111
+ ## License
112
+
113
+ Apache-2.0
Binary file
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@otisk/preview",
3
3
  "type": "module",
4
4
  "description": "Raster print-preview for the otisk typesetting engine: render HTML/CSS pages to RGBA bitmaps (WASM) for an HTML5-canvas preview that matches the PDF print geometry.",
5
- "version": "1.1.0",
5
+ "version": "1.1.1",
6
6
  "license": "Apache-2.0",
7
7
  "files": [
8
8
  "engine_wasm_bg.wasm",