Skip to content

Instantly share code, notes, and snippets.

@kidapu
Last active June 14, 2022 01:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kidapu/7d15e5d23b38ed05de25ac9bcc751354 to your computer and use it in GitHub Desktop.
Save kidapu/7d15e5d23b38ed05de25ac9bcc751354 to your computer and use it in GitHub Desktop.
facetype.js( https://github.com/gero3/facetype.js ) の node.js で動く版
npm install 
node main.js
//
// Lib
//
const opentype = require('opentype.js');
const fs = require("fs");
//
// Literals
//
// 変換する font
const srcfontPath = './datas/MPLUSRounded1c-Bold.ttf'
// 利用したい文字列。空の場合は全ての文字を利用する。
const restrictStr = 'testあいう'
//
// Process
//
const font = opentype.loadSync(srcfontPath);
// console.log(font.names)
const convertedFont = convert(font);
const fontFullName = Object.values(font.names['fullName'])[0]
saveJson(convertedFont, './out/' + fontFullName + '.json');
//
// Method
//
function saveJson(output, filePath) {
// fs.writeFileSync(filePath, JSON.stringify([output]));
console.log(output)
// fs.writeFileSync(filePath, JSON.stringify(output, '', ''));
fs.writeFileSync(filePath, output);
}
function convert(font) {
var scale = (1000 * 100) / ((font.unitsPerEm || 2048) * 72);
var result = {};
result.glyphs = {};
var restriction = {
range: null,
set: null
};
if (restrictStr != '') {
var restrictContent = restrictStr;
var rangeSeparator = '-';
if (restrictContent.indexOf(rangeSeparator) != -1) {
var rangeParts = restrictContent.split(rangeSeparator);
if (rangeParts.length === 2 && !isNaN(rangeParts[0]) && !isNaN(rangeParts[1])) {
restriction.range = [parseInt(rangeParts[0]), parseInt(rangeParts[1])];
}
}
if (restriction.range === null) {
restriction.set = restrictContent;
}
}
console.log('restriction: ', restriction)
for (let glyphId in font.glyphs['glyphs']) {
let glyph = font.glyphs['glyphs'][glyphId];
// console.log('- - - - - -')
// console.log('glyph:', glyphId, glyph)
// console.log('glyph:', glyphId, glyph)
// console.log(Object.values(glyph))
if (glyph.unicode !== undefined) {
var glyphCharacter = String.fromCharCode(glyph.unicode);
var needToExport = true;
if (restriction.range !== null) {
needToExport = (glyph.unicode >= restriction.range[0] && glyph.unicode <= restriction.range[1]);
}
else if (restriction.set !== null) {
needToExport = (restrictStr.indexOf(glyphCharacter) != -1);
}
if (needToExport) {
var token = {};
token.ha = Math.round(glyph.advanceWidth * scale);
token.x_min = Math.round(glyph.xMin * scale);
token.x_max = Math.round(glyph.xMax * scale);
token.o = ""
// if (reverseTypeface.checked) { glyph.path.commands = reverseCommands(glyph.path.commands); }
glyph.path.commands.forEach(function (command, i) {
if (command.type.toLowerCase() === "c") { command.type = "b"; }
token.o += command.type.toLowerCase();
token.o += " "
if (command.x !== undefined && command.y !== undefined) {
token.o += Math.round(command.x * scale);
token.o += " "
token.o += Math.round(command.y * scale);
token.o += " "
}
if (command.x1 !== undefined && command.y1 !== undefined) {
token.o += Math.round(command.x1 * scale);
token.o += " "
token.o += Math.round(command.y1 * scale);
token.o += " "
}
if (command.x2 !== undefined && command.y2 !== undefined) {
token.o += Math.round(command.x2 * scale);
token.o += " "
token.o += Math.round(command.y2 * scale);
token.o += " "
}
});
result.glyphs[String.fromCharCode(glyph.unicode)] = token;
}
};
}
result.familyName = font.familyName;
result.ascender = Math.round(font.ascender * scale);
result.descender = Math.round(font.descender * scale);
result.underlinePosition = Math.round(font.tables.post.underlinePosition * scale);
result.underlineThickness = Math.round(font.tables.post.underlineThickness * scale);
result.boundingBox = {
"yMin": Math.round(font.tables.head.yMin * scale),
"xMin": Math.round(font.tables.head.xMin * scale),
"yMax": Math.round(font.tables.head.yMax * scale),
"xMax": Math.round(font.tables.head.xMax * scale)
};
result.resolution = 1000;
result.original_font_information = font.tables.name;
const fontStyleName = Object.values(font.names['fontFamily'])[0].toLowerCase()
if (fontStyleName.toLowerCase().indexOf("bold") > -1) {
result.cssFontWeight = "bold";
} else {
result.cssFontWeight = "normal";
};
if (fontStyleName.toLowerCase().indexOf("italic") > -1) {
result.cssFontStyle = "italic";
} else {
result.cssFontStyle = "normal";
};
return JSON.stringify(result);
};
function reverseCommands(commands) {
var paths = [];
var path;
commands.forEach(function (c) {
if (c.type.toLowerCase() === "m") {
path = [c];
paths.push(path);
} else if (c.type.toLowerCase() !== "z") {
path.push(c);
}
});
var reversed = [];
paths.forEach(function (p) {
var result = { "type": "m", "x": p[p.length - 1].x, "y": p[p.length - 1].y };
reversed.push(result);
for (var i = p.length - 1; i > 0; i--) {
var command = p[i];
result = { "type": command.type };
if (command.x2 !== undefined && command.y2 !== undefined) {
result.x1 = command.x2;
result.y1 = command.y2;
result.x2 = command.x1;
result.y2 = command.y1;
} else if (command.x1 !== undefined && command.y1 !== undefined) {
result.x1 = command.x1;
result.y1 = command.y1;
}
result.x = p[i - 1].x;
result.y = p[i - 1].y;
reversed.push(result);
}
});
return reversed;
};
{
"name": "01-font-convert",
"version": "1.0.0",
"description": "",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"opentype.js": "^1.3.4"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment