Skip to content

Commit 9c478eb

Browse files
authored
Merge pull request FriendsOfCake#339 from FriendsOfCake/feature/tc-lib-pdf-engine
Add TcLibPdf engine (tc-lib-pdf), deprecate Tcpdf engine
2 parents e7569aa + 081356a commit 9c478eb

20 files changed

Lines changed: 439 additions & 4 deletions

README.md

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ Plugin containing CakePdf lib which will use a PDF engine to convert HTML to PDF
99
Engines included in the plugin:
1010
* DomPdf (^3.0)
1111
* Mpdf (^8.0.4)
12-
* Tcpdf (^6.3)
12+
* TcLibPdf (^8) - successor of the deprecated Tcpdf engine
13+
* Tcpdf (^6.3) - **deprecated**, the underlying `tecnickcom/tcpdf` package is deprecated upstream; use TcLibPdf instead
1314
* WeasyPrint (**Recommended** if you have the privileges to install something on your server)
1415
* WkHtmlToPdf (project no longer maintained but binaries still available for various environments)
1516

@@ -33,14 +34,31 @@ CakePdf does not include any of the supported PDF engines, you need to install
3334
the ones you intend to use yourself.
3435

3536
Check [WeasyPrint's](https://doc.courtbouillon.org/weasyprint/stable/first_steps.html#installation) installation guide to install it on your system.
36-
DomPdf, Mpdf and Tcpdf can be installed via composer using one of the following commands:
37+
DomPdf, Mpdf, TcLibPdf and Tcpdf can be installed via composer using one of the following commands:
3738

3839
```
3940
composer require dompdf/dompdf
41+
composer require tecnickcom/tc-lib-pdf
4042
composer require tecnickcom/tcpdf
4143
composer require mpdf/mpdf
4244
```
4345

46+
### TcLibPdf font setup
47+
48+
Unlike the deprecated Tcpdf engine, `tecnickcom/tc-lib-pdf` does not bundle any
49+
fonts. It loads fonts from generated `*.json` font files located in a directory
50+
referenced by the `K_PATH_FONTS` constant. Define it once during your
51+
application bootstrap, before any PDF is rendered:
52+
53+
```php
54+
define('K_PATH_FONTS', '/absolute/path/to/your/fonts');
55+
```
56+
57+
The directory must contain at least the core fonts you reference (e.g.
58+
`helvetica.json`). See the
59+
[tc-lib-pdf-font](https://github.com/tecnickcom/tc-lib-pdf-font) documentation
60+
for how to generate font files.
61+
4462
## Setup
4563

4664
Loading the plugin using CakePHP's console:
@@ -81,6 +99,7 @@ Configuration options:
8199
* `TexToPdfEngine`: The options are passed as CLI arguments
82100
* `DomPdfEngine`: The options are passed to constructor of `Dompdf` class
83101
* `MpdfEngine`: The options are passed to constructor of `Mpdf` class
102+
* `TcLibPdfEngine`: Supports `unit`, `unicode`, `subsetFont`, `compress`, `mode`, `font` (`['family', 'style', 'size']`), `margins` (`['left', 'top', 'right', 'bottom']`) and `metadata` (`['author', 'creator', 'subject', 'keywords']`)
84103
* crypto: Crypto engine to be used, or an array of crypto config options
85104
* className: Crypto class to use
86105
* binary: Binary file to use

composer.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@
1313
"dompdf/dompdf": "^3.0",
1414
"mpdf/mpdf": "^8.1.6",
1515
"tecnickcom/tcpdf": "^6.3",
16-
"cakephp/cakephp-codesniffer": "^5.3"
16+
"cakephp/cakephp-codesniffer": "^5.3",
17+
"tecnickcom/tc-lib-pdf": "^8.5"
1718
},
1819
"suggest": {
1920
"dompdf/dompdf": "If you wish to use the DomPdf engine",
20-
"tecnickcom/tcpdf": "If you wish to use the Tcpdf engine",
21+
"tecnickcom/tcpdf": "If you wish to use the Tcpdf engine (deprecated, use tc-lib-pdf instead)",
22+
"tecnickcom/tc-lib-pdf": "If you wish to use the TcLibPdf engine (successor of the deprecated tcpdf)",
2123
"mpdf/mpdf": "If you wish to use the Mpdf engine"
2224
},
2325
"autoload": {

src/Pdf/Engine/TcLibPdfEngine.php

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace CakePdf\Pdf\Engine;
5+
6+
use Com\Tecnick\Pdf\Tcpdf;
7+
8+
/**
9+
* Engine for the actively maintained `tecnickcom/tc-lib-pdf` library, the
10+
* successor of the now deprecated `tecnickcom/tcpdf` package used by
11+
* {@see \CakePdf\Pdf\Engine\TcpdfEngine}.
12+
*
13+
* Unlike the old TCPDF engine, tc-lib-pdf ships no fonts. The standard PDF
14+
* core fonts (Helvetica, Times, Courier, Symbol, ZapfDingbats) and any custom
15+
* font must be available as generated `*.json` font files in a directory
16+
* pointed to by the `K_PATH_FONTS` constant. Define it once during bootstrap:
17+
*
18+
* ```php
19+
* define('K_PATH_FONTS', '/path/to/generated/fonts');
20+
* ```
21+
*
22+
* See the tc-lib-pdf-font documentation for how to generate font files.
23+
*
24+
* Engine specific options are read from the `options` config key:
25+
*
26+
* - `unit`: Document unit of measure. Defaults to `mm`.
27+
* - `unicode`: Whether the document is in Unicode mode. Defaults to `true`.
28+
* - `subsetFont`: Whether to subset embedded fonts. Defaults to `false`.
29+
* - `compress`: Whether to compress the PDF output. Defaults to `true`.
30+
* - `mode`: PDF conformance mode (e.g. `pdfa2b`, `pdfx4`). Defaults to `''`.
31+
* - `font`: Default font as `['family' => ..., 'style' => ..., 'size' => ...]`.
32+
* - `margins`: Fallback page margins in document units as
33+
* `['left' => ..., 'top' => ..., 'right' => ..., 'bottom' => ...]`. The
34+
* standard CakePdf `margin` setting takes precedence when set.
35+
* - `metadata`: Document metadata as
36+
* `['author' => ..., 'creator' => ..., 'subject' => ..., 'keywords' => ...]`.
37+
*/
38+
class TcLibPdfEngine extends AbstractPdfEngine
39+
{
40+
/**
41+
* @var array<string, mixed>
42+
*/
43+
protected array $_defaultConfig = [
44+
'options' => [
45+
'unit' => 'mm',
46+
'unicode' => true,
47+
'subsetFont' => false,
48+
'compress' => true,
49+
'mode' => '',
50+
'font' => [
51+
'family' => 'helvetica',
52+
'style' => '',
53+
'size' => 12,
54+
],
55+
'margins' => [
56+
'left' => 15,
57+
'top' => 15,
58+
'right' => 15,
59+
'bottom' => 15,
60+
],
61+
'metadata' => [],
62+
],
63+
];
64+
65+
/**
66+
* Generates Pdf from html
67+
*
68+
* @return string raw pdf data
69+
*/
70+
public function output(): string
71+
{
72+
$tcpdf = $this->_createInstance();
73+
74+
$this->_applyMetadata($tcpdf);
75+
$tcpdf->enableDefaultPageContent();
76+
77+
$font = (array)$this->getConfig('options.font');
78+
$defaultFont = $tcpdf->font->insert(
79+
$tcpdf->pon,
80+
(string)($font['family'] ?? 'helvetica'),
81+
(string)($font['style'] ?? ''),
82+
(int)($font['size'] ?? 12),
83+
);
84+
85+
$tcpdf->addPage($this->_pageOptions());
86+
$tcpdf->page->addContent($defaultFont['out']);
87+
88+
$region = $tcpdf->page->getRegion();
89+
$tcpdf->addHTMLCell(
90+
html: $this->_Pdf->html(),
91+
posx: (float)$region['RX'],
92+
posy: (float)$region['RY'],
93+
width: (float)$region['RW'],
94+
);
95+
96+
return $tcpdf->getOutPDFString();
97+
}
98+
99+
/**
100+
* Creates the tc-lib-pdf instance.
101+
*
102+
* @return \Com\Tecnick\Pdf\Tcpdf
103+
*/
104+
protected function _createInstance(): Tcpdf
105+
{
106+
return new Tcpdf(
107+
unit: (string)$this->getConfig('options.unit'),
108+
isunicode: (bool)$this->getConfig('options.unicode'),
109+
subsetfont: (bool)$this->getConfig('options.subsetFont'),
110+
compress: (bool)$this->getConfig('options.compress'),
111+
mode: (string)$this->getConfig('options.mode'),
112+
);
113+
}
114+
115+
/**
116+
* Builds the page options array from the CakePdf instance and engine config.
117+
*
118+
* The standard CakePdf `margin` setting takes precedence; the engine
119+
* `options.margins` config is used as a fallback for any unset side.
120+
*
121+
* @return array<string, mixed>
122+
*/
123+
protected function _pageOptions(): array
124+
{
125+
$orientation = $this->_Pdf->orientation() === 'landscape' ? 'L' : 'P';
126+
127+
$fallback = (array)$this->getConfig('options.margins');
128+
$margin = (array)$this->_Pdf->margin();
129+
$left = (float)($margin['left'] ?? $fallback['left'] ?? 0);
130+
$top = (float)($margin['top'] ?? $fallback['top'] ?? 0);
131+
$right = (float)($margin['right'] ?? $fallback['right'] ?? 0);
132+
$bottom = (float)($margin['bottom'] ?? $fallback['bottom'] ?? 0);
133+
134+
return [
135+
'format' => $this->_Pdf->pageSize(),
136+
'orientation' => $orientation,
137+
'margin' => [
138+
'PL' => $left,
139+
'PR' => $right,
140+
'PT' => $top,
141+
'PB' => $bottom,
142+
'CT' => $top,
143+
'CB' => $bottom,
144+
],
145+
];
146+
}
147+
148+
/**
149+
* Applies document metadata to the tc-lib-pdf instance.
150+
*
151+
* @param \Com\Tecnick\Pdf\Tcpdf $tcpdf The tc-lib-pdf instance.
152+
* @return void
153+
*/
154+
protected function _applyMetadata(Tcpdf $tcpdf): void
155+
{
156+
$title = $this->_Pdf->title();
157+
if ($title !== null && $title !== '') {
158+
$tcpdf->setTitle($title);
159+
}
160+
161+
$metadata = (array)$this->getConfig('options.metadata');
162+
if (isset($metadata['author'])) {
163+
$tcpdf->setAuthor((string)$metadata['author']);
164+
}
165+
if (isset($metadata['creator'])) {
166+
$tcpdf->setCreator((string)$metadata['creator']);
167+
}
168+
if (isset($metadata['subject'])) {
169+
$tcpdf->setSubject((string)$metadata['subject']);
170+
}
171+
if (isset($metadata['keywords'])) {
172+
$tcpdf->setKeywords((string)$metadata['keywords']);
173+
}
174+
}
175+
}

src/Pdf/Engine/TcpdfEngine.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55

66
use TCPDF;
77

8+
/**
9+
* @deprecated 5.3.0 The underlying `tecnickcom/tcpdf` package is deprecated upstream.
10+
* Use {@see \CakePdf\Pdf\Engine\TcLibPdfEngine} (backed by `tecnickcom/tc-lib-pdf`) instead.
11+
*/
812
class TcpdfEngine extends AbstractPdfEngine
913
{
1014
/**

0 commit comments

Comments
 (0)