10

我对不同浏览器如何在 HTML5 Canvas 上呈现字体大小有疑问。特别是在字体大小不是整数的情况下。例如“8.5px Arial”、“2.23em Arial”等。

对于 canvas.font= FontSize + "px Arial"; 其中 FontSize 是 (8.1, 8.2, 8.3, ...) 我希望得到线性结果,但是唯一始终存档的浏览器是 IE !( 我知道 )。Firefox 四舍五入低于 11.2 像素,但超出此范围是线性的。Chrome 和 Safari 仅将字体缩放为整数值。

舍入规则似乎设置为像素并向下舍入到 0.5 以下最接近的整数

我的画布应用程序正在执行一些程序化动画转换(缩放和翻译)为了提高效率而尝试避免画布转换,尽管我怀疑它会解决问题,但我也没有通过仅使用 CSS3 设置 html 文本大小来测试这一点(即Canvas.font 应该基于规范)

浏览器在 pt、px、em 和 % 字体大小之间的行为至少是一致的。[编辑:除了 Safari 不呈现 % 大小]

[顺便说一句:所有字体一旦放大一点就会看起来有点粗体。当我们从 17.4px 到 17.5px .. BAMB 时,Safari 会拿走那个蛋糕!]

我在下面附上了一些示例图片,但我真的很想了解如何让所有浏览器更像 IE(我从来没想过我会这么说) - 这是一个错误还是渲染字体的标准?

这是我的测试代码,可以为 PX 字体大小的情况复制。

<!DOCTYPE html><html><head><script>
function display() {
    var canvas = document.getElementById('test');
    // For EM and % cases....
    //canvas.style.font="5px Arial";
    canvas.height = 1000;
    var context = canvas.getContext('2d');
    var minSize = 10;
    var lineHeight = 100;
    for(var a=minSize; a< 20; a+=0.1)
    {
        var font_size =  Math.round(a*10000)/10000;
        context.font = a + "px Arial";
        context.fillText("A: EXAMPLE TEXT > " +  font_size, 20, (font_size-minSize)*lineHeight);
    }
}
</script></head><body onload="display()"><canvas id="test"></canvas></body></html>

像素比例 像素尺度 点比例 点量表 em 比例 - 1em = 5px Arial 时间尺度 百分比比例 - 100% = 5px Arial 百分制

4

1 回答 1

6

我以为你们应该为我做我的工作;)无论如何,这就是我解决问题的方法,尽管它有点小技巧,并且仍然有一些我将描述的问题。

回顾一下(因为问题可能不清楚)我试图将字体大小乘以一些浮点数来放大和缩小文本。但这会导致结果不稳定,因为大多数将字体大小四舍五入到最接近的整数值。

比如说。

var zoom = 1.02;
var font_size = 12;
context.font = (font_size * zoom) + "px Arial"; // 12.24px

zoom = 1.04 (12.48px) 将呈现与上述代码相同的效果,而 zoom = 1.06 (12.75px) 将四舍五入为 13px。

这导致值之间的字体大小发生非常不希望的跳跃,而画布上的所有其他元素都正确缩放。

由于所有浏览器都呈现给定的文本字符串(例如“EXAMPLE TEXT”)并且长度略有不同,因此问题变得更加复杂。

解决方案

在初始化期间以标准字体大小 (zoom=1) 渲染文本并测量行长,将此值称为 iniLineLength

在场景渲染期间,我使用隐藏的画布将文本渲染到然后使用 drawImage 到主画布,宽度为乘数。

tmpContext.font = (font_size * zoom) + "px Arial";
tmpContext.fillText(MyLineOfText,0, 0); 
var s = (iniLineLength * zoom) / tmpContext.measureText(MyLineOfText) ;
mainContext.drawImage(tmpCanvas,x, y, pw * s, ph);

根据行长与预期行长的距离,在主画布上拉伸或收缩生成的文本行。

在理想世界中,s 总是等于 1,因为预期的线长度总是与实际的线长度相同。预期的行长是我们的示例行长 iniLineLength 乘以与我们在此渲染过程中的字体大小相同的缩放因子。

我对这一切的奖励是它具有使浏览器行为的所有差异正常化的效果......几乎。

问题

即使行长标准化,行中每个字符的确切位置也不相同。给出下图中的效果。

在此处输入图像描述

然而,这已经是我所拥有的巨大改进。

此外,您还需要将 tmpCanvas 剪辑到 mainCanvas,否则您的浏览器将在尝试创建和复制百万像素的文本时停止运行,只是为了让一个字符全屏显示。

考虑到这一点,您还可以根据需要设置您的 tmp 画布宽度和高度,以适应您要渲染的实际文本行,这将节省内存、时间等。

于 2013-03-17T11:09:51.027 回答