]>
git.immae.eu Git - github/wallabag/wallabag.git/blob - inc/3rdparty/libraries/mpdf/classes/ttfontsuni_analysis.php
3 require_once ( _MPDF_PATH
. 'classes/ttfontsuni.php' );
5 class TTFontFile_Analysis
EXTENDS TTFontFile
{
7 // Used to get font information from files in directory
8 function extractCoreInfo ( $file , $TTCfontID = 0 ) {
9 $this- > filename
= $file ;
10 $this- > fh
= fopen ( $file , 'rb' );
11 if (! $this- > fh
) { return ( 'ERROR - Can \' t open file ' . $file
); }
13 $this- > charWidths
= '' ;
14 $this- > glyphPos
= array ();
15 $this- > charToGlyph
= array ();
16 $this- > tables
= array ();
17 $this- > otables
= array ();
20 $this- > numTTCFonts
= 0 ;
21 $this- > TTCFonts
= array ();
22 $this- > version
= $version = $this- > read_ulong ();
23 $this- > panose
= array (); // mPDF 5.0
24 if ( $version == 0x4F54544F )
25 return ( "ERROR - NOT ADDED as Postscript outlines are not supported - " . $file );
26 if ( $version == 0x74746366 ) {
28 $this- > version
= $version = $this- > read_ulong (); // TTC Header version now
29 if (! in_array ( $version , array ( 0x00010000 , 0x00020000 )))
30 return ( "ERROR - NOT ADDED as Error parsing TrueType Collection: version=" . $version . " - " . $file );
32 else return ( "ERROR - Error parsing TrueType Collection - " . $file );
33 $this- > numTTCFonts
= $this- > read_ulong ();
34 for ( $i = 1 ; $i <= $this- > numTTCFonts
; $i ++
) {
35 $this- > TTCFonts
[ $i ][ 'offset' ] = $this- > read_ulong ();
37 $this- > seek ( $this- > TTCFonts
[ $TTCfontID ][ 'offset' ]);
38 $this- > version
= $version = $this- > read_ulong (); // TTFont version again now
39 $this- > readTableDirectory ( false );
42 if (! in_array ( $version , array ( 0x00010000 , 0x74727565 )))
43 return ( "ERROR - NOT ADDED as Not a TrueType font: version=" . $version . " - " . $file );
44 $this- > readTableDirectory ( false );
47 /* Included for testing...
48 $cmap_offset = $this->seek_table("cmap");
50 $cmapTableCount = $this->read_ushort();
51 $unicode_cmap_offset = 0;
52 for ($i=0;$i<$cmapTableCount;$i++) {
53 $x[$i]['platformId'] = $this->read_ushort();
54 $x[$i]['encodingId'] = $this->read_ushort();
55 $x[$i]['offset'] = $this->read_ulong();
56 $save_pos = $this->_pos;
57 $x[$i]['format'] = $this->get_ushort($cmap_offset + $x[$i]['offset'] );
58 $this->seek($save_pos );
62 ///////////////////////////////////
63 // name - Naming table
64 ///////////////////////////////////
66 /* Test purposes - displays table of names
67 $name_offset = $this->seek_table("name");
68 $format = $this->read_ushort();
69 if ($format != 0 && $format != 1) // mPDF 5.3.73
70 die("Unknown name table format ".$format);
71 $numRecords = $this->read_ushort();
72 $string_data_offset = $name_offset + $this->read_ushort();
73 for ($i=0;$i<$numRecords; $i++) {
74 $x[$i]['platformId'] = $this->read_ushort();
75 $x[$i]['encodingId'] = $this->read_ushort();
76 $x[$i]['languageId'] = $this->read_ushort();
77 $x[$i]['nameId'] = $this->read_ushort();
78 $x[$i]['length'] = $this->read_ushort();
79 $x[$i]['offset'] = $this->read_ushort();
82 if ($x[$i]['platformId'] == 1 && $x[$i]['encodingId'] == 0 && $x[$i]['languageId'] == 0) { // Roman
84 $N = $this->get_chunk($string_data_offset + $x[$i]['offset'] , $x[$i]['length'] );
90 $this->seek($string_data_offset + $x[$i]['offset'] );
91 $length = $x[$i]['length'] ;
94 // die("PostScript name is UTF-16BE string of odd length");
98 $char = $this->read_ushort();
105 $x[$i]['names'][$nameId] = $N;
110 $name_offset = $this- > seek_table ( "name" );
111 $format = $this- > read_ushort ();
112 if ( $format != 0 && $format != 1 ) // mPDF 5.3.73
113 return ( "ERROR - NOT ADDED as Unknown name table format " . $format . " - " . $file );
114 $numRecords = $this- > read_ushort ();
115 $string_data_offset = $name_offset +
$this- > read_ushort ();
116 $names = array ( 1 => '' , 2 => '' , 3 => '' , 4 => '' , 6 => '' );
117 $K = array_keys ( $names );
118 $nameCount = count ( $names );
119 for ( $i = 0 ; $i < $numRecords ; $i ++
) {
120 $platformId = $this- > read_ushort ();
121 $encodingId = $this- > read_ushort ();
122 $languageId = $this- > read_ushort ();
123 $nameId = $this- > read_ushort ();
124 $length = $this- > read_ushort ();
125 $offset = $this- > read_ushort ();
126 if (! in_array ( $nameId , $K )) continue ;
128 if ( $platformId == 3 && $encodingId == 1 && $languageId == 0x409 ) { // Microsoft, Unicode, US English, PS Name
130 $this- > seek ( $string_data_offset +
$offset );
131 if ( $length %
2 != 0 )
135 while ( $length > 0 ) {
136 $char = $this- > read_ushort ();
143 else if ( $platformId == 1 && $encodingId == 0 && $languageId == 0 ) { // Macintosh, Roman, English, PS Name
145 $N = $this- > get_chunk ( $string_data_offset +
$offset , $length );
149 if ( $N && $names [ $nameId ]== '' ) {
150 $names [ $nameId ] = $N ;
152 if ( $nameCount == 0 ) break ;
156 $psName = preg_replace ( '/ /' , '-' , $names [ 6 ]);
158 $psName = preg_replace ( '/ /' , '-' , $names [ 4 ]);
160 $psName = preg_replace ( '/ /' , '-' , $names [ 1 ]);
163 if (! $names [ 1 ] && ! $psName )
164 return ( "ERROR - NOT ADDED as Could not find valid font name - " . $file );
165 $this- > name
= $psName ;
166 if ( $names [ 1 ]) { $this
-> familyName
= $names
[ 1 ]; } else { $this
-> familyName
= $psName
; }
167 if ( $names [ 2 ]) { $this
-> styleName
= $names
[ 2 ]; } else { $this
-> styleName
= 'Regular' ; }
169 ///////////////////////////////////
170 // head - Font header table
171 ///////////////////////////////////
172 $this- > seek_table ( "head" );
173 $ver_maj = $this- > read_ushort ();
174 $ver_min = $this- > read_ushort ();
176 return ( 'ERROR - NOT ADDED as Unknown head table version ' . $ver_maj . '.' . $ver_min . " - " . $file );
177 $this- > fontRevision
= $this- > read_ushort () . $this- > read_ushort ();
179 $magic = $this- > read_ulong ();
180 if ( $magic != 0x5F0F3CF5 )
181 return ( 'ERROR - NOT ADDED as Invalid head table magic ' . $magic . " - " . $file );
183 $this- > unitsPerEm
= $unitsPerEm = $this- > read_ushort ();
184 $scale = 1000 / $unitsPerEm ;
186 $macStyle = $this- > read_short ();
188 $indexLocFormat = $this- > read_short ();
190 ///////////////////////////////////
191 // OS/2 - OS/2 and Windows metrics table
192 ///////////////////////////////////
196 if ( isset ( $this- > tables
[ "OS/2" ])) {
197 $this- > seek_table ( "OS/2" );
199 $sF = $this- > read_short ();
200 $sFamily = ( $sF >> 8 );
201 $this- > _pos +
= 10 ; //PANOSE = 10 byte length
202 $panose = fread ( $this- > fh
, 10 );
203 $this- > panose
= array ();
204 for ( $p = 0 ; $p < strlen ( $panose ); $p ++
) { $this
-> panose
[] = ord ( $panose
[ $p
]); }
206 $fsSelection = $this- > read_short ();
209 ///////////////////////////////////
210 // post - PostScript table
211 ///////////////////////////////////
212 $this- > seek_table ( "post" );
214 $this- > italicAngle
= $this- > read_short () +
$this- > read_ushort () / 65536.0 ;
216 $isFixedPitch = $this- > read_ulong ();
220 ///////////////////////////////////
221 // cmap - Character to glyph index mapping table
222 ///////////////////////////////////
223 $cmap_offset = $this- > seek_table ( "cmap" );
225 $cmapTableCount = $this- > read_ushort ();
226 $unicode_cmap_offset = 0 ;
227 for ( $i = 0 ; $i < $cmapTableCount ; $i ++
) {
228 $platformID = $this- > read_ushort ();
229 $encodingID = $this- > read_ushort ();
230 $offset = $this- > read_ulong ();
231 $save_pos = $this- > _pos
;
232 if (( $platformID == 3 && $encodingID == 1 ) || $platformID == 0 ) { // Microsoft, Unicode
233 $format = $this- > get_ushort ( $cmap_offset +
$offset );
235 if (! $unicode_cmap_offset ) $unicode_cmap_offset = $cmap_offset +
$offset ;
238 else if ((( $platformID == 3 && $encodingID == 10 ) || $platformID == 0 )) { // Microsoft, Unicode Format 12 table HKCS
239 $format = $this- > get_ushort ( $cmap_offset +
$offset );
241 $unicode_cmap_offset = $cmap_offset +
$offset ;
245 $this- > seek ( $save_pos );
248 if (! $unicode_cmap_offset )
249 return ( 'ERROR - Font (' . $this- > filename
. ') NOT ADDED as it is not Unicode encoded, and cannot be used by mPDF' );
258 $glyphToChar = array ();
260 // Format 12 CMAP does characters above Unicode BMP i.e. some HKCS characters U+20000 and above
262 $this- > seek ( $unicode_cmap_offset +
4 );
263 $length = $this- > read_ulong ();
264 $limit = $unicode_cmap_offset +
$length ;
266 $nGroups = $this- > read_ulong ();
267 for ( $i = 0 ; $i < $nGroups ; $i ++
) {
268 $startCharCode = $this- > read_ulong ();
269 $endCharCode = $this- > read_ulong ();
270 $startGlyphCode = $this- > read_ulong ();
271 if (( $endCharCode > 0x20000 && $endCharCode < 0x2A6DF ) || ( $endCharCode > 0x2F800 && $endCharCode < 0x2FA1F )) {
274 if ( $endCharCode > 0x10000 && $endCharCode < 0x1FFFF ) {
277 if (( $endCharCode > 0x0590 && $endCharCode < 0x077F ) || ( $endCharCode > 0xFE70 && $endCharCode < 0xFEFF ) || ( $endCharCode > 0xFB50 && $endCharCode < 0xFDFF )) {
280 if ( $endCharCode > 0x0900 && $endCharCode < 0x0DFF ) {
283 if ( $endCharCode > 0xE000 && $endCharCode < 0xF8FF ) {
285 if ( $endCharCode > 0xF500 && $endCharCode < 0xF7FF ) {
289 if (( $endCharCode > 0x2E80 && $endCharCode < 0x4DC0 ) || ( $endCharCode > 0x4E00 && $endCharCode < 0xA4CF ) || ( $endCharCode > 0xAC00 && $endCharCode < 0xD7AF ) || ( $endCharCode > 0xF900 && $endCharCode < 0xFAFF ) || ( $endCharCode > 0xFE30 && $endCharCode < 0xFE4F )) {
294 // Get each glyphToChar - only point if going to analyse un-mapped Arabic Glyphs
295 if ( isset ( $this- > tables
[ 'post' ])) {
296 for ( $unichar = $startCharCode ; $unichar <= $endCharCode ; $unichar ++
) {
297 $glyph = $startGlyphCode +
$offset ;
299 $glyphToChar [ $glyph ][] = $unichar ;
307 else { // Format 4 CMap
308 $this- > seek ( $unicode_cmap_offset +
2 );
309 $length = $this- > read_ushort ();
310 $limit = $unicode_cmap_offset +
$length ;
313 $segCount = $this- > read_ushort () / 2 ;
316 for ( $i = 0 ; $i < $segCount ; $i ++
) { $endCount
[] = $this
-> read_ushort (); }
318 $startCount = array ();
319 for ( $i = 0 ; $i < $segCount ; $i ++
) { $startCount
[] = $this
-> read_ushort (); }
321 for ( $i = 0 ; $i < $segCount ; $i ++
) { $idDelta
[] = $this
-> read_short (); }
322 $idRangeOffset_start = $this- > _pos
;
323 $idRangeOffset = array ();
324 for ( $i = 0 ; $i < $segCount ; $i ++
) { $idRangeOffset
[] = $this
-> read_ushort (); }
326 for ( $n = 0 ; $n < $segCount ; $n ++
) {
327 if (( $endCount [ $n ] > 0x0590 && $endCount [ $n ] < 0x077F ) || ( $endCount [ $n ] > 0xFE70 && $endCount [ $n ] < 0xFEFF ) || ( $endCount [ $n ] > 0xFB50 && $endCount [ $n ] < 0xFDFF )) {
330 if ( $endCount [ $n ] > 0x0900 && $endCount [ $n ] < 0x0DFF ) {
333 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 )) {
336 if ( $endCount [ $n ] > 0xE000 && $endCount [ $n ] < 0xF8FF ) {
338 if ( $endCount [ $n ] > 0xF500 && $endCount [ $n ] < 0xF7FF ) {
342 // Get each glyphToChar - only point if going to analyse un-mapped Arabic Glyphs
343 if ( isset ( $this- > tables
[ 'post' ])) {
344 $endpoint = ( $endCount [ $n ] +
1 );
345 for ( $unichar = $startCount [ $n ]; $unichar < $endpoint ; $unichar ++
) {
346 if ( $idRangeOffset [ $n ] == 0 )
347 $glyph = ( $unichar +
$idDelta [ $n ]) & 0xFFFF ;
349 $offset = ( $unichar - $startCount [ $n ]) * 2 +
$idRangeOffset [ $n ];
350 $offset = $idRangeOffset_start +
2 * $n +
$offset ;
351 if ( $offset >= $limit )
354 $glyph = $this- > get_ushort ( $offset );
356 $glyph = ( $glyph +
$idDelta [ $n ]) & 0xFFFF ;
359 $glyphToChar [ $glyph ][] = $unichar ;
365 // 'POST' table for un-mapped arabic glyphs
366 if ( isset ( $this- > tables
[ 'post' ])) {
367 $this- > seek_table ( "post" );
368 // Only works on Format 2.0
369 $formata = $this- > read_ushort ();
370 $formatb = $this- > read_ushort ();
371 if ( $formata == 2 && $formatb == 0 ) {
373 $nGlyfs = $this- > read_ushort ();
374 $glyphNameIndex = array ();
375 for ( $i = 0 ; $i < $nGlyfs ; $i ++
) {
376 $glyphNameIndex [( $this- > read_ushort ())] = $i ;
379 $opost = $this- > get_table ( 'post' );
380 $ptr = 34 +
( $nGlyfs * 2 );
381 for ( $i = 0 ; $i < $nGlyfs ; $i ++
) {
382 $len = ord ( substr ( $opost , $ptr , 1 ));
384 $name = substr ( $opost , $ptr , $len );
385 $gid = $glyphNameIndex [ $i +
258 ];
386 // Select uni0600.xxx(x) - uni06FF.xxx(x)
387 if ( preg_match ( '/^uni(06[0-9a-f] {2} )\.(fina|medi|init|fin|med|ini)$/i' , $name , $m )) {
388 if (! isset ( $glyphToChar [ $gid ]) || ( isset ( $glyphToChar [ $gid ]) && is_array ( $glyphToChar [ $gid ]) && count ( $glyphToChar [ $gid ])== 1 && $glyphToChar [ $gid ][ 0 ]> 57343 && $glyphToChar [ $gid ][ 0 ]< 63489 )) { // if set in PUA private use area E000-F8FF, or NOT Unicode mapped
389 $uni = hexdec ( $m [ 1 ]);
390 $form = strtoupper ( substr ( $m [ 2 ], 0 , 1 ));
391 // Assign new PUA Unicode between F500 - F7FF
393 if ( $form == 'I' ) { $bit +
= 0xF600 ; }
394 else if ( $form == 'M' ) { $bit +
= 0xF700 ; }
395 else { $bit +
= 0xF500 ; }
397 $name = 'uni' . strtoupper ( $m [ 1 ]). '.' . strtolower ( $m [ 2 ]);
398 $unAGlyphs .= ' : ' . $name ;
400 $unAGlyphs .= ' : ' . $unihexstr ;
401 $unAGlyphs .= ' : ' . $uni ;
402 $unAGlyphs .= ' : ' . $form ;
403 // if already set in PUA private use area E000-F8FF
404 if ( isset ( $glyphToChar [ $gid ]) && $glyphToChar [ $gid ][ 0 ]> 57343 && $glyphToChar [ $gid ][ 0 ]< 63489 ) {
405 $unAGlyphs .= ' : ' . $glyphToChar [ $gid ][ 0 ]. ' {'.dechex($glyphToChar[$gid][0]).'} ' ;
407 //else $unAGlyphs .= ':';
408 $unAGlyphs .= ' : ' . strtoupper ( dechex ( $bit ));
409 $unAGlyphs .= '<br />' ;
415 $unAGlyphs = 'GID:Name:Unicode base Hex:Dec:Form:PUA Unicode<br />' . $unAGlyphs ;
425 if ( $macStyle & ( 1 << 0 )) { $bold
= true ; } // bit 0 bold
426 else if ( $fsSelection & ( 1 << 5 )) { $bold
= true ; } // 5 BOLD Characters are emboldened
428 if ( $macStyle & ( 1 << 1 )) { $italic
= true ; } // bit 1 italic
429 else if ( $fsSelection & ( 1 << 0 )) { $italic
= true ; } // 0 ITALIC Font contains Italic characters, otherwise they are upright
430 else if ( $this- > italicAngle
<> 0 ) { $italic
= true ; }
432 if ( $isFixedPitch ) { $ftype
= 'mono' ; }
433 else if ( $sFamily > 0 && $sFamily < 8 ) { $ftype
= 'serif' ; }
434 else if ( $sFamily == 8 ) { $ftype
= 'sans' ; }
435 else if ( $sFamily == 10 ) { $ftype
= 'cursive' ; }
438 $bFamilyType = ord ( $panose [ 0 ]);
439 if ( $bFamilyType == 2 ) {
440 $bSerifStyle = ord ( $panose [ 1 ]);
442 if ( $bSerifStyle > 1 && $bSerifStyle < 11 ) { $ftype
= 'serif' ; }
443 else if ( $bSerifStyle > 10 ) { $ftype
= 'sans' ; }
445 $bProportion = ord ( $panose [ 3 ]);
446 if ( $bProportion == 9 || $bProportion == 1 ) { $ftype
= 'mono' ; } // ==1 i.e. No Fit needed for OCR-a and -b
448 else if ( $bFamilyType == 3 ) {
454 return array ( $this- > familyName
, $bold , $italic , $ftype , $TTCfontID , $rtl , $indic , $cjk , $sip , $smp , $puaag , $pua , $unAGlyphs );