|
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
|
|
|
|
* PHP class t1asm *
|
|
|
|
|
|
* *
|
|
|
|
|
|
* Version: 1.1 *
|
|
|
|
|
|
* Date: 2009-10-01 *
|
|
|
|
|
|
* Author: Ian Back <ianb@bpm1.com> *
|
|
|
|
|
|
* License: GPL *
|
|
|
|
|
|
* *
|
|
|
|
|
|
* This program allows editing and then 'assembles' Adobe Type-1 font programs *
|
|
|
|
|
|
* in pseudo-PostScript form into PFB PFA format. *
|
|
|
|
|
|
* Requires .t1a and .uni2gn files *
|
|
|
|
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
SAMPLE USE OF tiasm
|
|
|
|
|
|
|
|
|
|
|
|
$asm = new t1asm();
|
|
|
|
|
|
$asm->LoadFontFile('originalfont'); // Loads originalfont.t1a and looks for (optional) originalfont.ufm for glyph name map
|
|
|
|
|
|
|
|
|
|
|
|
// Override fontnames if required
|
|
|
|
|
|
$asm->SetFontName('mPDF__001');
|
|
|
|
|
|
$asm->SetFamilyName('mPDF');
|
|
|
|
|
|
$asm->SetFullName('mPDF__001-Italic');
|
|
|
|
|
|
|
|
|
|
|
|
// Define array of codepoint(decimal) to Unicode(decimal)
|
|
|
|
|
|
$chars = array(
|
|
|
|
|
|
0=>0
|
|
|
|
|
|
1=>0
|
|
|
|
|
|
2=>0
|
|
|
|
|
|
...
|
|
|
|
|
|
83=>83
|
|
|
|
|
|
84=>84
|
|
|
|
|
|
85=>85
|
|
|
|
|
|
86=>86
|
|
|
|
|
|
...
|
|
|
|
|
|
253=>20156
|
|
|
|
|
|
254=>19289
|
|
|
|
|
|
255=>4013
|
|
|
|
|
|
);
|
|
|
|
|
|
$asm->DefineChars($chars);
|
|
|
|
|
|
|
|
|
|
|
|
//Available:
|
|
|
|
|
|
$asm->pdf_diffstr; // String of /Diffs for inclusion in a PDF file
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$s = $asm->OutputPFB('', false);
|
|
|
|
|
|
// OR
|
|
|
|
|
|
$asm->OutputPFB('myfontassembled',false); // makes a .pfb if (*,true) or gzcompressed as a .z file if not
|
|
|
|
|
|
|
|
|
|
|
|
//Available:
|
|
|
|
|
|
$asm->of_size1; // size in bytes of 1st (ASCII) block
|
|
|
|
|
|
$asm->of_size2; // size in bytes of 2nd (binary) block
|
|
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
//======================================================
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class t1asm {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var $PFB_ASCII = 1;
|
|
|
|
|
|
var $PFB_BINARY = 2;
|
|
|
|
|
|
var $PFB_DONE = 3;
|
|
|
|
|
|
var $PFB_MARKER = 0x80;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var $file_op = '';
|
|
|
|
|
|
var $ofp;
|
|
|
|
|
|
var $file_ip = '';
|
|
|
|
|
|
var $tbl_prefix ='';
|
|
|
|
|
|
|
|
|
|
|
|
var $agn;
|
|
|
|
|
|
var $uni2gn;
|
|
|
|
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
|
|
var $pfb = 1;
|
|
|
|
|
|
var $ever_active = 0;
|
|
|
|
|
|
var $in_eexec = 0;
|
|
|
|
|
|
|
|
|
|
|
|
/* lenIV and charstring start command */
|
|
|
|
|
|
var $lenIV = 4;
|
|
|
|
|
|
var $cs_start = 'RD';
|
|
|
|
|
|
|
|
|
|
|
|
/* decryption stuff */
|
|
|
|
|
|
var $c1 = 52845;
|
|
|
|
|
|
var $c2 = 22719;
|
|
|
|
|
|
var $cr = 4330;
|
|
|
|
|
|
var $er = 55665;
|
|
|
|
|
|
|
|
|
|
|
|
var $cs_commands = array();
|
|
|
|
|
|
var $op_buffer = '';
|
|
|
|
|
|
var $wob = '';
|
|
|
|
|
|
var $blocktyp;
|
|
|
|
|
|
var $dest = '';
|
|
|
|
|
|
|
|
|
|
|
|
var $if_header;
|
|
|
|
|
|
var $if_FullName;
|
|
|
|
|
|
var $if_FontName;
|
|
|
|
|
|
var $if_FamilyName;
|
|
|
|
|
|
var $if_encs;
|
|
|
|
|
|
var $if_eexec_start;
|
|
|
|
|
|
var $if_Subrs;
|
|
|
|
|
|
var $if_CharStrings;
|
|
|
|
|
|
var $if_source;
|
|
|
|
|
|
var $fid;
|
|
|
|
|
|
var $SubroutineStr;
|
|
|
|
|
|
|
|
|
|
|
|
var $pdf_diffstr;
|
|
|
|
|
|
|
|
|
|
|
|
var $offs;
|
|
|
|
|
|
|
|
|
|
|
|
var $of_encodingstr;
|
|
|
|
|
|
var $of_header;
|
|
|
|
|
|
var $of_size1;
|
|
|
|
|
|
var $of_size2;
|
|
|
|
|
|
|
|
|
|
|
|
var $of_FullName;
|
|
|
|
|
|
var $of_FontName;
|
|
|
|
|
|
var $of_FamilyName;
|
|
|
|
|
|
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
|
|
|
|
|
|
|
|
function t1asm() {
|
|
|
|
|
|
$this->_initialise();
|
|
|
|
|
|
/* Adobe Glyph Names */
|
|
|
|
|
|
$this->agn = array ( 65 => 'A', 198 => 'AE', 508 => 'AEacute', 193 => 'Aacute', 258 => 'Abreve', 194 => 'Acircumflex', 196 => 'Adieresis', 192 => 'Agrave', 913 => 'Alpha', 902 => 'Alphatonos', 256 => 'Amacron', 260 => 'Aogonek', 197 => 'Aring', 506 => 'Aringacute', 195 => 'Atilde', 66 => 'B', 914 => 'Beta', 67 => 'C', 262 => 'Cacute', 268 => 'Ccaron', 199 => 'Ccedilla', 264 => 'Ccircumflex', 266 => 'Cdotaccent', 935 => 'Chi', 68 => 'D', 270 => 'Dcaron', 272 => 'Dcroat', 916 => 'Delta', 69 => 'E', 201 => 'Eacute', 276 => 'Ebreve', 282 => 'Ecaron', 202 => 'Ecircumflex', 203 => 'Edieresis', 278 => 'Edotaccent', 200 => 'Egrave', 274 => 'Emacron', 330 => 'Eng', 280 => 'Eogonek', 917 => 'Epsilon', 904 => 'Epsilontonos', 919 => 'Eta', 905 => 'Etatonos', 208 => 'Eth', 8364 => 'Euro', 70 => 'F', 71 => 'G', 915 => 'Gamma', 286 => 'Gbreve', 486 => 'Gcaron', 284 => 'Gcircumflex', 290 => 'Gcommaaccent', 288 => 'Gdotaccent', 72 => 'H', 9679 => 'H18533', 9642 => 'H18543', 9643 => 'H18551', 9633 => 'H22073', 294 => 'Hbar', 292 => 'Hcircumflex', 73 => 'I', 306 => 'IJ', 205 => 'Iacute', 300 => 'Ibreve', 206 => 'Icircumflex', 207 => 'Idieresis', 304 => 'Idotaccent', 8465 => 'Ifraktur', 204 => 'Igrave', 298 => 'Imacron', 302 => 'Iogonek', 921 => 'Iota', 938 => 'Iotadieresis', 906 => 'Iotatonos', 296 => 'Itilde', 74 => 'J', 308 => 'Jcircumflex', 75 => 'K', 922 => 'Kappa', 310 => 'Kcommaaccent', 76 => 'L', 313 => 'Lacute', 923 => 'Lambda', 317 => 'Lcaron', 315 => 'Lcommaaccent', 319 => 'Ldot', 321 => 'Lslash', 77 => 'M', 924 => 'Mu', 78 => 'N', 323 => 'Nacute', 327 => 'Ncaron', 325 => 'Ncommaaccent', 209 => 'Ntilde', 925 => 'Nu', 79 => 'O', 338 => 'OE', 211 => 'Oacute', 334 => 'Obreve', 212 => 'Ocircumflex', 214 => 'Odieresis', 210 => 'Ograve', 416 => 'Ohorn', 336 => 'Ohungarumlaut', 332 => 'Omacron', 937 => 'Omega', 911 => 'Omegatonos', 927 => 'Omicron', 908 => 'Omicrontonos', 216 => 'Oslash', 510 => 'Oslashacute', 213 => 'Otilde', 80 => 'P', 934 => 'Phi', 928 => 'Pi', 936 => 'Psi', 81 => 'Q', 82 => 'R', 340 => 'Racute', 344 => 'Rcaron', 342 => 'Rcommaaccent', 8476 => 'Rfraktur', 929 => 'Rho', 83 => 'S', 9484 => 'SF010000', 9492 => 'SF020000', 9488 => 'SF030000', 9496 => 'SF040000', 9532 => 'SF050000', 9516 => 'SF060000', 9524 => 'SF070000', 9500 => 'SF080000', 9508 => 'SF090000', 9472 => 'SF100000', 9474 => 'SF110000', 9569 => 'SF190000', 9570 => 'SF200000', 9558 => 'SF210000', 9557 => 'SF220000', 9571 => 'SF230000', 9553 => 'SF240000', 9559 => 'SF250000', 9565 => 'SF260000', 9564 => 'SF270000', 9563 => 'SF280000', 9566 => 'SF360000', 9567 => 'SF370000', 9562 => 'SF380000', 9556 => 'SF390000', 9577 => 'SF400000', 9574 => 'SF410000', 9568 => 'SF420000', 9552 => 'SF430000', 9580 => 'SF440000', 9575 => 'SF450000', 9576 => 'SF460000', 9572 => 'SF470000', 9573 => 'SF480000', 9561 => 'SF490000', 9560 => 'SF500000', 9554 => 'SF510000', 9555 => 'SF520000', 9579 => 'SF530000', 9578 => 'SF540000', 346 => 'Sacute', 352 => 'Scaron', 350 => 'Scedilla', 348 => 'Scircumflex', 536 => 'Scommaaccent', 931 => 'Sigma', 84 => 'T', 932 => 'Tau', 358 => 'Tbar', 356 => 'Tcaron', 354 => 'Tcommaaccent', 920 => 'Theta', 222 => 'Thorn', 85 => 'U', 218 => 'Uacute', 364 => 'Ubreve', 219 => 'Ucircumflex', 220 => 'Udieresis', 217 => 'Ugrave', 431 => 'Uhorn', 368 => 'Uhungarumlaut', 362 => 'Umacron', 370 => 'Uogonek', 933 => 'Upsilon', 978 => 'Upsilon1', 939 => 'Upsilondieresis', 910 => 'Upsilontonos', 366 => 'Uring', 360 => 'Utilde', 86 => 'V', 87 => 'W', 7810 => 'Wacute', 372 => 'Wcircumflex', 7812 => 'Wdieresis', 7808 => 'Wgrave', 88 => 'X', 926 => 'Xi', 89 => 'Y', 221 => 'Yacute', 374 => 'Ycircumflex', 376 => 'Ydieresis', 7922 => 'Ygrave', 90 => 'Z', 377 => 'Zacute', 381 => 'Zcaron', 379 => 'Zdotaccent', 918 => 'Zeta', 97 => 'a', 225 => 'aacute', 259 => 'abreve', 226 => 'acircumflex', 180 => 'acute', 769 => 'acutecomb', 228 => 'adieresis', 230 => 'ae', 509 => 'aeacute', 8213 => 'afii00208', 1040 => 'afii10017', 1041 => 'afii10018', 1042 => 'afii10019', 1043 => 'afii10020', 1044 => 'afii10021', 1045 => 'afii10022', 1025 => 'afii10023', 1046 => 'afii10024', 1047 => 'afi
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* initialise table of charstring commands */
|
|
|
|
|
|
$this->cs_commands = array(
|
|
|
|
|
|
'abs' => array(12, 9 ),
|
|
|
|
|
|
'add' => array(12, 10 ),
|
|
|
|
|
|
'and' => array(12, 3 ),
|
|
|
|
|
|
'blend' => array(16, -1 ),
|
|
|
|
|
|
'callgsubr' => array(29, -1 ),
|
|
|
|
|
|
'callothersubr' => array(12, 16 ),
|
|
|
|
|
|
'callsubr' => array(10, -1 ),
|
|
|
|
|
|
'closepath' => array(9, -1 ),
|
|
|
|
|
|
'cntrmask' => array(20, -1 ),
|
|
|
|
|
|
'div' => array(12, 12 ),
|
|
|
|
|
|
'dotsection' => array(12, 0 ),
|
|
|
|
|
|
'drop' => array(12, 18 ),
|
|
|
|
|
|
'dup' => array(12, 27 ),
|
|
|
|
|
|
'endchar' => array(14, -1 ),
|
|
|
|
|
|
'eq' => array(12, 15 ),
|
|
|
|
|
|
'error' => array(0, -1 ),
|
|
|
|
|
|
'escape' => array(12, -1 ),
|
|
|
|
|
|
'exch' => array(12, 28 ),
|
|
|
|
|
|
'flex' => array(12, 35 ),
|
|
|
|
|
|
'flex1' => array(12, 37 ),
|
|
|
|
|
|
'get' => array(12, 21 ),
|
|
|
|
|
|
'hflex' => array(12, 34 ),
|
|
|
|
|
|
'hflex1' => array(12, 36 ),
|
|
|
|
|
|
'hhcurveto' => array(27, -1 ),
|
|
|
|
|
|
'hintmask' => array(19, -1 ),
|
|
|
|
|
|
'hlineto' => array(6, -1 ),
|
|
|
|
|
|
'hmoveto' => array(22, -1 ),
|
|
|
|
|
|
'hsbw' => array(13, -1 ),
|
|
|
|
|
|
'hstem' => array(1, -1 ),
|
|
|
|
|
|
'hstem3' => array(12, 2 ),
|
|
|
|
|
|
'hstemhm' => array(18, -1 ),
|
|
|
|
|
|
'hvcurveto' => array(31, -1 ),
|
|
|
|
|
|
'ifelse' => array(12, 22 ),
|
|
|
|
|
|
'index' => array(12, 29 ),
|
|
|
|
|
|
'load' => array(12, 13 ),
|
|
|
|
|
|
'mul' => array(12, 24 ),
|
|
|
|
|
|
'neg' => array(12, 14 ),
|
|
|
|
|
|
'not' => array(12, 5 ),
|
|
|
|
|
|
'or' => array(12, 4 ),
|
|
|
|
|
|
'pop' => array(12, 17 ),
|
|
|
|
|
|
'put' => array(12, 20 ),
|
|
|
|
|
|
'random' => array(12, 23 ),
|
|
|
|
|
|
'rcurveline' => array(24, -1 ),
|
|
|
|
|
|
'return' => array(11, -1 ),
|
|
|
|
|
|
'rlinecurve' => array(25, -1 ),
|
|
|
|
|
|
'rlineto' => array(5, -1 ),
|
|
|
|
|
|
'rmoveto' => array(21, -1 ),
|
|
|
|
|
|
'roll' => array(12, 30 ),
|
|
|
|
|
|
'rrcurveto' => array(8, -1 ),
|
|
|
|
|
|
'sbw' => array(12, 7 ),
|
|
|
|
|
|
'seac' => array(12, 6 ),
|
|
|
|
|
|
'setcurrentpoint' => array(12, 33 ),
|
|
|
|
|
|
'sqrt' => array(12, 26 ),
|
|
|
|
|
|
'store' => array(12, 8 ),
|
|
|
|
|
|
'sub' => array(12, 11 ),
|
|
|
|
|
|
'vhcurveto' => array(30, -1 ),
|
|
|
|
|
|
'vlineto' => array(7, -1 ),
|
|
|
|
|
|
'vmoveto' => array(4, -1 ),
|
|
|
|
|
|
'vstem' => array(3, -1 ),
|
|
|
|
|
|
'vstem3' => array(12, 1 ),
|
|
|
|
|
|
'vstemhm' => array(23, -1 ),
|
|
|
|
|
|
'vvcurveto' => array(26, -1 )
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
$this->SubroutineStr = "dup 0 15 RD \x0a\xc2\xbf1p|\x0a\x0e\x0a=-\xe2\x80\x9cD\\xc3\xa2R NP\ndup 1 9 RD \x0a\xc2\xbf1py\xc2\xbc\xc3\xb6Uz NP\ndup 2 9 RD \x0a\xc2\xbf1py\xc2\xbd\xc3\x84\xc5\xbei NP\ndup 3 5 RD \x0a\xc2\xbf1p\xc3\xb9 NP\ndup 4 12 RD \x0a\xc2\xbf1p~\xc2\xb6+6\xc3\xa46z NP\n";
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
|
|
// Public functions
|
|
|
|
|
|
|
|
|
|
|
|
function LoadFontFile($file) {
|
|
|
|
|
|
/* returns:
|
|
|
|
|
|
var $if_header;
|
|
|
|
|
|
var $if_FullName;
|
|
|
|
|
|
var $if_FontName;
|
|
|
|
|
|
var $if_FamilyName;
|
|
|
|
|
|
var $if_encs;
|
|
|
|
|
|
var $if_eexec_start;
|
|
|
|
|
|
var $if_Subrs;
|
|
|
|
|
|
var $if_CharStrings;
|
|
|
|
|
|
var $if_source;
|
|
|
|
|
|
var $fid;
|
|
|
|
|
|
var $SubroutineStr;
|
|
|
|
|
|
*/
|
|
|
|
|
|
$this->_initialise();
|
|
|
|
|
|
$mqr=ini_get("magic_quotes_runtime");
|
|
|
|
|
|
if ($mqr) { set_magic_quotes_runtime(0); }
|
|
|
|
|
|
$this->lenIV = 4;
|
|
|
|
|
|
$this->cs_start = 'RD';
|
|
|
|
|
|
$fontname = preg_replace('/.*\//', '', $file);
|
|
|
|
|
|
|
|
|
|
|
|
$this->file_ip = _MPDF_PATH.'unifont/'.$fontname;
|
|
|
|
|
|
$this->lenIV = 4;
|
|
|
|
|
|
$this->cs_start = 'RD';
|
|
|
|
|
|
|
|
|
|
|
|
$this->SubroutineStr = "dup 0 15 RD \x0a\xc2\xbf1p|\x0a\x0e\x0a=-\xe2\x80\x9cD\\xc3\xa2R NP\ndup 1 9 RD \x0a\xc2\xbf1py\xc2\xbc\xc3\xb6Uz NP\ndup 2 9 RD \x0a\xc2\xbf1py\xc2\xbd\xc3\x84\xc5\xbei NP\ndup 3 5 RD \x0a\xc2\xbf1p\xc3\xb9 NP\ndup 4 12 RD \x0a\xc2\xbf1p~\xc2\xb6+6\xc3\xa46z NP\n";
|
|
|
|
|
|
$offs = array();
|
|
|
|
|
|
include($this->file_ip .'.dat.php');
|
|
|
|
|
|
if (!isset($offs)) { die("ERROR - Data file not found to embed font subsets - ".$this->file_ip .'.dat.php'); }
|
|
|
|
|
|
$this->offs = $offs;
|
|
|
|
|
|
$fh = fopen($this->file_ip .'.dat', "rb") or die("ERROR - Data file not found to embed font subsets - ".$this->file_ip .'.char.dat');
|
|
|
|
|
|
$l = $this->_freadint($fh); // Read 4-byte integer
|
|
|
|
|
|
$this->if_header = fread($fh, $l);
|
|
|
|
|
|
$l = $this->_freadint($fh); // Read 4-byte integer
|
|
|
|
|
|
$this->if_eexec_start = fread($fh, $l);
|
|
|
|
|
|
fclose($fh);
|
|
|
|
|
|
|
|
|
|
|
|
// Read uni2gn [code-point to glyph-name] derived from .ufm file if exists
|
|
|
|
|
|
$this->uni2gn = array();
|
|
|
|
|
|
include($file.'.uni2gn.php');
|
|
|
|
|
|
if (!$this->uni2gn) { die("ERROR - Data file not found to embed font subsets - ".$this->file_ip .'.uni2gn.php'); }
|
|
|
|
|
|
if ($mqr) { set_magic_quotes_runtime($mqr); }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function SetFontName($fn) {
|
|
|
|
|
|
$this->of_FontName = $fn;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function SetFamilyName($fn) {
|
|
|
|
|
|
$this->of_FamilyName = $fn;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function SetFullName($fn) {
|
|
|
|
|
|
$this->of_FullName = $fn;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function DefineChars($chars) {
|
|
|
|
|
|
// chars = code point (decimal) => Unicode(decimal)
|
|
|
|
|
|
// convertto [0]=>'exclamationmark', [1]=>'afii080012'
|
|
|
|
|
|
// e.g of code point (decimal) => Adobe glyph name
|
|
|
|
|
|
$last_c1 = -99;
|
|
|
|
|
|
$this->pdf_diffstr = ''; // String of /Diffs for PDF file
|
|
|
|
|
|
$this->of_encodingstr = '';
|
|
|
|
|
|
$this->useChars = array();
|
|
|
|
|
|
foreach ($chars AS $c1=>$c2) { // c1 decimal codepoint => c2 decimal(Unicode)
|
|
|
|
|
|
if (isset($this->uni2gn[$c2]) && isset($this->offs[$this->uni2gn[$c2]])) {
|
|
|
|
|
|
$op = $this->uni2gn[$c2];
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
// debug** print out missing characters - not found in the t1a file
|
|
|
|
|
|
//if ($c2 >31) { echo '&#x'.dechex($c2).'; '.$c2.'; Ux'.dechex($c2).' <br />'; }
|
|
|
|
|
|
$op = '.notdef';
|
|
|
|
|
|
}
|
|
|
|
|
|
if ($c1 != ($last_c1+1)) { $this->pdf_diffstr .= $c1 . " "; }
|
|
|
|
|
|
$this->pdf_diffstr .= "/" . $op . " ";
|
|
|
|
|
|
$this->of_encodingstr .= "dup ". $c1 . " /" . $op . " put\n";
|
|
|
|
|
|
$this->useChars[] = $op;
|
|
|
|
|
|
$last_c1 = $c1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function OutputPFB($file='', $compress=true, $subr=true) {
|
|
|
|
|
|
// $subr - also get list of subroutines
|
|
|
|
|
|
// takes longer but will make more compact output file
|
|
|
|
|
|
if (empty($this->useChars) || empty($this->of_encodingstr)) {
|
|
|
|
|
|
$this->pfb_error('Error [OutputPDF]: No characters have been defined.');
|
|
|
|
|
|
}
|
|
|
|
|
|
if ($file) {
|
|
|
|
|
|
$this->dest = 'F';
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
$this->dest = 'R';
|
|
|
|
|
|
}
|
|
|
|
|
|
$this->of_size1 = 0;
|
|
|
|
|
|
$this->of_size2 = 0;
|
|
|
|
|
|
$this->op_buffer = '';
|
|
|
|
|
|
$this->wob = '';
|
|
|
|
|
|
$this->in_eexec = 0;
|
|
|
|
|
|
$this->blocktyp = $this->PFB_ASCII;
|
|
|
|
|
|
$this->pfb = 1;
|
|
|
|
|
|
$this->ever_active = 0;
|
|
|
|
|
|
$this->lenIV = 4;
|
|
|
|
|
|
$this->cs_start = 'RD';
|
|
|
|
|
|
$this->c1 = 52845;
|
|
|
|
|
|
$this->c2 = 22719;
|
|
|
|
|
|
$this->cr = 4330;
|
|
|
|
|
|
$this->er = 55665;
|
|
|
|
|
|
|
|
|
|
|
|
// Replace Header items
|
|
|
|
|
|
$this->of_header = $this->if_header;
|
|
|
|
|
|
|
|
|
|
|
|
if ($this->of_FullName)
|
|
|
|
|
|
$this->of_header = preg_replace('/(\/FullName\s+\().*?(\) readonly)/', '\\1'.$this->of_FullName.'\\2' , $this->of_header);
|
|
|
|
|
|
if ($this->of_FamilyName)
|
|
|
|
|
|
$this->of_header = preg_replace('/(\/FamilyName\s+\().*?(\) readonly)/', '\\1'.$this->of_FamilyName.'\\2' , $this->of_header);
|
|
|
|
|
|
if ($this->of_FontName)
|
|
|
|
|
|
$this->of_header = preg_replace('/(\/FontName\s+\/)\S*( def)/', '\\1'.$this->of_FontName.'\\2' , $this->of_header);
|
|
|
|
|
|
|
|
|
|
|
|
// Add Header to write output buffer
|
|
|
|
|
|
$this->wob .= $this->of_header;
|
|
|
|
|
|
// Add Encodings
|
|
|
|
|
|
$this->wob .= "/Encoding ".count($this->useChars)." array\n";
|
|
|
|
|
|
$this->wob .= $this->of_encodingstr;
|
|
|
|
|
|
$this->wob .= "readonly def\n";
|
|
|
|
|
|
$this->wob .= "currentdict end\n";
|
|
|
|
|
|
$this->wob .= "currentfile eexec\n";
|
|
|
|
|
|
|
|
|
|
|
|
// Write ASCII block to main output buffer
|
|
|
|
|
|
$this->pfb_writer_output_block();
|
|
|
|
|
|
|
|
|
|
|
|
/************ BINARY *****************/
|
|
|
|
|
|
$this->in_eexec = 1;
|
|
|
|
|
|
$this->blocktyp = $this->PFB_BINARY;
|
|
|
|
|
|
|
|
|
|
|
|
$buffer = '';
|
|
|
|
|
|
for ($i = 0; $i < $this->lenIV; $i++) {
|
|
|
|
|
|
$buffer .= chr(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
$this->eexec_string($buffer);
|
|
|
|
|
|
// Add eexec section start
|
|
|
|
|
|
$this->if_eexec_start = trim($this->if_eexec_start) . "\n";
|
|
|
|
|
|
|
|
|
|
|
|
$this->eexec_string($this->if_eexec_start);
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
|
|
// Subroutines
|
|
|
|
|
|
$this->eexec_string("/Subrs 5 array\n");
|
|
|
|
|
|
//Subrs 0 - 4 are obligatory and fixed
|
|
|
|
|
|
$this->eexec_string($this->SubroutineStr);
|
|
|
|
|
|
$this->eexec_string("ND\n2 index ");
|
|
|
|
|
|
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
|
|
// CharStrings
|
|
|
|
|
|
$of_CharStrings = array();
|
|
|
|
|
|
foreach($this->useChars AS $uc) { // glyphname e.g. lambda
|
|
|
|
|
|
if (isset($this->offs[$uc])) {
|
|
|
|
|
|
$of_CharStrings[$uc] = $this->offs[$uc];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
//NB .notdef is obligatory
|
|
|
|
|
|
$of_CharStrings['.notdef'] = $this->offs['.notdef'];
|
|
|
|
|
|
|
|
|
|
|
|
$this->eexec_string("/CharStrings ".count($of_CharStrings)." dict dup begin\n");
|
|
|
|
|
|
$fh = fopen($this->file_ip .'.dat', "rb") or die("ERROR - Data file not found to embed font subsets - ".$this->file_ip .'.dat');
|
|
|
|
|
|
foreach($of_CharStrings AS $gn => $offset) {
|
|
|
|
|
|
fseek($fh, $offset);
|
|
|
|
|
|
$l = $this->_freadint($fh); // Read 4-byte integer
|
|
|
|
|
|
$cdat = fread($fh, $l);
|
|
|
|
|
|
$this->eexec_string("/".$gn." ");
|
|
|
|
|
|
$this->eexec_string($cdat);
|
|
|
|
|
|
$this->eexec_string("\n");
|
|
|
|
|
|
}
|
|
|
|
|
|
fclose($fh);
|
|
|
|
|
|
$this->eexec_string("end\nend\nreadonly put\nnoaccess put\ndup/FontName get exch definefont pop\nmark currentfile closefile\n");
|
|
|
|
|
|
$this->pfb_writer_output_block();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ASCII trailer
|
|
|
|
|
|
$this->blocktyp = $this->PFB_ASCII;
|
|
|
|
|
|
$this->in_eexec = 0;
|
|
|
|
|
|
for ($i = 0; $i < 8; $i++) {
|
|
|
|
|
|
$this->wob .= "0000000000000000000000000000000000000000000000000000000000000000\n";
|
|
|
|
|
|
}
|
|
|
|
|
|
$this->wob .= "cleartomark\n";
|
|
|
|
|
|
$this->pfb_writer_output_block();
|
|
|
|
|
|
$this->_out(chr($this->PFB_MARKER));
|
|
|
|
|
|
$this->_out(chr($this->PFB_DONE));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Compress
|
|
|
|
|
|
if ($compress) {
|
|
|
|
|
|
$pos=strpos($this->op_buffer,'eexec');
|
|
|
|
|
|
$this->of_size1=$pos+6;
|
|
|
|
|
|
$pos=strpos($this->op_buffer,'00000000');
|
|
|
|
|
|
$this->of_size2=$pos-$this->of_size1;
|
|
|
|
|
|
$this->op_buffer=substr($this->op_buffer,0,$this->of_size1+$this->of_size2);
|
|
|
|
|
|
$this->op_buffer = gzcompress($this->op_buffer);
|
|
|
|
|
|
$this->file_op = $file.'.z';
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
$this->file_op = $file.'.pfb';
|
|
|
|
|
|
}
|
|
|
|
|
|
// Output to file or return
|
|
|
|
|
|
if ($this->dest == 'F') {
|
|
|
|
|
|
$this->ofp = fopen($this->file_op, "wb");
|
|
|
|
|
|
fwrite($this->ofp,$this->op_buffer,strlen($this->op_buffer));
|
|
|
|
|
|
fclose($this->ofp);
|
|
|
|
|
|
}
|
|
|
|
|
|
else { return $this->op_buffer; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
|
|
// Private / internal functions
|
|
|
|
|
|
function _freadint($f)
|
|
|
|
|
|
{
|
|
|
|
|
|
//Read a 4-byte integer from file
|
|
|
|
|
|
$i=ord(fread($f,1))<<24;
|
|
|
|
|
|
$i+=ord(fread($f,1))<<16;
|
|
|
|
|
|
$i+=ord(fread($f,1))<<8;
|
|
|
|
|
|
$i+=ord(fread($f,1));
|
|
|
|
|
|
return $i;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function _initialise() {
|
|
|
|
|
|
global $mpdf_tbl_prefix;
|
|
|
|
|
|
$this->tbl_prefix = $mpdf_tbl_prefix;
|
|
|
|
|
|
$this->if_source = 'F';
|
|
|
|
|
|
$this->fid = false;
|
|
|
|
|
|
$this->file_ip = '';
|
|
|
|
|
|
$this->file_op = '';
|
|
|
|
|
|
$this->op_buffer = '';
|
|
|
|
|
|
$this->if_header = '';
|
|
|
|
|
|
$this->if_FullName = '';
|
|
|
|
|
|
$this->if_FontName = '';
|
|
|
|
|
|
$this->if_FamilyName = '';
|
|
|
|
|
|
$this->if_encs = array();
|
|
|
|
|
|
$this->if_eexec_start = '';
|
|
|
|
|
|
$this->if_Subrs = array();
|
|
|
|
|
|
$this->if_CharStrings = array();
|
|
|
|
|
|
$this->SubroutineStr = '';
|
|
|
|
|
|
$this->pdf_diffstr = ''; // String of /Diffs for PDF file
|
|
|
|
|
|
$this->of_encodingstr = '';
|
|
|
|
|
|
$this->useChars = array();
|
|
|
|
|
|
$this->uni2gn = array();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function pfb_error($msg) {
|
|
|
|
|
|
echo $msg;
|
|
|
|
|
|
//die($msg);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function eencrypt($plain) {
|
|
|
|
|
|
//return $plain;
|
|
|
|
|
|
$plain = ord($plain);
|
|
|
|
|
|
$cipher = ($plain ^ ($this->er >> 8));
|
|
|
|
|
|
$this->er = (($cipher + $this->er) * $this->c1 + $this->c2) & 0xffff;
|
|
|
|
|
|
return chr($cipher);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function cencrypt($plain) {
|
|
|
|
|
|
//return $plain;
|
|
|
|
|
|
if ($this->lenIV < 0) return $plain;
|
|
|
|
|
|
$cipher = ($plain ^ ($this->cr >> 8));
|
|
|
|
|
|
$this->cr = (($cipher + $this->cr) * $this->c1 + $this->c2) & 0xffff;
|
|
|
|
|
|
return $cipher;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* This function outputs a byte through possible eexec encryption. */
|
|
|
|
|
|
function eexec_byte($b) {
|
|
|
|
|
|
if ($this->in_eexec)
|
|
|
|
|
|
$this->wob .= ($this->eencrypt($b));
|
|
|
|
|
|
else
|
|
|
|
|
|
$this->wob .= ($b);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* This function outputs a null-terminated string through possible eexec encryption. */
|
|
|
|
|
|
function eexec_string($string) {
|
|
|
|
|
|
if ($this->in_eexec) {
|
|
|
|
|
|
for($i=0; $i<strlen($string); $i++) {
|
|
|
|
|
|
$this->wob .= ($this->eencrypt(substr($string,$i,1)));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else { $this->wob .= $string; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* This function encrypts and buffers a single byte of charstring data. */
|
|
|
|
|
|
function charstring_byte($v) {
|
|
|
|
|
|
$b = ($v & 0xff);
|
|
|
|
|
|
$c = $this->cencrypt($b);
|
|
|
|
|
|
return chr($c);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* This function encodes an integer according to charstring number encoding. */
|
|
|
|
|
|
function charstring_int($num) {
|
|
|
|
|
|
$c = '';
|
|
|
|
|
|
if ($num >= -107 && $num <= 107) {
|
|
|
|
|
|
$c .= $this->charstring_byte($num + 139);
|
|
|
|
|
|
} else if ($num >= 108 && $num <= 1131) {
|
|
|
|
|
|
$x = $num - 108;
|
|
|
|
|
|
$c .= $this->charstring_byte($x / 256 + 247);
|
|
|
|
|
|
$c .= $this->charstring_byte($x % 256);
|
|
|
|
|
|
} else if ($num >= -1131 && $num <= -108) {
|
|
|
|
|
|
$x = abs($num) - 108;
|
|
|
|
|
|
$c .= $this->charstring_byte($x / 256 + 251);
|
|
|
|
|
|
$c .= $this->charstring_byte($x % 256);
|
|
|
|
|
|
} else if ($num >= (-2147483647-1) && $num <= 2147483647) {
|
|
|
|
|
|
$c .= $this->charstring_byte(255);
|
|
|
|
|
|
$c .= $this->charstring_byte($num >> 24);
|
|
|
|
|
|
$c .= $this->charstring_byte($num >> 16);
|
|
|
|
|
|
$c .= $this->charstring_byte($num >> 8);
|
|
|
|
|
|
$c .= $this->charstring_byte($num);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$this->pfb_error("can't format huge number `%d'", $num);
|
|
|
|
|
|
/* output 0 instead */
|
|
|
|
|
|
$c .= $this->charstring_byte(139);
|
|
|
|
|
|
}
|
|
|
|
|
|
return $c;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* This function parses an entire charstring into integers and commands,
|
|
|
|
|
|
outputting bytes through the charstring buffer. */
|
|
|
|
|
|
function parse_charstring($cs) {
|
|
|
|
|
|
/* initializes charstring encryption. */
|
|
|
|
|
|
$buffer = '';
|
|
|
|
|
|
$this->cr = 4330;
|
|
|
|
|
|
for ($i = 0; $i < $this->lenIV; $i++) {
|
|
|
|
|
|
$buffer .= $this->charstring_byte(chr(0));
|
|
|
|
|
|
}
|
|
|
|
|
|
$cc = preg_split('/\s+/',$cs,-1,PREG_SPLIT_NO_EMPTY);
|
|
|
|
|
|
foreach($cc AS $c) {
|
|
|
|
|
|
// Encode the integers according to charstring number encoding
|
|
|
|
|
|
if (preg_match('/^[\-]{0,1}\d+$/',$c)) {
|
|
|
|
|
|
$buffer .= $this->charstring_int($c);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Encode the commands according to charstring command encoding
|
|
|
|
|
|
else if (isset($this->cs_commands[$c])) {
|
|
|
|
|
|
$one = $this->cs_commands[$c][0];
|
|
|
|
|
|
$two = $this->cs_commands[$c][1];
|
|
|
|
|
|
if ($one < 0 || $one > 255)
|
|
|
|
|
|
$this->pfb_error("bad charstring command number $d in %s in %s", $one, $c, $cs);
|
|
|
|
|
|
else if ($two > 255)
|
|
|
|
|
|
$this->pfb_error("bad charstring command number $d in %s in %s", $two, $c, $cs);
|
|
|
|
|
|
else if ($two < 0) {
|
|
|
|
|
|
$buffer .= $this->charstring_byte($one);
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
$buffer .= $this->charstring_byte($one);
|
|
|
|
|
|
$buffer .= $this->charstring_byte($two);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
$this->pfb_error("unknown charstring entry %s in %s", $c, $cs);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
$s = sprintf("%d ", strlen($buffer));
|
|
|
|
|
|
$this->eexec_string($s);
|
|
|
|
|
|
$s = sprintf("%s ", $this->cs_start);
|
|
|
|
|
|
$this->eexec_string($s);
|
|
|
|
|
|
$this->eexec_string($buffer);
|
|
|
|
|
|
$buffer = '';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function pfb_writer_output_block() {
|
|
|
|
|
|
$l = strlen($this->wob);
|
|
|
|
|
|
if ($l == 0)
|
|
|
|
|
|
return;
|
|
|
|
|
|
/* output four-byte block length */
|
|
|
|
|
|
$this->_out(chr($this->PFB_MARKER));
|
|
|
|
|
|
$this->_out(chr($this->blocktyp));
|
|
|
|
|
|
$this->_out(chr($l & 0xff));
|
|
|
|
|
|
$this->_out(chr(($l >> 8) & 0xff));
|
|
|
|
|
|
$this->_out(chr(($l >> 16) & 0xff));
|
|
|
|
|
|
$this->_out(chr(($l >> 24) & 0xff));
|
|
|
|
|
|
/* output block data */
|
|
|
|
|
|
$this->_out($this->wob);
|
|
|
|
|
|
$this->wob = '';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function _out($s) {
|
|
|
|
|
|
$this->op_buffer .= $s;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//+++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
|
|
|
|
|
|
|
|
} // end of class
|
|
|
|
|
|
|
|
|
|
|
|
?>
|