PHP Classes

File: src/FreePDF/makefont/makefont.php

Recommend this page to a friend!
  Classes of John Conde   PHP Free PDF Library   src/FreePDF/makefont/makefont.php   Download  
File: src/FreePDF/makefont/makefont.php
Role: Example script
Content type: text/plain
Description: Example script
Class: PHP Free PDF Library
Generate PDF documents programatically
Author: By
Last change:
Date: 1 year ago
Size: 12,729 bytes
 

Contents

Class file image Download
<?php use FreePDF\TTFParser; require('../TTFParser.php'); function Message($txt, $severity = ''): void { if (PHP_SAPI === 'cli') { if ($severity) { echo "$severity: "; } echo "$txt\n"; } else { if ($severity) { echo "<b>$severity</b>: "; } echo "$txt<br>"; } } function Notice($txt): void { Message($txt, 'Notice'); } function Warning($txt): void { Message($txt, 'Warning'); } function Error(string $txt): void { Message($txt, 'Error'); exit; } function LoadMap($enc): array { $file = __DIR__ . '/' . strtolower($enc) . '.map'; $a = file($file); if (empty($a)) { Error('Encoding not found: ' . $enc); } $map = array_fill(0, 256, array('uv' => -1, 'name' => '.notdef')); foreach ($a as $line) { $e = explode(' ', rtrim($line)); $c = hexdec(substr($e[0], 1)); $uv = hexdec(substr($e[1], 2)); $name = $e[2]; $map[$c] = array('uv' => $uv, 'name' => $name); } return $map; } function GetInfoFromTrueType($file, $embed, $subset, $map): array { // Return information from a TrueType font try { $ttf = new TTFParser($file); $ttf->Parse(); } catch (Exception $e) { Error($e->getMessage()); } if ($embed) { if (!$ttf->embeddable) { Error('Font license does not allow embedding'); } if ($subset) { $chars = array(); foreach ($map as $v) { if ($v['name'] !== '.notdef') { $chars[] = $v['uv']; } } $ttf->Subset($chars); $info['Data'] = $ttf->Build(); } else { $info['Data'] = file_get_contents($file); } $info['OriginalSize'] = strlen($info['Data']); } $k = 1000 / $ttf->unitsPerEm; $info['FontName'] = $ttf->postScriptName; $info['Bold'] = $ttf->bold; $info['ItalicAngle'] = $ttf->italicAngle; $info['IsFixedPitch'] = $ttf->isFixedPitch; $info['Ascender'] = round($k * $ttf->typoAscender); $info['Descender'] = round($k * $ttf->typoDescender); $info['UnderlineThickness'] = round($k * $ttf->underlineThickness); $info['UnderlinePosition'] = round($k * $ttf->underlinePosition); $info['FontBBox'] = array( round($k * $ttf->xMin), round($k * $ttf->yMin), round($k * $ttf->xMax), round($k * $ttf->yMax) ); $info['CapHeight'] = round($k * $ttf->capHeight); $info['MissingWidth'] = round($k * $ttf->glyphs[0]['w']); $widths = array_fill(0, 256, $info['MissingWidth']); foreach ($map as $c => $v) { if ($v['name'] !== '.notdef') { if (isset($ttf->chars[$v['uv']])) { $id = $ttf->chars[$v['uv']]; $w = $ttf->glyphs[$id]['w']; $widths[$c] = round($k * $w); } else { Warning('Character ' . $v['name'] . ' is missing'); } } } $info['Widths'] = $widths; return $info; } function GetInfoFromType1($file, $embed, $map): array { // Return information from a Type1 font if ($embed) { $f = fopen($file, 'rb'); if (!$f) { Error('Can\'t open font file'); } // Read first segment $a = unpack('Cmarker/Ctype/Vsize', fread($f, 6)); if ($a['marker'] != 128) { Error('Font file is not a valid binary Type1'); } $size1 = $a['size']; $data = fread($f, $size1); // Read second segment $a = unpack('Cmarker/Ctype/Vsize', fread($f, 6)); if ($a['marker'] != 128) { Error('Font file is not a valid binary Type1'); } $size2 = $a['size']; $data .= fread($f, $size2); fclose($f); $info['Data'] = $data; $info['Size1'] = $size1; $info['Size2'] = $size2; } $afm = substr($file, 0, -3) . 'afm'; if (!file_exists($afm)) { Error('AFM font file not found: ' . $afm); } $a = file($afm); if (empty($a)) { Error('AFM file empty or not readable'); } foreach ($a as $line) { $e = explode(' ', rtrim($line)); if (count($e) < 2) { continue; } $entry = $e[0]; if ($entry === 'C') { $w = $e[4]; $name = $e[7]; $cw[$name] = $w; } elseif ($entry === 'FontName') { $info['FontName'] = $e[1]; } elseif ($entry === 'Weight') { $info['Weight'] = $e[1]; } elseif ($entry === 'ItalicAngle') { $info['ItalicAngle'] = (int)$e[1]; } elseif ($entry === 'Ascender') { $info['Ascender'] = (int)$e[1]; } elseif ($entry === 'Descender') { $info['Descender'] = (int)$e[1]; } elseif ($entry === 'UnderlineThickness') { $info['UnderlineThickness'] = (int)$e[1]; } elseif ($entry === 'UnderlinePosition') { $info['UnderlinePosition'] = (int)$e[1]; } elseif ($entry === 'IsFixedPitch') { $info['IsFixedPitch'] = ($e[1] == 'true'); } elseif ($entry === 'FontBBox') { $info['FontBBox'] = array((int)$e[1], (int)$e[2], (int)$e[3], (int)$e[4]); } elseif ($entry === 'CapHeight') { $info['CapHeight'] = (int)$e[1]; } elseif ($entry === 'StdVW') { $info['StdVW'] = (int)$e[1]; } } if (!isset($info['FontName'])) { Error('FontName missing in AFM file'); } if (!isset($info['Ascender'])) { $info['Ascender'] = $info['FontBBox'][3]; } if (!isset($info['Descender'])) { $info['Descender'] = $info['FontBBox'][1]; } $info['Bold'] = isset($info['Weight']) && preg_match('/bold|black/i', $info['Weight']); if (isset($cw['.notdef'])) { $info['MissingWidth'] = $cw['.notdef']; } else { $info['MissingWidth'] = 0; } $widths = array_fill(0, 256, $info['MissingWidth']); foreach ($map as $c => $v) { if ($v['name'] !== '.notdef') { if (isset($cw[$v['name']])) { $widths[$c] = $cw[$v['name']]; } else { Warning('Character ' . $v['name'] . ' is missing'); } } } $info['Widths'] = $widths; return $info; } function MakeFontDescriptor($info): string { // Ascent $fd = "array('Ascent'=>" . $info['Ascender']; // Descent $fd .= ",'Descent'=>" . $info['Descender']; // CapHeight if (!empty($info['CapHeight'])) { $fd .= ",'CapHeight'=>" . $info['CapHeight']; } else { $fd .= ",'CapHeight'=>" . $info['Ascender']; } // Flags $flags = 0; if ($info['IsFixedPitch']) { $flags += 1 << 0; } $flags += 1 << 5; if ($info['ItalicAngle'] !== 0) { $flags += 1 << 6; } $fd .= ",'Flags'=>" . $flags; // FontBBox $fbb = $info['FontBBox']; $fd .= ",'FontBBox'=>'[" . $fbb[0] . ' ' . $fbb[1] . ' ' . $fbb[2] . ' ' . $fbb[3] . "]'"; // ItalicAngle $fd .= ",'ItalicAngle'=>" . $info['ItalicAngle']; // StemV if (isset($info['StdVW'])) { $stemv = $info['StdVW']; } elseif ($info['Bold']) { $stemv = 120; } else { $stemv = 70; } $fd .= ",'StemV'=>" . $stemv; // MissingWidth $fd .= ",'MissingWidth'=>" . $info['MissingWidth'] . ')'; return $fd; } function MakeWidthArray($widths): string { $s = "array(\n\t"; for ($c = 0; $c <= 255; $c++) { if (chr($c) === "'") { $s .= "'\\''"; } elseif (chr($c) === "\\") { $s .= "'\\\\'"; } elseif ($c >= 32 && $c <= 126) { $s .= "'" . chr($c) . "'"; } else { $s .= "chr($c)"; } $s .= '=>' . $widths[$c]; if ($c < 255) { $s .= ','; } if (($c + 1) % 22 === 0) { $s .= "\n\t"; } } $s .= ')'; return $s; } function MakeFontEncoding($map): string { // Build differences from reference encoding $ref = LoadMap('cp1252'); $s = ''; $last = 0; for ($c = 32; $c <= 255; $c++) { if ($map[$c]['name'] !== $ref[$c]['name']) { if ($c !== $last + 1) { $s .= $c . ' '; } $last = $c; $s .= '/' . $map[$c]['name'] . ' '; } } return rtrim($s); } function MakeUnicodeArray($map): string { // Build mapping to Unicode values $ranges = array(); foreach ($map as $c => $v) { $uv = $v['uv']; if ($uv !== -1) { if (isset($range)) { if ($c === $range[1] + 1 && $uv === $range[3] + 1) { $range[1]++; $range[3]++; } else { $ranges[] = $range; $range = array($c, $c, $uv, $uv); } } else { $range = array($c, $c, $uv, $uv); } } } $ranges[] = $range; foreach ($ranges as $range) { if (isset($s)) { $s .= ','; } else { $s = 'array('; } $s .= $range[0] . '=>'; $nb = $range[1] - $range[0] + 1; if ($nb > 1) { $s .= 'array(' . $range[2] . ',' . $nb . ')'; } else { $s .= $range[2]; } } $s .= ')'; return $s; } function SaveToFile($file, $s, $mode): void { $f = fopen($file, 'w' . $mode); if (!$f) { Error('Can\'t write to file ' . $file); } fwrite($f, $s); fclose($f); } function MakeDefinitionFile($file, $type, $enc, $embed, $subset, $map, $info): void { $s = "<?php\n"; $s .= '$type = \'' . $type . "';\n"; $s .= '$name = \'' . $info['FontName'] . "';\n"; $s .= '$desc = ' . MakeFontDescriptor($info) . ";\n"; $s .= '$up = ' . $info['UnderlinePosition'] . ";\n"; $s .= '$ut = ' . $info['UnderlineThickness'] . ";\n"; $s .= '$cw = ' . MakeWidthArray($info['Widths']) . ";\n"; $s .= '$enc = \'' . $enc . "';\n"; $diff = MakeFontEncoding($map); if ($diff) { $s .= '$diff = \'' . $diff . "';\n"; } $s .= '$uv = ' . MakeUnicodeArray($map) . ";\n"; if ($embed) { $s .= '$file = \'' . $info['File'] . "';\n"; if ($type === 'Type1') { $s .= '$size1 = ' . $info['Size1'] . ";\n"; $s .= '$size2 = ' . $info['Size2'] . ";\n"; } else { $s .= '$originalsize = ' . $info['OriginalSize'] . ";\n"; if ($subset) { $s .= "\$subsetted = true;\n"; } } } $s .= "?>\n"; SaveToFile($file, $s, 't'); } function MakeFont($fontfile, $enc = 'cp1252', $embed = true, $subset = true): void { // Generate a font definition file if (!file_exists($fontfile)) { Error('Font file not found: ' . $fontfile); } $ext = strtolower(substr($fontfile, -3)); if ($ext === 'ttf' || $ext === 'otf') { $type = 'TrueType'; } elseif ($ext === 'pfb') { $type = 'Type1'; } else { Error('Unrecognized font file extension: ' . $ext); } $map = LoadMap($enc); if ($type === 'TrueType') { $info = GetInfoFromTrueType($fontfile, $embed, $subset, $map); } else { $info = GetInfoFromType1($fontfile, $embed, $map); } $basename = substr(basename($fontfile), 0, -4); if ($embed) { if (function_exists('gzcompress')) { $file = $basename . '.z'; SaveToFile($file, gzcompress($info['Data']), 'b'); $info['File'] = $file; Message('Font file compressed: ' . $file); } else { $info['File'] = basename($fontfile); $subset = false; Notice('Font file could not be compressed (zlib extension not available)'); } } MakeDefinitionFile($basename . '.php', $type, $enc, $embed, $subset, $map, $info); Message('Font definition file generated: ' . $basename . '.php'); } if (PHP_SAPI === 'cli') { // Command-line interface ini_set('log_errors', '0'); if ($argc === 1) { die("Usage: php makefont.php fontfile [encoding] [embed] [subset]\n"); } $fontfile = $argv[1]; if ($argc >= 3) { $enc = $argv[2]; } else { $enc = 'cp1252'; } if ($argc >= 4) { $embed = ($argv[3] == 'true' || $argv[3] == '1'); } else { $embed = true; } if ($argc >= 5) { $subset = ($argv[4] == 'true' || $argv[4] == '1'); } else { $subset = true; } MakeFont($fontfile, $enc, $embed, $subset); }