PageRenderTime 42ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/fpdf/makefont/makefont.php

https://bitbucket.org/OverSite/capstone-demo
PHP | 410 lines | 372 code | 17 blank | 21 comment | 74 complexity | 6bd59a7f6318a97eab6040ff763c7ddd MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, MIT, LGPL-2.1, Apache-2.0
  1. <?php
  2. /*******************************************************************************
  3. * Utility to generate font definition files *
  4. * *
  5. * Version: 1.3 *
  6. * Date: 2015-11-29 *
  7. * Author: Olivier PLATHEY *
  8. *******************************************************************************/
  9. require('ttfparser.php');
  10. function Message($txt, $severity = '')
  11. {
  12. if (PHP_SAPI == 'cli') {
  13. if ($severity)
  14. echo "$severity: ";
  15. echo "$txt\n";
  16. } else {
  17. if ($severity)
  18. echo "<b>$severity</b>: ";
  19. echo "$txt<br>";
  20. }
  21. }
  22. function Notice($txt)
  23. {
  24. Message($txt, 'Notice');
  25. }
  26. function Warning($txt)
  27. {
  28. Message($txt, 'Warning');
  29. }
  30. function Error($txt)
  31. {
  32. Message($txt, 'Error');
  33. exit;
  34. }
  35. function LoadMap($enc)
  36. {
  37. $file = dirname(__FILE__) . '/' . strtolower($enc) . '.map';
  38. $a = file($file);
  39. if (empty($a))
  40. Error('Encoding not found: ' . $enc);
  41. $map = array_fill(0, 256, array('uv' => -1, 'name' => '.notdef'));
  42. foreach ($a as $line) {
  43. $e = explode(' ', rtrim($line));
  44. $c = hexdec(substr($e[0], 1));
  45. $uv = hexdec(substr($e[1], 2));
  46. $name = $e[2];
  47. $map[$c] = array('uv' => $uv, 'name' => $name);
  48. }
  49. return $map;
  50. }
  51. function GetInfoFromTrueType($file, $embed, $subset, $map)
  52. {
  53. // Return information from a TrueType font
  54. try {
  55. $ttf = new TTFParser($file);
  56. $ttf->Parse();
  57. } catch (Exception $e) {
  58. Error($e->getMessage());
  59. }
  60. if ($embed) {
  61. if (!$ttf->embeddable)
  62. Error('Font license does not allow embedding');
  63. if ($subset) {
  64. $chars = array();
  65. foreach ($map as $v) {
  66. if ($v['name'] != '.notdef')
  67. $chars[] = $v['uv'];
  68. }
  69. $ttf->Subset($chars);
  70. $info['Data'] = $ttf->Build();
  71. } else
  72. $info['Data'] = file_get_contents($file);
  73. $info['OriginalSize'] = strlen($info['Data']);
  74. }
  75. $k = 1000 / $ttf->unitsPerEm;
  76. $info['FontName'] = $ttf->postScriptName;
  77. $info['Bold'] = $ttf->bold;
  78. $info['ItalicAngle'] = $ttf->italicAngle;
  79. $info['IsFixedPitch'] = $ttf->isFixedPitch;
  80. $info['Ascender'] = round($k * $ttf->typoAscender);
  81. $info['Descender'] = round($k * $ttf->typoDescender);
  82. $info['UnderlineThickness'] = round($k * $ttf->underlineThickness);
  83. $info['UnderlinePosition'] = round($k * $ttf->underlinePosition);
  84. $info['FontBBox'] = array(round($k * $ttf->xMin), round($k * $ttf->yMin), round($k * $ttf->xMax), round($k * $ttf->yMax));
  85. $info['CapHeight'] = round($k * $ttf->capHeight);
  86. $info['MissingWidth'] = round($k * $ttf->glyphs[0]['w']);
  87. $widths = array_fill(0, 256, $info['MissingWidth']);
  88. foreach ($map as $c => $v) {
  89. if ($v['name'] != '.notdef') {
  90. if (isset($ttf->chars[$v['uv']])) {
  91. $id = $ttf->chars[$v['uv']];
  92. $w = $ttf->glyphs[$id]['w'];
  93. $widths[$c] = round($k * $w);
  94. } else
  95. Warning('Character ' . $v['name'] . ' is missing');
  96. }
  97. }
  98. $info['Widths'] = $widths;
  99. return $info;
  100. }
  101. function GetInfoFromType1($file, $embed, $map)
  102. {
  103. // Return information from a Type1 font
  104. if ($embed) {
  105. $f = fopen($file, 'rb');
  106. if (!$f)
  107. Error('Can\'t open font file');
  108. // Read first segment
  109. $a = unpack('Cmarker/Ctype/Vsize', fread($f, 6));
  110. if ($a['marker'] != 128)
  111. Error('Font file is not a valid binary Type1');
  112. $size1 = $a['size'];
  113. $data = fread($f, $size1);
  114. // Read second segment
  115. $a = unpack('Cmarker/Ctype/Vsize', fread($f, 6));
  116. if ($a['marker'] != 128)
  117. Error('Font file is not a valid binary Type1');
  118. $size2 = $a['size'];
  119. $data .= fread($f, $size2);
  120. fclose($f);
  121. $info['Data'] = $data;
  122. $info['Size1'] = $size1;
  123. $info['Size2'] = $size2;
  124. }
  125. $afm = substr($file, 0, -3) . 'afm';
  126. if (!file_exists($afm))
  127. Error('AFM font file not found: ' . $afm);
  128. $a = file($afm);
  129. if (empty($a))
  130. Error('AFM file empty or not readable');
  131. foreach ($a as $line) {
  132. $e = explode(' ', rtrim($line));
  133. if (count($e) < 2)
  134. continue;
  135. $entry = $e[0];
  136. if ($entry == 'C') {
  137. $w = $e[4];
  138. $name = $e[7];
  139. $cw[$name] = $w;
  140. } elseif ($entry == 'FontName')
  141. $info['FontName'] = $e[1];
  142. elseif ($entry == 'Weight')
  143. $info['Weight'] = $e[1];
  144. elseif ($entry == 'ItalicAngle')
  145. $info['ItalicAngle'] = (int)$e[1];
  146. elseif ($entry == 'Ascender')
  147. $info['Ascender'] = (int)$e[1];
  148. elseif ($entry == 'Descender')
  149. $info['Descender'] = (int)$e[1];
  150. elseif ($entry == 'UnderlineThickness')
  151. $info['UnderlineThickness'] = (int)$e[1];
  152. elseif ($entry == 'UnderlinePosition')
  153. $info['UnderlinePosition'] = (int)$e[1];
  154. elseif ($entry == 'IsFixedPitch')
  155. $info['IsFixedPitch'] = ($e[1] == 'true');
  156. elseif ($entry == 'FontBBox')
  157. $info['FontBBox'] = array((int)$e[1], (int)$e[2], (int)$e[3], (int)$e[4]);
  158. elseif ($entry == 'CapHeight')
  159. $info['CapHeight'] = (int)$e[1];
  160. elseif ($entry == 'StdVW')
  161. $info['StdVW'] = (int)$e[1];
  162. }
  163. if (!isset($info['FontName']))
  164. Error('FontName missing in AFM file');
  165. if (!isset($info['Ascender']))
  166. $info['Ascender'] = $info['FontBBox'][3];
  167. if (!isset($info['Descender']))
  168. $info['Descender'] = $info['FontBBox'][1];
  169. $info['Bold'] = isset($info['Weight']) && preg_match('/bold|black/i', $info['Weight']);
  170. if (isset($cw['.notdef']))
  171. $info['MissingWidth'] = $cw['.notdef'];
  172. else
  173. $info['MissingWidth'] = 0;
  174. $widths = array_fill(0, 256, $info['MissingWidth']);
  175. foreach ($map as $c => $v) {
  176. if ($v['name'] != '.notdef') {
  177. if (isset($cw[$v['name']]))
  178. $widths[$c] = $cw[$v['name']];
  179. else
  180. Warning('Character ' . $v['name'] . ' is missing');
  181. }
  182. }
  183. $info['Widths'] = $widths;
  184. return $info;
  185. }
  186. function MakeFontDescriptor($info)
  187. {
  188. // Ascent
  189. $fd = "array('Ascent'=>" . $info['Ascender'];
  190. // Descent
  191. $fd .= ",'Descent'=>" . $info['Descender'];
  192. // CapHeight
  193. if (!empty($info['CapHeight']))
  194. $fd .= ",'CapHeight'=>" . $info['CapHeight'];
  195. else
  196. $fd .= ",'CapHeight'=>" . $info['Ascender'];
  197. // Flags
  198. $flags = 0;
  199. if ($info['IsFixedPitch'])
  200. $flags += 1 << 0;
  201. $flags += 1 << 5;
  202. if ($info['ItalicAngle'] != 0)
  203. $flags += 1 << 6;
  204. $fd .= ",'Flags'=>" . $flags;
  205. // FontBBox
  206. $fbb = $info['FontBBox'];
  207. $fd .= ",'FontBBox'=>'[" . $fbb[0] . ' ' . $fbb[1] . ' ' . $fbb[2] . ' ' . $fbb[3] . "]'";
  208. // ItalicAngle
  209. $fd .= ",'ItalicAngle'=>" . $info['ItalicAngle'];
  210. // StemV
  211. if (isset($info['StdVW']))
  212. $stemv = $info['StdVW'];
  213. elseif ($info['Bold'])
  214. $stemv = 120;
  215. else
  216. $stemv = 70;
  217. $fd .= ",'StemV'=>" . $stemv;
  218. // MissingWidth
  219. $fd .= ",'MissingWidth'=>" . $info['MissingWidth'] . ')';
  220. return $fd;
  221. }
  222. function MakeWidthArray($widths)
  223. {
  224. $s = "array(\n\t";
  225. for ($c = 0; $c <= 255; $c++) {
  226. if (chr($c) == "'")
  227. $s .= "'\\''";
  228. elseif (chr($c) == "\\")
  229. $s .= "'\\\\'";
  230. elseif ($c >= 32 && $c <= 126)
  231. $s .= "'" . chr($c) . "'";
  232. else
  233. $s .= "chr($c)";
  234. $s .= '=>' . $widths[$c];
  235. if ($c < 255)
  236. $s .= ',';
  237. if (($c + 1) % 22 == 0)
  238. $s .= "\n\t";
  239. }
  240. $s .= ')';
  241. return $s;
  242. }
  243. function MakeFontEncoding($map)
  244. {
  245. // Build differences from reference encoding
  246. $ref = LoadMap('cp1252');
  247. $s = '';
  248. $last = 0;
  249. for ($c = 32; $c <= 255; $c++) {
  250. if ($map[$c]['name'] != $ref[$c]['name']) {
  251. if ($c != $last + 1)
  252. $s .= $c . ' ';
  253. $last = $c;
  254. $s .= '/' . $map[$c]['name'] . ' ';
  255. }
  256. }
  257. return rtrim($s);
  258. }
  259. function MakeUnicodeArray($map)
  260. {
  261. // Build mapping to Unicode values
  262. $ranges = array();
  263. foreach ($map as $c => $v) {
  264. $uv = $v['uv'];
  265. if ($uv != -1) {
  266. if (isset($range)) {
  267. if ($c == $range[1] + 1 && $uv == $range[3] + 1) {
  268. $range[1]++;
  269. $range[3]++;
  270. } else {
  271. $ranges[] = $range;
  272. $range = array($c, $c, $uv, $uv);
  273. }
  274. } else
  275. $range = array($c, $c, $uv, $uv);
  276. }
  277. }
  278. $ranges[] = $range;
  279. foreach ($ranges as $range) {
  280. if (isset($s))
  281. $s .= ',';
  282. else
  283. $s = 'array(';
  284. $s .= $range[0] . '=>';
  285. $nb = $range[1] - $range[0] + 1;
  286. if ($nb > 1)
  287. $s .= 'array(' . $range[2] . ',' . $nb . ')';
  288. else
  289. $s .= $range[2];
  290. }
  291. $s .= ')';
  292. return $s;
  293. }
  294. function SaveToFile($file, $s, $mode)
  295. {
  296. $f = fopen($file, 'w' . $mode);
  297. if (!$f)
  298. Error('Can\'t write to file ' . $file);
  299. fwrite($f, $s);
  300. fclose($f);
  301. }
  302. function MakeDefinitionFile($file, $type, $enc, $embed, $subset, $map, $info)
  303. {
  304. $s = "<?php\n";
  305. $s .= '$type = \'' . $type . "';\n";
  306. $s .= '$name = \'' . $info['FontName'] . "';\n";
  307. $s .= '$desc = ' . MakeFontDescriptor($info) . ";\n";
  308. $s .= '$up = ' . $info['UnderlinePosition'] . ";\n";
  309. $s .= '$ut = ' . $info['UnderlineThickness'] . ";\n";
  310. $s .= '$cw = ' . MakeWidthArray($info['Widths']) . ";\n";
  311. $s .= '$enc = \'' . $enc . "';\n";
  312. $diff = MakeFontEncoding($map);
  313. if ($diff)
  314. $s .= '$diff = \'' . $diff . "';\n";
  315. $s .= '$uv = ' . MakeUnicodeArray($map) . ";\n";
  316. if ($embed) {
  317. $s .= '$file = \'' . $info['File'] . "';\n";
  318. if ($type == 'Type1') {
  319. $s .= '$size1 = ' . $info['Size1'] . ";\n";
  320. $s .= '$size2 = ' . $info['Size2'] . ";\n";
  321. } else {
  322. $s .= '$originalsize = ' . $info['OriginalSize'] . ";\n";
  323. if ($subset)
  324. $s .= "\$subsetted = true;\n";
  325. }
  326. }
  327. $s .= "?>\n";
  328. SaveToFile($file, $s, 't');
  329. }
  330. function MakeFont($fontfile, $enc = 'cp1252', $embed = true, $subset = true)
  331. {
  332. // Generate a font definition file
  333. if (get_magic_quotes_runtime())
  334. @set_magic_quotes_runtime(false);
  335. ini_set('auto_detect_line_endings', '1');
  336. if (!file_exists($fontfile))
  337. Error('Font file not found: ' . $fontfile);
  338. $ext = strtolower(substr($fontfile, -3));
  339. if ($ext == 'ttf' || $ext == 'otf')
  340. $type = 'TrueType';
  341. elseif ($ext == 'pfb')
  342. $type = 'Type1';
  343. else
  344. Error('Unrecognized font file extension: ' . $ext);
  345. $map = LoadMap($enc);
  346. if ($type == 'TrueType')
  347. $info = GetInfoFromTrueType($fontfile, $embed, $subset, $map);
  348. else
  349. $info = GetInfoFromType1($fontfile, $embed, $map);
  350. $basename = substr(basename($fontfile), 0, -4);
  351. if ($embed) {
  352. if (function_exists('gzcompress')) {
  353. $file = $basename . '.z';
  354. SaveToFile($file, gzcompress($info['Data']), 'b');
  355. $info['File'] = $file;
  356. Message('Font file compressed: ' . $file);
  357. } else {
  358. $info['File'] = basename($fontfile);
  359. $subset = false;
  360. Notice('Font file could not be compressed (zlib extension not available)');
  361. }
  362. }
  363. MakeDefinitionFile($basename . '.php', $type, $enc, $embed, $subset, $map, $info);
  364. Message('Font definition file generated: ' . $basename . '.php');
  365. }
  366. if (PHP_SAPI == 'cli') {
  367. // Command-line interface
  368. ini_set('log_errors', '0');
  369. if ($argc == 1)
  370. die("Usage: php makefont.php fontfile [encoding] [embed] [subset]\n");
  371. $fontfile = $argv[1];
  372. if ($argc >= 3)
  373. $enc = $argv[2];
  374. else
  375. $enc = 'cp1252';
  376. if ($argc >= 4)
  377. $embed = ($argv[3] == 'true' || $argv[3] == '1');
  378. else
  379. $embed = true;
  380. if ($argc >= 5)
  381. $subset = ($argv[4] == 'true' || $argv[4] == '1');
  382. else
  383. $subset = true;
  384. MakeFont($fontfile, $enc, $embed, $subset);
  385. }
  386. ?>