ILIAS  release_5-1 Revision 5.0.0-5477-g43f3e3fab5f
TCPDF_FONTS Class Reference

Font methods for TCPDF library. More...

+ Collaboration diagram for TCPDF_FONTS:

Static Public Member Functions

static addTTFfont ($fontfile, $fonttype='', $enc='', $flags=32, $outpath='', $platid=3, $encid=1, $addcbbox=false, $link=false)
 Convert and add the selected TrueType or Type1 font to the fonts folder (that must be writeable). More...
 
static _getTTFtableChecksum ($table, $length)
 Returs the checksum of a TTF table. More...
 
static _getTrueTypeFontSubset ($font, $subsetchars)
 Returns a subset of the TrueType font data without the unused glyphs. More...
 
static _putfontwidths ($font, $cidoffset=0)
 Outputs font widths. More...
 
static updateCIDtoGIDmap ($map, $cid, $gid)
 Update the CIDToGIDMap string with a new value. More...
 
static _getfontpath ()
 Return fonts path. More...
 
static getFontFullPath ($file, $fontdir=false)
 Return font full path. More...
 
static getFontRefSize ($size, $refsize=12)
 Get a reference font size. More...
 
static unichr ($c, $unicode=true)
 Returns the unicode caracter specified by the value. More...
 
static unichrUnicode ($c)
 Returns the unicode caracter specified by UTF-8 value. More...
 
static unichrASCII ($c)
 Returns the unicode caracter specified by ASCII value. More...
 
static arrUTF8ToUTF16BE ($unicode, $setbom=false)
 Converts array of UTF-8 characters to UTF16-BE string. More...
 
static UTF8ArrayToUniArray ($ta, $isunicode=true)
 Convert an array of UTF8 values to array of unicode characters. More...
 
static UTF8ArrSubString ($strarr, $start='', $end='', $unicode=true)
 Extract a slice of the $strarr array and return it as string. More...
 
static UniArrSubString ($uniarr, $start='', $end='')
 Extract a slice of the $uniarr array and return it as string. More...
 
static UTF8ArrToLatin1Arr ($unicode)
 Converts UTF-8 characters array to array of Latin1 characters array
More...
 
static UTF8ArrToLatin1 ($unicode)
 Converts UTF-8 characters array to array of Latin1 string
More...
 
static uniord ($uch)
 Converts UTF-8 character to integer value. More...
 
static getUniord ($uch)
 Converts UTF-8 character to integer value. More...
 
static UTF8StringToArray ($str, $isunicode=true, &$currentfont)
 Converts UTF-8 strings to codepoints array. More...
 
static UTF8ToLatin1 ($str, $isunicode=true, &$currentfont)
 Converts UTF-8 strings to Latin1 when using the standard 14 core fonts. More...
 
static UTF8ToUTF16BE ($str, $setbom=false, $isunicode=true, &$currentfont)
 Converts UTF-8 strings to UTF16-BE. More...
 
static utf8StrRev ($str, $setbom=false, $forcertl=false, $isunicode=true, &$currentfont)
 Reverse the RLT substrings using the Bidirectional Algorithm (http://unicode.org/reports/tr9/). More...
 
static utf8StrArrRev ($arr, $str='', $setbom=false, $forcertl=false, $isunicode=true, &$currentfont)
 Reverse the RLT substrings array using the Bidirectional Algorithm (http://unicode.org/reports/tr9/). More...
 
static utf8Bidi ($ta, $str='', $forcertl=false, $isunicode=true, &$currentfont)
 Reverse the RLT substrings using the Bidirectional Algorithm (http://unicode.org/reports/tr9/). More...
 

Static Protected Attributes

static $cache_uniord = array()
 Static cache used for speed up uniord performances. More...
 

Detailed Description

Font methods for TCPDF library.

Definition at line 48 of file tcpdf_fonts.php.

Member Function Documentation

◆ _getfontpath()

static TCPDF_FONTS::_getfontpath ( )
static

Return fonts path.

Returns
string static

Definition at line 1522 of file tcpdf_fonts.php.

1522 {
1523 if (!defined('K_PATH_FONTS') AND is_dir($fdir = realpath(dirname(__FILE__).'/../fonts'))) {
1524 if (substr($fdir, -1) != '/') {
1525 $fdir .= '/';
1526 }
1527 define('K_PATH_FONTS', $fdir);
1528 }
1529 return defined('K_PATH_FONTS') ? K_PATH_FONTS : '';
1530 }

Referenced by addTTFfont(), and TCPDF\getFontsList().

+ Here is the caller graph for this function:

◆ _getTrueTypeFontSubset()

static TCPDF_FONTS::_getTrueTypeFontSubset (   $font,
  $subsetchars 
)
static

Returns a subset of the TrueType font data without the unused glyphs.

Parameters
$font(string) TrueType font data.
$subsetchars(array) Array of used characters (the glyphs to keep).
Returns
(string) A subset of TrueType font data without the unused glyphs.
Author
Nicola Asuni
Since
5.2.000 (2010-06-02) static

Definition at line 952 of file tcpdf_fonts.php.

952 {
953 ksort($subsetchars);
954 $offset = 0; // offset position of the font data
955 if (TCPDF_STATIC::_getULONG($font, $offset) != 0x10000) {
956 // sfnt version must be 0x00010000 for TrueType version 1.0.
957 return $font;
958 }
959 $offset += 4;
960 // get number of tables
961 $numTables = TCPDF_STATIC::_getUSHORT($font, $offset);
962 $offset += 2;
963 // skip searchRange, entrySelector and rangeShift
964 $offset += 6;
965 // tables array
966 $table = array();
967 // for each table
968 for ($i = 0; $i < $numTables; ++$i) {
969 // get table info
970 $tag = substr($font, $offset, 4);
971 $offset += 4;
972 $table[$tag] = array();
973 $table[$tag]['checkSum'] = TCPDF_STATIC::_getULONG($font, $offset);
974 $offset += 4;
975 $table[$tag]['offset'] = TCPDF_STATIC::_getULONG($font, $offset);
976 $offset += 4;
977 $table[$tag]['length'] = TCPDF_STATIC::_getULONG($font, $offset);
978 $offset += 4;
979 }
980 // check magicNumber
981 $offset = $table['head']['offset'] + 12;
982 if (TCPDF_STATIC::_getULONG($font, $offset) != 0x5F0F3CF5) {
983 // magicNumber must be 0x5F0F3CF5
984 return $font;
985 }
986 $offset += 4;
987 // get offset mode (indexToLocFormat : 0 = short, 1 = long)
988 $offset = $table['head']['offset'] + 50;
989 $short_offset = (TCPDF_STATIC::_getSHORT($font, $offset) == 0);
990 $offset += 2;
991 // get the offsets to the locations of the glyphs in the font, relative to the beginning of the glyphData table
992 $indexToLoc = array();
993 $offset = $table['loca']['offset'];
994 if ($short_offset) {
995 // short version
996 $tot_num_glyphs = floor($table['loca']['length'] / 2); // numGlyphs + 1
997 for ($i = 0; $i < $tot_num_glyphs; ++$i) {
998 $indexToLoc[$i] = TCPDF_STATIC::_getUSHORT($font, $offset) * 2;
999 $offset += 2;
1000 }
1001 } else {
1002 // long version
1003 $tot_num_glyphs = ($table['loca']['length'] / 4); // numGlyphs + 1
1004 for ($i = 0; $i < $tot_num_glyphs; ++$i) {
1005 $indexToLoc[$i] = TCPDF_STATIC::_getULONG($font, $offset);
1006 $offset += 4;
1007 }
1008 }
1009 // get glyphs indexes of chars from cmap table
1010 $subsetglyphs = array(); // glyph IDs on key
1011 $subsetglyphs[0] = true; // character codes that do not correspond to any glyph in the font should be mapped to glyph index 0
1012 $offset = $table['cmap']['offset'] + 2;
1013 $numEncodingTables = TCPDF_STATIC::_getUSHORT($font, $offset);
1014 $offset += 2;
1015 $encodingTables = array();
1016 for ($i = 0; $i < $numEncodingTables; ++$i) {
1017 $encodingTables[$i]['platformID'] = TCPDF_STATIC::_getUSHORT($font, $offset);
1018 $offset += 2;
1019 $encodingTables[$i]['encodingID'] = TCPDF_STATIC::_getUSHORT($font, $offset);
1020 $offset += 2;
1021 $encodingTables[$i]['offset'] = TCPDF_STATIC::_getULONG($font, $offset);
1022 $offset += 4;
1023 }
1024 foreach ($encodingTables as $enctable) {
1025 // get all platforms and encodings
1026 $offset = $table['cmap']['offset'] + $enctable['offset'];
1027 $format = TCPDF_STATIC::_getUSHORT($font, $offset);
1028 $offset += 2;
1029 switch ($format) {
1030 case 0: { // Format 0: Byte encoding table
1031 $offset += 4; // skip length and version/language
1032 for ($c = 0; $c < 256; ++$c) {
1033 if (isset($subsetchars[$c])) {
1034 $g = TCPDF_STATIC::_getBYTE($font, $offset);
1035 $subsetglyphs[$g] = true;
1036 }
1037 ++$offset;
1038 }
1039 break;
1040 }
1041 case 2: { // Format 2: High-byte mapping through table
1042 $offset += 4; // skip length and version/language
1043 $numSubHeaders = 0;
1044 for ($i = 0; $i < 256; ++$i) {
1045 // Array that maps high bytes to subHeaders: value is subHeader index * 8.
1046 $subHeaderKeys[$i] = (TCPDF_STATIC::_getUSHORT($font, $offset) / 8);
1047 $offset += 2;
1048 if ($numSubHeaders < $subHeaderKeys[$i]) {
1049 $numSubHeaders = $subHeaderKeys[$i];
1050 }
1051 }
1052 // the number of subHeaders is equal to the max of subHeaderKeys + 1
1053 ++$numSubHeaders;
1054 // read subHeader structures
1055 $subHeaders = array();
1056 $numGlyphIndexArray = 0;
1057 for ($k = 0; $k < $numSubHeaders; ++$k) {
1058 $subHeaders[$k]['firstCode'] = TCPDF_STATIC::_getUSHORT($font, $offset);
1059 $offset += 2;
1060 $subHeaders[$k]['entryCount'] = TCPDF_STATIC::_getUSHORT($font, $offset);
1061 $offset += 2;
1062 $subHeaders[$k]['idDelta'] = TCPDF_STATIC::_getUSHORT($font, $offset);
1063 $offset += 2;
1064 $subHeaders[$k]['idRangeOffset'] = TCPDF_STATIC::_getUSHORT($font, $offset);
1065 $offset += 2;
1066 $subHeaders[$k]['idRangeOffset'] -= (2 + (($numSubHeaders - $k - 1) * 8));
1067 $subHeaders[$k]['idRangeOffset'] /= 2;
1068 $numGlyphIndexArray += $subHeaders[$k]['entryCount'];
1069 }
1070 for ($k = 0; $k < $numGlyphIndexArray; ++$k) {
1071 $glyphIndexArray[$k] = TCPDF_STATIC::_getUSHORT($font, $offset);
1072 $offset += 2;
1073 }
1074 for ($i = 0; $i < 256; ++$i) {
1075 $k = $subHeaderKeys[$i];
1076 if ($k == 0) {
1077 // one byte code
1078 $c = $i;
1079 if (isset($subsetchars[$c])) {
1080 $g = $glyphIndexArray[0];
1081 $subsetglyphs[$g] = true;
1082 }
1083 } else {
1084 // two bytes code
1085 $start_byte = $subHeaders[$k]['firstCode'];
1086 $end_byte = $start_byte + $subHeaders[$k]['entryCount'];
1087 for ($j = $start_byte; $j < $end_byte; ++$j) {
1088 // combine high and low bytes
1089 $c = (($i << 8) + $j);
1090 if (isset($subsetchars[$c])) {
1091 $idRangeOffset = ($subHeaders[$k]['idRangeOffset'] + $j - $subHeaders[$k]['firstCode']);
1092 $g = ($glyphIndexArray[$idRangeOffset] + $subHeaders[$k]['idDelta']) % 65536;
1093 if ($g < 0) {
1094 $g = 0;
1095 }
1096 $subsetglyphs[$g] = true;
1097 }
1098 }
1099 }
1100 }
1101 break;
1102 }
1103 case 4: { // Format 4: Segment mapping to delta values
1104 $length = TCPDF_STATIC::_getUSHORT($font, $offset);
1105 $offset += 2;
1106 $offset += 2; // skip version/language
1107 $segCount = floor(TCPDF_STATIC::_getUSHORT($font, $offset) / 2);
1108 $offset += 2;
1109 $offset += 6; // skip searchRange, entrySelector, rangeShift
1110 $endCount = array(); // array of end character codes for each segment
1111 for ($k = 0; $k < $segCount; ++$k) {
1112 $endCount[$k] = TCPDF_STATIC::_getUSHORT($font, $offset);
1113 $offset += 2;
1114 }
1115 $offset += 2; // skip reservedPad
1116 $startCount = array(); // array of start character codes for each segment
1117 for ($k = 0; $k < $segCount; ++$k) {
1118 $startCount[$k] = TCPDF_STATIC::_getUSHORT($font, $offset);
1119 $offset += 2;
1120 }
1121 $idDelta = array(); // delta for all character codes in segment
1122 for ($k = 0; $k < $segCount; ++$k) {
1123 $idDelta[$k] = TCPDF_STATIC::_getUSHORT($font, $offset);
1124 $offset += 2;
1125 }
1126 $idRangeOffset = array(); // Offsets into glyphIdArray or 0
1127 for ($k = 0; $k < $segCount; ++$k) {
1128 $idRangeOffset[$k] = TCPDF_STATIC::_getUSHORT($font, $offset);
1129 $offset += 2;
1130 }
1131 $gidlen = (floor($length / 2) - 8 - (4 * $segCount));
1132 $glyphIdArray = array(); // glyph index array
1133 for ($k = 0; $k < $gidlen; ++$k) {
1134 $glyphIdArray[$k] = TCPDF_STATIC::_getUSHORT($font, $offset);
1135 $offset += 2;
1136 }
1137 for ($k = 0; $k < $segCount; ++$k) {
1138 for ($c = $startCount[$k]; $c <= $endCount[$k]; ++$c) {
1139 if (isset($subsetchars[$c])) {
1140 if ($idRangeOffset[$k] == 0) {
1141 $g = ($idDelta[$k] + $c) % 65536;
1142 } else {
1143 $gid = (floor($idRangeOffset[$k] / 2) + ($c - $startCount[$k]) - ($segCount - $k));
1144 $g = ($glyphIdArray[$gid] + $idDelta[$k]) % 65536;
1145 }
1146 if ($g < 0) {
1147 $g = 0;
1148 }
1149 $subsetglyphs[$g] = true;
1150 }
1151 }
1152 }
1153 break;
1154 }
1155 case 6: { // Format 6: Trimmed table mapping
1156 $offset += 4; // skip length and version/language
1157 $firstCode = TCPDF_STATIC::_getUSHORT($font, $offset);
1158 $offset += 2;
1159 $entryCount = TCPDF_STATIC::_getUSHORT($font, $offset);
1160 $offset += 2;
1161 for ($k = 0; $k < $entryCount; ++$k) {
1162 $c = ($k + $firstCode);
1163 if (isset($subsetchars[$c])) {
1164 $g = TCPDF_STATIC::_getUSHORT($font, $offset);
1165 $subsetglyphs[$g] = true;
1166 }
1167 $offset += 2;
1168 }
1169 break;
1170 }
1171 case 8: { // Format 8: Mixed 16-bit and 32-bit coverage
1172 $offset += 10; // skip reserved, length and version/language
1173 for ($k = 0; $k < 8192; ++$k) {
1174 $is32[$k] = TCPDF_STATIC::_getBYTE($font, $offset);
1175 ++$offset;
1176 }
1177 $nGroups = TCPDF_STATIC::_getULONG($font, $offset);
1178 $offset += 4;
1179 for ($i = 0; $i < $nGroups; ++$i) {
1180 $startCharCode = TCPDF_STATIC::_getULONG($font, $offset);
1181 $offset += 4;
1182 $endCharCode = TCPDF_STATIC::_getULONG($font, $offset);
1183 $offset += 4;
1184 $startGlyphID = TCPDF_STATIC::_getULONG($font, $offset);
1185 $offset += 4;
1186 for ($k = $startCharCode; $k <= $endCharCode; ++$k) {
1187 $is32idx = floor($c / 8);
1188 if ((isset($is32[$is32idx])) AND (($is32[$is32idx] & (1 << (7 - ($c % 8)))) == 0)) {
1189 $c = $k;
1190 } else {
1191 // 32 bit format
1192 // convert to decimal (http://www.unicode.org/faq//utf_bom.html#utf16-4)
1193 //LEAD_OFFSET = (0xD800 - (0x10000 >> 10)) = 55232
1194 //SURROGATE_OFFSET = (0x10000 - (0xD800 << 10) - 0xDC00) = -56613888
1195 $c = ((55232 + ($k >> 10)) << 10) + (0xDC00 + ($k & 0x3FF)) -56613888;
1196 }
1197 if (isset($subsetchars[$c])) {
1198 $subsetglyphs[$startGlyphID] = true;
1199 }
1200 ++$startGlyphID;
1201 }
1202 }
1203 break;
1204 }
1205 case 10: { // Format 10: Trimmed array
1206 $offset += 10; // skip reserved, length and version/language
1207 $startCharCode = TCPDF_STATIC::_getULONG($font, $offset);
1208 $offset += 4;
1209 $numChars = TCPDF_STATIC::_getULONG($font, $offset);
1210 $offset += 4;
1211 for ($k = 0; $k < $numChars; ++$k) {
1212 $c = ($k + $startCharCode);
1213 if (isset($subsetchars[$c])) {
1214 $g = TCPDF_STATIC::_getUSHORT($font, $offset);
1215 $subsetglyphs[$g] = true;
1216 }
1217 $offset += 2;
1218 }
1219 break;
1220 }
1221 case 12: { // Format 12: Segmented coverage
1222 $offset += 10; // skip length and version/language
1223 $nGroups = TCPDF_STATIC::_getULONG($font, $offset);
1224 $offset += 4;
1225 for ($k = 0; $k < $nGroups; ++$k) {
1226 $startCharCode = TCPDF_STATIC::_getULONG($font, $offset);
1227 $offset += 4;
1228 $endCharCode = TCPDF_STATIC::_getULONG($font, $offset);
1229 $offset += 4;
1230 $startGlyphCode = TCPDF_STATIC::_getULONG($font, $offset);
1231 $offset += 4;
1232 for ($c = $startCharCode; $c <= $endCharCode; ++$c) {
1233 if (isset($subsetchars[$c])) {
1234 $subsetglyphs[$startGlyphCode] = true;
1235 }
1236 ++$startGlyphCode;
1237 }
1238 }
1239 break;
1240 }
1241 case 13: { // Format 13: Many-to-one range mappings
1242 // to be implemented ...
1243 break;
1244 }
1245 case 14: { // Format 14: Unicode Variation Sequences
1246 // to be implemented ...
1247 break;
1248 }
1249 }
1250 }
1251 // include all parts of composite glyphs
1252 $new_sga = $subsetglyphs;
1253 while (!empty($new_sga)) {
1254 $sga = $new_sga;
1255 $new_sga = array();
1256 foreach ($sga as $key => $val) {
1257 if (isset($indexToLoc[$key])) {
1258 $offset = ($table['glyf']['offset'] + $indexToLoc[$key]);
1259 $numberOfContours = TCPDF_STATIC::_getSHORT($font, $offset);
1260 $offset += 2;
1261 if ($numberOfContours < 0) { // composite glyph
1262 $offset += 8; // skip xMin, yMin, xMax, yMax
1263 do {
1264 $flags = TCPDF_STATIC::_getUSHORT($font, $offset);
1265 $offset += 2;
1266 $glyphIndex = TCPDF_STATIC::_getUSHORT($font, $offset);
1267 $offset += 2;
1268 if (!isset($subsetglyphs[$glyphIndex])) {
1269 // add missing glyphs
1270 $new_sga[$glyphIndex] = true;
1271 }
1272 // skip some bytes by case
1273 if ($flags & 1) {
1274 $offset += 4;
1275 } else {
1276 $offset += 2;
1277 }
1278 if ($flags & 8) {
1279 $offset += 2;
1280 } elseif ($flags & 64) {
1281 $offset += 4;
1282 } elseif ($flags & 128) {
1283 $offset += 8;
1284 }
1285 } while ($flags & 32);
1286 }
1287 }
1288 }
1289 $subsetglyphs += $new_sga;
1290 }
1291 // sort glyphs by key (and remove duplicates)
1292 ksort($subsetglyphs);
1293 // build new glyf and loca tables
1294 $glyf = '';
1295 $loca = '';
1296 $offset = 0;
1297 $glyf_offset = $table['glyf']['offset'];
1298 for ($i = 0; $i < $tot_num_glyphs; ++$i) {
1299 if (isset($subsetglyphs[$i])) {
1300 $length = ($indexToLoc[($i + 1)] - $indexToLoc[$i]);
1301 $glyf .= substr($font, ($glyf_offset + $indexToLoc[$i]), $length);
1302 } else {
1303 $length = 0;
1304 }
1305 if ($short_offset) {
1306 $loca .= pack('n', floor($offset / 2));
1307 } else {
1308 $loca .= pack('N', $offset);
1309 }
1310 $offset += $length;
1311 }
1312 // array of table names to preserve (loca and glyf tables will be added later)
1313 // the cmap table is not needed and shall not be present, since the mapping from character codes to glyph descriptions is provided separately
1314 $table_names = array ('head', 'hhea', 'hmtx', 'maxp', 'cvt ', 'fpgm', 'prep'); // minimum required table names
1315 // get the tables to preserve
1316 $offset = 12;
1317 foreach ($table as $tag => $val) {
1318 if (in_array($tag, $table_names)) {
1319 $table[$tag]['data'] = substr($font, $table[$tag]['offset'], $table[$tag]['length']);
1320 if ($tag == 'head') {
1321 // set the checkSumAdjustment to 0
1322 $table[$tag]['data'] = substr($table[$tag]['data'], 0, 8)."\x0\x0\x0\x0".substr($table[$tag]['data'], 12);
1323 }
1324 $pad = 4 - ($table[$tag]['length'] % 4);
1325 if ($pad != 4) {
1326 // the length of a table must be a multiple of four bytes
1327 $table[$tag]['length'] += $pad;
1328 $table[$tag]['data'] .= str_repeat("\x0", $pad);
1329 }
1330 $table[$tag]['offset'] = $offset;
1331 $offset += $table[$tag]['length'];
1332 // check sum is not changed (so keep the following line commented)
1333 //$table[$tag]['checkSum'] = self::_getTTFtableChecksum($table[$tag]['data'], $table[$tag]['length']);
1334 } else {
1335 unset($table[$tag]);
1336 }
1337 }
1338 // add loca
1339 $table['loca']['data'] = $loca;
1340 $table['loca']['length'] = strlen($loca);
1341 $pad = 4 - ($table['loca']['length'] % 4);
1342 if ($pad != 4) {
1343 // the length of a table must be a multiple of four bytes
1344 $table['loca']['length'] += $pad;
1345 $table['loca']['data'] .= str_repeat("\x0", $pad);
1346 }
1347 $table['loca']['offset'] = $offset;
1348 $table['loca']['checkSum'] = self::_getTTFtableChecksum($table['loca']['data'], $table['loca']['length']);
1349 $offset += $table['loca']['length'];
1350 // add glyf
1351 $table['glyf']['data'] = $glyf;
1352 $table['glyf']['length'] = strlen($glyf);
1353 $pad = 4 - ($table['glyf']['length'] % 4);
1354 if ($pad != 4) {
1355 // the length of a table must be a multiple of four bytes
1356 $table['glyf']['length'] += $pad;
1357 $table['glyf']['data'] .= str_repeat("\x0", $pad);
1358 }
1359 $table['glyf']['offset'] = $offset;
1360 $table['glyf']['checkSum'] = self::_getTTFtableChecksum($table['glyf']['data'], $table['glyf']['length']);
1361 // rebuild font
1362 $font = '';
1363 $font .= pack('N', 0x10000); // sfnt version
1364 $numTables = count($table);
1365 $font .= pack('n', $numTables); // numTables
1366 $entrySelector = floor(log($numTables, 2));
1367 $searchRange = pow(2, $entrySelector) * 16;
1368 $rangeShift = ($numTables * 16) - $searchRange;
1369 $font .= pack('n', $searchRange); // searchRange
1370 $font .= pack('n', $entrySelector); // entrySelector
1371 $font .= pack('n', $rangeShift); // rangeShift
1372 $offset = ($numTables * 16);
1373 foreach ($table as $tag => $data) {
1374 $font .= $tag; // tag
1375 $font .= pack('N', $data['checkSum']); // checkSum
1376 $font .= pack('N', ($data['offset'] + $offset)); // offset
1377 $font .= pack('N', $data['length']); // length
1378 }
1379 foreach ($table as $data) {
1380 $font .= $data['data'];
1381 }
1382 // set checkSumAdjustment on head table
1383 $checkSumAdjustment = 0xB1B0AFBA - self::_getTTFtableChecksum($font, strlen($font));
1384 $font = substr($font, 0, $table['head']['offset'] + 8).pack('N', $checkSumAdjustment).substr($font, $table['head']['offset'] + 12);
1385 return $font;
1386 }
static _getTTFtableChecksum($table, $length)
Returs the checksum of a TTF table.
static _getSHORT($str, $offset)
Get SHORT from string (Big Endian 16-bit signed integer).
static _getBYTE($str, $offset)
Get BYTE from string (8-bit unsigned integer).
static _getUSHORT($str, $offset)
Get USHORT from string (Big Endian 16-bit unsigned integer).
static _getULONG($str, $offset)
Get ULONG from string (Big Endian 32-bit unsigned integer).
$data

References $data, TCPDF_STATIC\_getBYTE(), TCPDF_STATIC\_getSHORT(), TCPDF_STATIC\_getULONG(), and TCPDF_STATIC\_getUSHORT().

Referenced by TCPDF\_putfonts().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ _getTTFtableChecksum()

static TCPDF_FONTS::_getTTFtableChecksum (   $table,
  $length 
)
static

Returs the checksum of a TTF table.

Parameters
$table(string) table to check
$length(int) length of table in bytes
Returns
int checksum
Author
Nicola Asuni
Since
5.2.000 (2010-06-02) static

Definition at line 930 of file tcpdf_fonts.php.

930 {
931 $sum = 0;
932 $tlen = ($length / 4);
933 $offset = 0;
934 for ($i = 0; $i < $tlen; ++$i) {
935 $v = unpack('Ni', substr($table, $offset, 4));
936 $sum += $v['i'];
937 $offset += 4;
938 }
939 $sum = unpack('Ni', pack('N', $sum));
940 return $sum['i'];
941 }

◆ _putfontwidths()

static TCPDF_FONTS::_putfontwidths (   $font,
  $cidoffset = 0 
)
static

Outputs font widths.

Parameters
$font(array) font data
$cidoffset(int) offset for CID values
Returns
PDF command string for font widths
Author
Nicola Asuni
Since
4.4.000 (2008-12-07) static

Definition at line 1397 of file tcpdf_fonts.php.

1397 {
1398 ksort($font['cw']);
1399 $rangeid = 0;
1400 $range = array();
1401 $prevcid = -2;
1402 $prevwidth = -1;
1403 $interval = false;
1404 // for each character
1405 foreach ($font['cw'] as $cid => $width) {
1406 $cid -= $cidoffset;
1407 if ($font['subset'] AND (!isset($font['subsetchars'][$cid]))) {
1408 // ignore the unused characters (font subsetting)
1409 continue;
1410 }
1411 if ($width != $font['dw']) {
1412 if ($cid == ($prevcid + 1)) {
1413 // consecutive CID
1414 if ($width == $prevwidth) {
1415 if ($width == $range[$rangeid][0]) {
1416 $range[$rangeid][] = $width;
1417 } else {
1418 array_pop($range[$rangeid]);
1419 // new range
1420 $rangeid = $prevcid;
1421 $range[$rangeid] = array();
1422 $range[$rangeid][] = $prevwidth;
1423 $range[$rangeid][] = $width;
1424 }
1425 $interval = true;
1426 $range[$rangeid]['interval'] = true;
1427 } else {
1428 if ($interval) {
1429 // new range
1430 $rangeid = $cid;
1431 $range[$rangeid] = array();
1432 $range[$rangeid][] = $width;
1433 } else {
1434 $range[$rangeid][] = $width;
1435 }
1436 $interval = false;
1437 }
1438 } else {
1439 // new range
1440 $rangeid = $cid;
1441 $range[$rangeid] = array();
1442 $range[$rangeid][] = $width;
1443 $interval = false;
1444 }
1445 $prevcid = $cid;
1446 $prevwidth = $width;
1447 }
1448 }
1449 // optimize ranges
1450 $prevk = -1;
1451 $nextk = -1;
1452 $prevint = false;
1453 foreach ($range as $k => $ws) {
1454 $cws = count($ws);
1455 if (($k == $nextk) AND (!$prevint) AND ((!isset($ws['interval'])) OR ($cws < 4))) {
1456 if (isset($range[$k]['interval'])) {
1457 unset($range[$k]['interval']);
1458 }
1459 $range[$prevk] = array_merge($range[$prevk], $range[$k]);
1460 unset($range[$k]);
1461 } else {
1462 $prevk = $k;
1463 }
1464 $nextk = $k + $cws;
1465 if (isset($ws['interval'])) {
1466 if ($cws > 3) {
1467 $prevint = true;
1468 } else {
1469 $prevint = false;
1470 }
1471 if (isset($range[$k]['interval'])) {
1472 unset($range[$k]['interval']);
1473 }
1474 --$nextk;
1475 } else {
1476 $prevint = false;
1477 }
1478 }
1479 // output data
1480 $w = '';
1481 foreach ($range as $k => $ws) {
1482 if (count(array_count_values($ws)) == 1) {
1483 // interval mode is more compact
1484 $w .= ' '.$k.' '.($k + count($ws) - 1).' '.$ws[0];
1485 } else {
1486 // range mode
1487 $w .= ' '.$k.' [ '.implode(' ', $ws).' ]';
1488 }
1489 }
1490 return '/W ['.$w.' ]';
1491 }
$w

References $w.

◆ addTTFfont()

static TCPDF_FONTS::addTTFfont (   $fontfile,
  $fonttype = '',
  $enc = '',
  $flags = 32,
  $outpath = '',
  $platid = 3,
  $encid = 1,
  $addcbbox = false,
  $link = false 
)
static

Convert and add the selected TrueType or Type1 font to the fonts folder (that must be writeable).

Parameters
$fontfile(string) Font file (full path).
$fonttype(string) Font type. Leave empty for autodetect mode. Valid values are: TrueTypeUnicode, TrueType, Type1, CID0JP = CID-0 Japanese, CID0KR = CID-0 Korean, CID0CS = CID-0 Chinese Simplified, CID0CT = CID-0 Chinese Traditional.
$enc(string) Name of the encoding table to use. Leave empty for default mode. Omit this parameter for TrueType Unicode and symbolic fonts like Symbol or ZapfDingBats.
$flags(int) Unsigned 32-bit integer containing flags specifying various characteristics of the font (PDF32000:2008 - 9.8.2 Font Descriptor Flags): +1 for fixed font; +4 for symbol or +32 for non-symbol; +64 for italic. Fixed and Italic mode are generally autodetected so you have to set it to 32 = non-symbolic font (default) or 4 = symbolic font.
$outpath(string) Output path for generated font files (must be writeable by the web server). Leave empty for default font folder.
$platid(int) Platform ID for CMAP table to extract (when building a Unicode font for Windows this value should be 3, for Macintosh should be 1).
$encid(int) Encoding ID for CMAP table to extract (when building a Unicode font for Windows this value should be 1, for Macintosh should be 0). When Platform ID is 3, legal values for Encoding ID are: 0=Symbol, 1=Unicode, 2=ShiftJIS, 3=PRC, 4=Big5, 5=Wansung, 6=Johab, 7=Reserved, 8=Reserved, 9=Reserved, 10=UCS-4.
$addcbbox(boolean) If true includes the character bounding box information on the php font file.
$link(boolean) If true link to system font instead of copying the font data (not transportable) - Note: do not work with Type1 fonts.
Returns
(string) TCPDF font name or boolean false in case of error.
Author
Nicola Asuni
Since
5.9.123 (2010-09-30) static

Definition at line 72 of file tcpdf_fonts.php.

72 {
73 if (!file_exists($fontfile)) {
74 // Could not find file
75 return false;
76 }
77 // font metrics
78 $fmetric = array();
79 // build new font name for TCPDF compatibility
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));
83 }
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)) {
90 // set generic name
91 $font_name = 'tcpdffont';
92 }
93 // set output path
94 if (empty($outpath)) {
95 $outpath = self::_getfontpath();
96 }
97 // check if this font already exist
98 if (@file_exists($outpath.$font_name.'.php')) {
99 // this font already exist (delete it from fonts folder to rebuild it)
100 return $font_name;
101 }
102 $fmetric['file'] = $font_name;
103 $fmetric['ctg'] = $font_name.'.ctg.z';
104 // get font data
105 $font = file_get_contents($fontfile);
106 $fmetric['originalsize'] = strlen($font);
107 // autodetect font type
108 if (empty($fonttype)) {
109 if (TCPDF_STATIC::_getULONG($font, 0) == 0x10000) {
110 // True Type (Unicode or not)
111 $fonttype = 'TrueTypeUnicode';
112 } elseif (substr($font, 0, 4) == 'OTTO') {
113 // Open Type (Unicode or not)
114 //Unsupported font format: OpenType with CFF data
115 return false;
116 } else {
117 // Type 1
118 $fonttype = 'Type1';
119 }
120 }
121 // set font type
122 switch ($fonttype) {
123 case 'CID0CT':
124 case 'CID0CS':
125 case 'CID0KR':
126 case 'CID0JP': {
127 $fmetric['type'] = 'cidfont0';
128 break;
129 }
130 case 'Type1': {
131 $fmetric['type'] = 'Type1';
132 if (empty($enc) AND (($flags & 4) == 0)) {
133 $enc = 'cp1252';
134 }
135 break;
136 }
137 case 'TrueType': {
138 $fmetric['type'] = 'TrueType';
139 break;
140 }
141 case 'TrueTypeUnicode':
142 default: {
143 $fmetric['type'] = 'TrueTypeUnicode';
144 break;
145 }
146 }
147 // set encoding maps (if any)
148 $fmetric['enc'] = preg_replace('/[^A-Za-z0-9_\-]/', '', $enc);
149 $fmetric['diff'] = '';
150 if (($fmetric['type'] == 'TrueType') OR ($fmetric['type'] == 'Type1')) {
151 if (!empty($enc) AND ($enc != 'cp1252') AND isset(TCPDF_FONT_DATA::$encmap[$enc])) {
152 // build differences from reference encoding
153 $enc_ref = TCPDF_FONT_DATA::$encmap['cp1252'];
154 $enc_target = TCPDF_FONT_DATA::$encmap[$enc];
155 $last = 0;
156 for ($i = 32; $i <= 255; ++$i) {
157 if ($enc_target[$i] != $enc_ref[$i]) {
158 if ($i != ($last + 1)) {
159 $fmetric['diff'] .= $i.' ';
160 }
161 $last = $i;
162 $fmetric['diff'] .= '/'.$enc_target[$i].' ';
163 }
164 }
165 }
166 }
167 // parse the font by type
168 if ($fmetric['type'] == 'Type1') {
169 // ---------- TYPE 1 ----------
170 // read first segment
171 $a = unpack('Cmarker/Ctype/Vsize', substr($font, 0, 6));
172 if ($a['marker'] != 128) {
173 // Font file is not a valid binary Type1
174 return false;
175 }
176 $fmetric['size1'] = $a['size'];
177 $data = substr($font, 6, $fmetric['size1']);
178 // read second segment
179 $a = unpack('Cmarker/Ctype/Vsize', substr($font, (6 + $fmetric['size1']), 6));
180 if ($a['marker'] != 128) {
181 // Font file is not a valid binary Type1
182 return false;
183 }
184 $fmetric['size2'] = $a['size'];
185 $encrypted = substr($font, (12 + $fmetric['size1']), $fmetric['size2']);
186 $data .= $encrypted;
187 // store compressed font
188 $fmetric['file'] .= '.z';
189 $fp = TCPDF_STATIC::fopenLocal($outpath.$fmetric['file'], 'wb');
190 fwrite($fp, gzcompress($data));
191 fclose($fp);
192 // get font info
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;
205 }
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;
213 }
214 // get internal map
215 $imap = array();
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];
219 }
220 }
221 // decrypt eexec encrypted part
222 $r = 55665; // eexec encryption constant
223 $c1 = 52845;
224 $c2 = 22719;
225 $elen = strlen($encrypted);
226 $eplain = '';
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);
231 }
232 if (preg_match('#/ForceBold[\s]*([^\s]*)#', $eplain, $matches) > 0) {
233 if ($matches[1] == 'true') {
234 $fmetric['Flags'] |= 0x40000;
235 }
236 }
237 if (preg_match('#/StdVW[\s]*\[([^\]]*)#', $eplain, $matches) > 0) {
238 $fmetric['StemV'] = intval($matches[1]);
239 } else {
240 $fmetric['StemV'] = 70;
241 }
242 if (preg_match('#/StdHW[\s]*\[([^\]]*)#', $eplain, $matches) > 0) {
243 $fmetric['StemH'] = intval($matches[1]);
244 } else {
245 $fmetric['StemH'] = 30;
246 }
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]);
252 if ($v1 <= $v2) {
253 $fmetric['XHeight'] = $v1;
254 $fmetric['CapHeight'] = $v2;
255 } else {
256 $fmetric['XHeight'] = $v2;
257 $fmetric['CapHeight'] = $v1;
258 }
259 } else {
260 $fmetric['XHeight'] = 450;
261 $fmetric['CapHeight'] = 700;
262 }
263 } else {
264 $fmetric['XHeight'] = 450;
265 $fmetric['CapHeight'] = 700;
266 }
267 // get the number of random bytes at the beginning of charstrings
268 if (preg_match('#/lenIV[\s]*([0-9]*)#', $eplain, $matches) > 0) {
269 $lenIV = intval($matches[1]);
270 } else {
271 $lenIV = 4;
272 }
273 $fmetric['Leading'] = 0;
274 // get charstring data
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);
277 if (!empty($enc) AND isset(TCPDF_FONT_DATA::$encmap[$enc])) {
278 $enc_map = TCPDF_FONT_DATA::$encmap[$enc];
279 } else {
280 $enc_map = false;
281 }
282 $fmetric['cw'] = '';
283 $fmetric['MaxWidth'] = 0;
284 $cwidths = array();
285 foreach ($matches as $k => $v) {
286 $cid = 0;
287 if (isset($imap[$v[1]])) {
288 $cid = $imap[$v[1]];
289 } elseif ($enc_map !== false) {
290 $cid = array_search($v[1], $enc_map);
291 if ($cid === false) {
292 $cid = 0;
293 } elseif ($cid > 1000) {
294 $cid -= 1000;
295 }
296 }
297 // decrypt charstring encrypted part
298 $r = 4330; // charstring encryption constant
299 $c1 = 52845;
300 $c2 = 22719;
301 $cd = $v[2];
302 $clen = strlen($cd);
303 $ccom = array();
304 for ($i = 0; $i < $clen; ++$i) {
305 $chr = ord($cd[$i]);
306 $ccom[] = ($chr ^ ($r >> 8));
307 $r = ((($chr + $r) * $c1 + $c2) % 65536);
308 }
309 // decode numbers
310 $cdec = array();
311 $ck = 0;
312 $i = $lenIV;
313 while ($i < $clen) {
314 if ($ccom[$i] < 32) {
315 $cdec[$ck] = $ccom[$i];
316 if (($ck > 0) AND ($cdec[$ck] == 13)) {
317 // hsbw command: update width
318 $cwidths[$cid] = $cdec[($ck - 1)];
319 }
320 ++$i;
321 } elseif (($ccom[$i] >= 32) AND ($ccom[$i] <= 246)) {
322 $cdec[$ck] = ($ccom[$i] - 139);
323 ++$i;
324 } elseif (($ccom[$i] >= 247) AND ($ccom[$i] <= 250)) {
325 $cdec[$ck] = ((($ccom[$i] - 247) * 256) + $ccom[($i + 1)] + 108);
326 $i += 2;
327 } elseif (($ccom[$i] >= 251) AND ($ccom[$i] <= 254)) {
328 $cdec[$ck] = ((-($ccom[$i] - 251) * 256) - $ccom[($i + 1)] - 108);
329 $i += 2;
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'];
334 $i += 5;
335 }
336 ++$ck;
337 }
338 } // end for each matches
339 $fmetric['MissingWidth'] = $cwidths[0];
340 $fmetric['MaxWidth'] = $fmetric['MissingWidth'];
341 $fmetric['AvgWidth'] = 0;
342 // set chars widths
343 for ($cid = 0; $cid <= 255; ++$cid) {
344 if (isset($cwidths[$cid])) {
345 if ($cwidths[$cid] > $fmetric['MaxWidth']) {
346 $fmetric['MaxWidth'] = $cwidths[$cid];
347 }
348 $fmetric['AvgWidth'] += $cwidths[$cid];
349 $fmetric['cw'] .= ','.$cid.'=>'.$cwidths[$cid];
350 } else {
351 $fmetric['cw'] .= ','.$cid.'=>'.$fmetric['MissingWidth'];
352 }
353 }
354 $fmetric['AvgWidth'] = round($fmetric['AvgWidth'] / count($cwidths));
355 } else {
356 // ---------- TRUE TYPE ----------
357 $offset = 0; // offset position of the font data
358 if (TCPDF_STATIC::_getULONG($font, $offset) != 0x10000) {
359 // sfnt version must be 0x00010000 for TrueType version 1.0.
360 return false;
361 }
362 if ($fmetric['type'] != 'cidfont0') {
363 if ($link) {
364 // creates a symbolic link to the existing font
365 symlink($fontfile, $outpath.$fmetric['file']);
366 } else {
367 // store compressed font
368 $fmetric['file'] .= '.z';
369 $fp = TCPDF_STATIC::fopenLocal($outpath.$fmetric['file'], 'wb');
370 fwrite($fp, gzcompress($font));
371 fclose($fp);
372 }
373 }
374 $offset += 4;
375 // get number of tables
376 $numTables = TCPDF_STATIC::_getUSHORT($font, $offset);
377 $offset += 2;
378 // skip searchRange, entrySelector and rangeShift
379 $offset += 6;
380 // tables array
381 $table = array();
382 // ---------- get tables ----------
383 for ($i = 0; $i < $numTables; ++$i) {
384 // get table info
385 $tag = substr($font, $offset, 4);
386 $offset += 4;
387 $table[$tag] = array();
388 $table[$tag]['checkSum'] = TCPDF_STATIC::_getULONG($font, $offset);
389 $offset += 4;
390 $table[$tag]['offset'] = TCPDF_STATIC::_getULONG($font, $offset);
391 $offset += 4;
392 $table[$tag]['length'] = TCPDF_STATIC::_getULONG($font, $offset);
393 $offset += 4;
394 }
395 // check magicNumber
396 $offset = $table['head']['offset'] + 12;
397 if (TCPDF_STATIC::_getULONG($font, $offset) != 0x5F0F3CF5) {
398 // magicNumber must be 0x5F0F3CF5
399 return false;
400 }
401 $offset += 4;
402 $offset += 2; // skip flags
403 // get FUnits
404 $fmetric['unitsPerEm'] = TCPDF_STATIC::_getUSHORT($font, $offset);
405 $offset += 2;
406 // units ratio constant
407 $urk = (1000 / $fmetric['unitsPerEm']);
408 $offset += 16; // skip created, modified
409 $xMin = round(TCPDF_STATIC::_getFWORD($font, $offset) * $urk);
410 $offset += 2;
411 $yMin = round(TCPDF_STATIC::_getFWORD($font, $offset) * $urk);
412 $offset += 2;
413 $xMax = round(TCPDF_STATIC::_getFWORD($font, $offset) * $urk);
414 $offset += 2;
415 $yMax = round(TCPDF_STATIC::_getFWORD($font, $offset) * $urk);
416 $offset += 2;
417 $fmetric['bbox'] = ''.$xMin.' '.$yMin.' '.$xMax.' '.$yMax.'';
418 $macStyle = TCPDF_STATIC::_getUSHORT($font, $offset);
419 $offset += 2;
420 // PDF font flags
421 $fmetric['Flags'] = $flags;
422 if (($macStyle & 2) == 2) {
423 // italic flag
424 $fmetric['Flags'] |= 64;
425 }
426 // get offset mode (indexToLocFormat : 0 = short, 1 = long)
427 $offset = $table['head']['offset'] + 50;
428 $short_offset = (TCPDF_STATIC::_getSHORT($font, $offset) == 0);
429 $offset += 2;
430 // get the offsets to the locations of the glyphs in the font, relative to the beginning of the glyphData table
431 $indexToLoc = array();
432 $offset = $table['loca']['offset'];
433 if ($short_offset) {
434 // short version
435 $tot_num_glyphs = floor($table['loca']['length'] / 2); // numGlyphs + 1
436 for ($i = 0; $i < $tot_num_glyphs; ++$i) {
437 $indexToLoc[$i] = TCPDF_STATIC::_getUSHORT($font, $offset) * 2;
438 if (isset($indexToLoc[($i - 1)]) && ($indexToLoc[$i] == $indexToLoc[($i - 1)])) {
439 // the last glyph didn't have an outline
440 unset($indexToLoc[($i - 1)]);
441 }
442 $offset += 2;
443 }
444 } else {
445 // long version
446 $tot_num_glyphs = floor($table['loca']['length'] / 4); // numGlyphs + 1
447 for ($i = 0; $i < $tot_num_glyphs; ++$i) {
448 $indexToLoc[$i] = TCPDF_STATIC::_getULONG($font, $offset);
449 if (isset($indexToLoc[($i - 1)]) && ($indexToLoc[$i] == $indexToLoc[($i - 1)])) {
450 // the last glyph didn't have an outline
451 unset($indexToLoc[($i - 1)]);
452 }
453 $offset += 4;
454 }
455 }
456 // get glyphs indexes of chars from cmap table
457 $offset = $table['cmap']['offset'] + 2;
458 $numEncodingTables = TCPDF_STATIC::_getUSHORT($font, $offset);
459 $offset += 2;
460 $encodingTables = array();
461 for ($i = 0; $i < $numEncodingTables; ++$i) {
462 $encodingTables[$i]['platformID'] = TCPDF_STATIC::_getUSHORT($font, $offset);
463 $offset += 2;
464 $encodingTables[$i]['encodingID'] = TCPDF_STATIC::_getUSHORT($font, $offset);
465 $offset += 2;
466 $encodingTables[$i]['offset'] = TCPDF_STATIC::_getULONG($font, $offset);
467 $offset += 4;
468 }
469 // ---------- get os/2 metrics ----------
470 $offset = $table['OS/2']['offset'];
471 $offset += 2; // skip version
472 // xAvgCharWidth
473 $fmetric['AvgWidth'] = round(TCPDF_STATIC::_getFWORD($font, $offset) * $urk);
474 $offset += 2;
475 // usWeightClass
476 $usWeightClass = round(TCPDF_STATIC::_getUFWORD($font, $offset) * $urk);
477 // estimate StemV and StemH (400 = usWeightClass for Normal - Regular font)
478 $fmetric['StemV'] = round((70 * $usWeightClass) / 400);
479 $fmetric['StemH'] = round((30 * $usWeightClass) / 400);
480 $offset += 2;
481 $offset += 2; // usWidthClass
482 $fsType = TCPDF_STATIC::_getSHORT($font, $offset);
483 $offset += 2;
484 if ($fsType == 2) {
485 // This Font cannot be modified, embedded or exchanged in any manner without first obtaining permission of the legal owner.
486 return false;
487 }
488 // ---------- get font name ----------
489 $fmetric['name'] = '';
490 $offset = $table['name']['offset'];
491 $offset += 2; // skip Format selector (=0).
492 // Number of NameRecords that follow n.
493 $numNameRecords = TCPDF_STATIC::_getUSHORT($font, $offset);
494 $offset += 2;
495 // Offset to start of string storage (from start of table).
496 $stringStorageOffset = TCPDF_STATIC::_getUSHORT($font, $offset);
497 $offset += 2;
498 for ($i = 0; $i < $numNameRecords; ++$i) {
499 $offset += 6; // skip Platform ID, Platform-specific encoding ID, Language ID.
500 // Name ID.
501 $nameID = TCPDF_STATIC::_getUSHORT($font, $offset);
502 $offset += 2;
503 if ($nameID == 6) {
504 // String length (in bytes).
505 $stringLength = TCPDF_STATIC::_getUSHORT($font, $offset);
506 $offset += 2;
507 // String offset from start of storage area (in bytes).
508 $stringOffset = TCPDF_STATIC::_getUSHORT($font, $offset);
509 $offset += 2;
510 $offset = ($table['name']['offset'] + $stringStorageOffset + $stringOffset);
511 $fmetric['name'] = substr($font, $offset, $stringLength);
512 $fmetric['name'] = preg_replace('/[^a-zA-Z0-9_\-]/', '', $fmetric['name']);
513 break;
514 } else {
515 $offset += 4; // skip String length, String offset
516 }
517 }
518 if (empty($fmetric['name'])) {
519 $fmetric['name'] = $font_name;
520 }
521 // ---------- get post data ----------
522 $offset = $table['post']['offset'];
523 $offset += 4; // skip Format Type
524 $fmetric['italicAngle'] = TCPDF_STATIC::_getFIXED($font, $offset);
525 $offset += 4;
526 $fmetric['underlinePosition'] = round(TCPDF_STATIC::_getFWORD($font, $offset) * $urk);
527 $offset += 2;
528 $fmetric['underlineThickness'] = round(TCPDF_STATIC::_getFWORD($font, $offset) * $urk);
529 $offset += 2;
530 $isFixedPitch = (TCPDF_STATIC::_getULONG($font, $offset) == 0) ? false : true;
531 $offset += 2;
532 if ($isFixedPitch) {
533 $fmetric['Flags'] |= 1;
534 }
535 // ---------- get hhea data ----------
536 $offset = $table['hhea']['offset'];
537 $offset += 4; // skip Table version number
538 // Ascender
539 $fmetric['Ascent'] = round(TCPDF_STATIC::_getFWORD($font, $offset) * $urk);
540 $offset += 2;
541 // Descender
542 $fmetric['Descent'] = round(TCPDF_STATIC::_getFWORD($font, $offset) * $urk);
543 $offset += 2;
544 // LineGap
545 $fmetric['Leading'] = round(TCPDF_STATIC::_getFWORD($font, $offset) * $urk);
546 $offset += 2;
547 // advanceWidthMax
548 $fmetric['MaxWidth'] = round(TCPDF_STATIC::_getUFWORD($font, $offset) * $urk);
549 $offset += 2;
550 $offset += 22; // skip some values
551 // get the number of hMetric entries in hmtx table
552 $numberOfHMetrics = TCPDF_STATIC::_getUSHORT($font, $offset);
553 // ---------- get maxp data ----------
554 $offset = $table['maxp']['offset'];
555 $offset += 4; // skip Table version number
556 // get the the number of glyphs in the font.
557 $numGlyphs = TCPDF_STATIC::_getUSHORT($font, $offset);
558 // ---------- get CIDToGIDMap ----------
559 $ctg = array();
560 foreach ($encodingTables as $enctable) {
561 // get only specified Platform ID and Encoding ID
562 if (($enctable['platformID'] == $platid) AND ($enctable['encodingID'] == $encid)) {
563 $offset = $table['cmap']['offset'] + $enctable['offset'];
564 $format = TCPDF_STATIC::_getUSHORT($font, $offset);
565 $offset += 2;
566 switch ($format) {
567 case 0: { // Format 0: Byte encoding table
568 $offset += 4; // skip length and version/language
569 for ($c = 0; $c < 256; ++$c) {
570 $g = TCPDF_STATIC::_getBYTE($font, $offset);
571 $ctg[$c] = $g;
572 ++$offset;
573 }
574 break;
575 }
576 case 2: { // Format 2: High-byte mapping through table
577 $offset += 4; // skip length and version/language
578 $numSubHeaders = 0;
579 for ($i = 0; $i < 256; ++$i) {
580 // Array that maps high bytes to subHeaders: value is subHeader index * 8.
581 $subHeaderKeys[$i] = (TCPDF_STATIC::_getUSHORT($font, $offset) / 8);
582 $offset += 2;
583 if ($numSubHeaders < $subHeaderKeys[$i]) {
584 $numSubHeaders = $subHeaderKeys[$i];
585 }
586 }
587 // the number of subHeaders is equal to the max of subHeaderKeys + 1
588 ++$numSubHeaders;
589 // read subHeader structures
590 $subHeaders = array();
591 $numGlyphIndexArray = 0;
592 for ($k = 0; $k < $numSubHeaders; ++$k) {
593 $subHeaders[$k]['firstCode'] = TCPDF_STATIC::_getUSHORT($font, $offset);
594 $offset += 2;
595 $subHeaders[$k]['entryCount'] = TCPDF_STATIC::_getUSHORT($font, $offset);
596 $offset += 2;
597 $subHeaders[$k]['idDelta'] = TCPDF_STATIC::_getUSHORT($font, $offset);
598 $offset += 2;
599 $subHeaders[$k]['idRangeOffset'] = TCPDF_STATIC::_getUSHORT($font, $offset);
600 $offset += 2;
601 $subHeaders[$k]['idRangeOffset'] -= (2 + (($numSubHeaders - $k - 1) * 8));
602 $subHeaders[$k]['idRangeOffset'] /= 2;
603 $numGlyphIndexArray += $subHeaders[$k]['entryCount'];
604 }
605 for ($k = 0; $k < $numGlyphIndexArray; ++$k) {
606 $glyphIndexArray[$k] = TCPDF_STATIC::_getUSHORT($font, $offset);
607 $offset += 2;
608 }
609 for ($i = 0; $i < 256; ++$i) {
610 $k = $subHeaderKeys[$i];
611 if ($k == 0) {
612 // one byte code
613 $c = $i;
614 $g = $glyphIndexArray[0];
615 $ctg[$c] = $g;
616 } else {
617 // two bytes code
618 $start_byte = $subHeaders[$k]['firstCode'];
619 $end_byte = $start_byte + $subHeaders[$k]['entryCount'];
620 for ($j = $start_byte; $j < $end_byte; ++$j) {
621 // combine high and low bytes
622 $c = (($i << 8) + $j);
623 $idRangeOffset = ($subHeaders[$k]['idRangeOffset'] + $j - $subHeaders[$k]['firstCode']);
624 $g = ($glyphIndexArray[$idRangeOffset] + $subHeaders[$k]['idDelta']) % 65536;
625 if ($g < 0) {
626 $g = 0;
627 }
628 $ctg[$c] = $g;
629 }
630 }
631 }
632 break;
633 }
634 case 4: { // Format 4: Segment mapping to delta values
635 $length = TCPDF_STATIC::_getUSHORT($font, $offset);
636 $offset += 2;
637 $offset += 2; // skip version/language
638 $segCount = floor(TCPDF_STATIC::_getUSHORT($font, $offset) / 2);
639 $offset += 2;
640 $offset += 6; // skip searchRange, entrySelector, rangeShift
641 $endCount = array(); // array of end character codes for each segment
642 for ($k = 0; $k < $segCount; ++$k) {
643 $endCount[$k] = TCPDF_STATIC::_getUSHORT($font, $offset);
644 $offset += 2;
645 }
646 $offset += 2; // skip reservedPad
647 $startCount = array(); // array of start character codes for each segment
648 for ($k = 0; $k < $segCount; ++$k) {
649 $startCount[$k] = TCPDF_STATIC::_getUSHORT($font, $offset);
650 $offset += 2;
651 }
652 $idDelta = array(); // delta for all character codes in segment
653 for ($k = 0; $k < $segCount; ++$k) {
654 $idDelta[$k] = TCPDF_STATIC::_getUSHORT($font, $offset);
655 $offset += 2;
656 }
657 $idRangeOffset = array(); // Offsets into glyphIdArray or 0
658 for ($k = 0; $k < $segCount; ++$k) {
659 $idRangeOffset[$k] = TCPDF_STATIC::_getUSHORT($font, $offset);
660 $offset += 2;
661 }
662 $gidlen = (floor($length / 2) - 8 - (4 * $segCount));
663 $glyphIdArray = array(); // glyph index array
664 for ($k = 0; $k < $gidlen; ++$k) {
665 $glyphIdArray[$k] = TCPDF_STATIC::_getUSHORT($font, $offset);
666 $offset += 2;
667 }
668 for ($k = 0; $k < $segCount; ++$k) {
669 for ($c = $startCount[$k]; $c <= $endCount[$k]; ++$c) {
670 if ($idRangeOffset[$k] == 0) {
671 $g = ($idDelta[$k] + $c) % 65536;
672 } else {
673 $gid = (floor($idRangeOffset[$k] / 2) + ($c - $startCount[$k]) - ($segCount - $k));
674 $g = ($glyphIdArray[$gid] + $idDelta[$k]) % 65536;
675 }
676 if ($g < 0) {
677 $g = 0;
678 }
679 $ctg[$c] = $g;
680 }
681 }
682 break;
683 }
684 case 6: { // Format 6: Trimmed table mapping
685 $offset += 4; // skip length and version/language
686 $firstCode = TCPDF_STATIC::_getUSHORT($font, $offset);
687 $offset += 2;
688 $entryCount = TCPDF_STATIC::_getUSHORT($font, $offset);
689 $offset += 2;
690 for ($k = 0; $k < $entryCount; ++$k) {
691 $c = ($k + $firstCode);
692 $g = TCPDF_STATIC::_getUSHORT($font, $offset);
693 $offset += 2;
694 $ctg[$c] = $g;
695 }
696 break;
697 }
698 case 8: { // Format 8: Mixed 16-bit and 32-bit coverage
699 $offset += 10; // skip reserved, length and version/language
700 for ($k = 0; $k < 8192; ++$k) {
701 $is32[$k] = TCPDF_STATIC::_getBYTE($font, $offset);
702 ++$offset;
703 }
704 $nGroups = TCPDF_STATIC::_getULONG($font, $offset);
705 $offset += 4;
706 for ($i = 0; $i < $nGroups; ++$i) {
707 $startCharCode = TCPDF_STATIC::_getULONG($font, $offset);
708 $offset += 4;
709 $endCharCode = TCPDF_STATIC::_getULONG($font, $offset);
710 $offset += 4;
711 $startGlyphID = TCPDF_STATIC::_getULONG($font, $offset);
712 $offset += 4;
713 for ($k = $startCharCode; $k <= $endCharCode; ++$k) {
714 $is32idx = floor($c / 8);
715 if ((isset($is32[$is32idx])) AND (($is32[$is32idx] & (1 << (7 - ($c % 8)))) == 0)) {
716 $c = $k;
717 } else {
718 // 32 bit format
719 // convert to decimal (http://www.unicode.org/faq//utf_bom.html#utf16-4)
720 //LEAD_OFFSET = (0xD800 - (0x10000 >> 10)) = 55232
721 //SURROGATE_OFFSET = (0x10000 - (0xD800 << 10) - 0xDC00) = -56613888
722 $c = ((55232 + ($k >> 10)) << 10) + (0xDC00 + ($k & 0x3FF)) -56613888;
723 }
724 $ctg[$c] = 0;
725 ++$startGlyphID;
726 }
727 }
728 break;
729 }
730 case 10: { // Format 10: Trimmed array
731 $offset += 10; // skip reserved, length and version/language
732 $startCharCode = TCPDF_STATIC::_getULONG($font, $offset);
733 $offset += 4;
734 $numChars = TCPDF_STATIC::_getULONG($font, $offset);
735 $offset += 4;
736 for ($k = 0; $k < $numChars; ++$k) {
737 $c = ($k + $startCharCode);
738 $g = TCPDF_STATIC::_getUSHORT($font, $offset);
739 $ctg[$c] = $g;
740 $offset += 2;
741 }
742 break;
743 }
744 case 12: { // Format 12: Segmented coverage
745 $offset += 10; // skip length and version/language
746 $nGroups = TCPDF_STATIC::_getULONG($font, $offset);
747 $offset += 4;
748 for ($k = 0; $k < $nGroups; ++$k) {
749 $startCharCode = TCPDF_STATIC::_getULONG($font, $offset);
750 $offset += 4;
751 $endCharCode = TCPDF_STATIC::_getULONG($font, $offset);
752 $offset += 4;
753 $startGlyphCode = TCPDF_STATIC::_getULONG($font, $offset);
754 $offset += 4;
755 for ($c = $startCharCode; $c <= $endCharCode; ++$c) {
756 $ctg[$c] = $startGlyphCode;
757 ++$startGlyphCode;
758 }
759 }
760 break;
761 }
762 case 13: { // Format 13: Many-to-one range mappings
763 // to be implemented ...
764 break;
765 }
766 case 14: { // Format 14: Unicode Variation Sequences
767 // to be implemented ...
768 break;
769 }
770 }
771 }
772 }
773 if (!isset($ctg[0])) {
774 $ctg[0] = 0;
775 }
776 // get xHeight (height of x)
777 $offset = ($table['glyf']['offset'] + $indexToLoc[$ctg[120]] + 4);
778 $yMin = TCPDF_STATIC::_getFWORD($font, $offset);
779 $offset += 4;
780 $yMax = TCPDF_STATIC::_getFWORD($font, $offset);
781 $offset += 2;
782 $fmetric['XHeight'] = round(($yMax - $yMin) * $urk);
783 // get CapHeight (height of H)
784 $offset = ($table['glyf']['offset'] + $indexToLoc[$ctg[72]] + 4);
785 $yMin = TCPDF_STATIC::_getFWORD($font, $offset);
786 $offset += 4;
787 $yMax = TCPDF_STATIC::_getFWORD($font, $offset);
788 $offset += 2;
789 $fmetric['CapHeight'] = round(($yMax - $yMin) * $urk);
790 // ceate widths array
791 $cw = array();
792 $offset = $table['hmtx']['offset'];
793 for ($i = 0 ; $i < $numberOfHMetrics; ++$i) {
794 $cw[$i] = round(TCPDF_STATIC::_getUFWORD($font, $offset) * $urk);
795 $offset += 4; // skip lsb
796 }
797 if ($numberOfHMetrics < $numGlyphs) {
798 // fill missing widths with the last value
799 $cw = array_pad($cw, $numGlyphs, $cw[($numberOfHMetrics - 1)]);
800 }
801 $fmetric['MissingWidth'] = $cw[0];
802 $fmetric['cw'] = '';
803 $fmetric['cbbox'] = '';
804 for ($cid = 0; $cid <= 65535; ++$cid) {
805 if (isset($ctg[$cid])) {
806 if (isset($cw[$ctg[$cid]])) {
807 $fmetric['cw'] .= ','.$cid.'=>'.$cw[$ctg[$cid]];
808 }
809 if ($addcbbox AND isset($indexToLoc[$ctg[$cid]])) {
810 $offset = ($table['glyf']['offset'] + $indexToLoc[$ctg[$cid]]);
811 $xMin = round(TCPDF_STATIC::_getFWORD($font, $offset + 2) * $urk);
812 $yMin = round(TCPDF_STATIC::_getFWORD($font, $offset + 4) * $urk);
813 $xMax = round(TCPDF_STATIC::_getFWORD($font, $offset + 6) * $urk);
814 $yMax = round(TCPDF_STATIC::_getFWORD($font, $offset + 8) * $urk);
815 $fmetric['cbbox'] .= ','.$cid.'=>array('.$xMin.','.$yMin.','.$xMax.','.$yMax.')';
816 }
817 }
818 }
819 } // end of true type
820 if (($fmetric['type'] == 'TrueTypeUnicode') AND (count($ctg) == 256)) {
821 $fmetric['type'] = 'TrueType';
822 }
823 // ---------- create php font file ----------
824 $pfile = '<'.'?'.'php'."\n";
825 $pfile .= '// TCPDF FONT FILE DESCRIPTION'."\n";
826 $pfile .= '$type=\''.$fmetric['type'].'\';'."\n";
827 $pfile .= '$name=\''.$fmetric['name'].'\';'."\n";
828 $pfile .= '$up='.$fmetric['underlinePosition'].';'."\n";
829 $pfile .= '$ut='.$fmetric['underlineThickness'].';'."\n";
830 if ($fmetric['MissingWidth'] > 0) {
831 $pfile .= '$dw='.$fmetric['MissingWidth'].';'."\n";
832 } else {
833 $pfile .= '$dw='.$fmetric['AvgWidth'].';'."\n";
834 }
835 $pfile .= '$diff=\''.$fmetric['diff'].'\';'."\n";
836 if ($fmetric['type'] == 'Type1') {
837 // Type 1
838 $pfile .= '$enc=\''.$fmetric['enc'].'\';'."\n";
839 $pfile .= '$file=\''.$fmetric['file'].'\';'."\n";
840 $pfile .= '$size1='.$fmetric['size1'].';'."\n";
841 $pfile .= '$size2='.$fmetric['size2'].';'."\n";
842 } else {
843 $pfile .= '$originalsize='.$fmetric['originalsize'].';'."\n";
844 if ($fmetric['type'] == 'cidfont0') {
845 // CID-0
846 switch ($fonttype) {
847 case 'CID0JP': {
848 $pfile .= '// Japanese'."\n";
849 $pfile .= '$enc=\'UniJIS-UTF16-H\';'."\n";
850 $pfile .= '$cidinfo=array(\'Registry\'=>\'Adobe\', \'Ordering\'=>\'Japan1\',\'Supplement\'=>5);'."\n";
851 $pfile .= 'include(dirname(__FILE__).\'/uni2cid_aj16.php\');'."\n";
852 break;
853 }
854 case 'CID0KR': {
855 $pfile .= '// Korean'."\n";
856 $pfile .= '$enc=\'UniKS-UTF16-H\';'."\n";
857 $pfile .= '$cidinfo=array(\'Registry\'=>\'Adobe\', \'Ordering\'=>\'Korea1\',\'Supplement\'=>0);'."\n";
858 $pfile .= 'include(dirname(__FILE__).\'/uni2cid_ak12.php\');'."\n";
859 break;
860 }
861 case 'CID0CS': {
862 $pfile .= '// Chinese Simplified'."\n";
863 $pfile .= '$enc=\'UniGB-UTF16-H\';'."\n";
864 $pfile .= '$cidinfo=array(\'Registry\'=>\'Adobe\', \'Ordering\'=>\'GB1\',\'Supplement\'=>2);'."\n";
865 $pfile .= 'include(dirname(__FILE__).\'/uni2cid_ag15.php\');'."\n";
866 break;
867 }
868 case 'CID0CT':
869 default: {
870 $pfile .= '// Chinese Traditional'."\n";
871 $pfile .= '$enc=\'UniCNS-UTF16-H\';'."\n";
872 $pfile .= '$cidinfo=array(\'Registry\'=>\'Adobe\', \'Ordering\'=>\'CNS1\',\'Supplement\'=>0);'."\n";
873 $pfile .= 'include(dirname(__FILE__).\'/uni2cid_aj16.php\');'."\n";
874 break;
875 }
876 }
877 } else {
878 // TrueType
879 $pfile .= '$enc=\''.$fmetric['enc'].'\';'."\n";
880 $pfile .= '$file=\''.$fmetric['file'].'\';'."\n";
881 $pfile .= '$ctg=\''.$fmetric['ctg'].'\';'."\n";
882 // create CIDToGIDMap
883 $cidtogidmap = str_pad('', 131072, "\x00"); // (256 * 256 * 2) = 131072
884 foreach ($ctg as $cid => $gid) {
885 $cidtogidmap = self::updateCIDtoGIDmap($cidtogidmap, $cid, $ctg[$cid]);
886 }
887 // store compressed CIDToGIDMap
888 $fp = TCPDF_STATIC::fopenLocal($outpath.$fmetric['ctg'], 'wb');
889 fwrite($fp, gzcompress($cidtogidmap));
890 fclose($fp);
891 }
892 }
893 $pfile .= '$desc=array(';
894 $pfile .= '\'Flags\'=>'.$fmetric['Flags'].',';
895 $pfile .= '\'FontBBox\'=>\'['.$fmetric['bbox'].']\',';
896 $pfile .= '\'ItalicAngle\'=>'.$fmetric['italicAngle'].',';
897 $pfile .= '\'Ascent\'=>'.$fmetric['Ascent'].',';
898 $pfile .= '\'Descent\'=>'.$fmetric['Descent'].',';
899 $pfile .= '\'Leading\'=>'.$fmetric['Leading'].',';
900 $pfile .= '\'CapHeight\'=>'.$fmetric['CapHeight'].',';
901 $pfile .= '\'XHeight\'=>'.$fmetric['XHeight'].',';
902 $pfile .= '\'StemV\'=>'.$fmetric['StemV'].',';
903 $pfile .= '\'StemH\'=>'.$fmetric['StemH'].',';
904 $pfile .= '\'AvgWidth\'=>'.$fmetric['AvgWidth'].',';
905 $pfile .= '\'MaxWidth\'=>'.$fmetric['MaxWidth'].',';
906 $pfile .= '\'MissingWidth\'=>'.$fmetric['MissingWidth'].'';
907 $pfile .= ');'."\n";
908 if (!empty($fmetric['cbbox'])) {
909 $pfile .= '$cbbox=array('.substr($fmetric['cbbox'], 1).');'."\n";
910 }
911 $pfile .= '$cw=array('.substr($fmetric['cw'], 1).');'."\n";
912 $pfile .= '// --- EOF ---'."\n";
913 // store file
914 $fp = TCPDF_STATIC::fopenLocal($outpath.$font_name.'.php', 'w');
915 fwrite($fp, $pfile);
916 fclose($fp);
917 // return TCPDF font name
918 return $font_name;
919 }
print $file
static _getfontpath()
Return fonts path.
static $encmap
Array of Encoding Maps.
static fopenLocal($filename, $mode)
Wrapper to use fopen only with local files.
static _getFWORD($str, $offset)
Get FWORD from string (Big Endian 16-bit signed integer).
static _getUFWORD($str, $offset)
Get UFWORD from string (Big Endian 16-bit unsigned integer).
static _getFIXED($str, $offset)
Get FIXED from string (32-bit signed fixed-point number (16.16).
$r
Definition: example_031.php:79

References $data, TCPDF_FONT_DATA\$encmap, $file, $r, TCPDF_STATIC\_getBYTE(), TCPDF_STATIC\_getFIXED(), _getfontpath(), TCPDF_STATIC\_getFWORD(), TCPDF_STATIC\_getSHORT(), TCPDF_STATIC\_getUFWORD(), TCPDF_STATIC\_getULONG(), TCPDF_STATIC\_getUSHORT(), and TCPDF_STATIC\fopenLocal().

+ Here is the call graph for this function:

◆ arrUTF8ToUTF16BE()

static TCPDF_FONTS::arrUTF8ToUTF16BE (   $unicode,
  $setbom = false 
)
static

Converts array of UTF-8 characters to UTF16-BE string.


Based on: http://www.faqs.org/rfcs/rfc2781.html

  Encoding UTF-16:

  Encoding of a single character from an ISO 10646 character value to
   UTF-16 proceeds as follows. Let U be the character number, no greater
   than 0x10FFFF.

   1) If U < 0x10000, encode U as a 16-bit unsigned integer and
      terminate.

   2) Let U' = U - 0x10000. Because U is less than or equal to 0x10FFFF,
      U' must be less than or equal to 0xFFFFF. That is, U' can be
      represented in 20 bits.

   3) Initialize two 16-bit unsigned integers, W1 and W2, to 0xD800 and
      0xDC00, respectively. These integers each have 10 bits free to
      encode the character value, for a total of 20 bits.

   4) Assign the 10 high-order bits of the 20-bit U' to the 10 low-order
      bits of W1 and the 10 low-order bits of U' to the 10 low-order
      bits of W2. Terminate.

   Graphically, steps 2 through 4 look like:
   U' = yyyyyyyyyyxxxxxxxxxx
   W1 = 110110yyyyyyyyyy
   W2 = 110111xxxxxxxxxx
Parameters
$unicode(array) array containing UTF-8 unicode values
$setbom(boolean) if true set the Byte Order Mark (BOM = 0xFEFF)
Returns
string
Author
Nicola Asuni
Since
2.1.000 (2008-01-08) static

Definition at line 1744 of file tcpdf_fonts.php.

1744 {
1745 $outstr = ''; // string to be returned
1746 if ($setbom) {
1747 $outstr .= "\xFE\xFF"; // Byte Order Mark (BOM)
1748 }
1749 foreach ($unicode as $char) {
1750 if ($char == 0x200b) {
1751 // skip Unicode Character 'ZERO WIDTH SPACE' (DEC:8203, U+200B)
1752 } elseif ($char == 0xFFFD) {
1753 $outstr .= "\xFF\xFD"; // replacement character
1754 } elseif ($char < 0x10000) {
1755 $outstr .= chr($char >> 0x08);
1756 $outstr .= chr($char & 0xFF);
1757 } else {
1758 $char -= 0x10000;
1759 $w1 = 0xD800 | ($char >> 0x0a);
1760 $w2 = 0xDC00 | ($char & 0x3FF);
1761 $outstr .= chr($w1 >> 0x08);
1762 $outstr .= chr($w1 & 0xFF);
1763 $outstr .= chr($w2 >> 0x08);
1764 $outstr .= chr($w2 & 0xFF);
1765 }
1766 }
1767 return $outstr;
1768 }

Referenced by TCPDF\getCellCode().

+ Here is the caller graph for this function:

◆ getFontFullPath()

static TCPDF_FONTS::getFontFullPath (   $file,
  $fontdir = false 
)
static

Return font full path.

Parameters
$file(string) Font file name.
$fontdir(string) Font directory (set to false fto search on default directories)
Returns
string Font full path or empty string
Author
Nicola Asuni
Since
6.0.025 static

Definition at line 1543 of file tcpdf_fonts.php.

1543 {
1544 $fontfile = '';
1545 // search files on various directories
1546 if (($fontdir !== false) AND @file_exists($fontdir.$file)) {
1547 $fontfile = $fontdir.$file;
1548 } elseif (@file_exists(self::_getfontpath().$file)) {
1549 $fontfile = self::_getfontpath().$file;
1550 } elseif (@file_exists($file)) {
1551 $fontfile = $file;
1552 }
1553 return $fontfile;
1554 }

References $file.

Referenced by TCPDF\_putfonts(), TCPDF\_puttruetypeunicode(), and TCPDF\AddFont().

+ Here is the caller graph for this function:

◆ getFontRefSize()

static TCPDF_FONTS::getFontRefSize (   $size,
  $refsize = 12 
)
static

Get a reference font size.

Parameters
$size(string) String containing font size value.
$refsize(float) Reference font size in points.
Returns
float value in points static

Definition at line 1566 of file tcpdf_fonts.php.

1566 {
1567 switch ($size) {
1568 case 'xx-small': {
1569 $size = ($refsize - 4);
1570 break;
1571 }
1572 case 'x-small': {
1573 $size = ($refsize - 3);
1574 break;
1575 }
1576 case 'small': {
1577 $size = ($refsize - 2);
1578 break;
1579 }
1580 case 'medium': {
1581 $size = $refsize;
1582 break;
1583 }
1584 case 'large': {
1585 $size = ($refsize + 2);
1586 break;
1587 }
1588 case 'x-large': {
1589 $size = ($refsize + 4);
1590 break;
1591 }
1592 case 'xx-large': {
1593 $size = ($refsize + 6);
1594 break;
1595 }
1596 case 'smaller': {
1597 $size = ($refsize - 3);
1598 break;
1599 }
1600 case 'larger': {
1601 $size = ($refsize + 3);
1602 break;
1603 }
1604 }
1605 return $size;
1606 }
$size
Definition: RandomTest.php:79

References $size.

Referenced by TCPDF\getHTMLFontUnits().

+ Here is the caller graph for this function:

◆ getUniord()

static TCPDF_FONTS::getUniord (   $uch)
static

Converts UTF-8 character to integer value.


Invalid byte sequences will be replaced with 0xFFFD (replacement character)
Based on: http://www.faqs.org/rfcs/rfc3629.html

   Char. number range  |        UTF-8 octet sequence
      (hexadecimal)    |              (binary)
   --------------------+-----------------------------------------------
   0000 0000-0000 007F | 0xxxxxxx
   0000 0080-0000 07FF | 110xxxxx 10xxxxxx
   0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
   0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
   ---------------------------------------------------------------------

  ABFN notation:
  ---------------------------------------------------------------------
  UTF8-octets = *( UTF8-char )
  UTF8-char   = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4
  UTF8-1      = x00-7F
  UTF8-2      = xC2-DF UTF8-tail

  UTF8-3      = xE0 xA0-BF UTF8-tail / xE1-EC 2( UTF8-tail ) /
                xED x80-9F UTF8-tail / xEE-EF 2( UTF8-tail )
  UTF8-4      = xF0 x90-BF 2( UTF8-tail ) / xF1-F3 3( UTF8-tail ) /
                xF4 x80-8F 2( UTF8-tail )
  UTF8-tail   = x80-BF
  ---------------------------------------------------------------------
Parameters
$uch(string) character string to process.
Returns
integer Unicode value
Author
Nicola Asuni static

Definition at line 1928 of file tcpdf_fonts.php.

1928 {
1929 if (function_exists('mb_convert_encoding')) {
1930 list(, $char) = @unpack('N', mb_convert_encoding($uch, 'UCS-4BE', 'UTF-8'));
1931 if ($char >= 0) {
1932 return $char;
1933 }
1934 }
1935 $bytes = array(); // array containing single character byte sequences
1936 $countbytes = 0;
1937 $numbytes = 1; // number of octetc needed to represent the UTF-8 character
1938 $length = strlen($uch);
1939 for ($i = 0; $i < $length; ++$i) {
1940 $char = ord($uch[$i]); // get one string character at time
1941 if ($countbytes == 0) { // get starting octect
1942 if ($char <= 0x7F) {
1943 return $char; // use the character "as is" because is ASCII
1944 } elseif (($char >> 0x05) == 0x06) { // 2 bytes character (0x06 = 110 BIN)
1945 $bytes[] = ($char - 0xC0) << 0x06;
1946 ++$countbytes;
1947 $numbytes = 2;
1948 } elseif (($char >> 0x04) == 0x0E) { // 3 bytes character (0x0E = 1110 BIN)
1949 $bytes[] = ($char - 0xE0) << 0x0C;
1950 ++$countbytes;
1951 $numbytes = 3;
1952 } elseif (($char >> 0x03) == 0x1E) { // 4 bytes character (0x1E = 11110 BIN)
1953 $bytes[] = ($char - 0xF0) << 0x12;
1954 ++$countbytes;
1955 $numbytes = 4;
1956 } else {
1957 // use replacement character for other invalid sequences
1958 return 0xFFFD;
1959 }
1960 } elseif (($char >> 0x06) == 0x02) { // bytes 2, 3 and 4 must start with 0x02 = 10 BIN
1961 $bytes[] = $char - 0x80;
1962 ++$countbytes;
1963 if ($countbytes == $numbytes) {
1964 // compose UTF-8 bytes to a single unicode value
1965 $char = $bytes[0];
1966 for ($j = 1; $j < $numbytes; ++$j) {
1967 $char += ($bytes[$j] << (($numbytes - $j - 1) * 0x06));
1968 }
1969 if ((($char >= 0xD800) AND ($char <= 0xDFFF)) OR ($char >= 0x10FFFF)) {
1970 // The definition of UTF-8 prohibits encoding character numbers between
1971 // U+D800 and U+DFFF, which are reserved for use with the UTF-16
1972 // encoding form (as surrogate pairs) and do not directly represent
1973 // characters.
1974 return 0xFFFD; // use replacement character
1975 } else {
1976 return $char;
1977 }
1978 }
1979 } else {
1980 // use replacement character for other invalid sequences
1981 return 0xFFFD;
1982 }
1983 }
1984 return 0xFFFD;
1985 }

◆ UniArrSubString()

static TCPDF_FONTS::UniArrSubString (   $uniarr,
  $start = '',
  $end = '' 
)
static

Extract a slice of the $uniarr array and return it as string.

Parameters
$uniarr(string) The input array of characters.
$start(int) the starting element of $strarr.
$end(int) first element that will not be returned.
Returns
Return part of a string
Since
4.5.037 (2009-04-07) static

Definition at line 1817 of file tcpdf_fonts.php.

1817 {
1818 if (strlen($start) == 0) {
1819 $start = 0;
1820 }
1821 if (strlen($end) == 0) {
1822 $end = count($uniarr);
1823 }
1824 $string = '';
1825 for ($i=$start; $i < $end; ++$i) {
1826 $string .= $uniarr[$i];
1827 }
1828 return $string;
1829 }

Referenced by TCPDF\replaceMissingChars(), and TCPDF\Write().

+ Here is the caller graph for this function:

◆ unichr()

static TCPDF_FONTS::unichr (   $c,
  $unicode = true 
)
static

Returns the unicode caracter specified by the value.

Parameters
$c(int) UTF-8 value
$unicode(boolean) True if we are in unicode mode, false otherwise.
Returns
Returns the specified character.
Since
2.3.000 (2008-03-05) static

Definition at line 1666 of file tcpdf_fonts.php.

1666 {
1667 if (!$unicode) {
1668 return chr($c);
1669 } elseif ($c <= 0x7F) {
1670 // one byte
1671 return chr($c);
1672 } elseif ($c <= 0x7FF) {
1673 // two bytes
1674 return chr(0xC0 | $c >> 6).chr(0x80 | $c & 0x3F);
1675 } elseif ($c <= 0xFFFF) {
1676 // three bytes
1677 return chr(0xE0 | $c >> 12).chr(0x80 | $c >> 6 & 0x3F).chr(0x80 | $c & 0x3F);
1678 } elseif ($c <= 0x10FFFF) {
1679 // four bytes
1680 return chr(0xF0 | $c >> 18).chr(0x80 | $c >> 12 & 0x3F).chr(0x80 | $c >> 6 & 0x3F).chr(0x80 | $c & 0x3F);
1681 } else {
1682 return '';
1683 }
1684 }

Referenced by TCPDF\_fixAES256Password(), TCPDF\getCellCode(), TCPDF\getNumLines(), TCPDF\putHtmlListBullet(), and TCPDF\Write().

+ Here is the caller graph for this function:

◆ unichrASCII()

static TCPDF_FONTS::unichrASCII (   $c)
static

Returns the unicode caracter specified by ASCII value.

Parameters
$c(int) UTF-8 value
Returns
Returns the specified character. static

Definition at line 1702 of file tcpdf_fonts.php.

1702 {
1703 return self::unichr($c, false);
1704 }
static unichr($c, $unicode=true)
Returns the unicode caracter specified by the value.

◆ unichrUnicode()

static TCPDF_FONTS::unichrUnicode (   $c)
static

Returns the unicode caracter specified by UTF-8 value.

Parameters
$c(int) UTF-8 value
Returns
Returns the specified character. static

Definition at line 1692 of file tcpdf_fonts.php.

1692 {
1693 return self::unichr($c, true);
1694 }

◆ uniord()

static TCPDF_FONTS::uniord (   $uch)
static

Converts UTF-8 character to integer value.


Uses the getUniord() method if the value is not cached.

Parameters
$uch(string) character string to process.
Returns
integer Unicode value static

Definition at line 1888 of file tcpdf_fonts.php.

1888 {
1889 if (!isset(self::$cache_uniord[$uch])) {
1890 self::$cache_uniord[$uch] = self::getUniord($uch);
1891 }
1892 return self::$cache_uniord[$uch];
1893 }
static getUniord($uch)
Converts UTF-8 character to integer value.

◆ updateCIDtoGIDmap()

static TCPDF_FONTS::updateCIDtoGIDmap (   $map,
  $cid,
  $gid 
)
static

Update the CIDToGIDMap string with a new value.

Parameters
$map(string) CIDToGIDMap.
$cid(int) CID value.
$gid(int) GID value.
Returns
(string) CIDToGIDMap.
Author
Nicola Asuni
Since
5.9.123 (2011-09-29) static

Definition at line 1506 of file tcpdf_fonts.php.

1506 {
1507 if (($cid >= 0) AND ($cid <= 0xFFFF) AND ($gid >= 0)) {
1508 if ($gid > 0xFFFF) {
1509 $gid -= 0x10000;
1510 }
1511 $map[($cid * 2)] = chr($gid >> 8);
1512 $map[(($cid * 2) + 1)] = chr($gid & 0xFF);
1513 }
1514 return $map;
1515 }

◆ UTF8ArrayToUniArray()

static TCPDF_FONTS::UTF8ArrayToUniArray (   $ta,
  $isunicode = true 
)
static

Convert an array of UTF8 values to array of unicode characters.

Parameters
$ta(array) The input array of UTF8 values.
$isunicode(boolean) True for Unicode mode, false otherwise.
Returns
Return array of unicode characters
Since
4.5.037 (2009-04-07) static

Definition at line 1778 of file tcpdf_fonts.php.

1778 {
1779 if ($isunicode) {
1780 return array_map(array('TCPDF_FONTS', 'unichrUnicode'), $ta);
1781 }
1782 return array_map(array('TCPDF_FONTS', 'unichrASCII'), $ta);
1783 }

Referenced by TCPDF\replaceMissingChars(), and TCPDF\Write().

+ Here is the caller graph for this function:

◆ UTF8ArrSubString()

static TCPDF_FONTS::UTF8ArrSubString (   $strarr,
  $start = '',
  $end = '',
  $unicode = true 
)
static

Extract a slice of the $strarr array and return it as string.

Parameters
$strarr(string) The input array of characters.
$start(int) the starting element of $strarr.
$end(int) first element that will not be returned.
$unicode(boolean) True if we are in unicode mode, false otherwise.
Returns
Return part of a string static

Definition at line 1794 of file tcpdf_fonts.php.

1794 {
1795 if (strlen($start) == 0) {
1796 $start = 0;
1797 }
1798 if (strlen($end) == 0) {
1799 $end = count($strarr);
1800 }
1801 $string = '';
1802 for ($i = $start; $i < $end; ++$i) {
1803 $string .= self::unichr($strarr[$i], $unicode);
1804 }
1805 return $string;
1806 }

Referenced by TCPDF\hyphenateText(), and TCPDF\hyphenateWord().

+ Here is the caller graph for this function:

◆ UTF8ArrToLatin1()

static TCPDF_FONTS::UTF8ArrToLatin1 (   $unicode)
static

Converts UTF-8 characters array to array of Latin1 string

Parameters
$unicode(array) array containing UTF-8 unicode values
Returns
array
Author
Nicola Asuni
Since
4.8.023 (2010-01-15) static

Definition at line 1864 of file tcpdf_fonts.php.

1864 {
1865 $outstr = ''; // string to be returned
1866 foreach ($unicode as $char) {
1867 if ($char < 256) {
1868 $outstr .= chr($char);
1869 } elseif (array_key_exists($char, TCPDF_FONT_DATA::$uni_utf8tolatin)) {
1870 // map from UTF-8
1871 $outstr .= chr(TCPDF_FONT_DATA::$uni_utf8tolatin[$char]);
1872 } elseif ($char == 0xFFFD) {
1873 // skip
1874 } else {
1875 $outstr .= '?';
1876 }
1877 }
1878 return $outstr;
1879 }
static $uni_utf8tolatin
Array of character substitutions from UTF-8 Unicode to Latin1.

References TCPDF_FONT_DATA\$uni_utf8tolatin.

◆ UTF8ArrToLatin1Arr()

static TCPDF_FONTS::UTF8ArrToLatin1Arr (   $unicode)
static

Converts UTF-8 characters array to array of Latin1 characters array

Parameters
$unicode(array) array containing UTF-8 unicode values
Returns
array
Author
Nicola Asuni
Since
4.8.023 (2010-01-15) static

Definition at line 1839 of file tcpdf_fonts.php.

1839 {
1840 $outarr = array(); // array to be returned
1841 foreach ($unicode as $char) {
1842 if ($char < 256) {
1843 $outarr[] = $char;
1844 } elseif (array_key_exists($char, TCPDF_FONT_DATA::$uni_utf8tolatin)) {
1845 // map from UTF-8
1846 $outarr[] = TCPDF_FONT_DATA::$uni_utf8tolatin[$char];
1847 } elseif ($char == 0xFFFD) {
1848 // skip
1849 } else {
1850 $outarr[] = 63; // '?' character
1851 }
1852 }
1853 return $outarr;
1854 }

References TCPDF_FONT_DATA\$uni_utf8tolatin.

Referenced by TCPDF\GetArrStringWidth().

+ Here is the caller graph for this function:

◆ utf8Bidi()

static TCPDF_FONTS::utf8Bidi (   $ta,
  $str = '',
  $forcertl = false,
  $isunicode = true,
$currentfont 
)
static

Reverse the RLT substrings using the Bidirectional Algorithm (http://unicode.org/reports/tr9/).

Parameters
$ta(array) array of characters composing the string.
$str(string) string to process
$forcertl(bool) if 'R' forces RTL, if 'L' forces LTR
$isunicode(boolean) True if the document is in Unicode mode, false otherwise.
$currentfont(array) Reference to current font array.
Returns
array of unicode chars
Author
Nicola Asuni
Since
2.4.000 (2008-03-06) static

Definition at line 2088 of file tcpdf_fonts.php.

2088 {
2089 // paragraph embedding level
2090 $pel = 0;
2091 // max level
2092 $maxlevel = 0;
2093 if (TCPDF_STATIC::empty_string($str)) {
2094 // create string from array
2095 $str = self::UTF8ArrSubString($ta, '', '', $isunicode);
2096 }
2097 // check if string contains arabic text
2098 if (preg_match(TCPDF_FONT_DATA::$uni_RE_PATTERN_ARABIC, $str)) {
2099 $arabic = true;
2100 } else {
2101 $arabic = false;
2102 }
2103 // check if string contains RTL text
2104 if (!($forcertl OR $arabic OR preg_match(TCPDF_FONT_DATA::$uni_RE_PATTERN_RTL, $str))) {
2105 return $ta;
2106 }
2107
2108 // get number of chars
2109 $numchars = count($ta);
2110
2111 if ($forcertl == 'R') {
2112 $pel = 1;
2113 } elseif ($forcertl == 'L') {
2114 $pel = 0;
2115 } else {
2116 // P2. In each paragraph, find the first character of type L, AL, or R.
2117 // P3. If a character is found in P2 and it is of type AL or R, then set the paragraph embedding level to one; otherwise, set it to zero.
2118 for ($i=0; $i < $numchars; ++$i) {
2119 $type = TCPDF_FONT_DATA::$uni_type[$ta[$i]];
2120 if ($type == 'L') {
2121 $pel = 0;
2122 break;
2123 } elseif (($type == 'AL') OR ($type == 'R')) {
2124 $pel = 1;
2125 break;
2126 }
2127 }
2128 }
2129
2130 // Current Embedding Level
2131 $cel = $pel;
2132 // directional override status
2133 $dos = 'N';
2134 $remember = array();
2135 // start-of-level-run
2136 $sor = $pel % 2 ? 'R' : 'L';
2137 $eor = $sor;
2138
2139 // Array of characters data
2140 $chardata = Array();
2141
2142 // X1. Begin by setting the current embedding level to the paragraph embedding level. Set the directional override status to neutral. Process each character iteratively, applying rules X2 through X9. Only embedding levels from 0 to 61 are valid in this phase.
2143 // In the resolution of levels in rules I1 and I2, the maximum embedding level of 62 can be reached.
2144 for ($i=0; $i < $numchars; ++$i) {
2145 if ($ta[$i] == TCPDF_FONT_DATA::$uni_RLE) {
2146 // X2. With each RLE, compute the least greater odd embedding level.
2147 // a. If this new level would be valid, then this embedding code is valid. Remember (push) the current embedding level and override status. Reset the current level to this new level, and reset the override status to neutral.
2148 // b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status.
2149 $next_level = $cel + ($cel % 2) + 1;
2150 if ($next_level < 62) {
2151 $remember[] = array('num' => TCPDF_FONT_DATA::$uni_RLE, 'cel' => $cel, 'dos' => $dos);
2152 $cel = $next_level;
2153 $dos = 'N';
2154 $sor = $eor;
2155 $eor = $cel % 2 ? 'R' : 'L';
2156 }
2157 } elseif ($ta[$i] == TCPDF_FONT_DATA::$uni_LRE) {
2158 // X3. With each LRE, compute the least greater even embedding level.
2159 // a. If this new level would be valid, then this embedding code is valid. Remember (push) the current embedding level and override status. Reset the current level to this new level, and reset the override status to neutral.
2160 // b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status.
2161 $next_level = $cel + 2 - ($cel % 2);
2162 if ( $next_level < 62 ) {
2163 $remember[] = array('num' => TCPDF_FONT_DATA::$uni_LRE, 'cel' => $cel, 'dos' => $dos);
2164 $cel = $next_level;
2165 $dos = 'N';
2166 $sor = $eor;
2167 $eor = $cel % 2 ? 'R' : 'L';
2168 }
2169 } elseif ($ta[$i] == TCPDF_FONT_DATA::$uni_RLO) {
2170 // X4. With each RLO, compute the least greater odd embedding level.
2171 // a. If this new level would be valid, then this embedding code is valid. Remember (push) the current embedding level and override status. Reset the current level to this new level, and reset the override status to right-to-left.
2172 // b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status.
2173 $next_level = $cel + ($cel % 2) + 1;
2174 if ($next_level < 62) {
2175 $remember[] = array('num' => TCPDF_FONT_DATA::$uni_RLO, 'cel' => $cel, 'dos' => $dos);
2176 $cel = $next_level;
2177 $dos = 'R';
2178 $sor = $eor;
2179 $eor = $cel % 2 ? 'R' : 'L';
2180 }
2181 } elseif ($ta[$i] == TCPDF_FONT_DATA::$uni_LRO) {
2182 // X5. With each LRO, compute the least greater even embedding level.
2183 // a. If this new level would be valid, then this embedding code is valid. Remember (push) the current embedding level and override status. Reset the current level to this new level, and reset the override status to left-to-right.
2184 // b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status.
2185 $next_level = $cel + 2 - ($cel % 2);
2186 if ( $next_level < 62 ) {
2187 $remember[] = array('num' => TCPDF_FONT_DATA::$uni_LRO, 'cel' => $cel, 'dos' => $dos);
2188 $cel = $next_level;
2189 $dos = 'L';
2190 $sor = $eor;
2191 $eor = $cel % 2 ? 'R' : 'L';
2192 }
2193 } elseif ($ta[$i] == TCPDF_FONT_DATA::$uni_PDF) {
2194 // X7. With each PDF, determine the matching embedding or override code. If there was a valid matching code, restore (pop) the last remembered (pushed) embedding level and directional override.
2195 if (count($remember)) {
2196 $last = count($remember ) - 1;
2197 if (($remember[$last]['num'] == TCPDF_FONT_DATA::$uni_RLE) OR
2198 ($remember[$last]['num'] == TCPDF_FONT_DATA::$uni_LRE) OR
2199 ($remember[$last]['num'] == TCPDF_FONT_DATA::$uni_RLO) OR
2200 ($remember[$last]['num'] == TCPDF_FONT_DATA::$uni_LRO)) {
2201 $match = array_pop($remember);
2202 $cel = $match['cel'];
2203 $dos = $match['dos'];
2204 $sor = $eor;
2205 $eor = ($cel > $match['cel'] ? $cel : $match['cel']) % 2 ? 'R' : 'L';
2206 }
2207 }
2208 } elseif (($ta[$i] != TCPDF_FONT_DATA::$uni_RLE) AND
2209 ($ta[$i] != TCPDF_FONT_DATA::$uni_LRE) AND
2210 ($ta[$i] != TCPDF_FONT_DATA::$uni_RLO) AND
2211 ($ta[$i] != TCPDF_FONT_DATA::$uni_LRO) AND
2212 ($ta[$i] != TCPDF_FONT_DATA::$uni_PDF)) {
2213 // X6. For all types besides RLE, LRE, RLO, LRO, and PDF:
2214 // a. Set the level of the current character to the current embedding level.
2215 // b. Whenever the directional override status is not neutral, reset the current character type to the directional override status.
2216 if ($dos != 'N') {
2217 $chardir = $dos;
2218 } else {
2219 if (isset(TCPDF_FONT_DATA::$uni_type[$ta[$i]])) {
2220 $chardir = TCPDF_FONT_DATA::$uni_type[$ta[$i]];
2221 } else {
2222 $chardir = 'L';
2223 }
2224 }
2225 // stores string characters and other information
2226 $chardata[] = array('char' => $ta[$i], 'level' => $cel, 'type' => $chardir, 'sor' => $sor, 'eor' => $eor);
2227 }
2228 } // end for each char
2229
2230 // X8. All explicit directional embeddings and overrides are completely terminated at the end of each paragraph. Paragraph separators are not included in the embedding.
2231 // X9. Remove all RLE, LRE, RLO, LRO, PDF, and BN codes.
2232 // X10. The remaining rules are applied to each run of characters at the same level. For each run, determine the start-of-level-run (sor) and end-of-level-run (eor) type, either L or R. This depends on the higher of the two levels on either side of the boundary (at the start or end of the paragraph, the level of the 'other' run is the base embedding level). If the higher level is odd, the type is R; otherwise, it is L.
2233
2234 // 3.3.3 Resolving Weak Types
2235 // Weak types are now resolved one level run at a time. At level run boundaries where the type of the character on the other side of the boundary is required, the type assigned to sor or eor is used.
2236 // Nonspacing marks are now resolved based on the previous characters.
2237 $numchars = count($chardata);
2238
2239 // W1. Examine each nonspacing mark (NSM) in the level run, and change the type of the NSM to the type of the previous character. If the NSM is at the start of the level run, it will get the type of sor.
2240 $prevlevel = -1; // track level changes
2241 $levcount = 0; // counts consecutive chars at the same level
2242 for ($i=0; $i < $numchars; ++$i) {
2243 if ($chardata[$i]['type'] == 'NSM') {
2244 if ($levcount) {
2245 $chardata[$i]['type'] = $chardata[$i]['sor'];
2246 } elseif ($i > 0) {
2247 $chardata[$i]['type'] = $chardata[($i-1)]['type'];
2248 }
2249 }
2250 if ($chardata[$i]['level'] != $prevlevel) {
2251 $levcount = 0;
2252 } else {
2253 ++$levcount;
2254 }
2255 $prevlevel = $chardata[$i]['level'];
2256 }
2257
2258 // W2. Search backward from each instance of a European number until the first strong type (R, L, AL, or sor) is found. If an AL is found, change the type of the European number to Arabic number.
2259 $prevlevel = -1;
2260 $levcount = 0;
2261 for ($i=0; $i < $numchars; ++$i) {
2262 if ($chardata[$i]['char'] == 'EN') {
2263 for ($j=$levcount; $j >= 0; $j--) {
2264 if ($chardata[$j]['type'] == 'AL') {
2265 $chardata[$i]['type'] = 'AN';
2266 } elseif (($chardata[$j]['type'] == 'L') OR ($chardata[$j]['type'] == 'R')) {
2267 break;
2268 }
2269 }
2270 }
2271 if ($chardata[$i]['level'] != $prevlevel) {
2272 $levcount = 0;
2273 } else {
2274 ++$levcount;
2275 }
2276 $prevlevel = $chardata[$i]['level'];
2277 }
2278
2279 // W3. Change all ALs to R.
2280 for ($i=0; $i < $numchars; ++$i) {
2281 if ($chardata[$i]['type'] == 'AL') {
2282 $chardata[$i]['type'] = 'R';
2283 }
2284 }
2285
2286 // W4. A single European separator between two European numbers changes to a European number. A single common separator between two numbers of the same type changes to that type.
2287 $prevlevel = -1;
2288 $levcount = 0;
2289 for ($i=0; $i < $numchars; ++$i) {
2290 if (($levcount > 0) AND (($i+1) < $numchars) AND ($chardata[($i+1)]['level'] == $prevlevel)) {
2291 if (($chardata[$i]['type'] == 'ES') AND ($chardata[($i-1)]['type'] == 'EN') AND ($chardata[($i+1)]['type'] == 'EN')) {
2292 $chardata[$i]['type'] = 'EN';
2293 } elseif (($chardata[$i]['type'] == 'CS') AND ($chardata[($i-1)]['type'] == 'EN') AND ($chardata[($i+1)]['type'] == 'EN')) {
2294 $chardata[$i]['type'] = 'EN';
2295 } elseif (($chardata[$i]['type'] == 'CS') AND ($chardata[($i-1)]['type'] == 'AN') AND ($chardata[($i+1)]['type'] == 'AN')) {
2296 $chardata[$i]['type'] = 'AN';
2297 }
2298 }
2299 if ($chardata[$i]['level'] != $prevlevel) {
2300 $levcount = 0;
2301 } else {
2302 ++$levcount;
2303 }
2304 $prevlevel = $chardata[$i]['level'];
2305 }
2306
2307 // W5. A sequence of European terminators adjacent to European numbers changes to all European numbers.
2308 $prevlevel = -1;
2309 $levcount = 0;
2310 for ($i=0; $i < $numchars; ++$i) {
2311 if ($chardata[$i]['type'] == 'ET') {
2312 if (($levcount > 0) AND ($chardata[($i-1)]['type'] == 'EN')) {
2313 $chardata[$i]['type'] = 'EN';
2314 } else {
2315 $j = $i+1;
2316 while (($j < $numchars) AND ($chardata[$j]['level'] == $prevlevel)) {
2317 if ($chardata[$j]['type'] == 'EN') {
2318 $chardata[$i]['type'] = 'EN';
2319 break;
2320 } elseif ($chardata[$j]['type'] != 'ET') {
2321 break;
2322 }
2323 ++$j;
2324 }
2325 }
2326 }
2327 if ($chardata[$i]['level'] != $prevlevel) {
2328 $levcount = 0;
2329 } else {
2330 ++$levcount;
2331 }
2332 $prevlevel = $chardata[$i]['level'];
2333 }
2334
2335 // W6. Otherwise, separators and terminators change to Other Neutral.
2336 $prevlevel = -1;
2337 $levcount = 0;
2338 for ($i=0; $i < $numchars; ++$i) {
2339 if (($chardata[$i]['type'] == 'ET') OR ($chardata[$i]['type'] == 'ES') OR ($chardata[$i]['type'] == 'CS')) {
2340 $chardata[$i]['type'] = 'ON';
2341 }
2342 if ($chardata[$i]['level'] != $prevlevel) {
2343 $levcount = 0;
2344 } else {
2345 ++$levcount;
2346 }
2347 $prevlevel = $chardata[$i]['level'];
2348 }
2349
2350 //W7. Search backward from each instance of a European number until the first strong type (R, L, or sor) is found. If an L is found, then change the type of the European number to L.
2351 $prevlevel = -1;
2352 $levcount = 0;
2353 for ($i=0; $i < $numchars; ++$i) {
2354 if ($chardata[$i]['char'] == 'EN') {
2355 for ($j=$levcount; $j >= 0; $j--) {
2356 if ($chardata[$j]['type'] == 'L') {
2357 $chardata[$i]['type'] = 'L';
2358 } elseif ($chardata[$j]['type'] == 'R') {
2359 break;
2360 }
2361 }
2362 }
2363 if ($chardata[$i]['level'] != $prevlevel) {
2364 $levcount = 0;
2365 } else {
2366 ++$levcount;
2367 }
2368 $prevlevel = $chardata[$i]['level'];
2369 }
2370
2371 // N1. A sequence of neutrals takes the direction of the surrounding strong text if the text on both sides has the same direction. European and Arabic numbers act as if they were R in terms of their influence on neutrals. Start-of-level-run (sor) and end-of-level-run (eor) are used at level run boundaries.
2372 $prevlevel = -1;
2373 $levcount = 0;
2374 for ($i=0; $i < $numchars; ++$i) {
2375 if (($levcount > 0) AND (($i+1) < $numchars) AND ($chardata[($i+1)]['level'] == $prevlevel)) {
2376 if (($chardata[$i]['type'] == 'N') AND ($chardata[($i-1)]['type'] == 'L') AND ($chardata[($i+1)]['type'] == 'L')) {
2377 $chardata[$i]['type'] = 'L';
2378 } elseif (($chardata[$i]['type'] == 'N') AND
2379 (($chardata[($i-1)]['type'] == 'R') OR ($chardata[($i-1)]['type'] == 'EN') OR ($chardata[($i-1)]['type'] == 'AN')) AND
2380 (($chardata[($i+1)]['type'] == 'R') OR ($chardata[($i+1)]['type'] == 'EN') OR ($chardata[($i+1)]['type'] == 'AN'))) {
2381 $chardata[$i]['type'] = 'R';
2382 } elseif ($chardata[$i]['type'] == 'N') {
2383 // N2. Any remaining neutrals take the embedding direction
2384 $chardata[$i]['type'] = $chardata[$i]['sor'];
2385 }
2386 } elseif (($levcount == 0) AND (($i+1) < $numchars) AND ($chardata[($i+1)]['level'] == $prevlevel)) {
2387 // first char
2388 if (($chardata[$i]['type'] == 'N') AND ($chardata[$i]['sor'] == 'L') AND ($chardata[($i+1)]['type'] == 'L')) {
2389 $chardata[$i]['type'] = 'L';
2390 } elseif (($chardata[$i]['type'] == 'N') AND
2391 (($chardata[$i]['sor'] == 'R') OR ($chardata[$i]['sor'] == 'EN') OR ($chardata[$i]['sor'] == 'AN')) AND
2392 (($chardata[($i+1)]['type'] == 'R') OR ($chardata[($i+1)]['type'] == 'EN') OR ($chardata[($i+1)]['type'] == 'AN'))) {
2393 $chardata[$i]['type'] = 'R';
2394 } elseif ($chardata[$i]['type'] == 'N') {
2395 // N2. Any remaining neutrals take the embedding direction
2396 $chardata[$i]['type'] = $chardata[$i]['sor'];
2397 }
2398 } elseif (($levcount > 0) AND ((($i+1) == $numchars) OR (($i+1) < $numchars) AND ($chardata[($i+1)]['level'] != $prevlevel))) {
2399 //last char
2400 if (($chardata[$i]['type'] == 'N') AND ($chardata[($i-1)]['type'] == 'L') AND ($chardata[$i]['eor'] == 'L')) {
2401 $chardata[$i]['type'] = 'L';
2402 } elseif (($chardata[$i]['type'] == 'N') AND
2403 (($chardata[($i-1)]['type'] == 'R') OR ($chardata[($i-1)]['type'] == 'EN') OR ($chardata[($i-1)]['type'] == 'AN')) AND
2404 (($chardata[$i]['eor'] == 'R') OR ($chardata[$i]['eor'] == 'EN') OR ($chardata[$i]['eor'] == 'AN'))) {
2405 $chardata[$i]['type'] = 'R';
2406 } elseif ($chardata[$i]['type'] == 'N') {
2407 // N2. Any remaining neutrals take the embedding direction
2408 $chardata[$i]['type'] = $chardata[$i]['sor'];
2409 }
2410 } elseif ($chardata[$i]['type'] == 'N') {
2411 // N2. Any remaining neutrals take the embedding direction
2412 $chardata[$i]['type'] = $chardata[$i]['sor'];
2413 }
2414 if ($chardata[$i]['level'] != $prevlevel) {
2415 $levcount = 0;
2416 } else {
2417 ++$levcount;
2418 }
2419 $prevlevel = $chardata[$i]['level'];
2420 }
2421
2422 // I1. For all characters with an even (left-to-right) embedding direction, those of type R go up one level and those of type AN or EN go up two levels.
2423 // I2. For all characters with an odd (right-to-left) embedding direction, those of type L, EN or AN go up one level.
2424 for ($i=0; $i < $numchars; ++$i) {
2425 $odd = $chardata[$i]['level'] % 2;
2426 if ($odd) {
2427 if (($chardata[$i]['type'] == 'L') OR ($chardata[$i]['type'] == 'AN') OR ($chardata[$i]['type'] == 'EN')) {
2428 $chardata[$i]['level'] += 1;
2429 }
2430 } else {
2431 if ($chardata[$i]['type'] == 'R') {
2432 $chardata[$i]['level'] += 1;
2433 } elseif (($chardata[$i]['type'] == 'AN') OR ($chardata[$i]['type'] == 'EN')) {
2434 $chardata[$i]['level'] += 2;
2435 }
2436 }
2437 $maxlevel = max($chardata[$i]['level'],$maxlevel);
2438 }
2439
2440 // L1. On each line, reset the embedding level of the following characters to the paragraph embedding level:
2441 // 1. Segment separators,
2442 // 2. Paragraph separators,
2443 // 3. Any sequence of whitespace characters preceding a segment separator or paragraph separator, and
2444 // 4. Any sequence of white space characters at the end of the line.
2445 for ($i=0; $i < $numchars; ++$i) {
2446 if (($chardata[$i]['type'] == 'B') OR ($chardata[$i]['type'] == 'S')) {
2447 $chardata[$i]['level'] = $pel;
2448 } elseif ($chardata[$i]['type'] == 'WS') {
2449 $j = $i+1;
2450 while ($j < $numchars) {
2451 if ((($chardata[$j]['type'] == 'B') OR ($chardata[$j]['type'] == 'S')) OR
2452 (($j == ($numchars-1)) AND ($chardata[$j]['type'] == 'WS'))) {
2453 $chardata[$i]['level'] = $pel;
2454 break;
2455 } elseif ($chardata[$j]['type'] != 'WS') {
2456 break;
2457 }
2458 ++$j;
2459 }
2460 }
2461 }
2462
2463 // Arabic Shaping
2464 // Cursively connected scripts, such as Arabic or Syriac, require the selection of positional character shapes that depend on adjacent characters. Shaping is logically applied after the Bidirectional Algorithm is used and is limited to characters within the same directional run.
2465 if ($arabic) {
2466 $endedletter = array(1569,1570,1571,1572,1573,1575,1577,1583,1584,1585,1586,1608,1688);
2467 $alfletter = array(1570,1571,1573,1575);
2468 $chardata2 = $chardata;
2469 $laaletter = false;
2470 $charAL = array();
2471 $x = 0;
2472 for ($i=0; $i < $numchars; ++$i) {
2473 if ((TCPDF_FONT_DATA::$uni_type[$chardata[$i]['char']] == 'AL') OR ($chardata[$i]['char'] == 32) OR ($chardata[$i]['char'] == 8204)) {
2474 $charAL[$x] = $chardata[$i];
2475 $charAL[$x]['i'] = $i;
2476 $chardata[$i]['x'] = $x;
2477 ++$x;
2478 }
2479 }
2480 $numAL = $x;
2481 for ($i=0; $i < $numchars; ++$i) {
2482 $thischar = $chardata[$i];
2483 if ($i > 0) {
2484 $prevchar = $chardata[($i-1)];
2485 } else {
2486 $prevchar = false;
2487 }
2488 if (($i+1) < $numchars) {
2489 $nextchar = $chardata[($i+1)];
2490 } else {
2491 $nextchar = false;
2492 }
2493 if (TCPDF_FONT_DATA::$uni_type[$thischar['char']] == 'AL') {
2494 $x = $thischar['x'];
2495 if ($x > 0) {
2496 $prevchar = $charAL[($x-1)];
2497 } else {
2498 $prevchar = false;
2499 }
2500 if (($x+1) < $numAL) {
2501 $nextchar = $charAL[($x+1)];
2502 } else {
2503 $nextchar = false;
2504 }
2505 // if laa letter
2506 if (($prevchar !== false) AND ($prevchar['char'] == 1604) AND (in_array($thischar['char'], $alfletter))) {
2508 $laaletter = true;
2509 if ($x > 1) {
2510 $prevchar = $charAL[($x-2)];
2511 } else {
2512 $prevchar = false;
2513 }
2514 } else {
2516 $laaletter = false;
2517 }
2518 if (($prevchar !== false) AND ($nextchar !== false) AND
2519 ((TCPDF_FONT_DATA::$uni_type[$prevchar['char']] == 'AL') OR (TCPDF_FONT_DATA::$uni_type[$prevchar['char']] == 'NSM')) AND
2520 ((TCPDF_FONT_DATA::$uni_type[$nextchar['char']] == 'AL') OR (TCPDF_FONT_DATA::$uni_type[$nextchar['char']] == 'NSM')) AND
2521 ($prevchar['type'] == $thischar['type']) AND
2522 ($nextchar['type'] == $thischar['type']) AND
2523 ($nextchar['char'] != 1567)) {
2524 if (in_array($prevchar['char'], $endedletter)) {
2525 if (isset($arabicarr[$thischar['char']][2])) {
2526 // initial
2527 $chardata2[$i]['char'] = $arabicarr[$thischar['char']][2];
2528 }
2529 } else {
2530 if (isset($arabicarr[$thischar['char']][3])) {
2531 // medial
2532 $chardata2[$i]['char'] = $arabicarr[$thischar['char']][3];
2533 }
2534 }
2535 } elseif (($nextchar !== false) AND
2536 ((TCPDF_FONT_DATA::$uni_type[$nextchar['char']] == 'AL') OR (TCPDF_FONT_DATA::$uni_type[$nextchar['char']] == 'NSM')) AND
2537 ($nextchar['type'] == $thischar['type']) AND
2538 ($nextchar['char'] != 1567)) {
2539 if (isset($arabicarr[$chardata[$i]['char']][2])) {
2540 // initial
2541 $chardata2[$i]['char'] = $arabicarr[$thischar['char']][2];
2542 }
2543 } elseif ((($prevchar !== false) AND
2544 ((TCPDF_FONT_DATA::$uni_type[$prevchar['char']] == 'AL') OR (TCPDF_FONT_DATA::$uni_type[$prevchar['char']] == 'NSM')) AND
2545 ($prevchar['type'] == $thischar['type'])) OR
2546 (($nextchar !== false) AND ($nextchar['char'] == 1567))) {
2547 // final
2548 if (($i > 1) AND ($thischar['char'] == 1607) AND
2549 ($chardata[$i-1]['char'] == 1604) AND
2550 ($chardata[$i-2]['char'] == 1604)) {
2551 //Allah Word
2552 // mark characters to delete with false
2553 $chardata2[$i-2]['char'] = false;
2554 $chardata2[$i-1]['char'] = false;
2555 $chardata2[$i]['char'] = 65010;
2556 } else {
2557 if (($prevchar !== false) AND in_array($prevchar['char'], $endedletter)) {
2558 if (isset($arabicarr[$thischar['char']][0])) {
2559 // isolated
2560 $chardata2[$i]['char'] = $arabicarr[$thischar['char']][0];
2561 }
2562 } else {
2563 if (isset($arabicarr[$thischar['char']][1])) {
2564 // final
2565 $chardata2[$i]['char'] = $arabicarr[$thischar['char']][1];
2566 }
2567 }
2568 }
2569 } elseif (isset($arabicarr[$thischar['char']][0])) {
2570 // isolated
2571 $chardata2[$i]['char'] = $arabicarr[$thischar['char']][0];
2572 }
2573 // if laa letter
2574 if ($laaletter) {
2575 // mark characters to delete with false
2576 $chardata2[($charAL[($x-1)]['i'])]['char'] = false;
2577 }
2578 } // end if AL (Arabic Letter)
2579 } // end for each char
2580 /*
2581 * Combining characters that can occur with Arabic Shadda (0651 HEX, 1617 DEC) are replaced.
2582 * Putting the combining mark and shadda in the same glyph allows us to avoid the two marks overlapping each other in an illegible manner.
2583 */
2584 for ($i = 0; $i < ($numchars-1); ++$i) {
2585 if (($chardata2[$i]['char'] == 1617) AND (isset(TCPDF_FONT_DATA::$uni_diacritics[($chardata2[$i+1]['char'])]))) {
2586 // check if the subtitution font is defined on current font
2587 if (isset($currentfont['cw'][(TCPDF_FONT_DATA::$uni_diacritics[($chardata2[$i+1]['char'])])])) {
2588 $chardata2[$i]['char'] = false;
2589 $chardata2[$i+1]['char'] = TCPDF_FONT_DATA::$uni_diacritics[($chardata2[$i+1]['char'])];
2590 }
2591 }
2592 }
2593 // remove marked characters
2594 foreach ($chardata2 as $key => $value) {
2595 if ($value['char'] === false) {
2596 unset($chardata2[$key]);
2597 }
2598 }
2599 $chardata = array_values($chardata2);
2600 $numchars = count($chardata);
2601 unset($chardata2);
2602 unset($arabicarr);
2603 unset($laaletter);
2604 unset($charAL);
2605 }
2606
2607 // L2. From the highest level found in the text to the lowest odd level on each line, including intermediate levels not actually present in the text, reverse any contiguous sequence of characters that are at that level or higher.
2608 for ($j=$maxlevel; $j > 0; $j--) {
2609 $ordarray = Array();
2610 $revarr = Array();
2611 $onlevel = false;
2612 for ($i=0; $i < $numchars; ++$i) {
2613 if ($chardata[$i]['level'] >= $j) {
2614 $onlevel = true;
2615 if (isset(TCPDF_FONT_DATA::$uni_mirror[$chardata[$i]['char']])) {
2616 // L4. A character is depicted by a mirrored glyph if and only if (a) the resolved directionality of that character is R, and (b) the Bidi_Mirrored property value of that character is true.
2617 $chardata[$i]['char'] = TCPDF_FONT_DATA::$uni_mirror[$chardata[$i]['char']];
2618 }
2619 $revarr[] = $chardata[$i];
2620 } else {
2621 if ($onlevel) {
2622 $revarr = array_reverse($revarr);
2623 $ordarray = array_merge($ordarray, $revarr);
2624 $revarr = Array();
2625 $onlevel = false;
2626 }
2627 $ordarray[] = $chardata[$i];
2628 }
2629 }
2630 if ($onlevel) {
2631 $revarr = array_reverse($revarr);
2632 $ordarray = array_merge($ordarray, $revarr);
2633 }
2634 $chardata = $ordarray;
2635 }
2636 $ordarray = array();
2637 foreach ($chardata as $cd) {
2638 $ordarray[] = $cd['char'];
2639 // store char values for subsetting
2640 $currentfont['subsetchars'][$cd['char']] = true;
2641 }
2642 return $ordarray;
2643 }
static UTF8ArrSubString($strarr, $start='', $end='', $unicode=true)
Extract a slice of the $strarr array and return it as string.
Unicode data and encoding maps for TCPDF.
static $uni_LRO
Unicode code for Left-to-Right Override.
static $uni_type
Array of Unicode types.
static $uni_PDF
Unicode code for Pop Directional Format.
static $uni_diacritics
Array of character substitutions for sequences of two diacritics symbols.
static $uni_RLE
Unicode code for Right-to-Left Embedding.
static $uni_mirror
Mirror unicode characters.
static $uni_RLO
Unicode code for Right-to-Left Override.
static $uni_arabicsubst
Arabic shape substitutions: char code => (isolated, final, initial, medial).
static $uni_LRE
Unicode code for Left-to-Right Embedding.
static $uni_RE_PATTERN_ARABIC
Pattern to test Arabic strings using regular expressions.
static $uni_RE_PATTERN_RTL
Pattern to test RTL (Righ-To-Left) strings using regular expressions.
static $uni_laa_array
Arabic laa letter: (char code => isolated, final, initial, medial).
static empty_string($str)
Determine whether a string is empty.
$x
Definition: example_009.php:98

References TCPDF_FONT_DATA\$uni_arabicsubst, TCPDF_FONT_DATA\$uni_diacritics, TCPDF_FONT_DATA\$uni_laa_array, TCPDF_FONT_DATA\$uni_LRE, TCPDF_FONT_DATA\$uni_LRO, TCPDF_FONT_DATA\$uni_mirror, TCPDF_FONT_DATA\$uni_PDF, TCPDF_FONT_DATA\$uni_RE_PATTERN_ARABIC, TCPDF_FONT_DATA\$uni_RE_PATTERN_RTL, TCPDF_FONT_DATA\$uni_RLE, TCPDF_FONT_DATA\$uni_RLO, TCPDF_FONT_DATA\$uni_type, $x, and TCPDF_STATIC\empty_string().

Referenced by TCPDF\__construct(), TCPDF\_fixAES256Password(), TCPDF\getCellCode(), TCPDF\getNumLines(), TCPDF\GetStringWidth(), and TCPDF\Write().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ utf8StrArrRev()

static TCPDF_FONTS::utf8StrArrRev (   $arr,
  $str = '',
  $setbom = false,
  $forcertl = false,
  $isunicode = true,
$currentfont 
)
static

Reverse the RLT substrings array using the Bidirectional Algorithm (http://unicode.org/reports/tr9/).

Parameters
$arr(array) array of unicode values.
$str(string) string to manipulate (or empty value).
$setbom(bool) if true set the Byte Order Mark (BOM = 0xFEFF)
$forcertl(bool) if true forces RTL text direction
$isunicode(boolean) True if the document is in Unicode mode, false otherwise.
$currentfont(array) Reference to current font array.
Returns
string
Author
Nicola Asuni
Since
4.9.000 (2010-03-27) static

Definition at line 2072 of file tcpdf_fonts.php.

2072 {
2073 return self::arrUTF8ToUTF16BE(self::utf8Bidi($arr, $str, $forcertl, $isunicode, $currentfont), $setbom);
2074 }
static arrUTF8ToUTF16BE($unicode, $setbom=false)
Converts array of UTF-8 characters to UTF16-BE string.

◆ UTF8StringToArray()

static TCPDF_FONTS::UTF8StringToArray (   $str,
  $isunicode = true,
$currentfont 
)
static

Converts UTF-8 strings to codepoints array.


Invalid byte sequences will be replaced with 0xFFFD (replacement character)

Parameters
$str(string) string to process.
$isunicode(boolean) True when the documetn is in Unicode mode, false otherwise.
$currentfont(array) Reference to current font array.
Returns
array containing codepoints (UTF-8 characters values)
Author
Nicola Asuni static

Definition at line 1997 of file tcpdf_fonts.php.

1997 {
1998 if ($isunicode) {
1999 // requires PCRE unicode support turned on
2000 $chars = TCPDF_STATIC::pregSplit('//','u', $str, -1, PREG_SPLIT_NO_EMPTY);
2001 $carr = array_map(array('TCPDF_FONTS', 'uniord'), $chars);
2002 } else {
2003 $chars = str_split($str);
2004 $carr = array_map('ord', $chars);
2005 }
2006 $currentfont['subsetchars'] += array_fill_keys($carr, true);
2007 return $carr;
2008 }
static pregSplit($pattern, $modifiers, $subject, $limit=NULL, $flags=NULL)
Split string by a regular expression.

References TCPDF_STATIC\pregSplit().

Referenced by TCPDF\_fixAES256Password(), TCPDF\getCellCode(), TCPDF\GetNumChars(), TCPDF\getNumLines(), TCPDF\GetStringWidth(), TCPDF\hyphenateText(), TCPDF\hyphenateWord(), TCPDF\isCharDefined(), TCPDF\replaceMissingChars(), and TCPDF\Write().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ utf8StrRev()

static TCPDF_FONTS::utf8StrRev (   $str,
  $setbom = false,
  $forcertl = false,
  $isunicode = true,
$currentfont 
)
static

Reverse the RLT substrings using the Bidirectional Algorithm (http://unicode.org/reports/tr9/).

Parameters
$str(string) string to manipulate.
$setbom(bool) if true set the Byte Order Mark (BOM = 0xFEFF)
$forcertl(bool) if true forces RTL text direction
$isunicode(boolean) True if the document is in Unicode mode, false otherwise.
$currentfont(array) Reference to current font array.
Returns
string
Author
Nicola Asuni
Since
2.1.000 (2008-01-08) static

Definition at line 2055 of file tcpdf_fonts.php.

2055 {
2056 return self::utf8StrArrRev(self::UTF8StringToArray($str, $isunicode, $currentfont), $str, $setbom, $forcertl, $isunicode, $currentfont);
2057 }
static utf8StrArrRev($arr, $str='', $setbom=false, $forcertl=false, $isunicode=true, &$currentfont)
Reverse the RLT substrings array using the Bidirectional Algorithm (http://unicode....

Referenced by TCPDF\getInternalPageNumberAliases().

+ Here is the caller graph for this function:

◆ UTF8ToLatin1()

static TCPDF_FONTS::UTF8ToLatin1 (   $str,
  $isunicode = true,
$currentfont 
)
static

Converts UTF-8 strings to Latin1 when using the standard 14 core fonts.


Parameters
$str(string) string to process.
$isunicode(boolean) True when the documetn is in Unicode mode, false otherwise.
$currentfont(array) Reference to current font array.
Returns
string
Since
3.2.000 (2008-06-23) static

Definition at line 2019 of file tcpdf_fonts.php.

2019 {
2020 $unicode = self::UTF8StringToArray($str, $isunicode, $currentfont); // array containing UTF-8 unicode values
2021 return self::UTF8ArrToLatin1($unicode);
2022 }
static UTF8StringToArray($str, $isunicode=true, &$currentfont)
Converts UTF-8 strings to codepoints array.
static UTF8ArrToLatin1($unicode)
Converts UTF-8 characters array to array of Latin1 string

Referenced by TCPDF\getCellCode(), and TCPDF\getInternalPageNumberAliases().

+ Here is the caller graph for this function:

◆ UTF8ToUTF16BE()

static TCPDF_FONTS::UTF8ToUTF16BE (   $str,
  $setbom = false,
  $isunicode = true,
$currentfont 
)
static

Converts UTF-8 strings to UTF16-BE.


Parameters
$str(string) string to process.
$setbom(boolean) if true set the Byte Order Mark (BOM = 0xFEFF)
$isunicode(boolean) True when the documetn is in Unicode mode, false otherwise.
$currentfont(array) Reference to current font array.
Returns
string
Author
Nicola Asuni
Since
1.53.0.TC005 (2005-01-05) static

Definition at line 2035 of file tcpdf_fonts.php.

2035 {
2036 if (!$isunicode) {
2037 return $str; // string is not in unicode
2038 }
2039 $unicode = self::UTF8StringToArray($str, $isunicode, $currentfont); // array containing UTF-8 unicode values
2040 return self::arrUTF8ToUTF16BE($unicode, $setbom);
2041 }

Referenced by TCPDF\_putpages(), TCPDF\_textstring(), TCPDF\addHTMLTOC(), TCPDF\addTOC(), and TCPDF\replaceRightShiftPageNumAliases().

+ Here is the caller graph for this function:

Field Documentation

◆ $cache_uniord

TCPDF_FONTS::$cache_uniord = array()
staticprotected

Static cache used for speed up uniord performances.

Definition at line 54 of file tcpdf_fonts.php.


The documentation for this class was generated from the following file: