Chris@909: Chris@909: #***************************************************************************** Chris@909: # Utility to generate font definition files # Chris@909: # Version: 1.13 # Chris@909: # Date: 2004-12-31 # Chris@909: ******************************************************************************# Chris@909: Chris@909: function ReadMap($enc) Chris@909: { Chris@909: #Read a map file Chris@909: $file=dirname(__FILE__) + '/' + $enc.downcase + '.map'; Chris@909: $a=file($file); Chris@909: if ($a)) Chris@909: die('Error: encoding not found: '.$enc); Chris@909: $cc2gn = [] Chris@909: foreach($a as $l) Chris@909: { Chris@909: if ($l{0}=='!') Chris@909: { Chris@909: $e=rtrim($l).scan('/[ \\t]+/'); Chris@909: $cc=hexdec(substr($e[0],1)); Chris@909: $gn=$e[2]; Chris@909: $cc2gn[$cc]=$gn; Chris@909: end Chris@909: end Chris@909: for($i=0;$i<=255;$i++) Chris@909: { Chris@909: if (!$cc2gn[$i].nil?) Chris@909: $cc2gn[$i]='.notdef'; Chris@909: end Chris@909: return $cc2gn; Chris@909: } Chris@909: Chris@909: function ReadAFM($file,&$map) Chris@909: { Chris@909: #Read a font metric file Chris@909: $a=file($file); Chris@909: if ($a.empty?) Chris@909: die('File not found'); Chris@909: $widths = [] Chris@909: $fm = [] Chris@909: $fix=Hash.new('Edot'=>'Edotaccent','edot'=>'edotaccent','Idot'=>'Idotaccent','Zdot'=>'Zdotaccent','zdot'=>'zdotaccent', Chris@909: 'Odblacute'=>'Ohungarumlaut','odblacute'=>'ohungarumlaut','Udblacute'=>'Uhungarumlaut','udblacute'=>'uhungarumlaut', Chris@909: 'Gcedilla'=>'Gcommaaccent','gcedilla'=>'gcommaaccent','Kcedilla'=>'Kcommaaccent','kcedilla'=>'kcommaaccent', Chris@909: 'Lcedilla'=>'Lcommaaccent','lcedilla'=>'lcommaaccent','Ncedilla'=>'Ncommaaccent','ncedilla'=>'ncommaaccent', Chris@909: 'Rcedilla'=>'Rcommaaccent','rcedilla'=>'rcommaaccent','Scedilla'=>'Scommaaccent','scedilla'=>'scommaaccent', Chris@909: 'Tcedilla'=>'Tcommaaccent','tcedilla'=>'tcommaaccent','Dslash'=>'Dcroat','dslash'=>'dcroat','Dmacron'=>'Dcroat','dmacron'=>'dcroat', Chris@909: 'combininggraveaccent'=>'gravecomb','combininghookabove'=>'hookabovecomb','combiningtildeaccent'=>'tildecomb', Chris@909: 'combiningacuteaccent'=>'acutecomb','combiningdotbelow'=>'dotbelowcomb','dongsign'=>'dong'); Chris@909: foreach($a as $l) Chris@909: { Chris@909: $e=explode(' ',rtrim($l)); Chris@909: if ($e.length<2) Chris@909: continue; Chris@909: $code=$e[0]; Chris@909: $param=$e[1]; Chris@909: if ($code=='C') Chris@909: { Chris@909: #Character metrics Chris@909: $cc=(int)$e[1]; Chris@909: $w=$e[4]; Chris@909: $gn=$e[7]; Chris@909: if (substr($gn,-4)=='20AC') Chris@909: $gn='Euro'; Chris@909: if ($fix[$gn].nil?) Chris@909: { Chris@909: #Fix incorrect glyph name Chris@909: foreach($map as $c=>$n) Chris@909: { Chris@909: if ($n==$fix[$gn]) Chris@909: $map[$c]=$gn; Chris@909: end Chris@909: end Chris@909: if ($map.empty?) Chris@909: { Chris@909: #Symbolic font: use built-in encoding Chris@909: $widths[$cc]=$w; Chris@909: else Chris@909: { Chris@909: $widths[$gn]=$w; Chris@909: if ($gn=='X') Chris@909: $fm['CapXHeight']=$e[13]; Chris@909: end Chris@909: if ($gn=='.notdef') Chris@909: $fm['MissingWidth']=$w; Chris@909: elsif ($code=='FontName') Chris@909: $fm['FontName']=$param; Chris@909: elsif ($code=='Weight') Chris@909: $fm['Weight']=$param; Chris@909: elsif ($code=='ItalicAngle') Chris@909: $fm['ItalicAngle']=(double)$param; Chris@909: elsif ($code=='Ascender') Chris@909: $fm['Ascender']=(int)$param; Chris@909: elsif ($code=='Descender') Chris@909: $fm['Descender']=(int)$param; Chris@909: elsif ($code=='UnderlineThickness') Chris@909: $fm['UnderlineThickness']=(int)$param; Chris@909: elsif ($code=='UnderlinePosition') Chris@909: $fm['UnderlinePosition']=(int)$param; Chris@909: elsif ($code=='IsFixedPitch') Chris@909: $fm['IsFixedPitch']=($param=='true'); Chris@909: elsif ($code=='FontBBox') Chris@909: $fm['FontBBox']=Hash.new($e[1],$e[2],$e[3],$e[4]); Chris@909: elsif ($code=='CapHeight') Chris@909: $fm['CapHeight']=(int)$param; Chris@909: elsif ($code=='StdVW') Chris@909: $fm['StdVW']=(int)$param; Chris@909: end Chris@909: if (!$fm['FontName'].nil?) Chris@909: die('FontName not found'); Chris@909: if (!$map.empty?) Chris@909: { Chris@909: if (!$widths['.notdef'].nil?) Chris@909: $widths['.notdef']=600; Chris@909: if (!$widths['Delta'].nil? and $widths['increment'].nil?) Chris@909: $widths['Delta']=$widths['increment']; Chris@909: #Order widths according to map Chris@909: for($i=0;$i<=255;$i++) Chris@909: { Chris@909: if (!$widths[$map[$i]].nil?) Chris@909: { Chris@909: echo 'Warning: character '.$map[$i].' is missing
'; Chris@909: $widths[$i]=$widths['.notdef']; Chris@909: else Chris@909: $widths[$i]=$widths[$map[$i]]; Chris@909: end Chris@909: end Chris@909: $fm['Widths']=$widths; Chris@909: return $fm; Chris@909: } Chris@909: Chris@909: function MakeFontDescriptor($fm,$symbolic) Chris@909: { Chris@909: #Ascent Chris@909: $asc=($fm['Ascender'].nil? ? $fm['Ascender'] : 1000); Chris@909: $fd="Hash.new('Ascent'=>".$asc; Chris@909: #Descent Chris@909: $desc=($fm['Descender'].nil? ? $fm['Descender'] : -200); Chris@909: $fd<<",'Descent'=>".$desc; Chris@909: #CapHeight Chris@909: if ($fm['CapHeight'].nil?) Chris@909: $ch=$fm['CapHeight']; Chris@909: elsif ($fm['CapXHeight'].nil?) Chris@909: $ch=$fm['CapXHeight']; Chris@909: else Chris@909: $ch=$asc; Chris@909: $fd<<",'CapHeight'=>".$ch; Chris@909: #Flags Chris@909: $flags=0; Chris@909: if ($fm['IsFixedPitch'].nil? and $fm['IsFixedPitch']) Chris@909: $flags+=1<<0; Chris@909: if ($symbolic) Chris@909: $flags+=1<<2; Chris@909: if (!$symbolic) Chris@909: $flags+=1<<5; Chris@909: if ($fm['ItalicAngle'].nil? and $fm['ItalicAngle']!=0) Chris@909: $flags+=1<<6; Chris@909: $fd<<",'Flags'=>".$flags; Chris@909: #FontBBox Chris@909: if ($fm['FontBBox'].nil?) Chris@909: $fbb=$fm['FontBBox']; Chris@909: else Chris@909: $fbb=Hash.new(0,$des-100,1000,$asc+100); Chris@909: $fd<<",'FontBBox'=>'[".$fbb[0].' '.$fbb[1].' '.$fbb[2].' '.$fbb[3]."]'"; Chris@909: #ItalicAngle Chris@909: $ia=($fm['ItalicAngle'].nil? ? $fm['ItalicAngle'] : 0); Chris@909: $fd<<",'ItalicAngle'=>".$ia; Chris@909: #StemV Chris@909: if ($fm['StdVW'].nil?) Chris@909: $stemv=$fm['StdVW']; Chris@909: elsif ($fm['Weight'].nil? and eregi('(bold|black)',$fm['Weight'])) Chris@909: $stemv=120; Chris@909: else Chris@909: $stemv=70; Chris@909: $fd<<",'StemV'=>".$stemv; Chris@909: #MissingWidth Chris@909: if ($fm['MissingWidth'].nil?) Chris@909: $fd<<",'MissingWidth'=>".$fm['MissingWidth']; Chris@909: $fd<<')'; Chris@909: return $fd; Chris@909: } Chris@909: Chris@909: function MakeWidthArray($fm) Chris@909: { Chris@909: #Make character width array Chris@909: $s="Hash.new(\n\t"; Chris@909: $cw=$fm['Widths']; Chris@909: for($i=0;$i<=255;$i++) Chris@909: { Chris@909: if ($i.chr=="'") Chris@909: $s<<"'\\''"; Chris@909: elsif ($i.chr=="\\") Chris@909: $s<<"'\\\\'"; Chris@909: elsif ($i>=32 and $i<=126) Chris@909: $s<<"'".$i.chr."'"; Chris@909: else Chris@909: $s<<"$i.chr"; Chris@909: $s<<'=>'.$fm['Widths'][$i]; Chris@909: if ($i<255) Chris@909: $s<<','; Chris@909: if (($i+1)%22==0) Chris@909: $s<<"\n\t"; Chris@909: end Chris@909: $s<<')'; Chris@909: return $s; Chris@909: } Chris@909: Chris@909: function MakeFontEncoding($map) Chris@909: { Chris@909: #Build differences from reference encoding Chris@909: $ref=ReadMap('cp1252'); Chris@909: $s=''; Chris@909: $last=0; Chris@909: for($i=32;$i<=255;$i++) Chris@909: { Chris@909: if ($map[$i]!=$ref[$i]) Chris@909: { Chris@909: if ($i!=$last+1) Chris@909: $s<<$i.' '; Chris@909: $last=$i; Chris@909: $s<<'/'.$map[$i].' '; Chris@909: end Chris@909: end Chris@909: return rtrim($s); Chris@909: } Chris@909: Chris@909: function SaveToFile($file,$s,$mode='t') Chris@909: { Chris@909: $f=fopen($file,'w'.$mode); Chris@909: if (!$f) Chris@909: die('Can\'t write to file '.$file); Chris@909: fwrite($f,$s,$s.length); Chris@909: fclose($f); Chris@909: } Chris@909: Chris@909: function ReadShort($f) Chris@909: { Chris@909: $a=unpack('n1n',fread($f,2)); Chris@909: return $a['n']; Chris@909: } Chris@909: Chris@909: function ReadLong($f) Chris@909: { Chris@909: $a=unpack('N1N',fread($f,4)); Chris@909: return $a['N']; Chris@909: } Chris@909: Chris@909: function CheckTTF($file) Chris@909: { Chris@909: #Check if font license allows embedding Chris@909: $f=fopen($file,'rb'); Chris@909: if (!$f) Chris@909: die('Error: Can\'t open '.$file); Chris@909: #Extract number of tables Chris@909: fseek($f,4,SEEK_CUR); Chris@909: $nb=ReadShort($f); Chris@909: fseek($f,6,SEEK_CUR); Chris@909: #Seek OS/2 table Chris@909: $found=false; Chris@909: for($i=0;$i<$nb;$i++) Chris@909: { Chris@909: if (fread($f,4)=='OS/2') Chris@909: { Chris@909: $found=true; Chris@909: break; Chris@909: end Chris@909: fseek($f,12,SEEK_CUR); Chris@909: end Chris@909: if (!$found) Chris@909: { Chris@909: fclose($f); Chris@909: return; Chris@909: end Chris@909: fseek($f,4,SEEK_CUR); Chris@909: $offset=ReadLong($f); Chris@909: fseek($f,$offset,SEEK_SET); Chris@909: #Extract fsType flags Chris@909: fseek($f,8,SEEK_CUR); Chris@909: $fsType=ReadShort($f); Chris@909: $rl=($fsType & 0x02)!=0; Chris@909: $pp=($fsType & 0x04)!=0; Chris@909: $e=($fsType & 0x08)!=0; Chris@909: fclose($f); Chris@909: if ($rl and !$pp and !$e) Chris@909: echo 'Warning: font license does not allow embedding'; Chris@909: } Chris@909: Chris@909: #***************************************************************************** Chris@909: # $fontfile : chemin du fichier TTF (ou chaîne vide si pas d'incorporation) # Chris@909: # $afmfile : chemin du fichier AFM # Chris@909: # $enc : encodage (ou chaîne vide si la police est symbolique) # Chris@909: # $patch : patch optionnel pour l'encodage # Chris@909: # $type : type de la police si $fontfile est vide # Chris@909: ******************************************************************************# Chris@909: function MakeFont($fontfile,$afmfile,$enc='cp1252',$patch=Hash.new(),$type='TrueType') Chris@909: { Chris@909: #Generate a font definition file Chris@909: set_magic_quotes_runtime(0); Chris@909: ini_set('auto_detect_line_endings','1'); Chris@909: if ($enc) Chris@909: { Chris@909: $map=ReadMap($enc); Chris@909: foreach($patch as $cc=>$gn) Chris@909: $map[$cc]=$gn; Chris@909: end Chris@909: else Chris@909: $map = [] Chris@909: if (!file_exists($afmfile)) Chris@909: die('Error: AFM file not found: '.$afmfile); Chris@909: $fm=ReadAFM($afmfile,$map); Chris@909: if ($enc) Chris@909: $diff=MakeFontEncoding($map); Chris@909: else Chris@909: $diff=''; Chris@909: $fd=MakeFontDescriptor($fm,$map.empty?); Chris@909: #Find font type Chris@909: if ($fontfile) Chris@909: { Chris@909: $ext=strtolower(substr($fontfile,-3)); Chris@909: if ($ext=='ttf') Chris@909: $type='TrueType'; Chris@909: elsif ($ext=='pfb') Chris@909: $type='Type1'; Chris@909: else Chris@909: die('Error: unrecognized font file extension: '.$ext); Chris@909: end Chris@909: else Chris@909: { Chris@909: if ($type!='TrueType' and $type!='Type1') Chris@909: die('Error: incorrect font type: '.$type); Chris@909: end Chris@909: #Start generation Chris@909: $s=''."\n"; Chris@909: $s<<'$type=\''.$type."';\n"; Chris@909: $s<<'$name=\''.$fm['FontName']."';\n"; Chris@909: $s<<'$desc='.$fd.";\n"; Chris@909: if (!$fm['UnderlinePosition'].nil?) Chris@909: $fm['UnderlinePosition']=-100; Chris@909: if (!$fm['UnderlineThickness'].nil?) Chris@909: $fm['UnderlineThickness']=50; Chris@909: $s<<'$up='.$fm['UnderlinePosition'].";\n"; Chris@909: $s<<'$ut='.$fm['UnderlineThickness'].";\n"; Chris@909: $w=MakeWidthArray($fm); Chris@909: $s<<'$cw='.$w.";\n"; Chris@909: $s<<'$enc=\''.$enc."';\n"; Chris@909: $s<<'$diff=\''.$diff."';\n"; Chris@909: $basename=substr(basename($afmfile),0,-4); Chris@909: if ($fontfile) Chris@909: { Chris@909: #Embedded font Chris@909: if (!file_exists($fontfile)) Chris@909: die('Error: font file not found: '.$fontfile); Chris@909: if ($type=='TrueType') Chris@909: CheckTTF($fontfile); Chris@909: $f=fopen($fontfile,'rb'); Chris@909: if (!$f) Chris@909: die('Error: Can\'t open '.$fontfile); Chris@909: $file=fread($f,filesize($fontfile)); Chris@909: fclose($f); Chris@909: if ($type=='Type1') Chris@909: { Chris@909: #Find first two sections and discard third one Chris@909: $header=($file[0][0]==128); Chris@909: if ($header) Chris@909: { Chris@909: #Strip first binary header Chris@909: $file=substr($file,6); Chris@909: end Chris@909: $pos=$file.include?('eexec'); Chris@909: if (!$pos) Chris@909: die('Error: font file does not seem to be valid Type1'); Chris@909: $size1=$pos+6; Chris@909: if ($header and ?($file{$size1})==128) Chris@909: { Chris@909: #Strip second binary header Chris@909: $file=substr($file,0,$size1).substr($file,$size1+6); Chris@909: end Chris@909: $pos=$file.include?('00000000'); Chris@909: if (!$pos) Chris@909: die('Error: font file does not seem to be valid Type1'); Chris@909: $size2=$pos-$size1; Chris@909: $file=substr($file,0,$size1+$size2); Chris@909: end Chris@909: if (respond_to('gzcompress')) Chris@909: { Chris@909: $cmp=$basename.'.z'; Chris@909: SaveToFile($cmp,gzcompress($file),'b'); Chris@909: $s<<'$file=\''.$cmp."';\n"; Chris@909: echo 'Font file compressed ('.$cmp.')
'; Chris@909: else Chris@909: { Chris@909: $s<<'$file=\''.basename($fontfile)."';\n"; Chris@909: echo 'Notice: font file could not be compressed (zlib extension not available)
'; Chris@909: end Chris@909: if ($type=='Type1') Chris@909: { Chris@909: $s<<'$size1='.$size1.";\n"; Chris@909: $s<<'$size2='.$size2.";\n"; Chris@909: else Chris@909: $s<<'$originalsize='.filesize($fontfile).";\n"; Chris@909: end Chris@909: else Chris@909: { Chris@909: #Not embedded font Chris@909: $s<<'$file='."'';\n"; Chris@909: end Chris@909: $s<<"\n"; Chris@909: SaveToFile($basename.'.rb',$s); Chris@909: echo 'Font definition file generated ('.$basename.'.rb'.')
'; Chris@909: } Chris@909: