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()?;
// 1-indexed string: pages 1, 3, 4 and 7 of the source.
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()?;
// Original order is 0,1,2; produce 2,0,1.
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_documentnames. Theimport_*_from_documentfamily does not exist in pdfium-render. - ALWAYS call these methods on
document.pages_mut(), never onpages(). - 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-savingafter copying. In-memory page changes are lost otherwise. - NEVER call
appendon aPdfDocument.appendis aPdfPagesmethod. - NEVER pin the index type to
u16. UsePdfPageIndexor inference so the code survives the 0.9.0 type change.
Companion skills
pdfium-syntax-document-loadingfor loading sources andcreate_new_pdf.pdfium-impl-savingfor persisting the merged or extracted document.pdfium-impl-page-manipulationfor deleting, rotating, resizing pages.pdfium-impl-page-objects-editfor copying page objects, not whole pages.pdfium-syntax-pagesforpages(),len(),iter(),get().pdfium-errors-runtimeforPdfiumErrorandPageIndexOutOfBounds.
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.