use std::borrow::Cow;
use cfg_if::cfg_if;
use printpdf::{
Op, PdfDocument, PdfPage, PdfParseErrorSeverity, PdfParseOptions, PdfSaveOptions, PdfWarnMsg,
};
#[cfg(feature = "rayon")]
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use crate::{Bendable, IntoDataBytes, TryFromDataBytes};
fn clean_up_warnings(warnings: &mut Vec<PdfWarnMsg>) {
warnings.retain(|warning| {
warning.severity == PdfParseErrorSeverity::Warning
|| warning.severity == PdfParseErrorSeverity::Error
});
}
impl TryFromDataBytes for PdfDocument {
type Error = String;
type Format = ();
fn try_from_data_bytes(
bytes: crate::Bytes,
_format: Self::Format,
_crop: crate::Crop,
) -> Result<Self, Self::Error> {
let mut warnings = Vec::new();
let result = PdfDocument::parse(
&bytes,
&PdfParseOptions {
fail_on_error: false,
},
&mut warnings,
);
clean_up_warnings(&mut warnings);
for warning in warnings {
println!("Warning: {:#?}", warning);
}
result
}
}
impl IntoDataBytes for PdfDocument {
fn into_data_bytes(self) -> crate::Bytes {
let mut warnings = Vec::new();
let result = self.save(
&PdfSaveOptions {
image_optimization: None,
..Default::default()
},
&mut warnings,
);
clean_up_warnings(&mut warnings);
for warning in warnings {
println!("Warning: {:#?}", warning);
}
result
}
}
impl Bendable for PdfDocument {
type Unit = Op;
fn map<F: Fn(Cow<Self::Unit>) -> Self::Unit + Sync>(self, f: F) -> Self {
let PdfDocument {
metadata,
resources,
bookmarks,
pages,
} = self;
PdfDocument {
pages: pages
.into_iter()
.map(|page| PdfPage {
ops: {
cfg_if! {
if #[cfg(feature = "rayon")] {
page.ops.into_par_iter()
} else {
page.ops.into_iter()
}
}
}
.map(|op| f(Cow::Owned(op)))
.collect::<Vec<Op>>(),
..page
})
.collect(),
metadata,
resources,
bookmarks,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn map_integrity() {
let mut warnings = Vec::new();
let original = PdfDocument::parse(
include_bytes!("../../../testing material/doc/pdf/basic-text.pdf"),
&PdfParseOptions {
fail_on_error: true,
},
&mut warnings,
)
.unwrap();
clean_up_warnings(&mut warnings);
for warning in warnings {
println!("Warning: {:#?}", warning);
}
assert_eq!(
format!("{:?}", original),
format!("{:?}", original.clone().map(|u| u.into_owned()))
)
}
}