diff --git a/bericht_batch.php b/bericht_batch.php index 07e2f6e..8d1375f 100644 --- a/bericht_batch.php +++ b/bericht_batch.php @@ -60,14 +60,14 @@ if ($action === 'generate') { // Inhaltsverzeichnis-Seite $pdf->AddPage('P', 'A4'); - $pdf->SetFont('helvetica', 'B', 18); + $pdf->SetFont(bericht_ensure_hack_font(), 'B', 18); $pdf->Cell(0, 12, 'Bericht-Sammlung', 0, 1, 'C'); - $pdf->SetFont('helvetica', '', 11); + $pdf->SetFont(bericht_ensure_hack_font(), '', 11); $pdf->Cell(0, 8, 'Erstellt: '.dol_print_date(dol_now(), 'dayhour'), 0, 1, 'C'); $pdf->Ln(8); - $pdf->SetFont('helvetica', 'B', 13); + $pdf->SetFont(bericht_ensure_hack_font(), 'B', 13); $pdf->Cell(0, 8, 'Enthaltene Berichte ('.count($ids).')', 0, 1, 'L'); - $pdf->SetFont('helvetica', '', 10); + $pdf->SetFont(bericht_ensure_hack_font(), '', 10); $berichte = array(); foreach ($ids as $id) { diff --git a/bericht_card.php b/bericht_card.php index 96fccbc..d7a385a 100644 --- a/bericht_card.php +++ b/bericht_card.php @@ -499,7 +499,10 @@ if (!$bericht) { print ''; print '
'; print ''; - print ''; + // DolEditor (CKEditor) — wird im PDF mit writeHTMLCell gerendert + require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php'; + $noteEditor = new DolEditor('page-note', '', '100%', 120, 'dolibarr_notes', 'In', false, true, true, 4, '100%'); + $noteEditor->Create(0); print '
'; print ''; diff --git a/fonts/Hack-Bold.ttf b/fonts/Hack-Bold.ttf new file mode 100644 index 0000000..7ff4975 Binary files /dev/null and b/fonts/Hack-Bold.ttf differ diff --git a/fonts/Hack-BoldItalic.ttf b/fonts/Hack-BoldItalic.ttf new file mode 100644 index 0000000..3b137d9 Binary files /dev/null and b/fonts/Hack-BoldItalic.ttf differ diff --git a/fonts/Hack-Italic.ttf b/fonts/Hack-Italic.ttf new file mode 100644 index 0000000..d26198a Binary files /dev/null and b/fonts/Hack-Italic.ttf differ diff --git a/fonts/Hack-Regular.ttf b/fonts/Hack-Regular.ttf new file mode 100644 index 0000000..92a90cb Binary files /dev/null and b/fonts/Hack-Regular.ttf differ diff --git a/js/editor.js b/js/editor.js index b0eaf2c..d3e409c 100644 --- a/js/editor.js +++ b/js/editor.js @@ -26,6 +26,29 @@ const cfg = window.BERICHT_CONFIG || {}; if (!cfg.berichtid) { console.warn('Bericht: keine Konfiguration'); return; } + /** + * Liest den Notiz-Text aus — funktioniert mit CKEditor (DolEditor) UND plain textarea + */ + function getNoteValue() { + if (window.CKEDITOR && window.CKEDITOR.instances && window.CKEDITOR.instances['page-note']) { + return window.CKEDITOR.instances['page-note'].getData() || ''; + } + const el = document.getElementById('page-note'); + return el ? el.value : ''; + } + + /** + * Setzt den Notiz-Text. + */ + function setNoteValue(html) { + if (window.CKEDITOR && window.CKEDITOR.instances && window.CKEDITOR.instances['page-note']) { + window.CKEDITOR.instances['page-note'].setData(html || ''); + return; + } + const el = document.getElementById('page-note'); + if (el) el.value = html || ''; + } + // PDF.js worker (lokal) if (window.pdfjsLib) { pdfjsLib.GlobalWorkerOptions.workerSrc = '/bericht/js/lib/pdf.worker.min.js'; @@ -157,7 +180,7 @@ if (wrapL) wrapL.classList.remove('empty'); // wird gleich aus loadPageMeta überschrieben falls gespeichert fabricCanvas.clear(); - document.getElementById('page-note').value = ''; + setNoteValue(''); await loadPageMeta(); // setzt currentPageRotation + ggf. loadedFabricJson @@ -354,7 +377,7 @@ if (!r.ok) return; const data = await r.json(); if (data.fabric_json) loadedFabricJson = data.fabric_json; - if (data.note) document.getElementById('page-note').value = data.note; + if (data.note) setNoteValue(data.note); if (typeof data.rotation !== 'undefined' && data.rotation !== null) { currentPageRotation = parseInt(data.rotation, 10) || 0; } @@ -745,7 +768,7 @@ fd.append('token', cfg.token); fd.append('pageid', currentPageId); fd.append('fabric_json', JSON.stringify(fabricCanvas.toJSON(['bgImage']))); - fd.append('note', document.getElementById('page-note').value || ''); + fd.append('note', getNoteValue() || ''); fd.append('rotation', currentPageRotation); // Phase 6: Composite-PNG diff --git a/lib/bericht.lib.php b/lib/bericht.lib.php index 0b2c0af..3415b04 100644 --- a/lib/bericht.lib.php +++ b/lib/bericht.lib.php @@ -276,7 +276,7 @@ function bericht_burn_annotations($pdf, $fabric_json, $x, $y, $w, $h) case 'text': case 'textbox': $fontsize = max(6, ($obj['fontSize'] ?? 16) * $sx * 2.83); - $pdf->SetFont('helvetica', '', $fontsize); + $pdf->SetFont(bericht_ensure_hack_font(), '', $fontsize); $pdf->SetTextColor($stroke[0], $stroke[1], $stroke[2]); $pdf->Text($ox, $oy + $fontsize * 0.35, $obj['text'] ?? ''); break; @@ -305,10 +305,64 @@ function bericht_render_cover_for_preview($template_path, $bericht, $parent, $te * @param string $fmt A4/A3/A5/Letter * @param bool $fpdi_loaded */ +/** + * Registriert den Hack-Font (Eddys Corporate-Font) in TCPDF und gibt den Font-Key zurück. + * Konvertiert die TTFs beim ersten Aufruf via TCPDF_FONTS::addTTFfont ins TCPDF-Font-Verzeichnis. + * Fallback auf 'helvetica' wenn etwas schiefgeht. + * + * @return string Font-Key für $pdf->SetFont() + */ +function bericht_ensure_hack_font() +{ + static $cached = null; + if ($cached !== null) return $cached; + + if (!class_exists('TCPDF_FONTS')) { + $cached = 'helvetica'; + return $cached; + } + $dir = dirname(__DIR__).'/fonts'; + $files = array( + '' => $dir.'/Hack-Regular.ttf', + 'B' => $dir.'/Hack-Bold.ttf', + 'I' => $dir.'/Hack-Italic.ttf', + 'BI' => $dir.'/Hack-BoldItalic.ttf', + ); + try { + $key = null; + foreach ($files as $style => $path) { + if (!file_exists($path)) continue; + $k = TCPDF_FONTS::addTTFfont($path, 'TrueTypeUnicode', '', 32); + if ($style === '' && $k) $key = $k; + } + $cached = $key ?: 'helvetica'; + } catch (Throwable $e) { + $cached = 'helvetica'; + } + return $cached; +} + +/** + * Rendert eine HTML-Notiz (CKEditor-Output) mit TCPDF::writeHTMLCell + * in einen reservierten Bereich unterhalb des Bildes. + */ +function bericht_write_note_html($pdf, $html, $x, $y, $w, $h) +{ + if (empty($html)) return; + // CKEditor liefert

— TCPDF kann das direkt + $pdf->SetFont(bericht_ensure_hack_font(), '', 9); + $pdf->SetTextColor(40, 40, 40); + // Border 0, kein Auto-Pagebreak damit die Notiz im reservierten Bereich bleibt + $autoPB = $pdf->getAutoPageBreak(); + $bMargin = $pdf->getBreakMargin(); + $pdf->SetAutoPageBreak(false, 0); + $pdf->writeHTMLCell($w, $h, $x, $y, $html, 0, 1, false, true, 'L', true); + $pdf->SetAutoPageBreak($autoPB, $bMargin); +} + function bericht_render_page_to_pdf($pdf, $page, $ori, $fmt, $fpdi_loaded) { - // Phase 6: Wenn der Editor ein Composite-PNG hochgeladen hat, nutzen wir das - // direkt — ein Bild über die ganze Seite. Keine Server-Shape-Logik nötig. + // Phase 6: Wenn der Editor ein Composite-PNG hochgeladen hat, nutzen wir das direkt if (!empty($page->composite_path)) { $full = bericht_resolve_data_path($page->composite_path); if ($full && file_exists($full)) { @@ -316,8 +370,14 @@ function bericht_render_page_to_pdf($pdf, $page, $ori, $fmt, $fpdi_loaded) $pageW = $pdf->getPageWidth(); $pageH = $pdf->getPageHeight(); $margin = 10; + // Notiz-Bereich reservieren wenn eine Notiz existiert + $note_h = 0; + if (!empty($page->note)) { + // ca. 1/4 Seite für HTML-Notizen, aber mindestens 20mm, max 80mm + $note_h = max(20, min(80, $pageH * 0.25)); + } $maxW = $pageW - 2 * $margin; - $maxH = $pageH - 2 * $margin - (empty($page->note) ? 0 : 10); + $maxH = $pageH - 2 * $margin - $note_h - ($note_h ? 4 : 0); list($iw, $ih) = @getimagesize($full); if ($iw && $ih) { $ratio = min($maxW / $iw, $maxH / $ih); @@ -327,9 +387,9 @@ function bericht_render_page_to_pdf($pdf, $page, $ori, $fmt, $fpdi_loaded) $pdf->Image($full, $x, $y, $w, $h); } if (!empty($page->note)) { - $pdf->SetY(-20); - $pdf->SetFont('helvetica', 'I', 9); - $pdf->MultiCell(0, 5, $page->note, 0, 'L'); + // Notiz direkt unter dem Bild rendern — kein SetY(-20), keine auto-Page-Break + $note_y = $margin + ($ih && $iw ? ($ih * min($maxW / $iw, $maxH / $ih)) : $maxH) + 4; + bericht_write_note_html($pdf, $page->note, $margin, $note_y, $maxW, $note_h); } return; } @@ -342,13 +402,13 @@ function bericht_render_page_to_pdf($pdf, $page, $ori, $fmt, $fpdi_loaded) $pdf->AddPage($ori, $fmt); $pageW = $pdf->getPageWidth(); $pageH = $pdf->getPageHeight(); - $pdf->SetFont('helvetica', 'B', 32); + $pdf->SetFont(bericht_ensure_hack_font(), 'B', 32); $pdf->SetTextColor(40, 40, 40); $pdf->SetY($pageH / 2 - 20); $pdf->MultiCell(0, 20, $page->title, 0, 'C'); if (!empty($page->note)) { $pdf->Ln(12); - $pdf->SetFont('helvetica', '', 12); + $pdf->SetFont(bericht_ensure_hack_font(), '', 12); $pdf->MultiCell(0, 8, $page->note, 0, 'C'); } return; @@ -364,7 +424,7 @@ function bericht_render_page_to_pdf($pdf, $page, $ori, $fmt, $fpdi_loaded) $margin = 10; $title_h = !empty($page->title) ? 12 : 0; if ($title_h) { - $pdf->SetFont('helvetica', 'B', 16); + $pdf->SetFont(bericht_ensure_hack_font(), 'B', 16); $pdf->SetY($margin); $pdf->MultiCell(0, $title_h, $page->title, 0, 'C'); } @@ -385,7 +445,7 @@ function bericht_render_page_to_pdf($pdf, $page, $ori, $fmt, $fpdi_loaded) $x0 = $margin + $slot * ($w_each + $gap); // Label - $pdf->SetFont('helvetica', 'B', 11); + $pdf->SetFont(bericht_ensure_hack_font(), 'B', 11); $pdf->SetXY($x0, $top); $pdf->Cell($w_each, $label_h, $label, 0, 0, 'C'); // Bild darunter @@ -397,9 +457,7 @@ function bericht_render_page_to_pdf($pdf, $page, $ori, $fmt, $fpdi_loaded) } bericht_burn_annotations($pdf, $page->fabric_json, 0, 0, $pageW, $pageH); if (!empty($page->note)) { - $pdf->SetY(-20); - $pdf->SetFont('helvetica', 'I', 9); - $pdf->MultiCell(0, 5, $page->note, 0, 'L'); + bericht_write_note_html($pdf, $page->note, 10, $pdf->getPageHeight() - 22, $pdf->getPageWidth() - 20, 18); } return; } @@ -416,7 +474,7 @@ function bericht_render_page_to_pdf($pdf, $page, $ori, $fmt, $fpdi_loaded) // Titel oben $title_h = 0; if (!empty($page->title)) { - $pdf->SetFont('helvetica', 'B', 16); + $pdf->SetFont(bericht_ensure_hack_font(), 'B', 16); $pdf->SetY(10); $pdf->MultiCell(0, 10, $page->title, 0, 'C'); $title_h = 14; @@ -443,9 +501,7 @@ function bericht_render_page_to_pdf($pdf, $page, $ori, $fmt, $fpdi_loaded) // Notiz unten if (!empty($page->note)) { - $pdf->SetY(-20); - $pdf->SetFont('helvetica', 'I', 9); - $pdf->MultiCell(0, 5, $page->note, 0, 'L'); + bericht_write_note_html($pdf, $page->note, 10, $pdf->getPageHeight() - 22, $pdf->getPageWidth() - 20, 18); } return; } @@ -489,9 +545,7 @@ function bericht_render_page_to_pdf($pdf, $page, $ori, $fmt, $fpdi_loaded) } if (!empty($page->note)) { - $pdf->SetY(-20); - $pdf->SetFont('helvetica', 'I', 9); - $pdf->MultiCell(0, 5, $page->note, 0, 'L'); + bericht_write_note_html($pdf, $page->note, 10, $pdf->getPageHeight() - 22, $pdf->getPageWidth() - 20, 18); } }