浏览器没有获取本地字体列表的API,同时FLash也被浏览抛弃。需要一种新的方式判断字体是否支持。
下图列出了一些字体,特征各不一样。最直观的是字形,其次不同字体下的相同文字的宽度也是不一样的,由此我们能通过这两点差异对字体进行判断。
字体宽度
每种字体的宽度都不尽相同。 我们可以通过分别测量默认字体和目标字体的宽度,查看二者的差异。若果不一致则说明目标字体可用,否则说明不支持该字体,浏览器会退到了默认字体。
在canvas中可以使用measureText
测量文字渲染的宽度,这个宽度非常精确。
var canvas = document.createElement('canvas')
var ctx = canvas.getContext("2d");
var width = ctx.measureText('123').width; // 21.111328125
使用ctx.font
可以设置字号和字体,例如ctx.font="30px Arial"
,默认为10px sans-serif
我们可以提前计算好各种字体的宽度表,就可以快速地识别字体样式。
像素比对
根据用户设置的字体将某一个字符绘制在canvas上,并提取像素信息与默认字体进行比对,看是否一致。 这种方法最为准确,当然缺点也很明显就是计算量较大。
let isSupportFontFamily = function (f) {
let base = "Arial";
if (f.toLowerCase() == base.toLowerCase()) return true
let e = "a";
let d = 100;
let a = 100, i = 100;
let c = document.createElement("canvas");
let b = c.getContext("2d");
c.width = a;
c.height = i;
b.textAlign = "center";
b.fillStyle = "black";
b.textBaseline = "middle";
let g = function (j) {
b.clearRect(0, 0, a, i);
b.font = d + "px " + j + ", " + base;
b.fillText(e, a / 2, i / 2);
let k = b.getImageData(0, 0, a, i).data;
return [].slice.call(k).filter(l => l != 0);
};
return g(base).join("") !== g(f).join("");
};