Skip to content

Commit 7c15d5c

Browse files
committed
Add support for composite glyph parsing and encoding
Better glyph drawing Update font viewer links
1 parent 8fadad9 commit 7c15d5c

13 files changed

+960
-802
lines changed

classes/font.cls.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public static function load($file) {
4747
}
4848

4949
if ($class) {
50+
/** @noinspection PhpIncludeInspection */
5051
require_once dirname(__FILE__)."/".strtolower($class).".cls.php";
5152

5253
/** @var Font_TrueType $obj */

classes/font_glyph_outline.cls.php

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,6 @@
1616
* @package php-font-lib
1717
*/
1818
class Font_Glyph_Outline extends Font_Binary_Stream {
19-
const ARG_1_AND_2_ARE_WORDS = 0x0001;
20-
const ARGS_ARE_XY_VALUES = 0x0002;
21-
const ROUND_XY_TO_GRID = 0x0004;
22-
const WE_HAVE_A_SCALE = 0x0008;
23-
const MORE_COMPONENTS = 0x0020;
24-
const WE_HAVE_AN_X_AND_Y_SCALE = 0x0040;
25-
const WE_HAVE_A_TWO_BY_TWO = 0x0080;
26-
const WE_HAVE_INSTRUCTIONS = 0x0100;
27-
const USE_MY_METRICS = 0x0200;
28-
const OVERLAP_COMPOUND = 0x0400;
29-
3019
/**
3120
* @var Font_Table_glyf
3221
*/
@@ -95,7 +84,7 @@ function parse() {
9584
function parseData(){
9685
$font = $this->getFont();
9786
$font->seek($this->offset);
98-
87+
9988
$this->numberOfContours = $font->readInt16();
10089
$this->xMin = $font->readFWord();
10190
$this->yMin = $font->readFWord();
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
/**
3+
* @package php-font-lib
4+
* @link https://github.com/PhenX/php-font-lib
5+
* @author Fabien Ménager <[email protected]>
6+
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7+
* @version $Id: font_table_glyf.cls.php 46 2012-04-02 20:22:38Z fabien.menager $
8+
*/
9+
10+
/**
11+
* Glyph outline component
12+
*
13+
* @package php-font-lib
14+
*/
15+
class Font_Glyph_Outline_Component {
16+
public $flags;
17+
public $glyphIndex;
18+
public $a, $b, $c, $d, $e, $f;
19+
public $point_compound;
20+
public $point_component;
21+
public $instructions;
22+
}
Lines changed: 225 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,226 @@
1-
<?php
2-
/**
3-
* @package php-font-lib
4-
* @link https://github.com/PhenX/php-font-lib
5-
* @author Fabien Ménager <[email protected]>
6-
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7-
* @version $Id: font_table_glyf.cls.php 46 2012-04-02 20:22:38Z fabien.menager $
8-
*/
9-
10-
/**
11-
* `glyf` font table.
12-
*
13-
* @package php-font-lib
14-
*/
15-
class Font_Glyph_Outline_Composite extends Font_Glyph_Outline {
16-
public $flags;
17-
public $glyphIndex;
18-
19-
function parseData(){
20-
parent::parseData();
21-
22-
$font = $this->getFont();
23-
24-
$this->flags = $font->readUInt16();
25-
$this->glyphIndex = $font->readUInt16();
26-
}
1+
<?php
2+
/**
3+
* @package php-font-lib
4+
* @link https://github.com/PhenX/php-font-lib
5+
* @author Fabien Ménager <[email protected]>
6+
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
7+
* @version $Id: font_table_glyf.cls.php 46 2012-04-02 20:22:38Z fabien.menager $
8+
*/
9+
10+
require_once dirname(__FILE__)."/font_glyph_outline_component.cls.php";
11+
12+
/**
13+
* Composite glyph outline
14+
*
15+
* @package php-font-lib
16+
*/
17+
class Font_Glyph_Outline_Composite extends Font_Glyph_Outline {
18+
const ARG_1_AND_2_ARE_WORDS = 0x0001;
19+
const ARGS_ARE_XY_VALUES = 0x0002;
20+
const ROUND_XY_TO_GRID = 0x0004;
21+
const WE_HAVE_A_SCALE = 0x0008;
22+
const MORE_COMPONENTS = 0x0020;
23+
const WE_HAVE_AN_X_AND_Y_SCALE = 0x0040;
24+
const WE_HAVE_A_TWO_BY_TWO = 0x0080;
25+
const WE_HAVE_INSTRUCTIONS = 0x0100;
26+
const USE_MY_METRICS = 0x0200;
27+
const OVERLAP_COMPOUND = 0x0400;
28+
29+
/**
30+
* @var Font_Glyph_Outline_Component[]
31+
*/
32+
public $components = array();
33+
34+
function getGlyphIDs(){
35+
if (empty($this->components)) {
36+
$this->parseData();
37+
}
38+
39+
$glyphIDs = array();
40+
foreach ($this->components as $_component) {
41+
$glyphIDs[] = $_component->glyphIndex;
42+
}
43+
44+
return $glyphIDs;
45+
}
46+
47+
/*function parse() {
48+
//$this->parseData();
49+
}*/
50+
51+
function parseData(){
52+
parent::parseData();
53+
54+
$font = $this->getFont();
55+
56+
do {
57+
$flags = $font->readUInt16();
58+
$glyphIndex = $font->readUInt16();
59+
60+
$a = 1.0; $b = 0.0;
61+
$c = 0.0; $d = 1.0;
62+
$e = 0.0; $f = 0.0;
63+
64+
$point_compound = null;
65+
$point_component = null;
66+
67+
$instructions = null;
68+
69+
if ($flags & self::ARG_1_AND_2_ARE_WORDS) {
70+
if ($flags & self::ARGS_ARE_XY_VALUES) {
71+
$e = $font->readInt16();
72+
$f = $font->readInt16();
73+
}
74+
else {
75+
$point_compound = $font->readUInt16();
76+
$point_component = $font->readUInt16();
77+
}
78+
}
79+
else {
80+
if ($flags & self::ARGS_ARE_XY_VALUES) {
81+
$e = $font->readInt8();
82+
$f = $font->readInt8();
83+
}
84+
else {
85+
$point_compound = $font->readUInt8();
86+
$point_component = $font->readUInt8();
87+
}
88+
}
89+
90+
if ($flags & self::WE_HAVE_A_SCALE) {
91+
$a = $d = $font->readInt16();
92+
}
93+
elseif ($flags & self::WE_HAVE_AN_X_AND_Y_SCALE) {
94+
$a = $font->readInt16();
95+
$d = $font->readInt16();
96+
}
97+
elseif ($flags & self::WE_HAVE_A_TWO_BY_TWO) {
98+
$a = $font->readInt16();
99+
$b = $font->readInt16();
100+
$c = $font->readInt16();
101+
$d = $font->readInt16();
102+
}
103+
104+
//if ($flags & self::WE_HAVE_INSTRUCTIONS) {
105+
//
106+
//}
107+
108+
$component = new Font_Glyph_Outline_Component();
109+
$component->flags = $flags;
110+
$component->glyphIndex = $glyphIndex;
111+
$component->a = $a;
112+
$component->b = $b;
113+
$component->c = $c;
114+
$component->d = $d;
115+
$component->e = $e;
116+
$component->f = $f;
117+
$component->point_compound = $point_compound;
118+
$component->point_component = $point_component;
119+
$component->instructions = $instructions;
120+
121+
$this->components[] = $component;
122+
123+
} while ($flags & self::MORE_COMPONENTS);
124+
}
125+
126+
function encode(){
127+
$font = $this->getFont();
128+
129+
$gids = array_values($font->getSubset());
130+
131+
$size = $font->writeInt16(-1);
132+
$size += $font->writeFWord($this->xMin);
133+
$size += $font->writeFWord($this->yMin);
134+
$size += $font->writeFWord($this->xMax);
135+
$size += $font->writeFWord($this->yMax);
136+
137+
foreach ($this->components as $_i => $_component) {
138+
$flags = 0;
139+
if ($_component->point_component === null && $_component->point_compound === null) {
140+
$flags |= self::ARGS_ARE_XY_VALUES;
141+
142+
if (abs($_component->e) > 0x7F || abs($_component->f) > 0x7F) {
143+
$flags |= self::ARG_1_AND_2_ARE_WORDS;
144+
}
145+
}
146+
elseif ($_component->point_component > 0xFF || $_component->point_compound > 0xFF) {
147+
$flags |= self::ARG_1_AND_2_ARE_WORDS;
148+
}
149+
150+
if ($_component->b == 0 && $_component->c == 0) {
151+
if ($_component->a == $_component->d) {
152+
if ($_component->a != 1.0) {
153+
$flags |= self::WE_HAVE_A_SCALE;
154+
}
155+
}
156+
else {
157+
$flags |= self::WE_HAVE_AN_X_AND_Y_SCALE;
158+
}
159+
}
160+
else {
161+
$flags |= self::WE_HAVE_A_TWO_BY_TWO;
162+
}
163+
164+
if ($_i < count($this->components)-1) {
165+
$flags |= self::MORE_COMPONENTS;
166+
}
167+
168+
$size += $font->writeUInt16($flags);
169+
170+
$new_gid = array_search($_component->glyphIndex, $gids);
171+
$size += $font->writeUInt16($new_gid);
172+
173+
if ($flags & self::ARG_1_AND_2_ARE_WORDS) {
174+
if ($flags & self::ARGS_ARE_XY_VALUES) {
175+
$size += $font->writeInt16($_component->e);
176+
$size += $font->writeInt16($_component->f);
177+
}
178+
else {
179+
$size += $font->writeUInt16($_component->point_compound);
180+
$size += $font->writeUInt16($_component->point_component);
181+
}
182+
}
183+
else {
184+
if ($flags & self::ARGS_ARE_XY_VALUES) {
185+
$size += $font->writeInt8($_component->e);
186+
$size += $font->writeInt8($_component->f);
187+
}
188+
else {
189+
$size += $font->writeUInt8($_component->point_compound);
190+
$size += $font->writeUInt8($_component->point_component);
191+
}
192+
}
193+
194+
if ($flags & self::WE_HAVE_A_SCALE) {
195+
$size += $font->writeInt16($_component->a);
196+
}
197+
elseif ($flags & self::WE_HAVE_AN_X_AND_Y_SCALE) {
198+
$size += $font->writeInt16($_component->a);
199+
$size += $font->writeInt16($_component->d);
200+
}
201+
elseif ($flags & self::WE_HAVE_A_TWO_BY_TWO) {
202+
$size += $font->writeInt16($_component->a);
203+
$size += $font->writeInt16($_component->b);
204+
$size += $font->writeInt16($_component->c);
205+
$size += $font->writeInt16($_component->d);
206+
}
207+
}
208+
209+
return $size;
210+
}
211+
212+
public function getSVGContours(){
213+
$path = "";
214+
215+
/** @var Font_Table_glyf $glyph_data */
216+
$glyph_data = $this->getFont()->getTableObject("glyf");
217+
218+
$glyphs = $glyph_data->data;
219+
220+
foreach ($this->components as $component) {
221+
$path .= $glyphs[$component->glyphIndex]->getSVGContours();
222+
}
223+
224+
return $path;
225+
}
27226
}

0 commit comments

Comments
 (0)