ILIAS  release_5-0 Revision 5.0.0-1144-gc4397b1f870
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 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 updateCIDtoGIDmap ($map, $cid, $gid)
 Update the CIDToGIDMap string with a new value. More...
 
static _getfontpath ()
 Return fonts path. 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 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 getFontRefSize ($size, $refsize=12)
 Get a reference font size. 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 1677 of file tcpdf_fonts.php.

1677 {
1678 if (!defined('K_PATH_FONTS') AND is_dir($fdir = realpath(dirname(__FILE__).'/../fonts'))) {
1679 if (substr($fdir, -1) != '/') {
1680 $fdir .= '/';
1681 }
1682 define('K_PATH_FONTS', $fdir);
1683 }
1684 return defined('K_PATH_FONTS') ? K_PATH_FONTS : '';
1685 }

Referenced by TCPDF\_putfonts(), TCPDF\_puttruetypeunicode(), TCPDF\AddFont(), 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 937 of file tcpdf_fonts.php.

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

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 915 of file tcpdf_fonts.php.

915 {
916 $sum = 0;
917 $tlen = ($length / 4);
918 $offset = 0;
919 for ($i = 0; $i < $tlen; ++$i) {
920 $v = unpack('Ni', substr($table, $offset, 4));
921 $sum += $v['i'];
922 $offset += 4;
923 }
924 $sum = unpack('Ni', pack('N', $sum));
925 return $sum['i'];
926 }

◆ _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 1382 of file tcpdf_fonts.php.

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

◆ 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.
Author
Nicola Asuni
Since
5.9.123 (2010-09-30) static

Definition at line 66 of file tcpdf_fonts.php.

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

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

Referenced by TCPDF\addTTFfont().

+ Here is the call graph for this function:
+ Here is the caller 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 1564 of file tcpdf_fonts.php.

1564 {
1565 $outstr = ''; // string to be returned
1566 if ($setbom) {
1567 $outstr .= "\xFE\xFF"; // Byte Order Mark (BOM)
1568 }
1569 foreach ($unicode as $char) {
1570 if ($char == 0x200b) {
1571 // skip Unicode Character 'ZERO WIDTH SPACE' (DEC:8203, U+200B)
1572 } elseif ($char == 0xFFFD) {
1573 $outstr .= "\xFF\xFD"; // replacement character
1574 } elseif ($char < 0x10000) {
1575 $outstr .= chr($char >> 0x08);
1576 $outstr .= chr($char & 0xFF);
1577 } else {
1578 $char -= 0x10000;
1579 $w1 = 0xD800 | ($char >> 0x0a);
1580 $w2 = 0xDC00 | ($char & 0x3FF);
1581 $outstr .= chr($w1 >> 0x08);
1582 $outstr .= chr($w1 & 0xFF);
1583 $outstr .= chr($w2 >> 0x08);
1584 $outstr .= chr($w2 & 0xFF);
1585 }
1586 }
1587 return $outstr;
1588 }

Referenced by TCPDF\getCellCode().

+ 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 2494 of file tcpdf_fonts.php.

2494 {
2495 switch ($size) {
2496 case 'xx-small': {
2497 $size = ($refsize - 4);
2498 break;
2499 }
2500 case 'x-small': {
2501 $size = ($refsize - 3);
2502 break;
2503 }
2504 case 'small': {
2505 $size = ($refsize - 2);
2506 break;
2507 }
2508 case 'medium': {
2509 $size = $refsize;
2510 break;
2511 }
2512 case 'large': {
2513 $size = ($refsize + 2);
2514 break;
2515 }
2516 case 'x-large': {
2517 $size = ($refsize + 4);
2518 break;
2519 }
2520 case 'xx-large': {
2521 $size = ($refsize + 6);
2522 break;
2523 }
2524 case 'smaller': {
2525 $size = ($refsize - 3);
2526 break;
2527 }
2528 case 'larger': {
2529 $size = ($refsize + 3);
2530 break;
2531 }
2532 }
2533 return $size;
2534 }
$size
Definition: RandomTest.php:79

References $size.

Referenced by TCPDF\getHTMLFontUnits().

+ Here is the caller graph for this function:

◆ 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 1637 of file tcpdf_fonts.php.

1637 {
1638 if (strlen($start) == 0) {
1639 $start = 0;
1640 }
1641 if (strlen($end) == 0) {
1642 $end = count($uniarr);
1643 }
1644 $string = '';
1645 for ($i=$start; $i < $end; ++$i) {
1646 $string .= $uniarr[$i];
1647 }
1648 return $string;
1649 }

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 1486 of file tcpdf_fonts.php.

1486 {
1487 if (!$unicode) {
1488 return chr($c);
1489 } elseif ($c <= 0x7F) {
1490 // one byte
1491 return chr($c);
1492 } elseif ($c <= 0x7FF) {
1493 // two bytes
1494 return chr(0xC0 | $c >> 6).chr(0x80 | $c & 0x3F);
1495 } elseif ($c <= 0xFFFF) {
1496 // three bytes
1497 return chr(0xE0 | $c >> 12).chr(0x80 | $c >> 6 & 0x3F).chr(0x80 | $c & 0x3F);
1498 } elseif ($c <= 0x10FFFF) {
1499 // four bytes
1500 return chr(0xF0 | $c >> 18).chr(0x80 | $c >> 12 & 0x3F).chr(0x80 | $c >> 6 & 0x3F).chr(0x80 | $c & 0x3F);
1501 } else {
1502 return '';
1503 }
1504 }

Referenced by TCPDF\_fixAES256Password(), TCPDF\getCellCode(), TCPDF\getNumLines(), TCPDF\hyphenateWord(), TCPDF\putHtmlListBullet(), TCPDF\unichr(), 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 1522 of file tcpdf_fonts.php.

1522 {
1523 return self::unichr($c, false);
1524 }
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 1512 of file tcpdf_fonts.php.

1512 {
1513 return self::unichr($c, true);
1514 }

◆ uniord()

static TCPDF_FONTS::uniord (   $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 1770 of file tcpdf_fonts.php.

1770 {
1771 if (function_exists('mb_convert_encoding')) {
1772 list(, $char) = @unpack('N', mb_convert_encoding($uch, 'UCS-4BE', 'UTF-8'));
1773 if ($char >= 0) {
1774 return $char;
1775 }
1776 }
1777 $bytes = array(); // array containing single character byte sequences
1778 $countbytes = 0;
1779 $numbytes = 1; // number of octetc needed to represent the UTF-8 character
1780 $length = strlen($uch);
1781 for ($i = 0; $i < $length; ++$i) {
1782 $char = ord($uch[$i]); // get one string character at time
1783 if ($countbytes == 0) { // get starting octect
1784 if ($char <= 0x7F) {
1785 return $char; // use the character "as is" because is ASCII
1786 } elseif (($char >> 0x05) == 0x06) { // 2 bytes character (0x06 = 110 BIN)
1787 $bytes[] = ($char - 0xC0) << 0x06;
1788 ++$countbytes;
1789 $numbytes = 2;
1790 } elseif (($char >> 0x04) == 0x0E) { // 3 bytes character (0x0E = 1110 BIN)
1791 $bytes[] = ($char - 0xE0) << 0x0C;
1792 ++$countbytes;
1793 $numbytes = 3;
1794 } elseif (($char >> 0x03) == 0x1E) { // 4 bytes character (0x1E = 11110 BIN)
1795 $bytes[] = ($char - 0xF0) << 0x12;
1796 ++$countbytes;
1797 $numbytes = 4;
1798 } else {
1799 // use replacement character for other invalid sequences
1800 return 0xFFFD;
1801 }
1802 } elseif (($char >> 0x06) == 0x02) { // bytes 2, 3 and 4 must start with 0x02 = 10 BIN
1803 $bytes[] = $char - 0x80;
1804 ++$countbytes;
1805 if ($countbytes == $numbytes) {
1806 // compose UTF-8 bytes to a single unicode value
1807 $char = $bytes[0];
1808 for ($j = 1; $j < $numbytes; ++$j) {
1809 $char += ($bytes[$j] << (($numbytes - $j - 1) * 0x06));
1810 }
1811 if ((($char >= 0xD800) AND ($char <= 0xDFFF)) OR ($char >= 0x10FFFF)) {
1812 // The definition of UTF-8 prohibits encoding character numbers between
1813 // U+D800 and U+DFFF, which are reserved for use with the UTF-16
1814 // encoding form (as surrogate pairs) and do not directly represent
1815 // characters.
1816 return 0xFFFD; // use replacement character
1817 } else {
1818 return $char; // add char to array
1819 }
1820 }
1821 } else {
1822 // use replacement character for other invalid sequences
1823 return 0xFFFD;
1824 }
1825 }
1826 return 0xFFFD;
1827 }

◆ 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 1661 of file tcpdf_fonts.php.

1661 {
1662 if (($cid >= 0) AND ($cid <= 0xFFFF) AND ($gid >= 0)) {
1663 if ($gid > 0xFFFF) {
1664 $gid -= 0x10000;
1665 }
1666 $map[($cid * 2)] = chr($gid >> 8);
1667 $map[(($cid * 2) + 1)] = chr($gid & 0xFF);
1668 }
1669 return $map;
1670 }

◆ 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 1598 of file tcpdf_fonts.php.

1598 {
1599 if ($isunicode) {
1600 return array_map(array('self', 'unichrUnicode'), $ta);
1601 }
1602 return array_map(array('self', 'unichrASCII'), $ta);
1603 }

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 1614 of file tcpdf_fonts.php.

1614 {
1615 if (strlen($start) == 0) {
1616 $start = 0;
1617 }
1618 if (strlen($end) == 0) {
1619 $end = count($strarr);
1620 }
1621 $string = '';
1622 for ($i = $start; $i < $end; ++$i) {
1623 $string .= self::unichr($strarr[$i], $unicode);
1624 }
1625 return $string;
1626 }

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 1720 of file tcpdf_fonts.php.

1720 {
1721 $outstr = ''; // string to be returned
1722 foreach ($unicode as $char) {
1723 if ($char < 256) {
1724 $outstr .= chr($char);
1725 } elseif (array_key_exists($char, TCPDF_FONT_DATA::$uni_utf8tolatin)) {
1726 // map from UTF-8
1727 $outstr .= chr(TCPDF_FONT_DATA::$uni_utf8tolatin[$char]);
1728 } elseif ($char == 0xFFFD) {
1729 // skip
1730 } else {
1731 $outstr .= '?';
1732 }
1733 }
1734 return $outstr;
1735 }
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 1695 of file tcpdf_fonts.php.

1695 {
1696 $outarr = array(); // array to be returned
1697 foreach ($unicode as $char) {
1698 if ($char < 256) {
1699 $outarr[] = $char;
1700 } elseif (array_key_exists($char, TCPDF_FONT_DATA::$uni_utf8tolatin)) {
1701 // map from UTF-8
1702 $outarr[] = TCPDF_FONT_DATA::$uni_utf8tolatin[$char];
1703 } elseif ($char == 0xFFFD) {
1704 // skip
1705 } else {
1706 $outarr[] = 63; // '?' character
1707 }
1708 }
1709 return $outarr;
1710 }

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 1930 of file tcpdf_fonts.php.

1930 {
1931 // paragraph embedding level
1932 $pel = 0;
1933 // max level
1934 $maxlevel = 0;
1935 if (TCPDF_STATIC::empty_string($str)) {
1936 // create string from array
1937 $str = self::UTF8ArrSubString($ta, '', '', $isunicode);
1938 }
1939 // check if string contains arabic text
1940 if (preg_match(TCPDF_FONT_DATA::$uni_RE_PATTERN_ARABIC, $str)) {
1941 $arabic = true;
1942 } else {
1943 $arabic = false;
1944 }
1945 // check if string contains RTL text
1946 if (!($forcertl OR $arabic OR preg_match(TCPDF_FONT_DATA::$uni_RE_PATTERN_RTL, $str))) {
1947 return $ta;
1948 }
1949
1950 // get number of chars
1951 $numchars = count($ta);
1952
1953 if ($forcertl == 'R') {
1954 $pel = 1;
1955 } elseif ($forcertl == 'L') {
1956 $pel = 0;
1957 } else {
1958 // P2. In each paragraph, find the first character of type L, AL, or R.
1959 // 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.
1960 for ($i=0; $i < $numchars; ++$i) {
1961 $type = TCPDF_FONT_DATA::$uni_type[$ta[$i]];
1962 if ($type == 'L') {
1963 $pel = 0;
1964 break;
1965 } elseif (($type == 'AL') OR ($type == 'R')) {
1966 $pel = 1;
1967 break;
1968 }
1969 }
1970 }
1971
1972 // Current Embedding Level
1973 $cel = $pel;
1974 // directional override status
1975 $dos = 'N';
1976 $remember = array();
1977 // start-of-level-run
1978 $sor = $pel % 2 ? 'R' : 'L';
1979 $eor = $sor;
1980
1981 // Array of characters data
1982 $chardata = Array();
1983
1984 // 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.
1985 // In the resolution of levels in rules I1 and I2, the maximum embedding level of 62 can be reached.
1986 for ($i=0; $i < $numchars; ++$i) {
1987 if ($ta[$i] == TCPDF_FONT_DATA::$uni_RLE) {
1988 // X2. With each RLE, compute the least greater odd embedding level.
1989 // 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.
1990 // b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status.
1991 $next_level = $cel + ($cel % 2) + 1;
1992 if ($next_level < 62) {
1993 $remember[] = array('num' => TCPDF_FONT_DATA::$uni_RLE, 'cel' => $cel, 'dos' => $dos);
1994 $cel = $next_level;
1995 $dos = 'N';
1996 $sor = $eor;
1997 $eor = $cel % 2 ? 'R' : 'L';
1998 }
1999 } elseif ($ta[$i] == TCPDF_FONT_DATA::$uni_LRE) {
2000 // X3. With each LRE, compute the least greater even embedding level.
2001 // 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.
2002 // b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status.
2003 $next_level = $cel + 2 - ($cel % 2);
2004 if ( $next_level < 62 ) {
2005 $remember[] = array('num' => TCPDF_FONT_DATA::$uni_LRE, 'cel' => $cel, 'dos' => $dos);
2006 $cel = $next_level;
2007 $dos = 'N';
2008 $sor = $eor;
2009 $eor = $cel % 2 ? 'R' : 'L';
2010 }
2011 } elseif ($ta[$i] == TCPDF_FONT_DATA::$uni_RLO) {
2012 // X4. With each RLO, compute the least greater odd embedding level.
2013 // 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.
2014 // b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status.
2015 $next_level = $cel + ($cel % 2) + 1;
2016 if ($next_level < 62) {
2017 $remember[] = array('num' => TCPDF_FONT_DATA::$uni_RLO, 'cel' => $cel, 'dos' => $dos);
2018 $cel = $next_level;
2019 $dos = 'R';
2020 $sor = $eor;
2021 $eor = $cel % 2 ? 'R' : 'L';
2022 }
2023 } elseif ($ta[$i] == TCPDF_FONT_DATA::$uni_LRO) {
2024 // X5. With each LRO, compute the least greater even embedding level.
2025 // 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.
2026 // b. If the new level would not be valid, then this code is invalid. Do not change the current level or override status.
2027 $next_level = $cel + 2 - ($cel % 2);
2028 if ( $next_level < 62 ) {
2029 $remember[] = array('num' => TCPDF_FONT_DATA::$uni_LRO, 'cel' => $cel, 'dos' => $dos);
2030 $cel = $next_level;
2031 $dos = 'L';
2032 $sor = $eor;
2033 $eor = $cel % 2 ? 'R' : 'L';
2034 }
2035 } elseif ($ta[$i] == TCPDF_FONT_DATA::$uni_PDF) {
2036 // 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.
2037 if (count($remember)) {
2038 $last = count($remember ) - 1;
2039 if (($remember[$last]['num'] == TCPDF_FONT_DATA::$uni_RLE) OR
2040 ($remember[$last]['num'] == TCPDF_FONT_DATA::$uni_LRE) OR
2041 ($remember[$last]['num'] == TCPDF_FONT_DATA::$uni_RLO) OR
2042 ($remember[$last]['num'] == TCPDF_FONT_DATA::$uni_LRO)) {
2043 $match = array_pop($remember);
2044 $cel = $match['cel'];
2045 $dos = $match['dos'];
2046 $sor = $eor;
2047 $eor = ($cel > $match['cel'] ? $cel : $match['cel']) % 2 ? 'R' : 'L';
2048 }
2049 }
2050 } elseif (($ta[$i] != TCPDF_FONT_DATA::$uni_RLE) AND
2051 ($ta[$i] != TCPDF_FONT_DATA::$uni_LRE) AND
2052 ($ta[$i] != TCPDF_FONT_DATA::$uni_RLO) AND
2053 ($ta[$i] != TCPDF_FONT_DATA::$uni_LRO) AND
2054 ($ta[$i] != TCPDF_FONT_DATA::$uni_PDF)) {
2055 // X6. For all types besides RLE, LRE, RLO, LRO, and PDF:
2056 // a. Set the level of the current character to the current embedding level.
2057 // b. Whenever the directional override status is not neutral, reset the current character type to the directional override status.
2058 if ($dos != 'N') {
2059 $chardir = $dos;
2060 } else {
2061 if (isset(TCPDF_FONT_DATA::$uni_type[$ta[$i]])) {
2062 $chardir = TCPDF_FONT_DATA::$uni_type[$ta[$i]];
2063 } else {
2064 $chardir = 'L';
2065 }
2066 }
2067 // stores string characters and other information
2068 $chardata[] = array('char' => $ta[$i], 'level' => $cel, 'type' => $chardir, 'sor' => $sor, 'eor' => $eor);
2069 }
2070 } // end for each char
2071
2072 // X8. All explicit directional embeddings and overrides are completely terminated at the end of each paragraph. Paragraph separators are not included in the embedding.
2073 // X9. Remove all RLE, LRE, RLO, LRO, PDF, and BN codes.
2074 // 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.
2075
2076 // 3.3.3 Resolving Weak Types
2077 // 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.
2078 // Nonspacing marks are now resolved based on the previous characters.
2079 $numchars = count($chardata);
2080
2081 // 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.
2082 $prevlevel = -1; // track level changes
2083 $levcount = 0; // counts consecutive chars at the same level
2084 for ($i=0; $i < $numchars; ++$i) {
2085 if ($chardata[$i]['type'] == 'NSM') {
2086 if ($levcount) {
2087 $chardata[$i]['type'] = $chardata[$i]['sor'];
2088 } elseif ($i > 0) {
2089 $chardata[$i]['type'] = $chardata[($i-1)]['type'];
2090 }
2091 }
2092 if ($chardata[$i]['level'] != $prevlevel) {
2093 $levcount = 0;
2094 } else {
2095 ++$levcount;
2096 }
2097 $prevlevel = $chardata[$i]['level'];
2098 }
2099
2100 // 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.
2101 $prevlevel = -1;
2102 $levcount = 0;
2103 for ($i=0; $i < $numchars; ++$i) {
2104 if ($chardata[$i]['char'] == 'EN') {
2105 for ($j=$levcount; $j >= 0; $j--) {
2106 if ($chardata[$j]['type'] == 'AL') {
2107 $chardata[$i]['type'] = 'AN';
2108 } elseif (($chardata[$j]['type'] == 'L') OR ($chardata[$j]['type'] == 'R')) {
2109 break;
2110 }
2111 }
2112 }
2113 if ($chardata[$i]['level'] != $prevlevel) {
2114 $levcount = 0;
2115 } else {
2116 ++$levcount;
2117 }
2118 $prevlevel = $chardata[$i]['level'];
2119 }
2120
2121 // W3. Change all ALs to R.
2122 for ($i=0; $i < $numchars; ++$i) {
2123 if ($chardata[$i]['type'] == 'AL') {
2124 $chardata[$i]['type'] = 'R';
2125 }
2126 }
2127
2128 // 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.
2129 $prevlevel = -1;
2130 $levcount = 0;
2131 for ($i=0; $i < $numchars; ++$i) {
2132 if (($levcount > 0) AND (($i+1) < $numchars) AND ($chardata[($i+1)]['level'] == $prevlevel)) {
2133 if (($chardata[$i]['type'] == 'ES') AND ($chardata[($i-1)]['type'] == 'EN') AND ($chardata[($i+1)]['type'] == 'EN')) {
2134 $chardata[$i]['type'] = 'EN';
2135 } elseif (($chardata[$i]['type'] == 'CS') AND ($chardata[($i-1)]['type'] == 'EN') AND ($chardata[($i+1)]['type'] == 'EN')) {
2136 $chardata[$i]['type'] = 'EN';
2137 } elseif (($chardata[$i]['type'] == 'CS') AND ($chardata[($i-1)]['type'] == 'AN') AND ($chardata[($i+1)]['type'] == 'AN')) {
2138 $chardata[$i]['type'] = 'AN';
2139 }
2140 }
2141 if ($chardata[$i]['level'] != $prevlevel) {
2142 $levcount = 0;
2143 } else {
2144 ++$levcount;
2145 }
2146 $prevlevel = $chardata[$i]['level'];
2147 }
2148
2149 // W5. A sequence of European terminators adjacent to European numbers changes to all European numbers.
2150 $prevlevel = -1;
2151 $levcount = 0;
2152 for ($i=0; $i < $numchars; ++$i) {
2153 if ($chardata[$i]['type'] == 'ET') {
2154 if (($levcount > 0) AND ($chardata[($i-1)]['type'] == 'EN')) {
2155 $chardata[$i]['type'] = 'EN';
2156 } else {
2157 $j = $i+1;
2158 while (($j < $numchars) AND ($chardata[$j]['level'] == $prevlevel)) {
2159 if ($chardata[$j]['type'] == 'EN') {
2160 $chardata[$i]['type'] = 'EN';
2161 break;
2162 } elseif ($chardata[$j]['type'] != 'ET') {
2163 break;
2164 }
2165 ++$j;
2166 }
2167 }
2168 }
2169 if ($chardata[$i]['level'] != $prevlevel) {
2170 $levcount = 0;
2171 } else {
2172 ++$levcount;
2173 }
2174 $prevlevel = $chardata[$i]['level'];
2175 }
2176
2177 // W6. Otherwise, separators and terminators change to Other Neutral.
2178 $prevlevel = -1;
2179 $levcount = 0;
2180 for ($i=0; $i < $numchars; ++$i) {
2181 if (($chardata[$i]['type'] == 'ET') OR ($chardata[$i]['type'] == 'ES') OR ($chardata[$i]['type'] == 'CS')) {
2182 $chardata[$i]['type'] = 'ON';
2183 }
2184 if ($chardata[$i]['level'] != $prevlevel) {
2185 $levcount = 0;
2186 } else {
2187 ++$levcount;
2188 }
2189 $prevlevel = $chardata[$i]['level'];
2190 }
2191
2192 //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.
2193 $prevlevel = -1;
2194 $levcount = 0;
2195 for ($i=0; $i < $numchars; ++$i) {
2196 if ($chardata[$i]['char'] == 'EN') {
2197 for ($j=$levcount; $j >= 0; $j--) {
2198 if ($chardata[$j]['type'] == 'L') {
2199 $chardata[$i]['type'] = 'L';
2200 } elseif ($chardata[$j]['type'] == 'R') {
2201 break;
2202 }
2203 }
2204 }
2205 if ($chardata[$i]['level'] != $prevlevel) {
2206 $levcount = 0;
2207 } else {
2208 ++$levcount;
2209 }
2210 $prevlevel = $chardata[$i]['level'];
2211 }
2212
2213 // 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.
2214 $prevlevel = -1;
2215 $levcount = 0;
2216 for ($i=0; $i < $numchars; ++$i) {
2217 if (($levcount > 0) AND (($i+1) < $numchars) AND ($chardata[($i+1)]['level'] == $prevlevel)) {
2218 if (($chardata[$i]['type'] == 'N') AND ($chardata[($i-1)]['type'] == 'L') AND ($chardata[($i+1)]['type'] == 'L')) {
2219 $chardata[$i]['type'] = 'L';
2220 } elseif (($chardata[$i]['type'] == 'N') AND
2221 (($chardata[($i-1)]['type'] == 'R') OR ($chardata[($i-1)]['type'] == 'EN') OR ($chardata[($i-1)]['type'] == 'AN')) AND
2222 (($chardata[($i+1)]['type'] == 'R') OR ($chardata[($i+1)]['type'] == 'EN') OR ($chardata[($i+1)]['type'] == 'AN'))) {
2223 $chardata[$i]['type'] = 'R';
2224 } elseif ($chardata[$i]['type'] == 'N') {
2225 // N2. Any remaining neutrals take the embedding direction
2226 $chardata[$i]['type'] = $chardata[$i]['sor'];
2227 }
2228 } elseif (($levcount == 0) AND (($i+1) < $numchars) AND ($chardata[($i+1)]['level'] == $prevlevel)) {
2229 // first char
2230 if (($chardata[$i]['type'] == 'N') AND ($chardata[$i]['sor'] == 'L') AND ($chardata[($i+1)]['type'] == 'L')) {
2231 $chardata[$i]['type'] = 'L';
2232 } elseif (($chardata[$i]['type'] == 'N') AND
2233 (($chardata[$i]['sor'] == 'R') OR ($chardata[$i]['sor'] == 'EN') OR ($chardata[$i]['sor'] == 'AN')) AND
2234 (($chardata[($i+1)]['type'] == 'R') OR ($chardata[($i+1)]['type'] == 'EN') OR ($chardata[($i+1)]['type'] == 'AN'))) {
2235 $chardata[$i]['type'] = 'R';
2236 } elseif ($chardata[$i]['type'] == 'N') {
2237 // N2. Any remaining neutrals take the embedding direction
2238 $chardata[$i]['type'] = $chardata[$i]['sor'];
2239 }
2240 } elseif (($levcount > 0) AND ((($i+1) == $numchars) OR (($i+1) < $numchars) AND ($chardata[($i+1)]['level'] != $prevlevel))) {
2241 //last char
2242 if (($chardata[$i]['type'] == 'N') AND ($chardata[($i-1)]['type'] == 'L') AND ($chardata[$i]['eor'] == 'L')) {
2243 $chardata[$i]['type'] = 'L';
2244 } elseif (($chardata[$i]['type'] == 'N') AND
2245 (($chardata[($i-1)]['type'] == 'R') OR ($chardata[($i-1)]['type'] == 'EN') OR ($chardata[($i-1)]['type'] == 'AN')) AND
2246 (($chardata[$i]['eor'] == 'R') OR ($chardata[$i]['eor'] == 'EN') OR ($chardata[$i]['eor'] == 'AN'))) {
2247 $chardata[$i]['type'] = 'R';
2248 } elseif ($chardata[$i]['type'] == 'N') {
2249 // N2. Any remaining neutrals take the embedding direction
2250 $chardata[$i]['type'] = $chardata[$i]['sor'];
2251 }
2252 } elseif ($chardata[$i]['type'] == 'N') {
2253 // N2. Any remaining neutrals take the embedding direction
2254 $chardata[$i]['type'] = $chardata[$i]['sor'];
2255 }
2256 if ($chardata[$i]['level'] != $prevlevel) {
2257 $levcount = 0;
2258 } else {
2259 ++$levcount;
2260 }
2261 $prevlevel = $chardata[$i]['level'];
2262 }
2263
2264 // 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.
2265 // I2. For all characters with an odd (right-to-left) embedding direction, those of type L, EN or AN go up one level.
2266 for ($i=0; $i < $numchars; ++$i) {
2267 $odd = $chardata[$i]['level'] % 2;
2268 if ($odd) {
2269 if (($chardata[$i]['type'] == 'L') OR ($chardata[$i]['type'] == 'AN') OR ($chardata[$i]['type'] == 'EN')) {
2270 $chardata[$i]['level'] += 1;
2271 }
2272 } else {
2273 if ($chardata[$i]['type'] == 'R') {
2274 $chardata[$i]['level'] += 1;
2275 } elseif (($chardata[$i]['type'] == 'AN') OR ($chardata[$i]['type'] == 'EN')) {
2276 $chardata[$i]['level'] += 2;
2277 }
2278 }
2279 $maxlevel = max($chardata[$i]['level'],$maxlevel);
2280 }
2281
2282 // L1. On each line, reset the embedding level of the following characters to the paragraph embedding level:
2283 // 1. Segment separators,
2284 // 2. Paragraph separators,
2285 // 3. Any sequence of whitespace characters preceding a segment separator or paragraph separator, and
2286 // 4. Any sequence of white space characters at the end of the line.
2287 for ($i=0; $i < $numchars; ++$i) {
2288 if (($chardata[$i]['type'] == 'B') OR ($chardata[$i]['type'] == 'S')) {
2289 $chardata[$i]['level'] = $pel;
2290 } elseif ($chardata[$i]['type'] == 'WS') {
2291 $j = $i+1;
2292 while ($j < $numchars) {
2293 if ((($chardata[$j]['type'] == 'B') OR ($chardata[$j]['type'] == 'S')) OR
2294 (($j == ($numchars-1)) AND ($chardata[$j]['type'] == 'WS'))) {
2295 $chardata[$i]['level'] = $pel;
2296 break;
2297 } elseif ($chardata[$j]['type'] != 'WS') {
2298 break;
2299 }
2300 ++$j;
2301 }
2302 }
2303 }
2304
2305 // Arabic Shaping
2306 // 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.
2307 if ($arabic) {
2308 $endedletter = array(1569,1570,1571,1572,1573,1575,1577,1583,1584,1585,1586,1608,1688);
2309 $alfletter = array(1570,1571,1573,1575);
2310 $chardata2 = $chardata;
2311 $laaletter = false;
2312 $charAL = array();
2313 $x = 0;
2314 for ($i=0; $i < $numchars; ++$i) {
2315 if ((TCPDF_FONT_DATA::$uni_type[$chardata[$i]['char']] == 'AL') OR ($chardata[$i]['char'] == 32) OR ($chardata[$i]['char'] == 8204)) {
2316 $charAL[$x] = $chardata[$i];
2317 $charAL[$x]['i'] = $i;
2318 $chardata[$i]['x'] = $x;
2319 ++$x;
2320 }
2321 }
2322 $numAL = $x;
2323 for ($i=0; $i < $numchars; ++$i) {
2324 $thischar = $chardata[$i];
2325 if ($i > 0) {
2326 $prevchar = $chardata[($i-1)];
2327 } else {
2328 $prevchar = false;
2329 }
2330 if (($i+1) < $numchars) {
2331 $nextchar = $chardata[($i+1)];
2332 } else {
2333 $nextchar = false;
2334 }
2335 if (TCPDF_FONT_DATA::$uni_type[$thischar['char']] == 'AL') {
2336 $x = $thischar['x'];
2337 if ($x > 0) {
2338 $prevchar = $charAL[($x-1)];
2339 } else {
2340 $prevchar = false;
2341 }
2342 if (($x+1) < $numAL) {
2343 $nextchar = $charAL[($x+1)];
2344 } else {
2345 $nextchar = false;
2346 }
2347 // if laa letter
2348 if (($prevchar !== false) AND ($prevchar['char'] == 1604) AND (in_array($thischar['char'], $alfletter))) {
2350 $laaletter = true;
2351 if ($x > 1) {
2352 $prevchar = $charAL[($x-2)];
2353 } else {
2354 $prevchar = false;
2355 }
2356 } else {
2358 $laaletter = false;
2359 }
2360 if (($prevchar !== false) AND ($nextchar !== false) AND
2361 ((TCPDF_FONT_DATA::$uni_type[$prevchar['char']] == 'AL') OR (TCPDF_FONT_DATA::$uni_type[$prevchar['char']] == 'NSM')) AND
2362 ((TCPDF_FONT_DATA::$uni_type[$nextchar['char']] == 'AL') OR (TCPDF_FONT_DATA::$uni_type[$nextchar['char']] == 'NSM')) AND
2363 ($prevchar['type'] == $thischar['type']) AND
2364 ($nextchar['type'] == $thischar['type']) AND
2365 ($nextchar['char'] != 1567)) {
2366 if (in_array($prevchar['char'], $endedletter)) {
2367 if (isset($arabicarr[$thischar['char']][2])) {
2368 // initial
2369 $chardata2[$i]['char'] = $arabicarr[$thischar['char']][2];
2370 }
2371 } else {
2372 if (isset($arabicarr[$thischar['char']][3])) {
2373 // medial
2374 $chardata2[$i]['char'] = $arabicarr[$thischar['char']][3];
2375 }
2376 }
2377 } elseif (($nextchar !== false) AND
2378 ((TCPDF_FONT_DATA::$uni_type[$nextchar['char']] == 'AL') OR (TCPDF_FONT_DATA::$uni_type[$nextchar['char']] == 'NSM')) AND
2379 ($nextchar['type'] == $thischar['type']) AND
2380 ($nextchar['char'] != 1567)) {
2381 if (isset($arabicarr[$chardata[$i]['char']][2])) {
2382 // initial
2383 $chardata2[$i]['char'] = $arabicarr[$thischar['char']][2];
2384 }
2385 } elseif ((($prevchar !== false) AND
2386 ((TCPDF_FONT_DATA::$uni_type[$prevchar['char']] == 'AL') OR (TCPDF_FONT_DATA::$uni_type[$prevchar['char']] == 'NSM')) AND
2387 ($prevchar['type'] == $thischar['type'])) OR
2388 (($nextchar !== false) AND ($nextchar['char'] == 1567))) {
2389 // final
2390 if (($i > 1) AND ($thischar['char'] == 1607) AND
2391 ($chardata[$i-1]['char'] == 1604) AND
2392 ($chardata[$i-2]['char'] == 1604)) {
2393 //Allah Word
2394 // mark characters to delete with false
2395 $chardata2[$i-2]['char'] = false;
2396 $chardata2[$i-1]['char'] = false;
2397 $chardata2[$i]['char'] = 65010;
2398 } else {
2399 if (($prevchar !== false) AND in_array($prevchar['char'], $endedletter)) {
2400 if (isset($arabicarr[$thischar['char']][0])) {
2401 // isolated
2402 $chardata2[$i]['char'] = $arabicarr[$thischar['char']][0];
2403 }
2404 } else {
2405 if (isset($arabicarr[$thischar['char']][1])) {
2406 // final
2407 $chardata2[$i]['char'] = $arabicarr[$thischar['char']][1];
2408 }
2409 }
2410 }
2411 } elseif (isset($arabicarr[$thischar['char']][0])) {
2412 // isolated
2413 $chardata2[$i]['char'] = $arabicarr[$thischar['char']][0];
2414 }
2415 // if laa letter
2416 if ($laaletter) {
2417 // mark characters to delete with false
2418 $chardata2[($charAL[($x-1)]['i'])]['char'] = false;
2419 }
2420 } // end if AL (Arabic Letter)
2421 } // end for each char
2422 /*
2423 * Combining characters that can occur with Arabic Shadda (0651 HEX, 1617 DEC) are replaced.
2424 * Putting the combining mark and shadda in the same glyph allows us to avoid the two marks overlapping each other in an illegible manner.
2425 */
2426 for ($i = 0; $i < ($numchars-1); ++$i) {
2427 if (($chardata2[$i]['char'] == 1617) AND (isset(TCPDF_FONT_DATA::$uni_diacritics[($chardata2[$i+1]['char'])]))) {
2428 // check if the subtitution font is defined on current font
2429 if (isset($currentfont['cw'][(TCPDF_FONT_DATA::$uni_diacritics[($chardata2[$i+1]['char'])])])) {
2430 $chardata2[$i]['char'] = false;
2431 $chardata2[$i+1]['char'] = TCPDF_FONT_DATA::$uni_diacritics[($chardata2[$i+1]['char'])];
2432 }
2433 }
2434 }
2435 // remove marked characters
2436 foreach ($chardata2 as $key => $value) {
2437 if ($value['char'] === false) {
2438 unset($chardata2[$key]);
2439 }
2440 }
2441 $chardata = array_values($chardata2);
2442 $numchars = count($chardata);
2443 unset($chardata2);
2444 unset($arabicarr);
2445 unset($laaletter);
2446 unset($charAL);
2447 }
2448
2449 // 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.
2450 for ($j=$maxlevel; $j > 0; $j--) {
2451 $ordarray = Array();
2452 $revarr = Array();
2453 $onlevel = false;
2454 for ($i=0; $i < $numchars; ++$i) {
2455 if ($chardata[$i]['level'] >= $j) {
2456 $onlevel = true;
2457 if (isset(TCPDF_FONT_DATA::$uni_mirror[$chardata[$i]['char']])) {
2458 // 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.
2459 $chardata[$i]['char'] = TCPDF_FONT_DATA::$uni_mirror[$chardata[$i]['char']];
2460 }
2461 $revarr[] = $chardata[$i];
2462 } else {
2463 if ($onlevel) {
2464 $revarr = array_reverse($revarr);
2465 $ordarray = array_merge($ordarray, $revarr);
2466 $revarr = Array();
2467 $onlevel = false;
2468 }
2469 $ordarray[] = $chardata[$i];
2470 }
2471 }
2472 if ($onlevel) {
2473 $revarr = array_reverse($revarr);
2474 $ordarray = array_merge($ordarray, $revarr);
2475 }
2476 $chardata = $ordarray;
2477 }
2478 $ordarray = array();
2479 foreach ($chardata as $cd) {
2480 $ordarray[] = $cd['char'];
2481 // store char values for subsetting
2482 $currentfont['subsetchars'][$cd['char']] = true;
2483 }
2484 return $ordarray;
2485 }
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.

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, 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 1914 of file tcpdf_fonts.php.

1914 {
1915 return self::arrUTF8ToUTF16BE(self::utf8Bidi($arr, $str, $forcertl, $isunicode, $currentfont), $setbom);
1916 }
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 1839 of file tcpdf_fonts.php.

1839 {
1840 if ($isunicode) {
1841 // requires PCRE unicode support turned on
1842 $chars = preg_split("//u", $str, -1, PREG_SPLIT_NO_EMPTY);
1843 $carr = array_map(array('self', 'uniord'), $chars);
1844 } else {
1845 $chars = str_split($str);
1846 $carr = array_map('ord', $chars);
1847 }
1848 $currentfont['subsetchars'] += array_fill_keys($carr, true);
1849 return $carr;
1850 }

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 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 1897 of file tcpdf_fonts.php.

1897 {
1898 return self::utf8StrArrRev(self::UTF8StringToArray($str, $isunicode, $currentfont), $str, $setbom, $forcertl, $isunicode, $currentfont);
1899 }
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\_escapetext(), and 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 1861 of file tcpdf_fonts.php.

1861 {
1862 $unicode = self::UTF8StringToArray($str, $isunicode, $currentfont); // array containing UTF-8 unicode values
1863 return self::UTF8ArrToLatin1($unicode);
1864 }
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\_escapetext(), 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 1877 of file tcpdf_fonts.php.

1877 {
1878 if (!$isunicode) {
1879 return $str; // string is not in unicode
1880 }
1881 $unicode = self::UTF8StringToArray($str, $isunicode, $currentfont); // array containing UTF-8 unicode values
1882 return self::arrUTF8ToUTF16BE($unicode, $setbom);
1883 }

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

+ Here is the caller graph for this function:

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