Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Snappy Laravel Package

barryvdh/laravel-snappy

Generate PDF and image files in Laravel using wkhtmltopdf/wkhtmltoimage. Provides simple facades and service provider setup, config options, and easy rendering from views or HTML strings with headers, footers, and custom binaries.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the Package:

    composer require barryvdh/laravel-snappy
    

    Publish the config file:

    php artisan vendor:publish --provider="Barryvdh\Snappy\ServiceProvider"
    
  2. Configure Binaries: Edit config/snappy.php to set paths to wkhtmltopdf and wkhtmltoimage binaries. For Docker, ensure these are installed in your container:

    RUN apt-get update && apt-get install -y wkhtmltopdf
    
  3. First Use Case: Generate a PDF from a Blade view in a controller:

    use Barryvdh\Snappy\Facades\SnappyPdf;
    
    public function generatePdf()
    {
        return SnappyPdf::loadView('pdf.template', ['data' => $data])
            ->setOption('margin-top', '20mm')
            ->setOption('margin-bottom', '20mm')
            ->stream('document.pdf');
    }
    
  4. Verify Installation: Test with a simple Blade template (resources/views/pdf.template):

    <h1>Hello, {{ $data['name'] }}!</h1>
    <p>This is a test PDF.</p>
    

    Visit the route to confirm PDF generation.


Implementation Patterns

Core Workflows

1. PDF Generation from Views

Pattern: Use Blade templates for dynamic PDFs.

// Controller
public function invoice($id)
{
    $invoice = Invoice::find($id);
    return SnappyPdf::loadView('invoices.pdf', compact('invoice'))
        ->setPaper('a4')
        ->stream("invoice-{$invoice->id}.pdf");
}

Template (resources/views/invoices.pdf):

<!DOCTYPE html>
<html>
<head>
    <style>
        table { width: 100%; border-collapse: collapse; }
        th, td { border: 1px solid #ddd; padding: 8px; }
    </style>
</head>
<body>
    <h1>Invoice #{{ $invoice->number }}</h1>
    <table>
        <tr><th>Item</th><th>Qty</th><th>Price</th></tr>
        @foreach($invoice->items as $item)
            <tr>
                <td>{{ $item->description }}</td>
                <td>{{ $item->quantity }}</td>
                <td>${{ number_format($item->price, 2) }}</td>
            </tr>
        @endforeach
    </table>
</body>
</html>

2. PDF Generation from HTML Strings

Pattern: Dynamically generate PDFs from raw HTML (e.g., email templates).

$html = '<h1>Dynamic PDF</h1><p>Generated at: ' . now() . '</p>';
return SnappyPdf::loadHtml($html)
    ->setOption('encoding', 'UTF-8')
    ->download('dynamic.pdf');

3. Asynchronous Generation with Queues

Pattern: Offload PDF generation to background jobs for performance.

// Dispatch job
SnappyPdfJob::dispatch('invoices.pdf', ['invoice' => $invoice], 'invoice.pdf');

// Job class
use Barryvdh\Snappy\Facades\SnappyPdf;
use Illuminate\Bus\Queueable;

class SnappyPdfJob implements ShouldQueue
{
    use Queueable;

    public function handle()
    {
        $pdf = SnappyPdf::loadView($this->view, $this->data)
            ->setOptions($this->options);
        Storage::put($this->filename, $pdf->output());
    }
}

4. Custom Headers and Footers

Pattern: Add consistent headers/footers to all PDFs.

// Config in snappy.php
'pdf' => [
    'header-html' => resource_path('views/pdf/header.blade.php'),
    'footer-html' => resource_path('views/pdf/footer.blade.php'),
    'header-font-name' => 'DejaVuSans',
    'footer-font-name' => 'DejaVuSans',
],

Header Template (resources/views/pdf/header.blade.php):

<div style="text-align: center; font-size: 12px;">
    Company Name | Page <span class="page-number"></span>
</div>

5. Image Generation

Pattern: Convert HTML to images (e.g., thumbnails for previews).

use Barryvdh\Snappy\Facades\SnappyImage;

$image = SnappyImage::loadHtml('<h1>Preview</h1><p>This will be an image.</p>')
    ->setOption('width', 800)
    ->setOption('height', 600)
    ->get();
Storage::put('preview.png', $image);

Integration Tips

Laravel Facades vs. Service Container

  • Use Facades for simplicity in controllers/views:
    use Barryvdh\Snappy\Facades\SnappyPdf;
    
  • Use Service Container for dependency injection in services:
    public function __construct(private SnappyPdf $pdf) {}
    

Dynamic Options

Set options dynamically per request:

$pdf = SnappyPdf::loadView('template', $data)
    ->setOption('margin-top', '10mm')
    ->setOption('margin-bottom', '10mm')
    ->setOption('encoding', 'UTF-8');

Event Hooks

Extend functionality using events:

// Listen for PDF generation events
SnappyPdf::listen('generating', function ($job) {
    // Add custom logic before generation
    $job->setOption('custom-key', 'custom-value');
});

SnappyPdf::listen('generated', function ($pdf) {
    // Post-process the PDF
    $pdf->setContent($pdf->getContent() . 'Custom footer');
});

Testing

Use SnappyPdf in tests with mocks or temporary files:

public function testPdfGeneration()
{
    $pdf = SnappyPdf::loadHtml('<h1>Test</h1>');
    $content = $pdf->get();
    $this->assertStringContainsString('Test', $content);
}

Gotchas and Tips

Pitfalls

1. Binary Path Issues

  • Problem: PDF generation fails silently if wkhtmltopdf is not in the configured path.
  • Fix: Verify paths in config/snappy.php and ensure binaries are installed:
    which wkhtmltopdf  # Linux/Mac
    where wkhtmltopdf  # Windows
    
  • Docker Tip: Use a multi-stage build to include binaries:
    FROM barryvdh/laravel-snappy:latest
    COPY --from=builder /usr/local/bin/wkhtmltopdf /usr/local/bin/
    

2. CSS Rendering Quirks

  • Problem: Some CSS properties (e.g., position: fixed, flexbox) may not render as expected.
  • Fix:
    • Use inline styles or simplified CSS.
    • Test with WkHTMLToPDF’s CSS support list.
    • Example workaround for tables:
      table { border-collapse: collapse; width: 100%; }
      th, td { border: 1px solid #ddd; padding: 8px; }
      

3. Memory Limits

  • Problem: Large PDFs (e.g., 100+ pages) may hit PHP memory limits.
  • Fix:
    • Increase memory_limit in php.ini or .env:
      memory_limit = 512M
      
    • Use queues for async generation.
    • Optimize HTML (e.g., avoid nested tables, excessive images).

4. JavaScript Execution

  • Problem: JavaScript in HTML may not execute as expected in PDFs.
  • Fix:
    • Use SnappyPdf::loadHtml($html)->setOption('enable-javascript', true) cautiously.
    • Avoid complex JS; prefer server-side logic in Blade templates.

5. Font Issues

  • Problem: Custom fonts may not render in PDFs.
  • Fix:
    • Use system fonts (e.g., Arial, Times New Roman).
    • Specify font paths in snappy.php:
      'pdf' => [
          'font-path' => resource_path('fonts'),
      ],
      
    • Ensure fonts are installed on the server.

6. Queue Timeouts

  • Problem: Long-running PDF jobs may timeout in queues.
  • Fix:
    • Increase queue_worker_max_jobs in .env:
      QUEUE_W
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope
anil/file-picker
broqit/fields-ai