How to Use PDF Core Fonts with wkhtmltopdf and QPrinter
Learn what PDF core fonts mean, how to request them with wkhtmltopdf or QPrinter, and how to verify which fonts your generated PDF actually contains.

To use a PDF core font, request a Standard 14 family such as Helvetica, Times, or Courier, generate the PDF, and inspect its font table. A CSS declaration alone cannot guarantee that the resulting PDF references a Standard 14 font without embedding another font: wkhtmltopdf renders through its Qt/WebKit stack, where the installed fonts, font configuration, and build affect font selection. With QPrinter, you can call setFontEmbeddingEnabled(false), but older Qt support was platform-specific. Treat the generated PDF—not the CSS or setter—as the evidence.
This guide shows how to request core families, produce a test PDF with wkhtmltopdf, configure QPrinter, and verify the result. It also explains when a core-font reference is the wrong requirement.
1. Understand what “PDF core fonts” means
The PDF Standard 14, also called Base 14, are Times-Roman, Helvetica, Courier, Symbol, ZapfDingbats, and their standard bold, italic, and oblique variants. A PDF may refer to these fonts without carrying the original font program because PDF viewers are expected to have the fonts, metrics, or suitable substitutions available. The canonical names are PDF/PostScript names; a desktop font such as Arial or Times New Roman is not itself proof that a PDF uses a Standard 14 font. See Adobe’s PDF Reference, Standard Type 1 Fonts.
There are several different outcomes developers often conflate:
- Standard 14 reference: the PDF font resource names a standard font and does not embed its font program.
- Visual similarity: the page looks like Helvetica or Times in one viewer. This says nothing conclusive about the underlying PDF font resource.
- Embedded font: the PDF carries a font program. It may be a complete font or a subset containing only glyphs used in the document.
- Unicode and accessibility: text extraction, glyph coverage, and tagging are separate questions from whether the font is embedded.
Decide which outcome your requirement actually calls for before changing renderer settings. A font table can establish the font resource and embedding state; it cannot by itself establish visual fidelity, accessibility, or PDF/A conformance.
2. Request a core family in HTML and CSS
Use a deliberate family list and specify weight and style explicitly. The fallback names are there in case the first family cannot be resolved by the renderer. They do not force the PDF writer to create a Standard 14 reference.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<style>
body {
font-family: Helvetica, "Nimbus Sans", Arial, sans-serif;
font-weight: 400;
font-style: normal;
}
h1 { font-family: Times, "Nimbus Roman", serif; font-weight: 700; }
code { font-family: Courier, "Nimbus Mono PS", monospace; }
.emphasis { font-style: italic; }
</style>
</head>
<body>
<h1>Quarterly report</h1>
<p>A regular paragraph with <span class="emphasis">italic text</span>.</p>
<code>const answer = 42;</code>
</body>
</html>
Some CSS aliases, such as Times, are common shorthand, but inspection is still required. If exact PDF resource names matter, check the names reported by a PDF inspector against the canonical list. A substitution font can have a different name even where its appearance is close.
3. Generate and inspect with wkhtmltopdf
First record the exact executable and build. The project’s usage documentation identifies the patched-Qt build in its example version output; distributors may package different Qt patches and font dependencies. The project also notes that installed fonts and fontconfig/Freetype runtime configuration matter. See the wkhtmltopdf usage documentation and project downloads and build notes.


wkhtmltopdf --version
wkhtmltopdf report.html report.pdf
pdffonts report.pdf
For a remote page, the minimal form is wkhtmltopdf https://example.com/page output.pdf. For reproducible font debugging, prefer a local HTML fixture and run the same command in the production container or host. The executable must be installed and available on PATH.
pdffonts prints columns including name, type, encoding, emb, sub, and uni. Read them together:
| Column | What to check | What it does not prove |
|---|---|---|
name |
PDF font resource name; compare with the intended family and expected substitutions. | That the CSS family resolved exactly as written. |
type |
PDF font type, for example Type 1 or CID TrueType. | That the font is a Standard 14 reference. |
encoding |
Character encoding or character collection used by that resource. | Coverage for every character in your source text. |
emb |
yes means the font program is embedded; no means it is not. |
That non-embedding is valid for your archival profile or desired appearance. |
sub |
yes indicates a subset font program is embedded. |
An error. Subsetting is often normal when embedding is enabled. |
uni |
Whether a Unicode mapping is present for text extraction. | Universal glyph coverage or accessibility conformance. |
The wkhtmltopdf font-selection issue provides a useful example: the same HTML and reported wkhtmltopdf/Qt versions produced different font rows in a Docker container and a server. The differing inventories illustrate why the deployment environment and PDF output both need checking.
4. Configure QPrinter’s embedding option
For a Qt application generating a PDF through QPrinter, set the output format and destination, then disable font embedding where the backend supports the setting. Qt documents both the setter and the getter. Current QPrinter documentation describes these APIs; the archived Qt 4 reference matters for older wkhtmltopdf-era deployments.
#include <QPrinter>
#include <QPainter>
#include <QTextDocument>
#include <QDebug>
int main() {
QPrinter printer(QPrinter::HighResolution);
printer.setOutputFormat(QPrinter::PdfFormat);
printer.setOutputFileName("output.pdf");
printer.setFontEmbeddingEnabled(false);
qDebug() << "Embedding setting:" << printer.fontEmbeddingEnabled();
QTextDocument document;
document.setHtml(
"<h1 style='font-family: Helvetica'>Report</h1>"
"<p style='font-family: Helvetica'>Generated by Qt.</p>"
);
document.print(&printer);
return 0;
}
The getter confirms the setting exposed by the QPrinter object; it is not a substitute for inspecting the resulting PDF. The archived Qt documentation states that font embedding control was supported only on X11. On a legacy system, confirm the Qt version, platform, print engine, and actual emitted font table. Current Qt behavior may differ by version and backend.
5. Choose the font policy that matches the document
| Need | Practical policy | Validation |
|---|---|---|
| Small PDF and conventional Latin text | Try a Standard 14 reference, if the renderer can emit one. | Inspect name, type, encoding, and emb. |
| Consistent branding and layout | Use a specific licensed embeddable font and ensure it is installed in the renderer environment. | Check appearance on target viewers and embedded font rows. |
| Non-Latin or broad Unicode text | Choose a font with the needed glyph coverage and an explicit embedding policy. | Test representative scripts, symbols, extraction, and the PDF font table. |
| PDF/A or another archival profile | Follow that profile’s font and metadata requirements; do not assume a Standard 14 reference is acceptable. | Run a validator for the required profile in addition to checking fonts. |
Standard 14 encodings do not provide broad Unicode coverage. If text contains characters outside the chosen encoding, a core-font request can produce missing glyphs, substitutions, or unreliable output. Exact branding, controlled layout across platforms, accessibility needs, and archival requirements are reasons to define an explicit embeddable-font policy instead.
6. Make output reproducible
- Pin the renderer package. Record
wkhtmltopdf --version, including any patched Qt suffix, or record the Qt version and print backend for QPrinter. - Freeze the runtime environment. Use the same OS/container image, font files, fontconfig setup, and locale in staging and production.
- Use a fixture PDF. Include regular, bold, italic, symbols, and all scripts relevant to the real document. Include glyphs likely to expose fallback.
- Capture inspection output. Save the
pdffontsresult as a build artifact or regression record. Compare font names and embedding flags after renderer or image updates. - Set separate acceptance checks. Validate the font resource requirement, visual rendering, text extraction, and PDF profile conformance independently.
Do not treat a matching PDF file size as proof that font output is stable. Nor is a subset font automatically a failure: it means only used glyphs were embedded. Decide whether any embedded program is disallowed, or whether the concern is embedding a full font file.
7. Troubleshooting common font problems
The PDF contains an unexpected embedded font
Cause: CSS family resolution may have fallen back to an installed font before PDF generation; wkhtmltopdf’s environment can change the selected font objects. Fix: inspect the runtime font inventory and fontconfig setup, compare the production and development images, then rerun pdffonts. Do not infer the embedded resource from the CSS source.
setFontEmbeddingEnabled(false) seems ignored
Cause: the Qt version, target platform, print engine, or private/patched Qt build may not honor the switch. Archived Qt 4 documentation specifically limits support to X11. Fix: log fontEmbeddingEnabled(), identify the runtime backend, generate a small PDF, and inspect it. If the requirement is strict and the backend cannot meet it, select a PDF generation path that can satisfy and validate that requirement.
Some characters disappear or change
Cause: the selected core-font encoding may not include the required glyphs, or fallback has selected a font without them. Fix: switch to a font covering the document’s scripts, define whether it must be embedded, and test representative characters in the generated PDF. A family name cannot add glyphs to the font encoding.
Two hosts produce different font rows
Cause: different renderer builds, Qt patches, installed fonts, fontconfig state, or locale. Fix: capture version output and font inventory from both hosts, align the deployment image and runtime configuration, then compare pdffonts output. The wkhtmltopdf issue cited above shows that the same HTML can yield different font rows across environments.
The PDF looks right but extraction is wrong
Cause: visual rendering and Unicode mapping are separate properties. Fix: inspect uni, extract text with your downstream tools, and test the actual characters and scripts. If searchable text is a requirement, include it in acceptance criteria instead of relying on appearance.
8. Performance, reliability, and cost considerations
Standard 14 references can avoid carrying a font program, but actual file size depends on the whole document, images, and other resources. An embedded subset can also be small. Measure representative generated PDFs rather than assuming that disabling embedding will produce a meaningful size reduction.
For reliability, pin the same wkhtmltopdf or Qt build and render in the same deployment image. A newer or differently packaged build may alter fallback even when the HTML is unchanged. Keep fonts and locale deterministic, and retain inspection output for representative documents.
Font choice does not itself change the renderer’s computation cost in a predictable way. Large HTML documents, image assets, and page complexity can affect generation time and memory, so profile the actual workload. Avoid using untrusted HTML with wkhtmltopdf: the project’s downloads page warns about sanitizing user-supplied HTML/JavaScript because it can expose the server.
If you are generating a PDF from a web page and do not need to control its CSS font resources, ScreenshotNeo offers a one-request screenshot or PDF API. It is not a substitute for QPrinter font configuration or a PDF/A validator; use it when the task is capturing a page rather than specifying a document’s font embedding policy.
Or skip the browser setup
For a web-page capture, ScreenshotNeo returns a screenshot or PDF from one GET request. Its clean-shot flow accepts cookie banners and removes known consent platforms, newsletter popups, and chat widgets before capture; those steps can be disabled. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers report the page verdict and billing status. Its MCP server provides screenshot tools for AI agents. It does not give you control over the font resources in an HTML-to-PDF renderer’s output.
Example request (see the ScreenshotNeo API documentation):
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python:
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
Node.js:
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', new Uint8Array(await res.arrayBuffer()));
ScreenshotNeo includes 1,000 screenshots a month free with no card; paid plans start at $5 for 3,000, and every feature is on every plan. Create a free ScreenshotNeo account.
FAQ
Does CSS font-family: Helvetica guarantee the PDF uses Helvetica?
No. It requests a family from the renderer. Inspect the generated PDF to see the actual font resource and embedding state.
Is an embedded subset a problem?
Not by itself. A subset includes only glyphs used in the document. Whether embedding is acceptable depends on your file size, portability, licensing, and profile requirements.
Can I use a core font for Japanese, Arabic, or emoji?
Do not assume it covers those characters. Select a font with the necessary glyphs and define an embedding policy, then test the actual output.
What is the fastest useful check after a renderer upgrade?
Generate your representative fixture in the deployment image and compare pdffonts output, text extraction, and visual rendering against your acceptance criteria.


