使用 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 相关文章推荐
清除网页历史记录,屏蔽后退按钮!
Dec 22 Javascript
javascript break指定标签打破多层循环示例
Jan 20 Javascript
AngularJS模块详解及示例代码
Aug 17 Javascript
javascript中json对象json数组json字符串互转及取值方法
Apr 19 Javascript
JavaScript中递归实现的方法及其区别
Sep 12 Javascript
详解使用vue-admin-template的优化历程
May 20 Javascript
JavaScript简单实现关键字文本搜索高亮显示功能示例
Jul 25 Javascript
JavaScript中变量提升与函数提升经典实例分析
Jul 26 Javascript
vue-cli3.0配置及使用注意事项详解
Sep 05 Javascript
详解vue-cli项目开发/生产环境代理实现跨域请求
Jul 23 Javascript
js实现时分秒倒计时
Dec 03 Javascript
AJAX引擎原理以及XmlHttpRequest对象的axios、fetch区别详解
Apr 09 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中使用数组实现堆栈数据结构的代码
2012/02/05 PHP
php 解析xml 的四种方法详细介绍
2016/10/26 PHP
详谈PHP中public,private,protected,abstract等关键字的用法
2017/12/31 PHP
PHP切割汉字的常用方法实例总结
2019/04/27 PHP
PHP从零开始打造自己的MVC框架之路由类实现方法分析
2019/06/03 PHP
php 命名空间(namespace)原理与用法实例小结
2019/11/13 PHP
PHP 图片处理
2020/09/16 PHP
JavaScript 三种不同位置代码的写法
2009/10/25 Javascript
javascript操作cookie的文章(设置,删除cookies)
2010/04/01 Javascript
深入理解JavaScript系列(9) 根本没有“JSON对象”这回事!
2012/01/15 Javascript
IE不支持getElementsByClassName最终完美解决方案
2012/12/17 Javascript
控制台报错object is not a function的解决方法
2014/08/24 Javascript
iframe中子父类窗口调用JS的方法及注意事项
2015/08/25 Javascript
深入理解Javascript中的自执行匿名函数
2016/06/03 Javascript
静态页面实现 include 引入公用代码的示例
2017/09/25 Javascript
使用vue-cli打包过程中的步骤以及问题的解决
2018/05/08 Javascript
vue移动端微信授权登录插件封装的实例
2018/08/28 Javascript
nodejs高大上的部署方式(PM2)
2018/09/11 NodeJs
jquery实现图片无缝滚动 蒙版遮蔽效果
2020/01/11 jQuery
Python实现将json文件中向量写入Excel的方法
2018/03/26 Python
Numpy掩码式数组详解
2018/04/17 Python
Django中如何使用sass的方法步骤
2019/07/09 Python
Python:二维列表下标互换方式(矩阵转置)
2019/12/02 Python
Python批量将图片灰度化的实现代码
2020/04/11 Python
Python pip安装第三方库实现过程解析
2020/07/09 Python
python中的django是做什么的
2020/07/31 Python
Python urllib3软件包的使用说明
2020/11/18 Python
Python第三方库安装缓慢的解决方法
2021/02/06 Python
HTML5使用Audio标签实现歌词同步的效果
2016/03/17 HTML / CSS
商得四方公司面试题(gid+)
2014/04/30 面试题
教师推荐信范文
2013/11/24 职场文书
十佳美德少年事迹材料
2014/02/05 职场文书
校本教研活动总结
2014/07/01 职场文书
大二学生自我检讨书
2014/10/23 职场文书
环卫个人总结
2015/03/03 职场文书
PyQt5 QThread倒计时功能的实现代码
2021/04/02 Python