Fonts
phpdftk supports every font kind in ISO 32000-2: the 14 standard Type 1 fonts that every viewer ships, custom TrueType and Type 1 fonts with automatic subsetting, Type 0 composite (CID) fonts for full Unicode coverage, and Type 3 fonts whose glyph procedures are PDF content streams.
Standard Type 1 fonts
Section titled “Standard Type 1 fonts”The 14 standard fonts — Helvetica, Times, Courier in their weights — are always available, embedded in zero bytes, and perfect for body text when you don’t need a custom typeface.
use Phpdftk\Pdf\Core\Font\StandardFont;use Phpdftk\Pdf\Core\Font\Type1Font;use Phpdftk\Pdf\Writer\PdfWriter;
$writer = new PdfWriter();$page = $writer->addPage();
// The 14 standard Type1 fonts are always available — every PDF viewer ships them.// They cost zero bytes in the file and are perfect for prose, code, and tabular data// when you don't need a custom typeface.$specimens = [ [StandardFont::Helvetica, 'Helvetica - the workhorse sans-serif'], [StandardFont::HelveticaBold, 'Helvetica-Bold - a bolder workhorse'], [StandardFont::HelveticaOblique, 'Helvetica-Oblique - italicised'], [StandardFont::TimesRoman, 'Times-Roman - a serif for body copy'], [StandardFont::TimesBold, 'Times-Bold - a bolder serif'], [StandardFont::TimesItalic, 'Times-Italic - the cursive serif'], [StandardFont::Courier, 'Courier - monospace for code 0123456789'], [StandardFont::CourierBold, 'Courier-Bold - bolder monospace'],];
$y = 740;foreach ($specimens as [$face, $caption]) { $name = $writer->addFont(new Type1Font($face))->getResourceName(); $cs = $writer->addContentStream($page); $cs->beginText()->setFont($name, 16)->moveTextPosition(72, $y) ->showText($caption)->endText(); $y -= 36;}
$writer->save('type1.pdf');📄 View the sample PDF · View the full script on GitHub ↗
TrueType embedding & subsetting
Section titled “TrueType embedding & subsetting”TrueTypeFont::fromFile() parses a .ttf and registers it as a simple (non-composite) font. PdfWriter::addFont() embeds and subsets the program so only the WinAnsi-mapped glyphs you actually use are written into the file.
use Phpdftk\Pdf\Core\Font\StandardFont;use Phpdftk\Pdf\Core\Font\TrueTypeFont;use Phpdftk\Pdf\Core\Font\Type1Font;use Phpdftk\Pdf\Writer\PdfWriter;
// TrueTypeFont::fromFile() reads a .ttf, parses widths and metrics, and registers it as// a simple (non-composite) PDF font. Calling addFont() embeds and subsets the program// so only the glyphs needed for WinAnsi-encoded text are written into the file.$writer = new PdfWriter();$page = $writer->addPage();$caption = $writer->addFont(new Type1Font(StandardFont::HelveticaBold))->getResourceName();
$fontPath = __DIR__ . '/../../../vendor/mpdf/mpdf/ttfonts/DejaVuSerif.ttf';$dejavu = TrueTypeFont::fromFile($fontPath);$dejavuName = $writer->addFont($dejavu)->getResourceName();
$cs = $writer->addContentStream($page);$cs->beginText()->setFont($caption, 22)->moveTextPosition(72, 740) ->showText('TrueType embedding & subsetting')->endText();
$lines = [ [700, 'DejaVu Serif at 28pt — the font program is embedded.', 28], [650, 'Only the WinAnsi-mapped glyphs you use are written.', 18], [620, 'Smaller files than a full font, identical fidelity.', 18], [580, '"Lorem ipsum dolor sit amet, consectetur adipiscing."', 14], [560, 'The quick brown fox jumps over the lazy dog.', 14], [540, '0 1 2 3 4 5 6 7 8 9 - $ % & @ # ! ? * +', 14],];
foreach ($lines as [$y, $text, $size]) { $cs->beginText()->setFont($dejavuName, $size)->moveTextPosition(72, $y) ->showText($text)->endText();}
$writer->save('truetype-subset.pdf');📄 View the sample PDF · View the full script on GitHub ↗
Type 0 (CID) fonts for Unicode
Section titled “Type 0 (CID) fonts for Unicode”For non-WinAnsi text — CJK, Cyrillic, Greek, mathematical symbols — use addCompositeFont(). The font is embedded as a Type 0 CID font with a ToUnicode CMap, automatically subset to the codepoints you provide.
use Phpdftk\FontParser\TrueTypeParser;use Phpdftk\Pdf\Core\Font\StandardFont;use Phpdftk\Pdf\Core\Font\Type1Font;use Phpdftk\Pdf\Writer\PdfWriter;
// Type 0 (composite) fonts let you write any Unicode character a TTF font supports// — no encoding tricks, no WinAnsi limitations. The font is automatically subset// so only the glyphs you actually use are embedded.$writer = new PdfWriter();$page = $writer->addPage();$caption = $writer->addFont(new Type1Font(StandardFont::HelveticaBold))->getResourceName();
$fontPath = __DIR__ . '/../../../vendor/mpdf/mpdf/ttfonts/DejaVuSans.ttf';$ttData = (new TrueTypeParser($fontPath))->parse();
$samples = [ 'Latin Extended: café · résumé · naïve · jalapeño · København', 'Cyrillic: Привет, мир! Я люблю PDFs.', 'Greek: Καλημέρα κόσμε — αβγδεζηθ', 'Mathematical: ∑ x² ≤ ∫ f(x) dx · π ≈ 3.14159 · ∞ ≠ 0', 'Symbols: © ® ™ § ¶ † ‡ • ‰ ‹ › « » ←↑→↓ ↔',];
// Collect every codepoint actually used across all samples so the embedded font// is subset to exactly those glyphs.$allText = implode(' ', $samples);$codepoints = array_values(array_unique(array_map('mb_ord', mb_str_split($allText))));
$dejavu = $writer->addCompositeFont($ttData, $codepoints);$dejavuName = $dejavu->getResourceName();
// Post-subset Unicode → GID map from the font handle. Subsetting renumbers// the kept glyphs, so the original $ttData->fullUnicodeToGid points at// the wrong slots in the embedded font.$unicodeToGid = $dejavu->getUnicodeToGidMap();
$encodeHex = static function (string $text, array $unicodeToGid): string { $hex = ''; foreach (mb_str_split($text) as $char) { $gid = $unicodeToGid[mb_ord($char)] ?? 0; $hex .= sprintf('%04X', $gid); } return $hex;};
$cs = $writer->addContentStream($page);$cs->beginText()->setFont($caption, 22)->moveTextPosition(72, 740) ->showText('Unicode via Type 0 (CID) fonts')->endText();
$y = 690;foreach ($samples as $line) { $cs->beginText()->setFont($dejavuName, 14)->moveTextPosition(72, $y) ->showTextHex($encodeHex($line, $unicodeToGid))->endText(); $y -= 40;}
$writer->save('unicode-cid.pdf');📄 View the sample PDF · View the full script on GitHub ↗
Type 3 custom glyphs
Section titled “Type 3 custom glyphs”A Type3Font lets you ship arbitrary PDF content streams as glyphs — perfect for pictograms, dingbats, or any vector mark that should behave like text and scale to any size.
use Phpdftk\Pdf\Core\Content\ContentStream;use Phpdftk\Pdf\Core\Font\Encoding;use Phpdftk\Pdf\Core\Font\StandardFont;use Phpdftk\Pdf\Core\Font\Type1Font;use Phpdftk\Pdf\Core\Font\Type3Font;use Phpdftk\Pdf\Core\PdfArray;use Phpdftk\Pdf\Core\PdfDictionary;use Phpdftk\Pdf\Core\PdfName;use Phpdftk\Pdf\Core\PdfNumber;use Phpdftk\Pdf\Writer\PdfWriter;
// A Type 3 font lets you ship arbitrary PDF content streams as glyphs — perfect for// pictograms, custom dingbats, or any vector mark that should behave like text.$writer = new PdfWriter();$page = $writer->addPage();$caption = $writer->addFont(new Type1Font(StandardFont::HelveticaBold))->getResourceName();
// Glyph 'square' — a filled square spanning the 700×700 glyph space.$squareProc = new ContentStream();$squareProc ->setGlyphWidthAndBoundingBox(700, 0, 0, 0, 700, 700) ->rectangle(100, 100, 500, 500) ->fill();
// Glyph 'triangle' — a filled equilateral-ish triangle.$triangleProc = new ContentStream();$triangleProc ->setGlyphWidthAndBoundingBox(700, 0, 0, 0, 700, 700) ->moveTo(350, 650) ->lineTo(50, 100) ->lineTo(650, 100) ->closePath() ->fill();
// Glyph 'star' — a five-point star, painted with a single subpath.$starProc = new ContentStream();$starProc ->setGlyphWidthAndBoundingBox(700, 0, 0, 0, 700, 700) ->moveTo(350, 660) ->lineTo(431, 446) ->lineTo(660, 437) ->lineTo(478, 297) ->lineTo(553, 80) ->lineTo(350, 200) ->lineTo(147, 80) ->lineTo(222, 297) ->lineTo(40, 437) ->lineTo(269, 446) ->closePath() ->fill();
$squareRef = $writer->register($squareProc);$triangleRef = $writer->register($triangleProc);$starRef = $writer->register($starProc);
// Encoding: map ASCII 'A','B','C' to the three glyph names.$encoding = new Encoding();$encoding->differences = new PdfArray([ new PdfNumber(65), new PdfName('square'), new PdfName('triangle'), new PdfName('star'),]);$encodingRef = $writer->register($encoding);
$font = new Type3Font('DemoType3');$font->fontBBox = new PdfArray([ new PdfNumber(0), new PdfNumber(0), new PdfNumber(700), new PdfNumber(700),]);$font->firstChar = 65;$font->lastChar = 67;$font->widths = new PdfArray([ new PdfNumber(700), new PdfNumber(700), new PdfNumber(700),]);$font->encoding = $encodingRef;$font->addCharProc('square', $squareRef);$font->addCharProc('triangle', $triangleRef);$font->addCharProc('star', $starRef);$font->resources = new PdfDictionary(['ProcSet' => new PdfArray([new PdfName('PDF')])]);
$customName = $writer->addFont($font)->getResourceName();
$cs = $writer->addContentStream($page);$cs->beginText()->setFont($caption, 22)->moveTextPosition(72, 740) ->showText('Type 3 custom glyphs')->endText();
$cs->beginText()->setFont($caption, 11)->moveTextPosition(72, 700) ->showText('A, B and C have been remapped to a square, triangle and star.') ->endText();
// Paint "ABC" at 96pt.$cs->beginText()->setFont($customName, 96)->moveTextPosition(72, 540) ->showText('ABC')->endText();
// Mixed with regular text on the next line.$cs->beginText()->setFont($customName, 32)->moveTextPosition(72, 460) ->showText('AAA BBB CCC')->endText();
$writer->save('type3-custom.pdf');