Blazing-fast, modern HTML to PDF converter for Laravel powered by headless Chrome and Go.

Maintainers

Package info

github.com/mikailfaruqali/pdf

Language:HTML

pkg:composer/mikailfaruqali/pdf

Transparency log

Statistics

Installs: 6

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

1.0.3 2026-08-29 15:55 UTC

This package is auto-updated.

Last update: 2026-08-29 16:26:57 UTC


README

Latest Version on Packagist Total Downloads License

A modern, high-performance HTML-to-PDF converter for Laravel 11+ and PHP 8.4+, powered by headless Chrome / Chromium and the compiled Go binary pdf.

Features

  • 🚀 Blazing Fast: Direct headless Chrome execution via a lightweight Go core.
  • 🎨 Modern CSS: Full support for CSS Grid, Flexbox, Tailwind CSS, SVG, custom fonts, and @page rules.
  • 📑 Headers, Footers & Watermarks: Multi-fragment support with dynamic {page} and {pages} placeholders.
  • 🛠️ Developer Friendly: Fluent, expressive API with first-class Laravel Renderable (Blade views) support.
  • 📦 Automated Binary Installer: Built-in php artisan pdf:install to download pre-built binaries for your OS/architecture.

Requirements

  • PHP 8.2+, 8.3+, 8.4+, 8.5+
  • Laravel 10.0+, 11.0+, 12.0+, or 13.0+
  • Google Chrome, Chromium, Brave, or Microsoft Edge installed on the host system

Installation

Install the package via Composer:

composer require mikailfaruqali/pdf

Publish the configuration file (optional):

php artisan vendor:publish --tag=pdf-config

Download and install the native Go binary for your platform:

php artisan pdf:install

Verify your environment (checks both pdf binary and headless browser):

php artisan pdf:check

Configuration

The published config/pdf.php file allows you to customize defaults:

return [
    'binary_path' => env('PDF_BINARY_PATH'),
    'chrome_path' => env('PDF_CHROME_PATH'),
    'timeout'     => (int) env('PDF_TIMEOUT', 120),
    'temp_path'   => env('PDF_TEMP_PATH'),
];

Basic Usage

Using Blade Views

You can pass standard strings or any Laravel Renderable (such as view()):

use PDF\Facades\Pdf;

// Download PDF as response
return Pdf::make()
    ->content(view('invoices.show', ['invoice' => $invoice]))
    ->paper('A4')
    ->download('invoice-1001.pdf');

// Display inline in browser
return Pdf::make()
    ->content(view('reports.monthly'))
    ->inline('monthly-report.pdf');

// Save directly to disk
$path = Pdf::make()
    ->content('<h1>Hello World</h1>')
    ->save(storage_path('app/exports/hello.pdf'));

// Get raw PDF bytes
$pdfBytes = Pdf::make()
    ->content('<h1>Raw Output</h1>')
    ->get();

Advanced Options

Headers, Footers & Page Numbers

Headers and footers support dynamic placeholders {page} (or {pageNumber}) and {pages} (or {totalPages}), as well as math expressions like {page+1}:

return Pdf::make()
    ->content(view('documents.contract'))
    ->header(view('pdf.header'))
    ->footer('<div style="text-align: right; font-size: 10px;">Page {page} of {pages}</div>')
    ->headerHeight('25mm')
    ->footerHeight('15mm')
    ->headerSpacing('4mm')
    ->footerSpacing('4mm')
    ->download('contract.pdf');

Watermark

return Pdf::make()
    ->content(view('invoices.preview'))
    ->watermark('<h1 style="color: red; transform: rotate(-45deg);">CONFIDENTIAL</h1>')
    ->watermarkOpacity(0.15)
    ->watermarkBehind(true)
    ->download('confidential.pdf');

Custom PDF Viewer (Font, RTL & Theme)

The viewer is opt-in — it is only used when withViewer() is called and you return inline(). Without it, inline() streams the raw PDF to the browser's native viewer.

font(), dir() and theme() style the viewer UI only (its toolbar, title and chrome). They do not change the generated PDF — style the PDF from your own Blade/CSS.

use PDF\Facades\Pdf;

// Default viewer (system-ui font)
return Pdf::make()
    ->content($html)
    ->withViewer()
    ->inline('invoice.pdf');

// With custom embedded font and RTL direction
return Pdf::make()
    ->content($html)
    ->font(storage_path('fonts/NotoSans-Regular.ttf'), 'Noto Sans')
    ->dir('rtl')
    ->withViewer()
    ->inline('invoice.pdf');

// Kurdish / Arabic (RTL with font and custom CSS font-stack)
return Pdf::make()
    ->content($html)
    ->font(storage_path('fonts/Rabar.ttf'), 'Rabar', "'Rabar', 'Noto Sans Arabic', sans-serif")
    ->dir('rtl')
    ->withViewer()
    ->inline('invoice.pdf');

Viewer theme (light / dark)

The viewer ships with the sn-kit design system (GitHub Dark / GitHub Light palettes) and defaults to dark. The theme is set server-side and can also be toggled by the user from the toolbar — their choice is remembered in localStorage.

->theme('dark')      // default
->theme('light')
->theme('auto')      // follow the viewer's OS preference
->darkMode()         // alias for theme('dark')
->lightMode()        // alias for theme('light')

Supported font formats are detected from the file extension: .ttf, .otf, .woff, .woff2.

Viewer favicon

icon() sets the browser-tab icon. It accepts an emoji, an absolute URL, a data: URI, or a path to a local image — a local file is embedded as a data: URI so the viewer stays self-contained.

->icon('📄')                                  // emoji
->icon(public_path('img/logo.png'))           // local file, embedded
->icon('https://cdn.example.com/fav.ico')     // URL

Conditional chaining

The builder uses Laravel's Conditionable trait, so when() / unless() chain fluently — useful for driving the viewer from user or tenant settings:

return Pdf::make()
    ->content($html)
    ->withViewer()
    ->when($user->prefersDark, fn ($pdf) => $pdf->darkMode(), fn ($pdf) => $pdf->lightMode())
    ->when(app()->getLocale() === 'ckb', fn ($pdf) => $pdf->rtl()->font(storage_path('fonts/Rabar.ttf'), 'Rabar'))
    ->unless($tenant->logo === null, fn ($pdf) => $pdf->icon($tenant->logo))
    ->inline('invoice.pdf');

Custom View Templates & UI Studio

Configure custom print settings, page margins, orientation, headers, footers, watermarks, and viewer themes per Blade view and per locale.

use PDF\Facades\Pdf;

// Automatically loads template options saved for 'invoices.show' and the current locale (or '*' fallback)
return Pdf::make()
    ->view('invoices.show', ['invoice' => $invoice])
    ->inline('invoice.pdf');

You can also explicitly load or apply options:

Pdf::make()
    ->loadTemplate('invoices.show', 'en')
    ->content(view('invoices.show', $data))
    ->download('invoice.pdf');

Template Studio UI (/pdf-templates)

Manage templates with a visual editor matching the sn-kit design pattern (dark/light theme toggle, Select2 searchable views, real-time live preview):

  1. Run migrations:
php artisan migrate
  1. Navigate to http://your-app.test/pdf-templates in your browser.

Full Fluent API Reference

Pdf::make()
    ->view(string $view, array $data = [], array $mergeData = [], ?string $locale = null)
    ->loadTemplate(string $view, ?string $locale = null)
    ->applyTemplateOptions(array $options)
    ->content(string|Renderable $html)
    ->header(string|Renderable $html)
    ->footer(string|Renderable $html)
    ->watermark(string|Renderable $html)
    ->paper('A4')                          // A0-A6, B4, B5, Letter, Legal, etc.
    ->orientation('portrait'|'landscape')
    ->margin('10mm')                       // Applies to all 4 sides
    ->marginTop('5mm')
    ->marginBottom('5mm')
    ->marginLeft('5mm')
    ->marginRight('5mm')
    ->headerHeight('25mm')
    ->footerHeight('15mm')
    ->headerSpacing('2mm')
    ->footerSpacing('2mm')
    ->headerOffset('0mm')
    ->footerOffset('0mm')
    ->watermarkOpacity(0.3)
    ->watermarkBehind(true)
    ->scale(1.0)                           // 0.1 to 2.0
    ->preferCssPageSize(true)              // Honour @page size in CSS instead of ->paper()
    ->withViewer()                         // Opt in to the built-in viewer for ->inline()
    ->font($path, $family, $stack)         // Viewer UI font
    ->dir('rtl'|'ltr')                     // Viewer UI direction (->rtl() / ->ltr())
    ->theme('dark'|'light'|'auto')         // Viewer UI theme (->darkMode() / ->lightMode())
    ->icon('📄')                            // Viewer favicon (emoji, URL, data: URI, or file)
    ->when($cond, fn ($pdf) => ...)        // Conditional chaining (Laravel Conditionable)
    ->unless($cond, fn ($pdf) => ...)
    ->tempDirectory(sys_get_temp_dir())
    ->pageOffset(0)
    ->totalOffset(0)
    ->title('Invoice #1001')
    ->author('Mikail Faruq Ali')
    ->subject('Billing Invoice')
    ->keywords('billing, invoice, pdf')
    ->baseUrl(public_path('assets'))
    ->chromePath('/usr/bin/google-chrome')
    ->timeout(120)
    ->quiet()
    ->download('invoice.pdf')              // Return download Response
    ->inline('invoice.pdf')                // Return inline preview Response
    ->save('/path/to/invoice.pdf')         // Save to disk and return path
    ->toFile('/path/to/invoice.pdf')       // Alias for save()
    ->get();                               // Return binary PDF string

Artisan Commands

php artisan pdf:install

Detects system OS and architecture and downloads the matching pdf executable from GitHub Releases (github.com/mikailfaruqali/pdf/releases/latest) to storage/pdf/pdf (or pdf.exe on Windows), sets executable permissions, and updates .env.

Options:

  • --force: Overwrite existing binary if already present.
  • --tag=latest: Specify release tag to download.

php artisan pdf:check

Validates that:

  1. The pdf binary is installed, accessible, and executable.
  2. Google Chrome / Chromium is installed and operational.

License

The MIT License (MIT).