| name | pdfium-impl-multi-page |
| description | Use when merging, concatenating, splitting, extracting, or reordering pages across PDF documents with pdfium-render: combining several PDFs into one, pulling a page subset into a new file, or rearranging page order. Prevents the wrong-method-name mistake (the import_page_from_document family does not exist; the real names are the copy_*_from_document family), the index-base confusion (copy_pages_from_document takes a 1-indexed string while the numeric functions are 0-indexed), and the wrong-receiver mistake (append lives on PdfPages, not PdfDocument). Covers append, copy_page_from_document, copy_page_range_from_document, copy_pages_from_document, pages_mut, and the PdfPageIndex type change. Keywords: pdfium-render merge PDFs, concatenate PDF, combine PDF files, split PDF, extract pages, reorder pages, copy_pages_from_document, copy_page_from_document, copy_page_range_from_document, append, pages_mut, import_page_from_document not found, how do I merge two PDFs, join PDF pages, page index out of bounds, 1-indexed page range
|
| license | MIT |
| compatibility | Designed for Claude Code. Requires pdfium-render 0.8,0.9. |
| metadata | {"author":"OpenAEC-Foundation","version":"1.0"} |
pdfium-impl-multi-page
This skill covers moving whole pages between PDF documents with pdfium-render:
merging several files into one, extracting a subset of pages into a new file,
and reordering pages. Every operation works on the destination document's
mutable page collection, reached with document.pages_mut().
Scope boundary: deleting, rotating, and resizing pages within a single document
is pdfium-impl-page-manipulation. Copying individual page objects (text,
images, paths) between pages is pdfium-impl-page-objects-edit. This skill
handles whole-page transfer.
Default API surface: pdfium-render 0.9.x. Version notes for 0.8.x are inline
and collected in the version table.
The four operations
ALWAYS use one of these four verified PdfPages methods. The destination is the
collection from document.pages_mut().
| Operation | Method | Page selection |
|---|
| Copy all pages of another document | append(&source) | every page |
| Copy one page | copy_page_from_document(&source, src_idx, dest_idx) | one 0-indexed page |
| Copy a contiguous range | copy_page_range_from_document(&source, 0..=n, dest_idx) | 0-indexed RangeInclusive |
| Copy a scattered selection | copy_pages_from_document(&source, "1,3-4,7", dest_idx) | 1-indexed string |
All four return Result<(), PdfiumError>. Full signatures: references/methods.md.
The wrong-name trap
The methods are named copy_page_from_document, copy_page_range_from_document,
and copy_pages_from_document. There is NO import_page_from_document,
import_page_range_from_document, or import_pages_from_document. Those names
do not exist in any 0.8.x or 0.9.x release; code using them does not compile.
Verified against the docs.rs prelude pages for both 0.8.37 and the current
0.9.x line. ALWAYS use the copy_*_from_document names.
The index-base trap
The page-selection argument changes base between methods. Mixing them up copies
the wrong pages silently or returns PageIndexOutOfBounds.
| Method | Argument | Base | Example for the first three pages |
|---|
copy_page_from_document | source_page_index: PdfPageIndex | 0-indexed | 0, then 1, then 2 |
copy_page_range_from_document | source_page_range: RangeInclusive<PdfPageIndex> | 0-indexed, inclusive | 0..=2 |
copy_pages_from_document | pages: &str | 1-indexed string | "1-3" or "1,2,3" |
The destination_page_index argument on all three is always 0-indexed: it is
the position in the destination collection where the copied pages are inserted.
Inserting at the end
append always adds to the end. For the copy_* functions, pass the current
destination length as destination_page_index to insert after the last page:
let dest_len = document.pages().len();
document.pages_mut()
.copy_page_from_document(&source, 0, dest_len)?;
PdfPages::len() returns a PdfPageIndex, the exact type the destination
argument expects, so no cast is needed.
Decision tree
Moving whole pages between or within documents?
|
+-- Combining entire documents back to back?
| -> for each source: document.pages_mut().append(&source)
|
+-- Copying a contiguous block (pages 5 through 9)?
| -> copy_page_range_from_document(&source, 4..=8, dest_idx) // 0-indexed
|
+-- Copying scattered pages (1, 3, 4, 7)?
| -> copy_pages_from_document(&source, "1,3-4,7", dest_idx) // 1-indexed
|
+-- Copying exactly one page?
| -> copy_page_from_document(&source, src_idx, dest_idx) // 0-indexed
|
+-- Splitting or extracting into a NEW file?
| -> pdfium.create_new_pdf(), copy the wanted pages in, save
|
+-- Reordering pages of ONE document?
| -> create_new_pdf(), copy pages in the target order, save
|
+-- Deleting / rotating pages in place?
-> not this skill; see pdfium-impl-page-manipulation
Pattern: merge several PDFs into one
use pdfium_render::prelude::*;
let pdfium = Pdfium::default();
let mut merged = pdfium.create_new_pdf()?;
for path in ["a.pdf", "b.pdf", "c.pdf"] {
let source = pdfium.load_pdf_from_file(path, None)?;
merged.pages_mut().append(&source)?;
}
merged.save_to_file("merged.pdf")?;
Each source document must stay alive only for the duration of its append
call. append copies the pages into merged, so dropping source afterwards
is safe.
Pattern: extract a page subset into a new document
use pdfium_render::prelude::*;
let pdfium = Pdfium::default();
let source = pdfium.load_pdf_from_file("report.pdf", None)?;
let mut extract = pdfium.create_new_pdf()?;
extract.pages_mut()
.copy_pages_from_document(&source, "1,3-4,7", 0)?;
extract.save_to_file("extract.pdf")?;
Pattern: reorder the pages of one document
pdfium-render has no in-place page-move method. Reorder by copying pages into a
fresh document in the wanted order.
use pdfium_render::prelude::*;
let pdfium = Pdfium::default();
let source = pdfium.load_pdf_from_file("input.pdf", None)?;
let mut reordered = pdfium.create_new_pdf()?;
for src_index in [2, 0, 1] {
let dest = reordered.pages().len();
reordered.pages_mut()
.copy_page_from_document(&source, src_index, dest)?;
}
reordered.save_to_file("reordered.pdf")?;
Pattern: split one document into single-page files
use pdfium_render::prelude::*;
let pdfium = Pdfium::default();
let source = pdfium.load_pdf_from_file("input.pdf", None)?;
let page_count = source.pages().len();
for index in 0..page_count {
let mut single = pdfium.create_new_pdf()?;
single.pages_mut()
.copy_page_from_document(&source, index, 0)?;
single.save_to_file(format!("page-{index}.pdf"))?;
}
Version table
| Item | 0.8.x | 0.9.x |
|---|
append, copy_page_from_document, copy_page_range_from_document, copy_pages_from_document | present (verified on 0.8.37) | present |
| Receiver of all four methods | PdfPages (via pages_mut()) | PdfPages |
import_*_from_document names | do not exist | do not exist |
PdfPageIndex underlying type | u16 | c_int since 0.9.0 |
pages_mut() | present since 0.8.0 | present |
The PdfPageIndex type changed from u16 to c_int in 0.9.0. Code that wrote
the index type explicitly (let i: u16 = ...) breaks on upgrade. ALWAYS let
the index type be inferred, or write PdfPageIndex.
Critical rules
- ALWAYS use the
copy_*_from_document names. The import_*_from_document
family does not exist in pdfium-render.
- ALWAYS call these methods on
document.pages_mut(), never on pages().
- ALWAYS treat
copy_pages_from_document's string as 1-indexed, and the numeric
index and range functions as 0-indexed.
- ALWAYS save the destination document with
pdfium-impl-saving after copying.
In-memory page changes are lost otherwise.
- NEVER call
append on a PdfDocument. append is a PdfPages method.
- NEVER pin the index type to
u16. Use PdfPageIndex or inference so the
code survives the 0.9.0 type change.
Companion skills
pdfium-syntax-document-loading for loading sources and create_new_pdf.
pdfium-impl-saving for persisting the merged or extracted document.
pdfium-impl-page-manipulation for deleting, rotating, resizing pages.
pdfium-impl-page-objects-edit for copying page objects, not whole pages.
pdfium-syntax-pages for pages(), len(), iter(), get().
pdfium-errors-runtime for PdfiumError and PageIndexOutOfBounds.
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 happen, and the fix.