Inspect PDF Fonts and Embedding with pdffonts
pdffonts lists every font a PDF uses, whether each one is embedded, whether it is a subset, and whether it carries a ToUnicode map. The examples use pdffonts from Poppler 24.02.0, supplied here by Ubuntu package poppler-utils version 24.02.0-1ubuntu9.9.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about ten minutes. You need a readable PDF and a shell: these are ordinary user commands and do not need sudo. This guide only reads PDFs; it does not repair fonts, rewrite a document or change system font configuration.
1. Check the installed command
Confirm the command is the Poppler utility you expect, then read its local help. This catches machines where the package is missing or a different executable sits earlier in PATH:
$ command -v pdffonts
/usr/bin/pdffonts
$ dpkg-query -W -f='${Package} ${Version}\n' poppler-utils
poppler-utils 24.02.0-1ubuntu9.9
$ pdffonts -v
pdffonts version 24.02.0
Your package revision and copyright lines may differ. What matters is that a version prints and the executable is the one you intended to run. If dpkg-query says poppler-utils is not installed, install it through your normal package process before continuing.
Checkpoint
You have a readable PDF path and know which pdffonts binary will inspect it.
2. List every font in a PDF
Pass the PDF as the final argument, using a path that names an existing file rather than a shell wildcard that could grab the wrong document:
$ pdffonts /path/to/document.pdf
name type encoding emb sub uni object ID
------------------------------------ ----------------- ---------------- --- --- --- ---------
TWYWUS+NimbusSanL-Bold Type 1 Custom yes yes yes 105 0
KZEACY+NimbusRomNo9L-Regu Type 1 Custom yes yes yes 109 0
Rows depend entirely on the PDF. A font can appear only once even when used across many pages, while one family can appear as several entries if the PDF stores different styles, encodings or subsets. A successful run prints a header followed by zero or more font rows.
name is the name stored in the PDF. A prefix such as TWYWUS+ usually marks a subset, so do not assume the text after the plus sign is the whole embedded font. The object ID is the PDF font dictionary's object number and generation, handy when cross-checking against another PDF diagnostic tool.
3. Read the columns that affect portability
typeidentifies the stored font form: Type 1, Type 1C, TrueType, Type 3, CID Type 0C or CID TrueType.encodingshows the encoding the PDF reports, such asCustom. It is not a promise every text extractor interprets the file identically.embisyeswhen the font is embedded;nomeans the reader may need a local substitute.subisyeswhen the entry is a subset rather than the complete font.uniisyeswhen an explicit ToUnicode map is present;nocan make text extraction harder without making it impossible.
Embedded and subsetted are separate properties: a row can have both emb yes and sub yes, common for documents carrying only the glyphs they use. For a hand-off or archival review, record the rows rather than treating one column as the whole verdict.
4. Restrict the inspection to a page range
Use -f for the first page and -l for the last, useful when a large PDF has a suspicious page or you want to compare a cover with the main body:
$ pdffonts -f 1 -l 1 /path/to/document.pdf
name type encoding emb sub uni object ID
------------------------------------ ----------------- ---------------- --- --- --- ---------
TWYWUS+NimbusSanL-Bold Type 1 Custom yes yes yes 105 0
The range changes which pages get examined; it never modifies the PDF or renumbers the object IDs. Replace 1 with page numbers that exist in your document. A font used only outside the selected range will not appear in that range's report, so run the unrestricted command too when you need the full inventory.
Checkpoint
Compare a full report with a narrow one before concluding a font is absent. Page scope is an easy source of false assumptions.
5. Inspect a PDF arriving on standard input
Use a single hyphen as the PDF argument when a pipeline supplies the bytes:
$ cat /path/to/document.pdf | pdffonts -
name type encoding emb sub uni object ID
------------------------------------ ----------------- ---------------- --- --- --- ---------
TWYWUS+NimbusSanL-Bold Type 1 Custom yes yes yes 105 0
For a simple file, a direct path is clearer. The standard-input form suits a PDF already being streamed, but keep diagnostics separate from the data source, and do not pipe arbitrary untrusted input into a privileged process.
6. Find missing-font substitutions
Add -subst to ask Poppler which substitute fonts it would use for non-embedded ones:
$ pdffonts -subst /path/to/document.pdf
name object ID substitute font substitute font file
------------------------------------ --------- ------------------------------------ ------------------------------------
An empty table just means this PDF produced no substitution row for the installed Poppler run; it is not a guarantee every viewer on every platform matches. If rows appear, keep the substitute name and file in your report, since a substitution can alter layout, glyph appearance or text metrics. Do not confuse this with embedding fonts: it reports the fallback Poppler would use, and neither adds that font to the PDF nor repairs the document.
7. Handle passwords and failures safely
An encrypted PDF may need a user password via -upw. The owner password uses -opw, which the manual says bypasses PDF security restrictions:
$ pdffonts -upw 'USER_PASSWORD' /path/to/encrypted.pdf
name type encoding emb sub uni object ID
------------------------------------ ----------------- ---------------- --- --- --- ---------
Security warning
Do not put a real password in shell history, a shared terminal transcript or a process listing. Prefer an isolated session and clear any history entry your shell's normal way, and treat the owner password as security-sensitive authority: use it only when you are authorised to bypass the document's restrictions.
If the file cannot be opened, check the path and read permission without changing anything:
$ test -r /path/to/document.pdf && echo readable
$ pdffonts /path/to/document.pdf
$ printf 'exit status: %s\n' "$?"
exit status: 0
The documented exit statuses distinguish an input-open failure, output-open failure, permission failure and other errors. A non-zero result is a reason to investigate the file, password, permissions or PDF structure, not to reach for root by reflex.
Done means
- Version checked: Poppler version and command path confirmed.
- Full table recorded: including
emb,subanduni. - Page limits used sparingly: only when a page-scoped question required them.
- Standard input and substitutions understood: you know how to check both.
- Passwords treated as sensitive: the PDF and system configuration were left unchanged.