| name | pdfium-impl-wasm |
| description | Use when compiling a Rust application that uses pdfium-render to WebAssembly to run PDF rendering or inspection in a browser, when loading a PDF without a filesystem, or when diagnosing a WASM-only failure such as an out-of-memory crash, "Unable to locate wasmTable", or corrupted bitmap output. Prevents shipping the non-growable bblanchon WASM heap, calling filesystem loaders that do not exist in the browser, and using the memory-unsafe raw WASM bitmap buffer accessor. Covers the two-WASM-module architecture, bind_to_system_library in the browser, load_pdf_from_fetch and load_pdf_from_blob, the console_log feature, and safe bitmap buffer reads across pdfium-render 0.8.x and 0.9.x. Keywords: pdfium-render, WASM, WebAssembly, browser, wasm-pack, wasm-bindgen, load_pdf_from_fetch, load_pdf_from_blob, console_log, bind_to_system_library, paulocoutinhox, bblanchon, non-growable heap, out of memory, OOM, Unable to locate wasmTable, Module._malloc not defined, FPDFBitmap_GetBuffer, corrupted image, blank canvas in browser, how do I run pdfium in a browser, how to render a PDF in WASM.
|
| license | MIT |
| compatibility | Designed for Claude Code. Requires pdfium-render 0.8,0.9. |
| metadata | {"author":"OpenAEC-Foundation","version":"1.0"} |
pdfium-render: WebAssembly
Running pdfium-render in a browser. WASM is a first-class but delicate target:
PDFium is C++ and ships as its own WASM module, the browser has no filesystem, and
two of the most common pdfium-render failures only ever appear on WASM. This skill
owns the WASM target. General binding is pdfium-core-bindings-setup; general
document loading is pdfium-syntax-document-loading.
All API names below are verified against docs.rs/pdfium-render 0.9.1 and the
pdfium-render README. The default target is the 0.9.x API; 0.8.x differences are
flagged inline.
The Two-Module Architecture
A pdfium-render WASM application is ALWAYS two separate WASM modules:
- Your Rust application compiled to WASM (via
wasm-pack / wasm-bindgen).
- A prebuilt PDFium WASM module, packaged separately, NOT linked into module 1.
The PDFium WASM module must be loaded by the browser FIRST so its exported
functions exist. Your Rust module then binds to those exports at run time. This is
exactly why pdfium-render uses run-time binding: a compiled-in static PDFium is not
possible for the browser.
NEVER expect to bundle PDFium into your Rust .wasm. ALWAYS ship the PDFium WASM
module as a separate asset and load it before your application module.
Quick Reference
| Goal | API / artifact | Notes |
|---|
| Bind in the browser | Pdfium::bind_to_system_library() | binds to the separate PDFium WASM module |
| Load a PDF by URL | Pdfium::load_pdf_from_fetch(url, password) | async, browser only |
| Load a PDF from a Blob | Pdfium::load_pdf_from_blob(blob, password) | async, browser only |
| Route logs to the console | console_log crate feature | added 0.9.1 |
| Read a bitmap buffer (raw FFI) | FPDFBitmap_GetBuffer_as_vec / _as_array | NEVER raw FPDFBitmap_GetBuffer |
| PDFium WASM build | paulocoutinhox/pdfium-lib | growable heap |
Full signatures: see references/methods.md.
Decision Tree
Which prebuilt PDFium WASM build?
-> ALWAYS paulocoutinhox/pdfium-lib (growable heap)
-> NEVER bblanchon WASM build (non-growable heap, OOMs past a few pages)
How does the user supply the PDF?
-> from a URL -> load_pdf_from_fetch(url, password).await
-> from a <input file> -> get a Blob, load_pdf_from_blob(blob, password).await
-> NEVER load_pdf_from_file: no filesystem in the browser
Need PDFium log output?
-> enable the `console_log` feature
Dropping to raw FFI for bitmap bytes?
-> FPDFBitmap_GetBuffer_as_vec / _as_array
-> NEVER the raw FPDFBitmap_GetBuffer (memory-unsafe on WASM, issue #174)
Pattern: Cargo.toml for a WASM Build
[lib]
crate-type = ["cdylib"]
[dependencies]
pdfium-render = { version = "0.9", features = ["console_log"] }
wasm-bindgen = "0.2"
wasm-bindgen-futures = "0.4"
web-sys = { version = "0.3", features = ["Blob"] }
crate-type = ["cdylib"] is required for a wasm-bindgen target.
console_log is the only pdfium-render feature specific to WASM; the default
pdfium_latest, image_latest, and thread_safe features still apply.
- Build with the standard
wasm-bindgen toolchain, for example
wasm-pack build --target web. The canonical, end-to-end setup including the
HTML harness is the examples/ directory of the pdfium-render repository.
Pattern: Bind in the Browser
In the browser Pdfium::bind_to_system_library() is the binding entry point. It
binds to the PDFium functions the separately loaded PDFium WASM module exported.
use pdfium_render::prelude::*;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub async fn render_first_page(url: String) -> Result<(), JsValue> {
let bindings = Pdfium::bind_to_system_library()
.map_err(|e| JsValue::from_str(&e.to_string()))?;
let pdfium = Pdfium::new(bindings);
let document = pdfium.load_pdf_from_fetch(url, None).await
.map_err(|e| JsValue::from_str(&e.to_string()))?;
let _ = document.pages().len();
Ok(())
}
NEVER use bind_to_library(path) on WASM: there is no filesystem path to a .so /
.dll in the browser. NEVER use bind_to_statically_linked_library(): PDFium
cannot be statically linked into a browser WASM module.
Pattern: Load a PDF by URL
load_pdf_from_fetch is the browser replacement for load_pdf_from_file. It is an
async function and fetches the PDF over HTTP:
pub async fn load_pdf_from_fetch<'a>(
&'a self,
url: impl ToString,
password: Option<&str>,
) -> Result<PdfDocument<'a>, PdfiumError>
let document = pdfium.load_pdf_from_fetch("/files/report.pdf", None).await?;
password is the same uniform Option<&str> parameter as every other loader (see
pdfium-syntax-document-loading): pass Some("secret") for an encrypted PDF.
Pattern: Load a PDF from a Blob
load_pdf_from_blob loads a PDF the user picked through a <input type="file">
element or produced in JavaScript. The blob is a web_sys::Blob:
pub async fn load_pdf_from_blob<'a>(
&'a self,
blob: Blob,
password: Option<&str>,
) -> Result<PdfDocument<'a>, PdfiumError>
#[wasm_bindgen]
pub async fn open_uploaded(blob: web_sys::Blob) -> Result<(), JsValue> {
let pdfium = Pdfium::new(
Pdfium::bind_to_system_library()
.map_err(|e| JsValue::from_str(&e.to_string()))?,
);
let document = pdfium.load_pdf_from_blob(blob, None).await
.map_err(|e| JsValue::from_str(&e.to_string()))?;
let _ = document.pages().len();
Ok(())
}
The console_log Feature
The console_log crate feature (added in 0.9.1) makes pdfium-render initialize
console_log-based logging to the browser developer console. Enable it when you
have not set up console_log yourself. It is purely a WASM diagnostics aid and has
no effect on native builds.
ALWAYS enable console_log while bringing up a WASM build: without it, binding and
load failures surface as opaque JsValue errors with no context in the console.
Reading Bitmap Buffers Safely
Most code reads rendered pixels through the high-level PdfBitmap accessors
(as_image(), as_rgba_bytes(), as_raw_bytes(); see pdfium-syntax-rendering).
Those are safe on WASM. Only raw-FFI code touches the bitmap buffer directly.
On WASM the raw FPDFBitmap_GetBuffer accessor was memory-unsafe: it could
overwrite image data (issue #174). It is unsafe and superseded.
ALWAYS use the safe provided methods on PdfiumLibraryBindings when you must read a
bitmap buffer in raw FFI: FPDFBitmap_GetBuffer_as_vec,
FPDFBitmap_GetBuffer_as_array, or FPDFBitmap_GetBuffer_as_slice. NEVER call the
raw FPDFBitmap_GetBuffer on WASM. Raw FFI in general is pdfium-core-raw-ffi.
Version Traps
| Item | 0.8.x | 0.9.x | Action |
|---|
console_log feature | absent | added 0.9.1 | enable for WASM diagnostics on 0.9.1+ |
raw WASM FPDFBitmap_GetBuffer | memory-unsafe | superseded, unsafe | use _as_vec / _as_array |
load_pdf_from_bytes | deprecated 0.7.26 | REMOVED 0.9.0 | use load_pdf_from_byte_slice / _vec |
Anti-Patterns (summary)
- Shipping the bblanchon WASM PDFium build: non-growable heap, OOM crash past a few
pages (issue #13). Use the paulocoutinhox build.
- Calling
load_pdf_from_file on WASM: there is no browser filesystem.
- Version-mismatching your Rust module and the PDFium WASM build: produces
"Unable to locate wasmTable" / "Module._malloc() not defined" (issues #134, #128,
#95).
- Using the raw
FPDFBitmap_GetBuffer on WASM (issue #174).
- Binding before the PDFium WASM module has loaded.
Each anti-pattern with the failure detail and fix: see references/anti-patterns.md.
Cross-References
pdfium-core-bindings-setup: the three bind functions, prebuilt-binary sources,
feature flags. WASM uses bind_to_system_library().
pdfium-syntax-document-loading: the full loader family and the uniform
password: Option<&str> parameter.
pdfium-syntax-rendering: PdfBitmap and its safe pixel accessors.
pdfium-core-raw-ffi: the PdfiumLibraryBindings trait and raw FPDF_* calls.
pdfium-errors-binding: diagnosing a failed bind.
pdfium-impl-performance: memory cost of rendering, relevant to the WASM heap.
Reference Files
references/methods.md: complete API signatures and feature flags.
references/examples.md: verified Rust + WASM code.
references/anti-patterns.md: real WASM failures, why they fail, the fix.
Source
Verified 2026-05-20 against https://docs.rs/pdfium-render/latest/pdfium_render/
(crate root, Pdfium prelude page, PdfiumLibraryBindings trait page) and the
pdfium-render README WASM section. WASM anti-patterns (issues #13, #174, #134,
#128, #95) are recorded in vooronderzoek-pdfium.md sections 8 and 9.