Source for file makefont.php

Documentation is available at makefont.php

  1. <?php
  2. /*******************************************************************************
  3. * Utility to generate font definition files                                    *
  4. * Version: 1.13                                                                *
  5. * Date:    2004-12-31                                                          *
  6. *******************************************************************************/
  7.  
  8. function ReadMap($enc)
  9. {
  10.     //Read a map file
  11.     $file=dirname(__FILE__).'/'.strtolower($enc).'.map';
  12.     $a=file($file);
  13.     if(empty($a))
  14.         die('<B>Error:</B> encoding not found: '.$enc);
  15.     $cc2gn=array();
  16.     foreach($a as $l)
  17.     {
  18.         if($l{0}=='!')
  19.         {
  20.             $e=preg_split('/[ \\t]+/',rtrim($l));
  21.             $cc=hexdec(substr($e[0],1));
  22.             $gn=$e[2];
  23.             $cc2gn[$cc]=$gn;
  24.         }
  25.     }
  26.     for($i=0;$i<=255;$i++)
  27.     {
  28.         if(!isset($cc2gn[$i]))
  29.             $cc2gn[$i]='.notdef';
  30.     }
  31.     return $cc2gn;
  32. }
  33.  
  34. function ReadAFM($file,&$map)
  35. {
  36.     //Read a font metric file
  37.     $a=file($file);
  38.     if(empty($a))
  39.         die('File not found');
  40.     $widths=array();
  41.     $fm=array();
  42.     $fix=array('Edot'=>'Edotaccent','edot'=>'edotaccent','Idot'=>'Idotaccent','Zdot'=>'Zdotaccent','zdot'=>'zdotaccent',
  43.         'Odblacute'=>'Ohungarumlaut','odblacute'=>'ohungarumlaut','Udblacute'=>'Uhungarumlaut','udblacute'=>'uhungarumlaut',
  44.         'Gcedilla'=>'Gcommaaccent','gcedilla'=>'gcommaaccent','Kcedilla'=>'Kcommaaccent','kcedilla'=>'kcommaaccent',
  45.         'Lcedilla'=>'Lcommaaccent','lcedilla'=>'lcommaaccent','Ncedilla'=>'Ncommaaccent','ncedilla'=>'ncommaaccent',
  46.         'Rcedilla'=>'Rcommaaccent','rcedilla'=>'rcommaaccent','Scedilla'=>'Scommaaccent','scedilla'=>'scommaaccent',
  47.         'Tcedilla'=>'Tcommaaccent','tcedilla'=>'tcommaaccent','Dslash'=>'Dcroat','dslash'=>'dcroat','Dmacron'=>'Dcroat','dmacron'=>'dcroat',
  48.         'combininggraveaccent'=>'gravecomb','combininghookabove'=>'hookabovecomb','combiningtildeaccent'=>'tildecomb',
  49.         'combiningacuteaccent'=>'acutecomb','combiningdotbelow'=>'dotbelowcomb','dongsign'=>'dong');
  50.     foreach($a as $l)
  51.     {
  52.         $e=explode(' ',rtrim($l));
  53.         if(count($e)<2)
  54.             continue;
  55.         $code=$e[0];
  56.         $param=$e[1];
  57.         if($code=='C')
  58.         {
  59.             //Character metrics
  60.             $cc=(int)$e[1];
  61.             $w=$e[4];
  62.             $gn=$e[7];
  63.             if(substr($gn,-4)=='20AC')
  64.                 $gn='Euro';
  65.             if(isset($fix[$gn]))
  66.             {
  67.                 //Fix incorrect glyph name
  68.                 foreach($map as $c=>$n)
  69.                 {
  70.                     if($n==$fix[$gn])
  71.                         $map[$c]=$gn;
  72.                 }
  73.             }
  74.             if(empty($map))
  75.             {
  76.                 //Symbolic font: use built-in encoding
  77.                 $widths[$cc]=$w;
  78.             }
  79.             else
  80.             {
  81.                 $widths[$gn]=$w;
  82.                 if($gn=='X')
  83.                     $fm['CapXHeight']=$e[13];
  84.             }
  85.             if($gn=='.notdef')
  86.                 $fm['MissingWidth']=$w;
  87.         }
  88.         elseif($code=='FontName')
  89.             $fm['FontName']=$param;
  90.         elseif($code=='Weight')
  91.             $fm['Weight']=$param;
  92.         elseif($code=='ItalicAngle')
  93.             $fm['ItalicAngle']=(double)$param;
  94.         elseif($code=='Ascender')
  95.             $fm['Ascender']=(int)$param;
  96.         elseif($code=='Descender')
  97.             $fm['Descender']=(int)$param;
  98.         elseif($code=='UnderlineThickness')
  99.             $fm['UnderlineThickness']=(int)$param;
  100.         elseif($code=='UnderlinePosition')
  101.             $fm['UnderlinePosition']=(int)$param;
  102.         elseif($code=='IsFixedPitch')
  103.             $fm['IsFixedPitch']=($param=='true');
  104.         elseif($code=='FontBBox')
  105.             $fm['FontBBox']=array($e[1],$e[2],$e[3],$e[4]);
  106.         elseif($code=='CapHeight')
  107.             $fm['CapHeight']=(int)$param;
  108.         elseif($code=='StdVW')
  109.             $fm['StdVW']=(int)$param;
  110.     }
  111.     if(!isset($fm['FontName']))
  112.         die('FontName not found');
  113.     if(!empty($map))
  114.     {
  115.         if(!isset($widths['.notdef']))
  116.             $widths['.notdef']=600;
  117.         if(!isset($widths['Delta']and isset($widths['increment']))
  118.             $widths['Delta']=$widths['increment'];
  119.         //Order widths according to map
  120.         for($i=0;$i<=255;$i++)
  121.         {
  122.             if(!isset($widths[$map[$i]]))
  123.             {
  124.                 echo '<B>Warning:</B> character '.$map[$i].' is missing<BR>';
  125.                 $widths[$i]=$widths['.notdef'];
  126.             }
  127.             else
  128.                 $widths[$i]=$widths[$map[$i]];
  129.         }
  130.     }
  131.     $fm['Widths']=$widths;
  132.     return $fm;
  133. }
  134.  
  135. function MakeFontDescriptor($fm,$symbolic)
  136. {
  137.     //Ascent
  138.     $asc=(isset($fm['Ascender']$fm['Ascender'1000);
  139.     $fd="array('Ascent'=>".$asc;
  140.     //Descent
  141.     $desc=(isset($fm['Descender']$fm['Descender': -200);
  142.     $fd.=",'Descent'=>".$desc;
  143.     //CapHeight
  144.     if(isset($fm['CapHeight']))
  145.         $ch=$fm['CapHeight'];
  146.     elseif(isset($fm['CapXHeight']))
  147.         $ch=$fm['CapXHeight'];
  148.     else
  149.         $ch=$asc;
  150.     $fd.=",'CapHeight'=>".$ch;
  151.     //Flags
  152.     $flags=0;
  153.     if(isset($fm['IsFixedPitch']and $fm['IsFixedPitch'])
  154.         $flags+=1<<0;
  155.     if($symbolic)
  156.         $flags+=1<<2;
  157.     if(!$symbolic)
  158.         $flags+=1<<5;
  159.     if(isset($fm['ItalicAngle']and $fm['ItalicAngle']!=0)
  160.         $flags+=1<<6;
  161.     $fd.=",'Flags'=>".$flags;
  162.     //FontBBox
  163.     if(isset($fm['FontBBox']))
  164.         $fbb=$fm['FontBBox'];
  165.     else
  166.         $fbb=array(0,$des-100,1000,$asc+100);
  167.     $fd.=",'FontBBox'=>'[".$fbb[0].' '.$fbb[1].' '.$fbb[2].' '.$fbb[3]."]'";
  168.     //ItalicAngle
  169.     $ia=(isset($fm['ItalicAngle']$fm['ItalicAngle'0);
  170.     $fd.=",'ItalicAngle'=>".$ia;
  171.     //StemV
  172.     if(isset($fm['StdVW']))
  173.         $stemv=$fm['StdVW'];
  174.     elseif(isset($fm['Weight']and eregi('(bold|black)',$fm['Weight']))
  175.         $stemv=120;
  176.     else
  177.         $stemv=70;
  178.     $fd.=",'StemV'=>".$stemv;
  179.     //MissingWidth
  180.     if(isset($fm['MissingWidth']))
  181.         $fd.=",'MissingWidth'=>".$fm['MissingWidth'];
  182.     $fd.=')';
  183.     return $fd;
  184. }
  185.  
  186. function MakeWidthArray($fm)
  187. {
  188.     //Make character width array
  189.     $s="array(\n\t";
  190.     $cw=$fm['Widths'];
  191.     for($i=0;$i<=255;$i++)
  192.     {
  193.         if(chr($i)=="'")
  194.             $s.="'\\''";
  195.         elseif(chr($i)=="\\")
  196.             $s.="'\\\\'";
  197.         elseif($i>=32 and $i<=126)
  198.             $s.="'".chr($i)."'";
  199.         else
  200.             $s.="chr($i)";
  201.         $s.='=>'.$fm['Widths'][$i];
  202.         if($i<255)
  203.             $s.=',';
  204.         if(($i+1)%22==0)
  205.             $s.="\n\t";
  206.     }
  207.     $s.=')';
  208.     return $s;
  209. }
  210.  
  211. function MakeFontEncoding($map)
  212. {
  213.     //Build differences from reference encoding
  214.     $ref=ReadMap('cp1252');
  215.     $s='';
  216.     $last=0;
  217.     for($i=32;$i<=255;$i++)
  218.     {
  219.         if($map[$i]!=$ref[$i])
  220.         {
  221.             if($i!=$last+1)
  222.                 $s.=$i.' ';
  223.             $last=$i;
  224.             $s.='/'.$map[$i].' ';
  225.         }
  226.     }
  227.     return rtrim($s);
  228. }
  229.  
  230. function SaveToFile($file,$s,$mode='t')
  231. {
  232.     $f=fopen($file,'w'.$mode);
  233.     if(!$f)
  234.         die('Can\'t write to file '.$file);
  235.     fwrite($f,$s,strlen($s));
  236.     fclose($f);
  237. }
  238.  
  239. function ReadShort($f)
  240. {
  241.     $a=unpack('n1n',fread($f,2));
  242.     return $a['n'];
  243. }
  244.  
  245. function ReadLong($f)
  246. {
  247.     $a=unpack('N1N',fread($f,4));
  248.     return $a['N'];
  249. }
  250.  
  251. function CheckTTF($file)
  252. {
  253.     //Check if font license allows embedding
  254.     $f=fopen($file,'rb');
  255.     if(!$f)
  256.         die('<B>Error:</B> Can\'t open '.$file);
  257.     //Extract number of tables
  258.     fseek($f,4,SEEK_CUR);
  259.     $nb=ReadShort($f);
  260.     fseek($f,6,SEEK_CUR);
  261.     //Seek OS/2 table
  262.     $found=false;
  263.     for($i=0;$i<$nb;$i++)
  264.     {
  265.         if(fread($f,4)=='OS/2')
  266.         {
  267.             $found=true;
  268.             break;
  269.         }
  270.         fseek($f,12,SEEK_CUR);
  271.     }
  272.     if(!$found)
  273.     {
  274.         fclose($f);
  275.         return;
  276.     }
  277.     fseek($f,4,SEEK_CUR);
  278.     $offset=ReadLong($f);
  279.     fseek($f,$offset,SEEK_SET);
  280.     //Extract fsType flags
  281.     fseek($f,8,SEEK_CUR);
  282.     $fsType=ReadShort($f);
  283.     $rl=($fsType 0x02)!=0;
  284.     $pp=($fsType 0x04)!=0;
  285.     $e=($fsType 0x08)!=0;
  286.     fclose($f);
  287.     if($rl and !$pp and !$e)
  288.         echo '<B>Warning:</B> font license does not allow embedding';
  289. }
  290.  
  291. /*******************************************************************************
  292. * $fontfile : chemin du fichier TTF (ou chaîne vide si pas d'incorporation)    *
  293. * $afmfile :  chemin du fichier AFM                                            *
  294. * $enc :      encodage (ou chaîne vide si la police est symbolique)            *
  295. * $patch :    patch optionnel pour l'encodage                                  *
  296. * $type :     type de la police si $fontfile est vide                          *
  297. *******************************************************************************/
  298. function MakeFont($fontfile,$afmfile,$enc='cp1252',$patch=array(),$type='TrueType')
  299. {
  300.     //Generate a font definition file
  301.     ini_set('auto_detect_line_endings','1');
  302.     if($enc)
  303.     {
  304.         $map=ReadMap($enc);
  305.         foreach($patch as $cc=>$gn)
  306.             $map[$cc]=$gn;
  307.     }
  308.     else
  309.         $map=array();
  310.     if(!file_exists($afmfile))
  311.         die('<B>Error:</B> AFM file not found: '.$afmfile);
  312.     $fm=ReadAFM($afmfile,$map);
  313.     if($enc)
  314.         $diff=MakeFontEncoding($map);
  315.     else
  316.         $diff='';
  317.     $fd=MakeFontDescriptor($fm,empty($map));
  318.     //Find font type
  319.     if($fontfile)
  320.     {
  321.         $ext=strtolower(substr($fontfile,-3));
  322.         if($ext=='ttf')
  323.             $type='TrueType';
  324.         elseif($ext=='pfb')
  325.             $type='Type1';
  326.         else
  327.             die('<B>Error:</B> unrecognized font file extension: '.$ext);
  328.     }
  329.     else
  330.     {
  331.         if($type!='TrueType' and $type!='Type1')
  332.             die('<B>Error:</B> incorrect font type: '.$type);
  333.     }
  334.     //Start generation
  335.     $s='<?php'."\n";
  336.     $s.='$type=\''.$type."';\n";
  337.     $s.='$name=\''.$fm['FontName']."';\n";
  338.     $s.='$desc='.$fd.";\n";
  339.     if(!isset($fm['UnderlinePosition']))
  340.         $fm['UnderlinePosition']=-100;
  341.     if(!isset($fm['UnderlineThickness']))
  342.         $fm['UnderlineThickness']=50;
  343.     $s.='$up='.$fm['UnderlinePosition'].";\n";
  344.     $s.='$ut='.$fm['UnderlineThickness'].";\n";
  345.     $w=MakeWidthArray($fm);
  346.     $s.='$cw='.$w.";\n";
  347.     $s.='$enc=\''.$enc."';\n";
  348.     $s.='$diff=\''.$diff."';\n";
  349.     $basename=substr(basename($afmfile),0,-4);
  350.     if($fontfile)
  351.     {
  352.         //Embedded font
  353.         if(!file_exists($fontfile))
  354.             die('<B>Error:</B> font file not found: '.$fontfile);
  355.         if($type=='TrueType')
  356.             CheckTTF($fontfile);
  357.         $f=fopen($fontfile,'rb');
  358.         if(!$f)
  359.             die('<B>Error:</B> Can\'t open '.$fontfile);
  360.         $file=fread($f,filesize($fontfile));
  361.         fclose($f);
  362.         if($type=='Type1')
  363.         {
  364.             //Find first two sections and discard third one
  365.             $header=(ord($file{0})==128);
  366.             if($header)
  367.             {
  368.                 //Strip first binary header
  369.                 $file=substr($file,6);
  370.             }
  371.             $pos=strpos($file,'eexec');
  372.             if(!$pos)
  373.                 die('<B>Error:</B> font file does not seem to be valid Type1');
  374.             $size1=$pos+6;
  375.             if($header and ord($file{$size1})==128)
  376.             {
  377.                 //Strip second binary header
  378.                 $file=substr($file,0,$size1).substr($file,$size1+6);
  379.             }
  380.             $pos=strpos($file,'00000000');
  381.             if(!$pos)
  382.                 die('<B>Error:</B> font file does not seem to be valid Type1');
  383.             $size2=$pos-$size1;
  384.             $file=substr($file,0,$size1+$size2);
  385.         }
  386.         if(function_exists('gzcompress'))
  387.         {
  388.             $cmp=$basename.'.z';
  389.             SaveToFile($cmp,gzcompress($file),'b');
  390.             $s.='$file=\''.$cmp."';\n";
  391.             echo 'Font file compressed ('.$cmp.')<BR>';
  392.         }
  393.         else
  394.         {
  395.             $s.='$file=\''.basename($fontfile)."';\n";
  396.             echo '<B>Notice:</B> font file could not be compressed (zlib extension not available)<BR>';
  397.         }
  398.         if($type=='Type1')
  399.         {
  400.             $s.='$size1='.$size1.";\n";
  401.             $s.='$size2='.$size2.";\n";
  402.         }
  403.         else
  404.             $s.='$originalsize='.filesize($fontfile).";\n";
  405.     }
  406.     else
  407.     {
  408.         //Not embedded font
  409.         $s.='$file='."'';\n";
  410.     }
  411.     $s.="?>\n";
  412.     SaveToFile($basename.'.php',$s);
  413.     echo 'Font definition file generated ('.$basename.'.php'.')<BR>';
  414. }
  415. ?>

Documentation generated on Thu, 08 Jan 2009 17:44:36 +0100 by phpDocumentor 1.4.0a2