PluginProbe
PDF & Print by BestWebSoft – WordPress Posts and Pages PDF Generator Plugin / 2.4.3
PDF & Print by BestWebSoft – WordPress Posts and Pages PDF Generator Plugin v2.4.3
trunk 1.5 1.6 1.7 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 1.8.1 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.1 All 71 releases
pdf-print / mpdf / classes / ttfontsuni_analysis.php

ttfontsuni_analysis.php in PDF & Print by BestWebSoft – WordPress Posts and Pages PDF Generator Plugin 2.4.3, at mpdf/classes/ttfontsuni_analysis.php

447 lines 14.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 require_once __DIR__ . '/../MpdfException.php';
4 require_once __DIR__ . '/ttfontsuni.php';
5
6 class TTFontFile_Analysis extends TTFontFile
7 {
8
9 // Used to get font information from files in directory
10 function extractCoreInfo($file, $TTCfontID = 0)
11 {
12 $this->filename = $file;
13 $this->fh = fopen($file, 'rb');
14 if (!$this->fh) {
15 return ('ERROR - Can\'t open file ' . $file);
16 }
17 $this->_pos = 0;
18 $this->charWidths = '';
19 $this->glyphPos = array();
20 $this->charToGlyph = array();
21 $this->tables = array();
22 $this->otables = array();
23 $this->ascent = 0;
24 $this->descent = 0;
25 $this->numTTCFonts = 0;
26 $this->TTCFonts = array();
27 $this->version = $version = $this->read_ulong();
28 $this->panose = array(); // mPDF 5.0
29
30 if ($version == 0x4F54544F) {
31 throw new MpdfException('ERROR - NOT ADDED as Postscript outlines are not supported - ' . $file);
32 }
33
34 if ($version == 0x74746366) {
35 if ($TTCfontID > 0) {
36 $this->version = $version = $this->read_ulong(); // TTC Header version now
37 if (!in_array($version, array(0x00010000, 0x00020000))) {
38 throw new MpdfException("ERROR - NOT ADDED as Error parsing TrueType Collection: version=" . $version . " - " . $file);
39 }
40 } else {
41 throw new MpdfException("ERROR - Error parsing TrueType Collection - " . $file);
42 }
43 $this->numTTCFonts = $this->read_ulong();
44 for ($i = 1; $i <= $this->numTTCFonts; $i++) {
45 $this->TTCFonts[$i]['offset'] = $this->read_ulong();
46 }
47 $this->seek($this->TTCFonts[$TTCfontID]['offset']);
48 $this->version = $version = $this->read_ulong(); // TTFont version again now
49 $this->readTableDirectory(false);
50 } else {
51 if (!in_array($version, array(0x00010000, 0x74727565))) {
52 throw new MpdfException("ERROR - NOT ADDED as Not a TrueType font: version=" . $version . " - " . $file);
53 }
54 $this->readTableDirectory(false);
55 }
56
57 /* Included for testing...
58 $cmap_offset = $this->seek_table("cmap");
59 $this->skip(2);
60 $cmapTableCount = $this->read_ushort();
61 $unicode_cmap_offset = 0;
62 for ($i=0;$i<$cmapTableCount;$i++) {
63 $x[$i]['platformId'] = $this->read_ushort();
64 $x[$i]['encodingId'] = $this->read_ushort();
65 $x[$i]['offset'] = $this->read_ulong();
66 $save_pos = $this->_pos;
67 $x[$i]['format'] = $this->get_ushort($cmap_offset + $x[$i]['offset'] );
68 $this->seek($save_pos );
69 }
70 print_r($x); exit;
71 */
72 ///////////////////////////////////
73 // name - Naming table
74 ///////////////////////////////////
75
76 /* Test purposes - displays table of names
77 $name_offset = $this->seek_table("name");
78 $format = $this->read_ushort();
79 if ($format != 0 && $format != 1) // mPDF 5.3.73
80 die("Unknown name table format ".$format);
81 $numRecords = $this->read_ushort();
82 $string_data_offset = $name_offset + $this->read_ushort();
83 for ($i=0;$i<$numRecords; $i++) {
84 $x[$i]['platformId'] = $this->read_ushort();
85 $x[$i]['encodingId'] = $this->read_ushort();
86 $x[$i]['languageId'] = $this->read_ushort();
87 $x[$i]['nameId'] = $this->read_ushort();
88 $x[$i]['length'] = $this->read_ushort();
89 $x[$i]['offset'] = $this->read_ushort();
90
91 $N = '';
92 if ($x[$i]['platformId'] == 1 && $x[$i]['encodingId'] == 0 && $x[$i]['languageId'] == 0) { // Roman
93 $opos = $this->_pos;
94 $N = $this->get_chunk($string_data_offset + $x[$i]['offset'] , $x[$i]['length'] );
95 $this->_pos = $opos;
96 $this->seek($opos);
97 }
98 else { // Unicode
99 $opos = $this->_pos;
100 $this->seek($string_data_offset + $x[$i]['offset'] );
101 $length = $x[$i]['length'] ;
102 if ($length % 2 != 0)
103 $length -= 1;
104 // die("PostScript name is UTF-16BE string of odd length");
105 $length /= 2;
106 $N = '';
107 while ($length > 0) {
108 $char = $this->read_ushort();
109 $N .= (chr($char));
110 $length -= 1;
111 }
112 $this->_pos = $opos;
113 $this->seek($opos);
114 }
115 $x[$i]['names'][$nameId] = $N;
116 }
117 print_r($x); exit;
118 */
119
120 $name_offset = $this->seek_table("name");
121 $format = $this->read_ushort();
122 if ($format != 0 && $format != 1) // mPDF 5.3.73
123 throw new MpdfException("ERROR - NOT ADDED as Unknown name table format " . $format . " - " . $file);
124 $numRecords = $this->read_ushort();
125 $string_data_offset = $name_offset + $this->read_ushort();
126 $names = array(1 => '', 2 => '', 3 => '', 4 => '', 6 => '');
127 $K = array_keys($names);
128 $nameCount = count($names);
129 for ($i = 0; $i < $numRecords; $i++) {
130 $platformId = $this->read_ushort();
131 $encodingId = $this->read_ushort();
132 $languageId = $this->read_ushort();
133 $nameId = $this->read_ushort();
134 $length = $this->read_ushort();
135 $offset = $this->read_ushort();
136 if (!in_array($nameId, $K))
137 continue;
138 $N = '';
139 if ($platformId == 3 && $encodingId == 1 && $languageId == 0x409) { // Microsoft, Unicode, US English, PS Name
140 $opos = $this->_pos;
141 $this->seek($string_data_offset + $offset);
142 if ($length % 2 != 0)
143 $length += 1;
144 $length /= 2;
145 $N = '';
146 while ($length > 0) {
147 $char = $this->read_ushort();
148 $N .= (chr($char));
149 $length -= 1;
150 }
151 $this->_pos = $opos;
152 $this->seek($opos);
153 } else if ($platformId == 1 && $encodingId == 0 && $languageId == 0) { // Macintosh, Roman, English, PS Name
154 $opos = $this->_pos;
155 $N = $this->get_chunk($string_data_offset + $offset, $length);
156 $this->_pos = $opos;
157 $this->seek($opos);
158 }
159 if ($N && $names[$nameId] == '') {
160 $names[$nameId] = $N;
161 $nameCount -= 1;
162 if ($nameCount == 0)
163 break;
164 }
165 }
166 if ($names[6])
167 $psName = preg_replace('/ /', '-', $names[6]);
168 else if ($names[4])
169 $psName = preg_replace('/ /', '-', $names[4]);
170 else if ($names[1])
171 $psName = preg_replace('/ /', '-', $names[1]);
172 else
173 $psName = '';
174 if (!$names[1] && !$psName)
175 throw new MpdfException("ERROR - NOT ADDED as Could not find valid font name - " . $file);
176 $this->name = $psName;
177 if ($names[1]) {
178 $this->familyName = $names[1];
179 } else {
180 $this->familyName = $psName;
181 }
182 if ($names[2]) {
183 $this->styleName = $names[2];
184 } else {
185 $this->styleName = 'Regular';
186 }
187
188 ///////////////////////////////////
189 // head - Font header table
190 ///////////////////////////////////
191 $this->seek_table("head");
192 $ver_maj = $this->read_ushort();
193 $ver_min = $this->read_ushort();
194 if ($ver_maj != 1)
195 throw new MpdfException('ERROR - NOT ADDED as Unknown head table version ' . $ver_maj . '.' . $ver_min . " - " . $file);
196 $this->fontRevision = $this->read_ushort() . $this->read_ushort();
197 $this->skip(4);
198 $magic = $this->read_ulong();
199 if ($magic != 0x5F0F3CF5)
200 throw new MpdfException('ERROR - NOT ADDED as Invalid head table magic ' . $magic . " - " . $file);
201 $this->skip(2);
202 $this->unitsPerEm = $unitsPerEm = $this->read_ushort();
203 $scale = 1000 / $unitsPerEm;
204 $this->skip(24);
205 $macStyle = $this->read_short();
206 $this->skip(4);
207 $indexLocFormat = $this->read_short();
208
209 ///////////////////////////////////
210 // OS/2 - OS/2 and Windows metrics table
211 ///////////////////////////////////
212 $sFamily = '';
213 $panose = '';
214 $fsSelection = '';
215 if (isset($this->tables["OS/2"])) {
216 $this->seek_table("OS/2");
217 $this->skip(30);
218 $sF = $this->read_short();
219 $sFamily = ($sF >> 8);
220 $this->_pos += 10; //PANOSE = 10 byte length
221 $panose = fread($this->fh, 10);
222 $this->panose = array();
223 for ($p = 0; $p < strlen($panose); $p++) {
224 $this->panose[] = ord($panose[$p]);
225 }
226 $this->skip(20);
227 $fsSelection = $this->read_short();
228 }
229
230 ///////////////////////////////////
231 // post - PostScript table
232 ///////////////////////////////////
233 $this->seek_table("post");
234 $this->skip(4);
235 $this->italicAngle = $this->read_short() + $this->read_ushort() / 65536.0;
236 $this->skip(4);
237 $isFixedPitch = $this->read_ulong();
238
239
240
241 ///////////////////////////////////
242 // cmap - Character to glyph index mapping table
243 ///////////////////////////////////
244 $cmap_offset = $this->seek_table("cmap");
245 $this->skip(2);
246 $cmapTableCount = $this->read_ushort();
247 $unicode_cmap_offset = 0;
248 for ($i = 0; $i < $cmapTableCount; $i++) {
249 $platformID = $this->read_ushort();
250 $encodingID = $this->read_ushort();
251 $offset = $this->read_ulong();
252 $save_pos = $this->_pos;
253 if (($platformID == 3 && $encodingID == 1) || $platformID == 0) { // Microsoft, Unicode
254 $format = $this->get_ushort($cmap_offset + $offset);
255 if ($format == 4) {
256 if (!$unicode_cmap_offset)
257 $unicode_cmap_offset = $cmap_offset + $offset;
258 }
259 }
260 else if ((($platformID == 3 && $encodingID == 10) || $platformID == 0)) { // Microsoft, Unicode Format 12 table HKCS
261 $format = $this->get_ushort($cmap_offset + $offset);
262 if ($format == 12) {
263 $unicode_cmap_offset = $cmap_offset + $offset;
264 break;
265 }
266 }
267 $this->seek($save_pos);
268 }
269
270 if (!$unicode_cmap_offset)
271 throw new MpdfException('ERROR - Font (' . $this->filename . ') NOT ADDED as it is not Unicode encoded, and cannot be used by mPDF');
272
273 $rtl = false;
274 $indic = false;
275 $cjk = false;
276 $sip = false;
277 $smp = false;
278 $pua = false;
279 $puaag = false;
280 $glyphToChar = array();
281 $unAGlyphs = '';
282 // Format 12 CMAP does characters above Unicode BMP i.e. some HKCS characters U+20000 and above
283 if ($format == 12) {
284 $this->seek($unicode_cmap_offset + 4);
285 $length = $this->read_ulong();
286 $limit = $unicode_cmap_offset + $length;
287 $this->skip(4);
288 $nGroups = $this->read_ulong();
289 for ($i = 0; $i < $nGroups; $i++) {
290 $startCharCode = $this->read_ulong();
291 $endCharCode = $this->read_ulong();
292 $startGlyphCode = $this->read_ulong();
293 if (($endCharCode > 0x20000 && $endCharCode < 0x2A6DF) || ($endCharCode > 0x2F800 && $endCharCode < 0x2FA1F)) {
294 $sip = true;
295 }
296 if ($endCharCode > 0x10000 && $endCharCode < 0x1FFFF) {
297 $smp = true;
298 }
299 if (($endCharCode > 0x0590 && $endCharCode < 0x077F) || ($endCharCode > 0xFE70 && $endCharCode < 0xFEFF) || ($endCharCode > 0xFB50 && $endCharCode < 0xFDFF)) {
300 $rtl = true;
301 }
302 if ($endCharCode > 0x0900 && $endCharCode < 0x0DFF) {
303 $indic = true;
304 }
305 if ($endCharCode > 0xE000 && $endCharCode < 0xF8FF) {
306 $pua = true;
307 if ($endCharCode > 0xF500 && $endCharCode < 0xF7FF) {
308 $puaag = true;
309 }
310 }
311 if (($endCharCode > 0x2E80 && $endCharCode < 0x4DC0) || ($endCharCode > 0x4E00 && $endCharCode < 0xA4CF) || ($endCharCode > 0xAC00 && $endCharCode < 0xD7AF) || ($endCharCode > 0xF900 && $endCharCode < 0xFAFF) || ($endCharCode > 0xFE30 && $endCharCode < 0xFE4F)) {
312 $cjk = true;
313 }
314
315 $offset = 0;
316 // Get each glyphToChar - only point if going to analyse un-mapped Arabic Glyphs
317 if (isset($this->tables['post'])) {
318 for ($unichar = $startCharCode; $unichar <= $endCharCode; $unichar++) {
319 $glyph = $startGlyphCode + $offset;
320 $offset++;
321 $glyphToChar[$glyph][] = $unichar;
322 }
323 }
324 }
325 } else { // Format 4 CMap
326 $this->seek($unicode_cmap_offset + 2);
327 $length = $this->read_ushort();
328 $limit = $unicode_cmap_offset + $length;
329 $this->skip(2);
330
331 $segCount = $this->read_ushort() / 2;
332 $this->skip(6);
333 $endCount = array();
334 for ($i = 0; $i < $segCount; $i++) {
335 $endCount[] = $this->read_ushort();
336 }
337 $this->skip(2);
338 $startCount = array();
339 for ($i = 0; $i < $segCount; $i++) {
340 $startCount[] = $this->read_ushort();
341 }
342 $idDelta = array();
343 for ($i = 0; $i < $segCount; $i++) {
344 $idDelta[] = $this->read_short();
345 }
346 $idRangeOffset_start = $this->_pos;
347 $idRangeOffset = array();
348 for ($i = 0; $i < $segCount; $i++) {
349 $idRangeOffset[] = $this->read_ushort();
350 }
351
352 for ($n = 0; $n < $segCount; $n++) {
353 if (($endCount[$n] > 0x0590 && $endCount[$n] < 0x077F) || ($endCount[$n] > 0xFE70 && $endCount[$n] < 0xFEFF) || ($endCount[$n] > 0xFB50 && $endCount[$n] < 0xFDFF)) {
354 $rtl = true;
355 }
356 if ($endCount[$n] > 0x0900 && $endCount[$n] < 0x0DFF) {
357 $indic = true;
358 }
359 if (($endCount[$n] > 0x2E80 && $endCount[$n] < 0x4DC0) || ($endCount[$n] > 0x4E00 && $endCount[$n] < 0xA4CF) || ($endCount[$n] > 0xAC00 && $endCount[$n] < 0xD7AF) || ($endCount[$n] > 0xF900 && $endCount[$n] < 0xFAFF) || ($endCount[$n] > 0xFE30 && $endCount[$n] < 0xFE4F)) {
360 $cjk = true;
361 }
362 if ($endCount[$n] > 0xE000 && $endCount[$n] < 0xF8FF) {
363 $pua = true;
364 if ($endCount[$n] > 0xF500 && $endCount[$n] < 0xF7FF) {
365 $puaag = true;
366 }
367 }
368 // Get each glyphToChar - only point if going to analyse un-mapped Arabic Glyphs
369 if (isset($this->tables['post'])) {
370 $endpoint = ($endCount[$n] + 1);
371 for ($unichar = $startCount[$n]; $unichar < $endpoint; $unichar++) {
372 if ($idRangeOffset[$n] == 0)
373 $glyph = ($unichar + $idDelta[$n]) & 0xFFFF;
374 else {
375 $offset = ($unichar - $startCount[$n]) * 2 + $idRangeOffset[$n];
376 $offset = $idRangeOffset_start + 2 * $n + $offset;
377 if ($offset >= $limit)
378 $glyph = 0;
379 else {
380 $glyph = $this->get_ushort($offset);
381 if ($glyph != 0)
382 $glyph = ($glyph + $idDelta[$n]) & 0xFFFF;
383 }
384 }
385 $glyphToChar[$glyph][] = $unichar;
386 }
387 }
388 }
389 }
390
391
392 $bold = false;
393 $italic = false;
394 $ftype = '';
395 if ($macStyle & (1 << 0)) {
396 $bold = true;
397 } // bit 0 bold
398 else if ($fsSelection & (1 << 5)) {
399 $bold = true;
400 } // 5 BOLD Characters are emboldened
401
402 if ($macStyle & (1 << 1)) {
403 $italic = true;
404 } // bit 1 italic
405 else if ($fsSelection & (1 << 0)) {
406 $italic = true;
407 } // 0 ITALIC Font contains Italic characters, otherwise they are upright
408 else if ($this->italicAngle <> 0) {
409 $italic = true;
410 }
411
412 if ($isFixedPitch) {
413 $ftype = 'mono';
414 } else if ($sFamily > 0 && $sFamily < 8) {
415 $ftype = 'serif';
416 } else if ($sFamily == 8) {
417 $ftype = 'sans';
418 } else if ($sFamily == 10) {
419 $ftype = 'cursive';
420 }
421 // Use PANOSE
422 if ($panose) {
423 $bFamilyType = ord($panose[0]);
424 if ($bFamilyType == 2) {
425 $bSerifStyle = ord($panose[1]);
426 if (!$ftype) {
427 if ($bSerifStyle > 1 && $bSerifStyle < 11) {
428 $ftype = 'serif';
429 } else if ($bSerifStyle > 10) {
430 $ftype = 'sans';
431 }
432 }
433 $bProportion = ord($panose[3]);
434 if ($bProportion == 9 || $bProportion == 1) {
435 $ftype = 'mono';
436 } // ==1 i.e. No Fit needed for OCR-a and -b
437 } else if ($bFamilyType == 3) {
438 $ftype = 'cursive';
439 }
440 }
441
442 fclose($this->fh);
443 return array($this->familyName, $bold, $italic, $ftype, $TTCfontID, $rtl, $indic, $cjk, $sip, $smp, $puaag, $pua, $unAGlyphs);
444 }
445
446 }
447