PDF: Started building system to allow custom DOMPDF font loading

This commit is contained in:
Dan Brown
2026-04-20 15:42:28 +01:00
parent 4f370ccddb
commit e91747785b
5 changed files with 59 additions and 3 deletions

View File

@@ -68,7 +68,7 @@ return [
* Times-Roman, Times-Bold, Times-BoldItalic, Times-Italic, * Times-Roman, Times-Bold, Times-BoldItalic, Times-Italic,
* Symbol, ZapfDingbats. * Symbol, ZapfDingbats.
*/ */
'font_dir' => storage_path('fonts/'), // advised by dompdf (https://github.com/dompdf/dompdf/pull/782) 'font_dir' => storage_path('fonts/dompdf'), // advised by dompdf (https://github.com/dompdf/dompdf/pull/782)
/** /**
* The location of the DOMPDF font cache directory. * The location of the DOMPDF font cache directory.
@@ -78,7 +78,7 @@ return [
* *
* Note: This directory must exist and be writable by the webserver process. * Note: This directory must exist and be writable by the webserver process.
*/ */
'font_cache' => storage_path('fonts/'), 'font_cache' => storage_path('fonts/dompdf/cache'),
/** /**
* The location of a temporary directory. * The location of a temporary directory.

View File

@@ -4,6 +4,8 @@ namespace BookStack\Exports;
use BookStack\Exceptions\PdfExportException; use BookStack\Exceptions\PdfExportException;
use Dompdf\Dompdf; use Dompdf\Dompdf;
use FontLib\Font;
use Illuminate\Support\Str;
use Knp\Snappy\Pdf as SnappyPdf; use Knp\Snappy\Pdf as SnappyPdf;
use Symfony\Component\Process\Exception\ProcessTimedOutException; use Symfony\Component\Process\Exception\ProcessTimedOutException;
use Symfony\Component\Process\Process; use Symfony\Component\Process\Process;
@@ -60,12 +62,57 @@ class PdfGenerator
$domPdf = new Dompdf($options); $domPdf = new Dompdf($options);
$domPdf->setBasePath(base_path('public')); $domPdf->setBasePath(base_path('public'));
$fontMetrics = $domPdf->getFontMetrics();
$userFontfamilies = $this->getUserDomPdfFontFamilies();
foreach ($userFontfamilies as $fontFamily => $fonts) {
$fontMetrics->setFontFamily($fontFamily, $fonts);
}
// dd($userFontfamilies, $fontMetrics->getFontFamilies());
$domPdf->loadHTML($this->convertEntities($html)); $domPdf->loadHTML($this->convertEntities($html));
$domPdf->render(); $domPdf->render();
return (string) $domPdf->output(); return (string) $domPdf->output();
} }
/**
* @return array<string, array<string, string>>
*/
protected function getUserDomPdfFontFamilies(): array
{
$fontStore = storage_path('fonts/dompdf');
if (!is_dir($fontStore)) {
return [];
}
$fontFamilies = [];
$fontFiles = glob($fontStore . DIRECTORY_SEPARATOR . '*.ttf');
foreach ($fontFiles as $fontFile) {
$fontFileName = basename($fontFile, '.ttf');
$expectedUfm = $fontStore . DIRECTORY_SEPARATOR . $fontFileName . '.ufm';
if (!file_exists($expectedUfm)) {
$font = Font::load($fontFile);
$font->parse();
$font->saveAdobeFontMetrics($expectedUfm);
}
$nameParts = explode('-', $fontFileName);
if (count($nameParts) === 1 || $nameParts[1] === 'Regular') {
$nameParts[1] = 'Normal';
}
$family = trim(strtolower(preg_replace('/([A-Z])/', ' $1', $nameParts[0])));
$variation = Str::snake($nameParts[1]);
if (!isset($fontFamilies[$family])) {
$fontFamilies[$family] = [];
}
$fontFamilies[$family][$variation] = $fontStore . DIRECTORY_SEPARATOR . $fontFileName;
}
return $fontFamilies;
}
/** /**
* @throws PdfExportException * @throws PdfExportException
*/ */

View File

@@ -1,2 +1,6 @@
# Font cache files have once been stored directly in this folder
# therefore its important the contents non-ignored by git
# are chosen selectively
* *
!.gitignore !.gitignore
!dompdf/

3
storage/fonts/dompdf/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
*
!.gitignore
!cache/

2
storage/fonts/dompdf/cache/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*
!.gitignore