pdfium-syntax-document-loading
Loading a PDF is the first operation after binding a Pdfium instance. Every
loader returns Result<PdfDocument<'a>, PdfiumError>, where 'a is the borrow
of the Pdfium. pdfium-render 0.9.x exposes four native loaders, two
WASM-only loaders, and create_new_pdf for a blank document.
Scope: how to open and create documents. For binding the library see
pdfium-core-bindings-setup; for lifetime and struct-storage rules see
pdfium-core-memory; for saving see pdfium-impl-saving.
Quick Reference
Loader table (0.9.x)
| Loader | Input | Sync or async | Document borrows | Use when |
|---|---|---|---|---|
load_pdf_from_file |
filesystem path | sync | the Pdfium |
the PDF is a file on a native target |
load_pdf_from_byte_slice |
&'a [u8] |
sync | Pdfium AND the slice |
bytes outlive the document; no copy wanted |
load_pdf_from_byte_vec |
Vec<u8> |
sync | the Pdfium only |
bytes are owned and moved into the document |
load_pdf_from_reader |
R: Read + Seek |
sync | the Pdfium |
the PDF is behind a seekable stream |
load_pdf_from_fetch |
URL | async | the Pdfium |
browser WASM build, load by URL |
load_pdf_from_blob |
browser Blob |
async | the Pdfium |
browser WASM build, load from a Blob |
create_new_pdf |
nothing | sync | the Pdfium |
building a PDF from scratch |
Every loader returns Result<PdfDocument<'a>, PdfiumError>.
The password argument
ALWAYS pass the password as the LAST argument, typed password: Option<&str>,
on EVERY native loader:
Some("secret")opens an encrypted (password-protected) PDF.Noneopens an unencrypted PDF.
There is NO load_pdf_with_password, no *_encrypted loader, and no separate
decrypt step. The password is one uniform parameter. Searching for a dedicated
password function is the most common wrong assumption; it does not exist.
Core rules
- ALWAYS call a loader on a
Pdfiuminstance that outlives the returnedPdfDocument(seepdfium-core-memory). - NEVER use
load_pdf_from_bytes: it was removed in 0.9.0. Useload_pdf_from_byte_sliceorload_pdf_from_byte_vec. - ALWAYS use
load_pdf_from_byte_vecwhen the byte buffer is a local value that would drop before the document. - NEVER call
load_pdf_from_filein a browser WASM build: there is no filesystem. Useload_pdf_from_fetchorload_pdf_from_blob. - ALWAYS treat a wrong password or a corrupt file as a recoverable
PdfiumError, not a panic. Match the result.
Decision Trees
Which loader do I use?
Where is the PDF data?
A file on disk, native target -> load_pdf_from_file
Already in memory as bytes ...
can the buffer outlive the document?
YES -> load_pdf_from_byte_slice (no copy: document borrows the slice)
NO -> load_pdf_from_byte_vec (document takes ownership of the Vec)
Behind a stream that is Read + Seek -> load_pdf_from_reader
A URL, in a browser WASM build -> load_pdf_from_fetch (async)
A browser Blob, in a WASM build -> load_pdf_from_blob (async)
There is no PDF yet, you are creating one -> create_new_pdf
A plain network or pipe stream that is NOT Seek cannot feed
load_pdf_from_reader. Read it fully into a Vec<u8> first and use
load_pdf_from_byte_vec.
How do I handle the password?
Is the PDF encrypted?
Known encrypted -> pass Some("the-password")
Known unencrypted -> pass None
Unknown ...
load with None, then match the PdfiumError. On the password-error
variant, prompt for a password and retry the SAME loader with Some(...).
Do NOT guess: retry only on the password error, not on every error.
Patterns
Pattern 1: Load from a file (native)
use pdfium_render::prelude::*;
fn open_file(pdfium: &Pdfium, path: &str) -> Result<PdfDocument<'_>, PdfiumError> {
pdfium.load_pdf_from_file(path, None)
}
The path parameter is &(impl AsRef<Path> + ?Sized), so a &str, &Path,
or &PathBuf all work. This loader is unavailable in WASM builds.
Pattern 2: byte_slice versus byte_vec
// byte_slice: the document ALSO borrows the buffer; both share 'a. No copy.
// The buffer MUST outlive the document.
fn from_slice<'a>(pdfium: &'a Pdfium, buffer: &'a [u8])
-> Result<PdfDocument<'a>, PdfiumError> {
pdfium.load_pdf_from_byte_slice(buffer, None)
}
// byte_vec: the document OWNS the Vec. Nothing else has to stay alive.
fn from_vec(pdfium: &Pdfium, bytes: Vec<u8>)
-> Result<PdfDocument<'_>, PdfiumError> {
pdfium.load_pdf_from_byte_vec(bytes, None)
}
Choosing byte_slice for a locally produced buffer causes a "does not live
long enough" compile error; see references/anti-patterns.md and
pdfium-core-memory.
Pattern 3: Load from a seekable reader
use std::fs::File;
use pdfium_render::prelude::*;
fn open_reader(pdfium: &Pdfium, path: &str) -> Result<PdfDocument<'_>, PdfiumError> {
let file = File::open(path).map_err(PdfiumError::IoError)?;
pdfium.load_pdf_from_reader(file, None)
}
The reader type must be Read + Seek. File and Cursor<Vec<u8>> qualify; a
bare TCP stream does not.
Pattern 4: Open a password-protected PDF
fn open_encrypted<'a>(pdfium: &'a Pdfium, path: &str, password: &str)
-> Result<PdfDocument<'a>, PdfiumError> {
pdfium.load_pdf_from_file(path, Some(password))
}
When the encryption status is unknown, load with None, match the error, and
retry with Some(...) only on the password error. Full recovery code is in
references/examples.md; exact error variants are in pdfium-errors-runtime.
Pattern 5: Create a blank document
fn new_document(pdfium: &Pdfium) -> Result<PdfDocument<'_>, PdfiumError> {
pdfium.create_new_pdf()
}
create_new_pdf returns an empty PdfDocument with zero pages. Add pages and
content with pages_mut() and the page-object APIs (see
pdfium-impl-page-manipulation and pdfium-impl-page-objects-edit), then save
with pdfium-impl-saving.
Pattern 6: Load in a browser WASM build
#[cfg(target_arch = "wasm32")]
async fn open_url(pdfium: &Pdfium, url: &str) -> Result<PdfDocument<'_>, PdfiumError> {
pdfium.load_pdf_from_fetch(url, None).await
}
load_pdf_from_fetch and load_pdf_from_blob are async and exist for the
browser, where there is no filesystem. WASM packaging, the growable-heap
binary, and the console_log feature are covered in pdfium-impl-wasm.
Version Notes: 0.8.x vs 0.9.x
load_pdf_from_byteswas deprecated in 0.7.26 and REMOVED in 0.9.0. Code that still calls it will not compile on 0.9.x. Replace it: pass a&[u8]toload_pdf_from_byte_slice, or pass an ownedVec<u8>toload_pdf_from_byte_vec.load_pdf_from_byte_sliceandload_pdf_from_byte_vecexist across the 0.8.x and 0.9.x lines and are the supported replacements.- 0.9.0 simplified lifetime handling; the loader signatures above are the 0.9.x surface. Default all new code to them.
Anti-Patterns (summary)
| Anti-pattern | Why it fails | Fix |
|---|---|---|
load_pdf_from_bytes(...) |
removed in 0.9.0 | load_pdf_from_byte_slice or load_pdf_from_byte_vec |
hunting for load_pdf_with_password |
no such function exists | pass Some(password) to any loader |
load_pdf_from_byte_slice with a local buffer |
document borrows a buffer that drops first | load_pdf_from_byte_vec (moves ownership) |
load_pdf_from_file in a WASM build |
no filesystem in the browser | load_pdf_from_fetch / load_pdf_from_blob |
.unwrap() on a loader result |
wrong password or corrupt file panics the program | match the PdfiumError and recover |
Full failure transcripts and fixes are in references/anti-patterns.md.
Reference Files
references/methods.md: exact verified signatures, lifetime parameters, and version annotations for every loader andcreate_new_pdf.references/examples.md: complete, verified Rust programs for each loader, the password-recovery flow, and the WASM loaders.references/anti-patterns.md: each loading failure with the error it produces, WHY it fails, and the corrected code.
Related Skills
pdfium-core-bindings-setup: obtaining and binding thePdfiuminstance.pdfium-core-memory: the lifetime of the returnedPdfDocument, byte-slice versus byte-vec ownership, and struct storage.pdfium-impl-saving:save_to_file/save_to_writer/save_to_bytes.pdfium-impl-wasm: browser WASM packaging and the async loaders.pdfium-errors-runtime: thePdfiumErrorvariants for wrong password, corrupt file, and other load failures.