Files
vectorcraft/crates/eps/src/print/tests.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

86 lines
3.9 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! PostScript print jobs: DSC page comments, the setup of each sheet, and a file the PostScript
//! reader reads back.
use vectorcraft_color::{Color, Paint};
use vectorcraft_doc::{Appearance, Document, Node, NodeId};
use vectorcraft_geom::{Affine, Rect, shapes};
use super::*;
/// A 200 × 100 pt document with a red rectangle.
fn doc() -> Document {
let mut d = Document::new(200.0, 100.0);
let layer = d.layers[0].id;
let look = Appearance::basic(Paint::solid(Color::rgb(1.0, 0.0, 0.0)), Paint::None, 0.0);
let n = Node::path(d.alloc_id(), shapes::rectangle(Rect::new(20.0, 20.0, 120.0, 60.0)), look);
d.insert(Some(layer), 0, n).unwrap();
d
}
/// The document on a letter page, 36 pt in from its top-left corner.
fn page<'a>(d: &'a Document, marks: Option<&'a Node>) -> PrintPage<'a> {
PrintPage {
doc: d,
size: (612.0, 792.0),
view: Affine::IDENTITY,
window: None,
place: Affine::translate((36.0, 36.0)),
area: d.artboards[0].rect,
marks,
negative: false,
ink: None,
}
}
fn text(out: &EpsOutput) -> String {
String::from_utf8(out.bytes.clone()).unwrap()
}
#[test]
fn pages_follow_dsc_and_repeat_for_copies() {
let d = doc();
let mark =
Node::path(NodeId(9999), shapes::rectangle(Rect::new(0.0, 0.0, 10.0, 10.0)), Appearance::basic(Paint::None, Paint::registration(), 0.25));
let pages = [page(&d, None), PrintPage { size: (792.0, 612.0), ..page(&d, Some(&mark)) }];
let job = PrintJob { title: "Job".into(), created: Some(0), ..PrintJob::default() };
let out = print(&pages, &[0, 1, 0, 1], &job).unwrap();
let ps = text(&out);
assert!(ps.starts_with("%!PS-Adobe-3.0\n") && ps.ends_with("%%EOF\n"));
let dsc = |key: &str| ps.lines().filter_map(|l| l.strip_prefix(key)).map(str::trim).collect::<Vec<_>>();
assert_eq!(dsc("%%Pages:"), ["4"]);
assert_eq!(dsc("%%Page:"), ["1 1", "2 2", "3 3", "4 4"]);
assert_eq!(dsc("%%PageBoundingBox:"), ["0 0 612 792", "0 0 792 612", "0 0 612 792", "0 0 792 612"]);
assert_eq!(dsc("%%BoundingBox:"), ["0 0 792 792"]);
assert_eq!(dsc("%%LanguageLevel:"), ["3"]);
assert_eq!(ps.matches("showpage").count(), 4);
assert!(ps.contains("<< /PageSize [792 612] >> setpagedevice"));
// The marks are drawn in Registration on the pages that have them.
assert_eq!(ps.matches("/All /DeviceCMYK").count(), 2, "{ps}");
assert!(out.warnings.is_empty(), "{:?}", out.warnings);
// The PostScript reader reads the first page back: the rectangle 36 pt in, clipped to the
// artboard.
let back = crate::import(&out.bytes).unwrap();
let art = back.document.layers[0].children().unwrap().clone();
let clipped = art[0].children().unwrap();
assert_eq!(clipped[0].geometric_bounds().unwrap(), Rect::new(36.0, 36.0, 236.0, 136.0));
assert_eq!(clipped[1].geometric_bounds().unwrap(), Rect::new(56.0, 56.0, 156.0, 96.0));
assert!(back.warnings.iter().any(|w| w.contains("first of the file's 4 pages")), "{:?}", back.warnings);
}
#[test]
fn separations_screens_flatness_negatives_and_tiles() {
let d = doc();
let sheet = PrintPage { negative: true, ink: Some(("Cyan", 85.0, 15.0)), window: Some(Rect::new(0.0, 0.0, 100.0, 100.0)), ..page(&d, None) };
let job = PrintJob { level: Level::Two, flatness: Some(3.0), ..PrintJob::default() };
let ps = text(&print(&[sheet], &[0], &job).unwrap());
assert!(ps.contains("%%PlateColor: Cyan\n"));
assert!(ps.contains("85 15 {dup mul exch dup mul add 1 exch sub} setscreen"));
assert!(ps.contains("{1 exch sub} settransfer 1 g 0 0 612 792 rectfill"));
assert!(ps.contains("3 setflat"));
assert!(ps.contains("%%LanguageLevel: 2"));
// The tile clips the page.
assert!(ps.contains("0 0 m\n100 0 l\n100 100 l\n0 100 l\n"), "{ps}");
assert!(print(&[], &[], &job).is_err());
assert!(print(&[PrintPage { size: (f64::NAN, 1.0), ..page(&d, None) }], &[0], &job).is_err());
}