Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

azc99's avatar
Level 4

render custom fonts on forge deployed app

I have an app which creates pdfs from blade files. I am refactoring a laravel 10 app that uses mPDF (working perfectly) to laravel 11 using laravel-pdf. It works correctly locally (Laravel 11 Jetstream Herd), even using tailwind for fonts in app.css and tailwind.config.js. On deployed site all renders correctly except for the fonts indicating puppeteer and chrome is working for the most part. I have been in the google world for too long that shows that puppeteer has had this issue for some time.

Using the invoice example on Spatie's laravel-pdf site to test the fonts. I have tried using styles for the fonts with the same negative result. Most of the explanations on the web are for node.js not laravel. I have followed spatie's instructions on installing puppeteer on a forge deployed server.

Hoping someone has some experience with this issue as I think laravel-pdf working with tailwind is a great solution and I would have to reluctantly go back to mPDF.

<x-guest-layout>

  @push('styles')
  <style>
    @font-face {
      font-family: "HelveticaNeueLTStd-Lt";
      src: url("https://hkorderportal.com/fonts/HelveticaNeueLTStd-Lt.woff2") format('woff2');
    }

    @font-face {
      font-family: "HelveticaNeueLTStd-MD";
      src: url("https://nethouse.cc/fonts/HelveticaNeueLTStd-Md.woff2") format('woff2');
    }

    .name-bc {
      color: #0b0b0b;
      font-family: 'CustomFont', 'HelveticaNeueLTStd-MD', 'cursive';
    }

    .title-bc {
      color: #00478F;
      font-family: 'HelveticaNeueLTStd-Lt', 'cursive';
    }
  </style>
  @endpush

  <div class="px-2 py-8 max-w-xl mx-auto">
    <div class="flex items-center justify-between mb-8">
      <div class="flex items-center">
        <div class="text-gray-700 name-bc text-xl">Your Company Name1</div>
      </div>
      <div class="text-gray-700">
        <div class="name-bc text-xl mb-2 uppercase">Invoice</div>
        <div class="text-sm title-bc">Date: 01/05/2023</div>
        <div class="text-sm title-bc">Invoice #: {{ $invoiceNumber }}</div>
      </div>
    </div>
    <div class="border-b-2 border-gray-300 pb-8 mb-8">
      <h2 class="text-2xl name-bc mb-4">Bill To:</h2>
      <div class="text-gray-700 mb-2 title-bc">{{ $customerName }}</div>
      <div class="text-gray-700 mb-2 title-bc">123 Main St.</div>
      <div class="text-gray-700 mb-2 title-bc">Anytown, USA 12345</div>
      <div class="text-gray-700 name-bc">[email protected]</div>
    </div>
    <table class="w-full text-left mb-8">
      <thead>
        <tr>
          <th class="text-gray-700 name-bc uppercase py-2">Description</th>
          <th class="text-gray-700 name-bc uppercase py-2">Quantity</th>
          <th class="text-gray-700 name-bc uppercase py-2">Price</th>
          <th class="text-gray-700 name-bc uppercase py-2">Total</th>
        </tr>
      </thead>
      <tbody class="title-bc">
        <tr>
          <td class="py-4 text-blue-500">Product 1</td>
          <td class="py-4 text-blue-500">1</td>
          <td class="py-4 text-blue-500">0.00</td>
          <td class="py-4 text-blue-500">0.00</td>
        </tr>
        <tr>
          <td class="py-4 text-blue-500">Product 2</td>
          <td class="py-4 text-blue-500">2</td>
          <td class="py-4 text-blue-500">.00</td>
          <td class="py-4 text-blue-500">0.00</td>
        </tr>
        <tr>
          <td class="py-4 text-blue-500">Product 3</td>
          <td class="py-4 text-blue-500">3</td>
          <td class="py-4 text-blue-500">.00</td>
          <td class="py-4 text-blue-500">5.00</td>
        </tr>
      </tbody>
    </table>
    <div class="flex justify-end mb-8">
      <div class="text-blue-500 title-bc mr-2">Subtotal:</div>
      <div class="text-blue-500 name-bc">5.00</div>
    </div>
    <div class="text-right mb-8">
      <div class="text-blue-500 mr-2 title-bc">Tax:</div>
      <div class="text-blue-500 name-bc">.50</div>

    </div>
    <div class="flex justify-end mb-8">
      <div class="text-gray-700 mr-2 title-bc">Total:</div>
      <div class="text-gray-700 name-bc text-xl">0.50</div>
    </div>
    <div class="border-t-2 border-gray-300 pt-8 mb-8 title-bc">
      <div class="text-gray-700 mb-2">Payment is due within 30 days. Late payments are subject to fees.</div>
      <div class="text-gray-700 mb-2">Please make checks payable to Your Company Name and mail to:</div>
      <div class="text-gray-700">123 Main St., Anytown, USA 12345</div>
    </div>
  </div>
</x-guest-layout>
<?php

namespace App\Http\Controllers;

use Spatie\LaravelPdf\Facades\Pdf;
use Spatie\Browsershot\Browsershot;
use function Spatie\LaravelPdf\Support\pdf;

class DownloadInvoiceController
{
public function __invoke()
{
    PDF::view('pdf.invoice', [
    'invoiceNumber' => '1234',
    'customerName' => 'Grumpy Cat',
    ])
      ->withBrowsershot(function (Browsershot $browsershot) {
        $browsershot->newHeadless();
        $browsershot->deviceScaleFactor(3);
      })
        ->orientation('portrait')
        ->paperSize(8.5, 11, 'in')
        ->save('test.pdf');

    return pdf('pdf.invoice', [
      'invoiceNumber' => '1234',
      'customerName' => 'Grumpy Cat',
    ]);
  }

}
0 likes
1 reply
LaryAI's avatar
LaryAI
AI
Best Answer
Level 58

It seems like the issue you're facing is related to custom fonts not being rendered correctly when deploying your Laravel application on Forge and generating PDFs using Spatie's laravel-pdf package, which internally uses Browsershot and Puppeteer.

Here are some steps you can take to ensure that custom fonts are rendered correctly in your PDFs:

  1. Ensure Fonts Are Accessible: Make sure that the URLs provided for the font files are publicly accessible and that there are no CORS issues that might prevent the fonts from being loaded by Puppeteer.

  2. Install Fonts on the Server: Since Puppeteer uses the Chrome browser to render the PDF, it will need access to the fonts installed on the system. You can install the custom fonts directly on your Forge server.

    To install custom fonts on your Forge server, you can use the following steps:

    • Connect to your server via SSH.
    • Create a directory for custom fonts if it doesn't exist:
      sudo mkdir -p /usr/share/fonts/custom
      
    • Upload your font files to this directory.
    • Update the font cache:
      sudo fc-cache -fv
      
  3. Use Absolute Paths for Fonts in CSS: When specifying the src for @font-face in your CSS, use absolute file paths instead of URLs. This ensures that Puppeteer can access the fonts without needing to make network requests.

    For example:

    @font-face {
      font-family: "HelveticaNeueLTStd-Lt";
      src: local('HelveticaNeueLTStd-Lt'), url(file:///usr/share/fonts/custom/HelveticaNeueLTStd-Lt.woff2) format('woff2');
    }
    
  4. Adjust Browsershot Settings: You may need to adjust the Browsershot settings to ensure that it waits for all resources to load before taking the screenshot (generating the PDF). You can use the waitUntil method to wait for the networkidle0 or networkidle2 event, which indicates that there are no more network connections for at least 500 ms.

    $browsershot->waitUntil('networkidle0');
    
  5. Check Permissions: Ensure that the directory where the fonts are stored and the font files themselves have the correct permissions so that the web server and Puppeteer can read them.

  6. Debugging: If the issue persists, you can try to debug by taking a screenshot of the page before generating the PDF to see if the fonts are rendered correctly in the screenshot.

    $browsershot->screenshot('debug.png');
    

Here's an updated version of your controller method with the suggested Browsershot settings:

public function __invoke()
{
    $pdf = PDF::view('pdf.invoice', [
        'invoiceNumber' => '1234',
        'customerName' => 'Grumpy Cat',
    ])
    ->withBrowsershot(function (Browsershot $browsershot) {
        $browsershot->newHeadless();
        $browsershot->deviceScaleFactor(3);
        $browsershot->waitUntil('networkidle0'); // Wait for network to be idle
    })
    ->orientation('portrait')
    ->paperSize(8.5, 11, 'in');

    // Uncomment the line below to debug by taking a screenshot
    // $browsershot->screenshot('debug.png');

    $pdf->save('test.pdf');

    return $pdf->download('invoice.pdf');
}

Remember to replace the url(file:///usr/share/fonts/custom/HelveticaNeueLTStd-Lt.woff2) with the correct path to your font file on the server.

By following these steps, you should be able to get custom fonts working in your PDFs on your Forge deployed app. If you continue to have issues, you may need to look into the server logs or Browsershot/Puppeteer logs for more detailed error information.

Please or to participate in this conversation.