使用 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 相关文章推荐
Save a File Using a File Save Dialog Box
Jun 18 Javascript
各种常用浏览器getBoundingClientRect的解析
May 21 Javascript
extjs关于treePanel+chekBox全部选中以及清空选中问题探讨
Apr 02 Javascript
给html超链接设置事件不使用href来完成跳
Apr 20 Javascript
js实现顶部可折叠的菜单工具栏效果实例
May 09 Javascript
JS实现的简洁二级导航菜单雏形效果
Oct 13 Javascript
AngularJS ng-app 指令实例详解
Jul 30 Javascript
jQuery EasyUI API 中文帮助文档和扩展实例
Aug 01 Javascript
AngularJS递归指令实现Tree View效果示例
Nov 07 Javascript
深入理解React中何时使用箭头函数
Aug 23 Javascript
ES7中利用Await减少回调嵌套的方法详解
Nov 01 Javascript
JSONObject与JSONArray使用方法解析
Sep 28 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
PHP连接access数据库
2008/03/27 PHP
PHP Zip解压 文件在线解压缩的函数代码
2010/05/26 PHP
在openSUSE42.1下编译安装PHP7 的方法
2015/12/24 PHP
PHP中strnatcmp()函数“自然排序算法”进行字符串比较用法分析(对比strcmp函数)
2016/01/07 PHP
php好代码风格的阶段性总结
2016/06/25 PHP
PHP实现根据数组某个键值大小进行排序的方法
2018/03/13 PHP
详解PHP实现支付宝小程序用户授权的工具类
2018/12/25 PHP
jquery 得到当前页面高度和宽度的两个函数
2010/02/21 Javascript
Js(JavaScript)中,弹出是或否的选择框示例(confirm用法的实例分析)
2013/07/09 Javascript
JS Canvas定时器模拟动态加载动画
2016/09/17 Javascript
js无提示关闭浏览器窗口的两种方法分析
2016/11/06 Javascript
原生js实现无缝轮播图效果
2017/01/11 Javascript
详解vue.js2.0父组件点击触发子组件方法
2017/05/10 Javascript
菊花转动的jquery加载动画效果
2018/08/19 jQuery
微信小程序里引入SVG矢量图标的方法
2019/09/20 Javascript
vue el-table实现自定义表头
2019/12/11 Javascript
element el-table表格的二次封装实现(附表格高度自适应)
2021/01/19 Javascript
[01:03:33]Alliance vs TNC 2019国际邀请赛小组赛 BO2 第一场 8.16
2019/08/18 DOTA
详解supervisor使用教程
2017/11/21 Python
Python 实现还原已撤回的微信消息
2019/06/18 Python
Python3连接Mysql8.0遇到的问题及处理步骤
2020/02/17 Python
Python爬虫之爬取淘女郎照片示例详解
2020/07/28 Python
css3 transform及原生js实现鼠标拖动3D立方体旋转
2016/06/20 HTML / CSS
HTML5 Canvas中绘制椭圆的4种方法
2015/04/24 HTML / CSS
Html5 new XMLHttpRequest()监听附件上传进度
2021/01/14 HTML / CSS
瑞士男士时尚网上商店:Babista
2020/05/14 全球购物
"火柴棍式"程序员面试题
2014/03/16 面试题
什么时候需要进行强制类型转换
2016/09/03 面试题
新年抽奖获奖感言
2014/03/02 职场文书
爱耳日宣传活动总结
2014/07/05 职场文书
乡镇务虚会发言材料
2014/10/20 职场文书
2014年商场工作总结
2014/11/22 职场文书
出纳年终工作总结2014
2014/12/05 职场文书
优秀班集体申报材料
2014/12/25 职场文书
2015年幼儿园班主任个人工作总结
2015/10/22 职场文书
导游词之潮音寺
2019/09/26 职场文书