1<?php 2/******************************************************************************* 3 * Utility to generate font definition files * 4 * Version: 1.13 * 5 * Date: 2004-12-31 * 6 *******************************************************************************/ 7 8function 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 34function 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 135function 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 186function 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 211function 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 230function 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 239function ReadShort($f) 240{ 241 $a=unpack('n1n',fread($f,2)); 242 return $a['n']; 243} 244 245function ReadLong($f) 246{ 247 $a=unpack('N1N',fread($f,4)); 248 return $a['N']; 249} 250 251function 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 *******************************************************************************/ 298function MakeFont($fontfile,$afmfile,$destdir,$destfile,$enc='cp1252',$patch=array(),$type='TrueType') 299{ 300 //Generate a font definition file 301 set_magic_quotes_runtime(0); 302 ini_set('auto_detect_line_endings','1'); 303 if($enc) 304 { 305 $map=ReadMap($enc); 306 foreach($patch as $cc=>$gn) 307 $map[$cc]=$gn; 308 } 309 else 310 $map=array(); 311 if(!file_exists($afmfile)) 312 die('<B>Error:</B> AFM file not found: '.$afmfile); 313 $fm=ReadAFM($afmfile,$map); 314 if($enc) 315 $diff=MakeFontEncoding($map); 316 else 317 $diff=''; 318 $fd=MakeFontDescriptor($fm,empty($map)); 319 //Find font type 320 if($fontfile) 321 { 322 $ext=strtolower(substr($fontfile,-3)); 323 if($ext=='ttf') 324 $type='TrueType'; 325 elseif($ext=='pfb') 326 $type='Type1'; 327 else 328 die('<B>Error:</B> unrecognized font file extension: '.$ext); 329 } 330 else 331 { 332 if($type!='TrueType' and $type!='Type1') 333 die('<B>Error:</B> incorrect font type: '.$type); 334 } 335 //Start generation 336 $s='<?php'."\n"; 337 $s.='$type=\''.$type."';\n"; 338 $s.='$name=\''.$fm['FontName']."';\n"; 339 $s.='$desc='.$fd.";\n"; 340 if(!isset($fm['UnderlinePosition'])) 341 $fm['UnderlinePosition']=-100; 342 if(!isset($fm['UnderlineThickness'])) 343 $fm['UnderlineThickness']=50; 344 $s.='$up='.$fm['UnderlinePosition'].";\n"; 345 $s.='$ut='.$fm['UnderlineThickness'].";\n"; 346 $w=MakeWidthArray($fm); 347 $s.='$cw='.$w.";\n"; 348 $s.='$enc=\''.$enc."';\n"; 349 $s.='$diff=\''.$diff."';\n"; 350 $basename=substr(basename($afmfile),0,-4); 351 if($fontfile) 352 { 353 //Embedded font 354 if(!file_exists($fontfile)) 355 die('<B>Error:</B> font file not found: '.$fontfile); 356 if($type=='TrueType') 357 CheckTTF($fontfile); 358 $f=fopen($fontfile,'rb'); 359 if(!$f) 360 die('<B>Error:</B> Can\'t open '.$fontfile); 361 $file=fread($f,filesize($fontfile)); 362 fclose($f); 363 if($type=='Type1') 364 { 365 //Find first two sections and discard third one 366 $header=(ord($file{0})==128); 367 if($header) 368 { 369 //Strip first binary header 370 $file=substr($file,6); 371 } 372 $pos=strpos($file,'eexec'); 373 if(!$pos) 374 die('<B>Error:</B> font file does not seem to be valid Type1'); 375 $size1=$pos+6; 376 if($header and ord($file{$size1})==128) 377 { 378 //Strip second binary header 379 $file=substr($file,0,$size1).substr($file,$size1+6); 380 } 381 $pos=strpos($file,'00000000'); 382 if(!$pos) 383 die('<B>Error:</B> font file does not seem to be valid Type1'); 384 $size2=$pos-$size1; 385 $file=substr($file,0,$size1+$size2); 386 } 387 if(function_exists('gzcompress')) 388 { 389 $cmp=$basename.'.z'; 390 SaveToFile($destdir.$cmp,gzcompress($file),'b'); 391 $s.='$file=\''.$cmp."';\n"; 392 echo 'Font file compressed ('.$cmp.')<BR>'; 393 } 394 else 395 { 396 $s.='$file=\''.basename($fontfile)."';\n"; 397 echo '<B>Notice:</B> font file could not be compressed (zlib extension not available)<BR>'; 398 } 399 if($type=='Type1') 400 { 401 $s.='$size1='.$size1.";\n"; 402 $s.='$size2='.$size2.";\n"; 403 } 404 else 405 $s.='$originalsize='.filesize($fontfile).";\n"; 406 } 407 else 408 { 409 //Not embedded font 410 $s.='$file='."'';\n"; 411 } 412 $s.="?>\n"; 413 SaveToFile($destdir.$destfile,$s); 414 echo 'Font definition file generated ('.$basename.'.php'.')<BR>'; 415} 416?> 417