This package is a Laravel wrapper for PDFlib. It makes generating high professional (Print-)PDFs with PDFlib a breeze. PDFlib is the leading developer toolbox for generating and manipulating files in the Portable Document Format (PDF).
PDFlib itself is only free to use for demonstration purposes. If you want to bring it into production, you need a PDFlib license.
Since PDFlib is much more powerful than any other PDF generator, it's PHP extension needs to be registered. You can download the extension file directly from the PDFlib download page.
If you need further assistance installing PDFlib, check out the installation guide.
You also need:
- PHP:
^8.0
- Laravel:
^9.0
Please note that only supported Laravel versions are covered by test workflow!
Require this package with composer.
composer require contoweb/laravel-pdflib
All basic configuration is done in the pdf.php
configuration file.
To publish the config, run the vendor publish command:
php artisan vendor:publish --provider="Contoweb\Pdflib\PdflibServiceProvider"
You can then configure paths, measure unit and so on...
Laravel 5.5 uses Package Auto-Discovery, so doesn't require you to manually add the ServiceProvider. If you don't use auto-discovery, add the ServiceProvider to the providers array in config/app.php. Since Laravel 11, the file for providers has changed to bootstrap/providers.php.
Contoweb\Pdflib\PdflibServiceProvider::class,
If you want to use the PDF facade, add this to your facades in app.php:
'Pdf' => Contoweb\Pdflib\Facades\Pdf::class,
To create a new document, you can use the make:document
command:
php artisan make:document MarketingDocument
The new document file can be found in the app/Documents
directory.
app\Documents\MarketingDocument
Ìn a final step, generating a PDF is as easy as:
use App\Documents\MarketingDocument;
use Contoweb\Pdflib\Facades\Pdf;
use App\Http\Controllers\Controller;
class MarketingController extends Controller
{
public function storeDocument()
{
return Pdf::store(new MarketingDocument, 'marketing.pdf');
}
}
You can find your document in your configured export path then! But first, let us take a look how to write a simple PDF.
Within your document file, you have a boilerplated method draw()
:
public function draw(Writer $writer)
{
$writer->newPage();
$writer->useFont('Arial', 12);
$writer->writeText('Start something great...');
}
Here you actually write the document's content. As you can see, a small example is already boilerplated:
- Create a new page in the document.
- Use an available font from the
fonts()
method. - Write the text.
To create a new page, you can use
$writer->newPage();
You can optionally define the width and height of your document by passing the parameters.
$writer->newPage(210, 297); // A4 portrait format
In most cases, you want to write dynamic content on a already designed PDF.
To use a PDF template, use the FromTemplate
concern and define the template PDF in a new template()
function:
namespace App\Documents;
use Contoweb\Pdflib\Concerns\FromTemplate;
use Contoweb\Pdflib\Concerns\WithDraw;
use Contoweb\Pdflib\Writers\PdfWriter as Writer;
class MarketingDocument implements FromTemplate, WithDraw
{
public function template(): string {
return 'template.pdf';
}
// ...
public function draw(Writer $writer)
{
$writer->newPage()->fromTemplatePage(1);
}
}
Now, your first page is using the page 1 from template.pdf
.
As you can see, you don't need to define a page size since it's using the template's size.
Don't forget to configure your templates location in the configuration file.
If you're aware of (professional) print-ready PDFs, you may know that your print PDF isn't the same as the user finally sees.
There is a bleed box, crop marks and so on. For this case, you can use WithPreview
combined with the FromTemplate
concern.
While your original template includes all the boxes and marks, your preview PDF is a preview of the final document.
This requires you to add a previewTemplate()
and offset()
method.
namespace App\Documents;
use Contoweb\Pdflib\Concerns\FromTemplate;
use Contoweb\Pdflib\Concerns\WithDraw;
use Contoweb\Pdflib\Concerns\WithPreview;
use Contoweb\Pdflib\Writers\PdfWriter as Writer;
class MarketingDocument implements FromTemplate, WithDraw, WithPreview
{
public function template(): string {
return 'print.pdf';
}
public function previewTemplate(): string
{
return 'preview.pdf';
}
public function offset(): array
{
return [
'x' => 20,
'y' => 20,
];
}
//
}
The offset()
method defines the offset from the print PDF to the preview PDF (see image above).
Now you can generate the preview PDF with:
return Pdf::inPreviewMode()->store(new MarketingDocument, 'marketing.pdf');
You can also generate the print and preview PDF in one step:
return Pdf::store(new MarketingDocument, 'marketing.pdf')->withPreview();
The preview PDF will be automatically named to <<name>>_preview.pdf
.
You can override this by passing the name in ->withPreview('othername.pdf')
.
To tell PDFlib where your elements should be placed, you have to set the X
and Y
position of your "cursor".
$writer->setPosition(10, 100);
// only X axis
$writer->setXPosition(10);
//only Y axis
$writer->setYPosition(100);
In the configuration file, you can define which measure unit is used for positioning. You can choose between mm
or pt
.
Note: It may be confusing in the beginning, but PDFlib Y axis are measured from the bottom. So position 0 0 is in the left bottom corner, not the left top corner.
To write text, you can simply use:
$writer->writeTextLine('your text');
// or
$writer->writeText('your text');
Don't forget to set the cursor position and use the right font before writing text. Since the package extends PDFlib, you also can pass PDFlib options as a second parameter.
You only have to use
writeText
when placing two text blocks next to each other. Behind the scenes,wirteText()
uses PDFlibsshow()
method, whilewirteTextLine()
uses the mostly used PDFlib methodfit_text_line()
.
If you want to go to the next line, instead of reposition your cursor every time, you can use:
$writer->nextLine();
To use a custom line spacing instead of 1.0, just pass it as a parameter or set the line spacing with:
$writer->setLineSpacing(2.0);
The boilerplate document loads Arial
as an example font, but we don't provide a font file in the fonts folder.
In this case, PDFlib tries to load it from your host fonts.
You may want to use custom fonts and want ensure that your server is able to load it.
So it's highly recommended to place the font files (currently .ttf and .otf is supported) inside your configured font location (see pdf.php
configuration).
As a next step, you have to make the fonts available in your document. For TrueType fonts, just use the file name without the extension to auto-load the font:
public function fonts(): array
{
return ['OpenSans-Regular'];
}
An underlying font file like OpenSans-Regular.ttf
has to be available in your fonts location.
Now you can use the font in your document by it's name:
public function draw(Writer $writer)
{
$writer->newPage();
$writer->useFont('OpenSans-Regular', 12)
->writeText('This text is written with Open Sans font...');
}
You can also overwrite default font encoding and option list:
public function fonts(): array
{
return [
'OpenSans-Regular' => [
'encoding' => 'ansi',
'optlist' => ''
],
];
}
If you need to colorize your text, you can use the WithColor
concern. This requires you to define custom colors:
public function colors(): array
{
return [
'orange-rgb' => ['rgb', 255, 165, 0],
'blue-cmyk' => ['cmyk', 100, 100, 0, 0],
];
}
You can use the color with:
$writer->useColor('orange-rgb');
or as a parameter when using a font:
$writer->useFont('OpenSans-Regular', 12, 'blue-cmyk');
To write a table you can follow this example:
$items = [
['first_name' => 'John', 'last_name' => 'Doe'],
['first_name' => 'Jane','last_name' => 'Doe'],
];
$table = $writer
->setPosition(10, 150)
->newTable($items);
$table
->addColumn(50)
->addColumn(50)
->withHeader(['First name', 'Last name'])
->place("stroke={ {line=horother linewidth=0}}")
;
You can place images with:
$writer->drawImage('/path/to/the/image.jpeg', 150, 100);
This places an image with and resize it to 150x100.
Since loading rounded images is just a pain in PDFlib, you can use the method:
$writer->circleImage('/path/to/the/image.jpeg', 100);
Since this package extending PDFlib, you can use the whole PDFlib toolkit. The PDFlib Cookbook helps a lot, even to understand this package.
This package is just a basic beginning of wrapping PDFlib. Since PDFlib brings so much more functionality, we have to put the focus on the most used functions in the beginning.
You're welcome to PR your ideas!
If you want to use a filesystem disk / path other than the config in a specific document, you can use the following concerns:
Contoweb\Pdflib\Concerns\DifferentExportLocation
: Custom export locationContoweb\Pdflib\Concerns\DifferentFontsLocation
: Custom location for fontsContoweb\Pdflib\Concerns\DifferentTemplateLocation
: Custom template location
The storage and path are defined the same way as in the config file:
public function exportLocation(): array
{
return [
'disk' => 'other',
'path' => null,
];
}
public function fontsLocation(): array
{
return [
'disk' => 'other',
'path' => 'custom-font-directory',
];
}
public function templateLocation(): array
{
return [
'disk' => 'other',
'path' => 'custom-template-directory',
];
}
The MIT License (MIT). Please see License File for more information.