From 61504c84fbb519625809660e69b2bd68b24881ec Mon Sep 17 00:00:00 2001 From: Chris Main Date: Sat, 24 Oct 2026 05:39:36 -0400 Subject: [PATCH] Print: turn only landscape paper, and only for macOS queues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Review of #3925: the spooled job turned every sheet wider than tall, so custom paper that is wide in Portrait (a 4 × 2 in label) went to the queue tall, and a Portrait + Transverse page was turned back. Only the sheets whose paper the layout turned to landscape (not transverse) are written upright now. The desktop print service asked for upright pages on every platform, but craft-print already turns each sheet to its own orientation on Windows: only macOS asks for them now; Linux keeps main's behaviour. Co-Authored-By: Claude Opus 5.5 (1M context) --- apps/vectorcraft/src/printing.rs | 16 ++++++++++++++-- crates/engine/src/cmd/print.rs | 2 +- crates/pdf/src/print/mod.rs | 13 ++++++++----- crates/pdf/src/tests_print.rs | 14 ++++++++++++++ crates/ui-egui/src/print.rs | 6 +++--- 5 files changed, 40 insertions(+), 11 deletions(-) diff --git a/apps/vectorcraft/src/printing.rs b/apps/vectorcraft/src/printing.rs index 8f8d30a34..c9e6539a2 100644 --- a/apps/vectorcraft/src/printing.rs +++ b/apps/vectorcraft/src/printing.rs @@ -24,8 +24,9 @@ impl PrintService for SystemPrint { Some(std::sync::Arc::new(|job| SystemPrint.print(job))) } fn turns_landscape(&self) -> bool { - // `lp` doesn't turn a landscape page to the paper (macOS cuts it off on upright paper). - false + // macOS's `lp` doesn't turn a landscape page to the paper: it cuts it off on upright + // paper. craft-print turns each sheet to its own orientation on Windows. + !cfg!(target_os = "macos") } fn has_setup(&self) -> bool { true @@ -131,3 +132,14 @@ mod tests { assert_eq!(args, ["ms-settings:printers"]); } } + +#[cfg(test)] +mod turn_tests { + use super::SystemPrint; + use vectorcraft_ui_egui::print::PrintService; + + #[test] + fn only_macos_queues_need_landscape_pages_turned() { + assert_eq!(SystemPrint.turns_landscape(), !cfg!(target_os = "macos")); + } +} diff --git a/crates/engine/src/cmd/print.rs b/crates/engine/src/cmd/print.rs index a19ef1ae2..be17271c0 100644 --- a/crates/engine/src/cmd/print.rs +++ b/crates/engine/src/cmd/print.rs @@ -40,7 +40,7 @@ pub fn specs() -> Vec { "Print", [], Some("Cmd+P"), - "{preset?: name (as print.setup's: its settings instead of the document's; the saved settings stay), settings?: {…settings of print.setup} (over the document's or the preset's), path?, format?: pdf (default: a print-ready PDF) | postscript (the default for a .ps path: a PostScript file with DSC comments, %%Pages, a page per sheet with its paper size, marks, separations with their ink and halftone screen, the fixed flatness, negatives), level?: 3|2 (the PostScript language level), flattenerPreset?: \"medium\" (PostScript: the preset transparency is flattened with — high, low or a saved one, see flattener.presets.list), acknowledgeLoss?: bool (with path: write over the file the document was read from although reading it left things out), forPrinter?: bool (the PDF goes to a print queue: a page wider than tall is written upright on the paper, the art turned a quarter anticlockwise, as a printer driver turns a landscape job; macOS prints a landscape page as it is, cut off on upright paper)} print the document, one page per sheet of paper (per tile, per ink, per copy) → {pages, format, path, bytes, warnings}; no path → {dataBase64, bytes, pages, format, warnings}. Raster effects print at the document's raster effects resolution; a PDF leaves halftone screens and flatness to the output device", + "{preset?: name (as print.setup's: its settings instead of the document's; the saved settings stay), settings?: {…settings of print.setup} (over the document's or the preset's), path?, format?: pdf (default: a print-ready PDF) | postscript (the default for a .ps path: a PostScript file with DSC comments, %%Pages, a page per sheet with its paper size, marks, separations with their ink and halftone screen, the fixed flatness, negatives), level?: 3|2 (the PostScript language level), flattenerPreset?: \"medium\" (PostScript: the preset transparency is flattened with — high, low or a saved one, see flattener.presets.list), acknowledgeLoss?: bool (with path: write over the file the document was read from although reading it left things out), forPrinter?: bool (the PDF goes to a print queue: a page whose paper is turned to landscape is written upright, the art turned a quarter anticlockwise, as a printer driver turns a landscape job; macOS prints a landscape page as it is, cut off on upright paper; paper wide in Portrait and transverse pages stay as they are)} print the document, one page per sheet of paper (per tile, per ink, per copy) → {pages, format, path, bytes, warnings}; no path → {dataBase64, bytes, pages, format, warnings}. Raster effects print at the document's raster effects resolution; a PDF leaves halftone screens and flatness to the output device", has_doc, print ), diff --git a/crates/pdf/src/print/mod.rs b/crates/pdf/src/print/mod.rs index 9ef36ff2e..a8e54b324 100644 --- a/crates/pdf/src/print/mod.rs +++ b/crates/pdf/src/print/mod.rs @@ -68,8 +68,9 @@ pub struct PrintOptions { /// warnings that they are left to the device. pub postscript: bool, /// The job goes to a print queue, which puts each page on the paper as it is (macOS does - /// not turn a landscape page to the paper): a page wider than tall is written upright, the - /// art turned a quarter anticlockwise, as a printer driver turns a landscape job. + /// not turn a landscape page to the paper): a page whose paper the layout turned to landscape + /// is written upright, the art turned a quarter anticlockwise, as a printer driver turns a + /// landscape job. Paper that is wide in Portrait, and transverse pages, stay as they are. pub for_printer: bool, } @@ -392,15 +393,17 @@ pub fn plan<'a>(doc: &'a Document, opts: &PrintOptions) -> Result, plate: *plate, ink: ink.cloned(), }; - Some(if opts.for_printer { upright(sheet) } else { sheet }) + // Only the paper the layout turned: custom paper can be wide in Portrait. + let turned = l.orientation.landscape() && !set.transverse; + Some(if opts.for_printer && turned { upright(sheet) } else { sheet }) }) .collect(); let order = job.order(set); Ok(PrintPlan { plates, sheets, order, title, created, warnings: job.warnings, doc: job.doc }) } -/// `s` upright on the paper ([`PrintOptions::for_printer`]): a page wider than tall turns a -/// quarter anticlockwise, its top to the paper's left edge. +/// Landscape sheet `s` upright on the paper ([`PrintOptions::for_printer`]): a page wider than +/// tall turns a quarter anticlockwise, its top to the paper's left edge. fn upright(mut s: PlannedSheet) -> PlannedSheet { let (w, h) = s.size; if w <= h { diff --git a/crates/pdf/src/tests_print.rs b/crates/pdf/src/tests_print.rs index a37ea408e..cd1232a4a 100644 --- a/crates/pdf/src/tests_print.rs +++ b/crates/pdf/src/tests_print.rs @@ -462,6 +462,20 @@ fn for_a_printer_landscape_pages_print_upright_turned_anticlockwise() { let mut t = s; t["transverse"] = json!(true); assert_eq!(spooled(t).0, (612.0, 792.0)); + // Transverse in Portrait is wide on purpose: it stays wide. + assert_eq!(spooled(json!({"autoRotate": false, "transverse": true})).0, (792.0, 612.0)); +} + +#[test] +fn for_a_printer_paper_wide_in_portrait_stays_as_it_is() { + // A 4 × 2 in label in Portrait: the queue's media is wide too. + let d = doc(288.0, 144.0, &[(Rect::new(0.0, 0.0, 144.0, 144.0), rgb(1.0, 0.0, 0.0))]); + let v = + json!({"media": "custom", "width": 288, "height": 144, "orientation": "portrait", "autoRotate": false, "placement": {"origin": "topLeft"}}); + let opts = PrintOptions { settings: settings(v), uncompressed: true, for_printer: true, ..Default::default() }; + let p = pages(&print(&d, &opts).unwrap().bytes).remove(0); + assert_eq!(p.0, (288.0, 144.0)); + assert!(near(p.1[0].0, Rect::new(0.0, 0.0, 144.0, 144.0)), "{:?}", p.1); } #[test] diff --git a/crates/ui-egui/src/print.rs b/crates/ui-egui/src/print.rs index 1eeea2846..499f6f260 100644 --- a/crates/ui-egui/src/print.rs +++ b/crates/ui-egui/src/print.rs @@ -42,9 +42,9 @@ pub trait PrintService { fn shared_print(&self) -> Option { None } - /// Whether the system turns a page wider than tall to fit the paper. The desktop's print - /// queues put each page on the paper as it is, so their jobs are written upright - /// (`file.print`'s `forPrinter`); the browser's print dialog turns them itself. + /// Whether the system turns a landscape page to fit the paper. macOS's print queues put + /// each page on the paper as it is, so their jobs are written upright (`file.print`'s + /// `forPrinter`); Windows and the browser's print dialog turn them themselves. fn turns_landscape(&self) -> bool { true }