From 95434e9115b73bfc1d0cee6f66db2ce96fe40510 Mon Sep 17 00:00:00 2001 From: skylar taylor-barrick Date: Sun, 11 Oct 2026 22:05:01 +0200 Subject: [PATCH] M10.5: Preserve composed sheets with the shared scaling and duplex API --- Cargo.lock | 2 +- Cargo.toml | 2 +- ROADMAP.md | 2 +- crates/automation/src/printing.rs | 5 +++-- crates/print/src/spool.rs | 2 +- crates/print/src/tests.rs | 3 ++- crates/ui-egui/src/print_ui.rs | 12 +++++++++++- docs/architecture.md | 2 +- docs/hardware-parity.md | 2 +- 9 files changed, 22 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9abe21229..f22b7be59 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1093,7 +1093,7 @@ dependencies = [ [[package]] name = "craft-print" version = "0.1.0" -source = "git+https://github.com/storytold/craft-libs?rev=c22bb1b0ce6316f84973cb69675fe7331c5886cc#c22bb1b0ce6316f84973cb69675fe7331c5886cc" +source = "git+https://github.com/storytold/craft-libs?rev=da752825c70574a2423ee55427f8f7aa5b5f8ec8#da752825c70574a2423ee55427f8f7aa5b5f8ec8" dependencies = [ "tempfile", ] diff --git a/Cargo.toml b/Cargo.toml index 36e256011..ed72d2329 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ repository = "https://github.com/storytold/pdfcraft" # Shared frontend components; engines remain independent of egui. craft-ui = { git = "https://github.com/storytold/craft-libs", version = "0.1.0", rev = "5c874d51eeb3de70e735c8ce87a59a7dedd47675", features = ["serde"] } # Shared system spooler; document composition remains in pdfcraft-print. -craft-print = { git = "https://github.com/storytold/craft-libs", version = "0.1.0", rev = "c22bb1b0ce6316f84973cb69675fe7331c5886cc" } +craft-print = { git = "https://github.com/storytold/craft-libs", version = "0.1.0", rev = "da752825c70574a2423ee55427f8f7aa5b5f8ec8" } # internal pdfcraft-geom = { path = "crates/geom", version = "0.6.0" } pdfcraft-filters = { path = "crates/filters", version = "0.6.0" } diff --git a/ROADMAP.md b/ROADMAP.md index 8791fca45..e38d307cd 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -2,7 +2,7 @@ **Stage: alpha** · next: beta, ~26% (ready for real work 49% → 75%) and ~400–700 h away -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (shared print spooler; native Windows validation pending) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS) +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (shared print spooler; Windows CI enabled) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS) PdfCraft's one-page summary: how close it is to Adobe Acrobat Pro's offline feature set, and what comes next. Adobe's cloud services (Document Cloud, Acrobat Sign requests, shared review, the AI diff --git a/crates/automation/src/printing.rs b/crates/automation/src/printing.rs index 6ba8b393a..ef9f252c9 100644 --- a/crates/automation/src/printing.rs +++ b/crates/automation/src/printing.rs @@ -126,12 +126,13 @@ impl Automation { printer: if printer == "default" { None } else { Some(printer.to_string()) }, copies: a.opt_int("copies")?.unwrap_or(1).clamp(1, 999) as u32, collate: a.opt_bool("collate")?.unwrap_or(true), - duplex: match a.opt_str("duplex")?.unwrap_or("off") { + duplex: Some(match a.opt_str("duplex")?.unwrap_or("off") { "off" => spool::Duplex::Off, "long-edge" => spool::Duplex::LongEdge, "short-edge" => spool::Duplex::ShortEdge, d => return Err(bad(format!("unknown duplex {d:?}"))), - }, + }), + scaling: spool::Scaling::Exact, grayscale: a.opt_bool("grayscale")?.unwrap_or(false), title: name, options: match a.get("options") { diff --git a/crates/print/src/spool.rs b/crates/print/src/spool.rs index d6b797621..bad3ab210 100644 --- a/crates/print/src/spool.rs +++ b/crates/print/src/spool.rs @@ -2,7 +2,7 @@ //! stay in PdfCraft; these adapters retain the application's print-error surface. pub use craft_print::{ - Duplex, HANDLED_OPTIONS, HAS_PRINTER_PREFERENCES, Job, Printer, PrinterOption, lp_args, lpstat_command, parse_lpoptions, parse_lpstat, + Duplex, HANDLED_OPTIONS, HAS_PRINTER_PREFERENCES, Job, Printer, PrinterOption, Scaling, lp_args, lpstat_command, parse_lpoptions, parse_lpstat, parse_lpstat_e, parse_ppd, parse_windows_printers, ppd_text, printer_options, printers, printers_parsed, }; diff --git a/crates/print/src/tests.rs b/crates/print/src/tests.rs index 4e2c444e5..0cfead39c 100644 --- a/crates/print/src/tests.rs +++ b/crates/print/src/tests.rs @@ -194,10 +194,11 @@ fn spooler_arguments_and_printer_list() { printer: Some("Office_Laser".into()), copies: 3, collate: false, - duplex: Duplex::LongEdge, + duplex: Some(Duplex::LongEdge), grayscale: true, title: "memo.pdf".into(), options: Vec::new(), + ..Job::default() }; assert_eq!( lp_args(&job).join(" "), diff --git a/crates/ui-egui/src/print_ui.rs b/crates/ui-egui/src/print_ui.rs index 8bfb56eaa..a153eba61 100644 --- a/crates/ui-egui/src/print_ui.rs +++ b/crates/ui-egui/src/print_ui.rs @@ -159,7 +159,8 @@ impl PrintDraft { printer: self.printer.clone(), copies: self.copies.max(1), collate: self.collate, - duplex: self.duplex, + duplex: Some(self.duplex), + scaling: spool::Scaling::Exact, grayscale: self.grayscale, title: title.to_string(), // Only for the printer the options were read from. @@ -865,6 +866,15 @@ pub(crate) fn body( mod tests { use super::*; + #[test] + fn composed_sheets_keep_exact_scaling_and_the_dialogs_duplex_choice() { + let draft = PrintDraft { duplex: spool::Duplex::LongEdge, ..PrintDraft::default() }; + let job = draft.job("report.pdf"); + assert_eq!(job.scaling, spool::Scaling::Exact); + assert_eq!(job.duplex, Some(spool::Duplex::LongEdge)); + assert_eq!(PrintDraft::default().job("report.pdf").duplex, Some(spool::Duplex::Off)); + } + #[test] fn print_preview_rasters_stay_within_the_texture_limit() { // Actual size on a 14,400 pt (200 in) page would ask for a raster far past any texture. diff --git a/docs/architecture.md b/docs/architecture.md index 1d4b5db9b..4e047c10f 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -1,6 +1,6 @@ # PdfCraft architecture -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (shared print spooler; native Windows validation pending) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS) +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (shared print spooler; Windows CI enabled) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS) How PdfCraft is built today. The design rationale and the planned crates live in `plan/architecture.md` and `plan/adr/` (local-only); this file describes what is on `main`. Each diff --git a/docs/hardware-parity.md b/docs/hardware-parity.md index 86ce16756..5c74648d1 100644 --- a/docs/hardware-parity.md +++ b/docs/hardware-parity.md @@ -1,6 +1,6 @@ # Hardware and platform parity -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (shared print spooler; native Windows validation pending) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS) +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (shared print spooler; Windows CI enabled) · **Target:** Adobe Acrobat Pro (Acrobat DC, continuous track 26.002.21931, macOS) Each hardware feature Acrobat Pro uses, per platform, ours against Acrobat's. Acrobat runs on macOS and Windows (plus a limited web viewer/editor in Document Cloud); PdfCraft runs on macOS, Windows,