mirror of
https://github.com/rmontanana/inventario2.git
synced 2025-08-15 23:45:58 +00:00
433 lines
13 KiB
PHP
433 lines
13 KiB
PHP
<?php
|
|
/*******************************************************************************
|
|
* Utility to generate font definition files *
|
|
* *
|
|
* Version: 1.14 *
|
|
* Date: 2008-08-03 *
|
|
* Author: Olivier PLATHEY *
|
|
*******************************************************************************/
|
|
|
|
function ReadMap($enc)
|
|
{
|
|
//Read a map file
|
|
$file = dirname(__FILE__).'/'.strtolower($enc).'.map';
|
|
$a = file($file);
|
|
if (empty($a)) {
|
|
die('<b>Error:</b> encoding not found: '.$enc);
|
|
}
|
|
$cc2gn = [];
|
|
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 = [];
|
|
$fm = [];
|
|
$fix = ['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'] = (float) $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'] = [$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 '<b>Warning:</b> character '.$map[$i].' is missing<br>';
|
|
$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 = [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('<b>Error:</b> 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 '<b>Warning:</b> 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 = [], $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 = [];
|
|
}
|
|
if (!file_exists($afmfile)) {
|
|
die('<b>Error:</b> 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('<b>Error:</b> unrecognized font file extension: '.$ext);
|
|
}
|
|
} else {
|
|
if ($type != 'TrueType' && $type != 'Type1') {
|
|
die('<b>Error:</b> incorrect font type: '.$type);
|
|
}
|
|
}
|
|
//Start generation
|
|
$s = '<?php'."\n";
|
|
$s .= '$type=\''.$type."';\n";
|
|
$s .= '$name=\''.$fm['FontName']."';\n";
|
|
$s .= '$desc='.$fd.";\n";
|
|
if (!isset($fm['UnderlinePosition'])) {
|
|
$fm['UnderlinePosition'] = -100;
|
|
}
|
|
if (!isset($fm['UnderlineThickness'])) {
|
|
$fm['UnderlineThickness'] = 50;
|
|
}
|
|
$s .= '$up='.$fm['UnderlinePosition'].";\n";
|
|
$s .= '$ut='.$fm['UnderlineThickness'].";\n";
|
|
$w = MakeWidthArray($fm);
|
|
$s .= '$cw='.$w.";\n";
|
|
$s .= '$enc=\''.$enc."';\n";
|
|
$s .= '$diff=\''.$diff."';\n";
|
|
$basename = substr(basename($afmfile), 0, -4);
|
|
if ($fontfile) {
|
|
//Embedded font
|
|
if (!file_exists($fontfile)) {
|
|
die('<b>Error:</b> font file not found: '.$fontfile);
|
|
}
|
|
if ($type == 'TrueType') {
|
|
CheckTTF($fontfile);
|
|
}
|
|
$f = fopen($fontfile, 'rb');
|
|
if (!$f) {
|
|
die('<b>Error:</b> 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('<b>Error:</b> 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('<b>Error:</b> 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.')<br>';
|
|
} else {
|
|
$s .= '$file=\''.basename($fontfile)."';\n";
|
|
echo '<b>Notice:</b> font file could not be compressed (zlib extension not available)<br>';
|
|
}
|
|
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'.')<br>';
|
|
}
|