[librsvg: 1/4] Make multi-page PDFs with mixed sizes
- From: Marge Bot <marge-bot src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 1/4] Make multi-page PDFs with mixed sizes
- Date: Tue, 12 Oct 2021 18:48:22 +0000 (UTC)
commit 3e9d129bf5251225030d55e419ec5a08914eb9e3
Author: Michael Howell <michael notriddle com>
Date: Thu Oct 7 14:21:46 2021 -0700
Make multi-page PDFs with mixed sizes
Fixes #783
Part-of: <https://gitlab.gnome.org/GNOME/librsvg/-/merge_requests/600>
src/bin/rsvg-convert.rs | 35 +++++++++++++++++++++++----
tests/src/cmdline/rsvg_convert.rs | 16 +++++++++----
tests/src/predicates/pdf.rs | 50 ++++++++++++++++++++++++++-------------
3 files changed, 74 insertions(+), 27 deletions(-)
---
diff --git a/src/bin/rsvg-convert.rs b/src/bin/rsvg-convert.rs
index 3aeb74ec..d073bd19 100644
--- a/src/bin/rsvg-convert.rs
+++ b/src/bin/rsvg-convert.rs
@@ -27,7 +27,6 @@ use librsvg::rsvg_convert_only::{
use librsvg::{
AcceptLanguage, CairoRenderer, Color, Language, LengthUnit, Loader, Parse, RenderingError,
};
-use once_cell::unsync::OnceCell;
use std::ops::Deref;
use std::path::PathBuf;
@@ -450,9 +449,9 @@ impl Converter {
None => None,
};
- let mut surface: OnceCell<Surface> = OnceCell::new();
+ let mut surface: Option<Surface> = None;
- for input in &self.input {
+ for (page_idx, input) in self.input.iter().enumerate() {
let (stream, basefile) = match input {
Input::Stdin => (Stdin::stream(), None),
Input::Named(p) => {
@@ -553,9 +552,35 @@ impl Converter {
let final_size = self.final_size(&strategy, &natural_size, input)?;
- // Create the surface once on the first input
+ // Create the surface once on the first input,
+ // except for PDF, PS, and EPS, which allow differently-sized pages.
let page_size = page_size.unwrap_or(final_size);
- let s = surface.get_or_try_init(|| self.create_surface(page_size))?;
+ let s = match &mut surface {
+ Some(s) => {
+ match s {
+ #[cfg(system_deps_have_cairo_pdf)]
+ Surface::Pdf(pdf, size) => {
+ pdf.set_size(final_size.w, final_size.h).map_err(|e| {
+ error!(
+ "Error setting PDF page #{} size {}: {}",
+ page_idx + 1,
+ input,
+ e
+ )
+ })?;
+ *size = final_size;
+ }
+ #[cfg(system_deps_have_cairo_ps)]
+ Surface::Ps(ps, size) => {
+ ps.set_size(final_size.w, final_size.h);
+ *size = final_size;
+ }
+ _ => {}
+ }
+ s
+ }
+ surface @ None => surface.insert(self.create_surface(page_size)?),
+ };
let left = self.left.map(|l| l.to_user(¶ms)).unwrap_or(0.0);
let top = self.top.map(|l| l.to_user(¶ms)).unwrap_or(0.0);
diff --git a/tests/src/cmdline/rsvg_convert.rs b/tests/src/cmdline/rsvg_convert.rs
index 7794bb37..0ad21b3e 100644
--- a/tests/src/cmdline/rsvg_convert.rs
+++ b/tests/src/cmdline/rsvg_convert.rs
@@ -286,7 +286,13 @@ fn multiple_input_files_create_multi_page_pdf_output() {
.arg(three)
.assert()
.success()
- .stdout(file::is_pdf().with_page_count(3));
+ .stdout(
+ file::is_pdf()
+ .with_page_count(3)
+ .and(file::is_pdf().with_page_size(0, 150.0, 75.0))
+ .and(file::is_pdf().with_page_size(1, 123.0, 123.0))
+ .and(file::is_pdf().with_page_size(2, 75.0, 300.0)),
+ );
}
#[cfg(system_deps_have_cairo_pdf)]
@@ -610,7 +616,7 @@ fn unscaled_pdf_size() {
.arg("--format=pdf")
.assert()
.success()
- .stdout(file::is_pdf().with_page_size(72.0, 72.0));
+ .stdout(file::is_pdf().with_page_size(0, 72.0, 72.0));
}
#[cfg(system_deps_have_cairo_pdf)]
@@ -622,7 +628,7 @@ fn pdf_size_width_height() {
.arg("--height=3in")
.assert()
.success()
- .stdout(file::is_pdf().with_page_size(144.0, 216.0));
+ .stdout(file::is_pdf().with_page_size(0, 144.0, 216.0));
}
#[cfg(system_deps_have_cairo_pdf)]
@@ -635,7 +641,7 @@ fn pdf_size_width_height_proportional() {
.arg("--keep-aspect-ratio")
.assert()
.success()
- .stdout(file::is_pdf().with_page_size(144.0, 144.0));
+ .stdout(file::is_pdf().with_page_size(0, 144.0, 144.0));
}
#[cfg(system_deps_have_cairo_pdf)]
@@ -647,7 +653,7 @@ fn pdf_page_size() {
.arg("--page-height=297mm")
.assert()
.success()
- .stdout(file::is_pdf().with_page_size(210.0 / 25.4 * 72.0, 297.0 / 25.4 * 72.0));
+ .stdout(file::is_pdf().with_page_size(0, 210.0 / 25.4 * 72.0, 297.0 / 25.4 * 72.0));
}
#[cfg(system_deps_have_cairo_pdf)]
diff --git a/tests/src/predicates/pdf.rs b/tests/src/predicates/pdf.rs
index 14ba46f7..3398e623 100644
--- a/tests/src/predicates/pdf.rs
+++ b/tests/src/predicates/pdf.rs
@@ -19,16 +19,20 @@ impl PdfPredicate {
pub fn with_page_size(
self: Self,
+ idx: usize,
width_in_points: f64,
height_in_points: f64,
) -> DetailPredicate<Self> {
DetailPredicate::<Self> {
p: self,
- d: Detail::PageSize(Dimensions {
- w: width_in_points,
- h: height_in_points,
- unit: 1.0,
- }),
+ d: Detail::PageSize(
+ Dimensions {
+ w: width_in_points,
+ h: height_in_points,
+ unit: 1.0,
+ },
+ idx,
+ ),
}
}
@@ -78,7 +82,7 @@ pub struct DetailPredicate<PdfPredicate> {
#[derive(Debug)]
enum Detail {
PageCount(usize),
- PageSize(Dimensions),
+ PageSize(Dimensions, usize),
CreationDate(DateTime<Utc>),
Link(String),
}
@@ -138,17 +142,21 @@ impl cmp::Eq for Dimensions {}
trait Details {
fn get_page_count(&self) -> usize;
- fn get_page_size(&self) -> Option<Dimensions>;
+ fn get_page_size(&self, idx: usize) -> Option<Dimensions>;
fn get_creation_date(&self) -> Option<DateTime<Utc>>;
fn get_from_trailer<'a>(self: &'a Self, key: &[u8]) -> lopdf::Result<&'a lopdf::Object>;
- fn get_from_first_page<'a>(self: &'a Self, key: &[u8]) -> lopdf::Result<&'a lopdf::Object>;
+ fn get_from_page<'a>(
+ self: &'a Self,
+ idx: usize,
+ key: &[u8],
+ ) -> lopdf::Result<&'a lopdf::Object>;
}
impl DetailPredicate<PdfPredicate> {
fn eval_doc(&self, doc: &lopdf::Document) -> bool {
match &self.d {
Detail::PageCount(n) => doc.get_page_count() == *n,
- Detail::PageSize(d) => doc.get_page_size().map_or(false, |dim| dim == *d),
+ Detail::PageSize(d, idx) => doc.get_page_size(*idx).map_or(false, |dim| dim == *d),
Detail::CreationDate(d) => doc.get_creation_date().map_or(false, |date| date == *d),
Detail::Link(link) => document_has_link(doc, &link),
}
@@ -169,9 +177,9 @@ impl DetailPredicate<PdfPredicate> {
"actual page count",
format!("{} page(s)", doc.get_page_count()),
),
- Detail::PageSize(_) => Product::new(
+ Detail::PageSize(_, idx) => Product::new(
"actual page size",
- match doc.get_page_size() {
+ match doc.get_page_size(*idx) {
Some(dim) => format!("{}", dim),
None => "None".to_string(),
},
@@ -210,11 +218,11 @@ impl Details for lopdf::Document {
self.get_pages().len()
}
- fn get_page_size(self: &Self) -> Option<Dimensions> {
- match self.get_from_first_page(b"MediaBox") {
+ fn get_page_size(self: &Self, idx: usize) -> Option<Dimensions> {
+ match self.get_from_page(idx, b"MediaBox") {
Ok(obj) => {
let unit = self
- .get_from_first_page(b"UserUnit")
+ .get_from_page(idx, b"UserUnit")
.and_then(ObjExt::as_float)
.ok();
Dimensions::from_media_box(obj, unit).ok()
@@ -235,8 +243,16 @@ impl Details for lopdf::Document {
self.get_object(id)?.as_dict()?.get(key)
}
- fn get_from_first_page<'a>(self: &'a Self, key: &[u8]) -> lopdf::Result<&'a lopdf::Object> {
- match self.page_iter().next() {
+ fn get_from_page<'a>(
+ self: &'a Self,
+ idx: usize,
+ key: &[u8],
+ ) -> lopdf::Result<&'a lopdf::Object> {
+ let mut iter = self.page_iter();
+ for _ in 0..idx {
+ let _ = iter.next();
+ }
+ match iter.next() {
Some(id) => self.get_object(id)?.as_dict()?.get(key),
None => Err(lopdf::Error::ObjectNotFound),
}
@@ -270,7 +286,7 @@ impl fmt::Display for DetailPredicate<PdfPredicate> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match &self.d {
Detail::PageCount(n) => write!(f, "is a PDF with {} page(s)", n),
- Detail::PageSize(d) => write!(f, "is a PDF sized {}", d),
+ Detail::PageSize(d, _) => write!(f, "is a PDF sized {}", d),
Detail::CreationDate(d) => write!(f, "is a PDF created {:?}", d),
Detail::Link(l) => write!(f, "is a PDF with a link to {}", l),
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]