使用 Opentype.js 生成字体子集的实例代码详解


Posted in Javascript onMay 25, 2020

字体子集是将字体文件中部分多余的字符删除,来减小文件大小,从而在 Web 端使用或嵌入到其他应用或系统中,在网上可以找到不少这方面的工具。

Opentype.js是一套可以支持浏览器环境和 Node.js 环境的开源 OpenType 字体读写库,利用这个库可以很轻松实现浏览器环境和 Node.js 环境的字体子集功能。

在浏览器环境创建字体子集工具

首先创建一个简单的 HTML界面,包括一个选取字体文件按钮,一个输入框用于输入保留的字符,和一个保存下载按钮。

HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Font Subset</title>
</head>
<body>
 <div>
  <p><label for="text">Choose a font file:</label></p>
  <input type="file" id="file">
 </div>
 <div>
  <p><label for="text">Text:</label></p>
  <textarea id="text"></textarea>
 </div>
 <div>
  <input type="button" id="save" value="save">
 </div>
</body>
</html>

在 HTML 的</body>前引入 opentype.js,并加入 Javascript。

<script src="https://cdn.jsdelivr.net/npm/opentype.js@latest/dist/opentype.min.js"></script>
<script>
 var save = document.getElementById("save");
 save.onclick = function() {
  var file = document.getElementById("file");
  var text = document.getElementById("text");
  if (file.files.length === 0) {
   alert("Choose a font file.")
   return;
  }
  if (text.value === "") {
   alert("Type some text.")
   return;
  }

  var glyphsArray = text.value.split("");
  var glyphs = glyphsArray.filter(function(item) {
    return item !== " ";
   }).filter(function(item, index) {
    return glyphsArray.indexOf(item) === index;
   }).join("");

  var reader = new FileReader();
  reader.onload = function(error) {
   try {
    var font = opentype.parse(reader.result);
    var postScriptName = font.getEnglishName("postScriptName");
    var [familyName, styleName] = postScriptName.split("-");
    
    var notdefGlyph = font.glyphs.get(0);
    notdefGlyph.name = ".notdef";
    var subGlyphs = [notdefGlyph].concat(font.stringToGlyphs(glyphs));

    var subsetFont = new opentype.Font({
     familyName: familyName,
     styleName: styleName,
     unitsPerEm: font.unitsPerEm,
     ascender: font.ascender,
     descender: font.descender,
     designer: font.getEnglishName("designer"),
     designerURL: font.getEnglishName("designerURL"),
     manufacturer: font.getEnglishName("manufacturer"),
     manufacturerURL: font.getEnglishName("manufacturerURL"),
     license: font.getEnglishName("license"),
     licenseURL: font.getEnglishName("licenseURL"),
     version: font.getEnglishName("version"),
     description: font.getEnglishName("description"),
     copyright: "This is a subset font of " + postScriptName + ". " + font.getEnglishName("copyright"),
     trademark: font.getEnglishName("trademark"),
     glyphs: subGlyphs
    });
    subsetFont.download();
   } catch (error) {
    alert(error.message);
    throw(error);
   }
  };
  reader.onerror = function(error) {
   alert(error.message);
   throw(error);
  };
  reader.readAsArrayBuffer(file.files[0]);
 };
</script>

在 Node.js 环境创建字体子集工具

创建项目文件

在 Node.js 版的项目中,可以考虑通过配置文件来实现批量处理多个字体文件功能。

mkdir font_subset
cd font_subset
npm init

项目结构如下,把所有原始的字体保存在 src 目录下,子集化之后的字体保存在 dist 目录下,main.js 为主脚本。

font_subset
├── config.json
├── dist
├── main.js
├── node_modules
├── package-lock.json
├── package.json
└── src
 └── NotoSerifSC-Bold.otf

字体配置

修改 “config.json” 文件。fonts数组类型,可配置多个字体文件;texts字符串类型,输入需要保留的字符,字符可以重复,可包含空格,不可换行,英文双引号使用\"表示。

{
 "fonts": ["./src/NotoSerifSC-Bold.otf"],
 "texts": " 0123456789:"
}

生成字体

main.js 内容如下。

const config = require('./config.json');
const fonts = config.fonts;
const texts = config.texts;

const path = require('path');
const opentype = require('opentype.js');

const glyphs = [...new Set(texts.split(''))].join('');

fonts.forEach(item => {
 const font = opentype.loadSync(item);
 const postScriptName = font.getEnglishName('postScriptName');
 const dist = path.join(
  'dist',
  postScriptName.replace(/-/g, '_').toLowerCase() + '_subset.otf'
 );
 const [familyName, styleName] = postScriptName.split('-');
 
 const notdefGlyph = font.glyphs.get(0);
 notdefGlyph.name = '.notdef';
 const subGlyphs = [notdefGlyph].concat(font.stringToGlyphs(glyphs));
 
 const subsetFont = new opentype.Font({
  familyName: familyName,
  styleName: styleName,
  unitsPerEm: font.unitsPerEm,
  ascender: font.ascender,
  descender: font.descender,
  designer: font.getEnglishName('designer'),
  designerURL: font.getEnglishName('designerURL'),
  manufacturer: font.getEnglishName('manufacturer'),
  manufacturerURL: font.getEnglishName('manufacturerURL'),
  license: font.getEnglishName('license'),
  licenseURL: font.getEnglishName('licenseURL'),
  version: font.getEnglishName('version'),
  description: font.getEnglishName('description'),
  copyright: 'This is a subset font of ' + postScriptName + '. ' + font.getEnglishName('copyright'),
  trademark: font.getEnglishName('trademark'),
  glyphs: subGlyphs
 });

 subsetFont.download(dist);
});

打开终端项目所在目录,输入以下命令,字体保存到 “dist” 文件夹下。

node main.js

总结

到此这篇关于使用 Opentype.js 生成字体子集的实例代码详解的文章就介绍到这了,更多相关Opentype.js 字体子集内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
JS 操作符整理[推荐收藏]
Nov 15 Javascript
javascript检测浏览器flash版本的实现代码
Dec 06 Javascript
jquery实现的一个简单进度条效果实例
May 12 Javascript
js判断鼠标左、中、右键哪个被点击的方法
Jan 27 Javascript
JavaScript利用HTML DOM进行文档操作的方法
Mar 28 Javascript
AngularJs解决跨域问题案例详解(简单方法)
May 19 Javascript
javascript稀疏数组(sparse array)和密集数组用法分析
Dec 28 Javascript
angularjs 实现带查找筛选功能的select下拉框实例
Jan 11 Javascript
JavaScript实现简单图片轮播效果
Aug 21 Javascript
vue防止花括号{{}}闪烁v-text和v-html、v-cloak用法示例
Mar 13 Javascript
Node.js之readline模块的使用详解
Mar 25 Javascript
Vue.set 全局操作简单示例
Sep 19 Javascript
Node.js API详解之 repl模块用法实例分析
May 25 #Javascript
微信小程序仿抖音视频之整屏上下切换功能的实现代码
May 24 #Javascript
如何使用vue slot创建一个模态框的实例代码
May 24 #Javascript
使用React代码动态生成栅格布局的方法
May 24 #Javascript
ES6对象操作实例详解
May 23 #Javascript
ES6函数和数组用法实例分析
May 23 #Javascript
ES6箭头函数和扩展实例分析
May 23 #Javascript
You might like
西德产收音机
2021/03/01 无线电
php上传apk后自动提取apk包信息的使用(示例下载)
2013/04/26 PHP
PHP往XML中添加节点的方法
2015/03/12 PHP
情人节专属 纯js脚本1k大小的3D玫瑰效果
2012/02/11 Javascript
javascript数据类型示例分享
2015/01/19 Javascript
原生js和jquery实现图片轮播淡入淡出效果
2015/04/23 Javascript
Jquery技巧(必须掌握)
2016/03/16 Javascript
JS实现unicode和UTF-8之间的互相转换互转
2017/07/05 Javascript
详解Angular-ui-BootStrap组件的解释以及使用
2018/07/13 Javascript
Vue下拉框回显并默认选中随机问题
2018/09/06 Javascript
前端vue如何使用高德地图
2020/11/05 Javascript
2款Python内存检测工具介绍和使用方法
2014/06/01 Python
python中利用队列asyncio.Queue进行通讯详解
2017/09/10 Python
Pandas之drop_duplicates:去除重复项方法
2018/04/18 Python
python K近邻算法的kd树实现
2018/09/06 Python
在双python下设置python3为默认的方法
2018/10/31 Python
Python交互式图形编程的实现
2019/07/25 Python
python使用多线程编写tcp客户端程序
2019/09/02 Python
python对Excel的读取的示例代码
2020/02/14 Python
Python在字符串中处理html和xml的方法
2020/07/31 Python
美国马匹用品和马钉购物网站:State Line Tack
2018/08/05 全球购物
SIXPAD智能健身仪英国官网:革命性的训练装备品牌
2018/09/27 全球购物
The Hut美国/加拿大:英国领先的豪华在线百货商店
2019/03/26 全球购物
Carrs Silver官网:英国著名的银器品牌
2020/08/29 全球购物
车间调度岗位职责
2013/11/30 职场文书
2014企业领导班子四风对照检查材料思想汇报
2014/09/17 职场文书
无财产离婚协议书范本
2014/10/28 职场文书
计算机实训报告范文
2014/11/05 职场文书
2014超市收银员工作总结
2014/11/13 职场文书
2016春节家属慰问信
2015/03/25 职场文书
2015年化验员工作总结
2015/04/10 职场文书
爱国主义教育基地观后感
2015/06/18 职场文书
又涨知识了,自律到底多重要?
2019/06/27 职场文书
2020年元旦祝福语录,总有适合你的
2019/12/31 职场文书
Window server中安装Redis的超详细教程
2021/11/17 Redis
Python采集爬取京东商品信息和评论并存入MySQL
2022/04/12 Python