使用 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 相关文章推荐
javascript面向对象编程(一) 实例代码
Jun 25 Javascript
jQuery实现div浮动层跟随页面滚动效果
Feb 11 Javascript
javascript中hasOwnProperty() 方法使用指南
Mar 09 Javascript
JavaScript实现LI列表数据绑定的方法
Aug 04 Javascript
js窗口关闭提示信息(兼容IE和firefox)
Oct 23 Javascript
bootstrap modal弹出框的垂直居中
Dec 14 Javascript
利用CSS、JavaScript及Ajax实现图片预加载的三大方法
Jan 22 Javascript
javascript将json格式数组下载为excel表格的方法
Dec 22 Javascript
H5+C3+JS实现双人对战五子棋游戏(UI篇)
May 28 Javascript
JavaScript获取当前url路径过程解析
Dec 27 Javascript
基于脚手架创建Vue项目实现步骤详解
Aug 03 Javascript
JavaScript中CreateTextFile函数
Aug 30 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/05 新手入门
用PHP的ob_start();控制您的浏览器cache!
2006/11/25 PHP
随时给自己贴的图片加文字的php水印
2007/03/16 PHP
php iconv() : Detected an illegal character in input string
2010/12/05 PHP
PHP输出缓存ob系列函数详解
2014/03/11 PHP
PHP新建类问题分析及解决思路
2015/11/19 PHP
PHP的邮件群发系统phplist配置方法详细总结
2016/03/30 PHP
javascript实现拖动元素交换位置
2015/11/29 Javascript
解决微信浏览器Javascript无法使用window.location.reload()刷新页面
2016/06/21 Javascript
EasyUI中在表单提交之前进行验证
2016/07/19 Javascript
基于HTML+CSS+JS实现增加删除修改tab导航特效代码
2016/08/05 Javascript
AngularJS中directive指令使用之事件绑定与指令交互用法示例
2016/11/22 Javascript
JavaScript 字符串数字左补位,右补位,取固定长度,截位扩展函数代码
2017/03/25 Javascript
手把手教你把nodejs部署到linux上跑出hello world
2017/06/19 NodeJs
jQuery实现弹窗下底部页面禁止滑动效果
2017/12/19 jQuery
nvm、nrm、npm 安装和使用详解(小结)
2019/01/17 Javascript
vue组件间通信六种方式(总结篇)
2019/05/15 Javascript
vscode vue 文件模板的配置方法
2019/07/23 Javascript
vuex vue简单使用知识点总结
2019/08/29 Javascript
微信小程序官方动态自定义底部tabBar的例子
2019/09/04 Javascript
原生JavaScript实现日历功能代码实例(无引用Jq)
2019/09/23 Javascript
CountUp.js实现数字滚动增值效果
2019/10/17 Javascript
Python中if __name__ == '__main__'作用解析
2015/06/29 Python
Python有序字典简单实现方法示例
2017/09/28 Python
Python利用openpyxl库遍历Sheet的实例
2018/05/03 Python
Python将一个CSV文件里的数据追加到另一个CSV文件的方法
2018/07/04 Python
python中对_init_的理解及实例解析
2019/10/11 Python
使用OpenCV去除面积较小的连通域
2020/07/05 Python
PyQt5的相对布局管理的实现
2020/08/07 Python
HTML5之SVG 2D入门10—滤镜的定义及使用
2013/01/30 HTML / CSS
PHP面试题-$message和$$message的区别
2015/12/08 面试题
小学生作文批改评语
2014/12/25 职场文书
雷锋之歌观后感
2015/06/10 职场文书
2016年小学推普宣传周活动总结
2016/04/06 职场文书
Golang 字符串的常见操作
2022/04/19 Golang
在python中读取和写入CSV文件详情
2022/06/28 Python