/** * @param string $file * @param array $options * @return array */ public static function generate($file, array $options) { Cufon::log('Processing %s', $file); $script = new FontForgeScript(); $script->open($file); $script->flattenCID(); $script->reEncode('unicode'); $script->selectNone(); if (!empty($options['glyphs'])) { foreach ($options['glyphs'] as $glyph) { $ranges = explode(',', $glyph); foreach ($ranges as $range) { if (strpos($range, '-')) { // the range regex allows for things like 0xff-0xff-0xff, so we'll // just ignore everything between the first and last one. $points = explode('-', $range); $script->selectUnicodeRange(intval(reset($points), 16), intval(end($points), 16)); } else { $script->selectUnicode(intval($range, 16)); } } } } if (!empty($options['customGlyphs'])) { $glyphs = preg_split('//u', $options['customGlyphs'], -1, PREG_SPLIT_NO_EMPTY); foreach ($glyphs as $glyph) { $script->selectUnicode(UnicodeRange::getCodePoint($glyph)); } } $script->selectInvert(); $script->detachAndRemoveGlyphs(); $script->setFontOrder(FontForgeScript::ORDER_CUBIC); if (!$options['disableScaling']) { $script->scaleToEm($options['emSize']); } $script->selectAll(); $script->verticalFlip(0); if ($options['simplify']) { $script->simplify($options['simplifyDelta']); } $script->roundToInt(1); $svgFile = Cufon::getUnusedFilename('.svg'); Cufon::log('Converting to SVG with filename %s', $svgFile); $script->printNameIDs(); $script->generate($svgFile); $output = trim($script->execute()); $fonts = array(); $copyright = ''; if (!empty($output)) { $copyright = self::createJSDocComment("The following copyright notice may not be removed under " . "any circumstances.\n\n{$output}"); } foreach (SVGFontContainer::fromFile($svgFile, $options) as $font) { $fonts[$font->getId()] = sprintf("%s%s(%s);\n", $copyright, $options['callback'], $font->toJavaScript()); } unlink($svgFile); return $fonts; }
/** * @param string $file * @param array $options * @return array */ public static function generate($file, array $options) { Cufon::log('Processing %s', $file); $script = new FontForgeScript(); $script->open($file); $script->selectNone(); if (!empty($options['glyphs'])) { foreach ($options['glyphs'] as $glyph) { $ranges = explode(',', $glyph); foreach ($ranges as $range) { if (strpos($range, '-')) { // the range regex allows for things like 0xff-0xff-0xff, so we'll // just ignore everything between the first and last one. $points = explode('-', $range); $script->selectUnicodeRange(intval(reset($points), 16), intval(end($points), 16)); } else { $script->selectUnicode(intval($range, 16)); } } } } if (!empty($options['customGlyphs'])) { $glyphs = preg_split('//u', $options['customGlyphs'], -1, PREG_SPLIT_NO_EMPTY); foreach ($glyphs as $glyph) { // http://www.php.net/manual/en/function.ord.php#68914 $cp = unpack('N', mb_convert_encoding($glyph, 'UCS-4BE', 'UTF-8')); $script->selectUnicode($cp[1]); } } $script->selectInvert(); $script->detachAndRemoveGlyphs(); $script->setFontOrder(FontForgeScript::ORDER_CUBIC); if (!$options['disableScaling']) { $script->scaleToEm($options['emSize']); } $script->removeAllKerns(); $script->selectAll(); $script->verticalFlip(0); if ($options['simplify']) { $script->simplify($options['simplifyDelta']); } $script->roundToInt(1); $svgFile = Cufon::getUnusedFilename('.svg'); Cufon::log('Converting to SVG with filename %s', $svgFile); $script->generate($svgFile); $script->execute(); $fonts = array(); foreach (SVGFontContainer::fromFile($svgFile) as $font) { $fonts[$font->getId()] = $options['callback'] . '(' . $font->toJSON() . ');'; } unlink($svgFile); return $fonts; }
/** * @return string */ public function toJavaScript() { $font = $this->document; $fontJSON = array('w' => (int) $font['horiz-adv-x'], 'face' => array(), 'glyphs' => array(' ' => new stdClass())); $face = $font->xpath('font-face'); if (empty($face)) { return null; } foreach ($face[0]->attributes() as $key => $val) { $fontJSON['face'][$key] = $this->getSanitizedFaceValue($key, (string) $val); } $nameIndex = array(); $charIndex = array(); foreach ($font->xpath('glyph') as $glyph) { if (!isset($glyph['unicode'])) { continue; } if (mb_strlen($glyph['unicode'], 'utf-8') > 1) { // it's a ligature, for now we'll just ignore it continue; } $data = new stdClass(); if (isset($glyph['d'])) { $data->d = substr(VMLPath::fromSVG((string) $glyph['d']), 1, -2); // skip m and xe } if (isset($glyph['horiz-adv-x'])) { $data->w = (int) $glyph['horiz-adv-x']; } $char = (string) $glyph['unicode']; if (isset($glyph['glyph-name'])) { foreach (explode(',', (string) $glyph['glyph-name']) as $glyphName) { $nameIndex[$glyphName] = $char; $charIndex[$char] = $data; } } $fontJSON['glyphs'][$char] = $data; } $options = $this->container->getOptions(); $emSize = (int) $fontJSON['face']['units-per-em']; // for some extremely weird reason FontForge sometimes pumps out // astronomical kerning values. // @todo figure out what's really wrong $kerningLimit = $emSize * 2; if ($options['kerning']) { foreach ($font->xpath('hkern') as $hkern) { $k = (int) $hkern['k']; if (abs($k) > $kerningLimit) { continue; } $firstSet = array(); $secondSet = array(); if (isset($hkern['u1'])) { $firstSet = self::getMatchingCharsFromUnicodeRange((string) $hkern['u1'], $charIndex); } if (isset($hkern['g1'])) { $firstSet = array_merge($firstSet, self::getMatchingCharsFromGlyphNames((string) $hkern['g1'], $nameIndex)); } if (isset($hkern['u2'])) { $secondSet = self::getMatchingCharsFromUnicodeRange((string) $hkern['u2'], $charIndex); } if (isset($hkern['g2'])) { $secondSet = array_merge($secondSet, self::getMatchingCharsFromGlyphNames((string) $hkern['g2'], $nameIndex)); } if (!empty($secondSet)) { foreach ($firstSet as $firstGlyph) { foreach ($secondSet as $secondGlyph) { $glyph = $fontJSON['glyphs'][$firstGlyph]; if (!isset($glyph->k)) { $glyph->k = array(); } $glyph->k[$secondGlyph] = $k; } } } } } $nbsp = utf8_encode(chr(0xa0)); if (!isset($fontJSON['glyphs'][$nbsp]) && isset($fontJSON['glyphs'][' '])) { $fontJSON['glyphs'][$nbsp] = $fontJSON['glyphs'][' ']; } return self::processFont($fontJSON, $options); }