Files
vectorcraft/crates/ui-egui/src/tests_printps.rs
T
bflatasticandClaude Opus 5.5 0428e56342 M4.92: Print to a PostScript file
file.print {format: "postscript"} (the default for a .ps path) writes the
print job as Level 3 or 2 (level) PostScript instead of a PDF: DSC comments
with %%Pages the page count, one page per sheet with its paper size,
printer's marks in Registration, separations naming their ink (%%PlateColor)
with its halftone screen, a fixed flatness and film negatives. Transparency
is flattened first with flattenerPreset. The answer says which format was
written. In the app, a PostScript job is always saved, never sent to the
printer (the Print dialog's own options are unchanged).

The PDF print's layout is exposed as vectorcraft_pdf::plan (the PDF writer
uses it too); vectorcraft_eps::print draws its sheets with the EPS writer's
document walk, each sheet once however many copies print.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 17:01:36 +07:00

66 lines
2.4 KiB
Rust

//! Print to a PostScript file through the app: the job is saved, never sent to the printer.
use std::cell::RefCell;
use std::rc::Rc;
use serde_json::json;
use vectorcraft_engine::Session;
use crate::print::{PrintJob, PrintService, Printer};
use crate::{Services, VectorcraftApp};
/// What the app wrote: (path, bytes).
type Written = Rc<RefCell<Vec<(String, Vec<u8>)>>>;
/// A printer that counts the jobs it is sent.
struct Counting(Rc<RefCell<usize>>);
impl PrintService for Counting {
fn printers(&mut self) -> Vec<Printer> {
vec![Printer { name: "Office".into(), default: true }]
}
fn print(&mut self, _: &PrintJob) -> Result<String, String> {
*self.0.borrow_mut() += 1;
Ok("Sent".into())
}
}
#[test]
fn postscript_is_saved_not_printed() {
let sent = Rc::new(RefCell::new(0));
let written: Written = Rc::default();
let w = written.clone();
let services = Services {
print: Some(Box::new(Counting(sent.clone()))),
pick_save: Some(Box::new(|pick: &crate::FilePick| Some(format!("/tmp/{}", pick.name)))),
write: Some(Box::new(move |p: &str, b: &[u8]| {
w.borrow_mut().push((p.to_string(), b.to_vec()));
Ok(())
})),
..Default::default()
};
let mut app = VectorcraftApp::new(Session::new(), services);
app.run("file.new", json!({"width": 100, "height": 80, "artboards": 2})).unwrap();
// A .ps path: PostScript, at the level asked for.
let r = app.run("file.print", json!({"path": "/tmp/job.ps", "level": 2})).unwrap();
assert_eq!((r["format"].clone(), r["printed"].clone(), r["pages"].clone()), (json!("postscript"), json!(false), json!(2)), "{r}");
// No path: a picked .ps file.
let r = app.run("file.print", json!({"format": "postscript", "settings": {"copies": 2}})).unwrap();
assert_eq!(r["pages"], 4);
let w = written.borrow();
assert_eq!(w.len(), 2);
assert_eq!(w[0].0, "/tmp/job.ps");
assert!(w[1].0.ends_with(".ps"), "{}", w[1].0);
for (_, bytes) in w.iter() {
assert!(bytes.starts_with(b"%!PS-Adobe-3.0\n"));
}
assert!(String::from_utf8_lossy(&w[0].1).contains("%%LanguageLevel: 2"));
assert_eq!(*sent.borrow(), 0, "nothing went to the printer");
drop(w);
// A PDF still goes to the printer.
app.run("file.print", json!({"settings": {"copies": 1}})).unwrap();
assert_eq!(*sent.borrow(), 1);
assert!(app.run("file.print", json!({"format": "ps2"})).is_err());
}