我在 javascript 中使用 Canvas 对象。只是做一些测试,看看我在绘制循环中设置像素的速度有多快。
在 mac 上,它在 FF、safari、chrome 中运行良好。在 Windows 上,我对 FF 和 chrome 有闪烁的效果。对于不同的浏览器,windows 上的 Canvas 实现似乎与 mac 上的不同? (不确定这是不是真的)。
这是我用来绘图的基本代码(摘自下面的文章 - 我已经优化了下面的内容以收紧绘图循环,它现在运行得非常流畅):
var canvas = document.getElementById('myCanvasElt');
var ctx = canvas.getContext('2d');
var canvasData = ctx.getImageData(0, 0, canvas.width, canvas.height);
for (var x = 0; x < canvasData.width; x++) {
for (var y = 0; y < canvasData.height; y++) {
// Index of the pixel in the array
var idx = (x + y * canvas.width) * 4;
canvasData.data[idx + 0] = 0;
canvasData.data[idx + 1] = 255;
canvasData.data[idx + 2] = 0;
canvasData.data[idx + 3] = 255;
}
}
ctx.putImageData(canvasData, 0, 0);
同样,Windows 上的浏览器会有点闪烁。看起来 Canvas 实现试图在下一次绘图操作发生之前将 Canvas 清除为白色(这在 mac 上不会发生)。我想知道是否可以在 Canvas 对象中更改设置以修改该值(双缓冲、绘制前清除等)?
这是我用作引用的文章: http://hacks.mozilla.org/2009/06/pushing-pixels-with-canvas/
谢谢
最佳答案
我认为很明显,实现 Canvas 对象的浏览器使用 DIBS(设备独立位图)。您无需先锁定句柄就可以访问像素缓冲区这一事实证明了这一点。可以肯定的是,Direct2D 与浏览器中的 JS 无关。 GDI 是不同的,因为它使用 DDB(设备相关的位图,即从视频内存而不是传统的 ram 分配)。然而,所有这些都与最佳 JS 渲染速度无关。我认为按照您的方式编写 RGBA 值可能是最好的方法。
上述代码中的关键因素是对 putImageData() 的调用。这是浏览器在实现上可能有所不同的地方。您实际上是直接写入 DIB,而 putImageData 只是 InvalidateRect 的包装器吗?或者您实际上是在写入内存中的副本,然后将其复制到 Canvas 设备上下文中?如果您使用 linux 或 mac,那么这仍然是一个有效的问题。尽管设备上下文等通常是“windows”术语,但大多数操作系统以几乎相同的方式处理句柄或结构。但是,我们再次受到浏览器 vendor 的摆布。
我认为可以这样说:
如果您一次绘制许多像素,那么直接写入像素缓冲区可能是最好的方法。在 X 次操作后一次“bitblt”(复制)像素缓冲区会更快。这样做的原因是像 FillRect 这样的原生图形函数也调用“无效矩形”,它告诉系统如果屏幕需要重新绘制(刷新)那一部分。因此,如果您调用 100 行命令,则会发出 100 次更新 - 减慢进程。除非(这很重要)您使用应该使用的 beginPath/EndPath 方法。然后这是一个完全不同的球赛。
正是在这里开始/结束路径“系统”发挥作用,还有描边/轮廓命令。它们允许您在一次更新中执行 X 次绘图操作。但是很多人弄错了,每次调用 line/fillrect 等都会重绘。
此外,您是否尝试过创建一个不可见的 Canvas 对象,绘制到该对象上,然后复制到一个可见的 Canvas 上?这可能会更快(适当的双缓冲)。
关于javascript - 最佳像素绘制速度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2119016/