PageRenderTime 25ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/font/makefont/makefont-new.php

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