Files
craft-libs/crates/ps/examples/eps2pdf.rs
T
41fb227542 feat(ps): add bounded shared PostScript EPS reader (#1276)
* feat(ps): add craft-ps with an EPS reader (read feature)

The reading half of craft-ps (#115): a clean-room PostScript interpreter
that runs an EPS and returns what it paints as a one-page vector PDF of
its bounding box, colours kept, so apps can draw and export EPS as a
placed PDF. Moved from DesignCraft (storytold/designcraft, where it was
written for placed EPS), with its app-specific names made neutral.

Written from the PostScript Language Reference (3rd ed.), the EPS
specification, the Type 1 Font Format and Adobe TN 5012/5176/5177.
Covers the language, paths, clipping, strokepath, device/Separation/
DeviceN/Indexed/ICCBased/Lab colour, images with lazily decoded filters,
shadings 1-7 and patterns, and Type 1/3/42/CFF/CID text through CMaps,
horizontal and vertical.

Bounded: each operator charges work proportional to its operands
against the step limit as it goes, every byte read or decoded counts,
copies count against the memory cap; defaults 50 M steps / 1 GiB, and
20 M / 256 MiB on wasm32. No panics (deny lints, fuzzed in debug
builds). 34 tests, the Type 42 one on a TrueType font built in the
test. No new external crates: pdf-writer, miniz_oxide, weezl, skrifa
and kurbo are already locked at these versions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* clippy(ps): document stateful decoder complexity

* fix(ps): bound huge arc angle normalization

* fix(ps): preserve EffectCraft EPS text and limits parity

* fix(ps): address interpreter review findings

* fix(ps): preserve composite glyph paint order

* fix(ps): address interpreter review findings

* fix(ps): bound filter buffers and preserve file aliases

* fix(ps): make predictor allocation fallible

---------

Co-authored-by: markus.doebele <markus.doebele@top21.sh>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 06:10:27 -05:00

42 lines
1.5 KiB
Rust

//! `cargo run -p craft-ps --features read --example eps2pdf -- in.eps out.pdf`: convert one EPS.
fn main() -> std::process::ExitCode {
let args: Vec<String> = std::env::args().skip(1).collect();
let (Some(input), Some(output)) = (args.first(), args.get(1)) else {
eprintln!("usage: eps2pdf in.eps out.pdf");
return std::process::ExitCode::FAILURE;
};
let bytes = match std::fs::read(input) {
Ok(b) => b,
Err(e) => {
eprintln!("{input}: {e}");
return std::process::ExitCode::FAILURE;
}
};
let t = std::time::Instant::now();
match craft_ps::read::eps_to_pdf(&bytes, craft_ps::read::Limits::default()) {
Ok(c) => {
eprintln!(
"{input}: {:.0} ms, bbox {:?}, {} warnings, {} steps, {} KiB",
t.elapsed().as_secs_f64() * 1000.0,
c.bbox,
c.warnings.len(),
c.steps,
c.memory / 1024
);
for w in c.warnings.iter().take(20) {
eprintln!(" {w}");
}
if let Err(e) = std::fs::write(output, &c.pdf) {
eprintln!("{output}: {e}");
return std::process::ExitCode::FAILURE;
}
std::process::ExitCode::SUCCESS
}
Err(e) => {
eprintln!("{input}: {e} ({:.0} ms)", t.elapsed().as_secs_f64() * 1000.0);
std::process::ExitCode::FAILURE
}
}
}