padam87/rasterize-bundle
A Symfony bundle for converting PDFs and other documents into images. It configures rasterizer services and backends, making it easy to generate thumbnails, previews, or page images from uploaded files with minimal setup in Symfony applications.
The first thing to internalise: this is a Symfony bundle, not a Laravel package. There is no service provider, no facade, no config/rasterize.php. It auto-configures a RasterizerInterface service through Symfony's DI container. That means you have three realistic paths into it from a Laravel codebase:
POST /rasterize, and call it over HTTP from Laravel. Most common and least painful.Whichever route you take, the actual work is done by an external binary. You need one of:
puppeteer + a small render script (or puppeteer-cli). Best fidelity, current recommendation.src/Rasterizer/ for the exact list.Minimal install:
composer require padam87/rasterize-bundle
# plus the binary, e.g. in the image:
# npm i -g puppeteer-cli (or vendor a small script)
Where to look first, in this order:
src/RasterizerInterface.php – the contract; usually one method like rasterize(string $html, string $path): void.Resources/config/ – the service definitions and tags; this tells you how to wire it without the bundle.DependencyInjection/Configuration.php – the full config tree, including per-adapter options.First use case: an invoice or end-of-month report. Render a Blade view to an HTML string, hand it to the rasterizer, write the PDF to storage/app/invoices/, return a signed URL. Render first, rasterize second — never ask the rasterizer to fetch your app's HTML over HTTP unless you control auth and timing.
Inject and call, don't instantiate. In Symfony you'd type-hint RasterizerInterface; in Laravel, bind the concrete adapter in a service provider and inject it into a small PdfGenerator service of your own:
$this->app->bind(RasterizerInterface::class, fn () => new PuppeteerRasterizer(
binary: config('services.rasterize.puppeteer_bin'),
options: config('services.rasterize.options'),
));
Wrap it — a one-method PdfGenerator interface — so you can swap backend or fake it in tests without touching call sites.
Chain / registry pattern. The bundle's value proposition is that multiple rasterizers coexist. Use it: Puppeteer for anything with JS or modern CSS, wkhtmltopdf as the fast path for simple static HTML, and a fallback in a try/catch when the primary times out. Route by job type rather than by feature flag.
Render → rasterize, with assets made absolute. This is the pattern that saves the most debugging time. Render Blade to a string, then rewrite relative asset URLs to absolute file paths or a signed HTTP URL the headless browser can actually reach. asset() output pointing at http://localhost will 404 inside the container.
Queue it. PDF generation is seconds-long and memory-hungry. Push a GenerateInvoicePdf job, write to the local/s3 disk, notify via broadcast. Keep the HTTP path synchronous only for small single-page docs.
Config layering. Keep rasterizer choice and options in config/services.php, mirroring the bundle's config tree: default backend, per-backend timeout, viewport, format, margin, waitUntil. Read the bundle's Configuration.php and copy the shape rather than inventing keys.
Testing. Write a FakeRasterizer that writes a fixture PDF and asserts on the HTML it received — that's what you actually want to regression-test (template content, not Chromium's layout engine).
PdfGenerator wrapper thin so you can replace the backend in an afternoon. Treat it as a reference implementation more than a load-bearing dependency.No usable sandbox and /dev/shm crashes. Run with --no-sandbox --disable-dev-shm-usage --disable-gpu, and give the container ≥1GB RAM. Slim images also lack fonts — install fonts-liberation or you'll get tofu boxes instead of your invoice text.DOMContentLoaded. Set waitUntil: networkidle0 (or equivalent), and for JS chart libs add an explicit wait on a selector or a data-rendered flag. This is the single most common "why is my PDF blank" cause.<base href="..."> or absolute file:// paths.storage/app/tmp and clean up in a finally.RasterizerInterface and tagging the service is the intended way to add a backend. In Laravel, that translates to a Rasterizer contract plus a driver-style resolver — mirror the bundle's naming so upstream examples stay legible.file:///etc/passwd), or you've shipped an SSRF/local-file-read gadget.How can I help you explore Laravel packages today?