Error: encoding not found: ' . $enc); } $cc2gn = array(); foreach ($a as $l) { if ($l[0] == '!') { $e = preg_split('/[ \\t]+/', rtrim($l)); $cc = hexdec(substr($e[0], 1)); $gn = $e[2]; $cc2gn[$cc] = $gn; } } for ($i = 0; $i <= 255; $i++) { if (!isset($cc2gn[$i])) { $cc2gn[$i] = '.notdef'; } } return $cc2gn; } function ReadAFM($file, &$map) { //Read a font metric file $a = file($file); if (empty($a)) { die('File not found'); } $widths = array(); $fm = array(); $fix = array( 'Edot' => 'Edotaccent', 'edot' => 'edotaccent', 'Idot' => 'Idotaccent', 'Zdot' => 'Zdotaccent', 'zdot' => 'zdotaccent', 'Odblacute' => 'Ohungarumlaut', 'odblacute' => 'ohungarumlaut', 'Udblacute' => 'Uhungarumlaut', 'udblacute' => 'uhungarumlaut', 'Gcedilla' => 'Gcommaaccent', 'gcedilla' => 'gcommaaccent', 'Kcedilla' => 'Kcommaaccent', 'kcedilla' => 'kcommaaccent', 'Lcedilla' => 'Lcommaaccent', 'lcedilla' => 'lcommaaccent', 'Ncedilla' => 'Ncommaaccent', 'ncedilla' => 'ncommaaccent', 'Rcedilla' => 'Rcommaaccent', 'rcedilla' => 'rcommaaccent', 'Scedilla' => 'Scommaaccent', 'scedilla' => 'scommaaccent', 'Tcedilla' => 'Tcommaaccent', 'tcedilla' => 'tcommaaccent', 'Dslash' => 'Dcroat', 'dslash' => 'dcroat', 'Dmacron' => 'Dcroat', 'dmacron' => 'dcroat', 'combininggraveaccent' => 'gravecomb', 'combininghookabove' => 'hookabovecomb', 'combiningtildeaccent' => 'tildecomb', 'combiningacuteaccent' => 'acutecomb', 'combiningdotbelow' => 'dotbelowcomb', 'dongsign' => 'dong' ); foreach ($a as $l) { $e = explode(' ', rtrim($l)); if (count($e) < 2) { continue; } $code = $e[0]; $param = $e[1]; if ($code == 'C') { //Character metrics $cc = (int)$e[1]; $w = $e[4]; $gn = $e[7]; if (substr($gn, -4) == '20AC') { $gn = 'Euro'; } if (isset($fix[$gn])) { //Fix incorrect glyph name foreach ($map as $c => $n) { if ($n == $fix[$gn]) { $map[$c] = $gn; } } } if (empty($map)) { //Symbolic font: use built-in encoding $widths[$cc] = $w; } else { $widths[$gn] = $w; if ($gn == 'X') { $fm['CapXHeight'] = $e[13]; } } if ($gn == '.notdef') { $fm['MissingWidth'] = $w; } } elseif ($code == 'FontName') { $fm['FontName'] = $param; } elseif ($code == 'Weight') { $fm['Weight'] = $param; } elseif ($code == 'ItalicAngle') { $fm['ItalicAngle'] = (double)$param; } elseif ($code == 'Ascender') { $fm['Ascender'] = (int)$param; } elseif ($code == 'Descender') { $fm['Descender'] = (int)$param; } elseif ($code == 'UnderlineThickness') { $fm['UnderlineThickness'] = (int)$param; } elseif ($code == 'UnderlinePosition') { $fm['UnderlinePosition'] = (int)$param; } elseif ($code == 'IsFixedPitch') { $fm['IsFixedPitch'] = ($param == 'true'); } elseif ($code == 'FontBBox') { $fm['FontBBox'] = array( $e[1], $e[2], $e[3], $e[4] ); } elseif ($code == 'CapHeight') { $fm['CapHeight'] = (int)$param; } elseif ($code == 'StdVW') { $fm['StdVW'] = (int)$param; } } if (!isset($fm['FontName'])) { die('FontName not found'); } if (!empty($map)) { if (!isset($widths['.notdef'])) { $widths['.notdef'] = 600; } if (!isset($widths['Delta']) && isset($widths['increment'])) { $widths['Delta'] = $widths['increment']; } //Order widths according to map for ($i = 0; $i <= 255; $i++) { if (!isset($widths[$map[$i]])) { echo 'Warning: character ' . $map[$i] . ' is missing
'; $widths[$i] = $widths['.notdef']; } else { $widths[$i] = $widths[$map[$i]]; } } } $fm['Widths'] = $widths; return $fm; } function MakeFontDescriptor($fm, $symbolic) { //Ascent $asc = (isset($fm['Ascender']) ? $fm['Ascender'] : 1000); $fd = "array('Ascent'=>" . $asc; //Descent $desc = (isset($fm['Descender']) ? $fm['Descender'] : -200); $fd .= ",'Descent'=>" . $desc; //CapHeight if (isset($fm['CapHeight'])) { $ch = $fm['CapHeight']; } elseif (isset($fm['CapXHeight'])) { $ch = $fm['CapXHeight']; } else { $ch = $asc; } $fd .= ",'CapHeight'=>" . $ch; //Flags $flags = 0; if (isset($fm['IsFixedPitch']) && $fm['IsFixedPitch']) { $flags += 1 << 0; } if ($symbolic) { $flags += 1 << 2; } if (!$symbolic) { $flags += 1 << 5; } if (isset($fm['ItalicAngle']) && $fm['ItalicAngle'] != 0) { $flags += 1 << 6; } $fd .= ",'Flags'=>" . $flags; //FontBBox if (isset($fm['FontBBox'])) { $fbb = $fm['FontBBox']; } else { $fbb = array( 0, $desc - 100, 1000, $asc + 100 ); } $fd .= ",'FontBBox'=>'[" . $fbb[0] . ' ' . $fbb[1] . ' ' . $fbb[2] . ' ' . $fbb[3] . "]'"; //ItalicAngle $ia = (isset($fm['ItalicAngle']) ? $fm['ItalicAngle'] : 0); $fd .= ",'ItalicAngle'=>" . $ia; //StemV if (isset($fm['StdVW'])) { $stemv = $fm['StdVW']; } elseif (isset($fm['Weight']) && preg_match('/bold|black/i', $fm['Weight'])) { $stemv = 120; } else { $stemv = 70; } $fd .= ",'StemV'=>" . $stemv; //MissingWidth if (isset($fm['MissingWidth'])) { $fd .= ",'MissingWidth'=>" . $fm['MissingWidth']; } $fd .= ')'; return $fd; } function MakeWidthArray($fm) { //Make character width array $s = "array(\n\t"; $cw = $fm['Widths']; for ($i = 0; $i <= 255; $i++) { if (chr($i) == "'") { $s .= "'\\''"; } elseif (chr($i) == "\\") { $s .= "'\\\\'"; } elseif ($i >= 32 && $i <= 126) { $s .= "'" . chr($i) . "'"; } else { $s .= "chr($i)"; } $s .= '=>' . $fm['Widths'][$i]; if ($i < 255) { $s .= ','; } if (($i + 1) % 22 == 0) { $s .= "\n\t"; } } $s .= ')'; return $s; } function MakeFontEncoding($map) { //Build differences from reference encoding $ref = ReadMap('cp1252'); $s = ''; $last = 0; for ($i = 32; $i <= 255; $i++) { if ($map[$i] != $ref[$i]) { if ($i != $last + 1) { $s .= $i . ' '; } $last = $i; $s .= '/' . $map[$i] . ' '; } } return rtrim($s); } function SaveToFile($file, $s, $mode) { $f = fopen($file, 'w' . $mode); if (!$f) { die('Can\'t write to file ' . $file); } fwrite($f, $s, strlen($s)); fclose($f); } function ReadShort($f) { $a = unpack('n1n', fread($f, 2)); return $a['n']; } function ReadLong($f) { $a = unpack('N1N', fread($f, 4)); return $a['N']; } function CheckTTF($file) { //Check if font license allows embedding $f = fopen($file, 'rb'); if (!$f) { die('Error: Can\'t open ' . $file); } //Extract number of tables fseek($f, 4, SEEK_CUR); $nb = ReadShort($f); fseek($f, 6, SEEK_CUR); //Seek OS/2 table $found = false; for ($i = 0; $i < $nb; $i++) { if (fread($f, 4) == 'OS/2') { $found = true; break; } fseek($f, 12, SEEK_CUR); } if (!$found) { fclose($f); return; } fseek($f, 4, SEEK_CUR); $offset = ReadLong($f); fseek($f, $offset, SEEK_SET); //Extract fsType flags fseek($f, 8, SEEK_CUR); $fsType = ReadShort($f); $rl = ($fsType & 0x02) != 0; $pp = ($fsType & 0x04) != 0; $e = ($fsType & 0x08) != 0; fclose($f); if ($rl && !$pp && !$e) { echo 'Warning: font license does not allow embedding'; } } /******************************************************************************* * fontfile: path to TTF file (or empty string if not to be embedded) * * afmfile: path to AFM file * * enc: font encoding (or empty string for symbolic fonts) * * patch: optional patch for encoding * * type: font type if fontfile is empty * *******************************************************************************/ function MakeFont($fontfile, $afmfile, $enc = 'cp1252', $patch = array(), $type = 'TrueType') { //Generate a font definition file if (get_magic_quotes_runtime()) { @set_magic_quotes_runtime(0); } ini_set('auto_detect_line_endings', '1'); if ($enc) { $map = ReadMap($enc); foreach ($patch as $cc => $gn) { $map[$cc] = $gn; } } else { $map = array(); } if (!file_exists($afmfile)) { die('Error: AFM file not found: ' . $afmfile); } $fm = ReadAFM($afmfile, $map); if ($enc) { $diff = MakeFontEncoding($map); } else { $diff = ''; } $fd = MakeFontDescriptor($fm, empty($map)); //Find font type if ($fontfile) { $ext = strtolower(substr($fontfile, -3)); if ($ext == 'ttf') { $type = 'TrueType'; } elseif ($ext == 'pfb') { $type = 'Type1'; } else { die('Error: unrecognized font file extension: ' . $ext); } } else { if ($type != 'TrueType' && $type != 'Type1') { die('Error: incorrect font type: ' . $type); } } //Start generation $s = 'Error: font file not found: ' . $fontfile); } if ($type == 'TrueType') { CheckTTF($fontfile); } $f = fopen($fontfile, 'rb'); if (!$f) { die('Error: Can\'t open ' . $fontfile); } $file = fread($f, filesize($fontfile)); fclose($f); if ($type == 'Type1') { //Find first two sections and discard third one $header = (ord($file[0]) == 128); if ($header) { //Strip first binary header $file = substr($file, 6); } $pos = strpos($file, 'eexec'); if (!$pos) { die('Error: font file does not seem to be valid Type1'); } $size1 = $pos + 6; if ($header && ord($file[$size1]) == 128) { //Strip second binary header $file = substr($file, 0, $size1) . substr($file, $size1 + 6); } $pos = strpos($file, '00000000'); if (!$pos) { die('Error: font file does not seem to be valid Type1'); } $size2 = $pos - $size1; $file = substr($file, 0, $size1 + $size2); } if (function_exists('gzcompress')) { $cmp = $basename . '.z'; SaveToFile($cmp, gzcompress($file), 'b'); $s .= '$file=\'' . $cmp . "';\n"; echo 'Font file compressed (' . $cmp . ')
'; } else { $s .= '$file=\'' . basename($fontfile) . "';\n"; echo 'Notice: font file could not be compressed (zlib extension not available)
'; } if ($type == 'Type1') { $s .= '$size1=' . $size1 . ";\n"; $s .= '$size2=' . $size2 . ";\n"; } else { $s .= '$originalsize=' . filesize($fontfile) . ";\n"; } } else { //Not embedded font $s .= '$file=' . "'';\n"; } $s .= "?>\n"; SaveToFile($basename . '.php', $s, 't'); echo 'Font definition file generated (' . $basename . '.php' . ')
'; }