use crate::capability::Capability;
use crate::document::PdfDocument;
use crate::error::{internal_error, Error, Result};
use crate::license;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[non_exhaustive]
pub enum BookmarkMergeStrategy {
#[default]
Concat,
FlattenAll,
Discard,
}
#[derive(Debug, Clone, Default)]
#[non_exhaustive]
pub struct MergeOptions {
pub(crate) bookmarks: BookmarkMergeStrategy,
pub(crate) page_labels: bool,
}
#[derive(Debug, Default)]
pub struct PdfMerger {
inputs: Vec<PdfDocument>,
opts: MergeOptions,
}
impl PdfMerger {
pub fn new() -> Self {
Self::default()
}
#[allow(clippy::should_implement_trait)]
pub fn add(mut self, doc: PdfDocument) -> Self {
self.inputs.push(doc);
self
}
pub fn with_bookmarks(mut self, strategy: BookmarkMergeStrategy) -> Self {
self.opts.bookmarks = strategy;
self
}
pub fn with_page_labels(mut self, v: bool) -> Self {
self.opts.page_labels = v;
self
}
pub fn build(self) -> Result<PdfDocument> {
license::require_capability(Capability::PageOps)?;
if self.inputs.is_empty() {
return Err(internal_error(
"PdfMerger::build() called with no inputs; add at least one PdfDocument first",
));
}
let lopdf_docs: Vec<lopdf::Document> =
self.inputs.iter().map(|d| d.lopdf().clone()).collect();
let merged =
pdf_manip::pages::merge_documents(&lopdf_docs).map_err(|e| Error::InvalidPdf {
byte_offset: None,
reason: e.to_string(),
})?;
PdfDocument::from_lopdf(merged)
}
}