# Pdfium Impl Saving

> Use when persisting a pdfium-render PdfDocument to disk, to bytes, to a writer, or to a browser Blob, and when edits like form fills or object changes are not appearing in the output file. Prevents the save_to_writer 'static borrow-checker error, confusing PDF saving with image export, losing in-memory edits by never calling save, and calling the WASM-only save_to_blob on a native target. Covers save_to_file, save_to_writer, save_to_bytes, save_to_blob, the 'static writer bound, and saving after create_new_pdf or after edits. Keywords: pdfium-render save PDF, save_to_file, save_to_writer, save_to_bytes, save_to_blob, persist PdfDocument, write PDF to disk, PDF to Vec u8, export PDF, 'static bound writer, writer may not live long enough, borrowed value does not live long enough, edits not saved, changes lost, form fill not saved, save document after create_new_pdf, how do I save a PDF in Rust

- Skill: `impertio-studio/pdfium-impl-saving` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add impertio-studio/pdfium-impl-saving`
- Raw SKILL.md: https://api.skillmd.com/api/skills/impertio-studio/pdfium-impl-saving/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-impl-saving

---


# pdfium-impl-saving

Persist a `PdfDocument` with pdfium-render: to a file, to an owned `Vec<u8>`,
to any `Write` implementation, or to a browser `Blob`. This skill also covers
WHEN to save, because every edit pdfium-render makes is in-memory until a save
call commits it.

Scope: writing a PDF document back out. For loading see
`pdfium-syntax-document-loading`. For rendering a page to an image (a different
operation) see `pdfium-syntax-rendering` and `pdfium-impl-output-formats`.

Default API surface is 0.9.x. Document creation and saving landed in 0.7.0.

## The one rule that dominates this area

Every edit pdfium-render makes, a form fill, an added page object, a rotation,
lives ONLY in the in-memory `PdfDocument`. Dropping the document without a save
call discards all of it. pdfium-render NEVER writes back to the source file
implicitly. The save call is the single commit point.

## Quick Reference

### The four save methods

All four are methods on `PdfDocument`, all take `&self`, all return
`Result<_, PdfiumError>`.

| Method | Signature | Use for |
|--------|-----------|---------|
| `save_to_file` | `save_to_file(&self, path: &(impl AsRef<Path> + ?Sized))` | writing to the native filesystem |
| `save_to_bytes` | `save_to_bytes(&self) -> Result<Vec<u8>, PdfiumError>` | in-memory output, networks, databases, every target |
| `save_to_writer` | `save_to_writer<W: Write + 'static>(&self, writer: &mut W)` | streaming into an owned `Write` |
| `save_to_blob` | `save_to_blob(&self) -> Result<Blob, PdfiumError>` | WASM only: browser download |

Full signatures and version annotations: `references/methods.md`.

### Decision tree

```
Writing to disk on a native target?
  -> save_to_file(path)

Need the PDF as bytes (HTTP body, DB blob, in-memory pipeline)?
  -> save_to_bytes()            (no lifetime bounds, simplest, all targets)

Streaming into a specific owned writer (File handle, compressor)?
  -> save_to_writer(&mut writer)   (writer MUST be 'static: own its data)

Compiling to WASM, need a browser download?
  -> save_to_blob()             (does not exist on native targets)
```

ALWAYS prefer `save_to_bytes()` for plain in-memory output. It carries no
lifetime bounds and sidesteps the `save_to_writer` `'static` requirement.

## The save_to_writer 'static bound

`save_to_writer<W: Write + 'static>` has two bounds. `W: Write` is expected.
`W: 'static` is the one that surprises callers.

WHY THE BOUND EXISTS: pdfium-render hands the writer across the FFI boundary
into PDFium's C save callback. The `'static` bound guarantees the writer holds
NO borrowed references that could dangle during that callback.

CONSEQUENCE: the writer type must own all its data.

| Writer type | `'static`? | Works with save_to_writer? |
|-------------|------------|----------------------------|
| `Vec<u8>` | yes | yes |
| `std::fs::File` | yes | yes |
| `Cursor<Vec<u8>>` | yes | yes |
| `Cursor<&mut Vec<u8>>` | no (borrows) | no, compile error |
| `BufWriter<&mut File>` | no (borrows) | no, compile error |

The error reads "the parameter type `W` may not live long enough" or "borrowed
value does not live long enough". The fix is always: give the writer ownership,
or switch to `save_to_bytes()`.

The argument is `&mut W`. Pass a mutable reference and read the result back from
the same writer after the call returns.

## Patterns

Condensed patterns below. Complete runnable code is in `references/examples.md`.

### Pattern 1: Save to a file

```rust
let pdfium = Pdfium::default();
let document = pdfium.load_pdf_from_file("in.pdf", None)?;
// ... edits ...
document.save_to_file("out.pdf")?;
```

`save_to_file` accepts any `AsRef<Path>`: a `&str`, `String`, `Path`, or
`PathBuf`. It is unavailable on WASM, which has no filesystem.

### Pattern 2: Save to bytes

```rust
let bytes: Vec<u8> = document.save_to_bytes()?;
```

The shortest path for an HTTP response body, a database blob, or any in-memory
consumer. Works on every target including WASM.

### Pattern 3: Save through a writer

```rust
use std::fs::File;

let mut file = File::create("out.pdf").map_err(PdfiumError::IoError)?;
document.save_to_writer(&mut file)?;   // W = File, which is 'static
```

```rust
let mut buffer: Vec<u8> = Vec::new();
document.save_to_writer(&mut buffer)?; // W = Vec<u8>, which is 'static
// the PDF bytes are now in `buffer`
```

### Pattern 4: Save a newly created document

```rust
let document = pdfium.create_new_pdf()?;
// ... add at least one page and its content ...
document.save_to_file("new.pdf")?;
```

`Pdfium::create_new_pdf` yields a blank document. A valid PDF needs at least one
page, so add pages (see `pdfium-impl-multi-page`) before saving.

### Pattern 5: Save after editing

```rust
let document = pdfium.load_pdf_from_file("in.pdf", None)?;
// ... fill form fields, add objects, rotate pages ...
document.save_to_file("out.pdf")?;  // without this line, edits are discarded
```

### Pattern 6: Save to a Blob on WASM

```rust
// wasm32 target only
let blob = document.save_to_blob()?;
```

`save_to_blob` exists only when compiling to WASM. On native targets use
`save_to_bytes`. See `pdfium-impl-wasm`.

## When to save

| After this operation | Save with |
|----------------------|-----------|
| `create_new_pdf()` plus page and object creation | `save_to_file` / `save_to_bytes` |
| Filling form fields (`pdfium-impl-form-fields`) | `save_to_file` / `save_to_bytes` |
| Adding, editing, removing page objects | `save_to_file` / `save_to_bytes` |
| Page rotation, deletion, flatten, merge | `save_to_file` / `save_to_bytes` |
| Copying objects or pages into an existing document | `save_to_file` / `save_to_bytes` |

In every row the save call is mandatory. Skipping it discards the edit.

## Common mistakes

| Mistake | Correct approach |
|---------|------------------|
| `save_to_writer` with `Cursor<&mut Vec<u8>>` | own the data: `Vec<u8>`, `File`, or use `save_to_bytes()` |
| `save_to_file("page.png")` to get an image | saving writes a PDF; render and export via `pdfium-impl-output-formats` |
| Edit then drop the document, no save call | always call a `save_to_*` method to commit |
| `save_to_blob()` on a native target | method is WASM-only; use `save_to_bytes()` natively |
| Save over the source path while it is open | save to a new path, then replace if needed |
| Expect save to rebuild form-field appearances | it does not; verify in the target viewer (#145) |

Each mistake is explained with root cause and fix in
`references/anti-patterns.md`.

## Reference files

- `references/methods.md`: complete API signatures with version annotations.
- `references/examples.md`: working, verified Rust examples.
- `references/anti-patterns.md`: real failures, why they fail, and the fix.

## Related skills

- `pdfium-syntax-document-loading`: loading the document that saving persists.
- `pdfium-core-memory`: lifetimes, ownership, and the `'static` bound rationale.
- `pdfium-impl-form-fields`: the most common edit that must be saved afterward.
- `pdfium-impl-output-formats`: image export, a different operation from saving.
- `pdfium-impl-wasm`: the WASM build path and `save_to_blob`.
- `pdfium-errors-runtime`: handling `PdfiumError` from save calls.

