/**
  * TODO: cache results; replace makefont with this utility
  */
 function _read($file, $encoding)
 {
     error_log(sprintf("Parsing font file file %s for encoding %s", $file, $encoding));
     $font = new OpenTypeFile();
     $font->open($file);
     $hhea = $font->getTable('hhea');
     $head = $font->getTable('head');
     $hmtx = $font->getTable('hmtx');
     $post = $font->getTable('post');
     $cmap = $font->getTable('cmap');
     $subtable = $cmap->findSubtable(OT_CMAP_PLATFORM_WINDOWS, OT_CMAP_PLATFORM_WINDOWS_UNICODE);
     /**
      * Read character widths for selected encoding
      */
     $widths = array();
     $manager = ManagerEncoding::get();
     $map = $manager->getEncodingVector($encoding);
     foreach ($map as $code => $ucs2) {
         $glyphIndex = $subtable->lookup($ucs2);
         if (!is_null($glyphIndex)) {
             $widths[$code] = floor($hmtx->_hMetrics[$glyphIndex]['advanceWidth'] * 1000 / $head->_unitsPerEm);
         } else {
             $widths[$code] = DEFAULT_CHAR_WIDTH;
         }
     }
     // Fill unknown characters with the default char width
     for ($i = 0; $i < 256; $i++) {
         if (!isset($widths[chr($i)])) {
             $widths[chr($i)] = DEFAULT_CHAR_WIDTH;
         }
     }
     $this->ascender = floor($hhea->_ascender * 1000 / $head->_unitsPerEm);
     $this->descender = floor($hhea->_descender * 1000 / $head->_unitsPerEm);
     $this->bbox = array($head->_xMin * 1000 / $head->_unitsPerEm, $head->_yMin * 1000 / $head->_unitsPerEm, $head->_xMax * 1000 / $head->_unitsPerEm, $head->_yMax * 1000 / $head->_unitsPerEm);
     $this->underline_position = floor($post->_underlinePosition * 1000 / $head->_unitsPerEm);
     $this->underline_thickness = floor($post->_underlineThickness * 1000 / $head->_unitsPerEm);
     $this->char_widths = $widths;
     $font->close();
 }
Example #2
0
/**
 * @return Array font metrics hash or null of TTF file could not be parsed
 */
function ReadTTF($fontfile, $map)
{
    if (!is_readable($fontfile)) {
        return null;
    }
    /**
     * Open font file and read metrics information
     */
    $font = new OpenTypeFile();
    $font->open($fontfile);
    $head =& $font->getTable('head');
    $name =& $font->getTable('name');
    $cmap =& $font->getTable('cmap');
    $hmtx =& $font->getTable('hmtx');
    $hhea =& $font->getTable('hhea');
    $post =& $font->getTable('post');
    $subtable =& $cmap->findSubtable(OT_CMAP_PLATFORM_WINDOWS, OT_CMAP_PLATFORM_WINDOWS_UNICODE);
    /**
     * Prepare initial data
     */
    $widths = array();
    for ($i = 0; $i < 256; $i++) {
        $code = chr($i);
        if (!isset($map[$code])) {
            $widths[] = 1000;
            continue;
        }
        $ucs2 = $map[$code];
        /**
         * If the font is monospaced, only one entry need be in the array,
         * but  that entry  is required.  The  last entry  applies to  all
         * subsequent glyphs.
         */
        $glyphIndex = $subtable->lookup($ucs2);
        if (!is_null($glyphIndex)) {
            $realIndex = min($glyphIndex, $hhea->_numberOfHMetrics - 1);
            $widths[] = floor($hmtx->_hMetrics[$realIndex]['advanceWidth'] * 1000 / $head->_unitsPerEm);
        } else {
            $widths[] = 1000;
        }
    }
    $font_info = array();
    /**
     * Here we use a hack; as, acording to OT specifications,
     *
     * When  translated  to  ASCII,  these  [...]  strings  must  be
     * identical; no  longer than 63  characters; and restricted  to the
     * printable ASCII subset,  codes 33 through 126, except  for the 10
     * characters: '[', ']', '(', ')', '{', '}', '<', '>', '/', '%'.
     *
     * we can assume that UCS-2 encoded string we receive can be easily 
     * translated to ASCII by removing the high-byte of all two-byte characters 
     */
    $ps_name_ucs2 = $name->lookup(OT_CMAP_PLATFORM_WINDOWS, OT_CMAP_PLATFORM_WINDOWS_UNICODE, OT_CMAP_LANGUAGE_WINDOWS_ENGLISH_AMERICAN, OT_NAME_ID_POSTSCRIPT_NAME);
    $ps_name_ascii = "";
    for ($i = 0; $i < strlen($ps_name_ucs2); $i += 2) {
        $ps_name_ascii .= $ps_name_ucs2[$i + 1];
    }
    $font_info['FontName'] = $ps_name_ascii;
    $font_info['Weight'] = $name->lookup(null, null, null, OT_NAME_ID_SUBFAMILY_NAME);
    $font_info['ItalicAngle'] = $post->_italicAngle;
    $font_info['IsFixedPitch'] = (bool) $post->_isFixedPitch;
    // $font_info['CapHeight']
    // $font_info['StdVW']
    $font_info['Ascender'] = floor($hhea->_ascender * 1000 / $head->_unitsPerEm);
    $font_info['Descender'] = floor($hhea->_descender * 1000 / $head->_unitsPerEm);
    $font_info['UnderlineThickness'] = floor($post->_underlineThickness * 1000 / $head->_unitsPerEm);
    $font_info['UnderlinePosition'] = floor($post->_underlinePosition * 1000 / $head->_unitsPerEm);
    $font_info['FontBBox'] = array($head->_xMin * 1000 / $head->_unitsPerEm, $head->_yMin * 1000 / $head->_unitsPerEm, $head->_xMax * 1000 / $head->_unitsPerEm, $head->_yMax * 1000 / $head->_unitsPerEm);
    $font_info['Widths'] = $widths;
    $font->_delete();
    unset($font);
    return $font_info;
}