font-family-key public $bericht_title = ''; public $bericht_company = ''; public $bericht_logo = ''; /** * Muss direkt nach der Konstruktion aufgerufen werden. */ public function berichtInit($title, $company, $logo_path) { $this->bericht_title = (string) $title; $this->bericht_company = (string) $company; $this->bericht_logo = (string) $logo_path; // Hack-Font registrieren (Eddys Corporate-Font) if (class_exists('TCPDF_FONTS') && defined('DOL_DATA_ROOT')) { $fontdir = dirname(__DIR__).'/fonts/'; $outdir = DOL_DATA_ROOT.'/bericht/tcpdf_fonts/'; if (!is_dir($outdir)) @mkdir($outdir, 0755, true); if (is_dir($outdir) && is_writable($outdir)) { $map = array( '' => 'Hack-Regular.ttf', 'B' => 'Hack-Bold.ttf', 'I' => 'Hack-Italic.ttf', 'BI' => 'Hack-BoldItalic.ttf', ); foreach ($map as $style => $fn) { $src = $fontdir.$fn; if (!file_exists($src)) continue; try { $k = TCPDF_FONTS::addTTFfont($src, 'TrueTypeUnicode', '', 32, $outdir); if ($k) { $ffile = $outdir.$k.'.php'; if (file_exists($ffile)) { // WICHTIG: Jede TTF wird als eigene Family mit style='' registriert, // sonst sucht TCPDF bei SetFont(..., 'B') nach "hackB.php" und // bricht mit "Could not include font definition file" ab. $this->AddFont($k, '', $ffile); $this->hack_font_styles[$style] = $k; } } } catch (Throwable $e) { error_log('[BerichtPdf] Hack-Font '.$fn.' fehlgeschlagen: '.$e->getMessage()); } } if (!empty($this->hack_font_styles[''])) { $this->hack_font_key = $this->hack_font_styles['']; } } else { error_log('[BerichtPdf] Font-Outdir nicht schreibbar: '.$outdir); } } } /** * Leitet SetFont() um, wenn die Family einer unserer Hack-Varianten ist: * ein Style-Wechsel ('B'/'I'/'BI') wird auf die passende Hack-Family mit * leerem Style gemappt. So vermeiden wir den TCPDF-Fallback auf "hack.php". */ public function SetFont($family, $style = '', $size = null, $fontfile = '', $subset = 'default', $out = true) { $fam = strtolower($family); $is_hack = in_array($fam, $this->hack_font_styles, true); if ($is_hack && !empty($this->hack_font_styles)) { $st = strtoupper(str_replace('U', '', (string) $style)); if (!isset($this->hack_font_styles[$st])) { // Kaskade: BI → B → '', I → '' if ($st === 'BI' && isset($this->hack_font_styles['B'])) $st = 'B'; elseif (isset($this->hack_font_styles[''])) $st = ''; } $target = $this->hack_font_styles[$st] ?? $this->hack_font_styles[''] ?? $family; return parent::SetFont($target, '', $size, $fontfile, $subset, $out); } return parent::SetFont($family, $style, $size, $fontfile, $subset, $out); } public function Header() { $pageW = $this->getPageWidth(); $logo_w = 0; if ($this->bericht_logo && file_exists($this->bericht_logo)) { $info = @getimagesize($this->bericht_logo); if ($info && $info[0] && $info[1]) { $maxW = 40; $maxH = 18; $ratio = min($maxW / $info[0], $maxH / $info[1]); $w = $info[0] * $ratio; $h = $info[1] * $ratio; $this->Image($this->bericht_logo, $pageW - 10 - $w, 6, $w, $h); $logo_w = $w; } } $this->SetTextColor(40, 40, 40); $this->SetFont($this->hack_font_key, 'B', 13); $this->SetXY(10, 8); $textW = $pageW - 20 - $logo_w - 4; $this->Cell($textW, 6, $this->bericht_title, 0, 2, 'L'); if ($this->bericht_company) { $this->SetFont($this->hack_font_key, '', 9); $this->SetX(10); $this->Cell($textW, 5, $this->bericht_company, 0, 2, 'L'); } $this->SetDrawColor(180, 180, 180); $this->SetLineWidth(0.2); $this->Line(10, 27, $pageW - 10, 27); } public function Footer() { $this->SetY(-12); $this->SetFont($this->hack_font_key, '', 9); $this->SetTextColor(100, 100, 100); $txt = 'Seite '.$this->getAliasNumPage().' / '.$this->getAliasNbPages(); $this->Cell(0, 8, $txt, 0, 0, 'C'); } } class BerichtPdf extends TCPDF { use BerichtPdfTrait; } if (class_exists('\\setasign\\Fpdi\\Tcpdf\\Fpdi')) { class BerichtPdfFpdi extends \setasign\Fpdi\Tcpdf\Fpdi { use BerichtPdfTrait; } }