72 public static function addTTFfont($fontfile, $fonttype=
'', $enc=
'', $flags=32, $outpath=
'', $platid=3, $encid=1, $addcbbox=
false, $link=
false) {
73 if (!file_exists($fontfile)) {
80 $font_path_parts = pathinfo($fontfile);
81 if (!isset($font_path_parts[
'filename'])) {
82 $font_path_parts[
'filename'] = substr($font_path_parts[
'basename'], 0, -(strlen($font_path_parts[
'extension']) + 1));
84 $font_name = strtolower($font_path_parts[
'filename']);
85 $font_name = preg_replace(
'/[^a-z0-9_]/',
'', $font_name);
86 $search = array(
'bold',
'oblique',
'italic',
'regular');
87 $replace = array(
'b',
'i',
'i',
'');
88 $font_name = str_replace($search, $replace, $font_name);
89 if (empty($font_name)) {
91 $font_name =
'tcpdffont';
94 if (empty($outpath)) {
95 $outpath = self::_getfontpath();
98 if (@file_exists($outpath.$font_name.
'.php')) {
102 $fmetric[
'file'] = $font_name;
103 $fmetric[
'ctg'] = $font_name.
'.ctg.z';
105 $font = file_get_contents($fontfile);
106 $fmetric[
'originalsize'] = strlen($font);
108 if (empty($fonttype)) {
111 $fonttype =
'TrueTypeUnicode';
112 } elseif (substr($font, 0, 4) ==
'OTTO') {
127 $fmetric[
'type'] =
'cidfont0';
131 $fmetric[
'type'] =
'Type1';
132 if (empty($enc) AND (($flags & 4) == 0)) {
138 $fmetric[
'type'] =
'TrueType';
141 case 'TrueTypeUnicode':
143 $fmetric[
'type'] =
'TrueTypeUnicode';
148 $fmetric[
'enc'] = preg_replace(
'/[^A-Za-z0-9_\-]/',
'', $enc);
149 $fmetric[
'diff'] =
'';
150 if (($fmetric[
'type'] ==
'TrueType') OR ($fmetric[
'type'] ==
'Type1')) {
156 for ($i = 32; $i <= 255; ++$i) {
157 if ($enc_target != $enc_ref[$i]) {
158 if ($i != ($last + 1)) {
159 $fmetric[
'diff'] .= $i.
' ';
162 $fmetric[
'diff'] .=
'/'.$enc_target[$i].
' ';
168 if ($fmetric[
'type'] ==
'Type1') {
171 $a = unpack(
'Cmarker/Ctype/Vsize', substr($font, 0, 6));
172 if ($a[
'marker'] != 128) {
176 $fmetric[
'size1'] = $a[
'size'];
177 $data = substr($font, 6, $fmetric[
'size1']);
179 $a = unpack(
'Cmarker/Ctype/Vsize', substr($font, (6 + $fmetric[
'size1']), 6));
180 if ($a[
'marker'] != 128) {
184 $fmetric[
'size2'] = $a[
'size'];
185 $encrypted = substr($font, (12 + $fmetric[
'size1']), $fmetric[
'size2']);
188 $fmetric[
'file'] .=
'.z';
189 $fp = fopen($outpath.$fmetric[
'file'],
'wb');
190 fwrite($fp, gzcompress($data));
193 $fmetric[
'Flags'] = $flags;
194 preg_match (
'#/FullName[\s]*\(([^\)]*)#', $font, $matches);
195 $fmetric[
'name'] = preg_replace(
'/[^a-zA-Z0-9_\-]/',
'', $matches[1]);
196 preg_match(
'#/FontBBox[\s]*{([^}]*)#', $font, $matches);
197 $fmetric[
'bbox'] = trim($matches[1]);
198 $bv = explode(
' ', $fmetric[
'bbox']);
199 $fmetric[
'Ascent'] = intval($bv[3]);
200 $fmetric[
'Descent'] = intval($bv[1]);
201 preg_match(
'#/ItalicAngle[\s]*([0-9\+\-]*)#', $font, $matches);
202 $fmetric[
'italicAngle'] = intval($matches[1]);
203 if ($fmetric[
'italicAngle'] != 0) {
204 $fmetric[
'Flags'] |= 64;
206 preg_match(
'#/UnderlinePosition[\s]*([0-9\+\-]*)#', $font, $matches);
207 $fmetric[
'underlinePosition'] = intval($matches[1]);
208 preg_match(
'#/UnderlineThickness[\s]*([0-9\+\-]*)#', $font, $matches);
209 $fmetric[
'underlineThickness'] = intval($matches[1]);
210 preg_match(
'#/isFixedPitch[\s]*([^\s]*)#', $font, $matches);
211 if ($matches[1] ==
'true') {
212 $fmetric[
'Flags'] |= 1;
216 if (preg_match_all(
'#dup[\s]([0-9]+)[\s]*/([^\s]*)[\s]put#sU', $font, $fmap, PREG_SET_ORDER) > 0) {
217 foreach ($fmap as $v) {
218 $imap[$v[2]] = $v[1];
225 $elen = strlen($encrypted);
227 for ($i = 0; $i < $elen; ++$i) {
228 $chr = ord($encrypted[$i]);
229 $eplain .= chr($chr ^ ($r >> 8));
230 $r = ((($chr + $r) * $c1 + $c2) % 65536);
232 if (preg_match(
'#/ForceBold[\s]*([^\s]*)#', $eplain, $matches) > 0) {
233 if ($matches[1] ==
'true') {
234 $fmetric[
'Flags'] |= 0x40000;
237 if (preg_match(
'#/StdVW[\s]*\[([^\]]*)#', $eplain, $matches) > 0) {
238 $fmetric[
'StemV'] = intval($matches[1]);
240 $fmetric[
'StemV'] = 70;
242 if (preg_match(
'#/StdHW[\s]*\[([^\]]*)#', $eplain, $matches) > 0) {
243 $fmetric[
'StemH'] = intval($matches[1]);
245 $fmetric[
'StemH'] = 30;
247 if (preg_match(
'#/BlueValues[\s]*\[([^\]]*)#', $eplain, $matches) > 0) {
248 $bv = explode(
' ', $matches[1]);
249 if (count($bv) >= 6) {
250 $v1 = intval($bv[2]);
251 $v2 = intval($bv[4]);
253 $fmetric[
'XHeight'] = $v1;
254 $fmetric[
'CapHeight'] = $v2;
256 $fmetric[
'XHeight'] = $v2;
257 $fmetric[
'CapHeight'] = $v1;
260 $fmetric[
'XHeight'] = 450;
261 $fmetric[
'CapHeight'] = 700;
264 $fmetric[
'XHeight'] = 450;
265 $fmetric[
'CapHeight'] = 700;
268 if (preg_match(
'#/lenIV[\s]*([0-9]*)#', $eplain, $matches) > 0) {
269 $lenIV = intval($matches[1]);
273 $fmetric[
'Leading'] = 0;
275 $eplain = substr($eplain, (strpos($eplain,
'/CharStrings') + 1));
276 preg_match_all(
'#/([A-Za-z0-9\.]*)[\s][0-9]+[\s]RD[\s](.*)[\s]ND#sU', $eplain, $matches, PREG_SET_ORDER);
283 $fmetric[
'MaxWidth'] = 0;
285 foreach ($matches as $k => $v) {
287 if (isset($imap[$v[1]])) {
289 } elseif ($enc_map !==
false) {
290 $cid = array_search($v[1], $enc_map);
291 if ($cid ===
false) {
293 } elseif ($cid > 1000) {
304 for ($i = 0; $i < $clen; ++$i) {
306 $ccom[] = ($chr ^ ($r >> 8));
307 $r = ((($chr + $r) * $c1 + $c2) % 65536);
314 if ($ccom[$i] < 32) {
315 $cdec[$ck] = $ccom[$i];
316 if (($ck > 0) AND ($cdec[$ck] == 13)) {
318 $cwidths[$cid] = $cdec[($ck - 1)];
321 } elseif (($ccom[$i] >= 32) AND ($ccom[$i] <= 246)) {
322 $cdec[$ck] = ($ccom[$i] - 139);
324 } elseif (($ccom[$i] >= 247) AND ($ccom[$i] <= 250)) {
325 $cdec[$ck] = ((($ccom[$i] - 247) * 256) + $ccom[($i + 1)] + 108);
327 } elseif (($ccom[$i] >= 251) AND ($ccom[$i] <= 254)) {
328 $cdec[$ck] = ((-($ccom[$i] - 251) * 256) - $ccom[($i + 1)] - 108);
330 } elseif ($ccom[$i] == 255) {
331 $sval = chr($ccom[($i + 1)]).chr($ccom[($i + 2)]).chr($ccom[($i + 3)]).chr($ccom[($i + 4)]);
332 $vsval = unpack(
'li', $sval);
333 $cdec[$ck] = $vsval[
'i'];
339 $fmetric[
'MissingWidth'] = $cwidths[0];
340 $fmetric[
'MaxWidth'] = $fmetric[
'MissingWidth'];
341 $fmetric[
'AvgWidth'] = 0;
343 for ($cid = 0; $cid <= 255; ++$cid) {
344 if (isset($cwidths[$cid])) {
345 if ($cwidths[$cid] > $fmetric[
'MaxWidth']) {
346 $fmetric[
'MaxWidth'] = $cwidths[$cid];
348 $fmetric[
'AvgWidth'] += $cwidths[$cid];
349 $fmetric[
'cw'] .=
','.$cid.
'=>'.$cwidths[$cid];
351 $fmetric[
'cw'] .=
','.$cid.
'=>'.$fmetric[
'MissingWidth'];
354 $fmetric[
'AvgWidth'] = round($fmetric[
'AvgWidth'] / count($cwidths));
357 if ($fmetric[
'type'] !=
'cidfont0') {
360 symlink($fontfile, $outpath.$fmetric[
'file']);
363 $fmetric[
'file'] .=
'.z';
364 $fp = fopen($outpath.$fmetric[
'file'],
'wb');
365 fwrite($fp, gzcompress($font));
383 for ($i = 0; $i < $numTables; ++$i) {
385 $tag = substr($font, $offset, 4);
387 $table[$tag] = array();
396 $offset = $table[
'head'][
'offset'] + 12;
407 $urk = (1000 / $fmetric[
'unitsPerEm']);
417 $fmetric[
'bbox'] =
''.$xMin.
' '.$yMin.
' '.$xMax.
' '.$yMax.
'';
421 $fmetric[
'Flags'] = $flags;
422 if (($macStyle & 2) == 2) {
424 $fmetric[
'Flags'] |= 64;
427 $offset = $table[
'head'][
'offset'] + 50;
431 $indexToLoc = array();
432 $offset = $table[
'loca'][
'offset'];
435 $tot_num_glyphs = floor($table[
'loca'][
'length'] / 2);
436 for ($i = 0; $i < $tot_num_glyphs; ++$i) {
442 $tot_num_glyphs = floor($table[
'loca'][
'length'] / 4);
443 for ($i = 0; $i < $tot_num_glyphs; ++$i) {
449 $offset = $table[
'cmap'][
'offset'] + 2;
452 $encodingTables = array();
453 for ($i = 0; $i < $numEncodingTables; ++$i) {
462 $offset = $table[
'OS/2'][
'offset'];
470 $fmetric[
'StemV'] = round((70 * $usWeightClass) / 400);
471 $fmetric[
'StemH'] = round((30 * $usWeightClass) / 400);
481 $fmetric[
'name'] =
'';
482 $offset = $table[
'name'][
'offset'];
490 for ($i = 0; $i < $numNameRecords; ++$i) {
502 $offset = ($table[
'name'][
'offset'] + $stringStorageOffset + $stringOffset);
503 $fmetric[
'name'] = substr($font, $offset, $stringLength);
504 $fmetric[
'name'] = preg_replace(
'/[^a-zA-Z0-9_\-]/',
'', $fmetric[
'name']);
510 if (empty($fmetric[
'name'])) {
511 $fmetric[
'name'] = $font_name;
514 $offset = $table[
'post'][
'offset'];
525 $fmetric[
'Flags'] |= 1;
528 $offset = $table[
'hhea'][
'offset'];
546 $offset = $table[
'maxp'][
'offset'];
552 foreach ($encodingTables as $enctable) {
554 if (($enctable[
'platformID'] == $platid) AND ($enctable[
'encodingID'] == $encid)) {
555 $offset = $table[
'cmap'][
'offset'] + $enctable[
'offset'];
561 for ($c = 0; $c < 256; ++$c) {
571 for ($i = 0; $i < 256; ++$i) {
575 if ($numSubHeaders < $subHeaderKeys[$i]) {
576 $numSubHeaders = $subHeaderKeys[$i];
582 $subHeaders = array();
583 $numGlyphIndexArray = 0;
584 for ($k = 0; $k < $numSubHeaders; ++$k) {
593 $subHeaders[$k][
'idRangeOffset'] -= (2 + (($numSubHeaders - $k - 1) * 8));
594 $subHeaders[$k][
'idRangeOffset'] /= 2;
595 $numGlyphIndexArray += $subHeaders[$k][
'entryCount'];
597 for ($k = 0; $k < $numGlyphIndexArray; ++$k) {
601 for ($i = 0; $i < 256; ++$i) {
602 $k = $subHeaderKeys[$i];
606 $g = $glyphIndexArray[0];
610 $start_byte = $subHeaders[$k][
'firstCode'];
611 $end_byte = $start_byte + $subHeaders[$k][
'entryCount'];
612 for ($j = $start_byte; $j < $end_byte; ++$j) {
614 $c = (($i << 8) + $j);
615 $idRangeOffset = ($subHeaders[$k][
'idRangeOffset'] + $j - $subHeaders[$k][
'firstCode']);
616 $g = ($glyphIndexArray[$idRangeOffset] + $subHeaders[$k][
'idDelta']) % 65536;
634 for ($k = 0; $k < $segCount; ++$k) {
639 $startCount = array();
640 for ($k = 0; $k < $segCount; ++$k) {
645 for ($k = 0; $k < $segCount; ++$k) {
649 $idRangeOffset = array();
650 for ($k = 0; $k < $segCount; ++$k) {
654 $gidlen = (floor($length / 2) - 8 - (4 * $segCount));
655 $glyphIdArray = array();
656 for ($k = 0; $k < $gidlen; ++$k) {
660 for ($k = 0; $k < $segCount; ++$k) {
661 for ($c = $startCount[$k]; $c <= $endCount[$k]; ++$c) {
662 if ($idRangeOffset[$k] == 0) {
663 $g = ($idDelta[$k] + $c) % 65536;
665 $gid = (floor($idRangeOffset[$k] / 2) + ($c - $startCount[$k]) - ($segCount - $k));
666 $g = ($glyphIdArray[$gid] + $idDelta[$k]) % 65536;
682 for ($k = 0; $k < $entryCount; ++$k) {
683 $c = ($k + $firstCode);
692 for ($k = 0; $k < 8192; ++$k) {
698 for ($i = 0; $i < $nGroups; ++$i) {
705 for ($k = $startCharCode; $k <= $endCharCode; ++$k) {
706 $is32idx = floor($c / 8);
707 if ((isset($is32[$is32idx])) AND (($is32[$is32idx] & (1 << (7 - ($c % 8)))) == 0)) {
714 $c = ((55232 + ($k >> 10)) << 10) + (0xDC00 + ($k & 0x3FF)) -56613888;
728 for ($k = 0; $k < $numChars; ++$k) {
729 $c = ($k + $startCharCode);
740 for ($k = 0; $k < $nGroups; ++$k) {
747 for ($c = $startCharCode; $c <= $endCharCode; ++$c) {
748 $ctg[$c] = $startGlyphCode;
765 if (!isset($ctg[0])) {
769 $offset = ($table[
'glyf'][
'offset'] + $indexToLoc[$ctg[120]] + 4);
774 $fmetric[
'XHeight'] = round(($yMax - $yMin) * $urk);
776 $offset = ($table[
'glyf'][
'offset'] + $indexToLoc[$ctg[72]] + 4);
781 $fmetric[
'CapHeight'] = round(($yMax - $yMin) * $urk);
784 $offset = $table[
'hmtx'][
'offset'];
785 for ($i = 0 ; $i < $numberOfHMetrics; ++$i) {
789 if ($numberOfHMetrics < $numGlyphs) {
791 $cw = array_pad($cw, $numGlyphs, $cw[($numberOfHMetrics - 1)]);
793 $fmetric[
'MissingWidth'] = $cw[0];
795 for ($cid = 0; $cid <= 65535; ++$cid) {
796 if (isset($ctg[$cid])) {
797 if (isset($cw[$ctg[$cid]])) {
798 $fmetric[
'cw'] .=
','.$cid.
'=>'.$cw[$ctg[$cid]];
800 if ($addcbbox AND isset($indexToLoc[$ctg[$cid]])) {
801 $offset = ($table[
'glyf'][
'offset'] + $indexToLoc[$ctg[$cid]]);
806 $fmetric[
'cbbox'] .=
','.$cid.
'=>array('.$xMin.
','.$yMin.
','.$xMax.
','.$yMax.
')';
811 if (($fmetric[
'type'] ==
'TrueTypeUnicode') AND (count($ctg) == 256)) {
812 $fmetric[
'type'] ==
'TrueType';
815 $pfile =
'<'.
'?'.
'php'.
"\n";
816 $pfile .=
'// TCPDF FONT FILE DESCRIPTION'.
"\n";
817 $pfile .=
'$type=\''.$fmetric[
'type'].
'\';
'."\n";
818 $pfile .= '$name=\
''.$fmetric[
'name'].
'\';
'."\n";
819 $pfile .= '$up=
'.$fmetric['underlinePosition
'].';
'."\n";
820 $pfile .= '$ut=
'.$fmetric['underlineThickness
'].';
'."\n";
821 if ($fmetric['MissingWidth
'] > 0) {
822 $pfile .= '$dw=
'.$fmetric['MissingWidth
'].';
'."\n";
824 $pfile .= '$dw=
'.$fmetric['AvgWidth
'].';
'."\n";
826 $pfile .= '$diff=\
''.$fmetric[
'diff'].
'\';
'."\n";
827 if ($fmetric['type
'] == 'Type1
') {
829 $pfile .= '$enc=\
''.$fmetric[
'enc'].
'\';
'."\n";
830 $pfile .= '$file=\
''.$fmetric[
'file'].
'\';
'."\n";
831 $pfile .= '$size1=
'.$fmetric['size1
'].';
'."\n";
832 $pfile .= '$size2=
'.$fmetric['size2
'].';
'."\n";
834 $pfile .= '$originalsize=
'.$fmetric['originalsize
'].';
'."\n";
835 if ($fmetric['type
'] == 'cidfont0
') {
840 $pfile .=
'$enc=\'UniJIS-UTF16-H\';'.
"\n";
841 $pfile .=
'$cidinfo=array(\'Registry\'=>\'Adobe\', \'Ordering\'=>\'Japan1\',\'Supplement\'=>5);'.
"\n";
842 $pfile .=
'include(dirname(__FILE__).\'/uni2cid_aj16.php\');'.
"\n";
846 $pfile .=
'// Korean'.
"\n";
847 $pfile .=
'$enc=\'UniKS-UTF16-H\';'.
"\n";
848 $pfile .=
'$cidinfo=array(\'Registry\'=>\'Adobe\', \'Ordering\'=>\'Korea1\',\'Supplement\'=>0);'.
"\n";
849 $pfile .=
'include(dirname(__FILE__).\'/uni2cid_ak12.php\');'.
"\n";
853 $pfile .=
'// Chinese Simplified'.
"\n";
854 $pfile .=
'$enc=\'UniGB-UTF16-H\';'.
"\n";
855 $pfile .=
'$cidinfo=array(\'Registry\'=>\'Adobe\', \'Ordering\'=>\'GB1\',\'Supplement\'=>2);'.
"\n";
856 $pfile .=
'include(dirname(__FILE__).\'/uni2cid_ag15.php\');'.
"\n";
861 $pfile .=
'// Chinese Traditional'.
"\n";
862 $pfile .=
'$enc=\'UniCNS-UTF16-H\';'.
"\n";
863 $pfile .=
'$cidinfo=array(\'Registry\'=>\'Adobe\', \'Ordering\'=>\'CNS1\',\'Supplement\'=>0);'.
"\n";
864 $pfile .=
'include(dirname(__FILE__).\'/uni2cid_aj16.php\');'.
"\n";
870 $pfile .=
'$enc=\''.$fmetric[
'enc'].
'\';
'."\n";
871 $pfile .= '$file=\
''.$fmetric[
'file'].
'\';
'."\n";
872 $pfile .= '$ctg=\
''.$fmetric[
'ctg'].
'\';
'."\n";
873 // create CIDToGIDMap
874 $cidtogidmap = str_pad('', 131072, "\x00"); // (256 * 256 * 2) = 131072
875 foreach ($ctg as $cid => $gid) {
876 $cidtogidmap = self::updateCIDtoGIDmap($cidtogidmap, $cid, $ctg[$cid]);
878 // store compressed CIDToGIDMap
879 $fp = fopen($outpath.$fmetric['ctg
'], 'wb
');
880 fwrite($fp, gzcompress($cidtogidmap));
884 $pfile .= '$desc=array(
';
885 $pfile .= '\
'Flags\'=>'.$fmetric[
'Flags'].
',';
886 $pfile .=
'\'FontBBox\
'=>\'['.$fmetric[
'bbox'].
']\',';
887 $pfile .=
'\'ItalicAngle\
'=>'.$fmetric[
'italicAngle'].
',';
888 $pfile .=
'\'Ascent\
'=>'.$fmetric[
'Ascent'].
',';
889 $pfile .=
'\'Descent\
'=>'.$fmetric[
'Descent'].
',';
890 $pfile .=
'\'Leading\
'=>'.$fmetric[
'Leading'].
',';
891 $pfile .=
'\'CapHeight\
'=>'.$fmetric[
'CapHeight'].
',';
892 $pfile .=
'\'XHeight\
'=>'.$fmetric[
'XHeight'].
',';
893 $pfile .=
'\'StemV\
'=>'.$fmetric[
'StemV'].
',';
894 $pfile .=
'\'StemH\
'=>'.$fmetric[
'StemH'].
',';
895 $pfile .=
'\'AvgWidth\
'=>'.$fmetric[
'AvgWidth'].
',';
896 $pfile .=
'\'MaxWidth\
'=>'.$fmetric[
'MaxWidth'].
',';
897 $pfile .=
'\'MissingWidth\
'=>'.$fmetric[
'MissingWidth'].
'';
899 if (isset($fmetric[
'cbbox'])) {
900 $pfile .=
'$cbbox=array('.substr($fmetric[
'cbbox'], 1).
');'.
"\n";
902 $pfile .=
'$cw=array('.substr($fmetric[
'cw'], 1).
');'.
"\n";
903 $pfile .=
'// --- EOF ---'.
"\n";
905 $fp = fopen($outpath.$font_name.
'.php',
'w');
923 $tlen = ($length / 4);
925 for ($i = 0; $i < $tlen; ++$i) {
926 $v = unpack(
'Ni', substr($table, $offset, 4));
930 $sum = unpack(
'Ni', pack(
'N', $sum));
959 for ($i = 0; $i < $numTables; ++$i) {
961 $tag = substr($font, $offset, 4);
963 $table[$tag] = array();
972 $offset = $table[
'head'][
'offset'] + 12;
979 $offset = $table[
'head'][
'offset'] + 50;
983 $indexToLoc = array();
984 $offset = $table[
'loca'][
'offset'];
987 $tot_num_glyphs = floor($table[
'loca'][
'length'] / 2);
988 for ($i = 0; $i < $tot_num_glyphs; ++$i) {
994 $tot_num_glyphs = ($table[
'loca'][
'length'] / 4);
995 for ($i = 0; $i < $tot_num_glyphs; ++$i) {
1001 $subsetglyphs = array();
1002 $subsetglyphs[0] =
true;
1003 $offset = $table[
'cmap'][
'offset'] + 2;
1006 $encodingTables = array();
1007 for ($i = 0; $i < $numEncodingTables; ++$i) {
1015 foreach ($encodingTables as $enctable) {
1017 $offset = $table[
'cmap'][
'offset'] + $enctable[
'offset'];
1023 for ($c = 0; $c < 256; ++$c) {
1024 if (isset($subsetchars[$c])) {
1026 $subsetglyphs[$g] =
true;
1035 for ($i = 0; $i < 256; ++$i) {
1039 if ($numSubHeaders < $subHeaderKeys[$i]) {
1040 $numSubHeaders = $subHeaderKeys[$i];
1046 $subHeaders = array();
1047 $numGlyphIndexArray = 0;
1048 for ($k = 0; $k < $numSubHeaders; ++$k) {
1057 $subHeaders[$k][
'idRangeOffset'] -= (2 + (($numSubHeaders - $k - 1) * 8));
1058 $subHeaders[$k][
'idRangeOffset'] /= 2;
1059 $numGlyphIndexArray += $subHeaders[$k][
'entryCount'];
1061 for ($k = 0; $k < $numGlyphIndexArray; ++$k) {
1065 for ($i = 0; $i < 256; ++$i) {
1066 $k = $subHeaderKeys[$i];
1070 if (isset($subsetchars[$c])) {
1071 $g = $glyphIndexArray[0];
1072 $subsetglyphs[$g] =
true;
1076 $start_byte = $subHeaders[$k][
'firstCode'];
1077 $end_byte = $start_byte + $subHeaders[$k][
'entryCount'];
1078 for ($j = $start_byte; $j < $end_byte; ++$j) {
1080 $c = (($i << 8) + $j);
1081 if (isset($subsetchars[$c])) {
1082 $idRangeOffset = ($subHeaders[$k][
'idRangeOffset'] + $j - $subHeaders[$k][
'firstCode']);
1083 $g = ($glyphIndexArray[$idRangeOffset] + $subHeaders[$k][
'idDelta']) % 65536;
1087 $subsetglyphs[$g] =
true;
1101 $endCount = array();
1102 for ($k = 0; $k < $segCount; ++$k) {
1107 $startCount = array();
1108 for ($k = 0; $k < $segCount; ++$k) {
1113 for ($k = 0; $k < $segCount; ++$k) {
1117 $idRangeOffset = array();
1118 for ($k = 0; $k < $segCount; ++$k) {
1122 $gidlen = (floor($length / 2) - 8 - (4 * $segCount));
1123 $glyphIdArray = array();
1124 for ($k = 0; $k < $gidlen; ++$k) {
1128 for ($k = 0; $k < $segCount; ++$k) {
1129 for ($c = $startCount[$k]; $c <= $endCount[$k]; ++$c) {
1130 if (isset($subsetchars[$c])) {
1131 if ($idRangeOffset[$k] == 0) {
1132 $g = ($idDelta[$k] + $c) % 65536;
1134 $gid = (floor($idRangeOffset[$k] / 2) + ($c - $startCount[$k]) - ($segCount - $k));
1135 $g = ($glyphIdArray[$gid] + $idDelta[$k]) % 65536;
1140 $subsetglyphs[$g] =
true;
1152 for ($k = 0; $k < $entryCount; ++$k) {
1153 $c = ($k + $firstCode);
1154 if (isset($subsetchars[$c])) {
1156 $subsetglyphs[$g] =
true;
1164 for ($k = 0; $k < 8192; ++$k) {
1170 for ($i = 0; $i < $nGroups; ++$i) {
1177 for ($k = $startCharCode; $k <= $endCharCode; ++$k) {
1178 $is32idx = floor($c / 8);
1179 if ((isset($is32[$is32idx])) AND (($is32[$is32idx] & (1 << (7 - ($c % 8)))) == 0)) {
1186 $c = ((55232 + ($k >> 10)) << 10) + (0xDC00 + ($k & 0x3FF)) -56613888;
1188 if (isset($subsetchars[$c])) {
1189 $subsetglyphs[$startGlyphID] =
true;
1202 for ($k = 0; $k < $numChars; ++$k) {
1203 $c = ($k + $startCharCode);
1204 if (isset($subsetchars[$c])) {
1206 $subsetglyphs[$g] =
true;
1216 for ($k = 0; $k < $nGroups; ++$k) {
1223 for ($c = $startCharCode; $c <= $endCharCode; ++$c) {
1224 if (isset($subsetchars[$c])) {
1225 $subsetglyphs[$startGlyphCode] =
true;
1243 $new_sga = $subsetglyphs;
1244 while (!empty($new_sga)) {
1247 foreach ($sga as $key => $val) {
1248 if (isset($indexToLoc[$key])) {
1249 $offset = ($table[
'glyf'][
'offset'] + $indexToLoc[$key]);
1252 if ($numberOfContours < 0) {
1259 if (!isset($subsetglyphs[$glyphIndex])) {
1261 $new_sga[$glyphIndex] =
true;
1271 } elseif ($flags & 64) {
1273 } elseif ($flags & 128) {
1276 }
while ($flags & 32);
1280 $subsetglyphs += $new_sga;
1283 ksort($subsetglyphs);
1288 $glyf_offset = $table[
'glyf'][
'offset'];
1289 for ($i = 0; $i < $tot_num_glyphs; ++$i) {
1290 if (isset($subsetglyphs[$i])) {
1291 $length = ($indexToLoc[($i + 1)] - $indexToLoc[$i]);
1292 $glyf .= substr($font, ($glyf_offset + $indexToLoc[$i]), $length);
1296 if ($short_offset) {
1297 $loca .= pack(
'n', floor($offset / 2));
1299 $loca .= pack(
'N', $offset);
1305 $table_names = array (
'head',
'hhea',
'hmtx',
'maxp',
'cvt ',
'fpgm',
'prep');
1308 foreach ($table as $tag => $val) {
1309 if (in_array($tag, $table_names)) {
1310 $table[$tag][
'data'] = substr($font, $table[$tag][
'offset'], $table[$tag][
'length']);
1311 if ($tag ==
'head') {
1313 $table[$tag][
'data'] = substr($table[$tag][
'data'], 0, 8).
"\x0\x0\x0\x0".substr($table[$tag][
'data'], 12);
1315 $pad = 4 - ($table[$tag][
'length'] % 4);
1318 $table[$tag][
'length'] += $pad;
1319 $table[$tag][
'data'] .= str_repeat(
"\x0", $pad);
1321 $table[$tag][
'offset'] = $offset;
1322 $offset += $table[$tag][
'length'];
1326 unset($table[$tag]);
1330 $table[
'loca'][
'data'] = $loca;
1331 $table[
'loca'][
'length'] = strlen($loca);
1332 $pad = 4 - ($table[
'loca'][
'length'] % 4);
1335 $table[
'loca'][
'length'] += $pad;
1336 $table[
'loca'][
'data'] .= str_repeat(
"\x0", $pad);
1338 $table[
'loca'][
'offset'] = $offset;
1339 $table[
'loca'][
'checkSum'] = self::_getTTFtableChecksum($table[
'loca'][
'data'], $table[
'loca'][
'length']);
1340 $offset += $table[
'loca'][
'length'];
1342 $table[
'glyf'][
'data'] = $glyf;
1343 $table[
'glyf'][
'length'] = strlen($glyf);
1344 $pad = 4 - ($table[
'glyf'][
'length'] % 4);
1347 $table[
'glyf'][
'length'] += $pad;
1348 $table[
'glyf'][
'data'] .= str_repeat(
"\x0", $pad);
1350 $table[
'glyf'][
'offset'] = $offset;
1351 $table[
'glyf'][
'checkSum'] = self::_getTTFtableChecksum($table[
'glyf'][
'data'], $table[
'glyf'][
'length']);
1354 $font .= pack(
'N', 0x10000);
1355 $numTables = count($table);
1356 $font .= pack(
'n', $numTables);
1357 $entrySelector = floor(log($numTables, 2));
1358 $searchRange = pow(2, $entrySelector) * 16;
1359 $rangeShift = ($numTables * 16) - $searchRange;
1360 $font .= pack(
'n', $searchRange);
1361 $font .= pack(
'n', $entrySelector);
1362 $font .= pack(
'n', $rangeShift);
1363 $offset = ($numTables * 16);
1364 foreach ($table as $tag => $data) {
1366 $font .= pack(
'N', $data[
'checkSum']);
1367 $font .= pack(
'N', ($data[
'offset'] + $offset));
1368 $font .= pack(
'N', $data[
'length']);
1370 foreach ($table as $data) {
1371 $font .= $data[
'data'];
1374 $checkSumAdjustment = 0xB1B0AFBA - self::_getTTFtableChecksum($font, strlen($font));
1375 $font = substr($font, 0, $table[
'head'][
'offset'] + 8).pack(
'N', $checkSumAdjustment).substr($font, $table[
'head'][
'offset'] + 12);
1396 foreach ($font[
'cw'] as $cid => $width) {
1398 if ($font[
'subset'] AND (!isset($font[
'subsetchars'][$cid]))) {
1402 if ($width != $font[
'dw']) {
1403 if ($cid == ($prevcid + 1)) {
1405 if ($width == $prevwidth) {
1406 if ($width == $range[$rangeid][0]) {
1407 $range[$rangeid][] = $width;
1409 array_pop($range[$rangeid]);
1411 $rangeid = $prevcid;
1412 $range[$rangeid] = array();
1413 $range[$rangeid][] = $prevwidth;
1414 $range[$rangeid][] = $width;
1417 $range[$rangeid][
'interval'] =
true;
1422 $range[$rangeid] = array();
1423 $range[$rangeid][] = $width;
1425 $range[$rangeid][] = $width;
1432 $range[$rangeid] = array();
1433 $range[$rangeid][] = $width;
1437 $prevwidth = $width;
1444 foreach ($range as $k => $ws) {
1446 if (($k == $nextk) AND (!$prevint) AND ((!isset($ws[
'interval'])) OR ($cws < 4))) {
1447 if (isset($range[$k][
'interval'])) {
1448 unset($range[$k][
'interval']);
1450 $range[$prevk] = array_merge($range[$prevk], $range[$k]);
1456 if (isset($ws[
'interval'])) {
1462 if (isset($range[$k][
'interval'])) {
1463 unset($range[$k][
'interval']);
1472 foreach ($range as $k => $ws) {
1473 if (count(array_count_values($ws)) == 1) {
1475 $w .=
' '.$k.
' '.($k + count($ws) - 1).
' '.$ws[0];
1478 $w .=
' '.$k.
' [ '.implode(
' ', $ws).
' ]';
1481 return '/W ['.$w.
' ]';
1492 public static function unichr($c, $unicode=
true) {
1495 } elseif ($c <= 0x7F) {
1498 } elseif ($c <= 0x7FF) {
1500 return chr(0xC0 | $c >> 6).chr(0x80 | $c & 0x3F);
1501 } elseif ($c <= 0xFFFF) {
1503 return chr(0xE0 | $c >> 12).chr(0x80 | $c >> 6 & 0x3F).chr(0x80 | $c & 0x3F);
1504 } elseif ($c <= 0x10FFFF) {
1506 return chr(0xF0 | $c >> 18).chr(0x80 | $c >> 12 & 0x3F).chr(0x80 | $c >> 6 & 0x3F).chr(0x80 | $c & 0x3F);
1519 return self::unichr($c,
true);
1529 return self::unichr($c,
false);
1573 $outstr .=
"\xFE\xFF";
1575 foreach ($unicode as $char) {
1576 if ($char == 0x200b) {
1578 } elseif ($char == 0xFFFD) {
1579 $outstr .=
"\xFF\xFD";
1580 } elseif ($char < 0x10000) {
1581 $outstr .= chr($char >> 0x08);
1582 $outstr .= chr($char & 0xFF);
1585 $w1 = 0xD800 | ($char >> 0x0a);
1586 $w2 = 0xDC00 | ($char & 0x3FF);
1587 $outstr .= chr($w1 >> 0x08);
1588 $outstr .= chr($w1 & 0xFF);
1589 $outstr .= chr($w2 >> 0x08);
1590 $outstr .= chr($w2 & 0xFF);
1606 return array_map(array(
'TCPDF_FONTS',
'unichrUnicode'), $ta);
1608 return array_map(array(
'TCPDF_FONTS',
'unichrASCII'), $ta);
1621 if (strlen($start) == 0) {
1624 if (strlen($end) == 0) {
1625 $end = count($strarr);
1628 for ($i = $start; $i < $end; ++$i) {
1629 $string .= self::unichr($strarr[$i], $unicode);
1644 if (strlen($start) == 0) {
1647 if (strlen($end) == 0) {
1648 $end = count($uniarr);
1651 for ($i=$start; $i < $end; ++$i) {
1652 $string .= $uniarr[$i];
1668 if (($cid >= 0) AND ($cid <= 0xFFFF) AND ($gid >= 0)) {
1669 if ($gid > 0xFFFF) {
1672 $map[($cid * 2)] = chr($gid >> 8);
1673 $map[(($cid * 2) + 1)] = chr($gid & 0xFF);
1684 if (!defined(
'K_PATH_FONTS') AND is_dir($fdir = realpath(dirname(__FILE__).
'/../fonts'))) {
1685 if (substr($fdir, -1) !=
'/') {
1688 define(
'K_PATH_FONTS', $fdir);
1690 return defined(
'K_PATH_FONTS') ? K_PATH_FONTS :
'';
1705 if (($fontdir !==
false) AND @file_exists($fontdir.$file)) {
1706 $fontfile = $fontdir.$file;
1707 } elseif (@file_exists(self::_getfontpath().$file)) {
1708 $fontfile = self::_getfontpath().$file;
1709 } elseif (@file_exists($file)) {
1725 foreach ($unicode as $char) {
1731 } elseif ($char == 0xFFFD) {
1750 foreach ($unicode as $char) {
1752 $outstr .= chr($char);
1756 } elseif ($char == 0xFFFD) {
1773 if (!isset(self::$cache_uniord[$uch])) {
1774 self::$cache_uniord[$uch] = self::getUniord($uch);
1776 return self::$cache_uniord[$uch];
1813 if (function_exists(
'mb_convert_encoding')) {
1814 list(, $char) = @unpack(
'N', mb_convert_encoding($uch,
'UCS-4BE',
'UTF-8'));
1822 $length = strlen($uch);
1823 for ($i = 0; $i < $length; ++$i) {
1824 $char = ord($uch[$i]);
1825 if ($countbytes == 0) {
1826 if ($char <= 0x7F) {
1828 } elseif (($char >> 0x05) == 0x06) {
1829 $bytes[] = ($char - 0xC0) << 0x06;
1832 } elseif (($char >> 0x04) == 0x0E) {
1833 $bytes[] = ($char - 0xE0) << 0x0C;
1836 } elseif (($char >> 0x03) == 0x1E) {
1837 $bytes[] = ($char - 0xF0) << 0x12;
1844 } elseif (($char >> 0x06) == 0x02) {
1845 $bytes[] = $char - 0x80;
1847 if ($countbytes == $numbytes) {
1850 for ($j = 1; $j < $numbytes; ++$j) {
1851 $char += ($bytes[$j] << (($numbytes - $j - 1) * 0x06));
1853 if ((($char >= 0xD800) AND ($char <= 0xDFFF)) OR ($char >= 0x10FFFF)) {
1885 $carr = array_map(array(
'TCPDF_FONTS',
'uniord'), $chars);
1887 $chars = str_split($str);
1888 $carr = array_map(
'ord', $chars);
1890 $currentfont[
'subsetchars'] += array_fill_keys($carr,
true);
1903 public static function UTF8ToLatin1($str, $isunicode=
true, &$currentfont) {
1904 $unicode = self::UTF8StringToArray($str, $isunicode, $currentfont);
1905 return self::UTF8ArrToLatin1($unicode);
1919 public static function UTF8ToUTF16BE($str, $setbom=
false, $isunicode=
true, &$currentfont) {
1923 $unicode = self::UTF8StringToArray($str, $isunicode, $currentfont);
1924 return self::arrUTF8ToUTF16BE($unicode, $setbom);
1939 public static function utf8StrRev($str, $setbom=
false, $forcertl=
false, $isunicode=
true, &$currentfont) {
1940 return self::utf8StrArrRev(self::UTF8StringToArray($str, $isunicode, $currentfont), $str, $setbom, $forcertl, $isunicode, $currentfont);
1956 public static function utf8StrArrRev($arr, $str=
'', $setbom=
false, $forcertl=
false, $isunicode=
true, &$currentfont) {
1957 return self::arrUTF8ToUTF16BE(self::utf8Bidi($arr, $str, $forcertl, $isunicode, $currentfont), $setbom);
1972 public static function utf8Bidi($ta, $str=
'', $forcertl=
false, $isunicode=
true, &$currentfont) {
1979 $str = self::UTF8ArrSubString($ta,
'',
'', $isunicode);
1993 $numchars = count($ta);
1995 if ($forcertl ==
'R') {
1997 } elseif ($forcertl ==
'L') {
2002 for ($i=0; $i < $numchars; ++$i) {
2007 } elseif (($type ==
'AL') OR ($type ==
'R')) {
2018 $remember = array();
2020 $sor = $pel % 2 ?
'R' :
'L';
2024 $chardata = Array();
2028 for ($i=0; $i < $numchars; ++$i) {
2033 $next_level = $cel + ($cel % 2) + 1;
2034 if ($next_level < 62) {
2039 $eor = $cel % 2 ?
'R' :
'L';
2045 $next_level = $cel + 2 - ($cel % 2);
2046 if ( $next_level < 62 ) {
2051 $eor = $cel % 2 ?
'R' :
'L';
2057 $next_level = $cel + ($cel % 2) + 1;
2058 if ($next_level < 62) {
2063 $eor = $cel % 2 ?
'R' :
'L';
2069 $next_level = $cel + 2 - ($cel % 2);
2070 if ( $next_level < 62 ) {
2075 $eor = $cel % 2 ?
'R' :
'L';
2079 if (count($remember)) {
2080 $last = count($remember ) - 1;
2085 $match = array_pop($remember);
2086 $cel = $match[
'cel'];
2087 $dos = $match[
'dos'];
2089 $eor = ($cel > $match[
'cel'] ? $cel : $match[
'cel']) % 2 ?
'R' :
'L';
2110 $chardata[] = array(
'char' => $ta[$i],
'level' => $cel,
'type' => $chardir,
'sor' => $sor,
'eor' => $eor);
2121 $numchars = count($chardata);
2126 for ($i=0; $i < $numchars; ++$i) {
2127 if ($chardata[$i][
'type'] ==
'NSM') {
2129 $chardata[$i][
'type'] = $chardata[$i][
'sor'];
2131 $chardata[$i][
'type'] = $chardata[($i-1)][
'type'];
2134 if ($chardata[$i][
'level'] != $prevlevel) {
2139 $prevlevel = $chardata[$i][
'level'];
2145 for ($i=0; $i < $numchars; ++$i) {
2146 if ($chardata[$i][
'char'] ==
'EN') {
2147 for ($j=$levcount; $j >= 0; $j--) {
2148 if ($chardata[$j][
'type'] ==
'AL') {
2149 $chardata[$i][
'type'] =
'AN';
2150 } elseif (($chardata[$j][
'type'] ==
'L') OR ($chardata[$j][
'type'] ==
'R')) {
2155 if ($chardata[$i][
'level'] != $prevlevel) {
2160 $prevlevel = $chardata[$i][
'level'];
2164 for ($i=0; $i < $numchars; ++$i) {
2165 if ($chardata[$i][
'type'] ==
'AL') {
2166 $chardata[$i][
'type'] =
'R';
2173 for ($i=0; $i < $numchars; ++$i) {
2174 if (($levcount > 0) AND (($i+1) < $numchars) AND ($chardata[($i+1)][
'level'] == $prevlevel)) {
2175 if (($chardata[$i][
'type'] ==
'ES') AND ($chardata[($i-1)][
'type'] ==
'EN') AND ($chardata[($i+1)][
'type'] ==
'EN')) {
2176 $chardata[$i][
'type'] =
'EN';
2177 } elseif (($chardata[$i][
'type'] ==
'CS') AND ($chardata[($i-1)][
'type'] ==
'EN') AND ($chardata[($i+1)][
'type'] ==
'EN')) {
2178 $chardata[$i][
'type'] =
'EN';
2179 } elseif (($chardata[$i][
'type'] ==
'CS') AND ($chardata[($i-1)][
'type'] ==
'AN') AND ($chardata[($i+1)][
'type'] ==
'AN')) {
2180 $chardata[$i][
'type'] =
'AN';
2183 if ($chardata[$i][
'level'] != $prevlevel) {
2188 $prevlevel = $chardata[$i][
'level'];
2194 for ($i=0; $i < $numchars; ++$i) {
2195 if ($chardata[$i][
'type'] ==
'ET') {
2196 if (($levcount > 0) AND ($chardata[($i-1)][
'type'] ==
'EN')) {
2197 $chardata[$i][
'type'] =
'EN';
2200 while (($j < $numchars) AND ($chardata[$j][
'level'] == $prevlevel)) {
2201 if ($chardata[$j][
'type'] ==
'EN') {
2202 $chardata[$i][
'type'] =
'EN';
2204 } elseif ($chardata[$j][
'type'] !=
'ET') {
2211 if ($chardata[$i][
'level'] != $prevlevel) {
2216 $prevlevel = $chardata[$i][
'level'];
2222 for ($i=0; $i < $numchars; ++$i) {
2223 if (($chardata[$i][
'type'] ==
'ET') OR ($chardata[$i][
'type'] ==
'ES') OR ($chardata[$i][
'type'] ==
'CS')) {
2224 $chardata[$i][
'type'] =
'ON';
2226 if ($chardata[$i][
'level'] != $prevlevel) {
2231 $prevlevel = $chardata[$i][
'level'];
2237 for ($i=0; $i < $numchars; ++$i) {
2238 if ($chardata[$i][
'char'] ==
'EN') {
2239 for ($j=$levcount; $j >= 0; $j--) {
2240 if ($chardata[$j][
'type'] ==
'L') {
2241 $chardata[$i][
'type'] =
'L';
2242 } elseif ($chardata[$j][
'type'] ==
'R') {
2247 if ($chardata[$i][
'level'] != $prevlevel) {
2252 $prevlevel = $chardata[$i][
'level'];
2258 for ($i=0; $i < $numchars; ++$i) {
2259 if (($levcount > 0) AND (($i+1) < $numchars) AND ($chardata[($i+1)][
'level'] == $prevlevel)) {
2260 if (($chardata[$i][
'type'] ==
'N') AND ($chardata[($i-1)][
'type'] ==
'L') AND ($chardata[($i+1)][
'type'] ==
'L')) {
2261 $chardata[$i][
'type'] =
'L';
2262 } elseif (($chardata[$i][
'type'] ==
'N') AND
2263 (($chardata[($i-1)][
'type'] ==
'R') OR ($chardata[($i-1)][
'type'] ==
'EN') OR ($chardata[($i-1)][
'type'] ==
'AN')) AND
2264 (($chardata[($i+1)][
'type'] ==
'R') OR ($chardata[($i+1)][
'type'] ==
'EN') OR ($chardata[($i+1)][
'type'] ==
'AN'))) {
2265 $chardata[$i][
'type'] =
'R';
2266 } elseif ($chardata[$i][
'type'] ==
'N') {
2268 $chardata[$i][
'type'] = $chardata[$i][
'sor'];
2270 } elseif (($levcount == 0) AND (($i+1) < $numchars) AND ($chardata[($i+1)][
'level'] == $prevlevel)) {
2272 if (($chardata[$i][
'type'] ==
'N') AND ($chardata[$i][
'sor'] ==
'L') AND ($chardata[($i+1)][
'type'] ==
'L')) {
2273 $chardata[$i][
'type'] =
'L';
2274 } elseif (($chardata[$i][
'type'] ==
'N') AND
2275 (($chardata[$i][
'sor'] ==
'R') OR ($chardata[$i][
'sor'] ==
'EN') OR ($chardata[$i][
'sor'] ==
'AN')) AND
2276 (($chardata[($i+1)][
'type'] ==
'R') OR ($chardata[($i+1)][
'type'] ==
'EN') OR ($chardata[($i+1)][
'type'] ==
'AN'))) {
2277 $chardata[$i][
'type'] =
'R';
2278 } elseif ($chardata[$i][
'type'] ==
'N') {
2280 $chardata[$i][
'type'] = $chardata[$i][
'sor'];
2282 } elseif (($levcount > 0) AND ((($i+1) == $numchars) OR (($i+1) < $numchars) AND ($chardata[($i+1)][
'level'] != $prevlevel))) {
2284 if (($chardata[$i][
'type'] ==
'N') AND ($chardata[($i-1)][
'type'] ==
'L') AND ($chardata[$i][
'eor'] ==
'L')) {
2285 $chardata[$i][
'type'] =
'L';
2286 } elseif (($chardata[$i][
'type'] ==
'N') AND
2287 (($chardata[($i-1)][
'type'] ==
'R') OR ($chardata[($i-1)][
'type'] ==
'EN') OR ($chardata[($i-1)][
'type'] ==
'AN')) AND
2288 (($chardata[$i][
'eor'] ==
'R') OR ($chardata[$i][
'eor'] ==
'EN') OR ($chardata[$i][
'eor'] ==
'AN'))) {
2289 $chardata[$i][
'type'] =
'R';
2290 } elseif ($chardata[$i][
'type'] ==
'N') {
2292 $chardata[$i][
'type'] = $chardata[$i][
'sor'];
2294 } elseif ($chardata[$i][
'type'] ==
'N') {
2296 $chardata[$i][
'type'] = $chardata[$i][
'sor'];
2298 if ($chardata[$i][
'level'] != $prevlevel) {
2303 $prevlevel = $chardata[$i][
'level'];
2308 for ($i=0; $i < $numchars; ++$i) {
2309 $odd = $chardata[$i][
'level'] % 2;
2311 if (($chardata[$i][
'type'] ==
'L') OR ($chardata[$i][
'type'] ==
'AN') OR ($chardata[$i][
'type'] ==
'EN')) {
2312 $chardata[$i][
'level'] += 1;
2315 if ($chardata[$i][
'type'] ==
'R') {
2316 $chardata[$i][
'level'] += 1;
2317 } elseif (($chardata[$i][
'type'] ==
'AN') OR ($chardata[$i][
'type'] ==
'EN')) {
2318 $chardata[$i][
'level'] += 2;
2321 $maxlevel = max($chardata[$i][
'level'],$maxlevel);
2329 for ($i=0; $i < $numchars; ++$i) {
2330 if (($chardata[$i][
'type'] ==
'B') OR ($chardata[$i][
'type'] ==
'S')) {
2331 $chardata[$i][
'level'] = $pel;
2332 } elseif ($chardata[$i][
'type'] ==
'WS') {
2334 while ($j < $numchars) {
2335 if ((($chardata[$j][
'type'] ==
'B') OR ($chardata[$j][
'type'] ==
'S')) OR
2336 (($j == ($numchars-1)) AND ($chardata[$j][
'type'] ==
'WS'))) {
2337 $chardata[$i][
'level'] = $pel;
2339 } elseif ($chardata[$j][
'type'] !=
'WS') {
2350 $endedletter = array(1569,1570,1571,1572,1573,1575,1577,1583,1584,1585,1586,1608,1688);
2351 $alfletter = array(1570,1571,1573,1575);
2352 $chardata2 = $chardata;
2356 for ($i=0; $i < $numchars; ++$i) {
2357 if ((
TCPDF_FONT_DATA::$uni_type[$chardata[$i][
'char']] ==
'AL') OR ($chardata[$i][
'char'] == 32) OR ($chardata[$i][
'char'] == 8204)) {
2358 $charAL[$x] = $chardata[$i];
2359 $charAL[$x][
'i'] = $i;
2360 $chardata[$i][
'x'] = $x;
2365 for ($i=0; $i < $numchars; ++$i) {
2366 $thischar = $chardata[$i];
2368 $prevchar = $chardata[($i-1)];
2372 if (($i+1) < $numchars) {
2373 $nextchar = $chardata[($i+1)];
2378 $x = $thischar[
'x'];
2380 $prevchar = $charAL[($x-1)];
2384 if (($x+1) < $numAL) {
2385 $nextchar = $charAL[($x+1)];
2390 if (($prevchar !==
false) AND ($prevchar[
'char'] == 1604) AND (in_array($thischar[
'char'], $alfletter))) {
2394 $prevchar = $charAL[($x-2)];
2402 if (($prevchar !==
false) AND ($nextchar !==
false) AND
2405 ($prevchar[
'type'] == $thischar[
'type']) AND
2406 ($nextchar[
'type'] == $thischar[
'type']) AND
2407 ($nextchar[
'char'] != 1567)) {
2408 if (in_array($prevchar[
'char'], $endedletter)) {
2409 if (isset($arabicarr[$thischar[
'char']][2])) {
2411 $chardata2[$i][
'char'] = $arabicarr[$thischar[
'char']][2];
2414 if (isset($arabicarr[$thischar[
'char']][3])) {
2416 $chardata2[$i][
'char'] = $arabicarr[$thischar[
'char']][3];
2419 } elseif (($nextchar !==
false) AND
2421 ($nextchar[
'type'] == $thischar[
'type']) AND
2422 ($nextchar[
'char'] != 1567)) {
2423 if (isset($arabicarr[$chardata[$i][
'char']][2])) {
2425 $chardata2[$i][
'char'] = $arabicarr[$thischar[
'char']][2];
2427 } elseif ((($prevchar !==
false) AND
2429 ($prevchar[
'type'] == $thischar[
'type'])) OR
2430 (($nextchar !==
false) AND ($nextchar[
'char'] == 1567))) {
2432 if (($i > 1) AND ($thischar[
'char'] == 1607) AND
2433 ($chardata[$i-1][
'char'] == 1604) AND
2434 ($chardata[$i-2][
'char'] == 1604)) {
2437 $chardata2[$i-2][
'char'] =
false;
2438 $chardata2[$i-1][
'char'] =
false;
2439 $chardata2[$i][
'char'] = 65010;
2441 if (($prevchar !==
false) AND in_array($prevchar[
'char'], $endedletter)) {
2442 if (isset($arabicarr[$thischar[
'char']][0])) {
2444 $chardata2[$i][
'char'] = $arabicarr[$thischar[
'char']][0];
2447 if (isset($arabicarr[$thischar[
'char']][1])) {
2449 $chardata2[$i][
'char'] = $arabicarr[$thischar[
'char']][1];
2453 } elseif (isset($arabicarr[$thischar[
'char']][0])) {
2455 $chardata2[$i][
'char'] = $arabicarr[$thischar[
'char']][0];
2460 $chardata2[($charAL[($x-1)][
'i'])][
'char'] =
false;
2468 for ($i = 0; $i < ($numchars-1); ++$i) {
2472 $chardata2[$i][
'char'] =
false;
2478 foreach ($chardata2 as $key => $value) {
2479 if ($value[
'char'] ===
false) {
2480 unset($chardata2[$key]);
2483 $chardata = array_values($chardata2);
2484 $numchars = count($chardata);
2492 for ($j=$maxlevel; $j > 0; $j--) {
2493 $ordarray = Array();
2496 for ($i=0; $i < $numchars; ++$i) {
2497 if ($chardata[$i][
'level'] >= $j) {
2503 $revarr[] = $chardata[$i];
2506 $revarr = array_reverse($revarr);
2507 $ordarray = array_merge($ordarray, $revarr);
2511 $ordarray[] = $chardata[$i];
2515 $revarr = array_reverse($revarr);
2516 $ordarray = array_merge($ordarray, $revarr);
2518 $chardata = $ordarray;
2520 $ordarray = array();
2521 foreach ($chardata as $cd) {
2522 $ordarray[] = $cd[
'char'];
2524 $currentfont[
'subsetchars'][$cd[
'char']] =
true;
2539 $size = ($refsize - 4);
2543 $size = ($refsize - 3);
2547 $size = ($refsize - 2);
2555 $size = ($refsize + 2);
2559 $size = ($refsize + 4);
2563 $size = ($refsize + 6);
2567 $size = ($refsize - 3);
2571 $size = ($refsize + 3);