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