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

作者:阿沐时间:2026-10-23 18:59:56浏览:261

本文详细介绍如何利用 Opentype.js 库在浏览器和 Node.js 环境中生成字体子集,以减小文件体积。通过 HTML 界面交互和 Node.js 配置文件批量处理两种方案,结合完整代码示例,演示如何提取指定字符并保存为子集字体文件,适用于 Web 嵌入及系统应用。

字体子集与 Opentype.js 概述

字体子集技术通过剔除字体文件中未使用的字符来显著减小文件体积,便于在 Web 页面中使用或嵌入到其他应用程序及系统中,目前网络上已有多种相关工具可用。

Opentype.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 环境中构建字体子集工具

初始化项目文件

在 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 生成字体子集的完整流程与代码示例,更多相关内容可参考本站过往文章或继续浏览后续文章,感谢支持。

作者最新文章