Files

196 lines
9.2 KiB
PHP
Raw Permalink Normal View History

2026-08-20 11:41:17 +00:00
<?php
/**
* E052_custom_fonts_fallback.php
*
* Demonstrates custom font selection, Unicode coverage strategy, and
* font-family fallback across multiple scripts.
*
* What this demonstrates:
* - font->insert(): loading built-in and extended font families.
* - Subset vs full-embed tradeoff (constructor $subsetfont flag).
* - Choosing fonts by Unicode coverage: helvetica (Latin), dejavusans
* (Latin + Greek + Cyrillic + IPA), unifont (full Unicode BMP).
* - HTML font-family CSS mapping to pre-loaded font slots.
* - Per-script font selection in addHTMLCell markup.
*
* Companion libraries: tc-lib-pdf-font, tc-lib-unicode, tc-lib-unicode-data.
*
* @since 2026-05-01
* @category Library
* @package Pdf
* @author Nicola Asuni <info@tecnick.com>
* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE)
* @link https://github.com/tecnickcom/tc-lib-pdf
*
* This file is part of tc-lib-pdf software library.
*/
// NOTE: local file reads (images, fonts, attachments) are restricted to an allowlist of
// trusted paths that covers this package tree, so run the examples in place. To read assets
// from other locations, list them in the 'allowedPaths' entry of the fileOptions constructor
// parameter (see E047_remote_resources_security.php).
// NOTE: run make fonts in the project root to generate the dependencies and example fonts.
require __DIR__ . '/../vendor/autoload.php';
// K_PATH_FONTS must point to the directory holding .z and .php font metric files.
define('K_PATH_FONTS', (string) realpath(__DIR__ . '/../vendor/tecnickcom/tc-lib-pdf-font/target/fonts'));
// Subset font embedding: when $subsetfont = true (constructor arg 3), only the
// glyphs actually used in the document are embedded. This produces smaller PDFs
// but makes the font unsuitable for later editing. Set to false for archival PDFs
// (PDF/A, PDF/UA) or whenever the full character set must be available.
$pdf = new \Com\Tecnick\Pdf\Tcpdf(
unit: \Com\Tecnick\Pdf\Page\Unit::Millimeter,
isunicode: true,
subsetfont: false,
compress: true,
mode: \Com\Tecnick\Pdf\PdfConformance::None,
objEncrypt: null,
);
$pdf->setCreator('tc-lib-pdf');
$pdf->setAuthor('Nicola Asuni');
$pdf->setSubject('tc-lib-pdf example: 052');
$pdf->setTitle('Custom Fonts & Unicode Fallback');
$pdf->setKeywords('TCPDF tc-lib-pdf font unicode multilingual fallback subset dejavusans unifont');
$pdf->setPDFFilename('052_custom_fonts_fallback.pdf');
$pdf->setViewerPreferences(['DisplayDocTitle' => true]);
$pdf->enableDefaultPageContent();
// ----------
// Pre-load all font families that will be used in the document.
// font->insert() returns a font descriptor array. The 'out' key contains
// the PDF operator stream that must be injected onto a page before the
// font is used. Loading fonts before addPage() registers them in the
// font object pool; injecting 'out' at the start of each page activates
// the font for that page.
// Helvetica: core Type-1, no embedding required, Latin + standard symbols only.
$fHelvetica = $pdf->font->insert($pdf->pon, 'helvetica', '', 11);
$fHelveticaB = $pdf->font->insert($pdf->pon, 'helvetica', 'B', 11);
// Times New Roman (core): serif alternative for body text, Latin only.
$fTimes = $pdf->font->insert($pdf->pon, 'times', '', 11);
// Courier (core): monospaced, Latin only; good for code samples.
$fCourier = $pdf->font->insert($pdf->pon, 'courier', '', 10);
// DejaVu Sans: TrueType, Latin + Greek + Cyrillic + IPA + many other scripts.
// Covers most Western European, Eastern European, and Slavic languages.
$fDejavu = $pdf->font->insert($pdf->pon, 'dejavusans', '', 11);
// Unifont: TrueType, very broad Unicode BMP (plane 0) coverage including Arabic,
// Hebrew, Thai, Devanagari, and many additional scripts.
// File size is large; use subset=true when embedding it in production PDFs.
$fUnifont = $pdf->font->insert($pdf->pon, 'unifont', '', 11);
// ===| Page 1 Font Coverage Overview |=====================================
$pdf->addPage(['format' => 'A4']);
$pdf->page->addContent($fHelvetica['out']);
$overviewHtml = '<h1 style="font-family: helvetica;">Font Selection &amp; Unicode Fallback</h1>
<p style="font-family: helvetica; font-size: 10pt;">
PDF viewers cannot substitute fonts automatically — every glyph must come from
an embedded font resource. The strategy is:
</p>
<ol style="font-family: helvetica; font-size: 10pt;">
<li>Use <strong>core Type-1 fonts</strong> (helvetica, times, courier) for Latin-only text to
avoid embedding overhead.</li>
<li>Upgrade to <strong>DejaVu Sans</strong> for pages that mix Latin with Greek, Cyrillic, or
extended Latin (diacritics, IPA).</li>
<li>Use <strong>Unifont</strong> for pages that require full Unicode BMP coverage (Arabic, Hebrew,
Thai, Devanagari, Hangul, CJK).</li>
</ol>
<p style="font-family: helvetica; font-size: 10pt;">
In HTML cells, specify the font via <code>style="font-family: dejavusans"</code> or
<code>style="font-family: unifont"</code>.
The name must match the lowercase font identifier known to tc-lib-pdf-font.
</p>
<hr/>
<h2 style="font-family: helvetica;">Core Type-1 Fonts (Latin)</h2>
<p style="font-family: helvetica; font-size: 11pt;">
<span style="font-family: helvetica;">Helvetica — The quick brown fox jumps over the lazy dog.</span>
</p>
<p style="font-family: times; font-size: 11pt;">
<span style="font-family: times;">Times — The quick brown fox jumps over the lazy dog.</span>
</p>
<p style="font-family: courier; font-size: 10pt;">
<span style="font-family: courier;">Courier — The quick brown fox jumps over the lazy dog.</span>
</p>';
$pdf->addHTMLCell(html: $overviewHtml, posx: 15, posy: 20, width: 175);
// ===| Page 2 DejaVu Sans: Latin + Greek + Cyrillic |======================
$pdf->addPage(['format' => 'A4']);
$pdf->page->addContent($fDejavu['out']);
$dejavuHtml = '<h2 style="font-family: dejavusans;">DejaVu Sans — Extended Coverage</h2>
<p style="font-family: dejavusans; font-size: 10pt;">
DejaVu Sans covers Latin, Greek, Cyrillic, Armenian, Georgian, Hebrew,
Arabic (basic), and many more. Use it when helvetica glyphs are missing.
</p>
<h3 style="font-family: dejavusans;">Latin Extended</h3>
<p style="font-family: dejavusans; font-size: 11pt;">
Héllo Wörld — café, naïve, résumé, Ångström, façade, Ñoño.
</p>
<h3 style="font-family: dejavusans;">Greek (Ελληνικά)</h3>
<p style="font-family: dejavusans; font-size: 11pt;">
Ξεσκεπάζω την ψυχοφθόρα βδελυγμία.
</p>
<h3 style="font-family: dejavusans;">Cyrillic (Русский)</h3>
<p style="font-family: dejavusans; font-size: 11pt;">
Съешь же ещё этих мягких французских булок, да выпей чаю.
</p>
<h3 style="font-family: dejavusans;">IPA Phonetics</h3>
<p style="font-family: dejavusans; font-size: 11pt;">
/ˌɪntəˈnæʃənl/ · /fəˈnɛtɪk/ · /ˈælfəbɪt/
</p>
<hr/>
<p style="font-family: dejavusans; font-size: 9pt; color: #555555;">
Subset tip: dejavusans is ~750 KB uncompressed. With <code>$subsetfont = true</code> and
only the glyphs used in this page, the embedded subset would be much smaller.
For documents mixing many scripts across many pages, subset embedding is recommended.
</p>';
$pdf->addHTMLCell(html: $dejavuHtml, posx: 15, posy: 20, width: 175);
// ===| Page 3 Unifont: Full BMP |==========================================
$pdf->addPage(['format' => 'A4']);
$pdf->page->addContent($fUnifont['out']);
$unifontHtml = '<h2 style="font-family: unifont; font-size: 11pt; font-weight: normal;">Unifont — Full Unicode BMP Coverage</h2>
<p style="font-family: unifont; font-size: 11pt;">
Unifont offers very broad Unicode Plane 0 (BMP) coverage.
Use it as a last-resort fallback for scripts not covered by DejaVu.
Production PDFs should always use <code>$subsetfont = true</code> with Unifont.
</p>
<h3 style="font-family: unifont; font-size: 11pt; font-weight: normal;">Arabic (العربية) — RTL</h3>
<p style="font-family: unifont; font-size: 11pt; text-align: right;">
صِف خَلقَ خَودِكِ كَمِثلِ الشَّمسِ إِذ بَزَغَت
</p>
<h3 style="font-family: unifont; font-size: 11pt; font-weight: normal;">Hebrew (עברית) — RTL</h3>
<p style="font-family: unifont; font-size: 11pt; text-align: right;">
דג סקרן שט בים מאוכזב ולפתע מצא חברה
</p>
<h3 style="font-family: unifont; font-size: 11pt; font-weight: normal;">Devanagari (हिन्दी)</h3>
<p style="font-family: unifont; font-size: 11pt;">
ऋषि सुयश ने प्रख्यात ग्रंथ की रचना करके हमें ज्ञान दिया।
</p>
<hr/>
<p style="font-family: unifont; font-size: 11pt; color: #555555;">
Fallback strategy: attempt to render with the most specific font first.
Only escalate to Unifont for code points absent from narrower families.
This minimises file size while ensuring every glyph is available.
</p>';
$pdf->addHTMLCell(html: $unifontHtml, posx: 15, posy: 20, width: 175);
// ----------
$rawpdf = $pdf->getOutPDFString();
$pdf->renderPDF(rawpdf: $rawpdf);