11

图片描述

[TL;DR] 有人在群里发了张图片问最后一个是什么字。根据生活经验和一些图片上的信息搜索并没有匹配到对应的字。然后找了个提供字体识别服务的网站,获得图中所用字体后,把常用汉字输入预览,肉眼一一对比后确认了这个字,也是运气加眼神好。后来写了个简单的页面用程序来做对比:先把图片二值化再简化得到一个数组,然后把汉字渲染到canvas上后用相同的方法得到一个数组,对比两个数组计算相似度。细节就不说了,不是本文的重点,接下来说说怎么使用特殊字体在canvas上绘制文本。

@font-face

搜“canvas使用自定义字体”,搜索的结果基本是使用CSS的@font-face来指定字体。

@font-face {
  font-family: "myFont";
  src: url("./custom.ttf"); /* 省略其他格式 */
}

然后canvas中使用这个字体

const cvs = document.querySelector('canvas')
const ctx = cvs.getContext('2d')

context.font = '30px myFont'
ctx.fillText('测试', 50, 50)

结果发现没效果,查看网络面板,发现字体已经下载了。应该是文本在字体还未加载完就绘制了,所以要保证绘制前资源已经准备好。

window.onload = function () {
  // canvas fillText
}

加上后,还是没效果,难道font不像img一样在加载完后触发window.onload?于是我尝试把绘制文本放到一个较长延时的setTimeout函数里。

setTimeout(() => {
  // canvas fillText
}, 5000)

还是没效果,但是通过网络面板发现,字体是在差不多5s后才请求下载的。这里我们应该有了个猜测,随后查到资料证实了:原来对于大部分浏览器,字体是懒加载的,在@font-face中声明了并不会下载此字体,只有在使用了这个字体,浏览器才会下载。

对于DOM+CSS来说没有问题,因为页面可以先显示默认的字体,当自定义字体加载完成后,页面自动呈现新字体。但是对canvas来说就不行了,因为在绘制的时候自定义字体还未加载完,那么绘制到画布会使用的默认字体,等自定义字体加载完,画布是不会自动更换像素的。

所以要保证绘制前字体已经加载完,我们可以先对对DOM元素使用该字体触发字体下载。

<style>
@font-face {
  font-family: "myFont";
  src: url('./custom.ttf'); 
}
canvas {
  font-family: "";
  font-size: 0;
}
<style>

<!-- DOM元素中间必须有字符,可以使用&nbsp; -->
<canvas>.</canvas>

<script>
window.onload = function () {
  const cvs = document.querySelector('canvas')
  const ctx = cvs.getContext('2d')

  context.font = '30px myFont'
  ctx.fillText('测试', 50, 50)
}
</script>

FontFace

可以看到前面的方法比较麻烦,但在摸索过程中通过搜索“JS怎么监听字体加载完成”,搜到了一个新的APIdocument.fonts.ready,并且这个接口返回的是Promise,可见应该是挺新的接口。顺藤摸瓜,在MDN上找到了FontFace这个接口,它的作用和CSS中的@font-face类似。使用很简单,直接看代码。

<canvas></canvas>

<script>
const myFont = new FontFace('myFont', 'url(./custom.ttf)')

myFont.load().then(font => {
  document.fonts.add(font)
}).then(() => {
  const cvs = document.querySelector('canvas')
  const ctx = cvs.getContext('2d')

  ctx.font = '30px myFont'
  ctx.fillText('测试', 50, 50)
})
</scipt>

上面只是最简单的使用,如想了解更多的可以去看看相关文档:https://developer.mozilla.org...


vczhan
2.6k 声望514 粉丝