Comprehensive format specification documenting: - Complete JSON schema structure with field descriptions - All 7 message format patterns with examples - Pattern selection logic for regular vs Type3 fonts - Hex formatting rules and deduplication behavior - Code location reference and example parsing code - Testing reference and related documentation Closes bf-35gpt
11 KiB
GLYPH_UNMAPPED Message Format Specification
Overview
The GLYPH_UNMAPPED diagnostic (diagnostic code: FONT_GLYPH_UNMAPPED) is emitted when a character code cannot be resolved to a Unicode character through pdftract's 4-level fallback chain. This specification documents the complete message format for parsing and processing these diagnostics.
JSON Schema
All GLYPH_UNMAPPED diagnostics follow the DiagnosticJson structure:
pub struct DiagnosticJson {
/// Stable string identifier (always "FONT_GLYPH_UNMAPPED")
pub code: String,
/// Human-readable description of the diagnostic
pub message: String,
/// Severity level (always "error" for GLYPH_UNMAPPED)
pub severity: String,
/// Page index where diagnostic occurred, or null for document-level
pub page_index: Option<usize>,
/// PDF object reference where issue originated, if applicable
pub location: Option<ObjectLocationJson>,
/// Optional hint for resolution
pub hint: Option<String>,
}
Base JSON Structure
{
"code": "FONT_GLYPH_UNMAPPED",
"message": "...",
"severity": "error",
"page_index": 0,
"location": null,
"hint": null
}
Field Descriptions:
| Field | Type | Value | Description |
|---|---|---|---|
code |
string | "FONT_GLYPH_UNMAPPED" |
Stable identifier for the diagnostic type |
message |
string | (varies) | Human-readable description with context-specific details |
severity |
string | "error" |
Severity level for GLYPH_UNMAPPED |
page_index |
number|null | integer or null |
Zero-based page index where the glyph resolution failed |
location |
object|null | object or null |
PDF object reference ({object_number, generation_number}) |
hint |
string|null | string or null |
Optional resolution hint (rarely used for GLYPH_UNMAPPED) |
Message Format Patterns
Pattern 1: Standard Font Miss (Regular Fonts)
Format: Character code <HEX> could not be resolved to Unicode (font ID: <FONT_ID>)
Examples:
{
"code": "FONT_GLYPH_UNMAPPED",
"message": "Character code 41 could not be resolved to Unicode (font ID: FontId(123456))",
"severity": "error",
"page_index": 0,
"location": null,
"hint": null
}
Components:
<HEX>: Uppercase hexadecimal string (1+ bytes, no0xprefix)- Single-byte:
41,01,FF - Multi-byte:
0041,000101
- Single-byte:
<FONT_ID>:FontIdstruct in debug format:FontId(<u32>)
Emission Conditions:
- All 4 resolution levels fail:
- ToUnicode CMap
- Adobe Glyph List (AGL)
- Fingerprint matching
- Shape recognition (if available)
Deduplication: Emitted exactly once per (font_id, char_code) pair
Applicable Font Types: Type1, TrueType, CIDFont, Type0
Pattern 2: Type3 Font - Generic Failure
Format: Type3 font: character code 0x<HEX> could not be resolved to Unicode
Examples:
{
"code": "FONT_GLYPH_UNMAPPED",
"message": "Type3 font: character code 0x41 could not be resolved to Unicode",
"severity": "error",
"page_index": 1,
"location": null,
"hint": null
}
Components:
<HEX>: Single-byte hexadecimal (range00-FF)- Always prefixed with
0x - Font ID is NOT included (implicit from context)
Emission Conditions:
- All Type3-specific resolution levels fail
Deduplication: Once per (font, char_code) pair
Applicable Font Types: Type3 only
Pattern 3: Type3 Font - Shape Recognition Disabled
Format: Type3 font: character code 0x<HEX> could not be resolved (shape recognition disabled)
Examples:
{
"code": "FONT_GLYPH_UNMAPPED",
"message": "Type3 font: character code 0x7F could not be resolved (shape recognition disabled)",
"severity": "error",
"page_index": 0,
"location": null,
"hint": null
}
Components:
<HEX>: Single-byte hexadecimal (00-FF)
Emission Conditions:
- Shape recognition feature disabled at compile time (
--no-default-features --features shape-db) - Level 4 fallback unavailable
Conditional Compilation: Only emitted when shape-db feature is disabled
Resolution Hint: Recompile with --features shape-db to enable Level 4 fallback
Pattern 4: Type3 Font - No Glyph Name in Encoding
Format: Type3 font: character code 0x<HEX> has no glyph name in encoding
Examples:
{
"code": "FONT_GLYPH_UNMAPPED",
"message": "Type3 font: character code 0x20 has no glyph name in encoding",
"severity": "error",
"page_index": 0,
"location": null,
"hint": null
}
Components:
<HEX>: Single-byte hexadecimal (00-FF)
Emission Conditions:
- Encoding dictionary has no entry for the character code
- Cannot proceed to shape recognition (no glyph name to look up)
Implications: Immediate resolution failure - no fallback possible
Pattern 5: Type3 Font - Glyph Not in CharProcs
Format: Type3 font: glyph '<NAME>' not found in /CharProcs for code 0x<HEX>
Examples:
{
"code": "FONT_GLYPH_UNMAPPED",
"message": "Type3 font: glyph 'A' not found in /CharProcs for code 0x41",
"severity": "error",
"page_index": 0,
"location": null,
"hint": null
}
Components:
<NAME>: Glyph name from encoding (e.g.,A,custom,g003)<HEX>: Single-byte hexadecimal (00-FF)
Emission Conditions:
- Glyph name present in encoding dictionary
- Glyph name missing from
/CharProcsdictionary - Indicates malformed Type3 font (orphan encoding entry)
Implications: Malformed PDF - encoding references non-existent glyph
Pattern 6: Type3 Font - Rasterization Failed
Format: Type3 font: failed to rasterize glyph '<NAME>' for code 0x<HEX>
Examples:
{
"code": "FONT_GLYPH_UNMAPPED",
"message": "Type3 font: failed to rasterize glyph 'complex' for code 0x02",
"severity": "error",
"page_index": 1,
"location": null,
"hint": null
}
Components:
<NAME>: Glyph name from encoding<HEX>: Single-byte hexadecimal (00-FF)
Emission Conditions:
- Glyph exists in
/CharProcs - Content stream rendering failed during bitmap generation
- Indicates corrupt or malformed content stream
Implications: Malformed glyph content stream - cannot generate bitmap for shape matching
Pattern 7: Type3 Font - Shape Match Below Threshold
Format: Type3 font: shape match for '<NAME>' (code 0x<HEX>) found but distance <DIST> exceeds threshold
Examples:
{
"code": "FONT_GLYPH_UNMAPPED",
"message": "Type3 font: shape match for 'A' (code 0x41) found but distance 12 exceeds threshold",
"severity": "error",
"page_index": 0,
"location": null,
"hint": null
}
Components:
<NAME>: Glyph name<HEX>: Single-byte hexadecimal (00-FF)<DIST>: Hamming distance (integer, typically 0-255)
Emission Conditions:
- Shape match was found in database
- Hamming distance exceeded acceptable threshold (default: 8)
- Indicates "close but not confident enough" match
Implications: Low-confidence match - rejected to avoid false positives
Conditional Compilation: Only emitted when shape-db feature is enabled
Pattern Selection Logic
Regular Fonts (Type1, TrueType, CIDFont, Type0)
- Pattern used: Pattern 1 only
- Character codes: Can be multi-byte (e.g.,
0041for 2-byte CID key) - Font ID: Always included
- Failure reasons: Generic (all 4 levels failed)
Type3 Fonts
- Patterns used: Patterns 2-7
- Character codes: Always single-byte (
00-FF) - Font ID: NOT included (implicit from context)
- Failure reasons: Specific (encoding, CharProcs, rasterization, shape match)
Hex Formatting Rules
| Pattern | Hex Format | Prefix | Example |
|---|---|---|---|
| Pattern 1 | Concatenated uppercase hex | None | 41, 0041, 000101 |
| Patterns 2-7 | Single-byte uppercase hex | 0x |
0x41, 0xFF, 0x01 |
Deduplication Behavior
All patterns use the same deduplication mechanism:
- Cache key:
(font_id, char_code)for Pattern 1;(font, char_code)for Type3 patterns - Storage:
ResolverCache::emitted_misses(HashSet) - Behavior: First occurrence is emitted; subsequent occurrences are suppressed
- Scope: Per-document (cache resets on new document)
Code Location Reference
| Component | File | Lines |
|---|---|---|
| Diagnostic code enum | diagnostics.rs |
576 |
| Code string constant | diagnostics.rs |
1291 |
| JSON schema definition | schema/mod.rs |
813-834 |
| Pattern 1 emission | font/resolver.rs |
681-708 |
| Pattern 2 emission | font/resolver.rs |
565-571 |
| Pattern 3 emission | font/resolver.rs |
575-583 |
| Pattern 4 emission | font/resolver.rs |
616-624 |
| Pattern 5 emission | font/resolver.rs |
631-638 |
| Pattern 6 emission | font/resolver.rs |
645-652 |
| Pattern 7 emission | font/resolver.rs |
667-674 |
Example Parsing Code
use serde_json::Value;
fn parse_glyph_unmapped(diagnostic: &Value) -> GlyphUnmappedInfo {
let message = diagnostic["message"].as_str().unwrap();
// Pattern 1: Regular font miss
if let Some(caps) = regex!(r"Character code ([0-9A-F]+) could not be resolved to Unicode \(font ID: FontId\((\d+)\)\)")
.captures(message)
{
return GlyphUnmappedInfo::RegularFont {
char_code: caps.get(1).unwrap().as_str().to_string(),
font_id: caps.get(2).unwrap().as_str().parse::<u32>().unwrap(),
};
}
// Pattern 5: Glyph not in CharProcs
if let Some(caps) = regex!(r"Type3 font: glyph '([^']+)' not found in /CharProcs for code 0x([0-9A-F]{2})")
.captures(message)
{
return GlyphUnmappedInfo::Type3GlyphNotInCharProcs {
glyph_name: caps.get(1).unwrap().as_str().to_string(),
char_code: u8::from_str_radix(caps.get(2).unwrap().as_str(), 16).unwrap(),
};
}
// ... other patterns
GlyphUnmappedInfo::Unknown
}
Testing Reference
- Test fixture:
tests/fixtures/encoding/no-mapping.pdf - Test code:
crates/pdftract-core/tests/font_integration.rs(GLYPH_UNMAPPED emission tests) - Schema test:
crates/pdftract-core/src/schema/mod.rs::test_diagnostic_json()
Related Documentation
- Analysis of message patterns:
notes/bf-5n4dp.md - Font resolver implementation:
crates/pdftract-core/src/font/resolver.rs - Diagnostic system overview:
crates/pdftract-core/src/diagnostics.rs(module documentation)
Version History
- 2025-01-XX: Initial specification creation (bf-35gpt)
- Previous analysis: bf-5n4dp (pattern identification)
This specification is maintained as part of the pdftract project. For the latest version, refer to the source code and documentation in the /home/coding/pdftract repository.