All formats

FPDF and FPDI

LanguagePHP (FPDF 5.3+, FPDI 7.2+)
LicenseFPDF: permissive (FPDF license, MIT on Packagist); FPDI: MIT
Repositorygithub.com/Setasign/FPDF (Composer mirror), github.com/Setasign/FPDI
DocumentationFPDF manual, FPDI manual
Depends onext-zlib (FPDF also lists ext-gd for images)
Read / writeFPDI imports pages of existing PDFs / yes

FPDF is a single PHP class that writes PDFs: pages, the 14 standard fonts and TrueType fonts, text cells and multi-line cells with wrapping, lines, rectangles, images (JPEG, PNG, GIF, WebP), links and automatic page breaks. It’s small, fast and has no required dependencies. Text in the standard fonts must be in Windows-1252 encoding; for UTF-8 text use the tFPDF add-on or TCPDF/mPDF.

FPDI extends FPDF (or TCPDF, or tFPDF) with setSourceFile and importPage: it turns a page of an existing PDF into a template you can place on a new page and draw over. That’s the standard PHP way to merge PDFs, extract pages, or fill out a PDF form by writing text at fixed positions. The free FPDI parser doesn’t support PDFs with compressed cross-reference streams (PDF 1.5+ object streams); Setasign sells an add-on parser for those, or you can convert such files first with qpdf --object-streams=disable in.pdf out.pdf.

Installation#

Shell
composer require setasign/fpdf setasign/fpdi

Basic usage: create a PDF with FPDF#

PHP
<?php
require 'vendor/autoload.php';

$pdf = new FPDF();  // A4, portrait, millimeters
$pdf->SetTitle('Hello', true);
$pdf->AddPage();
$pdf->SetFont('Helvetica', 'B', 24);
$pdf->Cell(0, 15, 'Hello, PDF!', 0, 1);  // width 0 = up to the right margin, 1 = new line after
$pdf->SetFont('Helvetica', '', 12);
$pdf->MultiCell(0, 6, str_repeat('FPDF wraps long text in MultiCell. ', 10));
$pdf->Cell(0, 6, mb_convert_encoding('Café', 'windows-1252', 'UTF-8'), 0, 1);
$pdf->Image('logo.png', 10, 100, 50);  // x, y, width in mm
$pdf->Output('F', 'hello.pdf');         // 'I' inline, 'D' download, 'S' string

How to merge PDF files with FPDI#

PHP
<?php
require 'vendor/autoload.php';

use setasign\Fpdi\Fpdi;

$pdf = new Fpdi();
foreach (['a.pdf', 'b.pdf'] as $file) {
    $pageCount = $pdf->setSourceFile($file);
    for ($i = 1; $i <= $pageCount; $i++) {
        $tpl = $pdf->importPage($i);
        $size = $pdf->getTemplateSize($tpl);
        $pdf->AddPage($size['orientation'], [$size['width'], $size['height']]);
        $pdf->useTemplate($tpl);
    }
}
$pdf->Output('F', 'merged.pdf');

Imported pages keep their vector content and text; annotations, links and form fields aren’t copied.

How to split a PDF into pages#

PHP
use setasign\Fpdi\Fpdi;

$pageCount = (new Fpdi())->setSourceFile('in.pdf');
for ($i = 1; $i <= $pageCount; $i++) {
    $pdf = new Fpdi();
    $pdf->setSourceFile('in.pdf');
    $tpl = $pdf->importPage($i);
    $pdf->AddPage();
    $pdf->useTemplate($tpl, ['adjustPageSize' => true]);
    $pdf->Output('F', "page-$i.pdf");
}

How to write text onto an existing PDF#

Import the page, then draw with the normal FPDF methods, for example a stamp or values for a non-fillable form:

PHP
use setasign\Fpdi\Fpdi;

$pdf = new Fpdi();
$pdf->setSourceFile('in.pdf');
$tpl = $pdf->importPage(1);
$pdf->AddPage();
$pdf->useTemplate($tpl, ['adjustPageSize' => true]);

$pdf->SetFont('Helvetica', 'B', 40);
$pdf->SetTextColor(255, 0, 0);
$pdf->SetXY(30, 120);
$pdf->Write(0, 'CONFIDENTIAL');
$pdf->Output('F', 'stamped.pdf');

Tips#