annotate .svn/pristine/b0/b00b19ae72ee99ad4406b689ee8ffd14f04ede96.svn-base @ 1327:287f201c2802 redmine-2.2-integration

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