比较 HTML5 Canvas 中的两种字体
我正在尝试组合一个工具来检查给定字符是否以指定样式字体或系统默认字体显示。我的最终目标是能够检查,至少在现代(即:IE8+)浏览器中,给定字体是否支持连字。
我有两个画布显示相同的连字(在本例中为 st)。我将这些画布转化为数据并进行比较,看看字符是否匹配。
Arial(像大多数字体一样)没有 st 连字,因此它会退回到默认的衬线字体。这就是奇怪的地方:虽然它们显示相同的字体,但两个画布没有相同的数据。
为什么?因为它们在画布上的位置并不完全相同。我猜这与字体的不同相对高度有关(一个比另一个稍高,尽管字体不同)。差异似乎是一两个像素,并且不同字体的差异也不同。
如何解决这个问题呢?我当前唯一的想法是找到一种方法来测量字体的高度并相应地调整其位置,但不幸的是,我不知道该怎么做。我可以采取其他方法使两个图像相同吗?
您可以看到下面的代码。两个画布都已成功初始化并附加到元素的主体中,因此我可以直观地看到发生的情况(尽管这在我正在处理的实际脚本中不是必需的)。我已经放弃了初始化和上下文,因为它们都工作得很好。
function checkLig() {
lig = 'fb06' // this is the unicode for the st ligature
canvas0.width = 250;
canvas0.height = 50;
context0.fillStyle = 'rgb(0, 0, 0)';
context0.textBaseline = 'top';
context0.font = 'normal normal normal 40px Arial';
context0.fillText(String.fromCharCode(parseInt(lig, 16)), 0, 0);
var print0 = context0.getImageData(0, 0, 720, 50).data;
canvas1.width = 250;
canvas1.height = 50;
context1.fillStyle = 'rgb(0, 0, 0)';
context1.textBaseline = 'top';
context1.font = 'normal normal normal 40px serif';
context1.fillText(String.fromCharCode(parseInt(lig, 16)), 0, 0);
var print1 = context1.getImageData(0, 0, 720, 50).data;
var i = 0, same = true, len = 720 * 50 * 4;
while (i < len && same === true) {
if (print0[i] !== print1[i]) {
same = false;
}
else {
i++;
}
}
return same;
}
I'm trying to put together a tool that checks whether a given character is displayed in the specified style font or a system default font. My ultimate goal is to be able to check, at least in modern (read: IE8+) browsers, whether a ligature is supported in a given font.
I've got two canvases displaying the same ligature (in this case, st). I turn those canvases into data and compare them to see if the characters match.
Arial (like most fonts) does not have an st ligature, so it falls back to the default serif font. Here's where it gets weird: although they're displaying the same font, the two canvases don't have the same data.
Why? Because their positions on the canvas aren't exactly the same. I'm guessing it has something to do with the different relative heights of the fonts (one is slightly taller than the other, though which varies font to font). The difference appears to be one of a pixel or two, and it varies font by font.
How might one go about solving this? My only current idea is finding a way to measure the height of the font and adjusting its position accordingly, but I have no idea how to do that, unfortunately. Are there other approaches I might take to make the two images identical?
You can see the code below. Both canvases are successfully initialized and appended to the body of the element so I can see what's going on visually (though that's not necessary in the actual script I'm working on). I've dropped the initialization and context, as those are all working just fine.
function checkLig() {
lig = 'fb06' // this is the unicode for the st ligature
canvas0.width = 250;
canvas0.height = 50;
context0.fillStyle = 'rgb(0, 0, 0)';
context0.textBaseline = 'top';
context0.font = 'normal normal normal 40px Arial';
context0.fillText(String.fromCharCode(parseInt(lig, 16)), 0, 0);
var print0 = context0.getImageData(0, 0, 720, 50).data;
canvas1.width = 250;
canvas1.height = 50;
context1.fillStyle = 'rgb(0, 0, 0)';
context1.textBaseline = 'top';
context1.font = 'normal normal normal 40px serif';
context1.fillText(String.fromCharCode(parseInt(lig, 16)), 0, 0);
var print1 = context1.getImageData(0, 0, 720, 50).data;
var i = 0, same = true, len = 720 * 50 * 4;
while (i < len && same === true) {
if (print0[i] !== print1[i]) {
same = false;
}
else {
i++;
}
}
return same;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
所以我正确地理解了这个问题,问题是一个画布指定了 Arial (但回退到 Serif),另一个画布指定了 Serif,当您进行像素匹配时,它不是匹配的,因为其中一个画布有轻微的偏移?
一个建议是从每个画布中获取一个参考像素并比较两个参考像素的位置以获得偏移量。然后将该偏移量纳入比较循环中。
例如,在这种情况下,您可以通过从一个画布的左上角开始检查像素并在该列中向下扫描来获取参考像素,当到达底部时,返回到下一列的顶部并向下扫描。
一旦您遇到与背景颜色不同的像素,请记录该位置并将其用作参考像素。那应该是你的字体的边缘。
对下一个画布执行相同的操作,然后比较两个参考像素的位置以获得偏移量。在比较循环中考虑该偏移量。
希望我对这个问题有正确的想法,希望有所帮助!
So i understand the question correctly, the problem is one canvas is specifying Arial (but falls back to Serif) and the other is Serif and when you do the pixel matching, and it's not a match because one of them has a slight offset?
One suggestion is to grab a reference pixel from each canvas and compare the positions of the two reference pixels to get an offset. And then factor that offset into your comparison loop.
For example, in this case you could get your reference pixel by starting to check pixels from the upper left corner of one canvas and scan downwards in that column and when you reach the bottom, go back to the top of the next column and scan down.
As soon as you hit a pixel that is not the color of your background, record the position and use that as your reference pixel. That should be the edge of your font.
Do the same with your next canvas and then compare the positions of the two reference pixels to get an offset. Take that offset into consideration in your comparison loop.
Hope I have the right idea of the problem and i hope that helps!