@otisk/preview
v1.3.0
Published
Browser raster-preview bindings for the otisk PDF engine: render_page_rgba / page_count for HTML5-canvas previews (wasm-bindgen, --features raster-preview).
Readme
engine-wasm — WASM bindings for otisk
Thin wasm-bindgen wrapper around otisk::Engine. Exposes a single
JS-callable entry point so browser (and other wasm32-unknown-unknown)
hosts can drive the otisk pipeline:
// Issue 30 baseline + Issue 115 widening: an **optional** 4th argument
// crosses a JS-side `AssetResolver` into the engine. The 3-arg call
// `render_pdf(html, css, margin)` remains byte-identical to the
// Issue 31 parity baseline; passing `null` / `undefined` for the 4th
// arg is equivalent. When present, `assets` must be either a bare
// `function(url): Uint8Array` callable or an object with a synchronous
// `fetch(url): Uint8Array` method — every engine-side `@font-face`,
// `<img>`, `background-image`, `@color-profile` lookup is funneled
// through it.
#[wasm_bindgen]
pub fn render_pdf(
html: &str,
css: &str,
margin_mm: f32,
assets: Option<JsValue>, // bindgen-side: omittable in JS
) -> Result<Vec<u8>, JsValue>;JS call sites:
// 3-arg legacy form — unchanged, empty resolver.
const pdf = render_pdf(html, css, 10);
// 4-arg widened form — supply a resolver. `null` / `undefined` are
// equivalent to omitting the arg.
const pdf = render_pdf(html, css, 10, {
fetch(url) { /* return Uint8Array */ }
});See src/lib.rs and the issue specs at
.plans/pdfx4-engine/issues/30-wasm-bindings-crate.md (baseline) and
.plans/pdfx4-engine/issues/115-wasm-asset-resolver-crossing.md
(resolver crossing) for the full rationale.
Build (browser bundle)
wasm-pack build crates/engine-wasm --target web --out-dir ../../examples/web-ui/pkg --releaseThis produces examples/web-ui/pkg/engine_wasm_bg.wasm plus the
engine_wasm.js glue module. Serve the demo UI with any static server:
python3 -m http.server 4173 --directory examples/web-uiThe pkg/ output directory is git-ignored.
Build (raw .wasm, no JS glue)
For CI gate parity with the issue spec — no wasm-pack required:
cargo build -p engine-wasm --target wasm32-unknown-unknown --locked --releaseArtefact at target/wasm32-unknown-unknown/release/engine_wasm.wasm.
Size budget
SPECIFICATION.md §4.2: < 5 MB compressed (target; < 10 MB acceptable).
gzip is the number that matters — it's what npm reports and what CDNs serve
by default; brotli sits well under it but can't be relied on to be negotiated.
The shipped artefact is the @otisk/preview bundle: wasm-pack build --release
--features raster-preview (the tiny-skia raster backend + the usvg/resvg/
fontdb SVG stack). Measured sizes:
| build | raw | gzip | brotli |
|---|---|---|---|
| default features | 7.6 MB | 3.5 MB | 2.7 MB |
| raster-preview (published) | 10.0 MB | 4.54 MB ✅ | 2.9 MB |
The size comes from the Cargo release profile, not wasm-opt — wasm-pack
already runs wasm-opt -O, and forcing -Oz moves gzip by < 0.1%. The lever is
the workspace [profile.release] (root Cargo.toml): opt-level = "s",
lto = true, codegen-units = 1, strip = true. Without it (cargo defaults:
no LTO, codegen-units = 16, symbols retained) the raster-preview bundle is
~5.09 MB gzip — over budget. The native gpx binary opts out of these size
settings via its own gpx-release profile (see the profile rationale in the
root Cargo.toml), so shrinking the bundle never costs native throughput.
Host-target build
The crate is also exposed as an rlib so cargo build -p engine-wasm
on the host triple works (useful for cargo doc, future host-side
integration tests, and IDE indexing). The cdylib artefact only matters
for the wasm32-unknown-unknown target.
parity_export feature (Issue 31)
The crate ships a second WASM entry point — a raw C-ABI
render_pdf_raw — gated behind the parity_export feature. The Phase 2
parity harness (crates/otisk/tests/wasm_parity.rs) builds the artefact
with --no-default-features --features parity_export and drives it
through wasmtime without the wasm-bindgen JS glue. This surface is
internal — the wire format is not a stability contract, and browser
hosts should always use the default render_pdf.
cargo build -p engine-wasm --target wasm32-unknown-unknown \
--no-default-features --features parity_export --release