コード例 #1
0
ファイル: Cpdf.php プロジェクト: hmoyat/php-ezPDF
 /**
  * open the font file and return a php structure containing it.
  * first check if this one has been done before and saved in a form more suited to php
  * note that if a php serialized version does not exist it will try and make one, but will
  * require write access to the directory to do it... it is MUCH faster to have these serialized
  * files.
  *
  * @param string $font Font name (can contain both path and extension)
  *
  * @return bool true on success, false on error
  */
 protected function openFont($font)
 {
     // $font should only contain the font name
     $fullFontPath = $this->fontPath . '/' . $font;
     $this->debug('openFont: ' . $fullFontPath . ' / IsUnicode: ' . $this->isUnicode);
     // PATCH #13 - isUnicode cachedFile (font) problem | thank you jafjaf
     if ($this->isUnicode) {
         $cachedFile = 'cached' . $font . 'unicode.php';
     } else {
         $cachedFile = 'cached' . $font . '.php';
     }
     // use the temp folder to read/write cached font data
     if (file_exists($this->tempPath . '/' . $cachedFile)) {
         $cacheDate = filemtime($this->tempPath . '/' . $cachedFile);
         if ($cacheDate + $this->cacheTimeout >= time()) {
             $this->debug('openFont: font cache found in ' . $this->tempPath . '/' . $cachedFile);
             $this->fonts[$font] = (require $this->tempPath . '/' . $cachedFile);
             if (isset($this->fonts[$font]['_version_']) && $this->fonts[$font]['_version_'] == 3) {
                 // cache is valid - but without checking for a valid font path
                 return true;
             }
         }
     }
     // if no cache is found, parse the font file and rebuild the cache
     $this->debug('openFont: rebuilding font cache ' . $cachedFile, E_USER_NOTICE);
     if (file_exists($fullFontPath . '.ttf') && class_exists('TTF')) {
         $ttf = new TTF(file_get_contents($fullFontPath . '.ttf'));
         $head = $ttf->unmarshalHead();
         $uname = $ttf->unmarshalName();
         $hhea = $ttf->unmarshalHhea();
         $post = $ttf->unmarshalPost(true);
         $maxp = $ttf->unmarshalMAXP();
         $cmap = $ttf->unmarshalCmap();
         $cachedFont = array('isUnicode' => $this->isUnicode, 'ItalicAngle' => $post['italicAngle'], 'UnderlineThickness' => $post['underlineThickness'], 'UnderlinePosition' => $post['underlinePosition'], 'IsFixedPitch' => $post['isFixedPitch'] == 0 ? false : true, 'Ascender' => $hhea['ascender'], 'Descender' => $hhea['descender'], 'LineGap' => $hhea['lineGap'], 'FontName' => $font);
         foreach ($uname['nameRecords'] as $v) {
             if ($v['nameID'] == 1 && $v['languageID'] == 0) {
                 // fetch FontFamily from Default language (en?)
                 $cachedFont['FamilyName'] = preg_replace('/\\x00/', '', $v['value']);
             } else {
                 if ($v['nameID'] == 2 && $v['languageID'] == 0) {
                     // fetch font weight from Default language (en?)
                     $cachedFont['Weight'] = preg_replace('/\\x00/', '', $v['value']);
                 } else {
                     if ($v['nameID'] == 3 && $v['languageID'] == 0) {
                         // fetch Unique font name from Default language (en?)
                         $cachedFont['UniqueName'] = preg_replace('/\\x00/', '', $v['value']);
                     } else {
                         if ($v['nameID'] == 4 && $v['languageID'] == 0) {
                             // fetch font name (full style) from Default language (en?)
                             $cachedFont['FullName'] = preg_replace('/\\x00/', '', $v['value']);
                         } else {
                             if ($v['nameID'] == 5 && $v['languageID'] == 0) {
                                 // fetch version from Default language (en?)
                                 $cachedFont['Version'] = preg_replace('/\\x00/', '', $v['value']);
                             }
                         }
                     }
                 }
             }
         }
         // calculate the bounding box properly by using 'units per em' property
         $cachedFont['FontBBox'] = array(intval($head['xMin'] / ($head['unitsPerEm'] / 1000)), intval($head['yMin'] / ($head['unitsPerEm'] / 1000)), intval($head['xMax'] / ($head['unitsPerEm'] / 1000)), intval($head['yMax'] / ($head['unitsPerEm'] / 1000)));
         $cachedFont['UnitsPerEm'] = $head['unitsPerEm'];
         $encodingTable = array();
         $hmetrics = $ttf->unmarshalHmtx($hhea['numberOfHMetrics'], $maxp['numGlyphs']);
         // get format 6 or format 4 as primary cmap table map glyph with character
         foreach ($cmap['tables'] as $v) {
             if (isset($v['format']) && $v['format'] == "4") {
                 $encodingTable = $v;
                 break;
             }
         }
         if ($encodingTable['format'] == '4') {
             $glyphsIndices = range(1, $maxp['numGlyphs']);
             $charToGlyph = array();
             $segCount = $encodingTable['segCount'];
             $endCountArray = $encodingTable['endCountArray'];
             $startCountArray = $encodingTable['startCountArray'];
             $idDeltaArray = $encodingTable['idDeltaArray'];
             $idRangeOffsetArray = $encodingTable['idRangeOffsetArray'];
             $glyphIdArray = $encodingTable['glyphIdArray'];
             for ($seg = 0; $seg < $segCount; $seg++) {
                 $endCount = $endCountArray[$seg];
                 $startCount = $startCountArray[$seg];
                 $idDelta = $idDeltaArray[$seg];
                 $idRangeOffset = $idRangeOffsetArray[$seg];
                 for ($charCode = $startCount; $charCode <= $endCount; $charCode++) {
                     if ($idRangeOffset != 0) {
                         $j = $charCode - $startCount + $seg + $idRangeOffset / 2 - $segCount;
                         $gid0 = $glyphIdArray[$j];
                     } else {
                         $gid0 = $idDelta + $charCode;
                     }
                     $gid0 %= 65536;
                     if (in_array($gid0, $glyphsIndices)) {
                         $charToGlyph[sprintf("%d", $charCode)] = $gid0;
                     }
                 }
             }
             if ($this->isUnicode) {
                 $cidtogid = str_pad('', 256 * 256 * 2, "");
             }
             $cachedFont['C'] = array();
             foreach ($charToGlyph as $char => $glyphIndex) {
                 if (!empty($char)) {
                     $m = TTF::getHMetrics($hmetrics, $hhea['numberOfHMetrics'], $glyphIndex);
                     // calculate the correct char width by dividing it with 'units per em'
                     $cachedFont['C'][$char] = intval($m[0] / ($head['unitsPerEm'] / 1000));
                     if ($this->isUnicode) {
                         if ($char >= 0) {
                             if ($char >= 0 && $char < 0xffff && $glyphIndex) {
                                 $cidtogid[$char * 2] = chr($glyphIndex >> 8);
                                 $cidtogid[$char * 2 + 1] = chr($glyphIndex & 0xff);
                             }
                         }
                     }
                 }
             }
         } else {
             $this->debug('openFont: font file does not contain format 4 cmap', E_USER_WARNING);
         }
         if (isset($cidtogid)) {
             $cachedFont['CIDtoGID'] = base64_encode($cidtogid);
         }
     } else {
         if (file_exists($fullFontPath . '.afm')) {
             // use the core font program
             $cachedFont = array('isUnicode' => false);
             $file = file($fullFontPath . '.afm');
             foreach ($file as $row) {
                 $row = trim($row);
                 $pos = strpos($row, ' ');
                 if ($pos) {
                     // then there must be some keyword
                     $key = substr($row, 0, $pos);
                     switch ($key) {
                         case 'FontName':
                         case 'FullName':
                         case 'FamilyName':
                         case 'Weight':
                         case 'ItalicAngle':
                         case 'IsFixedPitch':
                         case 'CharacterSet':
                         case 'UnderlinePosition':
                         case 'UnderlineThickness':
                         case 'Version':
                         case 'EncodingScheme':
                         case 'CapHeight':
                         case 'XHeight':
                         case 'Ascender':
                         case 'Descender':
                         case 'StdHW':
                         case 'StdVW':
                         case 'StartCharMetrics':
                             $cachedFont[$key] = trim(substr($row, $pos));
                             break;
                         case 'FontBBox':
                             $cachedFont[$key] = explode(' ', trim(substr($row, $pos)));
                             break;
                         case 'C':
                             // C 39 ; WX 222 ; N quoteright ; B 53 463 157 718 ;
                             // use preg_match instead to improve performace
                             // IMPORTANT: if "L i fi ; L l fl ;" is required preg_match must be amended
                             $r = preg_match('/C (-?\\d+) ; WX (-?\\d+) ; N (\\w+) ; B (-?\\d+) (-?\\d+) (-?\\d+) (-?\\d+) ;/', $row, $m);
                             if ($r == 1) {
                                 //$dtmp = array('C'=> $m[1],'WX'=> $m[2], 'N' => $m[3], 'B' => array($m[4], $m[5], $m[6], $m[7]));
                                 $c = (int) $m[1];
                                 $n = $m[3];
                                 $width = floatval($m[2]);
                                 if ($c >= 0) {
                                     if ($c != hexdec($n)) {
                                         $cachedFont['codeToName'][$c] = $n;
                                     }
                                     $cachedFont['C'][$c] = $width;
                                     $cachedFont['C'][$n] = $width;
                                 } else {
                                     $cachedFont['C'][$n] = $width;
                                 }
                                 if (!isset($cachedFont['MissingWidth']) && $c == -1 && $n === '.notdef') {
                                     $cachedFont['MissingWidth'] = $width;
                                 }
                             }
                             break;
                     }
                 }
             }
         } else {
             $this->debug(sprintf('openFont: no font file found for "%s" IsUnicode: %b', $font, $this->isUnicode), E_USER_ERROR);
             return false;
         }
     }
     $cachedFont['_version_'] = 3;
     // store the data in as cached file and in $this->fonts array
     $this->fonts[$font] = $cachedFont;
     $fp = fopen(getcwd() . "/" . $this->tempPath . '/' . $cachedFile, 'w');
     // use the temp folder to write cached font data
     fwrite($fp, '<?php /* R&OS php pdf class font cache file */ return ' . var_export($cachedFont, true) . '; ?>');
     fclose($fp);
     return true;
 }