} else { if (strtolower(substr($f, -4, 4)) == '.ttf' || strtolower(substr($f, -4, 4)) == '.otf') { $ret[] = $ttf->extractCoreInfo($ttfdir . $f); } } for ($i = 0; $i < count($ret); $i++) { if (!is_array($ret[$i])) { if (!$pdf) { echo $ret[$i] . '<br />'; } } else { $tfname = $ret[$i][0]; $bold = $ret[$i][1]; $italic = $ret[$i][2]; $fname = strtolower($tfname); $fname = preg_replace_callback_callback('/[ ()]/', '', $fname); $tempfonttrans[$tfname] = $fname; $style = ''; if ($bold) { $style .= 'B'; } if ($italic) { $style .= 'I'; } if (!$style) { $style = 'R'; } $tempfontdata[$fname][$style] = $f; if ($isTTC) { $tempfontdata[$fname]['TTCfontID'][$style] = $ret[$i][4]; }
function substituteIndic($earr, $lang, $font) { global $voltdata; if (!isset($voltdata[$font])) { include_once _MPDF_PATH . 'includes/' . $font . '.volt.php'; $voltdata[$font] = $volt; } foreach ($earr as $eid => $char) { $earr[$eid] = sprintf("%04s", strtoupper(dechex($char))); } $vstr = "0020 " . implode(" ", $earr) . " 0020"; //============================ // Common Indic Punctuation marks // If NOT devanagari if ($lang != 'hi') { $vstr = str_replace('0964', '007C', $vstr); // U+0964 replace with "|" $vstr = str_replace('0965', '007C 007C', $vstr); // U+0964 replace with "|" } //============================ // Tamil numeral for Zero missing Added mPDF 4.2 if ($lang == 'ta') { $vstr = str_replace('0BE6', '0030', $vstr); // U+0BEB replace with "0" } //============================ // Re-order vowels // DEVANAGARI vowel sign matraI[093F] before consonant if ($lang == 'hi') { $prebasedvowels = "(093F)"; $nukta = "093C"; $halant = "094D"; $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $prebasedvowels . '/', '\\2 \\1', $vstr); // vowel sign pre-based shift left $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $prebasedvowels . ' ' . $nukta . '/', '\\2 \\1 ' . $nukta, $vstr); // before NUKTA $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $halant . ' ' . $prebasedvowels . '/', '\\2 \\1 ' . $halant, $vstr); // before CHAR HALANT == VIRAMA } else { if ($lang == 'bn') { // Khanda Ta 09CE not in font -> replace with 09A4|09CD $vstr = preg_replace_callback_callback('/09CE/', '09A4 09CD 200D', $vstr); // mPDF 5.3.09 // BENGALI double-part vowels [09CB 09C7 09BE][09CC 09C7 09D7] $vstr = str_replace('09CB', '09C7 09BE', $vstr); // convert to 2 parts $vstr = str_replace('09CC', '09C7 09D7', $vstr); // 09C7 pre-based is then shifted below $prebasedvowels = "(09BF|09C7|09C8)"; $nukta = "09BC"; $halant = "09CD"; // mPDF 5.0.044 $bnfullcons = "0995|0996|0997|0998|0999|099A|099B|099C|099D|099F|09A0|09A1|09A2|09A3|09A4|09A5|09A6|09A7|09A8|09AA|09AB|09AC|09AD|09AE|09AF|09B0|09B2|09B6|09B7|09B8|09B9|09DC|09DD|09DF"; $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $prebasedvowels . '/', '\\2 \\1', $vstr); // vowel sign pre-based shift left $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $prebasedvowels . ' ' . $nukta . '/', '\\2 \\1 ' . $nukta, $vstr); // before NUKTA $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $halant . ' ' . $prebasedvowels . '/', '\\2 \\1 ' . $halant, $vstr); // before CHAR HALANT // mPDF 5.0.044 // .. and shifting left-based vowel further to the left in case 3 consonants together. $vstr = preg_replace_callback_callback('/(' . $bnfullcons . ') ' . $halant . ' ' . $prebasedvowels . '/', '\\2 \\1 ' . $halant, $vstr); // mPDF 5.0.044 // If left-based vowel has now been shifted to left of RA/Halant (09B0/09CD) // Convert here to above-line form (E068) as it would get missed later // e.g. 09B0 09CD 09AD 09C7 would be changed above => // e.g. 09C7 09B0 09CD 09AD. The 09B0 09CD should => E068 // ??? need to add 09BF as well (09BF|09C7|09C8) $vstr = preg_replace_callback_callback('/(09C7|09C8) 09B0 09CD/', '\\1 E068', $vstr); } else { if ($lang == 'gu') { $prebasedvowels = "(0ABF)"; $nukta = "0ABC"; $halant = "0ACD"; $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $prebasedvowels . '/', '\\2 \\1', $vstr); // vowel sign pre-based shift left $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $prebasedvowels . ' ' . $nukta . '/', '\\2 \\1 ' . $nukta, $vstr); // before NUKTA $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $halant . ' ' . $prebasedvowels . '/', '\\2 \\1 ' . $halant, $vstr); // before CHAR HALANT } else { if ($lang == 'pa') { $prebasedvowels = "(0A3F)"; $nukta = "0A3C"; $halant = "0A4D"; $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $prebasedvowels . '/', '\\2 \\1', $vstr); // vowel sign pre-based shift left $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $prebasedvowels . ' ' . $nukta . '/', '\\2 \\1 ' . $nukta, $vstr); // before NUKTA $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $halant . ' ' . $prebasedvowels . '/', '\\2 \\1 ' . $halant, $vstr); // before CHAR HALANT } else { if ($lang == 'ta') { // Shrii (Shree) $vstr = preg_replace_callback_callback('/0BB6 0BCD 0BB0 0BC0/', 'E04B', $vstr); // TAMIL double-part vowels [0BCA 0BC6 0BBE][0BCB 0BC7 0BBE][0BCC 0BC6 0BD7] $vstr = preg_replace_callback_callback('/0BCA/', '0BC6 0BBE', $vstr); // convert to 2 parts $vstr = preg_replace_callback_callback('/0BCB/', '0BC7 0BBE', $vstr); // pre-based is then shifted below $vstr = preg_replace_callback_callback('/0BCC/', '0BC6 0BD7', $vstr); $prebasedvowels = "(0BC6|0BC7|0BC8)"; // No nukta $halant = "0BCD"; // Doesn't seem to move most in front of halanted consonants $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $prebasedvowels . '/', '\\2 \\1', $vstr); // vowel sign pre-based shift left // ? Only for special case KSS (already moved to left of 0BB7) $vstr = preg_replace_callback_callback('/0B95 ' . $halant . ' ' . $prebasedvowels . ' 0BB7/', '\\1 0B95 ' . $halant . ' 0BB7', $vstr); } else { if ($lang == 'or') { // ORIYA double-part vowels [] $vstr = str_replace('0B48', '0B47 0B56', $vstr); // 2-part Vowel $vstr = str_replace('0B4B', '0B47 0B3E', $vstr); // 2-part Vowel $vstr = str_replace('0B4C', '0B47 0B57', $vstr); // 2-part Vowel $orprebasedvowels = "(0B47)"; // No nukta $halant = "0B4D"; $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $orprebasedvowels . '/', '\\2 \\1', $vstr); // vowel sign pre-based shift left $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $halant . ' ' . $orprebasedvowels . '/', '\\2 \\1 ' . $halant, $vstr); // before CHAR HALANT $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $halant . ' ' . $orprebasedvowels . '/', '\\2 \\1 ' . $halant, $vstr); // before CHAR HALANT } else { if ($lang == 'ml') { // Chillus - old forms - remove ZWNJ after // This font Volt rules recognises e.g. "Na Halant(Virama)" as ChilluN $vstr = preg_replace_callback_callback('/(0D23 0D4D|0D28 0D4D|0D30 0D4D|0D32 0D4D|0D33 0D4D) 200D/', '\\1', $vstr); // See Chillus in Unicode [http://en.wikipedia.org/wiki/Malayalam_script] $vstr = str_replace('0D7A', '0D23 0D4D', $vstr); // [mlymChilluNn] $vstr = str_replace('0D7B', '0D28 0D4D', $vstr); // [mlymChilluN] $vstr = str_replace('0D7C', '0D30 0D4D', $vstr); // [mlymChilluR] $vstr = str_replace('0D7D', '0D32 0D4D', $vstr); // [mlymChilluL] $vstr = str_replace('0D7E', '0D33 0D4D', $vstr); // [mlymChilluLl] /* // Chillus - 0D7A-0D7E not in font directly, but as E005-E009 $vstr = preg_replace_callback_callback('/0D23 0D4D 200D/','0D7A', $vstr); $vstr = preg_replace_callback_callback('/0D28 0D4D 200D/','0D7B', $vstr); $vstr = preg_replace_callback_callback('/0D30 0D4D 200D/','0D7C', $vstr); $vstr = preg_replace_callback_callback('/0D32 0D4D 200D/','0D7D', $vstr); $vstr = preg_replace_callback_callback('/0D33 0D4D 200D/','0D7E', $vstr); $vstr = preg_replace_callback_callback('/0D7F/','E004', $vstr); // [mlymChilluK] $vstr = preg_replace_callback_callback('/0D7A/','E005', $vstr); // [mlymChilluNn] $vstr = preg_replace_callback_callback('/0D7B/','E006', $vstr); // [mlymChilluN] $vstr = preg_replace_callback_callback('/0D7C/','E007', $vstr); // [mlymChilluR] $vstr = preg_replace_callback_callback('/0D7D/','E008', $vstr); // [mlymChilluL] $vstr = preg_replace_callback_callback('/0D7E/','E009', $vstr); // [mlymChilluLl] */ // MALAYALAM double-part vowels [] $vstr = str_replace('0D4A', '0D46 0D3E', $vstr); // 2-part Vowel $vstr = str_replace('0D4B', '0D47 0D3E', $vstr); // 2-part Vowel $vstr = str_replace('0D4C', '0D46 0D57', $vstr); // 2-part Vowel $mlprebasedvowels = "(0D46|0D47|0D48)"; // No nukta $halant = "0D4D"; $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $mlprebasedvowels . '/', '\\2 \\1', $vstr); // vowel sign pre-based shift left $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $halant . ' ' . $mlprebasedvowels . '/', '\\2 \\1 ' . $halant, $vstr); // before CHAR HALANT } else { if ($lang == 'te') { // TELUGU double-part vowels [0C48 -> 0C46 0C56] $vstr = str_replace('0C48', '0C46 0C56', $vstr); // 2-part Vowel $prebasedvowels = "(0C46)"; $abvvowels = "(0C3E|0C3F|0C40|0C46|0C47|0C4A|0C4B|0C4C|0C55)"; // No nukta $halant = "0C4D"; $tefullforms = "0C15|0C17|0C18|0C1A|0C1B|0C1C|0C1D|0C20|0C21|0C22|0C24|0C25|0C26|0C27|0C28|0C2A|0C2B|0C2D|0C2E|0C2F|0C30|0C33|0C35|0C36|0C37|0C38|0C39|E028|E029|E02A|E02B|E078|E07A|E07B"; $vstr = preg_replace_callback_callback('/(' . $tefullforms . ') ' . $halant . ' (' . $tefullforms . ') ' . $abvvowels . '/', '\\1 \\3 ' . $halant . ' \\2', $vstr); // before HALANT } else { if ($lang == 'kn') { // KANNADA double-part vowels [0CC8 -> 0CC6 0CD6] $vstr = str_replace('0CC0', '0CBF 0CD5', $vstr); // 2-part Vowel $vstr = str_replace('0CC7', '0CC6 0CD5', $vstr); // 2-part Vowel $vstr = str_replace('0CC8', '0CC6 0CD6', $vstr); // 2-part Vowel AI - no glyph for single $vstr = str_replace('0CCA', '0CC6 0CC2', $vstr); // 2-part Vowel $vstr = str_replace('0CCB', '0CC6 0CC2 0CD5', $vstr); // 2-part Vowel $prebasedvowels = "(0CBF|0CC6)"; $halant = "0CCD"; } } } } } } } } } //============================ // SPECIALS // DEVANAGARI Ra Halant Ra if ($lang == 'hi') { $vstr = str_replace('0930 094D 0930', 'E05D 0930', $vstr); // Ra Halant Ra => halfRa FullRa } // GUJARATI if ($lang == 'gu') { $vstr = str_replace('0AB0 0AC2', 'E02E', $vstr); // Ra VowelUu => SpecialForm RaUu } // TELUGU Ra Halant <Consonant> Halant => halfRa Halant<Consonant> Halant if ($lang == 'te') { $vstr = preg_replace_callback_callback('/0C30 0C4D ([A-F0-9]{4}) 0C4D/', 'E021 0C4D \\1 0C4D', $vstr); } // KANNADA // Reph at end of word becomes E0CC instead of E00B if ($lang == 'kn') { $vstr = str_replace('0CB0 0CCD 0020', 'E0CC 0020', $vstr); // mPDF 5.3.87 } //============================ // MAIN BIT FROM VOLT RULES foreach ($voltdata[$font] as $rid => $reps) { //echo $rid . ': ' . $vstr.'<br />'; $vstr = preg_replace_callback_callback('/' . $reps['match'] . '/', $reps['replace'], $vstr); } //echo $vstr.'<br />'; exit; //============================ // SPECIALS // KANNADA // <Base> <BelowBase1> [<BelowBase2> ] MatraI -> <Base/MatraI ligature> <Belowbase1> etc if ($lang == 'kn') { $matraI = "0CBF"; $knbase = preg_split('/\\|/', "0C95|0C96|0C97|0C98|0C9A|0C9B|0C9C|0C9D|0CA0|0CA1|0CA2|0CA3|0CA4|0CA5|0CA6|0CA7|0CA8|0CAA|0CAB|0CAC|0CAD|0CAE|0CAF|0CB0|0CB2|0CB3|0CB5|0CB6|0CB7|0CB8|0CB9|E0A3|E07D|E07E"); $knmatraIligature = preg_split('/\\|/', "E082|E083|E084|E085|E086|E087|E088|E089|E08A|E08B|E08C|E08D|E08E|E08F|E090|E091|E092|E093|E094|E095|E096|E097|E098|E099|E09A|E09B|E09C|E09D|E09E|E09F|E0A0|E0A4|E0A1|E0A2"); $belowbase1 = "E02E|E02F|E030|E031|E032|E033|E034|E035|E036|E037|E038|E039|E03A|E03B|E03C|E03D|E03E|E03F|E040|E041|E042|E043|E044|E045|E046|E047|E048|E049|E04A|E04B|E04C|E04D|E04E|E04F|E050|E081"; $belowbase2 = "E052|E053|E054|E055|E056|E057|E058|E059|E05A|E05B|E05C|E05D|E05E|E05F|E060|E061|E062|E063|E064|E065|E066|E067|E068|E069|E06A|E06B|E06C|E06D|E06E|E06F|E070|E071|E072|E073|E074|E081"; for ($i = 0; $i < count($knbase); $i++) { $vstr = preg_replace_callback_callback('/' . $knbase[$i] . ' (' . $belowbase1 . ') (' . $belowbase2 . ') ' . $matraI . '/', $knmatraIligature[$i] . ' \\1 \\2', $vstr); $vstr = preg_replace_callback_callback('/' . $knbase[$i] . ' (' . $belowbase1 . ') ' . $matraI . '/', $knmatraIligature[$i] . ' \\1', $vstr); } } // KANNADA // [KanTtaFull] [matraI] => [KanTtaPartial] [matraI] if ($lang == 'kn') { $vstr = preg_replace_callback_callback('/0C9F ' . $matraI . '/', 'E015 ' . $matraI, $vstr); } // ORIYA if ($lang == 'or') { // SpecialCase Ra[0B30] Halant still left before [oryaFullNnNna] => E00F $vstr = preg_replace_callback_callback('/0B30 ' . $halant . ' E00F/', 'E00F E069', $vstr); // convert to Reph } //============================ // SHIFT REPH // DEVANAGARI Shift Reph [E015] if ($lang == 'hi') { // FIRSTLY - halfRa = E05D - Change this to Reph [E015] $himatchhalfforms = "E043|E044|E045|E046|E047|E048|E049|E04A|E04B|E04C|E04D|E04E|E04F|E050|E051|E052|E053|E054|E055|E056|E057|E058|E059|E05A|E05B|E05C|E05D|E05E|E05F|E060|E061|E062|E063|E064|E065|E066|E067|E068|E069|E06A|E06B|E06C|E06D|E06E|E06F|E070|E071|E072|E073|E074|E075|E076|E077|E078|E079|E07A|E07B|E07C|E07D|E07E|E07F|E080|E081|E082|E083|E084|E085|E086|E087|E088|E089|E08A|E0D3|E0D4|E0D5|E0D6|E0D7|E0D8|E0D9|E0DA|E0DB|E0DC|E0DD|E0DE|E0DF|E0E0|E0E1|E0E2|E0E3|E0E4|E0E5|E0E6|E0E7|E0E8|E0E9|E0EA|E0EB|E0EC|E0ED|E0EE|E0EF|E0F0|E0F1|E0F2|E0F3|E0F4|E0F5|E0F6|E0F7|E0F8|E0F9|E0FA|E0FB|E0FC|E0FD|E0FE|E0FF|E100|E101|E102|E103|E104|E105|E106|E107|E108|E109|E10A|E10B|E10C|E10D|E10E|E10F|E110|E111|E112|E113|E114|E115|E116|E117|E118|E119|E11A|E13D|E13E|E13F|E140|E141|E142|E143|E144|E145"; $himatchfullforms = "0915|0916|0917|0918|0919|091A|091B|091C|091D|091E|091F|0920|0921|0922|0923|0924|0925|0926|0927|0928|092A|092B|092C|092D|092E|092F|0930|0932|0933|0935|0936|0937|0938|0939|E028|E029|0958|0959|095A|E02A|E02B|E02C|E02D|095B|E02E|E02F|E030|E031|095C|095D|E032|E033|E034|E035|E036|0929|E037|095E|E038|E039|E03A|095F|0931|E03B|0934|E03C|E03D|E03E|E03F|E040|E041|E042|E08B|E08C|E08D|E08E|E08F|E090|E091|E092|E093|E094|E095|E096|E097|E098|E099|E09A|E09B|E09C|E09D|E09E|E09F|E0A0|E0A1|E0A2|E0A3|E0A4|E0A5|E0A6|E0A7|E0A8|E0A9|E0AA|E0AB|E0AC|E0AD|E0AE|E0AF|E0B0|E0B1|E0B2|E0B3|E0B4|E0B5|E0B6|E0B7|E0B8|E0B9|E0BA|E0BB|E0BC|E0BD|E0BE|E0BF|E0C0|E0C1|E0C2|E0C3|E0C4|E0C5|E0C6|E0C7|E0C8|E0C9|E0CA|E0CB|E0CC|E0CD|E0CE|E0CF|E0D0|E0D1|E0D2|E11E|E11F|E120|E121|E122|E123|E124|E125|E126|E127|E128|E129|E12A|E12B|E12C|E12D|E12E|E12F|E130|E131|E132|E133"; $vstr = preg_replace_callback_callback('/E05D (' . $himatchhalfforms . '|' . $himatchfullforms . ')/', 'E015 \\1', $vstr); // Reph = E015 - Shift Right to just after end of syllable // FullAllForms + HalfAllForms + 093E matraA while (preg_match('/E015 (' . $himatchhalfforms . ')/', $vstr)) { $vstr = preg_replace_callback_callback('/E015 (' . $himatchhalfforms . ')/', '\\1 E015', $vstr); } $vstr = preg_replace_callback_callback('/E015 (' . $himatchfullforms . ')/', '\\1 E015', $vstr); // Now shift it beyond post-based vowels // ??? Need to add others e.g. 0949,094A,094B,094C + presentation forms like E198 $vstr = str_replace('E015 093E', '093E E015', $vstr); $vstr = preg_replace_callback_callback('/E015 (0940|E194|E195|E196|E197|E198)/', '\\1 E014', $vstr); // (Small) reph [E014] to Right of matraI $vstr = str_replace('E015 0947', '0947 E014', $vstr); // (Small) reph [E014] to Right of matraI } else { if ($lang == 'bn') { $bnfullconjuncts = "E002|E003|E004|E041|E042|E043|E044|E045|E046|E047|E048|E049|E04A|E04B|E04C|E04D|E04E|E04F|E050|E051|E052|E053|E054|E055|E056|E057|E058|E059|E05A|E05B|E05C|E05D|E05E|E05F|E060|E061|E062|E063|E064|E065|E06A|E06B|E06C|E06D|E06E|E06F|E070|E071|E072|E073|E074|E075|E076|E077|E078|E079|E07A|E07B|E07C|E07D|E07E|E07F|E080|E081|E082|E083|E084|E085|E086|E087|E088|E089|E08A|E08B|E08C|E08D|E08E|E08F|E090|E091|E092|E093|E094|E095|E096|E097|E098|E099|E09A|E09B|E09C|E09D|E09E|E09F|E0A0|E0A1|E0A2|E0A3|E0A4|E0A5|E0A6|E0A7|E0A8|E0A9|E0AA|E0AB|E0AC|E0AD|E0AE|E0AF|E0B0|E0B1|E0B2|E0B3|E0B4|E0B5|E0B6|E0B7|E0B8|E0B9|E0BA|E0BB|E0BC|E0BD|E0BE|E0BF|E0C0|E0C1|E0C2|E0C3|E0C4|E0C5|E0C6|E0C7|E0C8|E0C9|E0CA|E0CB|E0CC|E0CD|E0CE|E0CF|E0D0|E0D1|E0D2|E0D3|E0D4|E0D5|E0D6|E0D7|E0D8|E0D9|E0DA|E0DB|E0DC|E0DD|E0DE|E0DF|E0E0|E0E1|E0E2|E0E3|E0E4|E0E5|E0E6|E0E7|E0E8|E0E9|E0EA|E0EB|E0EC|E0ED|E0EE|E0EF|E0F0|E0F1|E0F2|E0F3|E0F4|E0F5|E0F6|E0F7|E0F8|E0F9|E0FA|E0FB|E0FC|E0FD|E0FE|E0FF|E100|E101|E102|E103|E104|E105|E106|E107|E108|E109|E10A|E10B|E10C|E10D|E10E|E10F|E110|E111|E112|E113|E114|E115|E116|E117|E118|E119|E11A|E11B|E11C|E11D|E11E|E11F|E120|E121|E122|E123|E124|E125|E126|E127|E128|E129|E12A|E12B|E12C|E12D|E12E|E12F|E130|E131|E132|E133|E134|E135|E136|E137|E138|E139|E13A|E13B|E13C|E13D|E13E|E13F|E140|E141|E142|E143|E144|E145|E146|E147|E148|E149|E14A|E14B|E14C|E14D|E14E|E14F|E150|E151|E152|E153|E154|E155|E156|E157|E158|E159|E15A|E15B|E15C|E15D|E15E|E15F|E160|E161|E162|E163|E164|E165|E166|E167|E168|E169|E16A|E16B|E16C|E16D|E16E|E16F|E170|E171|E172|E173|E174|E175|E176|E177|E178|E179|E17A|E17B|E17C|E17D|E17E|E17F|E180|E181|E182|E183|E184|E185|E186|E187|E188|E189|E18A|E18B|E18C|E18D|E18E|E18F|E190|E191|E192|E193|E194|E195|E196|E197|E198|E199|E19A"; // $bnfullcons - set above; $vstr = preg_replace_callback_callback('/E068 (' . $bnfullconjuncts . '|' . $bnfullcons . ')/', '\\1 E068', $vstr); // ? Need to shift it beyond post-base vowels 09BE, 09C0, 09D7 haven't found so can't test?? $vstr = preg_replace_callback_callback('/E068 (09BE|09C0|09D7)/', '\\1 E068', $vstr); } else { if ($lang == 'gu') { $gufullforms = "0A95|0A96|0A97|0A98|0A99|0A9A|0A9B|0A9C|0A9D|0A9E|0A9F|0AA0|0AA1|0AA2|0AA3|0AA4|0AA5|0AA6|0AA7|0AA8|0AAA|0AAB|0AAC|0AAD|0AAE|0AAF|0AB0|0AB2|0AB3|0AB5|0AB6|0AB7|0AB8|0AB9|E002|E003|E004|E005|E006|E007|E008|E009|E00A|E00B|E00C|E00D|E00E|E00F|E010|E011|E012|E013|E014|E015|E016|E017|E018|E019|E01A|E01B|E01C|E01D|E01E|E01F|E020|E021|E022|E023|E024|E025|E026|E027|E05E|E05F|E060|E061|E062|E063|E064|E065|E066|E067|E068|E069|E06A|E06B|E06C|E06D|E06E|E06F|E070|E071|E072|E073|E074|E075|E076|E077|E078|E079|E07A|E07B|E07C|E07D|E07E|E07F|E080|E081|E082|E083|E084|E085|E086|E087|E088|E089|E08A|E08B|E08C|E08D|E08E|E08F|E090|E091|E092|E093|E094|E095|E096|E097|E098|E099|E09A|E09B|E09C|E09D|E09E|E09F|E0A0|E0A1|E0A2|E0A3|E0A4|E0A5"; $vstr = preg_replace_callback_callback('/E032 (' . $gufullforms . ')/', '\\1 E032', $vstr); // Now shift it beyond post-based vowels // ??? Need to add others e.g. 0949,094A,094B,094C + presentation forms like E198 // ? Need to shift it beyond post-base vowels 0ABE, 0AC0 haven't found so can't test?? $vstr = preg_replace_callback_callback('/E032 (0ABE|0AC0)/', '\\1 E032', $vstr); } else { if ($lang == 'te') { // tefullforms defined earlier $tepartialforms = "E00D|E00E|E00F|E010|E011|E012|E013|E014|E015|E016|E017|E018|E019|E01A|E01B|E01C|E01D|E01E|E01F|E020|E021|E022|E023|E024|E025|E026|E027|E07C|E07D|E07E"; $matraligs = "E07F|E080|E081|E082|E083|E084|E085|E086|E087|E088|E089|E08A|E08B|E08C|E08D|E08E|E08F|E090|E091|E092|E093|E094|E095|E096|E097|E098|E099|E09A|E09B|E09C|E09D|E09E|E09F|E0A0|E0A1|E0A2|E0A3|E0A4|E0A5|E0A6|E0A7|E0A8|E0A9|E0AA|E0AB|E0AC|E0AD|E0AE|E0AF"; $tevowels = "0C3E|0C3F|0C40|0C46|0C47|0C56|0C4A|0C4B|0C4C" . "|0C41|0C42|0C43|0C44"; // post matras $vstr = preg_replace_callback_callback('/(' . $tevowels . ') (E046|E069|E077)/', '\\2 \\1', $vstr); while (preg_match('/(' . $tepartialforms . ') (E046|E069|E077)/', $vstr)) { $vstr = preg_replace_callback_callback('/(' . $tepartialforms . ') (E046|E069|E077)/', '\\2 \\1', $vstr); } $vstr = preg_replace_callback_callback('/(' . $tefullforms . '|' . $matraligs . ') (E046|E069|E077)/', '\\2 \\1', $vstr); } else { if ($lang == 'kn') { $knfullforms = "0C95|0C96|0C97|0C98|0C99|0C9A|0C9B|0C9C|0C9D|0C9E|0C9F|0CA0|0CA1|0CA2|0CA3|0CA4|0CA5|0CA6|0CA7|0CA8|0CAA|0CAB|0CAC|0CAD|0CAE|0CAF|0CB0|0CB1|0CB2|0CB3|0CB5|0CB6|0CB7|0CB8|0CB9|E07D|E07E|E0A3"; $knpartialforms = "E00C|E00D|E00E|E00F|E010|E011|E012|E013|E014|0C9E|E015|E016|E017|E018|E019|E01A|E01B|E01C|E01D|E01E|E01F|E020|E021|E022|E023|E024|E025|E026|E027|E028|E029|E02A|E02B|E02C|E02D|E07F"; while (preg_match('/E00B (' . $knpartialforms . ')/', $vstr)) { $vstr = preg_replace_callback_callback('/E00B (' . $knpartialforms . ')/', '\\1 E00B', $vstr); } // mPDF 5.3.47 Also move Reph to right of matraIligatures $knfullforms .= "|E082|E083|E084|E085|E086|E087|E088|E089|E08A|E08B|E08C|E08D|E08E|E08F|E090|E091|E092|E093|E094|E095|E096|E097|E098|E099|E09A|E09B|E09C|E09D|E09E|E09F|E0A0|E0A4|E0A1|E0A2"; $vstr = preg_replace_callback_callback('/E00B (' . $knfullforms . ')/', '\\1 E00B', $vstr); // ? Need to shift it beyond base or below-base forms - haven't found so can't test?? // mPDF 5.3.87 // E004 added to list (which is a transformed version of 0CBE) $knvowels = "0CBE|0CC0|0CC1|0CC2|0CC3|0CC4|0CC7|0CC8|0CCA|0CCB|0CD5|0CD6|E004"; $vstr = preg_replace_callback_callback('/E00B (' . $knvowels . ')/', '\\1 E00B', $vstr); } else { if ($lang == 'or') { $orrephs = "E069|E06A|E06B|E06C"; $orfullforms = "0B15|0B16|0B17|0B18|0B19|0B1A|0B1B|0B1C|0B1D|0B1E|0B1F|0B20|0B21|0B22|0B23|0B24|0B25|0B26|0B27|0B28|0B29|0B2A|0B2B|0B2C|0B2D|0B2E|0B2F|0B30|0B31|0B32|0B33|0B34|0B35|0B36|0B37|0B38|E003|E004|E005|E006|E007|E008|E009|E00A|E00B|E00C|E00D|E00E|E00F|E010|E011|E012|E013|E014|E015|E016|E017|E018|E019|E01A|E01B|E01C|E01D|E01E|E01F|E020|E021|E022|E023|E024|E025|E026|E027|E028|E029|E02A|E02B|E02C|E02D|E02E|E02F|E030|E031|E032|E033|E034|E035|E036|E037"; // E123 - E147 FullHalant forms ? add to FullForms $orpartialforms = "E090|E091|E092|E093|E094|E095|E096|E097|E098|E099|E09A|E09B|E09C|E09D|E09E|E09F|E0A0|E0A1|E0A2|E0A3|E0A4|E0A5|E0A6|E0A7|E0A8|E0A9|E0AA|E0AB|E0AC|E0AD|E0AE|E0AF|E0B0|E0B1|E0B2|E0B3|E0B4|E0B5|E0B6|E0B7|E0B8|E0B9|E0BA|E0BB|E0BC|E0BD|E0BE|E0BF|E0C0|E0C1|E0C2|E0C3|E0C4|E0C5|E0C6|E0C7|E0C8|E0C9|E0CA|E0CB|E0CC|E0CD|E0CE|E0CF|E0D0|E0D1|E0D2|E0D3|E0D4|E0D5|E0D6|E0D7|E0D8|E0D9|E0DA|E0DB|E0DC|E0DD|E0DE|E0DF|E0E0|E0E1|E0E2|E0E3|E0E4|E0E5|E0E6|E0E7|E0E8|E0E9|E0EA|E0EB|E0EC|E0ED|E0EE|E0EF|E0F0|E0F1|E0F2|E0F3|E0F4|E0F5"; // Combined MatraIReph[E06D] split [0B3F & E069] to allow reph to be shifted forwards $vstr = preg_replace_callback_callback('/(' . $orfullforms . ') E06D (' . $orfullforms . ') 0B3E/', '\\1 0B3F E069 \\2 0B3E', $vstr); while (preg_match('/(' . $orrephs . ') (' . $orpartialforms . ')/', $vstr)) { $vstr = preg_replace_callback_callback('/(' . $orrephs . ') (' . $orpartialforms . ')/', '\\2 \\1', $vstr); } $vstr = preg_replace_callback_callback('/(' . $orrephs . ') (' . $orfullforms . ')/', '\\2 \\1', $vstr); // Combine Reph and MatraI $vstr = str_replace('E069 0B3F', 'E06D', $vstr); // Reph and MatraI -> MatraIReph $vstr = str_replace('E06A 0B3F', 'E06E', $vstr); // Reph and MatraI -> MatraIReph $vstr = str_replace('E06B 0B3F', 'E06F', $vstr); // Reph and MatraI -> MatraIReph } else { if ($lang == 'ml') { $halant = "0D4D"; $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $halant . ' 0D30/', 'E00E \\1', $vstr); // 0D30 = Ra $vstr = preg_replace_callback_callback('/([A-F0-9]{4}) ' . $halant . ' ' . $mlprebasedvowels . ' 0D30/', '\\2 E00E \\1', $vstr); // 0D30 = Ra $mlfullforms = "0D15|0D16|0D17|0D18|0D19|0D1A|0D1B|0D1C|0D1D|0D1E|0D1F|0D20|0D21|0D22|0D23|0D24|0D25|0D26|0D27|0D28|0D2A|0D2B|0D2C|0D2D|0D2E|0D2F|0D30|0D31|0D32|0D33|0D34|0D35|0D36|0D37|0D38|0D39" . "|E010|E011|E012|E013|E014|E015|E016|E017|E018|E019|E01A|E01B|E01C|E01D|E01E|E01F|E020|E021|E022|E023|E024|E025|E026|E027|E028|E029|E02A|E02B|E02C|E02D|E02E|E02F|E030|E031|E032|E033|E034|E035|E036|E037|E038|E039|E03A|E03B|E03C|E03D|E03E|E03F|E040|E041|E042|E043|E044|E045|E046|E047|E048|E049|E04A|E04B|E04C|E04D|E04E|E04F|E050|E051|E052|E053|E054|E055|E056|E057|E058|E059|E05A|E05B|E05C|E05D|E05E|E05F|E060|E061|E062|E063|E064|E065|E066|E067|E068|E069|E06A|E06B|E06C|E06D|E06E|E06F|E070|E071|E072|E073|E074|E075|E076|E077|E078|E079|E07A|E07B|E07C|E07D"; // = FullConsonants + FullConjuncts // = Add Chillu characters // mPDF 5.0.024 $mlfullforms .= "|E004|E005|E006|E007|E008|E009"; while (preg_match('/(' . $mlfullforms . ') E00E/', $vstr)) { $vstr = preg_replace_callback_callback('/(' . $mlfullforms . ') E00E/', 'E00E \\1', $vstr); } } } } } } } } //============================ // SHIFT post-based vowels to Left of SmallForms (NOT to left of full forms) // TELUGU Shift if ($lang == 'te') { // NB $tevowels defined above // NB $tefullforms defined above $tebelowbase1 = "E02C|E02D|E02E|E02F|E030|E031|E032|E033|E034|E035|E036|E037|E038|E039|E03A|E03B|E03C|E03D|E03E|E03F|E040|E041|E042|E043|E044|E045|E046|E047|E048|E049|E04A|E04B|E04C|E04D|E04E"; //'Small1KaToHa' $tebelowbase2 = "E04F|E050|E051|E052|E053|E054|E055|E056|E057|E058|E059|E05A|E05B|E05C|E05D|E05E|E05F|E060|E061|E062|E063|E064|E065|E066|E067|E068|E069|E06A|E06B|E06C|E06D|E06E|E06F|E070|E071"; // 'Small2KaToHa' $vstr = preg_replace_callback_callback('/(' . $tebelowbase2 . ') (' . $tevowels . ')/', '\\2 \\1', $vstr); $vstr = preg_replace_callback_callback('/(' . $tebelowbase1 . ') (' . $tevowels . ')/', '\\2 \\1', $vstr); } else { if ($lang == 'kn') { $knvowels = "0CBE|0CC0|0CC1|0CC2|0CC3|0CC4|0CC7|0CC8|0CCA|0CCB|0CD5|0CD6" . "|E004|E007|E008|E009|E00A"; // NB $knvowels defined above // NB $fullforms defined above // $belowbase1/2 defined above $vstr = preg_replace_callback_callback('/(' . $belowbase2 . ') (' . $knvowels . ')/', '\\2 \\1', $vstr); // mPDF 5.3.87 $vstr = preg_replace_callback_callback('/(' . $belowbase1 . ') (' . $knvowels . ')/', '\\2 \\1', $vstr); //$vstr = preg_replace_callback_callback('/('.$fullforms.') ('.$knvowels.')/', '\\2 \\1', $vstr); } } //============================ // Clear unwanted ZWJ, ZWNJ // MALAYALAM if ($lang == 'ml') { $vstr = preg_replace_callback_callback('/(200C|200D) /', '', $vstr); } //============================ // END & PUT IT BACK TOGETHER $vstr = preg_replace_callback_callback('/^0020 (.*) 0020$/', '\\1', $vstr); $varr = explode(" ", $vstr); $e = ''; foreach ($varr as $v) { $e .= code2utf(hexdec($v)); } //============================ return $e; }
if ($_REQUEST['filename']) { $filename = $_REQUEST['filename']; } else { die("No file specified"); } include "../mpdf.php"; $mpdf = new mPDF('utf-8-s'); $mpdf->debug = true; $mpdf->tabSpaces = 6; $mpdf->allow_charset_conversion = true; $mpdf->charset_in = 'windows-1252'; //============================================================== preg_match('/example[0]{0,1}(\\d+)_(.*?)\\.php/', $filename, $m); $num = intval($m[1]); $title = ucfirst(preg_replace_callback_callback('/_/', ' ', $m[2])); if (!$num || !$title) { die("Invalid file"); } if (preg_match('/\\//', $filename) || !preg_match('/\\.php$/', $filename)) { die("Hacking attempt"); } $html = ' <h1>mPDF</h1> <h2>Example ' . $num . '. ' . $title . '</h2> <div style="border:1px solid #555555; background-color: #DDDDDD; padding: 1em; font-size:8pt; font-family: lucidaconsole, mono;"> '; $lines = file($filename); $html .= '<pre>'; foreach ($lines as $line) { $html .= htmlspecialchars($line);
function extractCoreInfo($file, $TTCfontID = 0) { $this->filename = $file; $this->fh = fopen($file, 'rb'); if (!$this->fh) { return 'ERROR - Can\'t open file ' . $file; } $this->_pos = 0; $this->charWidths = ''; $this->glyphPos = array(); $this->charToGlyph = array(); $this->tables = array(); $this->otables = array(); $this->ascent = 0; $this->descent = 0; $this->numTTCFonts = 0; $this->TTCFonts = array(); $this->version = $version = $this->read_ulong(); $this->panose = array(); // mPDF 5.0 if ($version == 0x4f54544f) { return "ERROR - NOT ADDED as Postscript outlines are not supported - " . $file; } if ($version == 0x74746366) { if ($TTCfontID > 0) { $this->version = $version = $this->read_ulong(); // TTC Header version now if (!in_array($version, array(0x10000, 0x20000))) { return "ERROR - NOT ADDED as Error parsing TrueType Collection: version=" . $version . " - " . $file; } } else { return "ERROR - Error parsing TrueType Collection - " . $file; } $this->numTTCFonts = $this->read_ulong(); for ($i = 1; $i <= $this->numTTCFonts; $i++) { $this->TTCFonts[$i]['offset'] = $this->read_ulong(); } $this->seek($this->TTCFonts[$TTCfontID]['offset']); $this->version = $version = $this->read_ulong(); // TTFont version again now $this->readTableDirectory(false); } else { if (!in_array($version, array(0x10000, 0x74727565))) { return "ERROR - NOT ADDED as Not a TrueType font: version=" . $version . " - " . $file; } $this->readTableDirectory(false); } /* Included for testing... $cmap_offset = $this->seek_table("cmap"); $this->skip(2); $cmapTableCount = $this->read_ushort(); $unicode_cmap_offset = 0; for ($i=0;$i<$cmapTableCount;$i++) { $x[$i]['platformId'] = $this->read_ushort(); $x[$i]['encodingId'] = $this->read_ushort(); $x[$i]['offset'] = $this->read_ulong(); $save_pos = $this->_pos; $x[$i]['format'] = $this->get_ushort($cmap_offset + $x[$i]['offset'] ); $this->seek($save_pos ); } print_r($x); exit; */ /////////////////////////////////// // name - Naming table /////////////////////////////////// /* Test purposes - displays table of names $name_offset = $this->seek_table("name"); $format = $this->read_ushort(); if ($format != 0 && $format != 1) // mPDF 5.3.73 die("Unknown name table format ".$format); $numRecords = $this->read_ushort(); $string_data_offset = $name_offset + $this->read_ushort(); for ($i=0;$i<$numRecords; $i++) { $x[$i]['platformId'] = $this->read_ushort(); $x[$i]['encodingId'] = $this->read_ushort(); $x[$i]['languageId'] = $this->read_ushort(); $x[$i]['nameId'] = $this->read_ushort(); $x[$i]['length'] = $this->read_ushort(); $x[$i]['offset'] = $this->read_ushort(); $N = ''; if ($x[$i]['platformId'] == 1 && $x[$i]['encodingId'] == 0 && $x[$i]['languageId'] == 0) { // Roman $opos = $this->_pos; $N = $this->get_chunk($string_data_offset + $x[$i]['offset'] , $x[$i]['length'] ); $this->_pos = $opos; $this->seek($opos); } else { // Unicode $opos = $this->_pos; $this->seek($string_data_offset + $x[$i]['offset'] ); $length = $x[$i]['length'] ; if ($length % 2 != 0) $length -= 1; // die("PostScript name is UTF-16BE string of odd length"); $length /= 2; $N = ''; while ($length > 0) { $char = $this->read_ushort(); $N .= (chr($char)); $length -= 1; } $this->_pos = $opos; $this->seek($opos); } $x[$i]['names'][$nameId] = $N; } print_r($x); exit; */ $name_offset = $this->seek_table("name"); $format = $this->read_ushort(); if ($format != 0 && $format != 1) { // mPDF 5.3.73 return "ERROR - NOT ADDED as Unknown name table format " . $format . " - " . $file; } $numRecords = $this->read_ushort(); $string_data_offset = $name_offset + $this->read_ushort(); $names = array(1 => '', 2 => '', 3 => '', 4 => '', 6 => ''); $K = array_keys($names); $nameCount = count($names); for ($i = 0; $i < $numRecords; $i++) { $platformId = $this->read_ushort(); $encodingId = $this->read_ushort(); $languageId = $this->read_ushort(); $nameId = $this->read_ushort(); $length = $this->read_ushort(); $offset = $this->read_ushort(); if (!in_array($nameId, $K)) { continue; } $N = ''; if ($platformId == 3 && $encodingId == 1 && $languageId == 0x409) { // Microsoft, Unicode, US English, PS Name $opos = $this->_pos; $this->seek($string_data_offset + $offset); if ($length % 2 != 0) { $length += 1; } $length /= 2; $N = ''; while ($length > 0) { $char = $this->read_ushort(); $N .= chr($char); $length -= 1; } $this->_pos = $opos; $this->seek($opos); } else { if ($platformId == 1 && $encodingId == 0 && $languageId == 0) { // Macintosh, Roman, English, PS Name $opos = $this->_pos; $N = $this->get_chunk($string_data_offset + $offset, $length); $this->_pos = $opos; $this->seek($opos); } } if ($N && $names[$nameId] == '') { $names[$nameId] = $N; $nameCount -= 1; if ($nameCount == 0) { break; } } } if ($names[6]) { $psName = preg_replace_callback_callback('/ /', '-', $names[6]); } else { if ($names[4]) { $psName = preg_replace_callback_callback('/ /', '-', $names[4]); } else { if ($names[1]) { $psName = preg_replace_callback_callback('/ /', '-', $names[1]); } else { $psName = ''; } } } if (!$names[1] && !$psName) { return "ERROR - NOT ADDED as Could not find valid font name - " . $file; } $this->name = $psName; if ($names[1]) { $this->familyName = $names[1]; } else { $this->familyName = $psName; } if ($names[2]) { $this->styleName = $names[2]; } else { $this->styleName = 'Regular'; } /////////////////////////////////// // head - Font header table /////////////////////////////////// $this->seek_table("head"); $ver_maj = $this->read_ushort(); $ver_min = $this->read_ushort(); if ($ver_maj != 1) { return 'ERROR - NOT ADDED as Unknown head table version ' . $ver_maj . '.' . $ver_min . " - " . $file; } $this->fontRevision = $this->read_ushort() . $this->read_ushort(); $this->skip(4); $magic = $this->read_ulong(); if ($magic != 0x5f0f3cf5) { return 'ERROR - NOT ADDED as Invalid head table magic ' . $magic . " - " . $file; } $this->skip(2); $this->unitsPerEm = $unitsPerEm = $this->read_ushort(); $scale = 1000 / $unitsPerEm; $this->skip(24); $macStyle = $this->read_short(); $this->skip(4); $indexLocFormat = $this->read_short(); /////////////////////////////////// // OS/2 - OS/2 and Windows metrics table /////////////////////////////////// $sFamily = ''; $panose = ''; $fsSelection = ''; if (isset($this->tables["OS/2"])) { $this->seek_table("OS/2"); $this->skip(30); $sF = $this->read_short(); $sFamily = $sF >> 8; $this->_pos += 10; //PANOSE = 10 byte length $panose = fread($this->fh, 10); $this->panose = array(); for ($p = 0; $p < strlen($panose); $p++) { $this->panose[] = ord($panose[$p]); } $this->skip(20); $fsSelection = $this->read_short(); } /////////////////////////////////// // post - PostScript table /////////////////////////////////// $this->seek_table("post"); $this->skip(4); $this->italicAngle = $this->read_short() + $this->read_ushort() / 65536.0; $this->skip(4); $isFixedPitch = $this->read_ulong(); /////////////////////////////////// // cmap - Character to glyph index mapping table /////////////////////////////////// $cmap_offset = $this->seek_table("cmap"); $this->skip(2); $cmapTableCount = $this->read_ushort(); $unicode_cmap_offset = 0; for ($i = 0; $i < $cmapTableCount; $i++) { $platformID = $this->read_ushort(); $encodingID = $this->read_ushort(); $offset = $this->read_ulong(); $save_pos = $this->_pos; if ($platformID == 3 && $encodingID == 1 || $platformID == 0) { // Microsoft, Unicode $format = $this->get_ushort($cmap_offset + $offset); if ($format == 4) { if (!$unicode_cmap_offset) { $unicode_cmap_offset = $cmap_offset + $offset; } } } else { if ($platformID == 3 && $encodingID == 10 || $platformID == 0) { // Microsoft, Unicode Format 12 table HKCS $format = $this->get_ushort($cmap_offset + $offset); if ($format == 12) { $unicode_cmap_offset = $cmap_offset + $offset; break; } } } $this->seek($save_pos); } if (!$unicode_cmap_offset) { return 'ERROR - Font (' . $this->filename . ') NOT ADDED as it is not Unicode encoded, and cannot be used by mPDF'; } $rtl = false; $indic = false; $cjk = false; $sip = false; $smp = false; $pua = false; $puaag = false; $glyphToChar = array(); $unAGlyphs = ''; // Format 12 CMAP does characters above Unicode BMP i.e. some HKCS characters U+20000 and above if ($format == 12) { $this->seek($unicode_cmap_offset + 4); $length = $this->read_ulong(); $limit = $unicode_cmap_offset + $length; $this->skip(4); $nGroups = $this->read_ulong(); for ($i = 0; $i < $nGroups; $i++) { $startCharCode = $this->read_ulong(); $endCharCode = $this->read_ulong(); $startGlyphCode = $this->read_ulong(); if ($endCharCode > 0x20000 && $endCharCode < 0x2a6df || $endCharCode > 0x2f800 && $endCharCode < 0x2fa1f) { $sip = true; } if ($endCharCode > 0x10000 && $endCharCode < 0x1ffff) { $smp = true; } if ($endCharCode > 0x590 && $endCharCode < 0x77f || $endCharCode > 0xfe70 && $endCharCode < 0xfeff || $endCharCode > 0xfb50 && $endCharCode < 0xfdff) { $rtl = true; } if ($endCharCode > 0x900 && $endCharCode < 0xdff) { $indic = true; } if ($endCharCode > 0xe000 && $endCharCode < 0xf8ff) { $pua = true; if ($endCharCode > 0xf500 && $endCharCode < 0xf7ff) { $puaag = true; } } if ($endCharCode > 0x2e80 && $endCharCode < 0x4dc0 || $endCharCode > 0x4e00 && $endCharCode < 0xa4cf || $endCharCode > 0xac00 && $endCharCode < 0xd7af || $endCharCode > 0xf900 && $endCharCode < 0xfaff || $endCharCode > 0xfe30 && $endCharCode < 0xfe4f) { $cjk = true; } $offset = 0; // Get each glyphToChar - only point if going to analyse un-mapped Arabic Glyphs if (isset($this->tables['post'])) { for ($unichar = $startCharCode; $unichar <= $endCharCode; $unichar++) { $glyph = $startGlyphCode + $offset; $offset++; $glyphToChar[$glyph][] = $unichar; } } } } else { // Format 4 CMap $this->seek($unicode_cmap_offset + 2); $length = $this->read_ushort(); $limit = $unicode_cmap_offset + $length; $this->skip(2); $segCount = $this->read_ushort() / 2; $this->skip(6); $endCount = array(); for ($i = 0; $i < $segCount; $i++) { $endCount[] = $this->read_ushort(); } $this->skip(2); $startCount = array(); for ($i = 0; $i < $segCount; $i++) { $startCount[] = $this->read_ushort(); } $idDelta = array(); for ($i = 0; $i < $segCount; $i++) { $idDelta[] = $this->read_short(); } $idRangeOffset_start = $this->_pos; $idRangeOffset = array(); for ($i = 0; $i < $segCount; $i++) { $idRangeOffset[] = $this->read_ushort(); } for ($n = 0; $n < $segCount; $n++) { if ($endCount[$n] > 0x590 && $endCount[$n] < 0x77f || $endCount[$n] > 0xfe70 && $endCount[$n] < 0xfeff || $endCount[$n] > 0xfb50 && $endCount[$n] < 0xfdff) { $rtl = true; } if ($endCount[$n] > 0x900 && $endCount[$n] < 0xdff) { $indic = true; } 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) { $cjk = true; } if ($endCount[$n] > 0xe000 && $endCount[$n] < 0xf8ff) { $pua = true; if ($endCount[$n] > 0xf500 && $endCount[$n] < 0xf7ff) { $puaag = true; } } // Get each glyphToChar - only point if going to analyse un-mapped Arabic Glyphs if (isset($this->tables['post'])) { $endpoint = $endCount[$n] + 1; for ($unichar = $startCount[$n]; $unichar < $endpoint; $unichar++) { if ($idRangeOffset[$n] == 0) { $glyph = $unichar + $idDelta[$n] & 0xffff; } else { $offset = ($unichar - $startCount[$n]) * 2 + $idRangeOffset[$n]; $offset = $idRangeOffset_start + 2 * $n + $offset; if ($offset >= $limit) { $glyph = 0; } else { $glyph = $this->get_ushort($offset); if ($glyph != 0) { $glyph = $glyph + $idDelta[$n] & 0xffff; } } } $glyphToChar[$glyph][] = $unichar; } } } } // 'POST' table for un-mapped arabic glyphs if (isset($this->tables['post'])) { $this->seek_table("post"); // Only works on Format 2.0 $formata = $this->read_ushort(); $formatb = $this->read_ushort(); if ($formata == 2 && $formatb == 0) { $this->skip(28); $nGlyfs = $this->read_ushort(); $glyphNameIndex = array(); for ($i = 0; $i < $nGlyfs; $i++) { $glyphNameIndex[$this->read_ushort()] = $i; } $opost = $this->get_table('post'); $ptr = 34 + $nGlyfs * 2; for ($i = 0; $i < $nGlyfs; $i++) { $len = ord(substr($opost, $ptr, 1)); $ptr++; $name = substr($opost, $ptr, $len); $gid = $glyphNameIndex[$i + 258]; // Select uni0600.xxx(x) - uni06FF.xxx(x) if (preg_match('/^uni(06[0-9a-f]{2})\\.(fina|medi|init|fin|med|ini)$/i', $name, $m)) { 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 $uni = hexdec($m[1]); $form = strtoupper(substr($m[2], 0, 1)); // Assign new PUA Unicode between F500 - F7FF $bit = $uni & 0xff; if ($form == 'I') { $bit += 0xf600; } else { if ($form == 'M') { $bit += 0xf700; } else { $bit += 0xf500; } } $unAGlyphs .= $gid; $name = 'uni' . strtoupper($m[1]) . '.' . strtolower($m[2]); $unAGlyphs .= ' : ' . $name; $unihexstr = $m[1]; $unAGlyphs .= ' : ' . $unihexstr; $unAGlyphs .= ' : ' . $uni; $unAGlyphs .= ' : ' . $form; // if already set in PUA private use area E000-F8FF if (isset($glyphToChar[$gid]) && $glyphToChar[$gid][0] > 57343 && $glyphToChar[$gid][0] < 63489) { $unAGlyphs .= ' : ' . $glyphToChar[$gid][0] . ' {' . dechex($glyphToChar[$gid][0]) . '}'; } //else $unAGlyphs .= ':'; $unAGlyphs .= ' : ' . strtoupper(dechex($bit)); $unAGlyphs .= '<br />'; } } $ptr += $len; } if ($unAGlyphs) { $unAGlyphs = 'GID:Name:Unicode base Hex:Dec:Form:PUA Unicode<br />' . $unAGlyphs; } } } $bold = false; $italic = false; $ftype = ''; if ($macStyle & 1 << 0) { $bold = true; } else { if ($fsSelection & 1 << 5) { $bold = true; } } // 5 BOLD Characters are emboldened if ($macStyle & 1 << 1) { $italic = true; } else { if ($fsSelection & 1 << 0) { $italic = true; } else { if ($this->italicAngle != 0) { $italic = true; } } } if ($isFixedPitch) { $ftype = 'mono'; } else { if ($sFamily > 0 && $sFamily < 8) { $ftype = 'serif'; } else { if ($sFamily == 8) { $ftype = 'sans'; } else { if ($sFamily == 10) { $ftype = 'cursive'; } } } } // Use PANOSE if ($panose) { $bFamilyType = ord($panose[0]); if ($bFamilyType == 2) { $bSerifStyle = ord($panose[1]); if (!$ftype) { if ($bSerifStyle > 1 && $bSerifStyle < 11) { $ftype = 'serif'; } else { if ($bSerifStyle > 10) { $ftype = 'sans'; } } } $bProportion = ord($panose[3]); if ($bProportion == 9 || $bProportion == 1) { $ftype = 'mono'; } // ==1 i.e. No Fit needed for OCR-a and -b } else { if ($bFamilyType == 3) { $ftype = 'cursive'; } } } fclose($this->fh); return array($this->familyName, $bold, $italic, $ftype, $TTCfontID, $rtl, $indic, $cjk, $sip, $smp, $puaag, $pua, $unAGlyphs); }
function extractInfo($debug = false, $BMPonly = false, $kerninfo = false) { $this->panose = array(); $this->sFamilyClass = 0; $this->sFamilySubClass = 0; /////////////////////////////////// // name - Naming table /////////////////////////////////// $name_offset = $this->seek_table("name"); $format = $this->read_ushort(); if ($format != 0 && $format != 1) { die("Unknown name table format " . $format); } $numRecords = $this->read_ushort(); $string_data_offset = $name_offset + $this->read_ushort(); $names = array(1 => '', 2 => '', 3 => '', 4 => '', 6 => ''); $K = array_keys($names); $nameCount = count($names); for ($i = 0; $i < $numRecords; $i++) { $platformId = $this->read_ushort(); $encodingId = $this->read_ushort(); $languageId = $this->read_ushort(); $nameId = $this->read_ushort(); $length = $this->read_ushort(); $offset = $this->read_ushort(); if (!in_array($nameId, $K)) { continue; } $N = ''; if ($platformId == 3 && $encodingId == 1 && $languageId == 0x409) { // Microsoft, Unicode, US English, PS Name $opos = $this->_pos; $this->seek($string_data_offset + $offset); if ($length % 2 != 0) { die("PostScript name is UTF-16BE string of odd length"); } $length /= 2; $N = ''; while ($length > 0) { $char = $this->read_ushort(); $N .= chr($char); $length -= 1; } $this->_pos = $opos; $this->seek($opos); } else { if ($platformId == 1 && $encodingId == 0 && $languageId == 0) { // Macintosh, Roman, English, PS Name $opos = $this->_pos; $N = $this->get_chunk($string_data_offset + $offset, $length); $this->_pos = $opos; $this->seek($opos); } } if ($N && $names[$nameId] == '') { $names[$nameId] = $N; $nameCount -= 1; if ($nameCount == 0) { break; } } } if ($names[6]) { $psName = $names[6]; } else { if ($names[4]) { $psName = preg_replace_callback_callback('/ /', '-', $names[4]); } else { if ($names[1]) { $psName = preg_replace_callback_callback('/ /', '-', $names[1]); } else { $psName = ''; } } } if (!$psName) { die("Could not find PostScript font name: " . $this->filename); } if ($debug) { for ($i = 0; $i < count($psName); $i++) { $c = $psName[$i]; $oc = ord($c); if ($oc > 126 || strpos(' [](){}<>/%', $c) !== false) { die("psName=" . $psName . " contains invalid character " . $c . " ie U+" . ord(c)); } } } $this->name = $psName; if ($names[1]) { $this->familyName = $names[1]; } else { $this->familyName = $psName; } if ($names[2]) { $this->styleName = $names[2]; } else { $this->styleName = 'Regular'; } if ($names[4]) { $this->fullName = $names[4]; } else { $this->fullName = $psName; } if ($names[3]) { $this->uniqueFontID = $names[3]; } else { $this->uniqueFontID = $psName; } if ($names[6]) { $this->fullName = $names[6]; } /////////////////////////////////// // head - Font header table /////////////////////////////////// $this->seek_table("head"); if ($debug) { $ver_maj = $this->read_ushort(); $ver_min = $this->read_ushort(); if ($ver_maj != 1) { die('Unknown head table version ' . $ver_maj . '.' . $ver_min); } $this->fontRevision = $this->read_ushort() . $this->read_ushort(); $this->skip(4); $magic = $this->read_ulong(); if ($magic != 0x5f0f3cf5) { die('Invalid head table magic ' . $magic); } $this->skip(2); } else { $this->skip(18); } $this->unitsPerEm = $unitsPerEm = $this->read_ushort(); $scale = 1000 / $unitsPerEm; $this->skip(16); $xMin = $this->read_short(); $yMin = $this->read_short(); $xMax = $this->read_short(); $yMax = $this->read_short(); $this->bbox = array($xMin * $scale, $yMin * $scale, $xMax * $scale, $yMax * $scale); $this->skip(3 * 2); $indexToLocFormat = $this->read_ushort(); $glyphDataFormat = $this->read_ushort(); if ($glyphDataFormat != 0) { die('Unknown glyph data format ' . $glyphDataFormat); } /////////////////////////////////// // hhea metrics table /////////////////////////////////// // ttf2t1 seems to use this value rather than the one in OS/2 - so put in for compatibility if (isset($this->tables["hhea"])) { $this->seek_table("hhea"); $this->skip(4); $hheaAscender = $this->read_short(); $hheaDescender = $this->read_short(); $this->ascent = $hheaAscender * $scale; $this->descent = $hheaDescender * $scale; } /////////////////////////////////// // OS/2 - OS/2 and Windows metrics table /////////////////////////////////// if (isset($this->tables["OS/2"])) { $this->seek_table("OS/2"); $version = $this->read_ushort(); $this->skip(2); $usWeightClass = $this->read_ushort(); $this->skip(2); $fsType = $this->read_ushort(); if ($fsType == 0x2 || ($fsType & 0x300) != 0) { global $overrideTTFFontRestriction; if (!$overrideTTFFontRestriction) { die('ERROR - Font file ' . $this->filename . ' cannot be embedded due to copyright restrictions.'); } $this->restrictedUse = true; } $this->skip(20); $sF = $this->read_short(); $this->sFamilyClass = $sF >> 8; $this->sFamilySubClass = $sF & 0xff; $this->_pos += 10; //PANOSE = 10 byte length $panose = fread($this->fh, 10); $this->panose = array(); for ($p = 0; $p < strlen($panose); $p++) { $this->panose[] = ord($panose[$p]); } $this->skip(26); $sTypoAscender = $this->read_short(); $sTypoDescender = $this->read_short(); if (!$this->ascent) { $this->ascent = $sTypoAscender * $scale; } if (!$this->descent) { $this->descent = $sTypoDescender * $scale; } if ($version > 1) { $this->skip(16); $sCapHeight = $this->read_short(); $this->capHeight = $sCapHeight * $scale; } else { $this->capHeight = $this->ascent; } } else { $usWeightClass = 500; if (!$this->ascent) { $this->ascent = $yMax * $scale; } if (!$this->descent) { $this->descent = $yMin * $scale; } $this->capHeight = $this->ascent; } $this->stemV = 50 + intval(pow($usWeightClass / 65.0, 2)); /////////////////////////////////// // post - PostScript table /////////////////////////////////// $this->seek_table("post"); if ($debug) { $ver_maj = $this->read_ushort(); $ver_min = $this->read_ushort(); if ($ver_maj < 1 || $ver_maj > 4) { die('Unknown post table version ' . $ver_maj); } } else { $this->skip(4); } $this->italicAngle = $this->read_short() + $this->read_ushort() / 65536.0; $this->underlinePosition = $this->read_short() * $scale; $this->underlineThickness = $this->read_short() * $scale; $isFixedPitch = $this->read_ulong(); $this->flags = 4; if ($this->italicAngle != 0) { $this->flags = $this->flags | 64; } if ($usWeightClass >= 600) { $this->flags = $this->flags | 262144; } if ($isFixedPitch) { $this->flags = $this->flags | 1; } /////////////////////////////////// // hhea - Horizontal header table /////////////////////////////////// $this->seek_table("hhea"); if ($debug) { $ver_maj = $this->read_ushort(); $ver_min = $this->read_ushort(); if ($ver_maj != 1) { die('Unknown hhea table version ' . $ver_maj); } $this->skip(28); } else { $this->skip(32); } $metricDataFormat = $this->read_ushort(); if ($metricDataFormat != 0) { die('Unknown horizontal metric data format ' . $metricDataFormat); } $numberOfHMetrics = $this->read_ushort(); if ($numberOfHMetrics == 0) { die('Number of horizontal metrics is 0'); } /////////////////////////////////// // maxp - Maximum profile table /////////////////////////////////// $this->seek_table("maxp"); if ($debug) { $ver_maj = $this->read_ushort(); $ver_min = $this->read_ushort(); if ($ver_maj != 1) { die('Unknown maxp table version ' . $ver_maj); } } else { $this->skip(4); } $numGlyphs = $this->read_ushort(); /////////////////////////////////// // cmap - Character to glyph index mapping table /////////////////////////////////// $cmap_offset = $this->seek_table("cmap"); $this->skip(2); $cmapTableCount = $this->read_ushort(); $unicode_cmap_offset = 0; for ($i = 0; $i < $cmapTableCount; $i++) { $platformID = $this->read_ushort(); $encodingID = $this->read_ushort(); $offset = $this->read_ulong(); $save_pos = $this->_pos; if ($platformID == 3 && $encodingID == 1 || $platformID == 0) { // Microsoft, Unicode $format = $this->get_ushort($cmap_offset + $offset); if ($format == 4) { if (!$unicode_cmap_offset) { $unicode_cmap_offset = $cmap_offset + $offset; } if ($BMPonly) { break; } } } else { if (($platformID == 3 && $encodingID == 10 || $platformID == 0) && !$BMPonly) { $format = $this->get_ushort($cmap_offset + $offset); if ($format == 12) { $unicode_cmap_offset = $cmap_offset + $offset; break; } } } $this->seek($save_pos); } if (!$unicode_cmap_offset) { die('Font (' . $this->filename . ') does not have cmap for Unicode (platform 3, encoding 1, format 4, or platform 0, any encoding, format 4)'); } $sipset = false; $smpset = false; // Format 12 CMAP does characters above Unicode BMP i.e. some HKCS characters U+20000 and above if ($format == 12 && !$BMPonly) { $this->maxUniChar = 0; $this->seek($unicode_cmap_offset + 4); $length = $this->read_ulong(); $limit = $unicode_cmap_offset + $length; $this->skip(4); $nGroups = $this->read_ulong(); $glyphToChar = array(); $charToGlyph = array(); for ($i = 0; $i < $nGroups; $i++) { $startCharCode = $this->read_ulong(); $endCharCode = $this->read_ulong(); $startGlyphCode = $this->read_ulong(); if ($endCharCode > 0x20000 && $endCharCode < 0x2a6df || $endCharCode > 0x2f800 && $endCharCode < 0x2fa1f) { $sipset = true; } else { if ($endCharCode > 0x10000 && $endCharCode < 0x1ffff) { $smpset = true; } } $offset = 0; for ($unichar = $startCharCode; $unichar <= $endCharCode; $unichar++) { $glyph = $startGlyphCode + $offset; $offset++; $charToGlyph[$unichar] = $glyph; if ($unichar < 196608) { $this->maxUniChar = max($unichar, $this->maxUniChar); } $glyphToChar[$glyph][] = $unichar; } } } else { $glyphToChar = array(); $charToGlyph = array(); $this->getCMAP4($unicode_cmap_offset, $glyphToChar, $charToGlyph); } $this->sipset = $sipset; $this->smpset = $smpset; /////////////////////////////////// // hmtx - Horizontal metrics table /////////////////////////////////// $this->getHMTX($numberOfHMetrics, $numGlyphs, $glyphToChar, $scale); /////////////////////////////////// // kern - Kerning pair table /////////////////////////////////// if ($kerninfo) { // Recognises old form of Kerning table - as required by Windows - Format 0 only $kern_offset = $this->seek_table("kern"); $version = $this->read_ushort(); $nTables = $this->read_ushort(); // subtable header $sversion = $this->read_ushort(); $slength = $this->read_ushort(); $scoverage = $this->read_ushort(); $format = $scoverage >> 8; if ($kern_offset && $version == 0 && $format == 0) { // Format 0 $nPairs = $this->read_ushort(); $this->skip(6); for ($i = 0; $i < $nPairs; $i++) { $left = $this->read_ushort(); $right = $this->read_ushort(); $val = $this->read_short(); if (count($glyphToChar[$left]) == 1 && count($glyphToChar[$right]) == 1) { if ($left != 32 && $right != 32) { $this->kerninfo[$glyphToChar[$left][0]][$glyphToChar[$right][0]] = intval($val * $scale); } } } } } }
function parseMozGradient($bg) { // background[-image]: -moz-linear-gradient(left, #c7Fdde 20%, #FF0000 ); // background[-image]: linear-gradient(left, #c7Fdde 20%, #FF0000 ); // CSS3 if (preg_match('/repeating-/', $bg)) { $repeat = true; } else { $repeat = false; } if (preg_match('/linear-gradient\\((.*)\\)/', $bg, $m)) { $g = array(); $g['type'] = 2; $g['colorspace'] = 'RGB'; $g['extend'] = array('true', 'true'); $v = trim($m[1]); // Change commas inside e.g. rgb(x,x,x) while (preg_match('/(\\([^\\)]*?),/', $v)) { $v = preg_replace_callback_callback('/(\\([^\\)]*?),/', '\\1@', $v); } // Remove spaces inside e.g. rgb(x, x, x) while (preg_match('/(\\([^\\)]*?)[ ]/', $v)) { $v = preg_replace_callback_callback('/(\\([^\\)]*?)[ ]/', '\\1', $v); } $bgr = preg_split('/\\s*,\\s*/', $v); for ($i = 0; $i < count($bgr); $i++) { $bgr[$i] = preg_replace_callback_callback('/@/', ',', $bgr[$i]); } // Is first part $bgr[0] a valid point/angle? $first = preg_split('/\\s+/', trim($bgr[0])); if (preg_match('/(left|center|right|bottom|top|deg|grad|rad)/i', $bgr[0]) && !preg_match('/(<#|rgb|rgba|hsl|hsla)/i', $bgr[0])) { $startStops = 1; } else { if (trim($first[count($first) - 1]) === "0") { $startStops = 1; } else { $check = $this->mpdf->ConvertColor($first[0]); if ($check) { $startStops = 0; } else { $startStops = 1; } } } // first part a valid point/angle? if ($startStops == 1) { // default values // [<point> || <angle>,] = [<% em px left center right bottom top> || <deg grad rad 0>,] if (preg_match('/([\\-]*[0-9\\.]+)(deg|grad|rad)/i', $bgr[0], $m)) { $angle = $m[1] + 0; if (strtolower($m[2]) == 'deg') { $angle = $angle; } else { if (strtolower($m[2]) == 'grad') { $angle *= 360 / 400; } else { if (strtolower($m[2]) == 'rad') { $angle = rad2deg($angle); } } } while ($angle < 0) { $angle += 360; } $angle = $angle % 360; } else { if (trim($first[count($first) - 1]) === "0") { $angle = 0; } } if (preg_match('/left/i', $bgr[0])) { $startx = 0; } else { if (preg_match('/right/i', $bgr[0])) { $startx = 1; } } if (preg_match('/top/i', $bgr[0])) { $starty = 1; } else { if (preg_match('/bottom/i', $bgr[0])) { $starty = 0; } } // Check for %? ?% or %% if (preg_match('/(\\d+)[%]/i', $first[0], $m)) { $startx = $m[1] / 100; } else { if (!isset($startx) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i', $first[0], $m)) { $tmp = $this->mpdf->ConvertSize($m[1], $this->mpdf->w, $this->mpdf->FontSize, false); if ($tmp) { $startx = $m[1]; } } } if (isset($first[1]) && preg_match('/(\\d+)[%]/i', $first[1], $m)) { $starty = 1 - $m[1] / 100; } else { if (!isset($starty) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i', $first[1], $m)) { $tmp = $this->mpdf->ConvertSize($m[1], $this->mpdf->w, $this->mpdf->FontSize, false); if ($tmp) { $starty = $m[1]; } } } if (isset($startx) && !isset($starty)) { $starty = 0.5; } if (!isset($startx) && isset($starty)) { $startx = 0.5; } } else { // default values T2B $starty = 1; $startx = 0.5; $endy = 0; $endx = 0.5; } $coords = array(); if (!isset($startx)) { $startx = false; } if (!isset($starty)) { $starty = false; } if (!isset($endx)) { $endx = false; } if (!isset($endy)) { $endy = false; } if (!isset($angle)) { $angle = false; } $g['coords'] = array($startx, $starty, $endx, $endy, $angle, $repeat); $g['stops'] = array(); for ($i = $startStops; $i < count($bgr); $i++) { $stop = array(); // parse stops $el = preg_split('/\\s+/', trim($bgr[$i])); // mPDF 5.3.74 $col = $this->mpdf->ConvertColor($el[0]); if ($col) { $stop['col'] = $col; } else { $stop['col'] = $col = $this->mpdf->ConvertColor(255); } if ($col[0] == 1) { $g['colorspace'] = 'Gray'; } else { if ($col[0] == 4 || $col[0] == 6) { $g['colorspace'] = 'CMYK'; } } if ($col[0] == 5) { $stop['opacity'] = ord($col[4]) / 100; } else { if ($col[0] == 6) { $stop['opacity'] = ord($col[5]) / 100; } else { if ($col[0] == 1 && $col[2] == 1) { $stop['opacity'] = ord($col[3]) / 100; } } } // transparency converted from rgba or cmyka() if (isset($el[1]) && preg_match('/(\\d+)[%]/', $el[1], $m)) { $stop['offset'] = $m[1] / 100; if ($stop['offset'] > 1) { unset($stop['offset']); } } else { if (isset($el[1]) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i', $el[1], $m)) { $tmp = $this->mpdf->ConvertSize($m[1], $this->mpdf->w, $this->mpdf->FontSize, false); if ($tmp) { $stop['offset'] = $m[1]; } } } $g['stops'][] = $stop; } if (count($g['stops'])) { return $g; } } else { if (preg_match('/radial-gradient\\((.*)\\)/', $bg, $m)) { $g = array(); $g['type'] = 3; $g['colorspace'] = 'RGB'; $g['extend'] = array('true', 'true'); $v = trim($m[1]); // Change commas inside e.g. rgb(x,x,x) while (preg_match('/(\\([^\\)]*?),/', $v)) { $v = preg_replace_callback_callback('/(\\([^\\)]*?),/', '\\1@', $v); } // Remove spaces inside e.g. rgb(x, x, x) while (preg_match('/(\\([^\\)]*?)[ ]/', $v)) { $v = preg_replace_callback_callback('/(\\([^\\)]*?)[ ]/', '\\1', $v); } $bgr = preg_split('/\\s*,\\s*/', $v); for ($i = 0; $i < count($bgr); $i++) { $bgr[$i] = preg_replace_callback_callback('/@/', ',', $bgr[$i]); } // Is first part $bgr[0] a valid point/angle? $startStops = 0; $pos_angle = false; $shape_size = false; $first = preg_split('/\\s+/', trim($bgr[0])); $checkCol = $this->mpdf->ConvertColor($first[0]); if (preg_match('/(left|center|right|bottom|top|deg|grad|rad)/i', $bgr[0]) && !preg_match('/(<#|rgb|rgba|hsl|hsla)/i', $bgr[0])) { $startStops = 1; $pos_angle = $bgr[0]; } else { if (trim($first[count($first) - 1]) === "0") { $startStops = 1; $pos_angle = $bgr[0]; } else { if (preg_match('/(circle|ellipse|closest-side|closest-corner|farthest-side|farthest-corner|contain|cover)/i', $bgr[0])) { $startStops = 1; $shape_size = $bgr[0]; } else { if (!$checkCol) { $startStops = 1; $pos_angle = $bgr[0]; } } } } if (preg_match('/(circle|ellipse|closest-side|closest-corner|farthest-side|farthest-corner|contain|cover)/i', $bgr[1])) { $startStops = 2; $shape_size = $bgr[1]; } // If valid point/angle? if ($pos_angle) { // default values // [<point> || <angle>,] = [<% em px left center right bottom top> || <deg grad rad 0>,] if (preg_match('/left/i', $pos_angle)) { $startx = 0; } else { if (preg_match('/right/i', $pos_angle)) { $startx = 1; } } if (preg_match('/top/i', $pos_angle)) { $starty = 1; } else { if (preg_match('/bottom/i', $pos_angle)) { $starty = 0; } } // Check for %? ?% or %% if (preg_match('/(\\d+)[%]/i', $first[0], $m)) { $startx = $m[1] / 100; } else { if (!isset($startx) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i', $first[0], $m)) { $tmp = $this->mpdf->ConvertSize($m[1], $this->mpdf->w, $this->mpdf->FontSize, false); if ($tmp) { $startx = $m[1]; } } } if (isset($first[1]) && preg_match('/(\\d+)[%]/i', $first[1], $m)) { $starty = 1 - $m[1] / 100; } else { if (!isset($starty) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i', $first[1], $m)) { $tmp = $this->mpdf->ConvertSize($m[1], $this->mpdf->w, $this->mpdf->FontSize, false); if ($tmp) { $starty = $m[1]; } } } /* // ?? Angle has no effect in radial gradient (does not exist in CSS3 spec.) if (preg_match('/([\-]*[0-9\.]+)(deg|grad|rad)/i',$pos_angle,$m)) { $angle = $m[1] + 0; if (strtolower($m[2])=='deg') { $angle = $angle; } else if (strtolower($m[2])=='grad') { $angle *= (360/400); } else if (strtolower($m[2])=='rad') { $angle = rad2deg($angle); } while($angle < 0) { $angle += 360; } $angle = ($angle % 360); } */ if (!isset($starty)) { $starty = 0.5; } if (!isset($startx)) { $startx = 0.5; } } else { // default values Center $starty = 0.5; $startx = 0.5; $endy = 0.5; $endx = 0.5; } // If valid shape/size? $shape = 'ellipse'; // default $size = 'farthest-corner'; // default if ($shape_size) { // default values if (preg_match('/(circle|ellipse)/i', $shape_size, $m)) { $shape = $m[1]; } if (preg_match('/(closest-side|closest-corner|farthest-side|farthest-corner|contain|cover)/i', $shape_size, $m)) { $size = $m[1]; if ($size == 'contain') { $size = 'closest-side'; } else { if ($size == 'cover') { $size = 'farthest-corner'; } } } } $coords = array(); if (!isset($startx)) { $startx = false; } if (!isset($starty)) { $starty = false; } if (!isset($endx)) { $endx = false; } if (!isset($endy)) { $endy = false; } if (!isset($radius)) { $radius = false; } if (!isset($angle)) { $angle = 0; } $g['coords'] = array($startx, $starty, $endx, $endy, $radius, $angle, $shape, $size, $repeat); $g['stops'] = array(); for ($i = $startStops; $i < count($bgr); $i++) { $stop = array(); // parse stops $el = preg_split('/\\s+/', trim($bgr[$i])); // mPDF 5.3.74 $col = $this->mpdf->ConvertColor($el[0]); if ($col) { $stop['col'] = $col; } else { $stop['col'] = $col = $this->mpdf->ConvertColor(255); } if ($col[0] == 1) { $g['colorspace'] = 'Gray'; } else { if ($col[0] == 4 || $col[0] == 6) { $g['colorspace'] = 'CMYK'; } } if ($col[0] == 5) { $stop['opacity'] = ord($col[4]) / 100; } else { if ($col[0] == 6) { $stop['opacity'] = ord($col[5]) / 100; } else { if ($col[0] == 1 && $col[2] == 1) { $stop['opacity'] = ord($col[3]) / 100; } } } // transparency converted from rgba or cmyka() if (isset($el[1]) && preg_match('/(\\d+)[%]/', $el[1], $m)) { $stop['offset'] = $m[1] / 100; if ($stop['offset'] > 1) { unset($stop['offset']); } } else { if (isset($el[1]) && preg_match('/([0-9.]+(px|em|ex|pc|pt|cm|mm|in))/i', $el[1], $m)) { $tmp = $this->mpdf->ConvertSize($m[1], $this->mpdf->w, $this->mpdf->FontSize, false); $stop['offset'] = $el[1]; } } $g['stops'][] = $stop; } if (count($g['stops'])) { return $g; } } } return array(); }
<?php $ff = scandir('./'); sort($ff); $files = array(); foreach ($ff as $f) { if (preg_match('/example[0]{0,1}(\\d+)_(.*?)\\.php/', $f, $m)) { $num = intval($m[1]); $files[$num] = array(ucfirst(preg_replace_callback_callback('/_/', ' ', $m[2])), $m[0]); } } echo '<html><body><h3>mPDF Example Files</h3>'; foreach ($files as $n => $f) { echo '<p>' . $n . ') ' . $f[0] . ' <a href="' . $f[1] . '">PDF</a> <small><a href="show_code.php?filename=' . $f[1] . '">PHP</a></small></p>'; } echo '</body></html>'; exit; // For PHP4 compatability if (!function_exists('scandir')) { function scandir($dir = './', $sort = 0) { $dir_open = @opendir($dir); if (!$dir_open) { return false; while (($dir_content = readdir($dir_open)) !== false) { $files[] = $dir_content; } } if ($sort == 1) { rsort($files, SORT_STRING); } else {