# Pdfium Syntax Document Loading

> Use when opening a PDF with pdfium-render, choosing between load_pdf_from_file, load_pdf_from_byte_slice, load_pdf_from_byte_vec or load_pdf_from_reader, opening a password-protected PDF, creating a blank PDF, or loading a PDF in a browser WASM build. Prevents using the removed load_pdf_from_bytes and searching for a non-existent load_pdf_with_password function. Covers the four native loaders, the uniform password Option argument, create_new_pdf, byte-slice versus byte-vec ownership, and the WASM-only load_pdf_from_fetch and load_pdf_from_blob loaders. Keywords: pdfium-render load PDF, load_pdf_from_file, load_pdf_from_byte_slice, load_pdf_from_byte_vec, load_pdf_from_reader, load_pdf_from_bytes removed, password protected PDF, load_pdf_with_password does not exist, create_new_pdf, how do I open a PDF in Rust, my PDF will not open, encrypted PDF, WASM load PDF, load_pdf_from_fetch, load_pdf_from_blob

- Skill: `impertio-studio/pdfium-syntax-document-loading` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add impertio-studio/pdfium-syntax-document-loading`
- Raw SKILL.md: https://api.skillmd.com/api/skills/impertio-studio/pdfium-syntax-document-loading/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Docs & Writing
- License: MIT
- Author: Impertio-Studio (https://skillmd.com/u/impertio-studio)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/impertio-studio/pdfium-syntax-document-loading

---


# 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.
- `None` opens 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 `Pdfium` instance that outlives the returned
  `PdfDocument` (see `pdfium-core-memory`).
- NEVER use `load_pdf_from_bytes`: it was removed in 0.9.0. Use
  `load_pdf_from_byte_slice` or `load_pdf_from_byte_vec`.
- ALWAYS use `load_pdf_from_byte_vec` when the byte buffer is a local value
  that would drop before the document.
- NEVER call `load_pdf_from_file` in a browser WASM build: there is no
  filesystem. Use `load_pdf_from_fetch` or `load_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?

```text
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?

```text
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)

```rust
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

```rust
// 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

```rust
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

```rust
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

```rust
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

```rust
#[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_bytes` was 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]` to
  `load_pdf_from_byte_slice`, or pass an owned `Vec<u8>` to
  `load_pdf_from_byte_vec`.
- `load_pdf_from_byte_slice` and `load_pdf_from_byte_vec` exist 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 and `create_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 the `Pdfium` instance.
- `pdfium-core-memory`: the lifetime of the returned `PdfDocument`, 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`: the `PdfiumError` variants for wrong password,
  corrupt file, and other load failures.

