Merge pull request #147 from midasmatterhorn/fix/r4-print-shrink-zero-scale

print: shrink-to-fit refuses a sheet the written matrix cannot represent
This commit is contained in:
Dylan M. Taylor authored and GitHub committed 2026-11-14 11:34:07 -05:00
commit 689bd18cb6
2 files changed
+54

No files matched your search

+15
View File
@@ -1136,6 +1136,21 @@ pub(crate) fn plan(sheets: &[Sheet], paper: (f64, f64), fit: Fit) -> Result<Vec<
if scale >= 1.0 && close((w, h), paper) {
None
} else {
// The matrix is written with at most four decimals and a PDF real has no
// exponent, so a scale that rounds away prints nothing at all and one that
// rounds up prints the wrong size. Refuse both, the way a nondefault
// UserUnit is refused: an error, never a job that spools a blank page.
let written = number(scale).parse::<f64>().unwrap_or(0.0);
if written <= 0.0 || (written - scale).abs() > scale * 0.01 {
return Err(Error::Spool(format!(
"shrink to fit cannot place sheet {} ({:.2} x {:.2} in) on the {:.2} x {:.2} in paper; nothing was sent",
i + 1,
w / 72.0,
h / 72.0,
pw / 72.0,
ph / 72.0
)));
}
let [x0, y0, x1, y1] = sheet.bounds;
let (cw, ch) = (x1 - x0, y1 - y0);
// The paper in the page's unrotated space.
+39
View File
@@ -555,3 +555,42 @@ fn windows_jobs_reach_the_spooler() {
let missing = spool::submit(&mixed, &Job { printer: Some(name.into()), ..Job::default() });
assert!(matches!(missing, Err(Error::Spool(ref m)) if m.contains(name)), "{missing:?}");
}
#[test]
fn shrink_to_fit_refuses_a_sheet_the_output_cannot_represent() {
use crate::sheets::{Fit, plan, read};
// A runaway-zoom export: 16 000 000 pt wide. Written with four decimals the scale would be
// "0" -- a singular matrix, a blank page, reported back as a spooled job.
let huge = TestPage { media: Some([0.0, 0.0, 16_000_000.0, 792.0]), ..LETTER };
let pdf = test_pdf(&[huge], false);
let sheets = read(&pdf).unwrap();
let refused = plan(&sheets.sheets, (612.0, 792.0), Fit::Shrink { margin: 18.0 });
assert!(matches!(refused, Err(Error::Spool(ref m)) if m.contains("shrink")), "{refused:?}");
}
#[test]
fn shrink_to_fit_holds_the_one_percent_scale_boundary() {
use crate::sheets::{Fit, plan, read};
// The matrix carries the scale through the four-decimal formatter, so the plan refuses when
// what would be written is more than 1% off the real scale. Letter with an 18 pt margin gives
// 576 pt of printable width: a 118 700 pt wide, 120 000 pt tall sheet (no quarter turn) scales
// by 576 / 118 700 = 0.00485257, written 0.0049 -- 0.98% short, inside the bound, so it
// prints.
let inside = TestPage { media: Some([0.0, 0.0, 118_700.0, 120_000.0]), ..LETTER };
let pdf = test_pdf(&[inside], false);
let sheets = read(&pdf).unwrap();
let edits = plan(&sheets.sheets, (612.0, 792.0), Fit::Shrink { margin: 18.0 }).unwrap();
let updated = sheets.update(&edits).unwrap();
let frame = frame_of(&updated, pdf.len());
let written: f64 = frame.split_whitespace().nth(1).unwrap().parse().unwrap();
let real = edits[0].frame.as_ref().unwrap().matrix[0];
assert!(written != real && (written - real).abs() < real * 0.01, "just inside the 1% bound the written scale is accepted: {frame}");
// A 118 750 pt wide sheet: 576 / 118 750 = 0.00485053, written 0.0049, 1.02% off -- refused as
// an error before anything is sent, rather than printed a percent too small.
let outside = TestPage { media: Some([0.0, 0.0, 118_750.0, 120_000.0]), ..LETTER };
let pdf = test_pdf(&[outside], false);
let sheets = read(&pdf).unwrap();
let refused = plan(&sheets.sheets, (612.0, 792.0), Fit::Shrink { margin: 18.0 });
assert!(matches!(refused, Err(Error::Spool(ref m)) if m.contains("shrink") && m.contains("nothing was sent")), "{refused:?}");
}