画线或弧线时画布是否支持浮点数?

时间:2015-03-31 14:54:51

标签: html5 canvas html5-canvas

在canvas元素中,lineToarc方法实际上将浮点数视为浮点数吗?

例如:

context.moveTo(20.4562, 80.8923);
context.lineTo(120.1123, 90.2134);
context.arc(24.5113, 36.7989, 20.123, 0, Math.PI*2); 

画布是否真的支持浮点数坐标,或者它只是在绘制直线,圆弧,矩形等时将浮点数转换为整数?

2 个答案:

答案 0 :(得分:21)

位图本身不支持浮点值。它只能处理整数值。画布的2D上下文主要处理路径,其中每个SE未连接到位图。

路径是任意的,仅在内部存在。当它们被抚摸或填充时,它们会通过栅格化过程,即。转换为位图表示。

位图中的路径及其分配的点本身可以​​保存分数值,但位图不能。但是,可以使用插值(子像素)来表示小数值,这给人的印象是具有更大的可用位图分辨率,这反过来会消除锯齿状外观,如果值减少到只是整数。

(并且分辨率是进行插值的主要点。屏幕相当于72-96 DPI。如果屏幕具有更高的分辨率,300 + DPI,则不需要插值,如同但是我们现在在那里,如果插值没有被用来作为缺乏分辨率的补偿,那么图纸看起来很麻烦。

以下是它的工作原理

当像素落在整数边界值上时,将像素设置为该值的情况很简单。

int

当您处理浮点时,无法在某处设置像素,它必须向下舍入(地板)或放在下一个单元格中(ceil' ed),即。 3.2变为3,3.7变为4等。

intvsfloat

插值/子像素

然而,几十年前有人提出这个想法,将小数部分表示为实际像素和下一个像素之间的混合。

如果像素值为3.5,则小数部分将代表50%的黑色和50%的白色。它仍将占据整个像素单元,但由于它非常小,所以由于周围的像素会导致幻觉,它看起来只占据其细胞的一小部分。

所以在这种情况下,最后一个像素集看起来像这样:

subpixel 50%

如果值为3.25,则只有25%的剩余像素会混合,使得最后一个像素看起来像:

subpixel 25%

这将适用于落在小数值上的所有像素。当你画一条对角线和一些点"十字架"两个像素,这些像素的混合将应用于基于闭合整数的放置,使得线条看起来平滑。

现在,在画布的情况下,使用alpha通道插入形状。然后将形状混合并使用Porter-Duff与现有内容合成,这是我们所看到的最终结果。

在性能方面,这也是需要考虑的因素。如果需要插值,则成本上升,因为对于每个像素,浏览器(或子系统)必须计算分数表示。因此,您可以确保在将整数值传递给路径方法之前将其四舍五入使用整数值。这当然不适用于弧形,椭圆形,某些角度的对角线等,但在某些情况下它可以帮助加快速度。

这是插值原理,适用于使用分数坐标时。然而,有更复杂的插值和子像素方式。在现代世界中,2x2或4x4采样更为常见,可以提供更准确的结果。

演示

如果我们做一个小的放大线,我们可以看到线的末端"淡出"当我们改变分数值时进出。

此行宽3像素,然后我们在[0,1]之间添加一个分数值,我们可以看到最后一个ceil的像素正在重新采样:



var ctx = document.querySelector("canvas").getContext("2d"),
    x = 3.1, dx = 0.1;

ctx.imageSmoothingEnabled = ctx.mozImageSmoothingEnabled = ctx.webkitImageSmoothingEnabled = false;
ctx.font = "14px sans-serif";

(function loop() {
  ctx.fillStyle = "#000";
  ctx.clearRect(0,0,350,50);
  ctx.fillRect(0,0, x, 1); // forces pixel-alignment for demo

  ctx.drawImage(ctx.canvas, 0,0,4,1, 0, 0, 200, 50);
  
  x += dx;
  if (x <= 3 || x >= 4) dx = -dx;

  info(x);
  document.querySelector("div").innerHTML = "length: " + x.toFixed(2);
  
  setTimeout(loop, 160)
})();

function info(x) {
  ctx.fillStyle = "#f00";

  ctx.fillText("Perceived length", 210, 19);
  ctx.fillRect(0, 15, x * 50, 2);
  ctx.fillRect(x*50-1, 12, 2, 7);

  x = x === 3 ? 3 : 4;
  ctx.fillText("Actual length", 210, 40);
  ctx.fillRect(0, 35, x * 50, 2);
  ctx.fillRect(x*50-1, 32, 2, 7);
}
&#13;
div {font:bold 14px sans-serif}
&#13;
<canvas width=500 height=50></canvas><br>
<div></div>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

屏幕设备是像素设备,因此最终任何绘图都映射到整个像素,即整数。但是,在HTML5画布中使用浮点坐标而不是整数会改变结果。

如果使用非整数坐标绘制,它会自动使用消除锯齿来尝试平滑线条。您可以在this article中看到一个示例。

它也会影响drawImage,有关详细信息,请参阅此thread

请注意,使用浮点坐标会显着降低性能。

相关问题