EPS import: a font name re-encoded as <subset>+<name>*<n> names the font

A program that re-encodes a font in an EPS sets the copy under a name with a
`*<n>` 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 <noreply@anthropic.com>
This commit is contained in:
Matthew Farrow 2026-10-09 03:16:11 -04:00
parent 5d74c5bb77
commit 003ce917df
2 changed files with 15 additions and 1 deletions

View File

@ -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 `<subset>+<name>*<n>`.
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");
}

View File

@ -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);