Example #1
0
 private function readString($name)
 {
     $font = $this->font;
     $size = $font->readUInt16();
     $this->data["{$name}Size"] = $size;
     $this->data[$name] = Font::UTF16ToUTF8($font->read($size));
 }
Example #2
0
 protected function _encode()
 {
     if (empty($this->data)) {
         Font::d("  >> Table is empty");
         return 0;
     }
     return $this->getFont()->pack($this->def, $this->data);
 }
Example #3
0
 protected function _parse()
 {
     $font = $this->getFont();
     $tableOffset = $font->pos();
     $data = $font->unpack(self::$header_format);
     $records = array();
     for ($i = 0; $i < $data["count"]; $i++) {
         $record = new nameRecord();
         $record_data = $font->unpack(nameRecord::$format);
         $record->map($record_data);
         $records[] = $record;
     }
     $names = array();
     foreach ($records as $record) {
         $font->seek($tableOffset + $data["stringOffset"] + $record->offset);
         $s = $font->read($record->length);
         $record->string = Font::UTF16ToUTF8($s);
         $names[$record->nameID] = $record;
     }
     $data["records"] = $names;
     $this->data = $data;
 }
Example #4
0
 static function register_font($style, $remote_file)
 {
     $fontname = mb_strtolower($style["family"]);
     $families = Font_Metrics::get_font_families();
     $entry = array();
     if (isset($families[$fontname])) {
         $entry = $families[$fontname];
     }
     $local_file = DOMPDF_FONT_DIR . md5($remote_file);
     $cache_entry = $local_file;
     $local_file .= ".ttf";
     $style_string = Font_Metrics::get_type("{$style['weight']} {$style['style']}");
     if (!isset($entry[$style_string])) {
         $entry[$style_string] = $cache_entry;
         Font_Metrics::set_font_family($fontname, $entry);
         // Download the remote file
         if (!is_file($local_file)) {
             file_put_contents($local_file, file_get_contents($remote_file));
         }
         $font = Font::load($local_file);
         if (!$font) {
             return false;
         }
         $font->parse();
         $font->saveAdobeFontMetrics("{$cache_entry}.ufm");
         // Save the changes
         Font_Metrics::save_font_families();
     }
     return true;
 }
Example #5
0
/**
 * Installs a new font family
 * This function maps a font-family name to a font.  It tries to locate the
 * bold, italic, and bold italic versions of the font as well.  Once the
 * files are located, ttf versions of the font are copied to the fonts
 * directory.  Changes to the font lookup table are saved to the cache.
 *
 * @param string $fontname    the font-family name
 * @param string $normal      the filename of the normal face font subtype
 * @param string $bold        the filename of the bold face font subtype
 * @param string $italic      the filename of the italic face font subtype
 * @param string $bold_italic the filename of the bold italic face font subtype
 *
 * @throws Exception
 */
function install_font_family($dompdf, $fontname, $normal, $bold = null, $italic = null, $bold_italic = null)
{
    $fontMetrics = $dompdf->getFontMetrics();
    // Check if the base filename is readable
    if (!is_readable($normal)) {
        throw new Exception("Unable to read '{$normal}'.");
    }
    $dir = dirname($normal);
    $basename = basename($normal);
    $last_dot = strrpos($basename, '.');
    if ($last_dot !== false) {
        $file = substr($basename, 0, $last_dot);
        $ext = strtolower(substr($basename, $last_dot));
    } else {
        $file = $basename;
        $ext = '';
    }
    if (!in_array($ext, array(".ttf", ".otf"))) {
        throw new Exception("Unable to process fonts of type '{$ext}'.");
    }
    // Try $file_Bold.$ext etc.
    $path = "{$dir}/{$file}";
    $patterns = array("bold" => array("_Bold", "b", "B", "bd", "BD"), "italic" => array("_Italic", "i", "I"), "bold_italic" => array("_Bold_Italic", "bi", "BI", "ib", "IB"));
    foreach ($patterns as $type => $_patterns) {
        if (!isset(${$type}) || !is_readable(${$type})) {
            foreach ($_patterns as $_pattern) {
                if (is_readable("{$path}{$_pattern}{$ext}")) {
                    ${$type} = "{$path}{$_pattern}{$ext}";
                    break;
                }
            }
            if (is_null(${$type})) {
                echo "Unable to find {$type} face file.\n";
            }
        }
    }
    $fonts = compact("normal", "bold", "italic", "bold_italic");
    $entry = array();
    // Copy the files to the font directory.
    foreach ($fonts as $var => $src) {
        if (is_null($src)) {
            $entry[$var] = $dompdf->getOptions()->get('fontDir') . '/' . mb_substr(basename($normal), 0, -4);
            continue;
        }
        // Verify that the fonts exist and are readable
        if (!is_readable($src)) {
            throw new Exception("Requested font '{$src}' is not readable");
        }
        $dest = $dompdf->getOptions()->get('fontDir') . '/' . basename($src);
        if (!is_writeable(dirname($dest))) {
            throw new Exception("Unable to write to destination '{$dest}'.");
        }
        echo "Copying {$src} to {$dest}...\n";
        if (!copy($src, $dest)) {
            throw new Exception("Unable to copy '{$src}' to '{$dest}'");
        }
        $entry_name = mb_substr($dest, 0, -4);
        echo "Generating Adobe Font Metrics for {$entry_name}...\n";
        $font_obj = Font::load($dest);
        $font_obj->saveAdobeFontMetrics("{$entry_name}.ufm");
        $entry[$var] = $entry_name;
    }
    // Store the fonts in the lookup table
    $fontMetrics->setFontFamily($fontname, $entry);
    // Save the changes
    $fontMetrics->saveFontFamilies();
}
Example #6
0
 public function testLoadTTFFontSuccessfully()
 {
     $trueTypeFont = Font::load('sample-fonts/IntelClear-Light.ttf');
     $this->assertInstanceOf('FontLib\\TrueType\\File', $trueTypeFont);
 }
Example #7
0
 function encode($entry_offset)
 {
     Font::d("\n==== {$this->tag} ====");
     //Font::d("Entry offset  = $entry_offset");
     $data = $this->font_table;
     $font = $this->font;
     $table_offset = $font->pos();
     $this->offset = $table_offset;
     $table_length = $data->encode();
     $font->seek($table_offset);
     $table_data = $font->read($table_length);
     $font->seek($entry_offset);
     $font->write($this->tag, 4);
     $font->writeUInt32(self::computeChecksum($table_data));
     $font->writeUInt32($table_offset);
     $font->writeUInt32($table_length);
     Font::d("Bytes written = {$table_length}");
     $font->seek($table_offset + $table_length);
 }
Example #8
0
use FontLib\Font;
use FontLib\Binary_Stream;
$fontfile = null;
if (isset($_GET["fontfile"])) {
    $fontfile = basename($_GET["fontfile"]);
    $fontfile = "../fonts/{$fontfile}";
}
if (!file_exists($fontfile)) {
    return;
}
$name = isset($_GET["name"]) ? $_GET["name"] : null;
if (isset($_POST["subset"])) {
    $subset = $_POST["subset"];
    ob_start();
    require_once "../src/FontLib/Autoloader.php";
    $font = Font::load($fontfile);
    $font->parse();
    $font->setSubset($subset);
    $font->reduce();
    $new_filename = basename($fontfile);
    $dot = strpos($new_filename, ".");
    $new_filename = substr($new_filename, 0, $dot) . "-subset" . substr($new_filename, $dot);
    header("Content-Type: font/truetype");
    header("Content-Disposition: attachment; filename=\"{$new_filename}\"");
    $tmp = tempnam(sys_get_temp_dir(), "fnt");
    $font->open($tmp, Binary_Stream::modeWrite);
    $font->encode(array("OS/2"));
    $font->close();
    ob_end_clean();
    readfile($tmp);
    unlink($tmp);
Example #9
0
  $stream->w($type, $data);
  $stream->seek(0);
  $new_data = $stream->r($type);
  
  if ($new_data !== $data) {
    echo "NOT OK \t $data \t => $new_data<br />";
  }
  else {
    echo "OK $type<br />";
  }
}*/
// font RW
$filename = "../fonts/DejaVuSansMono.ttf";
$filename_out = "{$filename}.2.ttf";
Font::$debug = true;
$font = Font::load($filename);
$font->parse();
$font->setSubset("(.apbiI,mn");
$font->reduce();
$font->open($filename_out, Binary_Stream::modeWrite);
$font->encode(array("OS/2"));
?>

File size: <?php 
echo number_format(filesize($filename_out), 0, ".", " ");
?>
 bytes
Memory: <?php 
echo memory_get_peak_usage(true) / 1024;
?>
KB
Example #10
0
 public function getUTF16()
 {
     return Font::UTF8ToUTF16($this->string);
 }
Example #11
0
 function encode($tags = array())
 {
     if (!self::$raw) {
         $tags = array_merge(array("head", "hhea", "cmap", "hmtx", "maxp", "glyf", "loca", "name", "post"), $tags);
     } else {
         $tags = array_keys($this->directory);
     }
     $num_tables = count($tags);
     $n = 16;
     // @todo
     Font::d("Tables : " . implode(", ", $tags));
     /** @var DirectoryEntry[] $entries */
     $entries = array();
     foreach ($tags as $tag) {
         if (!isset($this->directory[$tag])) {
             Font::d("  >> '{$tag}' table doesn't exist");
             continue;
         }
         $entries[$tag] = $this->directory[$tag];
     }
     $this->header->data["numTables"] = $num_tables;
     $this->header->encode();
     $directory_offset = $this->pos();
     $offset = $directory_offset + $num_tables * $n;
     $this->seek($offset);
     $i = 0;
     foreach ($entries as $entry) {
         $entry->encode($directory_offset + $i * $n);
         $i++;
     }
 }
Example #12
0
 /**
  * @param array $style
  * @param string $remoteFile
  * @param resource $context
  * @return bool
  */
 public function registerFont($style, $remoteFile, $context = null)
 {
     $fontDir = $this->getOptions()->getFontDir();
     $fontname = mb_strtolower($style["family"]);
     $families = $this->getFontFamilies();
     $entry = array();
     if (isset($families[$fontname])) {
         $entry = $families[$fontname];
     }
     $localFile = $fontDir . DIRECTORY_SEPARATOR . md5($remoteFile);
     $localTempFile = $this->options->get('tempDir') . "/" . md5($remoteFile);
     $cacheEntry = $localFile;
     $localFile .= ".ttf";
     $styleString = $this->getType("{$style['weight']} {$style['style']}");
     if (!isset($entry[$styleString])) {
         $entry[$styleString] = $cacheEntry;
         // Download the remote file
         file_put_contents($localTempFile, file_get_contents($remoteFile, null, $context));
         $font = Font::load($localTempFile);
         if (!$font) {
             unlink($localTempFile);
             return false;
         }
         $font->parse();
         $font->saveAdobeFontMetrics("{$cacheEntry}.ufm");
         unlink($localTempFile);
         if (!file_exists("{$cacheEntry}.ufm")) {
             return false;
         }
         // Save the changes
         file_put_contents($localFile, file_get_contents($remoteFile, null, $context));
         if (!file_exists($localFile)) {
             unlink("{$cacheEntry}.ufm");
             return false;
         }
         $this->setFontFamily($fontname, $entry);
         $this->saveFontFamilies();
     }
     return true;
 }
Example #13
0
 /**
  * if the font is not loaded then load it and make the required object
  * else just make it the current font
  * the encoding array can contain 'encoding'=> 'none','WinAnsiEncoding','MacRomanEncoding' or 'MacExpertEncoding'
  * note that encoding='none' will need to be used for symbolic fonts
  * and 'differences' => an array of mappings between numbers 0->255 and character names.
  *
  */
 function selectFont($fontName, $encoding = '', $set = true)
 {
     $ext = substr($fontName, -4);
     if ($ext === '.afm' || $ext === '.ufm') {
         $fontName = substr($fontName, 0, mb_strlen($fontName) - 4);
     }
     if (!isset($this->fonts[$fontName])) {
         $this->addMessage("selectFont: selecting - {$fontName} - {$encoding}, {$set}");
         // load the file
         $this->openFont($fontName);
         if (isset($this->fonts[$fontName])) {
             $this->numObj++;
             $this->numFonts++;
             $font =& $this->fonts[$fontName];
             //$this->numFonts = md5($fontName);
             $pos = strrpos($fontName, '/');
             //      $dir = substr($fontName,0,$pos+1);
             $name = substr($fontName, $pos + 1);
             $options = array('name' => $name, 'fontFileName' => $fontName);
             if (is_array($encoding)) {
                 // then encoding and differences might be set
                 if (isset($encoding['encoding'])) {
                     $options['encoding'] = $encoding['encoding'];
                 }
                 if (isset($encoding['differences'])) {
                     $options['differences'] = $encoding['differences'];
                 }
             } else {
                 if (mb_strlen($encoding, '8bit')) {
                     // then perhaps only the encoding has been set
                     $options['encoding'] = $encoding;
                 }
             }
             $fontObj = $this->numObj;
             $this->o_font($this->numObj, 'new', $options);
             $font['fontNum'] = $this->numFonts;
             // if this is a '.afm' font, and there is a '.pfa' file to go with it ( as there
             // should be for all non-basic fonts), then load it into an object and put the
             // references into the font object
             $basefile = $fontName;
             $fbtype = '';
             if (file_exists("{$basefile}.pfb")) {
                 $fbtype = 'pfb';
             } else {
                 if (file_exists("{$basefile}.ttf")) {
                     $fbtype = 'ttf';
                 }
             }
             $fbfile = "{$basefile}.{$fbtype}";
             //      $pfbfile = substr($fontName,0,strlen($fontName)-4).'.pfb';
             //      $ttffile = substr($fontName,0,strlen($fontName)-4).'.ttf';
             $this->addMessage('selectFont: checking for - ' . $fbfile);
             // OAR - I don't understand this old check
             // if (substr($fontName, -4) ===  '.afm' &&  strlen($fbtype)) {
             if ($fbtype) {
                 $adobeFontName = isset($font['PostScriptName']) ? $font['PostScriptName'] : $font['FontName'];
                 //        $fontObj = $this->numObj;
                 $this->addMessage("selectFont: adding font file - {$fbfile} - {$adobeFontName}");
                 // find the array of font widths, and put that into an object.
                 $firstChar = -1;
                 $lastChar = 0;
                 $widths = array();
                 $cid_widths = array();
                 foreach ($font['C'] as $num => $d) {
                     if (intval($num) > 0 || $num == '0') {
                         if (!$font['isUnicode']) {
                             // With Unicode, widths array isn't used
                             if ($lastChar > 0 && $num > $lastChar + 1) {
                                 for ($i = $lastChar + 1; $i < $num; $i++) {
                                     $widths[] = 0;
                                 }
                             }
                         }
                         $widths[] = $d;
                         if ($font['isUnicode']) {
                             $cid_widths[$num] = $d;
                         }
                         if ($firstChar == -1) {
                             $firstChar = $num;
                         }
                         $lastChar = $num;
                     }
                 }
                 // also need to adjust the widths for the differences array
                 if (isset($options['differences'])) {
                     foreach ($options['differences'] as $charNum => $charName) {
                         if ($charNum > $lastChar) {
                             if (!$font['isUnicode']) {
                                 // With Unicode, widths array isn't used
                                 for ($i = $lastChar + 1; $i <= $charNum; $i++) {
                                     $widths[] = 0;
                                 }
                             }
                             $lastChar = $charNum;
                         }
                         if (isset($font['C'][$charName])) {
                             $widths[$charNum - $firstChar] = $font['C'][$charName];
                             if ($font['isUnicode']) {
                                 $cid_widths[$charName] = $font['C'][$charName];
                             }
                         }
                     }
                 }
                 if ($font['isUnicode']) {
                     $font['CIDWidths'] = $cid_widths;
                 }
                 $this->addMessage('selectFont: FirstChar = ' . $firstChar);
                 $this->addMessage('selectFont: LastChar = ' . $lastChar);
                 $widthid = -1;
                 if (!$font['isUnicode']) {
                     // With Unicode, widths array isn't used
                     $this->numObj++;
                     $this->o_contents($this->numObj, 'new', 'raw');
                     $this->objects[$this->numObj]['c'] .= '[' . implode(' ', $widths) . ']';
                     $widthid = $this->numObj;
                 }
                 $missing_width = 500;
                 $stemV = 70;
                 if (isset($font['MissingWidth'])) {
                     $missing_width = $font['MissingWidth'];
                 }
                 if (isset($font['StdVW'])) {
                     $stemV = $font['StdVW'];
                 } else {
                     if (isset($font['Weight']) && preg_match('!(bold|black)!i', $font['Weight'])) {
                         $stemV = 120;
                     }
                 }
                 // load the pfb file, and put that into an object too.
                 // note that pdf supports only binary format type 1 font files, though there is a
                 // simple utility to convert them from pfa to pfb.
                 // FIXME: should we move font subset creation to CPDF::output? See notes in issue #750.
                 if (!$this->isUnicode || $fbtype !== 'ttf' || empty($this->stringSubsets)) {
                     $data = file_get_contents($fbfile);
                 } else {
                     $this->stringSubsets[$fontName][] = 32;
                     // Force space if not in yet
                     $subset = $this->stringSubsets[$fontName];
                     sort($subset);
                     // Load font
                     $font_obj = Font::load($fbfile);
                     $font_obj->parse();
                     // Define subset
                     $font_obj->setSubset($subset);
                     $font_obj->reduce();
                     // Write new font
                     $tmp_name = $this->tmp . "/" . basename($fbfile) . ".tmp." . uniqid();
                     $font_obj->open($tmp_name, BinaryStream::modeWrite);
                     $font_obj->encode(array("OS/2"));
                     $font_obj->close();
                     // Parse the new font to get cid2gid and widths
                     $font_obj = Font::load($tmp_name);
                     // Find Unicode char map table
                     $subtable = null;
                     foreach ($font_obj->getData("cmap", "subtables") as $_subtable) {
                         if ($_subtable["platformID"] == 0 || $_subtable["platformID"] == 3 && $_subtable["platformSpecificID"] == 1) {
                             $subtable = $_subtable;
                             break;
                         }
                     }
                     if ($subtable) {
                         $glyphIndexArray = $subtable["glyphIndexArray"];
                         $hmtx = $font_obj->getData("hmtx");
                         unset($glyphIndexArray[0xffff]);
                         $cidtogid = str_pad('', max(array_keys($glyphIndexArray)) * 2 + 1, "");
                         $font['CIDWidths'] = array();
                         foreach ($glyphIndexArray as $cid => $gid) {
                             if ($cid >= 0 && $cid < 0xffff && $gid) {
                                 $cidtogid[$cid * 2] = chr($gid >> 8);
                                 $cidtogid[$cid * 2 + 1] = chr($gid & 0xff);
                             }
                             $width = $font_obj->normalizeFUnit(isset($hmtx[$gid]) ? $hmtx[$gid][0] : $hmtx[0][0]);
                             $font['CIDWidths'][$cid] = $width;
                         }
                         $font['CIDtoGID'] = base64_encode(gzcompress($cidtogid));
                         $font['CIDtoGID_Compressed'] = true;
                         $data = file_get_contents($tmp_name);
                     } else {
                         $data = file_get_contents($fbfile);
                     }
                     $font_obj->close();
                     unlink($tmp_name);
                 }
                 // create the font descriptor
                 $this->numObj++;
                 $fontDescriptorId = $this->numObj;
                 $this->numObj++;
                 $pfbid = $this->numObj;
                 // determine flags (more than a little flakey, hopefully will not matter much)
                 $flags = 0;
                 if ($font['ItalicAngle'] != 0) {
                     $flags += pow(2, 6);
                 }
                 if ($font['IsFixedPitch'] === 'true') {
                     $flags += 1;
                 }
                 $flags += pow(2, 5);
                 // assume non-sybolic
                 $list = array('Ascent' => 'Ascender', 'CapHeight' => 'Ascender', 'MissingWidth' => 'MissingWidth', 'Descent' => 'Descender', 'FontBBox' => 'FontBBox', 'ItalicAngle' => 'ItalicAngle');
                 $fdopt = array('Flags' => $flags, 'FontName' => $adobeFontName, 'StemV' => $stemV);
                 foreach ($list as $k => $v) {
                     if (isset($font[$v])) {
                         $fdopt[$k] = $font[$v];
                     }
                 }
                 if ($fbtype === 'pfb') {
                     $fdopt['FontFile'] = $pfbid;
                 } else {
                     if ($fbtype === 'ttf') {
                         $fdopt['FontFile2'] = $pfbid;
                     }
                 }
                 $this->o_fontDescriptor($fontDescriptorId, 'new', $fdopt);
                 // embed the font program
                 $this->o_contents($this->numObj, 'new');
                 $this->objects[$pfbid]['c'] .= $data;
                 // determine the cruicial lengths within this file
                 if ($fbtype === 'pfb') {
                     $l1 = strpos($data, 'eexec') + 6;
                     $l2 = strpos($data, '00000000') - $l1;
                     $l3 = mb_strlen($data, '8bit') - $l2 - $l1;
                     $this->o_contents($this->numObj, 'add', array('Length1' => $l1, 'Length2' => $l2, 'Length3' => $l3));
                 } else {
                     if ($fbtype == 'ttf') {
                         $l1 = mb_strlen($data, '8bit');
                         $this->o_contents($this->numObj, 'add', array('Length1' => $l1));
                     }
                 }
                 // tell the font object about all this new stuff
                 $tmp = array('BaseFont' => $adobeFontName, 'MissingWidth' => $missing_width, 'Widths' => $widthid, 'FirstChar' => $firstChar, 'LastChar' => $lastChar, 'FontDescriptor' => $fontDescriptorId);
                 if ($fbtype === 'ttf') {
                     $tmp['SubType'] = 'TrueType';
                 }
                 $this->addMessage("adding extra info to font.({$fontObj})");
                 foreach ($tmp as $fk => $fv) {
                     $this->addMessage("{$fk} : {$fv}");
                 }
                 $this->o_font($fontObj, 'add', $tmp);
             } else {
                 $this->addMessage('selectFont: pfb or ttf file not found, ok if this is one of the 14 standard fonts');
             }
             // also set the differences here, note that this means that these will take effect only the
             //first time that a font is selected, else they are ignored
             if (isset($options['differences'])) {
                 $font['differences'] = $options['differences'];
             }
         }
     }
     if ($set && isset($this->fonts[$fontName])) {
         // so if for some reason the font was not set in the last one then it will not be selected
         $this->currentBaseFont = $fontName;
         // the next lines mean that if a new font is selected, then the current text state will be
         // applied to it as well.
         $this->currentFont = $this->currentBaseFont;
         $this->currentFontNum = $this->fonts[$this->currentFont]['fontNum'];
         //$this->setCurrentFont();
     }
     return $this->currentFontNum;
     //return $this->numObj;
 }