makefont.php
411 lines
| 10.5 KiB
| text/x-php
|
XmlPhpLexer
|
r5127 | |||
#***************************************************************************** | ||||
# Utility to generate font definition files # | ||||
# Version: 1.13 # | ||||
# Date: 2004-12-31 # | ||||
******************************************************************************# | ||||
function ReadMap($enc) | ||||
{ | ||||
#Read a map file | ||||
$file=dirname(__FILE__) + '/' + $enc.downcase + '.map'; | ||||
$a=file($file); | ||||
if ($a)) | ||||
die('<B>Error:</B> encoding not found: '.$enc); | ||||
$cc2gn = [] | ||||
foreach($a as $l) | ||||
{ | ||||
if ($l{0}=='!') | ||||
{ | ||||
$e=rtrim($l).scan('/[ \\t]+/'); | ||||
$cc=hexdec(substr($e[0],1)); | ||||
$gn=$e[2]; | ||||
$cc2gn[$cc]=$gn; | ||||
end | ||||
end | ||||
for($i=0;$i<=255;$i++) | ||||
{ | ||||
if (!$cc2gn[$i].nil?) | ||||
$cc2gn[$i]='.notdef'; | ||||
end | ||||
return $cc2gn; | ||||
} | ||||
function ReadAFM($file,&$map) | ||||
{ | ||||
#Read a font metric file | ||||
$a=file($file); | ||||
if ($a.empty?) | ||||
die('File not found'); | ||||
$widths = [] | ||||
$fm = [] | ||||
$fix=Hash.new('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 ($e.length<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 ($fix[$gn].nil?) | ||||
{ | ||||
#Fix incorrect glyph name | ||||
foreach($map as $c=>$n) | ||||
{ | ||||
if ($n==$fix[$gn]) | ||||
$map[$c]=$gn; | ||||
end | ||||
end | ||||
if ($map.empty?) | ||||
{ | ||||
#Symbolic font: use built-in encoding | ||||
$widths[$cc]=$w; | ||||
else | ||||
{ | ||||
$widths[$gn]=$w; | ||||
if ($gn=='X') | ||||
$fm['CapXHeight']=$e[13]; | ||||
end | ||||
if ($gn=='.notdef') | ||||
$fm['MissingWidth']=$w; | ||||
elsif ($code=='FontName') | ||||
$fm['FontName']=$param; | ||||
elsif ($code=='Weight') | ||||
$fm['Weight']=$param; | ||||
elsif ($code=='ItalicAngle') | ||||
$fm['ItalicAngle']=(double)$param; | ||||
elsif ($code=='Ascender') | ||||
$fm['Ascender']=(int)$param; | ||||
elsif ($code=='Descender') | ||||
$fm['Descender']=(int)$param; | ||||
elsif ($code=='UnderlineThickness') | ||||
$fm['UnderlineThickness']=(int)$param; | ||||
elsif ($code=='UnderlinePosition') | ||||
$fm['UnderlinePosition']=(int)$param; | ||||
elsif ($code=='IsFixedPitch') | ||||
$fm['IsFixedPitch']=($param=='true'); | ||||
elsif ($code=='FontBBox') | ||||
$fm['FontBBox']=Hash.new($e[1],$e[2],$e[3],$e[4]); | ||||
elsif ($code=='CapHeight') | ||||
$fm['CapHeight']=(int)$param; | ||||
elsif ($code=='StdVW') | ||||
$fm['StdVW']=(int)$param; | ||||
end | ||||
if (!$fm['FontName'].nil?) | ||||
die('FontName not found'); | ||||
if (!$map.empty?) | ||||
{ | ||||
if (!$widths['.notdef'].nil?) | ||||
$widths['.notdef']=600; | ||||
if (!$widths['Delta'].nil? and $widths['increment'].nil?) | ||||
$widths['Delta']=$widths['increment']; | ||||
#Order widths according to map | ||||
for($i=0;$i<=255;$i++) | ||||
{ | ||||
if (!$widths[$map[$i]].nil?) | ||||
{ | ||||
echo '<B>Warning:</B> character '.$map[$i].' is missing<BR>'; | ||||
$widths[$i]=$widths['.notdef']; | ||||
else | ||||
$widths[$i]=$widths[$map[$i]]; | ||||
end | ||||
end | ||||
$fm['Widths']=$widths; | ||||
return $fm; | ||||
} | ||||
function MakeFontDescriptor($fm,$symbolic) | ||||
{ | ||||
#Ascent | ||||
$asc=($fm['Ascender'].nil? ? $fm['Ascender'] : 1000); | ||||
$fd="Hash.new('Ascent'=>".$asc; | ||||
#Descent | ||||
$desc=($fm['Descender'].nil? ? $fm['Descender'] : -200); | ||||
$fd<<",'Descent'=>".$desc; | ||||
#CapHeight | ||||
if ($fm['CapHeight'].nil?) | ||||
$ch=$fm['CapHeight']; | ||||
elsif ($fm['CapXHeight'].nil?) | ||||
$ch=$fm['CapXHeight']; | ||||
else | ||||
$ch=$asc; | ||||
$fd<<",'CapHeight'=>".$ch; | ||||
#Flags | ||||
$flags=0; | ||||
if ($fm['IsFixedPitch'].nil? and $fm['IsFixedPitch']) | ||||
$flags+=1<<0; | ||||
if ($symbolic) | ||||
$flags+=1<<2; | ||||
if (!$symbolic) | ||||
$flags+=1<<5; | ||||
if ($fm['ItalicAngle'].nil? and $fm['ItalicAngle']!=0) | ||||
$flags+=1<<6; | ||||
$fd<<",'Flags'=>".$flags; | ||||
#FontBBox | ||||
if ($fm['FontBBox'].nil?) | ||||
$fbb=$fm['FontBBox']; | ||||
else | ||||
$fbb=Hash.new(0,$des-100,1000,$asc+100); | ||||
$fd<<",'FontBBox'=>'[".$fbb[0].' '.$fbb[1].' '.$fbb[2].' '.$fbb[3]."]'"; | ||||
#ItalicAngle | ||||
$ia=($fm['ItalicAngle'].nil? ? $fm['ItalicAngle'] : 0); | ||||
$fd<<",'ItalicAngle'=>".$ia; | ||||
#StemV | ||||
if ($fm['StdVW'].nil?) | ||||
$stemv=$fm['StdVW']; | ||||
elsif ($fm['Weight'].nil? and eregi('(bold|black)',$fm['Weight'])) | ||||
$stemv=120; | ||||
else | ||||
$stemv=70; | ||||
$fd<<",'StemV'=>".$stemv; | ||||
#MissingWidth | ||||
if ($fm['MissingWidth'].nil?) | ||||
$fd<<",'MissingWidth'=>".$fm['MissingWidth']; | ||||
$fd<<')'; | ||||
return $fd; | ||||
} | ||||
function MakeWidthArray($fm) | ||||
{ | ||||
#Make character width array | ||||
$s="Hash.new(\n\t"; | ||||
$cw=$fm['Widths']; | ||||
for($i=0;$i<=255;$i++) | ||||
{ | ||||
if ($i.chr=="'") | ||||
$s<<"'\\''"; | ||||
elsif ($i.chr=="\\") | ||||
$s<<"'\\\\'"; | ||||
elsif ($i>=32 and $i<=126) | ||||
$s<<"'".$i.chr."'"; | ||||
else | ||||
$s<<"$i.chr"; | ||||
$s<<'=>'.$fm['Widths'][$i]; | ||||
if ($i<255) | ||||
$s<<','; | ||||
if (($i+1)%22==0) | ||||
$s<<"\n\t"; | ||||
end | ||||
$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].' '; | ||||
end | ||||
end | ||||
return rtrim($s); | ||||
} | ||||
function SaveToFile($file,$s,$mode='t') | ||||
{ | ||||
$f=fopen($file,'w'.$mode); | ||||
if (!$f) | ||||
die('Can\'t write to file '.$file); | ||||
fwrite($f,$s,$s.length); | ||||
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; | ||||
end | ||||
fseek($f,12,SEEK_CUR); | ||||
end | ||||
if (!$found) | ||||
{ | ||||
fclose($f); | ||||
return; | ||||
end | ||||
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 and !$pp and !$e) | ||||
echo '<B>Warning:</B> font license does not allow embedding'; | ||||
} | ||||
#***************************************************************************** | ||||
# $fontfile : chemin du fichier TTF (ou cha�ne vide si pas d'incorporation) # | ||||
# $afmfile : chemin du fichier AFM # | ||||
# $enc : encodage (ou cha�ne vide si la police est symbolique) # | ||||
# $patch : patch optionnel pour l'encodage # | ||||
# $type : type de la police si $fontfile est vide # | ||||
******************************************************************************# | ||||
function MakeFont($fontfile,$afmfile,$enc='cp1252',$patch=Hash.new(),$type='TrueType') | ||||
{ | ||||
#Generate a font definition file | ||||
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; | ||||
end | ||||
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,$map.empty?); | ||||
#Find font type | ||||
if ($fontfile) | ||||
{ | ||||
$ext=strtolower(substr($fontfile,-3)); | ||||
if ($ext=='ttf') | ||||
$type='TrueType'; | ||||
elsif ($ext=='pfb') | ||||
$type='Type1'; | ||||
else | ||||
die('<B>Error:</B> unrecognized font file extension: '.$ext); | ||||
end | ||||
else | ||||
{ | ||||
if ($type!='TrueType' and $type!='Type1') | ||||
die('<B>Error:</B> incorrect font type: '.$type); | ||||
end | ||||
#Start generation | ||||
$s=''."\n"; | ||||
$s<<'$type=\''.$type."';\n"; | ||||
$s<<'$name=\''.$fm['FontName']."';\n"; | ||||
$s<<'$desc='.$fd.";\n"; | ||||
if (!$fm['UnderlinePosition'].nil?) | ||||
$fm['UnderlinePosition']=-100; | ||||
if (!$fm['UnderlineThickness'].nil?) | ||||
$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=($file[0][0]==128); | ||||
if ($header) | ||||
{ | ||||
#Strip first binary header | ||||
$file=substr($file,6); | ||||
end | ||||
$pos=$file.include?('eexec'); | ||||
if (!$pos) | ||||
die('<B>Error:</B> font file does not seem to be valid Type1'); | ||||
$size1=$pos+6; | ||||
if ($header and ?($file{$size1})==128) | ||||
{ | ||||
#Strip second binary header | ||||
$file=substr($file,0,$size1).substr($file,$size1+6); | ||||
end | ||||
$pos=$file.include?('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); | ||||
end | ||||
if (respond_to('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>'; | ||||
end | ||||
if ($type=='Type1') | ||||
{ | ||||
$s<<'$size1='.$size1.";\n"; | ||||
$s<<'$size2='.$size2.";\n"; | ||||
else | ||||
$s<<'$originalsize='.filesize($fontfile).";\n"; | ||||
end | ||||
else | ||||
{ | ||||
#Not embedded font | ||||
$s<<'$file='."'';\n"; | ||||
end | ||||
$s<<"\n"; | ||||
SaveToFile($basename.'.rb',$s); | ||||
echo 'Font definition file generated ('.$basename.'.rb'.')<BR>'; | ||||
} | ||||