Skip to content

Commit

Permalink
feat: add kerning tables read and write directly
Browse files Browse the repository at this point in the history
  • Loading branch information
kekee000 committed Apr 17, 2024
1 parent 466d35f commit cff7621
Show file tree
Hide file tree
Showing 18 changed files with 153 additions and 49 deletions.
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ const font = Font.create(buffer, {
type: 'ttf',
// only read `a`, `b` glyphs
subset: [65, 66],
// save font hinting
// read font hinting tables, default false
hinting: true,
// read font kerning tables, default false
kerning: true,
// transform ttf compound glyph to simple
compound2simple: true,
// inflate function for woff
Expand Down Expand Up @@ -71,8 +73,10 @@ console.log(Object.keys(fontObject));
const buffer = font.write({
// support ttf, woff, woff2, eot, svg
type: 'woff',
// save font hinting, default false
hinting: true,
// save font hinting tables, default false
hinting: false,
// save font kerning tables, default false
kerning: false,
// write glyf data when simple glyph has no contours, default false
writeZeroContoursGlyfData: false,
// deflate function for woff, eg. pako.deflate
Expand Down
9 changes: 5 additions & 4 deletions demo/js/ttfmin.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ function onUpFileChange(e) {
let file = e.target.files[0];
let reader = new FileReader();
reader.onload = function (e) {

let ttfReader = new TTFReader({
hinting: true
hinting: true,
kerning: true,
});
curttfData = ttfReader.read(e.target.result);

console.log(curttfData);
ttfmin();
};

Expand Down Expand Up @@ -69,7 +69,8 @@ function ttfmin() {
let family = 'font-with-hitting';
ttf.get().name.fontFamily = family;
let writer = new TTFWriter({
hinting: true
hinting: true,
kerning: true,
});
let buffer = writer.write(ttf.get());
setFont({
Expand Down
20 changes: 16 additions & 4 deletions demo/ttfmin.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,13 @@
div {
padding: 10px;
}

.text-title {
display: inline-block;
width: 140px;
}
.ttf-text {
font-size: 14px;
letter-spacing: 1px;
}

.ttf-min-with-hitting {
Expand All @@ -39,16 +43,24 @@
</div>
<div>
相关文字:
<input id="text" type="text" value="ABCDEFGHIJKLMNOPQRSTUVWXYZ" style="width: 400px;line-height: 30px;">
<input id="text" type="text" value="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@" style="width: 400px;line-height: 30px;">
字号:<input id="font-size" type="range" value="12" min="8" max="100" step="1">
</div>

<div>
带hinting的字体:<span class="ttf-text ttf-min-with-hitting"></span>
<span class="text-title">带hinting的字体:</span><span class="ttf-text ttf-min-with-hitting"></span>
</div>

<div>
<span class="text-title">不带hinting的字体:</span><span class="ttf-text ttf-min-without-hitting"></span>
</div>

<div>
<span class="text-title">带kerning的字体:</span><span class="ttf-text ttf-min-with-hitting"></span>
</div>

<div>
不带hinting的字体:<span class="ttf-text ttf-min-without-hitting"></span>
<span class="text-title">不带kerning的字体:</span><span class="ttf-text ttf-min-without-hitting"></span>
</div>

</body>
Expand Down
8 changes: 7 additions & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,10 +194,16 @@ export namespace FontEditor {
subset?: TTF.CodePoint[];

/**
* keep hinting or not, default false
* keep hinting table or not, default false
*/
hinting?: boolean;

/**
* keep kerning table or not, default false
* kerning table adjusting the space between individual letters or characters
*/
kerning?: boolean;

/**
* tranfrom compound glyph to simple,
* @default true
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fonteditor-core",
"version": "2.3.3",
"version": "2.4.0",
"description": "fonts (ttf, woff, woff2, eot, svg, otf) parse, write, transform, glyph adjust.",
"keywords": [
"sfnt",
Expand Down
7 changes: 4 additions & 3 deletions src/ttf/font.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ export default class Font {
* @param {string} options.type 字体类型
*
* ttf, woff , eot 读取配置
* @param {boolean} options.hinting 保留hinting信息
* @param {boolean} options.hinting 是否保留 hinting 信息
* @param {boolean} options.kerning 是否保留 kerning 信息
* @param {boolean} options.compound2simple 复合字形转简单字形
*
* woff 读取配置
Expand Down Expand Up @@ -134,8 +135,8 @@ export default class Font {
* @param {boolean} options.toBuffer nodejs 环境中返回 Buffer 对象, 默认 true
*
* ttf 字体参数
* @param {boolean} options.hinting 保留hinting信息
*
* @param {boolean} options.hinting 是否保留 hinting 信息
* @param {boolean} options.kerning 是否保留 kerning 信息
* svg,woff 字体参数
* @param {Object} options.metadata 字体相关的信息
*
Expand Down
2 changes: 1 addition & 1 deletion src/ttf/table/GPOS.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @file GPOS
* @author fr33z00(https://github.com/fr33z00)
*
* @reference: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6cvt.html
* @reference: https://learn.microsoft.com/en-us/typography/opentype/spec/gpos
*/

import table from './table';
Expand Down
2 changes: 1 addition & 1 deletion src/ttf/table/kern.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @file kern
* @author fr33z00(https://github.com/fr33z00)
*
* @reference: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6cvt.html
* @reference: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kern.html
*/

import table from './table';
Expand Down
30 changes: 30 additions & 0 deletions src/ttf/table/kerx.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* @file kerx
* @author mengke01(kekee000@gmail.com)
*
* @reference: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kerx.html
*/

import table from './table';

export default table.create(
'kerx',
[],
{

read(reader, ttf) {
const length = ttf.tables.kerx.length;
return reader.readBytes(this.offset, length);
},

write(writer, ttf) {
if (ttf.kerx) {
writer.writeBytes(ttf.kerx, ttf.kerx.length);
}
},

size(ttf) {
return ttf.kerx ? ttf.kerx.length : 0;
}
}
);
5 changes: 3 additions & 2 deletions src/ttf/table/support.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import prep from './prep';
import gasp from './gasp';
import GPOS from './GPOS';
import kern from './kern';

import kerx from './kerx';

export default {
head,
Expand All @@ -37,5 +37,6 @@ export default {
prep,
gasp,
GPOS,
kern
kern,
kerx
};
8 changes: 4 additions & 4 deletions src/ttf/table/table.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,11 +200,11 @@ export default {
* 创建一个表结构
*
* @param {string} name 表名
* @param {Object} struct 表结构
* @param {Object} prototype 原型
* @param {Array<[string, number]>} struct 表结构
* @param {Object} proto 原型
* @return {Function} 表构造函数
*/
create(name, struct, prototype) {
create(name, struct, proto) {
class Table {
constructor(offset) {
this.name = name;
Expand All @@ -217,7 +217,7 @@ export default {
Table.prototype.write = write;
Table.prototype.size = size;
Table.prototype.valueOf = valueOf;
Object.assign(Table.prototype, prototype);
Object.assign(Table.prototype, proto);
return Table;
}
};
Expand Down
11 changes: 8 additions & 3 deletions src/ttf/ttfreader.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ export default class TTFReader {
*/
constructor(options = {}) {
options.subset = options.subset || []; // 子集
options.hinting = options.hinting || false; // 不保留hints信息
options.hinting = options.hinting || false; // 默认不保留 hints 信息
options.kerning = options.kerning || false; // 默认不保留 kerning 信息
options.compound2simple = options.compound2simple || false; // 复合字形转简单字形
this.options = options;
}
Expand Down Expand Up @@ -180,13 +181,17 @@ export default class TTFReader {
delete ttf.fpgm;
delete ttf.cvt;
delete ttf.prep;
delete ttf.GPOS;
delete ttf.kern;
ttf.glyf.forEach((glyf) => {
delete glyf.instructions;
});
}

if (!this.options.hinting && !this.options.kerning) {
delete ttf.GPOS;
delete ttf.kern;
delete ttf.kerx;
}

// 复合字形转简单字形
if (this.options.compound2simple && ttf.maxp.maxComponentElements) {
ttf.glyf.forEach((glyf, index) => {
Expand Down
14 changes: 12 additions & 2 deletions src/ttf/ttfwriter.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ export default class TTFWriter {
constructor(options = {}) {
this.options = {
writeZeroContoursGlyfData: options.writeZeroContoursGlyfData || false, // 不写入空 glyf 数据
hinting: options.hinting || false, // 不保留hints信息
hinting: options.hinting || false, // 默认不保留hints信息
kerning: options.kerning || false, // 默认不保留 kernings space 信息
support: options.support // 自定义的导出表结构,可以自己修改某些表项目
};
}
Expand Down Expand Up @@ -200,14 +201,23 @@ export default class TTFWriter {
ttf.writeOptions = {};
// hinting tables direct copy
if (this.options.hinting) {
['cvt', 'fpgm', 'prep', 'gasp', 'GPOS', 'kern'].forEach((table) => {
['cvt', 'fpgm', 'prep', 'gasp', 'GPOS', 'kern', 'kerx'].forEach((table) => {
if (ttf[table]) {
tables.push(table);
}
});
}
// copy kerning space table
if (this.options.kerning) {
['GPOS', 'kern', 'kerx'].forEach((table) => {
if (ttf[table]) {
tables.push(table);
}
});
}
ttf.writeOptions.writeZeroContoursGlyfData = !!this.options.writeZeroContoursGlyfData;
ttf.writeOptions.hinting = !!this.options.hinting;
ttf.writeOptions.kerning = !!this.options.kerning;
ttf.writeOptions.tables = tables.sort();
}

Expand Down
Binary file added test/data/FiraSansMedium.ttf
Binary file not shown.
8 changes: 5 additions & 3 deletions test/example/example.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ const font = Font.create(buffer, {
type: 'ttf',
// only read 0x21, 0x22 glyphs
subset: [0x21, 0x22],
// save font hinting
// read font hinting
hinting: true,
// read font kerning
kerning: true,
// transform ttf compound glyph to simple
compound2simple: true,
// inflate function for woff
Expand Down Expand Up @@ -47,6 +49,8 @@ fs.writeFileSync(`${baseDir}/output/font.eot`, utils.toBuffer(utils.ttf2eot(util
type: 'woff',
// save font hinting
hinting: true,
// save font kerning
kerning: true,
// deflate function for woff, eg. pako.deflate
deflate: undefined,
// for user to overwrite head.xMin, head.xMax, head.yMin, head.yMax, hhea etc.
Expand All @@ -61,8 +65,6 @@ fs.writeFileSync(`${baseDir}/output/font.eot`, utils.toBuffer(utils.ttf2eot(util
const svg = font.write({
// support ttf, woff, woff2, eot, svg
type: 'svg',
// save font hinting
hinting: true,
// deflate function for woff, eg. pako.deflate
deflate: undefined,
// for user to overwrite head.xMin, head.xMax, head.yMin, head.yMax, hhea etc.
Expand Down
4 changes: 2 additions & 2 deletions test/spec/ttf/otfreader.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,10 @@ describe('read otf buffer', function () {

});

describe('read otf hinting GPOS kern', function () {
describe('read otf kerning GPOS kern', function () {
let fontObject = new OTFReader().read(readData('SFNSDisplayCondensed-Black.otf'));

it('test read hinting', function () {
it('test read kerning', function () {
assert.equal(fontObject.GPOS.length, 57290);
});

Expand Down
15 changes: 5 additions & 10 deletions test/spec/ttf/ttfreader.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,22 +86,17 @@ describe('read ttf hinting', function () {
assert.equal(fontObject.prep.length, 204);
assert.equal(fontObject.gasp.length, 8);
assert.equal(fontObject.GPOS.length, 18);
fontObject.kern && assert.equal(fontObject.kern.length, 8);
});

});

describe('read ttf hinting GPOS kern', function () {
describe('read ttf kerning GPOS kern kerx', function () {
let fontObject = new TTFReader({
hinting: true
}).read(readData('baiduHealth-hinting.ttf'));
kerning: true
}).read(readData('FiraSansMedium.ttf'));

it('test read hinting', function () {
assert.equal(fontObject.cvt.length, 24);
assert.equal(fontObject.fpgm.length, 371);
assert.equal(fontObject.prep.length, 204);
assert.equal(fontObject.gasp.length, 8);
assert.equal(fontObject.GPOS.length, 18);
it('test read kerning', function () {
assert.equal(fontObject.GPOS.length, 5960);
});

});
Expand Down

0 comments on commit cff7621

Please sign in to comment.