[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 <?php 2 //============================================================+ 3 // File name : makefont.php 4 // Begin : 2004-12-31 5 // Last Update : 2010-03-19 6 // Version : 1.2.006 7 // License : GNU LGPL (http://www.gnu.org/copyleft/lesser.html) 8 // ---------------------------------------------------------------------------- 9 // Copyright (C) 2008 Nicola Asuni - Tecnick.com S.r.l. 10 // 11 // This program is free software: you can redistribute it and/or modify 12 // it under the terms of the GNU Lesser General Public License as published by 13 // the Free Software Foundation, either version 2.1 of the License, or 14 // (at your option) any later version. 15 // 16 // This program is distributed in the hope that it will be useful, 17 // but WITHOUT ANY WARRANTY; without even the implied warranty of 18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 // GNU Lesser General Public License for more details. 20 // 21 // You should have received a copy of the GNU Lesser General Public License 22 // along with this program. If not, see <http://www.gnu.org/licenses/>. 23 // 24 // See LICENSE.TXT file for more information. 25 // ---------------------------------------------------------------------------- 26 // 27 // Description : Utility to generate font definition files fot TCPDF 28 // 29 // Authors: Nicola Asuni, Olivier Plathey, Steven Wittens 30 // 31 // (c) Copyright: 32 // Nicola Asuni 33 // Tecnick.com S.r.l. 34 // Via della Pace, 11 35 // 09044 Quartucciu (CA) 36 // ITALY 37 // www.tecnick.com 38 // info@tecnick.com 39 //============================================================+ 40 41 /** 42 * Utility to generate font definition files fot TCPDF. 43 * @author Nicola Asuni, Olivier Plathey, Steven Wittens 44 * @copyright 2004-2008 Nicola Asuni - Tecnick.com S.r.l (www.tecnick.com) Via Della Pace, 11 - 09044 - Quartucciu (CA) - ITALY - www.tecnick.com - info@tecnick.com 45 * @package com.tecnick.tcpdf 46 * @link http://www.tcpdf.org 47 * @license http://www.gnu.org/copyleft/lesser.html LGPL 48 */ 49 50 /** 51 * 52 * @param string $fontfile path to font file (TTF, OTF or PFB). 53 * @param string $fmfile font metrics file (UFM or AFM). 54 * @param boolean $embedded Set to false to not embed the font, true otherwise (default). 55 * @param string $enc Name of the encoding table to use. Omit this parameter for TrueType Unicode, OpenType Unicode and symbolic fonts like Symbol or ZapfDingBats. 56 * @param array $patch Optional modification of the encoding 57 */ 58 function MakeFont($fontfile, $fmfile, $embedded=true, $enc='cp1252', $patch=array()) { 59 //Generate a font definition file 60 set_magic_quotes_runtime(0); 61 ini_set('auto_detect_line_endings', '1'); 62 if (!file_exists($fontfile)) { 63 die('Error: file not found: '.$fontfile); 64 } 65 if (!file_exists($fmfile)) { 66 die('Error: file not found: '.$fmfile); 67 } 68 $cidtogidmap = ''; 69 $map = array(); 70 $diff = ''; 71 $dw = 0; // default width 72 $ffext = strtolower(substr($fontfile, -3)); 73 $fmext = strtolower(substr($fmfile, -3)); 74 if ($fmext == 'afm') { 75 if (($ffext == 'ttf') OR ($ffext == 'otf')) { 76 $type = 'TrueType'; 77 } elseif ($ffext == 'pfb') { 78 $type = 'Type1'; 79 } else { 80 die('Error: unrecognized font file extension: '.$ffext); 81 } 82 if ($enc) { 83 $map = ReadMap($enc); 84 foreach ($patch as $cc => $gn) { 85 $map[$cc] = $gn; 86 } 87 } 88 $fm = ReadAFM($fmfile, $map); 89 if (isset($widths['.notdef'])) { 90 $dw = $widths['.notdef']; 91 } 92 if ($enc) { 93 $diff = MakeFontEncoding($map); 94 } 95 $fd = MakeFontDescriptor($fm, empty($map)); 96 } elseif ($fmext == 'ufm') { 97 $enc = ''; 98 if (($ffext == 'ttf') OR ($ffext == 'otf')) { 99 $type = 'TrueTypeUnicode'; 100 } else { 101 die('Error: not a TrueType font: '.$ffext); 102 } 103 $fm = ReadUFM($fmfile, $cidtogidmap); 104 $dw = $fm['MissingWidth']; 105 $fd = MakeFontDescriptor($fm, false); 106 } 107 //Start generation 108 $s = '<?php'."\n"; 109 $s .= '$type=\''.$type."';\n"; 110 $s .= '$name=\''.$fm['FontName']."';\n"; 111 $s .= '$desc='.$fd.";\n"; 112 if (!isset($fm['UnderlinePosition'])) { 113 $fm['UnderlinePosition'] = -100; 114 } 115 if (!isset($fm['UnderlineThickness'])) { 116 $fm['UnderlineThickness'] = 50; 117 } 118 $s .= '$up='.$fm['UnderlinePosition'].";\n"; 119 $s .= '$ut='.$fm['UnderlineThickness'].";\n"; 120 if ($dw <= 0) { 121 if (isset($fm['Widths'][32]) AND ($fm['Widths'][32] > 0)) { 122 // assign default space width 123 $dw = $fm['Widths'][32]; 124 } else { 125 $dw = 600; 126 } 127 } 128 $s .= '$dw='.$dw.";\n"; 129 $w = MakeWidthArray($fm); 130 $s .= '$cw='.$w.";\n"; 131 $s .= '$enc=\''.$enc."';\n"; 132 $s .= '$diff=\''.$diff."';\n"; 133 $basename = substr(basename($fmfile), 0, -4); 134 if ($embedded) { 135 //Embedded font 136 if (($type == 'TrueType') OR ($type == 'TrueTypeUnicode')) { 137 CheckTTF($fontfile); 138 } 139 $f = fopen($fontfile,'rb'); 140 if (!$f) { 141 die('Error: Unable to open '.$fontfile); 142 } 143 $file = fread($f, filesize($fontfile)); 144 fclose($f); 145 if ($type == 'Type1') { 146 //Find first two sections and discard third one 147 $header = (ord($file{0}) == 128); 148 if ($header) { 149 //Strip first binary header 150 $file = substr($file, 6); 151 } 152 $pos = strpos($file, 'eexec'); 153 if (!$pos) { 154 die('Error: font file does not seem to be valid Type1'); 155 } 156 $size1 = $pos + 6; 157 if ($header AND (ord($file{$size1}) == 128)) { 158 //Strip second binary header 159 $file = substr($file, 0, $size1).substr($file, $size1+6); 160 } 161 $pos = strpos($file, '00000000'); 162 if (!$pos) { 163 die('Error: font file does not seem to be valid Type1'); 164 } 165 $size2 = $pos - $size1; 166 $file = substr($file, 0, ($size1 + $size2)); 167 } 168 $basename = strtolower($basename); 169 if (function_exists('gzcompress')) { 170 $cmp = $basename.'.z'; 171 SaveToFile($cmp, gzcompress($file, 9), 'b'); 172 $s .= '$file=\''.$cmp."';\n"; 173 print "Font file compressed (".$cmp.")\n"; 174 if (!empty($cidtogidmap)) { 175 $cmp = $basename.'.ctg.z'; 176 SaveToFile($cmp, gzcompress($cidtogidmap, 9), 'b'); 177 print "CIDToGIDMap created and compressed (".$cmp.")\n"; 178 $s .= '$ctg=\''.$cmp."';\n"; 179 } 180 } else { 181 $s .= '$file=\''.basename($fontfile)."';\n"; 182 print "Notice: font file could not be compressed (zlib extension not available)\n"; 183 if (!empty($cidtogidmap)) { 184 $cmp = $basename.'.ctg'; 185 $f = fopen($cmp, 'wb'); 186 fwrite($f, $cidtogidmap); 187 fclose($f); 188 print "CIDToGIDMap created (".$cmp.")\n"; 189 $s .= '$ctg=\''.$cmp."';\n"; 190 } 191 } 192 if($type == 'Type1') { 193 $s .= '$size1='.$size1.";\n"; 194 $s .= '$size2='.$size2.";\n"; 195 } else { 196 $s.='$originalsize='.filesize($fontfile).";\n"; 197 } 198 } else { 199 //Not embedded font 200 $s .= '$file='."'';\n"; 201 } 202 $s .= "?>"; 203 SaveToFile($basename.'.php',$s); 204 print "Font definition file generated (".$basename.".php)\n"; 205 } 206 207 /** 208 * Read the specified encoding map. 209 * @param string $enc map name (see /enc/ folder for valid names). 210 */ 211 function ReadMap($enc) { 212 //Read a map file 213 $file = dirname(__FILE__).'/enc/'.strtolower($enc).'.map'; 214 $a = file($file); 215 if (empty($a)) { 216 die('Error: encoding not found: '.$enc); 217 } 218 $cc2gn = array(); 219 foreach ($a as $l) { 220 if ($l{0} == '!') { 221 $e = preg_split('/[ \\t]+/',rtrim($l)); 222 $cc = hexdec(substr($e[0],1)); 223 $gn = $e[2]; 224 $cc2gn[$cc] = $gn; 225 } 226 } 227 for($i = 0; $i <= 255; $i++) { 228 if(!isset($cc2gn[$i])) { 229 $cc2gn[$i] = '.notdef'; 230 } 231 } 232 return $cc2gn; 233 } 234 235 /** 236 * Read UFM file 237 */ 238 function ReadUFM($file, &$cidtogidmap) { 239 //Prepare empty CIDToGIDMap 240 $cidtogidmap = str_pad('', (256 * 256 * 2), "\x00"); 241 //Read a font metric file 242 $a = file($file); 243 if (empty($a)) { 244 die('File not found'); 245 } 246 $widths = array(); 247 $fm = array(); 248 foreach($a as $l) { 249 $e = explode(' ',chop($l)); 250 if(count($e) < 2) { 251 continue; 252 } 253 $code = $e[0]; 254 $param = $e[1]; 255 if($code == 'U') { 256 // U 827 ; WX 0 ; N squaresubnosp ; G 675 ; 257 //Character metrics 258 $cc = (int)$e[1]; 259 if ($cc != -1) { 260 $gn = $e[7]; 261 $w = $e[4]; 262 $glyph = $e[10]; 263 $widths[$cc] = $w; 264 if($cc == ord('X')) { 265 $fm['CapXHeight'] = $e[13]; 266 } 267 // Set GID 268 if (($cc >= 0) AND ($cc < 0xFFFF) AND $glyph) { 269 $cidtogidmap{($cc * 2)} = chr($glyph >> 8); 270 $cidtogidmap{(($cc * 2) + 1)} = chr($glyph & 0xFF); 271 } 272 } 273 if((isset($gn) AND ($gn == '.notdef')) AND (!isset($fm['MissingWidth']))) { 274 $fm['MissingWidth'] = $w; 275 } 276 } elseif($code == 'FontName') { 277 $fm['FontName'] = $param; 278 } elseif($code == 'Weight') { 279 $fm['Weight'] = $param; 280 } elseif($code == 'ItalicAngle') { 281 $fm['ItalicAngle'] = (double)$param; 282 } elseif($code == 'Ascender') { 283 $fm['Ascender'] = (int)$param; 284 } elseif($code == 'Descender') { 285 $fm['Descender'] = (int)$param; 286 } elseif($code == 'UnderlineThickness') { 287 $fm['UnderlineThickness'] = (int)$param; 288 } elseif($code == 'UnderlinePosition') { 289 $fm['UnderlinePosition'] = (int)$param; 290 } elseif($code == 'IsFixedPitch') { 291 $fm['IsFixedPitch'] = ($param == 'true'); 292 } elseif($code == 'FontBBox') { 293 $fm['FontBBox'] = array($e[1], $e[2], $e[3], $e[4]); 294 } elseif($code == 'CapHeight') { 295 $fm['CapHeight'] = (int)$param; 296 } elseif($code == 'StdVW') { 297 $fm['StdVW'] = (int)$param; 298 } 299 } 300 if(!isset($fm['MissingWidth'])) { 301 $fm['MissingWidth'] = 600; 302 } 303 if(!isset($fm['FontName'])) { 304 die('FontName not found'); 305 } 306 $fm['Widths'] = $widths; 307 return $fm; 308 } 309 310 /** 311 * Read AFM file 312 */ 313 function ReadAFM($file,&$map) { 314 //Read a font metric file 315 $a = file($file); 316 if(empty($a)) { 317 die('File not found'); 318 } 319 $widths = array(); 320 $fm = array(); 321 $fix = array( 322 'Edot'=>'Edotaccent', 323 'edot'=>'edotaccent', 324 'Idot'=>'Idotaccent', 325 'Zdot'=>'Zdotaccent', 326 'zdot'=>'zdotaccent', 327 'Odblacute' => 'Ohungarumlaut', 328 'odblacute' => 'ohungarumlaut', 329 'Udblacute'=>'Uhungarumlaut', 330 'udblacute'=>'uhungarumlaut', 331 'Gcedilla'=>'Gcommaaccent' 332 ,'gcedilla'=>'gcommaaccent', 333 'Kcedilla'=>'Kcommaaccent', 334 'kcedilla'=>'kcommaaccent', 335 'Lcedilla'=>'Lcommaaccent', 336 'lcedilla'=>'lcommaaccent', 337 'Ncedilla'=>'Ncommaaccent', 338 'ncedilla'=>'ncommaaccent', 339 'Rcedilla'=>'Rcommaaccent', 340 'rcedilla'=>'rcommaaccent', 341 'Scedilla'=>'Scommaaccent', 342 'scedilla'=>'scommaaccent', 343 'Tcedilla'=>'Tcommaaccent', 344 'tcedilla'=>'tcommaaccent', 345 'Dslash'=>'Dcroat', 346 'dslash'=>'dcroat', 347 'Dmacron'=>'Dcroat', 348 'dmacron'=>'dcroat', 349 'combininggraveaccent'=>'gravecomb', 350 'combininghookabove'=>'hookabovecomb', 351 'combiningtildeaccent'=>'tildecomb', 352 'combiningacuteaccent'=>'acutecomb', 353 'combiningdotbelow'=>'dotbelowcomb', 354 'dongsign'=>'dong' 355 ); 356 foreach($a as $l) { 357 $e = explode(' ', rtrim($l)); 358 if (count($e) < 2) { 359 continue; 360 } 361 $code = $e[0]; 362 $param = $e[1]; 363 if ($code == 'C') { 364 //Character metrics 365 $cc = (int)$e[1]; 366 $w = $e[4]; 367 $gn = $e[7]; 368 if (substr($gn, -4) == '20AC') { 369 $gn = 'Euro'; 370 } 371 if (isset($fix[$gn])) { 372 //Fix incorrect glyph name 373 foreach ($map as $c => $n) { 374 if ($n == $fix[$gn]) { 375 $map[$c] = $gn; 376 } 377 } 378 } 379 if (empty($map)) { 380 //Symbolic font: use built-in encoding 381 $widths[$cc] = $w; 382 } else { 383 $widths[$gn] = $w; 384 if($gn == 'X') { 385 $fm['CapXHeight'] = $e[13]; 386 } 387 } 388 if($gn == '.notdef') { 389 $fm['MissingWidth'] = $w; 390 } 391 } elseif($code == 'FontName') { 392 $fm['FontName'] = $param; 393 } elseif($code == 'Weight') { 394 $fm['Weight'] = $param; 395 } elseif($code == 'ItalicAngle') { 396 $fm['ItalicAngle'] = (double)$param; 397 } elseif($code == 'Ascender') { 398 $fm['Ascender'] = (int)$param; 399 } elseif($code == 'Descender') { 400 $fm['Descender'] = (int)$param; 401 } elseif($code == 'UnderlineThickness') { 402 $fm['UnderlineThickness'] = (int)$param; 403 } elseif($code == 'UnderlinePosition') { 404 $fm['UnderlinePosition'] = (int)$param; 405 } elseif($code == 'IsFixedPitch') { 406 $fm['IsFixedPitch'] = ($param == 'true'); 407 } elseif($code == 'FontBBox') { 408 $fm['FontBBox'] = array($e[1], $e[2], $e[3], $e[4]); 409 } elseif($code == 'CapHeight') { 410 $fm['CapHeight'] = (int)$param; 411 } elseif($code == 'StdVW') { 412 $fm['StdVW'] = (int)$param; 413 } 414 } 415 if (!isset($fm['FontName'])) { 416 die('FontName not found'); 417 } 418 if (!empty($map)) { 419 if (!isset($widths['.notdef'])) { 420 $widths['.notdef'] = 600; 421 } 422 if (!isset($widths['Delta']) AND isset($widths['increment'])) { 423 $widths['Delta'] = $widths['increment']; 424 } 425 //Order widths according to map 426 for ($i = 0; $i <= 255; $i++) { 427 if (!isset($widths[$map[$i]])) { 428 print "Warning: character ".$map[$i]." is missing\n"; 429 $widths[$i] = $widths['.notdef']; 430 } else { 431 $widths[$i] = $widths[$map[$i]]; 432 } 433 } 434 } 435 $fm['Widths'] = $widths; 436 return $fm; 437 } 438 439 function MakeFontDescriptor($fm, $symbolic=false) { 440 //Ascent 441 $asc = (isset($fm['Ascender']) ? $fm['Ascender'] : 1000); 442 $fd = "array('Ascent'=>".$asc; 443 //Descent 444 $desc = (isset($fm['Descender']) ? $fm['Descender'] : -200); 445 $fd .= ",'Descent'=>".$desc; 446 //CapHeight 447 if (isset($fm['CapHeight'])) { 448 $ch = $fm['CapHeight']; 449 } elseif (isset($fm['CapXHeight'])) { 450 $ch = $fm['CapXHeight']; 451 } else { 452 $ch = $asc; 453 } 454 $fd .= ",'CapHeight'=>".$ch; 455 //Flags 456 $flags = 0; 457 if (isset($fm['IsFixedPitch']) AND $fm['IsFixedPitch']) { 458 $flags += 1<<0; 459 } 460 if ($symbolic) { 461 $flags += 1<<2; 462 } else { 463 $flags += 1<<5; 464 } 465 if (isset($fm['ItalicAngle']) AND ($fm['ItalicAngle'] != 0)) { 466 $flags += 1<<6; 467 } 468 $fd .= ",'Flags'=>".$flags; 469 //FontBBox 470 if (isset($fm['FontBBox'])) { 471 $fbb = $fm['FontBBox']; 472 } else { 473 $fbb = array(0, ($desc - 100), 1000, ($asc + 100)); 474 } 475 $fd .= ",'FontBBox'=>'[".$fbb[0].' '.$fbb[1].' '.$fbb[2].' '.$fbb[3]."]'"; 476 //ItalicAngle 477 $ia = (isset($fm['ItalicAngle']) ? $fm['ItalicAngle'] : 0); 478 $fd .= ",'ItalicAngle'=>".$ia; 479 //StemV 480 if (isset($fm['StdVW'])) { 481 $stemv = $fm['StdVW']; 482 } elseif (isset($fm['Weight']) AND preg_match('/(bold|black)/i', $fm['Weight'])) { 483 $stemv = 120; 484 } else { 485 $stemv = 70; 486 } 487 $fd .= ",'StemV'=>".$stemv; 488 //MissingWidth 489 if(isset($fm['MissingWidth'])) { 490 $fd .= ",'MissingWidth'=>".$fm['MissingWidth']; 491 } 492 $fd .= ')'; 493 return $fd; 494 } 495 496 function MakeWidthArray($fm) { 497 //Make character width array 498 $s = 'array('; 499 $cw = $fm['Widths']; 500 $els = array(); 501 $c = 0; 502 foreach ($cw as $i => $w) { 503 if (is_numeric($i)) { 504 $els[] = (((($c++)%10) == 0) ? "\n" : '').$i.'=>'.$w; 505 } 506 } 507 $s .= implode(',', $els); 508 $s .= ')'; 509 return $s; 510 } 511 512 function MakeFontEncoding($map) { 513 //Build differences from reference encoding 514 $ref = ReadMap('cp1252'); 515 $s = ''; 516 $last = 0; 517 for ($i = 32; $i <= 255; $i++) { 518 if ($map[$i] != $ref[$i]) { 519 if ($i != $last+1) { 520 $s .= $i.' '; 521 } 522 $last = $i; 523 $s .= '/'.$map[$i].' '; 524 } 525 } 526 return rtrim($s); 527 } 528 529 function SaveToFile($file, $s, $mode='t') { 530 $f = fopen($file, 'w'.$mode); 531 if(!$f) { 532 die('Can\'t write to file '.$file); 533 } 534 fwrite($f, $s, strlen($s)); 535 fclose($f); 536 } 537 538 function ReadShort($f) { 539 $a = unpack('n1n', fread($f, 2)); 540 return $a['n']; 541 } 542 543 function ReadLong($f) { 544 $a = unpack('N1N', fread($f, 4)); 545 return $a['N']; 546 } 547 548 function CheckTTF($file) { 549 //Check if font license allows embedding 550 $f = fopen($file, 'rb'); 551 if (!$f) { 552 die('Error: unable to open '.$file); 553 } 554 //Extract number of tables 555 fseek($f, 4, SEEK_CUR); 556 $nb = ReadShort($f); 557 fseek($f, 6, SEEK_CUR); 558 //Seek OS/2 table 559 $found = false; 560 for ($i = 0; $i < $nb; $i++) { 561 if (fread($f, 4) == 'OS/2') { 562 $found = true; 563 break; 564 } 565 fseek($f, 12, SEEK_CUR); 566 } 567 if (!$found) { 568 fclose($f); 569 return; 570 } 571 fseek($f, 4, SEEK_CUR); 572 $offset = ReadLong($f); 573 fseek($f, $offset, SEEK_SET); 574 //Extract fsType flags 575 fseek($f, 8, SEEK_CUR); 576 $fsType = ReadShort($f); 577 $rl = ($fsType & 0x02) != 0; 578 $pp = ($fsType & 0x04) != 0; 579 $e = ($fsType & 0x08) != 0; 580 fclose($f); 581 if($rl AND (!$pp) AND (!$e)) { 582 print "Warning: font license does not allow embedding\n"; 583 } 584 } 585 586 $arg = $GLOBALS['argv']; 587 if (count($arg) >= 3) { 588 ob_start(); 589 array_shift($arg); 590 if (sizeof($arg) == 3) { 591 $arg[3] = $arg[2]; 592 $arg[2] = true; 593 } else { 594 if (!isset($arg[2])) { 595 $arg[2] = true; 596 } 597 if (!isset($arg[3])) { 598 $arg[3] = 'cp1252'; 599 } 600 } 601 if (!isset($arg[4])) { 602 $arg[4] = array(); 603 } 604 MakeFont($arg[0], $arg[1], $arg[2], $arg[3], $arg[4]); 605 $t = ob_get_clean(); 606 print preg_replace('!<BR( /)?>!i', "\n", $t); 607 } else { 608 print "Usage: makefont.php <ttf/otf/pfb file> <afm/ufm file> <encoding> <patch>\n"; 609 } 610 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Tue Mar 17 22:47:18 2015 | Cross-referenced by PHPXref 0.7.1 |