From 4614c08476da3626e70917c11e65ddb67cf9c557 Mon Sep 17 00:00:00 2001 From: Ronald Hunter <15822615+rotohun@users.noreply.github.com> Date: Sun, 18 Oct 2026 20:59:22 -0400 Subject: [PATCH] eps: read Illustrator text with hyphenation and tab attributes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Illustrator 6/8 EPS files whose PostScript can't be run (the Adobe_level2_AI5 procset is provided by the RIP, not embedded) are read through their private layer data instead. That reader aborted the whole file when a text object carried the hyphenation/tab-ruler operators `Th` (hyphen control), `XL` (hyphenation language) and `Xb`/`XB` (a tab definition, with `Xe` descriptions between them), reporting them as operators it doesn't know. These carry no geometry, so drop them like the sibling type attributes the reader already discards (§22 of the Illustrator File Format Specification) rather than failing the import. --- crates/eps/src/import/ai/read.rs | 4 ++++ crates/eps/src/import/tests_illustrator.rs | 17 +++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/crates/eps/src/import/ai/read.rs b/crates/eps/src/import/ai/read.rs index 432a3dd23..357b88fe6 100644 --- a/crates/eps/src/import/ai/read.rs +++ b/crates/eps/src/import/ai/read.rs @@ -1324,6 +1324,10 @@ impl<'a> Reader<'a> { // Far-Eastern type) and final-form positions (§15.3). "Tk" | "TK" | "TC" | "TW" | "Tq" | "Tc" | "Tw" | "Tm" | "Td" | "T*" | "TR" | "T+" | "T-" | "TV" | "Tv" | "Ty" | "TY" | "TG" | "Tg" | "Tu" | "Xu" => {} + // Hyphenation and tab-ruler attributes the reader doesn't keep either (§22): `Th` + // hyphen control, `XL` hyphenation language, `Xb`/`XB` a tab definition (and the `Xe` + // tab descriptions between them). + "Th" | "XL" | "Xb" | "XB" | "Xe" => {} "TE" => self.te(&vals), // An image whose samples follow in comment lines (read at `%AI5_EndRaster`). "XI" if self.raster.is_some() => { diff --git a/crates/eps/src/import/tests_illustrator.rs b/crates/eps/src/import/tests_illustrator.rs index eeff5610b..19c79deeb 100644 --- a/crates/eps/src/import/tests_illustrator.rs +++ b/crates/eps/src/import/tests_illustrator.rs @@ -121,6 +121,23 @@ fn a_postscript_ai_whose_layers_cant_be_read_says_why() { assert!(e.contains("`Adobe_packedarray`") && e.contains("its layers couldn't be read either") && e.contains("`frobnicate`"), "{e}"); } +/// A `.ai` in PostScript form (read through its layers) whose text carries hyphenation and +/// tab-ruler attributes: `XL` (hyphenation language), `Xb`/`XB` (a tab definition) and `Th` +/// (hyphen control). These keep no geometry, so the reader drops them rather than failing the +/// file the way it did before — the symptom seen on Illustrator 6/8 EPS files whose +/// `Adobe_level2_AI5` program can't be run. +#[test] +fn text_with_hyphenation_and_tab_attributes_opens_instead_of_failing() { + let text = "0 To\n1 0 0 1 10 50 0 Tp\nTP\n0 Tr\n0 0 0 1 k\n/_Helvetica 9 Tf\n\ + %_ 0 XL\n36 0 Xb\nXB\n0 1 2 2 99 Th\n0 Ta\n(hi) Tx\nTO\n"; + // The operators sit on a visible layer (so they'd be reported as unknown, not quietly skipped + // on a hidden one), beside the square so the layer is never empty. + let src = NAMED_PROLOG.replace("S\nLB\n%AI5_EndLayer--\n%AI5_BeginLayer", &format!("S\n{text}LB\n%AI5_EndLayer--\n%AI5_BeginLayer")); + let r = import(src.as_bytes()).unwrap(); + assert!(!r.preview, "read through the layers, not a fallback preview"); + assert!(!r.warnings.iter().any(|w| w.contains("doesn't know") || w.contains("couldn't be read")), "{:?}", r.warnings); +} + /// An Illustrator 3 file of paths alone, as image editors export their paths (storytold/photocraft#6036): /// no prolog and no layers, the paths unpainted (`n` closes, `N` doesn't), a compound path of two. const PATHS_ONLY: &str = "%!PS-Adobe-2.0 EPSF-1.2\n%%Creator: an image editor\n%%BoundingBox: 0 0 200 100\n\