Skip to main content

Dompdf PDF Generation

The J2Commerce Dompdf Library bundles dompdf v3.1.5 as a Joomla installable library extension. It converts HTML and CSS into PDF documents and is the recommended approach for generating invoices, gift certificates, packing slips, and any other printable output from J2Commerce extensions.

The library ships as a separate add-on available from the J2Commerce Extensions Store. It is not included with the core J2Commerce 6 component.

Two usage paths are available:

  • PdfFactory (recommended) — a thin wrapper at J2Commerce\Library\Dompdf\PdfFactory that pre-configures Joomla-aware defaults and manages autoloader loading
  • Direct Dompdf\Dompdf — access the underlying dompdf class directly for full control over every option

Architecture

Key Classes

ClassNamespacePurpose
PdfFactoryJ2Commerce\Library\DompdfJoomla-aware factory: autoloader, defaults, availability check
DompdfDompdfCore dompdf renderer — HTML to PDF
OptionsDompdfConfiguration container for a Dompdf instance

Installation

This library is a separate add-on available from the J2Commerce Extensions Store. It is not included with the core J2Commerce 6 component.

  1. Purchase and download the lib_dompdf.zip package from the J2Commerce website.
  2. Go to System -> Install -> Extensions.
  3. Upload the lib_dompdf.zip package file.
  4. The library installs automatically and creates the temp directory at JPATH_ROOT/tmp/dompdf/.

The install script enforces PHP >= 8.1.0 and Joomla >= 5.0.0. If either requirement is not met, installation is blocked.

On uninstall, the tmp/dompdf/ directory is removed.

Verify Installation

// File: your-plugin/src/Extension/YourPlugin.php

use J2Commerce\Library\Dompdf\PdfFactory;

if (!PdfFactory::isAvailable()) {
// Library not installed — show a notice or skip PDF generation
return;
}

Alternatively, the gift certificate plugin demonstrates a form field pattern that displays an admin badge:

// File: plugins/j2commerce/app_giftcertificate/src/Field/PdfcheckField.php

$dompdf_available = is_dir(Path::clean(JPATH_LIBRARIES . '/dompdf'));

Both approaches confirm the same thing: whether libraries/dompdf/vendor/autoload.php exists on disk.

PdfFactory is the recommended entry point. It handles autoloader bootstrapping exactly once per request, sets sensible Joomla-aware defaults (temp dir, font cache, security options), and returns a configured Dompdf instance ready to use.

Default Configuration Applied by PdfFactory

OptionDefault ValueNotes
tempDirJPATH_ROOT/tmp/dompdfMust be writable
fontDirJPATH_ROOT/tmp/dompdfFont metrics stored here
fontCacheJPATH_ROOT/tmp/dompdfFont cache stored here
isFontSubsettingEnabledtrueReduces PDF file size
isRemoteEnabledfalseRemote HTTP requests disabled for security
isHtml5ParserEnabledtrueUse the HTML5 parser
logOutputFileJPATH_ROOT/tmp/dompdf/dompdf_log.htmlDebug log
PaperA4Passed as second argument
OrientationportraitPassed as third argument

Basic PDF Generation — Get String Output

// File: plugins/j2commerce/your_plugin/src/Model/YourModel.php

declare(strict_types=1);

namespace J2Commerce\Plugin\J2Commerce\YourPlugin\Model;

use J2Commerce\Library\Dompdf\PdfFactory;
use Joomla\Filesystem\File;

\defined('_JEXEC') or die;

class YourModel
{
public function generatePdf(string $html): string
{
$dompdf = PdfFactory::create();
$dompdf->loadHtml($html);
$dompdf->render();

return $dompdf->output();
}
}

Saving a PDF to Disk

// File: plugins/j2commerce/your_plugin/src/Model/YourModel.php

use J2Commerce\Library\Dompdf\PdfFactory;
use Joomla\Filesystem\File;
use Joomla\Filesystem\Folder;
use Joomla\Filesystem\Path;

public function savePdf(string $html, string $filename): bool
{
$outputDir = JPATH_SITE . '/media/j2commerce/invoices';

if (!is_dir(Path::clean($outputDir))) {
Folder::create($outputDir);
}

$dompdf = PdfFactory::create();
$dompdf->loadHtml($html);
$dompdf->render();

$pdfContent = $dompdf->output();
$filePath = $outputDir . '/' . $filename;

if (is_file(Path::clean($filePath))) {
File::delete($filePath);
}

return File::write($filePath, $pdfContent);
}

Streaming a PDF to the Browser

Call stream() after render() to send the PDF directly to the browser, then exit. The Attachment option controls whether the browser prompts a download (true) or attempts to display inline (false).

// File: plugins/j2commerce/your_plugin/src/Extension/YourPlugin.php

use J2Commerce\Library\Dompdf\PdfFactory;
use Joomla\CMS\Factory;

public function streamPdfToBrowser(string $html, string $filename): void
{
$dompdf = PdfFactory::create();
$dompdf->loadHtml($html);
$dompdf->render();

// stream() sends HTTP headers and PDF body, then exits
$dompdf->stream($filename, ['Attachment' => false]);
Factory::getApplication()->close();
}

For a download prompt instead of inline display, set 'Attachment' => true.

Custom Paper Size and Orientation

Pass the paper size and orientation as the second and third arguments to PdfFactory::create(). Any size supported by dompdf is valid, including named sizes ('A4', 'letter', 'legal') and custom dimensions as a four-element array in points.

// A4 landscape
$dompdf = PdfFactory::create(null, 'A4', 'landscape');

// US Letter portrait (default)
$dompdf = PdfFactory::create(null, 'letter', 'portrait');

// Custom size: 200mm x 100mm expressed in points (1pt = 1/72 inch)
// 200mm = 566.93pt, 100mm = 283.46pt
$dompdf = PdfFactory::create(null, [0, 0, 283.46, 566.93], 'portrait');

Enabling Remote Images

By default PdfFactory disables remote HTTP/HTTPS resource loading for security. Enable it only when the HTML content originates from a trusted internal source.

use Dompdf\Options;
use J2Commerce\Library\Dompdf\PdfFactory;

$options = new Options();
$options->setTempDir(JPATH_ROOT . '/tmp/dompdf');
$options->setFontDir(JPATH_ROOT . '/tmp/dompdf');
$options->setFontCache(JPATH_ROOT . '/tmp/dompdf');
$options->setIsFontSubsettingEnabled(true);
$options->setIsRemoteEnabled(true); // allow external image URLs

$dompdf = PdfFactory::create($options, 'A4', 'portrait');
$dompdf->loadHtml($html);
$dompdf->render();

Passing a non-null Options object overrides all defaults entirely. Include every option you need; the factory does not merge with defaults when a custom Options is passed.

Checking Availability Before Use

Always guard PDF generation paths in plugins that declare the library as optional:

use J2Commerce\Library\Dompdf\PdfFactory;

if (!PdfFactory::isAvailable()) {
Factory::getApplication()->enqueueMessage(
'PDF generation requires the Dompdf Library. Please install it from the J2Commerce Extensions Store.',
'warning'
);
return;
}

$dompdf = PdfFactory::create();
// ... generate PDF

Method 2: Direct Dompdf

Use the underlying Dompdf\Dompdf class directly when you need precise control over every option or when the factory defaults are not appropriate for your use case.

Call PdfFactory::ensureAutoloaded() first to register the Composer autoloader. This is safe to call multiple times — it uses a static flag to load the autoloader exactly once per request.

// File: plugins/j2commerce/your_plugin/src/Model/YourModel.php

declare(strict_types=1);

namespace J2Commerce\Plugin\J2Commerce\YourPlugin\Model;

use Dompdf\Dompdf;
use Dompdf\Options;
use J2Commerce\Library\Dompdf\PdfFactory;

\defined('_JEXEC') or die;

class YourModel
{
public function generateCustomPdf(string $html): string
{
// Register the Composer autoloader before using Dompdf\ classes
PdfFactory::ensureAutoloaded();

$options = new Options();
$options->setTempDir(JPATH_ROOT . '/tmp/dompdf');
$options->setFontDir(JPATH_ROOT . '/tmp/dompdf');
$options->setFontCache(JPATH_ROOT . '/tmp/dompdf');
$options->setIsFontSubsettingEnabled(true);
$options->setIsRemoteEnabled(false);
$options->set('isHtml5ParserEnabled', true);
$options->setDpi(150);

$dompdf = new Dompdf($options);
$dompdf->setPaper('A4', 'portrait');
$dompdf->loadHtml($html);
$dompdf->render();

return $dompdf->output();
}
}

When to Use Direct vs Factory

Use PdfFactory::create() when:

  • Generating standard documents (invoices, certificates, packing slips)
  • You want the Joomla-aware defaults without boilerplate
  • You only need to override paper size or orientation

Use direct Dompdf when:

  • You need to change DPI, default font, media type, or other options not exposed by the factory
  • You are embedding PDF generation in a long-running process and need fine-grained memory control
  • You need access to dompdf's Canvas API or callback hooks

Integration with J2Commerce Extensions

Plugin Pattern (App Plugin)

The following pattern shows how a J2Commerce app plugin checks availability, generates a PDF, and attaches it to an order email. This mirrors the app_giftcertificate implementation.

// File: plugins/j2commerce/your_plugin/src/Extension/YourPlugin.php

declare(strict_types=1);

namespace J2Commerce\Plugin\J2Commerce\YourPlugin\Extension;

use J2Commerce\Library\Dompdf\PdfFactory;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\Event\SubscriberInterface;
use Joomla\Filesystem\File;
use Joomla\Filesystem\Folder;
use Joomla\Filesystem\Path;

\defined('_JEXEC') or die;

final class YourPlugin extends CMSPlugin implements SubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
'onJ2CommerceOrderEmailPrepare' => 'attachPdfToEmail',
];
}

public function attachPdfToEmail(\Joomla\Event\Event $event): void
{
if (!PdfFactory::isAvailable()) {
return;
}

$order = $event->getArgument('order');
$mailer = $event->getArgument('mailer');

$html = $this->buildHtml($order);
$pdfPath = $this->savePdf($html, 'order_' . $order->order_id . '.pdf');

if ($pdfPath !== null) {
$mailer->addAttachment($pdfPath);
}
}

private function buildHtml(object $order): string
{
return '<!DOCTYPE html><html><head>'
. '<meta charset="UTF-8">'
. '</head><body>'
. '<h1>Order #' . htmlspecialchars((string) $order->order_id, ENT_QUOTES, 'UTF-8') . '</h1>'
. '</body></html>';
}

private function savePdf(string $html, string $filename): ?string
{
$dir = JPATH_SITE . '/media/j2commerce/invoices';

if (!is_dir(Path::clean($dir))) {
Folder::create($dir);
}

$dompdf = PdfFactory::create();
$dompdf->loadHtml($html);
$dompdf->render();

$path = $dir . '/' . $filename;

if (is_file(Path::clean($path))) {
File::delete($path);
}

return File::write($path, $dompdf->output()) ? $path : null;
}
}

Declaring the Library Dependency

In your plugin's preflight() installer script, warn the user if the library is not present. Do not block installation — the plugin may have non-PDF features that work without the library.

// File: plugins/j2commerce/your_plugin/script.your_plugin.php

use Joomla\CMS\Factory;
use Joomla\Filesystem\Path;

public function preflight(string $type, object $parent): bool
{
if (!is_dir(Path::clean(JPATH_LIBRARIES . '/dompdf'))) {
Factory::getApplication()->enqueueMessage(
'PDF generation features require the Dompdf Library. Install it from the J2Commerce Extensions Store.',
'notice'
);
}

return true;
}

Configuration Reference

Options Methods Commonly Used

MethodTypeDescription
setTempDir(string $dir)stringWritable directory for temporary files
setFontDir(string $dir)stringDirectory where font metrics are stored
setFontCache(string $dir)stringDirectory for cached font data (may equal fontDir)
setIsRemoteEnabled(bool $enabled)boolAllow loading remote HTTP/HTTPS resources
setIsFontSubsettingEnabled(bool $enabled)boolEmbed only used glyphs — reduces file size
set('isHtml5ParserEnabled', bool)boolUse the HTML5 parser (recommended)
setDpi(int $dpi)intImage DPI (default: 96)
setDefaultFont(string $font)stringFallback font family (default: 'serif')
setLogOutputFile(string $path)stringDebug log file path
setChroot(array $dirs)arrayRestrict local file access to these directories

Dompdf Methods Used in Generation

MethodDescription
loadHtml(string $html, ?string $encoding)Parse and load HTML string
setPaper(string|array $paper, string $orientation)Set paper size and orientation
render()Lay out the document and produce the PDF
output(?array $options)Return the rendered PDF as a string
stream(string $filename, ?array $options)Send PDF to browser with HTTP headers

stream() Options

KeyTypeDefaultDescription
Attachmentbooltruetrue = download prompt; false = inline display

Troubleshooting

Blank or Corrupted PDF Output

Cause: HTML passed to loadHtml() contains invalid markup that confuses the layout engine.

Solution: Use PHP's tidy_repair_string() to normalize the HTML before passing it to dompdf. Check that the document has a <!DOCTYPE html> declaration and a <meta charset="UTF-8"> tag inside <head>.

if (function_exists('tidy_repair_string')) {
$config = ['output-html' => 'yes', 'char-encoding' => 'utf8', 'wrap' => 0];
$cleaned = tidy_repair_string($html, $config, 'utf8');

if ($cleaned !== false) {
$html = $cleaned;
}
}

$dompdf->loadHtml($html);

Images Not Appearing in PDF

Cause: Remote images require isRemoteEnabled = true. Local images must use absolute filesystem paths, not site-relative URLs.

Solution 1 — Local images: Replace relative URLs (/images/logo.png) with absolute filesystem paths (file:///var/www/html/images/logo.png) or absolute web URLs if remote loading is enabled.

Solution 2 — Inline base64: Embed images as data URIs to avoid any remote or path issues:

$imageData   = file_get_contents(JPATH_ROOT . '/images/logo.png');
$base64Image = 'data:image/png;base64,' . base64_encode($imageData);
$html = '<img src="' . $base64Image . '" />';

Solution 3 — Enable remote loading (for trusted, internal sources only):

$options = new Options();
// ... other options ...
$options->setIsRemoteEnabled(true);
$dompdf = PdfFactory::create($options);

Font Rendering Problems / Missing Characters

Cause: The font directory is not writable, so dompdf cannot cache font metrics on first use.

Solution: Ensure JPATH_ROOT/tmp/dompdf/ exists and is writable by the web server. The library's install script creates this directory automatically with mode 0755. Verify it with:

var_dump(is_writable(JPATH_ROOT . '/tmp/dompdf'));

For non-Latin scripts (Arabic, Chinese, Japanese), use a font that supports the required character set and register it with dompdf's FontMetrics before calling render().

Memory Limit Exceeded

Cause: Large documents, many images, or high DPI settings require significant memory. Dompdf loads the entire document into memory during layout.

Solution: Increase PHP memory limit for the PDF generation request, reduce image resolution, or split large documents into multiple smaller PDFs:

$previousLimit = ini_set('memory_limit', '256M');

$dompdf = PdfFactory::create();
$dompdf->loadHtml($html);
$dompdf->render();
$output = $dompdf->output();

ini_set('memory_limit', $previousLimit ?: '128M');

PDF Not Streaming — Headers Already Sent

Cause: Output (whitespace, BOM, or echo) was sent before stream() was called.

Solution: Call ob_end_clean() to discard any buffered output before streaming:

while (ob_get_level() > 0) {
ob_end_clean();
}

$dompdf->stream($filename, ['Attachment' => false]);
Factory::getApplication()->close();

Tmp Directory Not Created

Cause: The installer script did not run (e.g., the library was copied manually rather than installed through the Extension Manager).

Solution: Create the directory manually and ensure it is writable:

mkdir -p /path/to/joomla/tmp/dompdf
chmod 0755 /path/to/joomla/tmp/dompdf

API Reference

PdfFactory Methods

MethodSignatureReturnsDescription
ensureAutoloadedstatic (): voidvoidLoads vendor/autoload.php exactly once per request
createstatic (?Options $options, string $paper, string $orientation): DompdfDompdfCreates a configured Dompdf instance. Pass null for $options to use Joomla-aware defaults
getVersionstatic (): stringstringReturns the bundled dompdf version string ('3.1.5')
isAvailablestatic (): boolboolReturns true when libraries/dompdf/vendor/autoload.php exists

Default Parameter Values for PdfFactory::create()

ParameterDefaultNotes
$optionsnullNull triggers Joomla-aware defaults
$paper'A4'Any dompdf-supported size string or point array
$orientation'portrait''portrait' or 'landscape'