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

Documentation generated on Sat, 24 Mar 2007 10:00:21 +0100 by phpDocumentor 1.3.1