This guide shows developers how to use PDFluent to manage fonts in PDF documents, ensuring compatibility and optimising file size.
Strip unused glyphs from embedded fonts so the PDF only carries the characters that actually appear in the document.
use pdfluent::PdfDocument;
fn main() -> pdfluent::Result<()> {
let mut doc = PdfDocument::open("report.pdf")?;
let _report = doc.subset_fonts()?;
doc.save("subset.pdf")?;
Ok(())
}Before subsetting, you can list embedded fonts and their sizes to understand what will change.
use pdfluent::PdfDocument;
let mut doc = PdfDocument::open("input.pdf")?;
println!("{} pages", doc.page_count());FontSubsetOptions controls which font types are processed. Type 1 fonts often have limited glyph sets already; focus on TrueType and OpenType where gains are largest.
// subset_fonts() removes unused glyphs from embedded fonts.
// It is core-tier and takes no configuration in 1.0.PDFluent scans every page content stream, collects the Unicode codepoints actually used, then rewrites each embedded font to contain only those glyphs.
let report = doc.subset_fonts()?;
println!(
"Subsetted {} of {} fonts, saved {} bytes",
report.fonts_subsetted, report.fonts_processed, report.bytes_saved,
);Check the font sizes again after subsetting to measure the reduction.
// The FontSubsetReport summarises the result:
// fonts_processed - fonts_subsetted - bytes_saved
println!("bytes saved: {}", report.bytes_saved);Write the subsetted file. Combine with compress_streams() for maximum size reduction.
use pdfluent::CompressOptions;
doc.compress(CompressOptions::strict())?;
doc.save("subsetted.pdf")?;Scan every page resource dictionary and identify fonts that are referenced but not embedded in the file.
use pdfluent::PdfDocument;
fn main() -> pdfluent::Result<()> {
let doc = PdfDocument::open("input.pdf")?;
let missing: Vec<_> = doc
.fonts()
.filter(|f| !f.is_embedded() && !f.is_standard_14())
.collect();
if missing.is_empty() {
println!("All fonts are embedded.");
} else {
for font in &missing {
println!("Missing: {} ({:?})", font.name(), font.font_type());
}
std::process::exit(1);
}
Ok(())
}For an audit task you only need a read-only Document.
let doc = PdfDocument::open("input.pdf")?;doc.fonts() returns an iterator over all font dictionaries referenced from any page resource dictionary in the document.
for font in doc.fonts() {
println!(
"name={} type={:?} embedded={} standard14={}",
font.name(),
font.font_type(),
font.is_embedded(),
font.is_standard_14(),
);
}Standard 14 fonts (Helvetica, Times-Roman, Courier, etc.) are provided by PDF viewers and do not need embedding. All other fonts should be embedded for reliable rendering.
let unembedded: Vec<_> = doc
.fonts()
.filter(|f| !f.is_embedded() && !f.is_standard_14())
.collect();To know which page each font appears on, iterate page by page.
for (i, page) in doc.pages().enumerate() {
for font in page.fonts() {
if !font.is_embedded() && !font.is_standard_14() {
println!("Page {}: unembedded font {}", i + 1, font.name());
}
}
}Use the missing font list to fail a CI pipeline when required fonts are absent.
if !unembedded.is_empty() {
eprintln!("{} unembedded font(s) found", unembedded.len());
std::process::exit(1);
}