fix(print): robust custom dimension parsing, spool media option fallback, driver paper bounds and name resolution

This commit is contained in:
Combiler01 committed 2026-11-09 19:33:31 +05:30
1 parent a1cc08ab03
commit acae521115
4 files changed
+24 -9

No files matched your search

+11 -4
View File
@@ -37,12 +37,16 @@ fn bad(m: impl Into<String>) -> ToolError {
ToolError::InvalidArgs(m.into())
}
/// Parse explicit custom dimensions like "300x500", "300 x 500", "300x500 pt", "Custom.300x500".
/// Parse explicit custom dimensions like "300x500", "300 x 500", "300x500 pt", "300pt x 500pt", "Custom.300x500".
fn parse_custom_dimensions(s: &str) -> Option<(f64, f64)> {
let s = s.trim().trim_start_matches("Custom.").trim_start_matches("custom.").trim_end_matches("pt").trim_end_matches("points").trim();
let s = s.trim().trim_start_matches("Custom.").trim_start_matches("custom.").trim();
let (w_str, h_str) = s.split_once(['x', 'X', '*'])?;
let w: f64 = w_str.trim().parse().ok()?;
let h: f64 = h_str.trim().parse().ok()?;
let parse_dim = |d: &str| {
let d = d.trim().trim_end_matches("points").trim_end_matches("pt").trim();
d.parse::<f64>().ok()
};
let w = parse_dim(w_str)?;
let h = parse_dim(h_str)?;
if w.is_finite() && h.is_finite() && w >= 72.0 && h >= 72.0 && w <= 14400.0 && h <= 14400.0 { Some((w, h)) } else { None }
}
@@ -346,7 +350,10 @@ mod tests {
// Non-preset dimensions and driver papers carry their media selection.
assert_eq!(job(json!({}), Some("300x500")).options, [media("Custom.300x500")]);
assert_eq!(job(json!({}), Some("300 x 500 pt")).options, [media("Custom.300x500")]);
assert_eq!(job(json!({}), Some("300pt x 500pt")).options, [media("Custom.300x500")]);
assert_eq!(job(json!({}), Some("300 pt x 500 pt")).options, [media("Custom.300x500")]);
assert_eq!(job(json!({}), Some("Custom.300x500")).options, [media("Custom.300x500")]);
assert_eq!(job(json!({}), Some("Custom.300x500pt")).options, [media("Custom.300x500")]);
assert!(matches!(resolve_paper(Some("Quarto"), None), Err(ToolError::InvalidArgs(m)) if m.contains("US Letter")));
assert_eq!(spool_job(&Args(&json!({})), "default", String::new(), None, Some("Letter")).ok().map(|j| j.printer), Some(None));
+5 -2
View File
@@ -294,8 +294,11 @@ pub fn paper_media(name: Option<&str>, size: (f64, f64)) -> String {
}
if let Some(n) = name {
let is_dim = n.split_once(['x', 'X', '*']).is_some_and(|(w, h)| {
w.trim().trim_start_matches("Custom.").trim_start_matches("custom.").parse::<f64>().is_ok()
&& h.trim().trim_end_matches("pt").trim_end_matches("points").trim().parse::<f64>().is_ok()
let parse_dim = |d: &str| {
let d = d.trim().trim_start_matches("Custom.").trim_start_matches("custom.").trim_end_matches("points").trim_end_matches("pt").trim();
d.parse::<f64>().is_ok()
};
parse_dim(w) && parse_dim(h)
});
let is_clean = !n.is_empty()
&& n.len() <= 64
+2 -1
View File
@@ -223,7 +223,7 @@ pub fn printer_papers(printer: &str) -> Vec<Paper> {
let size = media.size();
let w_pts = (size.width_in_micron() as f64) * 72.0 / 25_400.0;
let h_pts = (size.height_in_micron() as f64) * 72.0 / 25_400.0;
if w_pts > 0.0 && h_pts > 0.0 {
if w_pts.is_finite() && h_pts.is_finite() && w_pts >= 72.0 && h_pts >= 72.0 && w_pts <= 14400.0 && h_pts <= 14400.0 {
let name = media.display_name().map(str::to_string).unwrap_or_else(|| {
if let Some(predefined) = media.as_predefined_name() { format!("{predefined:?}") } else { format!("{w_pts:.1} x {h_pts:.1} pt") }
});
@@ -252,6 +252,7 @@ fn resolve_paper_name(papers: &[Paper], paper_pts: (f64, f64)) -> Paper {
.iter()
.find(|(_, (w, h))| ((*w - w_pts).abs() <= 1.0 && (*h - h_pts).abs() <= 1.0) || ((*w - h_pts).abs() <= 1.0 && (*h - w_pts).abs() <= 1.0))
.map(|(n, _)| n.clone())
.or_else(|| crate::matching_paper(paper_pts).and_then(|idx| crate::PAPERS.get(idx).map(|(n, _)| n.to_string())))
.unwrap_or_default();
(name, (w_pts, h_pts))
}
@@ -297,7 +297,7 @@ impl PrintDraft {
if !(size.0 >= 72.0 && size.1 >= 72.0 && size.0.is_finite() && size.1.is_finite()) {
return None;
}
if let Some(pos) = self.matching_paper(size) {
if let Some(pos) = print::matching_paper(size) {
Some(pos)
} else if !name.is_empty() {
let norm = (size.0.min(size.1), size.0.max(size.1));
@@ -308,10 +308,14 @@ impl PrintDraft {
}
}) {
Some(pos)
} else if let Some(pos) = self.matching_paper(size) {
Some(pos)
} else {
self.papers.push((name, size));
Some(self.papers.len() - 1)
}
} else if let Some(pos) = self.matching_paper(size) {
Some(pos)
} else {
let custom_name = format!("{:.1} x {:.1} pt", size.0, size.1);
self.papers.push((custom_name, size));
@@ -435,7 +439,7 @@ impl PrintDraft {
}
.into_iter()
// The sheet the PDF was laid out on, not the queue's default paper.
.chain(self.papers.get(self.paper).map(|(name, size)| print::paper_media_option(Some(name), *size)))
.chain(Some(print::paper_media_option(Some(self.paper_name()), self.paper_size())))
.collect(),
}
}