| name | pdfium-impl-saving |
| description | 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
|
| license | MIT |
| compatibility | Designed for Claude Code. Requires pdfium-render 0.8,0.9. |
| metadata | {"author":"OpenAEC-Foundation","version":"1.0"} |
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
let pdfium = Pdfium::default();
let document = pdfium.load_pdf_from_file("in.pdf", None)?;
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
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
use std::fs::File;
let mut file = File::create("out.pdf").map_err(PdfiumError::IoError)?;
document.save_to_writer(&mut file)?;
let mut buffer: Vec<u8> = Vec::new();
document.save_to_writer(&mut buffer)?;
Pattern 4: Save a newly created document
let document = pdfium.create_new_pdf()?;
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
let document = pdfium.load_pdf_from_file("in.pdf", None)?;
document.save_to_file("out.pdf")?;
Pattern 6: Save to a Blob on WASM
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.