fix specific decoding issues

This commit is contained in:
Abimael Martell
2026-02-20 21:16:12 -08:00
parent b23d073553
commit 97910e86bf
3 changed files with 65 additions and 9 deletions
+16 -8
View File
@@ -674,21 +674,29 @@ pub(crate) fn extract_text_from_operand(
// This prevents partial CMap results from blocking the Differences path.
if entry.primary.code_byte_length == 1 {
let encoding_map = font_encodings.get(current_font);
let lookups = entry.primary.lookup_bytes(bytes);
let decoded: String = lookups
let decoded: String = bytes
.iter()
.filter_map(|&(b, ref cmap_result)| {
// 1. CMap mapped it? Use CMap result
if let Some(s) = cmap_result {
return Some(s.clone());
.filter_map(|&b| {
let code = b as u16;
// 1. Primary CMap
if let Some(s) = entry.primary.lookup(code) {
if !s.contains('\u{FFFD}') {
return Some(s);
}
}
// 2. Differences mapped it? Use Differences result
// 2. Fallback CMap (embedded font cmap)
if let Some(fb) = entry.fallback.as_ref().and_then(|c| c.lookup(code)) {
if !fb.contains('\u{FFFD}') {
return Some(fb);
}
}
// 3. Differences mapped it? Use Differences result
if let Some(map) = encoding_map {
if let Some(&ch) = map.get(&b) {
return Some(ch.to_string());
}
}
// 3. Printable ASCII/Latin-1 fallback
// 4. Printable ASCII/Latin-1 fallback
if b >= 0x20 {
return Some((b as char).to_string());
}
+4 -1
View File
@@ -1725,7 +1725,7 @@ pub fn build_glyph_to_unicode_map() -> HashMap<&'static str, char> {
m.insert("controlRS", '\x1E');
m.insert("controlSI", '');
m.insert("controlSO", '');
m.insert("controlSOT", '');
m.insert("controlSOT", '˜');
m.insert("controlSTX", '');
m.insert("controlSUB", '');
m.insert("controlSYN", '');
@@ -4544,6 +4544,9 @@ static GLYPH_TO_UNICODE: LazyLock<HashMap<&'static str, char>> = LazyLock::new(|
// Local overrides for non-standard glyph names seen in PDFs.
m.insert("C21", '≥');
m.insert("C25", '≈');
// Some Type1 fonts use custom glyph names for ASCII tilde.
m.insert("C19", '~');
m.insert("C24", '~');
m
});
+45
View File
@@ -758,6 +758,22 @@ fn build_simple_cmap_from_truetype(font_data: &[u8]) -> Option<ToUnicodeCMap> {
cmap.char_map.insert(gid, ch.to_string());
}
}
// Fill missing single-byte codes from glyph names (helps with ligatures like "t_i").
for gid in 0..face.number_of_glyphs() {
let gid = ttf_parser::GlyphId(gid);
let gid_val = gid.0;
if gid_val > 0xFF || cmap.char_map.contains_key(&gid_val) {
continue;
}
if let Some(name) = face.glyph_name(gid) {
if gid_val == 0x1B {
debug!("simple cmap glyph gid=0x1B name={:?}", name);
}
if let Some(s) = glyph_name_to_string(name) {
cmap.char_map.insert(gid_val, s);
}
}
}
if cmap.char_map.is_empty() {
return None;
}
@@ -769,6 +785,35 @@ fn build_simple_cmap_from_truetype(font_data: &[u8]) -> Option<ToUnicodeCMap> {
Some(cmap)
}
fn glyph_name_to_string(name: &str) -> Option<String> {
let base = name.split('.').next().unwrap_or(name);
if let Some(ch) = glyph_to_char(base) {
return Some(ch.to_string());
}
if base.contains('_') {
let mut out = String::new();
for part in base.split('_') {
if part.is_empty() {
return None;
}
if let Some(ch) = glyph_to_char(part) {
out.push(ch);
} else if part.len() == 1 {
out.push(part.chars().next().unwrap());
} else {
return None;
}
}
if !out.is_empty() {
return Some(out);
}
}
if matches!(base, "ti" | "tt" | "tz") {
return Some(base.to_string());
}
None
}
/// Build a ToUnicodeCMap from a font's glyph names (post table).
/// Uses Adobe Glyph List to map glyph names to Unicode.
fn build_cmap_from_glyph_names(face: &ttf_parser::Face<'_>) -> Option<ToUnicodeCMap> {