mirror of
https://github.com/keymanapp/keyman.git
synced 2026-09-25 00:57:42 +00:00
Merge pull request #11634 from keymanapp/fix/developer/cherry-pick/11625-11630-ttfmeta-to-stable
fix(developer): support Windows and Unicode names in .ttf 🍒 🏠
This commit is contained in:
commit
8fa82ac999
14 changed files with 677 additions and 14 deletions
|
|
@ -25,8 +25,7 @@
|
|||
"dependencies": {
|
||||
"@keymanapp/common-types": "*",
|
||||
"@keymanapp/developer-utils": "*",
|
||||
"@keymanapp/kmc-package": "*",
|
||||
"ttfmeta": "^1.1.2"
|
||||
"@keymanapp/kmc-package": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.3.5",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import ttfMeta from 'ttfmeta';
|
||||
import ttfMeta from './ttfmeta/lib/index.js';
|
||||
|
||||
/**
|
||||
* Extracts the font-family from an in-memory TTF or WOFF blob in `source`
|
||||
|
|
@ -7,7 +7,7 @@ import ttfMeta from 'ttfmeta';
|
|||
* @param source In-memory TTF or WOFF font blob
|
||||
*
|
||||
* @throws Uncaught exceptions from ttfMeta.promise if the font file is invalid.
|
||||
*
|
||||
*
|
||||
* @returns If the file is invalid or cannot be parsed, returns `null`,
|
||||
* otherwise returns the font family as a string.
|
||||
*/
|
||||
|
|
|
|||
21
developer/src/kmc-keyboard-info/src/ttfmeta/LICENSE
Normal file
21
developer/src/kmc-keyboard-info/src/ttfmeta/LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2021 Khen Solomon Lethil
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
1
developer/src/kmc-keyboard-info/src/ttfmeta/README.md
Normal file
1
developer/src/kmc-keyboard-info/src/ttfmeta/README.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
This was originally npmjs package ttfmeta. The source has been deleted from GitHub, so we will now using it locally so we can maintain it.
|
||||
52
developer/src/kmc-keyboard-info/src/ttfmeta/lib/index.js
Normal file
52
developer/src/kmc-keyboard-info/src/ttfmeta/lib/index.js
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
* ttfmeta
|
||||
* Copyright(c) 2021-2022 Khen Solomon Lethil
|
||||
* MIT Licensed
|
||||
* v1.0.9
|
||||
*/
|
||||
|
||||
import * as fs from "fs";
|
||||
import * as ttf from "./main.js";
|
||||
|
||||
/**
|
||||
* @namespace
|
||||
* @param {string | number | Buffer | URL} pathOrData
|
||||
* @param {{(error:string|null,meta?:typeof ttf.result):void}} callback
|
||||
*/
|
||||
export function ttfInfo(pathOrData, callback) {
|
||||
try {
|
||||
if (pathOrData instanceof Buffer) {
|
||||
ttf.ttfInfo(ttf.view(pathOrData), callback);
|
||||
} else {
|
||||
fs.readFile(pathOrData, function(error, data) {
|
||||
if (error) {
|
||||
callback(error.message || error.toString());
|
||||
} else {
|
||||
ttf.ttfInfo(ttf.view(data), callback);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (/** @type {any}*/ error) {
|
||||
callback(error.message || error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string | number | Buffer | URL} pathOrData
|
||||
* @returns {Promise<typeof ttf.result>}
|
||||
*/
|
||||
export function promise(pathOrData) {
|
||||
return new Promise(function(res, rej) {
|
||||
ttfInfo(pathOrData, function(e, d) {
|
||||
if (d) {
|
||||
res(d);
|
||||
} else {
|
||||
rej(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** @namespace */
|
||||
export const ttfMeta = { ttfInfo, promise };
|
||||
export default ttfMeta;
|
||||
317
developer/src/kmc-keyboard-info/src/ttfmeta/lib/main.js
Normal file
317
developer/src/kmc-keyboard-info/src/ttfmeta/lib/main.js
Normal file
|
|
@ -0,0 +1,317 @@
|
|||
import property from './meta.js';
|
||||
|
||||
const TABLE_COUNT_OFFSET = 4,
|
||||
TABLE_HEAD_OFFSET = 12,
|
||||
TABLE_HEAD_SIZE = 16,
|
||||
TAG_OFFSET = 0,
|
||||
TAG_SIZE = 4,
|
||||
CHECKSUM_OFFSET = TAG_OFFSET + TAG_SIZE,
|
||||
CHECKSUM_SIZE = 4,
|
||||
CONTENTS_PTR_OFFSET = CHECKSUM_OFFSET + CHECKSUM_SIZE,
|
||||
CONTENTS_PTR_SIZE = 4,
|
||||
LENGTH_OFFSET = TABLE_HEAD_SIZE + CONTENTS_PTR_OFFSET;
|
||||
|
||||
/**
|
||||
* org: count
|
||||
* @param {*} data
|
||||
*/
|
||||
function offsetCount(data) {
|
||||
return u16(data,TABLE_COUNT_OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* org: offset
|
||||
* @param {*} data
|
||||
* @param {string} name
|
||||
*/
|
||||
function offsetContent(data, name) {
|
||||
return offsetData(data, name).contents;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} data
|
||||
* @param {string} name
|
||||
* @returns {{tag:any,checksum:any,contents:any,length:any}}
|
||||
*/
|
||||
function offsetData(data, name) {
|
||||
var numTables = offsetCount(data);
|
||||
var header={
|
||||
tag: '',
|
||||
checksum: '',
|
||||
contents: '',
|
||||
length: ''
|
||||
};
|
||||
|
||||
for (var i = 0; i < numTables; ++i) {
|
||||
var o = TABLE_HEAD_OFFSET + i * TABLE_HEAD_SIZE;
|
||||
var tag = utf8(data.buffer.slice(o, o + CONTENTS_PTR_SIZE));
|
||||
|
||||
if (tag === name) {
|
||||
header.tag= tag,
|
||||
header.checksum= u32(data,o + CHECKSUM_OFFSET),
|
||||
header.contents= u32(data,o + CONTENTS_PTR_OFFSET),
|
||||
header.length= u32(data,o + LENGTH_OFFSET)
|
||||
return header;
|
||||
}
|
||||
}
|
||||
return header
|
||||
}
|
||||
|
||||
/**
|
||||
* org: tableName.js
|
||||
* @param {*} data
|
||||
*/
|
||||
function name(data) {
|
||||
var ntOffset = offsetContent(data, 'name'),
|
||||
offsetStorage = u16(data,ntOffset+4),
|
||||
numberNameRecords = u16(data,ntOffset+2);
|
||||
|
||||
var storage = offsetStorage + ntOffset;
|
||||
|
||||
/**
|
||||
* @type {any}
|
||||
*/
|
||||
var info = {};
|
||||
|
||||
for (var j = 0; j < numberNameRecords; j++) {
|
||||
var o = ntOffset + 6 + j*12;
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
var platformId = u16(data,o);
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
var encodingId = u16(data,o+2);
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
// var languageId = u16(data,o+4);
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
var nameId = u16(data,o+6);
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
var stringLength = u16(data,o+8);
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
var stringOffset = u16(data,o+10);
|
||||
|
||||
if (!info.hasOwnProperty(nameId)) {
|
||||
let decoder = null;
|
||||
if(platformId == 0) { // unicode
|
||||
decoder = utf16be;
|
||||
} else if(platformId == 1) { // macintosh
|
||||
if(encodingId == 0) decoder = macroman;
|
||||
} else if(platformId == 3) { // windows
|
||||
decoder = utf16be;
|
||||
}
|
||||
|
||||
if(!decoder) {
|
||||
throw new Error(`Unspecified platform ${platformId} and encoding ${encodingId} for font`);
|
||||
} else {
|
||||
info[nameId] = decoder(data.buffer.slice(storage+stringOffset, storage+stringOffset+stringLength));
|
||||
}
|
||||
|
||||
// info[nameId] = '';
|
||||
// for (var k = 0; k < stringLength; k++) {
|
||||
// var charCode = data.getInt8(storage+stringOffset+k);
|
||||
// if (charCode === 0) continue;
|
||||
// info[nameId] += String.fromCharCode(charCode);
|
||||
// }
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
const VERSION_OFFSET = 0, WEIGHT_CLASS_OFFSET = 4;
|
||||
|
||||
/**
|
||||
* org: tableOS2.js
|
||||
* @param {*} data
|
||||
*/
|
||||
function os2(data) {
|
||||
var o = offsetContent(data, 'OS/2');
|
||||
return {
|
||||
version : u16(data,o+VERSION_OFFSET),
|
||||
weightClass : u16(data,o+WEIGHT_CLASS_OFFSET)
|
||||
};
|
||||
}
|
||||
|
||||
const FORMAT_OFFSET = 0,
|
||||
ITALIC_ANGLE_OFFSET = FORMAT_OFFSET + 4,
|
||||
UNDERLINE_POSITION_OFFSET = ITALIC_ANGLE_OFFSET + 8,
|
||||
UNDERLINE_THICKNESS_OFFSET = UNDERLINE_POSITION_OFFSET + 2,
|
||||
IS_FIXED_PITCH_OFFSET = UNDERLINE_THICKNESS_OFFSET + 2;
|
||||
|
||||
export const result = {
|
||||
meta:{
|
||||
/**
|
||||
* @type {{name:string,text:string}[]}
|
||||
*/
|
||||
property:[],
|
||||
/**
|
||||
* @type {{name:string,text:string}[]}
|
||||
*/
|
||||
description:[],
|
||||
/**
|
||||
* @type {{name:string,text:string}[]}
|
||||
*/
|
||||
license:[],
|
||||
/**
|
||||
* @type {{name:string,text:string}[]}
|
||||
*/
|
||||
reference:[]
|
||||
},
|
||||
tables: {
|
||||
name: {},
|
||||
post: {},
|
||||
os2: {
|
||||
version:'',weightClass:''
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {*} fixed
|
||||
* org: fixed16dot16
|
||||
*/
|
||||
function f32(fixed) {
|
||||
if (fixed & 0x80000000) {
|
||||
// negative number is stored in two's complement
|
||||
fixed = -(~fixed + 1);
|
||||
}
|
||||
return fixed / 65536;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} data
|
||||
* @param {number} pos
|
||||
*/
|
||||
function i16(data,pos) {
|
||||
// return data.readInt16BE(pos);
|
||||
return data.getInt16(pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} data
|
||||
* @param {number} pos
|
||||
*/
|
||||
function u16(data,pos) {
|
||||
// return data.readUInt16BE(pos);
|
||||
return data.getUint16(pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} data
|
||||
* @param {number} pos
|
||||
*/
|
||||
function u32(data,pos) {
|
||||
// return data.readUInt32BE(pos);
|
||||
return data.getUint32(pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} str
|
||||
* @returns string
|
||||
*/
|
||||
function utf8(str) {
|
||||
// return new TextDecoder("utf-8").decode(new Uint16Array(str));
|
||||
return new TextDecoder("utf-8").decode(new Uint8Array(str));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} str
|
||||
* @returns string
|
||||
*/
|
||||
function utf16be(str) {
|
||||
return new TextDecoder("utf-16be").decode(new Uint8Array(str));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} str
|
||||
* @returns string
|
||||
*/
|
||||
function macroman(str) {
|
||||
return new TextDecoder("mac").decode(new Uint8Array(str));
|
||||
}
|
||||
|
||||
/**
|
||||
* org: tablePost.js
|
||||
* @param {*} data
|
||||
*/
|
||||
function post(data) {
|
||||
var o = offsetContent(data, 'post');
|
||||
return {
|
||||
format : f32(u32(data,o+FORMAT_OFFSET)),
|
||||
italicAngle : f32(u32(data,o+ITALIC_ANGLE_OFFSET)),
|
||||
|
||||
underlinePosition : i16(data,o+UNDERLINE_POSITION_OFFSET),
|
||||
underlineThickness: i16(data,o+UNDERLINE_THICKNESS_OFFSET),
|
||||
|
||||
isFixedPitch : u32(data,o+IS_FIXED_PITCH_OFFSET),
|
||||
minMemType42 : u32(data,o+7),
|
||||
maxMemType42 : u32(data,o+9),
|
||||
minMemType1 : u32(data,o+11),
|
||||
maxMemType1 : u32(data,o+13)
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} data
|
||||
* param {CallableFunction} callback
|
||||
*/
|
||||
function resultTables(data) {
|
||||
result.tables.name = name(data);
|
||||
result.tables.post = post(data);
|
||||
result.tables.os2 = os2(data);
|
||||
result.meta = property(result.tables.name);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Buffer} data
|
||||
* @return {DataView}
|
||||
*/
|
||||
export function view(data) {
|
||||
return new DataView(data.buffer, 0, data.byteLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* @namespace
|
||||
* @param {*} data
|
||||
* @param {{(error:string|null,meta?:typeof result):void}} callback
|
||||
*/
|
||||
export function ttfInfo(data, callback) {
|
||||
try {
|
||||
// let dataview = new DataView(data.buffer, 0, data.length);
|
||||
resultTables(data);
|
||||
callback(null,result);
|
||||
} catch (/** @type {any}*/error) {
|
||||
callback(error.message || error.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string | number | Buffer | URL | DataView} pathOrData
|
||||
* @returns {Promise<typeof result>}
|
||||
*/
|
||||
export function promise(pathOrData){
|
||||
return new Promise(function(res,rej){
|
||||
ttfInfo(pathOrData, function(e,d){
|
||||
if (d) {
|
||||
res(d);
|
||||
} else {
|
||||
rej(e);
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
113
developer/src/kmc-keyboard-info/src/ttfmeta/lib/meta.js
Normal file
113
developer/src/kmc-keyboard-info/src/ttfmeta/lib/meta.js
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/**
|
||||
* @type {Object.<number, string>}
|
||||
*/
|
||||
const tpl = {
|
||||
0: 'Copyright',
|
||||
1: 'Font Family',
|
||||
2: 'Font Subfamily',
|
||||
3: 'Unique identifier',
|
||||
4: 'Full name',
|
||||
5: 'Version',
|
||||
6: 'Postscript name',
|
||||
7: 'Note',
|
||||
8: 'Company',
|
||||
9: 'Author',
|
||||
10: 'Description',
|
||||
11: 'URL',
|
||||
12: 'URL',
|
||||
13: 'License',
|
||||
14: 'URL',
|
||||
// 15: '',
|
||||
16: 'Name'
|
||||
// 17: ''
|
||||
};
|
||||
|
||||
const tagName = (text='') => /^[^a-z]*$/.test(text)?text.split(' ').length>4?'paragraph':'title':'paragraph';
|
||||
/**
|
||||
* format meta.tables.name, property description license, reference
|
||||
* @param {{[k: string]: string}} e
|
||||
*/
|
||||
export default function (e){
|
||||
var meta={
|
||||
/**
|
||||
* @type {{name:string,text:string}[]}
|
||||
*/
|
||||
property:[],
|
||||
/**
|
||||
* @type {{name:string,text:string}[]}
|
||||
*/
|
||||
description:[],
|
||||
/**
|
||||
* @type {{name:string,text:string}[]}
|
||||
*/
|
||||
license:[],
|
||||
/**
|
||||
* @type {{name:string,text:string}[]}
|
||||
*/
|
||||
reference:[]
|
||||
};
|
||||
|
||||
for (const key in e) {
|
||||
if (e.hasOwnProperty(key)) {
|
||||
const i = parseInt(key);
|
||||
/**
|
||||
* @type {keyof typeof tpl}
|
||||
*/
|
||||
var tplId = (i);
|
||||
const context = e[i].trim();
|
||||
var pA = context.replace('~\r\n?~', "\n").split('\n').map(i=>i.trim()).filter( i => i);
|
||||
if (pA.length > 1) {
|
||||
/**
|
||||
* @type {keyof typeof meta}
|
||||
*/
|
||||
var id = (i == 10)?'description':'license';
|
||||
meta[id]=[];
|
||||
for (const eP in pA) {
|
||||
if (pA.hasOwnProperty(eP)) {
|
||||
var text = pA[eP].trim();
|
||||
meta[id].push({name:tagName(text),text:text});
|
||||
}
|
||||
}
|
||||
} else if(context) {
|
||||
if (/^s?https?:\/\/[-_.!~*'()a-zA-Z0-9;\/?:\@&=+\$,%#]+$/.test(context)){
|
||||
var has = meta.reference.findIndex(a => a.text == context);
|
||||
if (has < 0) {
|
||||
meta.reference.push({name:'url',text:context});
|
||||
}
|
||||
} else if (i > 0 && i < 6) {
|
||||
var name = tpl[tplId].replace(' ','-').toLowerCase();
|
||||
meta.property.push({name: name, text: context});
|
||||
} else {
|
||||
if (tpl.hasOwnProperty(i)){
|
||||
if (i == 0 || i == 7) {
|
||||
var pA = context.replace(/---+/, "\n").split('\n').map(i=>i.trim()).filter( i => i);
|
||||
for (const eP in pA) {
|
||||
if (pA.hasOwnProperty(eP)) {
|
||||
var text = pA[eP].trim();
|
||||
meta.description.push({name:tagName(text),text:text});
|
||||
}
|
||||
}
|
||||
} else if (i == 13) {
|
||||
meta.license.push({name:tagName(context), text: context});
|
||||
} else {
|
||||
|
||||
var name = tpl[tplId].replace(' ','-').toLowerCase();
|
||||
meta.property.push({name:name, text: context});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if (i == 1) {
|
||||
// meta.title =context.replace('_',' ');
|
||||
// meta.keywords = context.replace('_',',');
|
||||
// meta.description = context;
|
||||
// } else if (i == 7 && context) {
|
||||
// meta.description = context;
|
||||
// } else if (i == 4 && context) {
|
||||
// meta.description = context;
|
||||
// }
|
||||
}
|
||||
}
|
||||
return meta;
|
||||
}
|
||||
45
developer/src/kmc-keyboard-info/src/ttfmeta/test/local.mjs
Normal file
45
developer/src/kmc-keyboard-info/src/ttfmeta/test/local.mjs
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
import fs from "fs";
|
||||
import ttfMeta from "../index.mjs";
|
||||
|
||||
// var fontFile = '/storage/media/fonts/secondary/winuniiw.ttf';
|
||||
// var fontFile = './assets/font/Myanmar3.ttf';
|
||||
var fontFile = "./assets/font/ttfmeta.ttf";
|
||||
// var fontFile = '/storage/media/fonts/secondary/m-myanmar1.TTF';
|
||||
// var fontFile = '/Windows/Fonts/AdobeHeitiStd-Regular.otf';
|
||||
// var fontFile = '/Windows/Fonts/BirchStd.otf';
|
||||
|
||||
/**
|
||||
* send file
|
||||
*/
|
||||
ttfMeta
|
||||
.promise(fontFile)
|
||||
.then((e) => console.log(e))
|
||||
.catch((e) => console.log("error", e));
|
||||
|
||||
/**
|
||||
* custom read and send buffer for callback
|
||||
*/
|
||||
fs.readFile(fontFile, function(err, buffer) {
|
||||
if (err) {
|
||||
console.log("err", err);
|
||||
} else {
|
||||
ttfMeta.ttfInfo(buffer, function(err, info) {
|
||||
console.log("error", err);
|
||||
console.log("info", info);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* custom read and send buffer for promise
|
||||
*/
|
||||
fs.readFile(fontFile, function(err, buffer) {
|
||||
if (err) {
|
||||
console.log("err", err);
|
||||
} else {
|
||||
ttfMeta
|
||||
.promise(buffer)
|
||||
.then((e) => console.log(e))
|
||||
.catch((e) => console.log("error", e));
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
import "mocha";
|
||||
import fs from "fs";
|
||||
import assert from "assert";
|
||||
import ttfMeta from "../index.mjs";
|
||||
|
||||
const fontFile = "./assets/font/Myanmar3.ttf";
|
||||
|
||||
describe("ttfMeta", () => {
|
||||
it("Using callback", () => {
|
||||
ttfMeta.ttfInfo(fontFile, function(err, info) {
|
||||
assert.strictEqual(null, err);
|
||||
|
||||
// assert.strictEqual(7,Object.keys(info.tables.name).length);
|
||||
assert.strictEqual(9, Object.keys(info.tables.post).length);
|
||||
assert.strictEqual(2, Object.keys(info.tables.os2).length);
|
||||
});
|
||||
});
|
||||
|
||||
it("Using promise", () => {
|
||||
ttfMeta.promise(fontFile).then(function(info) {
|
||||
// assert.strictEqual(7,Object.keys(info.tables.name).length);
|
||||
assert.strictEqual(9, Object.keys(info.tables.post).length);
|
||||
assert.strictEqual(2, Object.keys(info.tables.os2).length);
|
||||
});
|
||||
});
|
||||
|
||||
it("Returning object has meta property", () => {
|
||||
ttfMeta.promise(fontFile).then(function(info) {
|
||||
assert.strictEqual(4, Object.keys(info.meta).length);
|
||||
|
||||
assert.ok(info.meta.property);
|
||||
assert.ok(info.meta.license);
|
||||
assert.ok(info.meta.reference);
|
||||
assert.ok(info.meta.description);
|
||||
});
|
||||
});
|
||||
|
||||
it("Expecting error on ttfMeta.ttfInfo callback", () => {
|
||||
ttfMeta.ttfInfo("./test/none.ttf", function(error) {
|
||||
assert.ok(error);
|
||||
assert.strictEqual("string", typeof error);
|
||||
});
|
||||
});
|
||||
|
||||
it("Expecting error on ttfMeta.promise", () => {
|
||||
ttfMeta
|
||||
.promise("./test/none.ttf")
|
||||
.then(function(info) {
|
||||
assert.throws(info);
|
||||
})
|
||||
.catch(function(error) {
|
||||
assert.ok(error);
|
||||
assert.strictEqual("string", typeof error);
|
||||
});
|
||||
});
|
||||
|
||||
it("Reading from Buffer", () => {
|
||||
fs.readFile(fontFile, function(err, buffer) {
|
||||
if (err) {
|
||||
throw err;
|
||||
} else {
|
||||
ttfMeta
|
||||
.promise(buffer)
|
||||
.then(function(info) {
|
||||
assert.ok(info);
|
||||
})
|
||||
.catch(function(error) {
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
BIN
developer/src/kmc-keyboard-info/test/fixtures/afghan_turkmen/Lateef-Bold.ttf
vendored
Normal file
BIN
developer/src/kmc-keyboard-info/test/fixtures/afghan_turkmen/Lateef-Bold.ttf
vendored
Normal file
Binary file not shown.
BIN
developer/src/kmc-keyboard-info/test/fixtures/afghan_turkmen/Lateef-Regular.ttf
vendored
Normal file
BIN
developer/src/kmc-keyboard-info/test/fixtures/afghan_turkmen/Lateef-Regular.ttf
vendored
Normal file
Binary file not shown.
50
developer/src/kmc-keyboard-info/test/test-font-family.ts
Normal file
50
developer/src/kmc-keyboard-info/test/test-font-family.ts
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import * as fs from 'fs';
|
||||
import { assert } from 'chai';
|
||||
import 'mocha';
|
||||
import { makePathToFixture } from './helpers/index.js';
|
||||
import { getFontFamily } from '../src/font-family.js';
|
||||
|
||||
const AFGHAN_TURKMEN_DISPLAY_FONT = makePathToFixture('afghan_turkmen', "Lateef-Regular.ttf");
|
||||
const AFGHAN_TURKMEN_OSK_FONT = makePathToFixture('afghan_turkmen', "Lateef-Bold.ttf");
|
||||
|
||||
const AFGHAN_TURKMEN_DISPLAY_FACE_NAME = "Lateef";
|
||||
const AFGHAN_TURKMEN_OSK_FACE_NAME = "Lateef";
|
||||
|
||||
describe('font-family', function () {
|
||||
it('correctly reads font facename from TrueType font file', async function() {
|
||||
// #11625
|
||||
const displayFontData: Uint8Array = fs.readFileSync(AFGHAN_TURKMEN_DISPLAY_FONT);
|
||||
const displayFacename = await getFontFamily(displayFontData);
|
||||
assert.equal(displayFacename, AFGHAN_TURKMEN_DISPLAY_FACE_NAME);
|
||||
|
||||
const oskFontData: Uint8Array = fs.readFileSync(AFGHAN_TURKMEN_OSK_FONT);
|
||||
const oskFacename = await getFontFamily(oskFontData);
|
||||
assert.equal(oskFacename, AFGHAN_TURKMEN_OSK_FACE_NAME);
|
||||
});
|
||||
|
||||
it.skip('can read all font files in keyboards repo', async function() {
|
||||
this.timeout(100000);
|
||||
async function testFonts(path: string) {
|
||||
const files = fs.readdirSync(path);
|
||||
for(const file of files) {
|
||||
if(fs.statSync(path + file).isDirectory()) {
|
||||
await testFonts(path + file + '/');
|
||||
} else if(file.match(/\.(ttf|otf)$/i)) {
|
||||
await testFont(path + file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function testFont(file: string) {
|
||||
console.log(`Testing ${file}`);
|
||||
const fontData: Uint8Array = fs.readFileSync(file);
|
||||
const facename = await getFontFamily(fontData);
|
||||
assert.isNotEmpty(facename);
|
||||
assert.isFalse(facename.includes('\u0000'));
|
||||
}
|
||||
|
||||
// To enable this, we need to have access to the shared fonts in the
|
||||
// keyboards repo
|
||||
await testFonts('.../keyboards/release/shared/fonts/');
|
||||
});
|
||||
});
|
||||
|
|
@ -18,6 +18,7 @@
|
|||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/ttfmeta/lib/*.js",
|
||||
"src/imports/langtags.js",
|
||||
],
|
||||
"references": [
|
||||
|
|
|
|||
11
package-lock.json
generated
11
package-lock.json
generated
|
|
@ -1272,8 +1272,7 @@
|
|||
"dependencies": {
|
||||
"@keymanapp/common-types": "*",
|
||||
"@keymanapp/developer-utils": "*",
|
||||
"@keymanapp/kmc-package": "*",
|
||||
"ttfmeta": "^1.1.2"
|
||||
"@keymanapp/kmc-package": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/chai": "^4.3.5",
|
||||
|
|
@ -11983,14 +11982,6 @@
|
|||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ttfmeta": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ttfmeta/-/ttfmeta-1.1.2.tgz",
|
||||
"integrity": "sha512-x0mKp7IkWjEa6CpI4/6HdCA3lzk8PaSBF5hubq03G2HyIzuDSdZRrO1dYgW4XD7q4sFdEWXSMYw7j0pzl4Ty6Q==",
|
||||
"engines": {
|
||||
"node": ">=16.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tunnel": {
|
||||
"version": "0.0.6",
|
||||
"license": "MIT",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue