mPDF
| Language | PHP 5.6 to 8.5 |
|---|---|
| License | GPL-2.0-only |
| Repository | github.com/mpdf/mpdf |
| Documentation | mpdf.github.io |
| Depends on | ext-gd, ext-mbstring, setasign/fpdi, psr/log, myclabs/deep-copy |
| Read / write | imports pages of existing PDFs (via FPDI) / yes |
mPDF turns HTML and CSS into PDF and is known for its font handling: it embeds and subsets TrueType fonts, does automatic font substitution for missing glyphs, and supports right-to-left scripts (Arabic, Hebrew), Indic scripts with OpenType shaping, and CJK. It also has HTML headers and footers, table of contents, bookmarks, watermarks, barcodes, columns, annotations, PDF/A and PDF/X output and encryption, and it can import pages from existing PDFs through FPDI.
mPDF is GPL-2.0: distributing an application that includes it means distributing under the GPL. It’s slower than Dompdf on large documents and CSS support is partial (no flexbox or grid). The tempDir must be writable.
Installation#
composer require mpdf/mpdf
Basic usage: convert HTML to PDF#
<?php
require 'vendor/autoload.php';
$mpdf = new \Mpdf\Mpdf(['format' => 'A4', 'margin_top' => 20, 'tempDir' => __DIR__ . '/tmp']);
$mpdf->SetTitle('Invoice #1001');
$mpdf->SetAuthor('Billing');
$mpdf->SetHTMLFooter('<div style="text-align: right">Page {PAGENO} of {nbpg}</div>');
$mpdf->WriteHTML('<h1>Invoice #1001</h1>
<p>Zażółć gęślą jaźń · Привет · 日本語</p>
<table border="1" style="border-collapse: collapse">
<tr><th>Item</th><th>Price</th></tr>
<tr><td>Widget</td><td>9.99</td></tr>
</table>');
$mpdf->Output('invoice.pdf', \Mpdf\Output\Destination::FILE);
Other destinations: INLINE (show in browser), DOWNLOAD, STRING_RETURN.
How to add a watermark#
$mpdf = new \Mpdf\Mpdf(['tempDir' => __DIR__ . '/tmp']);
$mpdf->SetWatermarkText('DRAFT');
$mpdf->showWatermarkText = true;
$mpdf->WriteHTML('<p>Draft document</p>');
$pdf = $mpdf->Output('', \Mpdf\Output\Destination::STRING_RETURN);
How to merge PDF files#
mPDF includes FPDI, so it can import pages from existing PDFs:
$mpdf = new \Mpdf\Mpdf(['tempDir' => __DIR__ . '/tmp']);
foreach (['a.pdf', 'b.pdf'] as $file) {
$pageCount = $mpdf->setSourceFile($file);
for ($i = 1; $i <= $pageCount; $i++) {
$mpdf->AddPage();
$tpl = $mpdf->importPage($i);
$mpdf->useTemplate($tpl);
}
}
$mpdf->Output('merged.pdf', \Mpdf\Output\Destination::FILE);
The same limitation as FPDI applies: files with compressed cross-reference streams need the commercial FPDI parser or a rewrite with qpdf first.
How to password-protect a PDF#
$mpdf = new \Mpdf\Mpdf(['tempDir' => __DIR__ . '/tmp']);
$mpdf->SetProtection(['print', 'copy'], 'user', 'owner', 128); // RC4 128-bit
$mpdf->WriteHTML('<p>Secret</p>');
$mpdf->Output('secret.pdf', \Mpdf\Output\Destination::FILE);
mPDF writes RC4 encryption (40 or 128 bit), which is weak by today’s standards; re-encrypt with qpdf for AES-256.
Tips#
- Register your own fonts with the
fontDirandfontdataconfiguration keys; set'autoScriptToLang' => trueand'autoLangToFont' => truefor mixed-script text. $mpdf->WriteHTML($css, \Mpdf\HTMLParserMode::HEADER_CSS)loads a stylesheet separately from the body.- Use
<pagebreak />or the CSSpage-break-beforeproperty for page breaks.