Migrate a TCPDF 6.x codebase to NextPDF
At a glance
Section titled “At a glance”The nextpdf/compat-legacy package exposes the TCPDF 6.x public method names,
parameter order, and defaults on top of the NextPDF core engine through the
NextPDF\Compat\Tcpdf\TCPDF adapter. Migrate in this order: move to the engine
with the smallest change, prove what already works, turn on strict mode to find
what does not, fix the call sites one at a time, then retire the adapter and use
the modern API. The adapter supports the migration; it is not the destination.
Prerequisites, up front:
- NextPDF core and
nextpdf/compat-legacyare installed. - You have an existing TCPDF 6.x codebase with a test suite. The suite is the safety net for each stage below.
This is a how-to. For the per-method behavior of one TCPDF call, read the method-coverage page. For the full file-by-file strategy with code, read the upstream migration page. Both links are under See also.
Install
Section titled “Install”Install the adapter alongside core. Do not remove the real TCPDF library yet — keeping both lets you compare output as you migrate.
composer require nextpdf/compat-legacyBefore you change any code, confirm that the engine link resolves
(nextpdf/core ^3.0) and the suite still runs.
Conceptual overview
Section titled “Conceptual overview”The adapter is a compatibility layer, not a fork of TCPDF and not a
byte-identical clone. Of roughly 120 surveyed TCPDF 6.x public methods, about 94
map directly to a NextPDF\Core\Document operation and behave compatibly for
the documented parameters. A defined minority either accept legacy parameters
that the engine does not honor (silent-ignore), or produce no output
(unimplemented or not-applicable). The authoritative, test-verified coverage
matrix is in the package repository at docs/TCPDF_COVERAGE.md. When this guide
and that matrix disagree, the matrix wins.
Two facts shape the whole migration:
- Output bytes differ. The engine is an independent PDF 2.0 implementation, so the rendered bytes differ from TCPDF output even when the visible result looks the same. Tests that assert on exact PDF bytes need re-baselining onto rendered content or structural properties.
- Strict mode is your audit tool. With strict mode off (the default),
methods that cannot reproduce TCPDF behavior degrade silently. With strict
mode on, those calls throw
TcpdfNotImplementedException, naming the exact ignored parameters and a migration hint. Run strict mode in a dedicated audit pass, never in production.
The adapter also exposes the wrapped engine document through getDocument(),
which returns the NextPDF\Core\Document. Use that as the exit path: migrate
call sites to the modern API one at a time until you can remove the adapter.
API surface
Section titled “API surface”| Concern | Surface |
|---|---|
| Construct | new NextPDF\Compat\Tcpdf\TCPDF('P', 'mm', 'A4') |
| Opt-in global aliases | NextPDF\Compat\Tcpdf\LegacyBootstrap::enableAliases() |
| Enable the audit | TCPDF::setStrictMode(true) |
| Audit exception | NextPDF\Compat\Tcpdf\Exception\TcpdfNotImplementedException |
| Escape hatch to modern API | TCPDF::getDocument(): NextPDF\Core\Document |
| Output | TCPDF::Output(string $name, string $dest) — S, F, E, I, D |
LegacyBootstrap::enableAliases() is idempotent. It registers \TCPDF,
\TCPDF_STATIC, \TCPDF_FONTS, \TCPDF_COLORS, and \TCPDF_IMAGES only when
those classes do not already exist. The method-coverage and quickstart pages
linked under See also cover the full per-method behavior and output
destinations.
Code sample — Quick start
Section titled “Code sample — Quick start”Change the import, keep the TCPDF-style calls, and produce a PDF.
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\TCPDF;
$pdf = new TCPDF('P', 'mm', 'A4');$pdf->SetCreator('Quickstart');$pdf->SetTitle('First Document');$pdf->SetFont('helvetica', '', 12);$pdf->AddPage();$pdf->Cell(0, 10, 'Hello from the NextPDF engine', 1, 1, 'C');
$pdf->Output(__DIR__ . '/quickstart.pdf', 'F');Output($name, 'F') writes the file and returns an empty string. Unlike legacy
TCPDF, the adapter’s Output() does not echo into the active output buffer, so
you can safely call it inside a queue worker or an HTTP handler that controls its
own response.
When you cannot change call sites that construct new \TCPDF(...) against the
global namespace, enable the opt-in aliases once at boot.
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\LegacyBootstrap;
LegacyBootstrap::enableAliases();
// Legacy code now resolves \TCPDF to the adapter:$pdf = new \TCPDF('P', 'mm', 'A4');$pdf->AddPage();$pdf->SetFont('helvetica', '', 12);$pdf->Cell(0, 10, 'Legacy call site, modern engine');$pdf->Output(__DIR__ . '/aliased.pdf', 'F');Do not enable aliases while the real TCPDF library is still autoloadable. The
alias is skipped when a \TCPDF class already exists, so you may keep using
legacy TCPDF without realizing it. During the migration, prefer per-file imports.
Code sample — Production
Section titled “Code sample — Production”The migration-safe step is the strict-mode audit. Run a representative
production path, or the suite, with strict mode on, and collect every
TcpdfNotImplementedException. Each exception is a work item: it names the
method, the ignored parameters, and a hint.
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\Exception\TcpdfNotImplementedException;use NextPDF\Compat\Tcpdf\TCPDF;
function renderInvoice(TCPDF $pdf): void{ // ... your existing rendering code, unchanged ...}
$pdf = new TCPDF('P', 'mm', 'A4');$pdf->setStrictMode(true);
try { renderInvoice($pdf); $pdf->Output(__DIR__ . '/audit.pdf', 'F');} catch (TcpdfNotImplementedException $exception) { // Each message names the method, the ignored parameters, and a hint. fwrite(STDERR, 'MIGRATION GAP: ' . $exception->getMessage() . "\n");}For each gap, pick the cheapest correct fix: drop a parameter you never relied
on, or express the intent through the modern API via getDocument(). The escape
hatch handles anything the TCPDF surface cannot express.
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\TCPDF;
$pdf = new TCPDF();$pdf->AddPage();
// Legacy path stays for the parts that already work:$pdf->SetFont('helvetica', '', 12);$pdf->Cell(0, 10, 'Header line', 0, 1);
// Modern path for what the TCPDF surface cannot express here —// for example a clickable image (the legacy Image() link parameter// is one of the silently ignored parameters):$document = $pdf->getDocument();$document->image('logo.png', 10, 30, 40, 0);$document->link(10, 30, 40, 20, 'https://example.com');Run strict mode as a dedicated continuous integration (CI) job, then turn it off and deploy the audited code path. Keep a periodic strict-mode CI job to catch regressions as you refactor.
Edge cases & gotchas
Section titled “Edge cases & gotchas”MultiCell()returns1,Write()returns0. These are compatibility placeholders, not computed values. Adjust any code that branches on those return values.Error()throws instead of callingdie(). The adapter raisesRuntimeException. Code that relies on process termination must catch the exception.- Silent-ignore parameters. Methods such as
Image(),writeHTML(),SetProtection(), andBookmark()accept legacy parameters that are ignored. Use strict mode to find them. For a clickable image, draw the image, then addDocument::link()over the same rectangle. - Unimplemented methods.
setSignature(),addEmptySignatureAppearance(), andendPage()are no-ops that throw in strict mode;Open()is a safe no-op that never throws. RemoveendPage()andOpen(). Signing requires a commercial NextPDF edition through the modern signature API. - PDF version is fixed.
setPDFVersion()cannot down-target an older PDF version; output is always PDF 2.0.setUserRights()is deprecated in PDF 2.0 and is ignored with a notice. - Alias conflict. If anything still resolves to the real TCPDF class after
you remove
tecnickcom/tcpdf, the alias caveat applies — import the adapter explicitly at those call sites.
Performance
Section titled “Performance”The adapter delegates to the engine; document build cost scales with content,
not with the adapter layer. Because the adapter’s Output() does not write to
the output buffer, it is safe inside a queue worker — move heavy TCPDF-style
generation off the request thread the same way you would move any NextPDF
generation. Re-baselining byte-level tests onto rendered content is a one-time
cost, and it gives you tests that survive future engine upgrades.
Security notes
Section titled “Security notes”- Encryption.
SetProtection()ignores the legacymodeandpubkeysparameters; the engine uses AES-256 for the standard handler. For certificate-based encryption, use the modern public-key encryption entry point exposed on the adapter, not the legacy parameters. - Signing is gated. Baseline signature support is a commercial-edition
capability reached through the modern signature API with a certificate value
object; the legacy
setSignature()is a no-op. This guide does not claim about long-term-validation or timestamped signature profiles for any edition. - Fail explicitly during the audit. Strict mode makes silent parameter loss visible, so you know when the adapter did not honor the caller’s intent. Treat collected exceptions as the migration work list, not as production behavior.
- Never write an empty
catchblock. The audit example catchesTcpdfNotImplementedExceptionand writes a defined work-item line.
The full encryption and signature posture during migration is in the compat-legacy security-and-operations page.
Conformance
Section titled “Conformance”This guide makes no normative standards claim of its own. The adapter writes PDF 2.0 (ISO 32000-2) output and cannot down-target an older version. That behavior and its clause are pinned on the upstream method-coverage page, which also records the OWASP fail-explicitly principle behind strict mode and the ISO/IEC 25023 functional-completeness framing of the coverage audit. This cookbook page restates the usage and defers those citations to the upstream page.
See also
Section titled “See also”- Return a generated PDF from a controller — return adapter output as an HTTP response.
- compat-legacy quickstart — first document, output destinations, and the escape hatch.
- TCPDF method coverage — the per-method audit and the authoritative matrix.
- Migrate from TCPDF 6.x to NextPDF — the full six-stage strategy with code.