From 003ce917dfa8698b46fc3fad0e0c316c4a61158a Mon Sep 17 00:00:00 2001 From: Matthew Farrow Date: Fri, 9 Oct 2026 03:16:11 -0400 Subject: [PATCH] EPS import: a font name re-encoded as +* names the font A program that re-encodes a font in an EPS sets the copy under a name with a `*` suffix (`KBKNNM+RollerBabyBV*1`). The suffix was part of the family name, so the installed font was never found and text fell back to a substitute. The suffix is dropped when `*` is followed only by digits. Co-Authored-By: Claude Sonnet 5.5 --- crates/eps/src/import/tests_fontnames.rs | 10 ++++++++++ crates/eps/src/import/text.rs | 6 +++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/crates/eps/src/import/tests_fontnames.rs b/crates/eps/src/import/tests_fontnames.rs index 01061bbb..8aa4c0ed 100644 --- a/crates/eps/src/import/tests_fontnames.rs +++ b/crates/eps/src/import/tests_fontnames.rs @@ -36,3 +36,13 @@ fn postscript_names_resolve_to_the_available_family() { }); assert_eq!(styles, [("MyFaceYaHei 3".to_string(), "Bold".to_string())]); } + +#[test] +fn reencoded_copies_of_a_font_name_the_font() { + // A program that re-encodes a font sets the copy under `+*`. + assert_eq!(crate::family_style("KBKNNM+RollerBabyBV*1"), ("Roller Baby BV".to_string(), "Regular".to_string())); + assert_eq!(crate::family_style("ABCDEF+Helvetica-Bold*12"), ("Helvetica".to_string(), "Bold".to_string())); + // Only `*` and digits at the end go; other names are as they were. + assert_eq!(crate::family_style("Odd*Name").0, "Odd*Name"); + assert_eq!(crate::family_style("*1").0, "*1"); +} diff --git a/crates/eps/src/import/text.rs b/crates/eps/src/import/text.rs index 0abf6148..42de4d0b 100644 --- a/crates/eps/src/import/text.rs +++ b/crates/eps/src/import/text.rs @@ -20,12 +20,16 @@ const DEFAULT_FONT: &str = "Helvetica"; /// A font's family and style from its PostScript name: `Helvetica-BoldOblique` → (`Helvetica`, /// `Bold Oblique`), `TimesNewRomanPS-BoldMT` → (`Times New Roman`, `Bold`), without a subset -/// prefix (`ABCDEF+`). +/// prefix (`ABCDEF+`) or the `*1` of a re-encoded copy (`ABCDEF+RollerBabyBV*1`). pub fn family_style(name: &str) -> (String, String) { let name = match name.split_once('+') { Some((prefix, rest)) if prefix.len() == 6 && prefix.bytes().all(|b| b.is_ascii_uppercase()) => rest, _ => name, }; + let name = match name.rsplit_once('*') { + Some((base, n)) if !base.is_empty() && !n.is_empty() && n.bytes().all(|b| b.is_ascii_digit()) => base, + _ => name, + }; let (family, style) = name.split_once('-').unwrap_or((name, "")); let trim = |s: &str| -> String { let s = ["PSMT", "MT", "PS"].iter().find_map(|suffix| s.strip_suffix(suffix)).unwrap_or(s);