| name | pdfium-impl-fonts |
| description | Use when embedding a custom TrueType or Type1 font into a PDF with pdfium-render, selecting one of the 14 built-in PDF fonts, inspecting font metadata, working with glyphs, or extracting an embedded font from a document. Prevents the removed-PdfFont-constructor compile error, garbled or unselectable text from a wrong is_cid_font flag, and the assumption that built-in fonts can render emoji. Covers PdfFonts loading constructors, PdfFontToken, PdfFontBuiltin, PdfFont inspection, PdfFontGlyphs, and embedded-font extraction across pdfium-render 0.8.x and 0.9.x. Keywords: pdfium-render, PdfFonts, PdfFont, PdfFontToken, PdfFontGlyphs, PdfFontBuiltin, load_true_type_from_bytes, load_type1_from_file, helvetica, embed font, custom font, is_cid_font, is_embedded, extract font, garbled text, unselectable text, text shows as boxes, copied text is wrong, emoji not rendering, how do I embed a font in a PDF, how to use a custom font.
|
| license | MIT |
| compatibility | Designed for Claude Code. Requires pdfium-render 0.8,0.9. |
| metadata | {"author":"OpenAEC-Foundation","version":"1.0"} |
pdfium-render: Fonts
Registering, embedding, inspecting, and extracting fonts with pdfium-render. A font
must be added to a document's PdfFonts collection before any text object can use
it. This skill owns the font lifecycle. Creating the text objects that consume a
font is pdfium-impl-page-objects-edit; reading page text is pdfium-syntax-text.
All API names below are verified against docs.rs/pdfium-render 0.9.1. The default
target is the 0.9.x API; 0.8.x differences are flagged inline.
Quick Reference
| Goal | API | Returns |
|---|
| Get the font collection | PdfDocument::fonts() / fonts_mut() | &PdfFonts / &mut PdfFonts |
| Use a built-in font | PdfFonts::helvetica() etc. | PdfFontToken |
| Use a built-in by enum | PdfFonts::new_built_in(PdfFontBuiltin) | PdfFontToken |
| Embed a TrueType font | PdfFonts::load_true_type_from_bytes(data, is_cid) | Result<PdfFontToken, _> |
| Embed a Type1 font | PdfFonts::load_type1_from_bytes(data, is_cid) | Result<PdfFontToken, _> |
| Look up a registered font | PdfFonts::get(token) | Option<&PdfFont> |
| Inspect a font | PdfFont::name/family/weight/is_embedded | see methods.md |
| Read raw font program | PdfFont::data() | Result<Vec<u8>, _> |
| Walk glyphs | PdfFont::glyphs() | &PdfFontGlyphs |
PdfFontBuiltin variants (14): TimesRoman, TimesBold, TimesItalic,
TimesBoldItalic, Helvetica, HelveticaBold, HelveticaOblique,
HelveticaBoldOblique, Courier, CourierBold, CourierOblique,
CourierBoldOblique, Symbol, ZapfDingbats.
Full signatures with version annotations: see references/methods.md.
The Token Model
PdfFonts constructors do NOT return a PdfFont. They return a PdfFontToken: a
small Copy handle that references a font registered in the document. The flow is
always:
fonts_mut() -> load/built-in constructor -> PdfFontToken (Copy)
-> pass token to PdfPageTextObject::new()
-> fonts().get(token) -> Option<&PdfFont> for inspection
PdfFontToken is Copy, Eq, and Hash, so registering a font ONCE and reusing
the token everywhere is correct and cheap. PdfFontToken is NOT Send/Sync; do
not move it across threads.
ALWAYS register a font once per document and reuse its token. NEVER call a load
function repeatedly for the same font: each call embeds another copy of the font
program and inflates the file.
Version Trap: removed PdfFont constructors
Direct PdfFont constructors (PdfFont::new_*) were deprecated in 0.8.3 and
REMOVED in 0.9.0. Code that constructs a PdfFont directly does not compile against
0.9.x.
let font = PdfFont::new_true_type_from_bytes(&document, &bytes, true)?;
let token = document.fonts_mut().load_true_type_from_bytes(&bytes, true)?;
ALWAYS obtain fonts through document.fonts_mut(). A PdfFont reference is only
ever read back with fonts().get(token) or from a text object's font().
Decision Tree: which font
Need a standard Latin font, no embedding, smallest file?
-> PdfFonts::helvetica() / times_roman() / courier() (+ bold/italic variants)
These are the 14 built-in PDF fonts; viewers supply the glyphs.
Need a specific brand / non-Latin / Unicode font in the output?
-> embed it: load_true_type_from_bytes / load_type1_from_bytes
The font program is stored IN the PDF.
Embedding a CJK or large-Unicode font (multi-byte character codes)?
-> is_cid_font = true
Embedding a simple single-byte Latin font?
-> is_cid_font = false
Need to read or save a font already inside a PDF?
-> text_object.font() -> is_embedded()? -> data()
Pattern: Built-In Font
The 14 built-in fonts need no font file. The constructor takes &mut self, so call
it through fonts_mut():
use pdfium_render::prelude::*;
let pdfium = Pdfium::default();
let mut document = pdfium.create_new_pdf()?;
let helvetica = document.fonts_mut().helvetica();
new_built_in(PdfFontBuiltin) is the enum-driven equivalent:
let token = document.fonts_mut().new_built_in(PdfFontBuiltin::TimesBold);
Built-in fonts cover Latin text only. They CANNOT render emoji, CJK, or other
scripts outside their character set. For anything else, embed a font.
Pattern: Embed a Custom TrueType Font
use pdfium_render::prelude::*;
let pdfium = Pdfium::default();
let mut document = pdfium.create_new_pdf()?;
let font_bytes = std::fs::read("Inter-Regular.ttf")?;
let inter = document.fonts_mut()
.load_true_type_from_bytes(&font_bytes, false)?;
let other = document.fonts_mut()
.load_true_type_from_file("NotoSansJP-Regular.ttf", true)?;
let _ = (inter, other);
load_true_type_from_file, load_true_type_from_reader, and
load_true_type_from_bytes all take (source, is_cid_font: bool) and return
Result<PdfFontToken, PdfiumError>. Type1 fonts use the matching
load_type1_from_* functions. The _from_fetch and _from_blob async variants
exist for WASM targets only (see pdfium-impl-wasm).
The is_cid_font Flag
is_cid_font is the single most important font-embedding decision and a documented
cause of garbled text (issues #84, #226).
is_cid_font = true: the font is registered as a CID-keyed font, using
multi-byte character codes. ALWAYS use true for CJK fonts and for large-Unicode
TrueType fonts that must cover characters beyond a single-byte range.
is_cid_font = false: the font is registered as a simple font with single-byte
character codes. Use false for simple Latin fonts.
A mismatch between the flag and the font's actual encoding maps character codes to
the wrong glyphs: the rendered text looks like garbage, boxes, or ÿ characters,
and copied text comes back wrong. See references/anti-patterns.md.
Pattern: Inspect a Font
Look a registered font back up with get(token), or take it from a text object:
if let Some(font) = document.fonts().get(token) {
println!("name: {}", font.name());
println!("family: {}", font.family());
println!("embedded: {:?}", font.is_embedded());
println!("serif: {}", font.is_serif());
println!("italic: {}", font.is_italic());
println!("weight: {:?}", font.weight());
}
PdfFont::name() and family() return String. The is_* predicate methods
return bool directly. is_embedded(), weight(), italic_angle(), ascent(),
and descent() return a Result because they query the PDFium font program.
ascent(font_size) and descent(font_size) take a PdfPoints size.
Pattern: Extract an Embedded Font
PdfFont::data() returns the raw font program. Combined with is_embedded() this
extracts fonts from an existing PDF:
let pdfium = Pdfium::default();
let document = pdfium.load_pdf_from_file("input.pdf", None)?;
for page in document.pages().iter() {
for object in page.objects().iter() {
if let Some(text_object) = object.as_text_object() {
let font = text_object.font();
if font.is_embedded()? {
let program = font.data()?;
std::fs::write(format!("{}.fontdata", font.name()), program)?;
}
}
}
}
text_object.font() returns a PdfFont by value. Narrowing a PdfPageObject to
PdfPageTextObject with as_text_object() is covered by pdfium-syntax-page-objects.
NEVER call data() on a non-embedded font expecting the font file: built-in fonts
are supplied by the viewer, not stored in the PDF.
Glyphs
PdfFont::glyphs() returns &PdfFontGlyphs, the font's glyph collection:
let glyphs = font.glyphs();
println!("glyph count: {}", glyphs.len());
for glyph in glyphs.iter() {
let width = glyph.width_at_font_size(PdfPoints::new(12.0));
let _ = width;
}
PdfFontGlyphs exposes len(), is_empty(), as_range(), as_range_inclusive(),
get(index), and iter(). A PdfFontGlyph gives width_at_font_size(PdfPoints)
and segments_at_font_size(PdfPoints) for the glyph outline path. Glyph indices use
the PdfFontGlyphIndex type alias.
Version Traps
| Item | 0.8.x | 0.9.x | Action |
|---|
PdfFont::new_* direct constructors | deprecated 0.8.3 | REMOVED | use PdfFonts load/built-in functions |
PdfFonts collection | present | present | reach it via fonts() / fonts_mut() |
_from_fetch / _from_blob loaders | WASM only | WASM only | native code uses _from_file/_bytes/_reader |
Anti-Patterns (summary)
- Calling a removed
PdfFont::new_* constructor: register via fonts_mut().
- Wrong
is_cid_font flag: garbled, boxed, or unselectable text.
- Expecting a built-in font to render emoji or CJK: it cannot; embed a font.
- Re-loading the same font per text object: bloats the file; register once, reuse
the
Copy token.
- Calling
data() on a non-embedded font and expecting the font program.
Each anti-pattern with the failure detail and fix: see references/anti-patterns.md.
Cross-References
pdfium-impl-page-objects-edit: building the PdfPageTextObject that uses a
PdfFontToken (PdfPageTextObject::new takes impl ToPdfFontToken).
pdfium-syntax-text: reading existing page text and per-character font info.
pdfium-syntax-page-objects: narrowing PdfPageObject with as_text_object().
pdfium-impl-wasm: the load_*_from_fetch / load_*_from_blob async loaders.
pdfium-core-memory: the self-referential trap when storing a document with its
fonts in one struct (0.9.0 relaxed this).
pdfium-errors-runtime: PdfiumError variants from font loading.
Reference Files
references/methods.md: complete API signatures with version annotations.
references/examples.md: verified, runnable Rust programs.
references/anti-patterns.md: real failures, why they fail, the fix.
Source
Verified 2026-05-20 against https://docs.rs/pdfium-render/latest/pdfium_render/
(prelude struct pages for PdfFonts, PdfFont, PdfFontToken, PdfFontGlyphs,
PdfFontGlyph, PdfPageTextObject, PdfDocument, and the PdfFontBuiltin enum).