]>
git.agnieray.net Git - galette.git/blob - galette/lib/Galette/IO/Pdf.php
4 * Copyright © 2003-2024 The Galette Team
6 * This file is part of Galette (https://galette.eu).
8 * Galette is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
13 * Galette is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with Galette. If not, see <http://www.gnu.org/licenses/>.
24 use Galette\Core\I18n
;
25 use Galette\Core\Preferences
;
26 use Galette\Entity\PdfModel
;
28 use Slim\Routing\RouteParser
;
32 * TCPDF configuration file for Galette
34 require_once GALETTE_CONFIG_PATH
. 'galette_tcpdf_config.php';
37 * PDF class for galette
39 * @author John Perr <johnperr@abul.org>
40 * @author Johan Cwiklinski <johan@x-tnd.be>
43 class Pdf
extends TCPDF
45 public const FONT
= 'DejaVuSans';
46 public const FONT_SIZE
= 10;
48 protected Preferences
$preferences;
50 private PdfModel
$model;
51 private bool $paginated = false;
52 protected string $filename;
53 private bool $has_footer = true;
54 protected float $footer_height;
57 * Main constructor, set creator and author
59 * @param Preferences $prefs Preferences
60 * @param ?PdfModel $model Related model
62 public function __construct(Preferences
$prefs, ?PdfModel
$model = null)
66 $this->preferences
= $prefs;
68 parent
::__construct('P', 'mm', 'A4', true, 'UTF-8');
70 $this->SetCreator(PDF_CREATOR
);
71 //add helvetica, hard-called from lib
72 $this->SetFont('helvetica');
73 //and then, set real font
74 $this->SetFont(self
::FONT
, '', self
::FONT_SIZE
);
77 $this->preferences
->pref_nom
,
81 $name . ' (using Galette ' . GALETTE_VERSION
. ')'
84 if ($this->i18n
->isRTL()) {
88 if ($model !== null) {
89 $this->model
= $model;
90 $this->SetTitle($this->model
->htitle
);
94 if ($this->has_footer
) {
95 $this->calculateFooterHeight();
104 public function init(): void
115 protected function setNoHeader(): void
117 $this->SetPrintHeader(false);
118 $this->setHeaderMargin(0);
126 protected function setNoFooter(): void
128 $this->SetPrintFooter(false);
129 $this->setFooterMargin(0);
130 $this->has_footer
= false;
134 * Calculate footer height
138 private function calculateFooterHeight(): void
141 $y_orig = $pdf->getY();
143 $y_end = $pdf->getY();
144 $this->footer_height
= $y_end - $y_orig;
148 * Set show pagination
152 public function showPagination(): void
154 $this->paginated
= true;
160 public function __destruct()
162 parent
::__destruct();
166 * This method is automatically called in case of fatal error;
167 * it simply outputs the message and halts the execution.
168 * An inherited class may override it to customize the error
169 * handling but should always halt the script, or the resulting
170 * document would probably be invalid.
171 * 2004-06-11 :: Nicola Asuni : changed bold tag with strong
172 * 2007-07-21 :: John Perr : changed function to return error to session
173 * 2017-02-14 :: Johan Cwiklinski : use slim's flash message; do not rely on session for redirect
175 * @param string $msg The error message
181 public function Error(mixed $msg): void
// phpcs:ignore PSR1.Methods.CamelCapsMethodName
186 'PDF error: ' . $msg,
190 $container->get('flash')->addMessage(
195 $redirect = (isset($_SERVER['HTTP_REFERER']) ?
196 $_SERVER['HTTP_REFERER'] : $container->get(RouteParser
::class)->urlFor('slash'));
197 header('Location: ' . $redirect);
202 * Converts color from HTML format #RRVVBB
203 * to RGB 3 colors array.
205 * @param string $hex6 7 chars string #RRVVBB
207 * @return array<string,float|int>
209 public function colorHex2Dec(string $hex6): array
212 "R" => hexdec(substr($hex6, 1, 2)),
213 "G" => hexdec(substr($hex6, 3, 2)),
214 "B" => hexdec(substr($hex6, 5, 2))
220 * Draws PDF page Header
224 public function Header(): void
// phpcs:ignore PSR1.Methods.CamelCapsMethodName
226 //just override default header to prevent black line at top
230 * Draws PDF page footer
232 * @param ?TCPDF $pdf PDF instance
236 public function Footer(TCPDF
$pdf = null): void
// phpcs:ignore PSR1.Methods.CamelCapsMethodName
240 $pdf->SetY(-($this->footer_height +
15));
242 if (isset($this->model
)) {
244 if (trim($this->model
->hstyles
) !== '') {
245 $hfooter .= "<style>\n" . $this->model
->hstyles
. "\n</style>\n\n";
247 $hfooter .= $this->model
->hfooter
;
248 $pdf->writeHtml($hfooter);
250 $address = $this->preferences
->getPostalAddress();
251 $hfooter = '<style>div#pdf_footer {text-align: center;font-size: 0.7em;}</style>';
252 $hfooter .= '<div id="pdf_footer">' . nl2br($address) . '</div>';
253 $pdf->writeHTML($hfooter);
256 if ($this->paginated
) {
257 $pdf->SetFont(self
::FONT
, '', self
::FONT_SIZE
- 3);
262 $this->getAliasRightShift() . $this->PageNo() .
263 '/' . $this->getAliasNbPages(),
266 ($this->i18n
->isRTL() ?
'L' : 'R')
272 * Draws PDF page header
274 * @param ?string $title Additional title to display just after logo
278 public function PageHeader(string $title = null): void
// phpcs:ignore PSR1.Methods.CamelCapsMethodName
280 if (isset($this->model
)) {
281 $this->modelPageHeader($title);
283 $this->standardPageHeader($title);
288 * Draws models PDF page header
290 * @param ?string $title Additional title to display just after logo
294 protected function modelPageHeader(string $title = null): void
297 if (trim($this->model
->hstyles
) !== '') {
298 $html .= "<style>\n" . $this->model
->hstyles
. "\n</style>\n\n";
300 $html .= "<div dir=\"" . ($this->i18n
->isRTL() ?
'rtl' : 'ltr') . "\">" . $this->model
->hheader
. "</div>";
301 $this->writeHtml($html, true, false, true, false, '');
303 if ($title !== null) {
304 $this->writeHtml('<h2 style="text-align:center;">' . $title . '</h2>');
307 if (trim($this->model
->title
) !== '') {
309 if (trim($this->model
->hstyles
) !== '') {
310 $htitle .= "<style>\n" . $this->model
->hstyles
.
313 $htitle .= '<div id="pdf_title">' . $this->model
->htitle
. '</div>';
314 $this->writeHtml($htitle);
316 if (trim($this->model
->subtitle
) !== '') {
318 if (trim($this->model
->hstyles
) !== '') {
319 $hsubtitle .= "<style>\n" . $this->model
->hstyles
.
322 $hsubtitle .= '<div id="pdf_subtitle">' . $this->model
->hsubtitle
.
324 $this->writeHtml($hsubtitle);
327 trim($this->model
->title
) !== ''
328 ||
trim($this->model
->subtitle
) !== ''
335 * Draws standard PDF page header
337 * @param ?string $title Additional title to display just after logo
341 protected function standardPageHeader(string $title = null): void
344 $print_logo = new \Galette\Core\
PrintLogo();
345 $logofile = $print_logo->getPath();
347 // Set logo size to max width 30 mm or max height 25 mm
348 $ratio = $print_logo->getWidth() / $print_logo->getHeight();
350 if ($print_logo->getHeight() > 16) {
353 $hlogo = $print_logo->getHeight();
355 $wlogo = round($hlogo * $ratio);
357 if ($print_logo->getWidth() > 16) {
360 $wlogo = $print_logo->getWidth();
362 $hlogo = round($wlogo / $ratio);
365 $this->SetFont(self
::FONT
, 'B', self
::FONT_SIZE +
4);
366 $this->SetTextColor(0, 0, 0);
370 $ystart = $this->GetY();
375 $this->preferences
->pref_nom
,
377 ($this->i18n
->isRTL() ?
'R' : 'L')
379 $this->SetFont(self
::FONT
, 'B', self
::FONT_SIZE +
2);
381 if ($title !== null) {
382 $this->Cell(0, 6, $title, 0, 1, ($this->i18n
->isRTL() ?
'R' : 'L'), false);
384 $yend = $this->getY(); //store position at the end of the text
386 $this->SetY($ystart);
387 if ($this->i18n
->isRTL()) {
390 $x = 190 - $wlogo; //right align
392 $this->Image($logofile, $x, $this->GetY(), $wlogo, $hlogo);
393 $this->y +
= $hlogo +
3;
394 //if position after logo is < than position after text,
395 //we have to change y
396 if ($this->getY() < $yend) {
402 * Draws body from model
406 public function PageBody(): void
// phpcs:ignore PSR1.Methods.CamelCapsMethodName
409 if (trim($this->model
->hstyles
) !== '') {
410 $hbody .= "<style>\n" . $this->model
->hstyles
. "\n</style>\n\n";
412 $hbody .= $this->model
->hbody
;
413 $this->writeHtml($hbody);
419 * @param string $text Text content
420 * @param integer $maxsize Maximal size
421 * @param integer $fontsize Font size
422 * @param string $fontstyle Font style (defaults to '')
423 * @param ?string $fontname Font name (defaults to static::FONT)
427 protected function fixSize(
431 string $fontstyle = '',
432 string $fontname = null
434 if ($fontname === null) {
435 $fontname = static::FONT
;
437 $this->SetFontSize($fontsize);
438 while ((int)$this->GetStringWidth($text, $fontname, $fontstyle, $fontsize) > $maxsize) {
440 $this->SetFontSize($fontsize);
447 * @param string $str Original string
448 * @param integer $length Max length
452 protected function cut(string $str, int $length): string
454 $length = $length - 2; //keep a margin
455 if ((int)$this->GetStringWidth($str) > $length) {
456 while ((int)$this->GetStringWidth($str . '...') > $length) {
457 $str = mb_substr($str, 0, -1, 'UTF-8');
465 * Stretch a header string
467 * @param string $str Original string
468 * @param integer $length Max length
472 protected function stretchHead(string $str, int $length): string
474 $this->SetFont(self
::FONT
, 'B', self
::FONT_SIZE
);
476 if ((int)$this->GetStringWidth($str) > $length) {
477 while ((int)$this->GetStringWidth($str) > $length) {
478 $this->setFontStretching(--$stretch);
489 public function getFilename(): string
491 return $this->filename
;
495 * Download PDF from browser
499 public function download(): string
501 return $this->Output($this->filename
, 'D');