* 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>
craft-ps
PostScript and EPS for the Craft apps. No feature is enabled by default.
| Feature | Provides |
|---|---|
read |
An EPS interpreter: runs the program and returns what it paints as a one-page PDF |
Writing PostScript and EPS (craft-libs #115) is planned as a separate feature next to read.
Reading EPS
read::eps_to_pdf(bytes, limits) runs an EPS (plain, or DOS EPS with a binary header) and
returns a one-page PDF 1.4 the size of its bounding box: vectors stay vectors, CMYK and spot
colours stay as they are, so an app can draw and export the result as a placed PDF.
read::cached_pdf converts with the default limits and remembers the result by content.
is_eps, bounding_box and postscript_section read the file without running it.
EPS binary sections and DSC comments are read by craft-eps.
It is written from the PostScript Language Reference (third edition), the EPS specification, the Type 1 Font Format and Adobe Technical Notes 5012 (Type 42), 5176 (CFF) and 5177 (Type 2 charstrings); no GPL code was used. It covers what EPS files use:
- the language: Level 3 operators, an explicit execution stack (no Rust recursion for
PostScript control flow),
stopped, resources,eexec; - graphics: paths, painting, clipping,
strokepath, user paths and forms; - colour: device spaces, Separation and DeviceN, Indexed, ICCBased, Lab;
- images, with filters decoded as they are read (ASCIIHex, ASCII85, RunLength, LZW, Flate with predictors, SubFile, ReusableStream; JPEG is passed through);
- smooth shadings (types 1–7, meshes included), shading and tiling patterns;
- text in Type 1, Type 3, Type 42 and CFF fonts (
StartData), CIDFonts and composite fonts through CMaps, horizontal and vertical.
Not covered: Level 2 binary tokens, CIDFontType 0 with Type 1 charstrings, CIDFontType 1 and the old composite FMapTypes other than 2 and 9.
Limits
Limits { steps, memory, stack_overflow_noop, skip_images, keep_unpainted, zero_division_zero, fallback_font } bounds one conversion. The optional font callback supplies host stand-ins for missing fonts; booleans let a host retain prior operand-overflow, image, partial-page, and numeric-coercion behavior. Every operator charges the work it does in
proportion to its operands (elements copied or searched, path segments, glyphs, samples)
against steps as it goes, and every byte read or decoded at any filter level counts too, so
the step limit bounds run time. memory bounds everything a conversion makes, copies
included. The defaults are 50 million steps and 1 GiB, or 20 million and 256 MiB on wasm32;
real EPS files use at most a few million steps and tens of megabytes, and a program that runs
into the limits ends within seconds. By default a program that fails or exceeds them before
painting anything gives Err; setting keep_unpainted returns a blank page with the warning.
One that fails later keeps what it painted (with a warning).
cargo run -p craft-ps --features read --example eps2pdf -- in.eps out.pdf converts one file
and prints the steps and memory it used.