PD4ML for Python Compared with WeasyPrint, xhtml2pdf and Playwright
Python developers who need HTML to PDF usually pick one of a few libraries: WeasyPrint, xhtml2pdf, a headless browser driven by Playwright, or pdfkit with wkhtmltopdf. Most are free and install with pip, and each works well for some kinds of documents. This page compares them with PD4ML for Python, the pip package that brings the PD4ML layout engine to Python, so you can see where each one fits: CSS layout, PDF/A and PDF/UA, e-invoices, Word output, signatures, deployment and license.
The comparison covers PD4ML v4.1.1 and, marked 4.2, features of the upcoming PD4ML 4.2 with its new v42 layout engine. Information about the other libraries comes from their documentation and PyPI pages as of November 2026; a cell marked "not verified" means we could not confirm it from public sources. ReportLab is not included: it builds PDFs from Python code rather than from HTML.
At a glance
- PD4ML for Python (
pd4mlon PyPI) runs the PD4ML engine in a Java virtual machine inside the Python process, with no server, and exposes its full API to Python. It needs Python 3.9 and Java 8 or later. Commercial license, perpetual, from €100; free evaluation with a watermark. - WeasyPrint (70.0) is a print-oriented HTML and CSS renderer written in Python on top of Pango. It is the most complete of the open-source options: paged media, PDF/A, PDF/UA and PDF/X. BSD-3-Clause.
- xhtml2pdf (0.2.28) converts HTML and CSS 2.1, with parts of CSS3, to PDF through ReportLab, in pure Python. It is actively developed again and has added Flexbox, signatures and PDF/X-4. Apache-2.0.
- Playwright (1.64) drives a headless Chromium whose print to PDF renders HTML as Chrome does, JavaScript included, but with few PDF options. Apache-2.0.
- pdfkit wraps the wkhtmltopdf command-line tool, whose Qt WebKit engine dates from 2012. wkhtmltopdf has been archived since January 2023 and pdfkit's last release was in 2021. MIT (pdfkit) and LGPL-3.0 (wkhtmltopdf).
Requirements, installation and license
| Item | PD4ML | WeasyPrint | xhtml2pdf | Playwright (Chromium) | pdfkit (wkhtmltopdf) |
|---|---|---|---|---|---|
| Install | pip install pd4ml |
pip install weasyprint |
pip install xhtml2pdf |
pip install playwright, then playwright install chromium |
pip install pdfkit plus the wkhtmltopdf binary |
| Python version | 3.9 or later | 3.10 or later | 3.10 or later | 3.10 or later | Any Python 3 |
| Runtime | Python plus Java 8 or later | Python plus the Pango library (1.44 or later) | Pure Python (ReportLab) | Python plus a downloaded Chromium | Python plus wkhtmltopdf |
| Engine | Own print-focused engines: v40 and v42 (Chrome-verified layout) 4.2 | Own CSS layout engine | ReportLab Platypus | Chromium | Qt WebKit (2012) |
| Maintained | Supported | Supported | Supported | Supported | Not supported wkhtmltopdf archived in 2023 |
| License | Commercial, perpetual | BSD-3-Clause | Apache-2.0 | Apache-2.0 | MIT; wkhtmltopdf LGPL-3.0 |
| Price | €100 single, €1,600–3,200 site, €8,000–16,000 enterprise (one-time) | Free | Free | Free | Free |
| Commercial support | Supported | Partial or add-on From its authors' company | Not supported Community | Not supported Community | Not supported |
PD4ML's Java runs inside the Python process: there is no separate server to deploy, and a long-running process (a web server, a worker) starts Java once. The first conversion of a fresh installation downloads the PD4ML library unless it was installed ahead of time with pd4ml install. Details: PD4ML for Python.
HTML and CSS layout support
| Feature | PD4ML | WeasyPrint | xhtml2pdf | Playwright (Chromium) | pdfkit (wkhtmltopdf) |
|---|---|---|---|---|---|
| CSS level | Modern CSS; v42 engine checked against Chrome 4.2 | CSS 2.1 and much of CSS3, paged media | CSS 2.1 and some CSS3 | Current Chrome | CSS 2.1 and early CSS3 of 2012 WebKit |
| Flexbox | Supported | Partial or add-on Supported, "not deeply tested" | Partial or add-on Level 1; inline-flex laid out as flex |
Supported | Not supported Old -webkit-box syntax only |
| CSS Grid | Supported Template areas, line names, dense placement 4.2 | Partial or add-on No subgrid, inline-grid, auto-fill/auto-fit, or rows split across pages |
Not supported | Supported | Not supported |
| Absolute and fixed positioning | Supported | Supported | Supported | Supported | Supported |
| CSS @page | Supported Size, :first/:left/:right, named pages, margin boxes 4.2 |
Supported Named pages, margin boxes, :nth() |
Partial or add-on Size, margins, named page templates and frames | Partial or add-on Size; margins through options | Not supported |
| Headers, footers, page numbers | Supported HTML headers and footers with page and total counts | Supported Margin boxes and counters | Supported Static frames, <pdf:pagenumber> |
Partial or add-on Header and footer templates | Supported HTML header and footer |
| Multi-column layout | Supported | Partial or add-on No column breaks or spanning | Not verified | Supported | Partial or add-on |
| Media queries | Supported Level 4 range syntax 4.2 | Supported | Partial or add-on Media types only | Supported | Supported |
| Vector SVG | Supported | Supported | Supported Through svglib | Supported | Supported |
| MathML | Supported | Not verified | Not supported | Supported | Not supported |
| Barcodes and QR codes | Supported QR codes (<qrcode>) |
Not supported | Supported <pdf:barcode> |
Not supported Through JavaScript libraries | Not supported Through JavaScript libraries |
| JavaScript | Not supported | Not supported | Not supported | Supported | Supported Old engine |
PD4ML's @page support is described in CSS @page rules, and its DOM API (Java, DMS and UA editions) in modifying the HTML document before conversion.
A headless browser renders whatever Chrome renders, including pages built by JavaScript, but its print to PDF knows little about paged documents: no margin boxes, no named pages, no PDF standards. WeasyPrint is the strongest of the open-source libraries for paged media.
Output formats
| Format | PD4ML | WeasyPrint | xhtml2pdf | Playwright (Chromium) | pdfkit (wkhtmltopdf) |
|---|---|---|---|---|---|
| Supported | Supported | Supported | Supported | Supported | |
| DOCX (Word) | Supported | Not supported | Not supported | Not supported | Not supported |
| RTF | Supported | Not supported | Not supported | Not supported | Not supported |
| PNG and TIFF images | Supported Paged | Not supported | Not supported | Partial or add-on Screenshots, not paged | Partial or add-on wkhtmltoimage, not through pdfkit |
| Several formats from one parse | Supported | Not supported | Not supported | Not supported | Not supported |
PDF/A, PDF/UA and e-invoices
| Standard | PD4ML | WeasyPrint | xhtml2pdf | Playwright (Chromium) | pdfkit (wkhtmltopdf) |
|---|---|---|---|---|---|
| PDF/A | Supported PDF/A-1a/1b, 2a/2b/2u, 3a/3b/3u, 4, 4e | Supported PDF/A-1 to 4 (a, b, u, e, f) | Not supported | Not supported | Not supported |
| PDF/UA accessible PDF | Supported PDF/UA-1 and PDF/UA-2 | Supported PDF/UA-1 and PDF/UA-2 | Not supported | Partial or add-on Tagged PDF option, no PDF/UA conformance | Not supported |
| ZUGFeRD and Factur-X | Supported Presets, including accessible PDF/A-3a invoices | Supported PDF/A-3b with the invoice attached | Not supported | Not supported | Not supported |
| PDF/X for print | Not supported | Supported PDF/X-1a, 3, 4, 5g | Supported PDF/X-4 | Not supported | Not supported |
| PDF 2.0 | Supported | Not verified | Not supported | Not supported | Not supported |
WeasyPrint states that it generates these variants but does not guarantee their validity; check its output with a validator. See PDF/A, PDF/UA and e-invoicing formats and ZUGFeRD and Factur-X PDF invoices.
Fonts and international text
| Feature | PD4ML | WeasyPrint | xhtml2pdf | Playwright (Chromium) | pdfkit (wkhtmltopdf) |
|---|---|---|---|---|---|
| TrueType and OpenType embedding with subsetting | Supported | Supported | Supported | Supported | Supported |
| Arabic and Hebrew, right to left | Supported | Supported | Supported Shaped with arabic-reshaper | Supported | Supported |
| Indic and other complex scripts | Supported | Supported HarfBuzz through Pango | Not verified | Supported | Partial or add-on |
| Kerning and ligatures | Supported | Supported | Not verified | Supported | Supported |
| Color emoji | Supported COLR and CBDT fonts 4.2 | Not verified | Not verified | Supported | Partial or add-on |
| WOFF2 web fonts | Supported | Supported | Supported With the fonts extra |
Supported | Not supported |
Security, signatures and forms
| Feature | PD4ML | WeasyPrint | xhtml2pdf | Playwright (Chromium) | pdfkit (wkhtmltopdf) |
|---|---|---|---|---|---|
| Passwords and permissions | Supported RC4, AES-128/256 | Not supported | Supported | Not supported | Not supported |
| Digital signatures | Supported PKCS#12, PKCS#11, HSM, cloud KMS, RFC 3161, PAdES-LT/LTV | Not supported | Supported PKCS#12 and PKCS#11 through pyHanko | Not supported | Not supported |
| Fillable forms from HTML | Supported Inputs, selects, text areas, buttons | Supported Text inputs, check boxes, text areas, selects | Supported No radio button fields | Not supported | Partial or add-on --enable-forms |
| Merge, optimize, XFDF | Supported | Not supported | Not supported | Not supported | Not supported |
| Fetching untrusted resources | Supported Allow and deny lists | Supported URL fetcher | Supported Restrictive defaults | Partial or add-on Browser sandbox | Not supported Known SSRF issue, unpatched |
Any of these PDFs can also be signed afterwards with a separate Python library such as pyHanko.
When to choose which
- WeasyPrint suits print-designed documents written for paged media (margin boxes, named pages), PDF/A, PDF/UA and PDF/X, when a permissive license matters and Pango can be installed.
- xhtml2pdf suits simple reports and invoices in pure Python, with no system libraries, including encrypted and signed output.
- Playwright suits pages that need JavaScript or must look exactly like the browser, when no PDF standard is required and a browser can run on the server.
- pdfkit with wkhtmltopdf suits existing projects only: the engine is unmaintained and has unpatched security issues, so new projects should use one of the others.
- PD4ML for Python suits templates written with modern CSS (Flexbox, Grid,
@page), documents that also need DOCX or RTF, PDF/UA and e-invoices from HTML, digital signatures with long-term validation, and teams that want commercial support. It needs Java on the server.
Frequently asked questions
What is the best Python library for converting HTML to PDF?
For print-designed HTML without JavaScript, WeasyPrint is the strongest free option. For pages that depend on JavaScript, a headless Chromium through Playwright. If you need CSS Grid without limits, Word output, PDF/A together with digital signatures, or commercial support, PD4ML for Python covers that through pip, with Java on the server.
Is PD4ML a good alternative to WeasyPrint?
Yes, when you need DOCX or RTF output, digital signatures, encryption, CSS Grid features WeasyPrint does not support, or one library for PDF, Word and images. WeasyPrint needs no Java and is free; it is the better fit for teams that only need PDF.
Is PD4ML a good alternative to wkhtmltopdf and pdfkit?
Yes. wkhtmltopdf was archived in January 2023 and its WebKit engine dates from 2012, so it supports neither Flexbox nor Grid. PD4ML supports both, has no browser engine to keep patched, and adds PDF/A, PDF/UA and signatures.
Should I use a headless browser instead?
A headless Chromium (Playwright, pyppeteer) renders exactly what Chrome shows, JavaScript included. It cannot produce PDF/A, PDF/UA, encrypted or signed PDFs, and each server needs a browser to install and keep updated. PD4ML does not run JavaScript; it lays out the HTML it is given.
Do I need Java to use PD4ML in Python?
Yes. PD4ML for Python starts a Java 8 or later virtual machine inside the Python process. There is no separate server; a long-running process starts Java once, and each conversion then takes milliseconds for an ordinary document.
Can Python create PDF/A and ZUGFeRD invoices from HTML?
Yes, with PD4ML or WeasyPrint. PD4ML has presets for ZUGFeRD and Factur-X on PDF/A-3, including accessible PDF/A-3a invoices; WeasyPrint documents Factur-X on PDF/A-3b with the invoice attached.
Can Python convert HTML to Word (DOCX)?
Among these libraries, only PD4ML converts HTML and CSS to DOCX and RTF, from the same layout as the PDF.
Try PD4ML for Python
Install the module with pip install pd4ml and convert one of your own templates. Unlicensed output carries a watermark, with all features enabled. See PD4ML for Python, the comparison with PHP libraries, the comparison with Java HTML-to-PDF libraries, and PD4ML editions and prices.
Product names are trademarks of their respective owners. Information about other libraries is taken from their public documentation as of November 2026 and may have changed; corrections are welcome through PD4ML support. This page is not legal advice on open-source licenses.
