Repository navigation
Expand file tree
/
Copy pathE052_custom_fonts_fallback.php
More file actions
262 lines (232 loc) · 12.6 KB
/
Copy pathE052_custom_fonts_fallback.php
File metadata and controls
262 lines (232 loc) · 12.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
<?php
declare(strict_types=1);
/**
* 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.
* - Synthetic bold and italic for a family that ships no such variation.
*
* 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);
// DejaVu Sans ExtraLight: a family that ships no bold and no italic variation,
// used below to show how those styles are synthesized.
$fExtraLight = $pdf->font->insert($pdf->pon, 'dejavusansextralight', '', 11);
// ===| Page 1 – Font Coverage Overview |=====================================
$pdf->addPage(['format' => 'A4']);
$pdf->page->addContent($fHelvetica['out']);
$overviewHtml = '<h1 style="font-family: helvetica;">Font Selection & 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);
// ===| Page 4 – Synthetic bold and italic |==================================
// A family ships one definition file per style variation, named after the font key:
// unifont.json, unifontb.json, unifonti.json, unifontbi.json. GNU Unifont and DejaVu
// Sans ExtraLight ship only the regular one, so the other three styles resolve to it
// and the requested style is painted by the text operators: bold strokes the glyphs
// with a width of a thirtieth of the font size, italic shears the text matrix.
//
// Nothing has to be enabled: <b>, <i> and the CSS font-weight and font-style
// properties work the same whether the variation exists or not.
//
// The four styles are one font: the glyph program is the same, so it is held once and
// embedded once no matter how many styles the document uses.
$pdf->addPage(['format' => 'A4']);
$pdf->page->addContent($fUnifont['out']);
$syntheticHtml = '<h2 style="font-family: helvetica;">Synthetic Bold & Italic</h2>
<p style="font-family: helvetica; font-size: 10pt;">
Helvetica ships all four style variations, so each one below is a distinct font program:
</p>
<p style="font-family: helvetica; font-size: 13pt;">
Regular · <b>Bold</b> · <i>Italic</i> · <b><i>Bold Italic</i></b>
</p>
<p style="font-family: helvetica; font-size: 10pt;">
Unifont ships only the regular one, so the other three are painted from it:
</p>
<p style="font-family: unifont; font-size: 11pt;">
Regular · <b>Bold</b> · <i>Italic</i> · <b><i>Bold Italic</i></b>
</p>
<p style="font-family: helvetica; font-size: 10pt;">
The same applies to an outline font such as DejaVu Sans ExtraLight:
</p>
<p style="font-family: dejavusansextralight; font-size: 13pt;">
Regular · <b>Bold</b> · <i>Italic</i> · <b><i>Bold Italic</i></b>
</p>
<p style="font-family: dejavusansextralight; font-size: 13pt; color: #cc0000;">
A coloured <b>synthetic bold</b> is outlined in its own colour.
</p>
<hr/>
<h3 style="font-family: helvetica;">What to expect</h3>
<ul style="font-family: helvetica; font-size: 10pt;">
<li>The advance widths never change, so a synthetic style wraps and justifies exactly
like the regular one and the document does not reflow.</li>
<li>The painted glyphs are wider than the advance they were measured with: a stroked
stem spills half the stroke width past each edge, and a sheared ascender leans
past the end of the run by the slant times the ascent. A synthetic italic run can
touch the run that follows it.</li>
<li>Only the drawing operators change, so text extraction, search and tagging are
unaffected.</li>
<li>A real bold or italic font is always better. The synthesis is a fallback, not a
substitute for a designed variation.</li>
</ul>
<p style="font-family: helvetica; font-size: 10pt;">
Low-level callers of getTextCell() and getTextLine() set the fill colour themselves,
and must set the stroke colour alongside it for a synthetic bold in a colour other
than black. The HTML renderer does it automatically.
</p>';
$pdf->addHTMLCell(html: $syntheticHtml, posx: 15, posy: 20, width: 175);
// ----------
$rawpdf = $pdf->getOutPDFString();
$pdf->renderPDF(rawpdf: $rawpdf);