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

Fpdi Laravel Package

setasign/fpdi

FPDI is a PHP library to import pages from existing PDFs and reuse them as templates in FPDF, TCPDF, or tFPDF. PSR-4 namespaced, Composer-friendly, no special PHP extensions required, with improved performance and lower memory use in v2.

View on GitHub
Deep Wiki
Context7
## Getting Started

### Minimal Setup for Laravel
1. **Install Dependencies**
   Add to `composer.json` (choose one PDF engine):
   ```json
   "require": {
       "setasign/fpdf": "1.9.*",
       "setasign/fpdi": "^2.6",
       "dompdf/dompdf": "^2.0" // Optional: For hybrid workflows
   }

Run composer install.

  1. Basic Usage in a Controller

    use setasign\Fpdi\Fpdi;
    
    public function generatePdf()
    {
        $pdf = new Fpdi();
        $pdf->AddPage();
        $pdf->setSourceFile(storage_path('app/templates/invoice_template.pdf'));
        $tplId = $pdf->importPage(1); // Import first page
        $pdf->useTemplate($tplId, 10, 10, 190); // Place template at (10,10) with width 190mm
    
        // Add dynamic content (e.g., text, images)
        $pdf->SetFont('Arial', 'B', 12);
        $pdf->Cell(0, 10, 'Dynamic Content', 0, 1, 'C');
    
        return $pdf->Output('invoice.pdf', 'D'); // Download
    }
    
  2. First Use Case: Invoice Generation

    • Store a pre-designed invoice template in storage/app/templates/.
    • Use FPDI to import the template, then overlay dynamic data (e.g., client name, amounts) using FPDF methods.
    • Example:
      $pdf->SetXY(50, 50); // Position cursor
      $pdf->Cell(0, 10, "Client: {$client->name}", 0, 1);
      

Implementation Patterns

1. Template-Based Workflows

  • Pattern: "Template + Overlay"

    • Store static PDFs (e.g., contracts, certificates) in storage/app/templates/.
    • Use FPDI to import pages, then add dynamic content via FPDF/TCPDF methods.
    • Example:
      $pdf = new Fpdi();
      $pdf->AddPage();
      $pdf->setSourceFile($templatePath);
      $tplId = $pdf->importPage(1);
      $pdf->useTemplate($tplId, 0, 0, 210); // Full-page template
      
      // Overlay dynamic data
      $pdf->SetFont('Helvetica', 'B', 12);
      $pdf->SetXY(100, 100);
      $pdf->Cell(0, 10, "Order #{$order->id}", 0, 1);
      
  • Multi-Page Templates:

    $pageCount = $pdf->setSourceFile($templatePath);
    for ($i = 1; $i <= $pageCount; $i++) {
        $tplId = $pdf->importPage($i);
        $pdf->AddPage();
        $pdf->useTemplate($tplId, 0, 0, 210);
        // Add page-specific content
    }
    

2. Dynamic Data Injection

  • Variables in Templates: Use placeholder text (e.g., [CLIENT_NAME]) in the source PDF, then overlay with FPDF:
    $pdf->SetXY(50, 50);
    $pdf->Cell(0, 10, str_replace('[CLIENT_NAME]', $client->name, '[CLIENT_NAME]'));
    
  • Images/Logos:
    $pdf->Image(storage_path('app/logos/company.png'), 10, 10, 50);
    

3. Integration with Laravel

  • Service Provider: Bind FPDI to the container for dependency injection:
    // app/Providers/AppServiceProvider.php
    public function register()
    {
        $this->app->bind(Fpdi::class, function () {
            return new Fpdi();
        });
    }
    
  • Queue Jobs: Offload PDF generation to queues (e.g., for large reports):
    // app/Jobs/GeneratePdfJob.php
    public function handle()
    {
        $pdf = resolve(Fpdi::class);
        // ... generation logic
        Storage::put('app/generated/report.pdf', $pdf->Output('', 'S'));
    }
    

4. Hybrid Workflows (FPDI + DomPDF)

  • Use FPDI to import complex layouts, then pass to DomPDF for HTML-to-PDF conversion:
    $pdf = new Fpdi();
    $pdf->AddPage();
    $pdf->setSourceFile($templatePath);
    $tplId = $pdf->importPage(1);
    $pdf->useTemplate($tplId, 0, 0, 210);
    
    // Convert to DomPDF-compatible PDF
    $dompdf = new Dompdf();
    $dompdf->loadHtml($pdf->getHtmlContent());
    $dompdf->render();
    

5. Storing Templates in Database

  • Store PDF templates as LONGTEXT in a templates table, then stream to FPDI:
    $template = Template::find(1);
    $pdf = new Fpdi();
    $pdf->setSourceFileFromString($template->pdf_data);
    $tplId = $pdf->importPage(1);
    

Gotchas and Tips

Common Pitfalls

  1. Page Units Mismatch

    • FPDI defaults to millimeters, but source PDFs may use points (pt).
    • Fix: Convert units explicitly:
      $size = $pdf->getTemplateSize($tplId);
      $widthPt = $size['width'] * 2.83464567; // mm to pt
      $pdf->useTemplate($tplId, 10, 10, $widthPt);
      
  2. Memory Leaks with Large PDFs

    • FPDI caches imported pages. For large documents (>100MB), manually clear:
      $pdf->cleanUp();
      
  3. Font Issues

    • FPDI inherits FPDF’s font system. Ensure fonts are added before useTemplate():
      $pdf->AddFont('DejaVu', '', 'DejaVuSansCondensed.ttf');
      $pdf->SetFont('DejaVu', '', 12);
      
  4. Recursive PDFs (Malformed Structures)

    • Some PDFs (e.g., scanned docs) may cause infinite loops.
    • Fix: Use setParserMode() to skip problematic objects:
      $pdf->setParserMode(Fpdi::PARSEMODE_FULL); // Default
      // or
      $pdf->setParserMode(Fpdi::PARSEMODE_SIMPLE); // Skip complex structures
      
  5. TCPDF-Specific Quirks

    • TCPDF’s Fpdi class requires explicit namespace:
      use setasign\Fpdi\Tcpdf\Fpdi; // Not \setasign\Fpdi\TcpdfFpdi (deprecated)
      

Debugging Tips

  1. Log Parser Errors Enable debug mode to log PDF parsing issues:

    $pdf->setDebug(true);
    // Check Laravel logs for FPDI errors
    
  2. Validate Source PDFs Use PDFBox to validate templates before integration.

  3. Check Template Size Always verify dimensions with getTemplateSize():

    $size = $pdf->getTemplateSize($tplId);
    if ($size['width'] > 210) {
        throw new \Exception("Template too wide for A4!");
    }
    

Performance Optimization

  1. Reuse PDF Objects Cache imported templates in memory for batch processing:

    $templates = [];
    foreach ($orders as $order) {
        if (!isset($templates[$order->template_id])) {
            $templates[$order->template_id] = $pdf->importPage($order->template_id);
        }
        $pdf->useTemplate($templates[$order->template_id], ...);
    }
    
  2. Stream Templates For large templates, stream directly from storage:

    $pdf->setSourceFileFromStream(fopen(storage_path('templates/large.pdf'), 'r'));
    
  3. Disable Unused Features Skip unnecessary parsing (e.g., annotations) for speed:

    $pdf->setParserMode(Fpdi::PARSEMODE_SIMPLE);
    

Extension Points

  1. Custom Filters Extend FPDI’s filter system to handle proprietary PDF encodings:
    // Example: Add a custom filter for encrypted streams
    $pdf->add
    
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.
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
ecotone/kafka
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata