A Qcodo based CMS/ecommerce framework
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

419 lines
11 KiB

13 years ago
  1. <?php
  2. /*******************************************************************************
  3. * Utility to generate font definition files *
  4. * *
  5. * Version: 1.14 *
  6. * Date: 2008-08-03 *
  7. * Author: Olivier PLATHEY *
  8. *******************************************************************************/
  9. function ReadMap($enc)
  10. {
  11. //Read a map file
  12. $file=dirname(__FILE__).'/'.strtolower($enc).'.map';
  13. $a=file($file);
  14. if(empty($a))
  15. die('<b>Error:</b> encoding not found: '.$enc);
  16. $cc2gn=array();
  17. foreach($a as $l)
  18. {
  19. if($l[0]=='!')
  20. {
  21. $e=preg_split('/[ \\t]+/',rtrim($l));
  22. $cc=hexdec(substr($e[0],1));
  23. $gn=$e[2];
  24. $cc2gn[$cc]=$gn;
  25. }
  26. }
  27. for($i=0;$i<=255;$i++)
  28. {
  29. if(!isset($cc2gn[$i]))
  30. $cc2gn[$i]='.notdef';
  31. }
  32. return $cc2gn;
  33. }
  34. function 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']) && 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. function MakeFontDescriptor($fm, $symbolic)
  135. {
  136. //Ascent
  137. $asc=(isset($fm['Ascender']) ? $fm['Ascender'] : 1000);
  138. $fd="array('Ascent'=>".$asc;
  139. //Descent
  140. $desc=(isset($fm['Descender']) ? $fm['Descender'] : -200);
  141. $fd.=",'Descent'=>".$desc;
  142. //CapHeight
  143. if(isset($fm['CapHeight']))
  144. $ch=$fm['CapHeight'];
  145. elseif(isset($fm['CapXHeight']))
  146. $ch=$fm['CapXHeight'];
  147. else
  148. $ch=$asc;
  149. $fd.=",'CapHeight'=>".$ch;
  150. //Flags
  151. $flags=0;
  152. if(isset($fm['IsFixedPitch']) && $fm['IsFixedPitch'])
  153. $flags+=1<<0;
  154. if($symbolic)
  155. $flags+=1<<2;
  156. if(!$symbolic)
  157. $flags+=1<<5;
  158. if(isset($fm['ItalicAngle']) && $fm['ItalicAngle']!=0)
  159. $flags+=1<<6;
  160. $fd.=",'Flags'=>".$flags;
  161. //FontBBox
  162. if(isset($fm['FontBBox']))
  163. $fbb=$fm['FontBBox'];
  164. else
  165. $fbb=array(0,$desc-100,1000,$asc+100);
  166. $fd.=",'FontBBox'=>'[".$fbb[0].' '.$fbb[1].' '.$fbb[2].' '.$fbb[3]."]'";
  167. //ItalicAngle
  168. $ia=(isset($fm['ItalicAngle']) ? $fm['ItalicAngle'] : 0);
  169. $fd.=",'ItalicAngle'=>".$ia;
  170. //StemV
  171. if(isset($fm['StdVW']))
  172. $stemv=$fm['StdVW'];
  173. elseif(isset($fm['Weight']) && preg_match('/bold|black/i',$fm['Weight']))
  174. $stemv=120;
  175. else
  176. $stemv=70;
  177. $fd.=",'StemV'=>".$stemv;
  178. //MissingWidth
  179. if(isset($fm['MissingWidth']))
  180. $fd.=",'MissingWidth'=>".$fm['MissingWidth'];
  181. $fd.=')';
  182. return $fd;
  183. }
  184. function MakeWidthArray($fm)
  185. {
  186. //Make character width array
  187. $s="array(\n\t";
  188. $cw=$fm['Widths'];
  189. for($i=0;$i<=255;$i++)
  190. {
  191. if(chr($i)=="'")
  192. $s.="'\\''";
  193. elseif(chr($i)=="\\")
  194. $s.="'\\\\'";
  195. elseif($i>=32 && $i<=126)
  196. $s.="'".chr($i)."'";
  197. else
  198. $s.="chr($i)";
  199. $s.='=>'.$fm['Widths'][$i];
  200. if($i<255)
  201. $s.=',';
  202. if(($i+1)%22==0)
  203. $s.="\n\t";
  204. }
  205. $s.=')';
  206. return $s;
  207. }
  208. function MakeFontEncoding($map)
  209. {
  210. //Build differences from reference encoding
  211. $ref=ReadMap('cp1252');
  212. $s='';
  213. $last=0;
  214. for($i=32;$i<=255;$i++)
  215. {
  216. if($map[$i]!=$ref[$i])
  217. {
  218. if($i!=$last+1)
  219. $s.=$i.' ';
  220. $last=$i;
  221. $s.='/'.$map[$i].' ';
  222. }
  223. }
  224. return rtrim($s);
  225. }
  226. function SaveToFile($file, $s, $mode)
  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. function ReadShort($f)
  235. {
  236. $a=unpack('n1n',fread($f,2));
  237. return $a['n'];
  238. }
  239. function ReadLong($f)
  240. {
  241. $a=unpack('N1N',fread($f,4));
  242. return $a['N'];
  243. }
  244. function CheckTTF($file)
  245. {
  246. //Check if font license allows embedding
  247. $f=fopen($file,'rb');
  248. if(!$f)
  249. die('<b>Error:</b> Can\'t open '.$file);
  250. //Extract number of tables
  251. fseek($f,4,SEEK_CUR);
  252. $nb=ReadShort($f);
  253. fseek($f,6,SEEK_CUR);
  254. //Seek OS/2 table
  255. $found=false;
  256. for($i=0;$i<$nb;$i++)
  257. {
  258. if(fread($f,4)=='OS/2')
  259. {
  260. $found=true;
  261. break;
  262. }
  263. fseek($f,12,SEEK_CUR);
  264. }
  265. if(!$found)
  266. {
  267. fclose($f);
  268. return;
  269. }
  270. fseek($f,4,SEEK_CUR);
  271. $offset=ReadLong($f);
  272. fseek($f,$offset,SEEK_SET);
  273. //Extract fsType flags
  274. fseek($f,8,SEEK_CUR);
  275. $fsType=ReadShort($f);
  276. $rl=($fsType & 0x02)!=0;
  277. $pp=($fsType & 0x04)!=0;
  278. $e=($fsType & 0x08)!=0;
  279. fclose($f);
  280. if($rl && !$pp && !$e)
  281. echo '<b>Warning:</b> font license does not allow embedding';
  282. }
  283. /*******************************************************************************
  284. * fontfile: path to TTF file (or empty string if not to be embedded) *
  285. * afmfile: path to AFM file *
  286. * enc: font encoding (or empty string for symbolic fonts) *
  287. * patch: optional patch for encoding *
  288. * type: font type if fontfile is empty *
  289. *******************************************************************************/
  290. function MakeFont($fontfile, $afmfile, $enc='cp1252', $patch=array(), $type='TrueType')
  291. {
  292. //Generate a font definition file
  293. if(get_magic_quotes_runtime())
  294. @set_magic_quotes_runtime(0);
  295. ini_set('auto_detect_line_endings','1');
  296. if($enc)
  297. {
  298. $map=ReadMap($enc);
  299. foreach($patch as $cc=>$gn)
  300. $map[$cc]=$gn;
  301. }
  302. else
  303. $map=array();
  304. if(!file_exists($afmfile))
  305. die('<b>Error:</b> AFM file not found: '.$afmfile);
  306. $fm=ReadAFM($afmfile,$map);
  307. if($enc)
  308. $diff=MakeFontEncoding($map);
  309. else
  310. $diff='';
  311. $fd=MakeFontDescriptor($fm,empty($map));
  312. //Find font type
  313. if($fontfile)
  314. {
  315. $ext=strtolower(substr($fontfile,-3));
  316. if($ext=='ttf')
  317. $type='TrueType';
  318. elseif($ext=='pfb')
  319. $type='Type1';
  320. else
  321. die('<b>Error:</b> unrecognized font file extension: '.$ext);
  322. }
  323. else
  324. {
  325. if($type!='TrueType' && $type!='Type1')
  326. die('<b>Error:</b> incorrect font type: '.$type);
  327. }
  328. //Start generation
  329. $s='<?php'."\n";
  330. $s.='$type=\''.$type."';\n";
  331. $s.='$name=\''.$fm['FontName']."';\n";
  332. $s.='$desc='.$fd.";\n";
  333. if(!isset($fm['UnderlinePosition']))
  334. $fm['UnderlinePosition']=-100;
  335. if(!isset($fm['UnderlineThickness']))
  336. $fm['UnderlineThickness']=50;
  337. $s.='$up='.$fm['UnderlinePosition'].";\n";
  338. $s.='$ut='.$fm['UnderlineThickness'].";\n";
  339. $w=MakeWidthArray($fm);
  340. $s.='$cw='.$w.";\n";
  341. $s.='$enc=\''.$enc."';\n";
  342. $s.='$diff=\''.$diff."';\n";
  343. $basename=substr(basename($afmfile),0,-4);
  344. if($fontfile)
  345. {
  346. //Embedded font
  347. if(!file_exists($fontfile))
  348. die('<b>Error:</b> font file not found: '.$fontfile);
  349. if($type=='TrueType')
  350. CheckTTF($fontfile);
  351. $f=fopen($fontfile,'rb');
  352. if(!$f)
  353. die('<b>Error:</b> Can\'t open '.$fontfile);
  354. $file=fread($f,filesize($fontfile));
  355. fclose($f);
  356. if($type=='Type1')
  357. {
  358. //Find first two sections and discard third one
  359. $header=(ord($file[0])==128);
  360. if($header)
  361. {
  362. //Strip first binary header
  363. $file=substr($file,6);
  364. }
  365. $pos=strpos($file,'eexec');
  366. if(!$pos)
  367. die('<b>Error:</b> font file does not seem to be valid Type1');
  368. $size1=$pos+6;
  369. if($header && ord($file[$size1])==128)
  370. {
  371. //Strip second binary header
  372. $file=substr($file,0,$size1).substr($file,$size1+6);
  373. }
  374. $pos=strpos($file,'00000000');
  375. if(!$pos)
  376. die('<b>Error:</b> font file does not seem to be valid Type1');
  377. $size2=$pos-$size1;
  378. $file=substr($file,0,$size1+$size2);
  379. }
  380. if(function_exists('gzcompress'))
  381. {
  382. $cmp=$basename.'.z';
  383. SaveToFile($cmp,gzcompress($file),'b');
  384. $s.='$file=\''.$cmp."';\n";
  385. echo 'Font file compressed ('.$cmp.')<br>';
  386. }
  387. else
  388. {
  389. $s.='$file=\''.basename($fontfile)."';\n";
  390. echo '<b>Notice:</b> font file could not be compressed (zlib extension not available)<br>';
  391. }
  392. if($type=='Type1')
  393. {
  394. $s.='$size1='.$size1.";\n";
  395. $s.='$size2='.$size2.";\n";
  396. }
  397. else
  398. $s.='$originalsize='.filesize($fontfile).";\n";
  399. }
  400. else
  401. {
  402. //Not embedded font
  403. $s.='$file='."'';\n";
  404. }
  405. $s.="?>\n";
  406. SaveToFile($basename.'.php',$s,'t');
  407. echo 'Font definition file generated ('.$basename.'.php'.')<br>';
  408. }
  409. ?>