/vendor/phenx/php-font-lib/classes/Font_Glyph_Outline_Simple.php
https://gitlab.com/techniconline/kmc · PHP · 331 lines · 249 code · 59 blank · 23 comment · 44 complexity · f132832a2f82c763f982dd197f6525fe MD5 · raw file
- <?php
- /**
- * @package php-font-lib
- * @link https://github.com/PhenX/php-font-lib
- * @author Fabien Ménager <fabien.menager@gmail.com>
- * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
- * @version $Id: Font_Table_glyf.php 46 2012-04-02 20:22:38Z fabien.menager $
- */
- /**
- * `glyf` font table.
- *
- * @package php-font-lib
- */
- class Font_Glyph_Outline_Simple extends Font_Glyph_Outline
- {
- const ON_CURVE = 0x01;
- const X_SHORT_VECTOR = 0x02;
- const Y_SHORT_VECTOR = 0x04;
- const REPEAT = 0x08;
- const THIS_X_IS_SAME = 0x10;
- const THIS_Y_IS_SAME = 0x20;
- public $instructions;
- public $points;
- function parseData()
- {
- parent::parseData();
- if (!$this->size) {
- return;
- }
- $font = $this->getFont();
- $noc = $this->numberOfContours;
- if ($noc == 0) {
- return;
- }
- $endPtsOfContours = $font->r(array(self::uint16, $noc));
- $instructionLength = $font->readUInt16();
- $this->instructions = $font->r(array(self::uint8, $instructionLength));
- $count = $endPtsOfContours[$noc - 1] + 1;
- // Flags
- $flags = array();
- for ($index = 0; $index < $count; $index++) {
- $flags[$index] = $font->readUInt8();
- if ($flags[$index] & self::REPEAT) {
- $repeats = $font->readUInt8();
- for ($i = 1; $i <= $repeats; $i++) {
- $flags[$index + $i] = $flags[$index];
- }
- $index += $repeats;
- }
- }
- $points = array();
- foreach ($flags as $i => $flag) {
- $points[$i]["onCurve"] = $flag & self::ON_CURVE;
- $points[$i]["endOfContour"] = in_array($i, $endPtsOfContours);
- }
- // X Coords
- $x = 0;
- for ($i = 0; $i < $count; $i++) {
- $flag = $flags[$i];
- if ($flag & self::THIS_X_IS_SAME) {
- if ($flag & self::X_SHORT_VECTOR) {
- $x += $font->readUInt8();
- }
- } else {
- if ($flag & self::X_SHORT_VECTOR) {
- $x -= $font->readUInt8();
- } else {
- $x += $font->readInt16();
- }
- }
- $points[$i]["x"] = $x;
- }
- // Y Coords
- $y = 0;
- for ($i = 0; $i < $count; $i++) {
- $flag = $flags[$i];
- if ($flag & self::THIS_Y_IS_SAME) {
- if ($flag & self::Y_SHORT_VECTOR) {
- $y += $font->readUInt8();
- }
- } else {
- if ($flag & self::Y_SHORT_VECTOR) {
- $y -= $font->readUInt8();
- } else {
- $y += $font->readInt16();
- }
- }
- $points[$i]["y"] = $y;
- }
- $this->points = $points;
- }
- public function splitSVGPath($path)
- {
- preg_match_all('/([a-z])|(-?\d+(?:\.\d+)?)/i', $path, $matches, PREG_PATTERN_ORDER);
- return $matches[0];
- }
- public function makePoints($path)
- {
- $path = $this->splitSVGPath($path);
- $l = count($path);
- $i = 0;
- $points = array();
- while ($i < $l) {
- switch ($path[$i]) {
- // moveTo
- case "M":
- $points[] = array(
- "onCurve" => true,
- "x" => $path[++$i],
- "y" => $path[++$i],
- "endOfContour" => false,
- );
- break;
- // lineTo
- case "L":
- $points[] = array(
- "onCurve" => true,
- "x" => $path[++$i],
- "y" => $path[++$i],
- "endOfContour" => false,
- );
- break;
- // quadraticCurveTo
- case "Q":
- $points[] = array(
- "onCurve" => false,
- "x" => $path[++$i],
- "y" => $path[++$i],
- "endOfContour" => false,
- );
- $points[] = array(
- "onCurve" => true,
- "x" => $path[++$i],
- "y" => $path[++$i],
- "endOfContour" => false,
- );
- break;
- // closePath
- /** @noinspection PhpMissingBreakStatementInspection */
- case "z":
- $points[count($points) - 1]["endOfContour"] = true;
- default:
- $i++;
- break;
- }
- }
- return $points;
- }
- function encode()
- {
- if (empty($this->points)) {
- return parent::encode();
- }
- return $this->size = $this->encodePoints($this->points);
- }
- public function encodePoints($points)
- {
- $endPtsOfContours = array();
- $flags = array();
- $coords_x = array();
- $coords_y = array();
- $last_x = 0;
- $last_y = 0;
- $xMin = $yMin = 0xFFFF;
- $xMax = $yMax = -0xFFFF;
- foreach ($points as $i => $point) {
- $flag = 0;
- if ($point["onCurve"]) {
- $flag |= self::ON_CURVE;
- }
- if ($point["endOfContour"]) {
- $endPtsOfContours[] = $i;
- }
- // Simplified, we could do some optimizations
- if ($point["x"] == $last_x) {
- $flag |= self::THIS_X_IS_SAME;
- } else {
- $x = intval($point["x"]);
- $xMin = min($x, $xMin);
- $xMax = max($x, $xMax);
- $coords_x[] = $x - $last_x; // int16
- }
- // Simplified, we could do some optimizations
- if ($point["y"] == $last_y) {
- $flag |= self::THIS_Y_IS_SAME;
- } else {
- $y = intval($point["y"]);
- $yMin = min($y, $yMin);
- $yMax = max($y, $yMax);
- $coords_y[] = $y - $last_y; // int16
- }
- $flags[] = $flag;
- $last_x = $point["x"];
- $last_y = $point["y"];
- }
- $font = $this->getFont();
- $l = 0;
- $l += $font->writeInt16(count($endPtsOfContours)); // endPtsOfContours
- $l += $font->writeFWord(isset($this->xMin) ? $this->xMin : $xMin); // xMin
- $l += $font->writeFWord(isset($this->yMin) ? $this->yMin : $yMin); // yMin
- $l += $font->writeFWord(isset($this->xMax) ? $this->xMax : $xMax); // xMax
- $l += $font->writeFWord(isset($this->yMax) ? $this->yMax : $yMax); // yMax
- // Simple glyf
- $l += $font->w(array(self::uint16, count($endPtsOfContours)), $endPtsOfContours); // endPtsOfContours
- $l += $font->writeUInt16(0); // instructionLength
- $l += $font->w(array(self::uint8, count($flags)), $flags); // flags
- $l += $font->w(array(self::int16, count($coords_x)), $coords_x); // xCoordinates
- $l += $font->w(array(self::int16, count($coords_y)), $coords_y); // yCoordinates
- return $l;
- }
- public function getSVGContours($points = null)
- {
- $path = "";
- if (!$points) {
- if (empty($this->points)) {
- $this->parseData();
- }
- $points = $this->points;
- }
- $length = count($points);
- $firstIndex = 0;
- $count = 0;
- for ($i = 0; $i < $length; $i++) {
- $count++;
- if ($points[$i]["endOfContour"]) {
- $path .= $this->getSVGPath($points, $firstIndex, $count);
- $firstIndex = $i + 1;
- $count = 0;
- }
- }
- return $path;
- }
- protected function getSVGPath($points, $startIndex, $count)
- {
- $offset = 0;
- $path = "";
- while ($offset < $count) {
- $point = $points[$startIndex + $offset % $count];
- $point_p1 = $points[$startIndex + ($offset + 1) % $count];
- if ($offset == 0) {
- $path .= "M{$point['x']},{$point['y']} ";
- }
- if ($point["onCurve"]) {
- if ($point_p1["onCurve"]) {
- $path .= "L{$point_p1['x']},{$point_p1['y']} ";
- $offset++;
- } else {
- $point_p2 = $points[$startIndex + ($offset + 2) % $count];
- if ($point_p2["onCurve"]) {
- $path .= "Q{$point_p1['x']},{$point_p1['y']},{$point_p2['x']},{$point_p2['y']} ";
- } else {
- $path .= "Q{$point_p1['x']},{$point_p1['y']}," . $this->midValue($point_p1['x'], $point_p2['x']) . "," . $this->midValue($point_p1['y'], $point_p2['y']) . " ";
- }
- $offset += 2;
- }
- } else {
- if ($point_p1["onCurve"]) {
- $path .= "Q{$point['x']},{$point['y']},{$point_p1['x']},{$point_p1['y']} ";
- } else {
- $path .= "Q{$point['x']},{$point['y']}," . $this->midValue($point['x'], $point_p1['x']) . "," . $this->midValue($point['y'], $point_p1['y']) . " ";
- }
- $offset++;
- }
- }
- $path .= "z ";
- return $path;
- }
- function midValue($a, $b)
- {
- return $a + ($b - $a) / 2;
- }
- }