/** * 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(); }
/** * @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; }