PHPackages                             savagescape/pdf - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [PDF &amp; Document Generation](/categories/documents)
4. /
5. savagescape/pdf

ActiveLibrary[PDF &amp; Document Generation](/categories/documents)

savagescape/pdf
===============

v0.9.5(1y ago)011MITPHPPHP ^8.2

Since Nov 23Pushed 1y ago2 watchersCompare

[ Source](https://github.com/savagescape/laravel-pdf)[ Packagist](https://packagist.org/packages/savagescape/pdf)[ RSS](/packages/savagescape-pdf/feed)WikiDiscussions master Synced 3w ago

READMEChangelogDependencies (7)Versions (7)Used By (0)

Savagescape\\Pdf
================

[](#savagescapepdf)

Render PDFs from HTML using a headless instance of Chromium via [gotenberg.dev](https://gotenberg.dev/)

See also:

- GitHub Repo:
- Docker Container:

---

Configuration
-------------

[](#configuration)

### Example Docker Compose service

[](#example-docker-compose-service)

```
  gotenberg:
    image: gotenberg/gotenberg:8
    restart: unless-stopped
```

### Configuring Laravel

[](#configuring-laravel)

1. Add a new service to `config/services.php` called `gotenberg` with a `url`: ```
    'gotenberg' => [
        'url' => env('GOTENBERG_URL', 'http://gotenberg:3000'),
    ],
    ```
2. Optional, set `GOTENBERG_URL` in .env to point to the correct container name.
3. It should be automatically discovered, but if not, add the service provider to Laravel's app configuration `bootstrap/app.php`: ```
    ->withProviders([
        Savagescape\Pdf\ServiceProvider::class,
    ])
    ```

---

Usage
-----

[](#usage)

You can either create a new `Savagescape\Pdf\Pdf` instance via the Factory or through the Facade.

### Factory

[](#factory)

```
use Savagescape\Pdf\Factory as PdfFactory;

class MyController
{
    // Let the router autowire the factory for you
    public function myRoute(PdfFactory $pdfFactory)
    {
        // or pull it directly from the container
        // $pdfFactory = app(PdfFactory::class);

        // From a string of HTML
        $pdf = $pdfFactory->fromHtml('Hello world');

        // or from a raw file
        $pdf = $pdfFactory->fromFile(resource_path('hello-world.html'));

        // or from a Blade view
        $pdf = $pdfFactory->fromView('hello-world', ['name' => 'Bob']);
    }
}
```

### Facade

[](#facade)

```
use Savagescape\Pdf\Facades\Pdf;

// From a string of HTML
$pdf = Pdf::fromHtml('Hello world');

// or from a raw file
$pdf = Pdf::fromFile(resource_path('hello-world.html'));

// or from a Blade view
$pdf = Pdf::fromView('hello-world', ['name' => 'Bob']);
```

Advanaced usage
---------------

[](#advanaced-usage)

### Setting render options

[](#setting-render-options)

To configure how Gotenberg renders the HTML into a PDF, you can configure any of the form field options inside of the `options()` callback.

Some shorthand syntax is included, for example `margins($top, $right, $bottom, $left)

See:

```
use Savagescape\Pdf\Facades\Pdf;
use Savagescape\Pdf\Options;

$pdf = Pdf::fromHtml('Hello world')
    ->options(function (Options $options) {
        // $options is a Fluent object mapping to Gotenberg options

        // sets "landscape" to "true"
        $options->landscape();

        // sets "printBackground" to "false"
        $options->printBackground(false);

        // sets "marginTop" to "1"
        $options->marginTop(1);

        // and you can chain them
        // sets "marginLeft" to "2" and "marginRight" to "3"
        $options->marginLeft(2)->marginRight(3);

        // Clear "marginBottom"
        $options->marginBottom(null);
    });
```

### Including other files

[](#including-other-files)

The HTML/file/view you start from is automatically mapped to `index.html`. To attach additional resources (like CSS, images, etc) you must pass them along to Gotenberg as well.

You can only add one file per-filename, trying to replace an already attached file will throw an exception.

You should reference any attached files using relative paths, eg: use `` instead of ``

Three filenames are reserved for special use by Gotenberg:

- `index.html` For the actual contents of your PDF (this is already handled for you.)
- `header.html` To render a header at the top of every page.
- `footer.html` To render a footer at the bottom of every page.

See:

Note

Attached files need to be transfered to the Gotenberg container along side your HTML. The larger the files you attach, the longer this will take.

```
use Savagescape\Pdf\Facades\Pdf;
use Savagescape\Pdf\Files;

// To simply attach an existing file, you can use ->attach()
// Also note that the filename you pass along doesn't necessarily
// have to match whats on disk
$pdf = Pdf::fromHtml('Hello world')
    ->attach('style.css', resource_path('path/to/my/custom.css'));

// To attach a file from a stream or a string you can interact with the Files object directly
$pdf = Pdf::fromHtml('Hello world')
    ->files(function (Files $files) {
        // Simply pass a string
        $files->addString('style.css', 'h1 { color: red; }');
        // Or a resource from fopen() or a stream from StreamInterface
        $files->addStream('logo.png', fopen(public_path('images/logo.png'), 'r'));
        // Or a file on disk (this is equivalent to using ->attach())
        $files->addFile('style.css', public_path('path/to/my/custom.css')));
    });
```

Rendering
---------

[](#rendering)

Now you've built your PDF you can either save it to your local disk, display it inline in the browser, trigger a download from the browser or use the stream as you wish.

The `Pdf` object also implements `Responsable` which will default to streaming the PDF as an inline attachment with the filename `download.pdf`.

Caution

Every time you call one of these methods, the PDF will be re-rendered! The result of the last stream **is not re-used**. This can be potentially expensive depending on how complex your HTML, styling and how large your attached files are.

```
use Savagescape\Pdf\Facades\Pdf;

$pdf = Pdf::fromHtml('Hello world');

// Store the PDF to disk
$pdf->store(storage_path('public/test.pdf'));

// Or, start a HTTP download
return $pdf->download('my-pdf-download.pdf');

// Or, display the PDF inline
return $pdf->inline('my-inline-pdf.pdf');

// Or, use the stream directly as you wish
$stream = $pdf->stream();

// Or, simply the return the Pdf object
// this is equivalent to $pdf->inline('download.pdf');
return $pdf;
```

---

In-depth Examples
-----------------

[](#in-depth-examples)

```
use Savagescape\Pdf\Facades\Pdf;
use Savagescape\Pdf\Factory;
use Savagescape\Pdf\Options;
use Savagescape\Pdf\Files;

class MyController
{
    // Using the facade to load a plain HTML string
    // Set Landscape orientation
    // Set 50px margins
    // Use the "screen" media type
    // Attaching:
    // - storage/signatures/bob.jpg as signature.jpg
    // - public/images/logo.png as logo.png
    // - a inline string as style.css
    // - resources/pdf/footer.html as footer.html
    // Trigger a download with the default filename "your-contract.pdf"
    public function example1(Request $request)
    {
        $html = margins('50px');
                $options->emulatedMediaType('screen');
            })
            ->attach('signature.jpg', storage_path('signatures/bob.jpg'))
            ->files(function (Files $files) {
                $files->addFile('logo.png', public_path('images/logo.png'))
                $files->addString('style.css', '.something-important { color: red; }');
                $files->addStream('footer.html', fopen(resource_path('pdf/footer.html')));
            })
            ->download('your-contract.pdf');
    }

    // Using the factory directly, load a Blade template
    // include '$car' data in the Blade template
    // Attach several images from relations against the model into the PDF
    // Automatically generate a document outline
    // Include CSS background graphics
    // Save the pdf into the storage path
    public function example2(Factory $pdfFactory, Car $car)
    {
        $pdf = $pdfFactory->fromView('example', ['car' => $car]);

        $pdf->attach('manufacturer_logo.png', storage_path($car->manufacturer->logo->storage_filename));
        foreach ($car->photos as $photo) {
            $pdf->attach($photo->filename, storage_path($photo->storage_filename));
        }

        $pdf->options(
            fn (Options $options) => $options->generateDocumentOutline()->printBackground()
        );

        $pdf->save(storage_path("brochure/car-{$myModel->id}.pdf"));
    }
}
```

###  Health Score

26

—

LowBetter than 41% of packages

Maintenance37

Infrequent updates — may be unmaintained

Popularity5

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity46

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~1 days

Total

6

Last Release

571d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/0100f39d02b5bb8546960af30a9b28f2157b9e6f913cefd9d0d87872b854384f?d=identicon)[savagescape](/maintainers/savagescape)

---

Top Contributors

[![philo23](https://avatars.githubusercontent.com/u/171550?v=4)](https://github.com/philo23 "philo23 (12 commits)")

###  Code Quality

TestsPHPUnit

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/savagescape-pdf/health.svg)

```
[![Health](https://phpackages.com/badges/savagescape-pdf/health.svg)](https://phpackages.com/packages/savagescape-pdf)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3345.1M337](/packages/psalm-plugin-laravel)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9742.3M121](/packages/roots-acorn)[yajra/laravel-datatables-oracle

jQuery DataTables API for Laravel

4.9k35.3M364](/packages/yajra-laravel-datatables-oracle)[pressbooks/pressbooks

Pressbooks is an open source book publishing tool built on a WordPress multisite platform. Pressbooks outputs books in multiple formats, including PDF, EPUB, web, and a variety of XML flavours, using a theming/templating system, driven by CSS.

45344.0k1](/packages/pressbooks-pressbooks)[moonshine/moonshine

Laravel administration panel

1.3k239.9k75](/packages/moonshine-moonshine)[laravel/folio

Page based routing for Laravel.

603526.4k31](/packages/laravel-folio)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
