33

可以将CanvasPixelArray获得的 via发送getImageData到工作脚本,并让工作脚本在其后台线程中操作像素,并最终将操作后的像素数组发回。

但是,我使用的是原生画布绘图功能,例如drawImage. 这些drawImage调用当前正在阻塞 UI 线程。这会导致按钮重绘缓慢,并且在单击按钮时会出现明显的延迟,仅举几个缺点。(编辑:现在可以使用 来完成一个小的改进ctx.imageSmoothingEnabled = false,至少在带有webkit前缀的 WebKit 上。)

我想使用 Web Workers 将绘图从主线程移动到后台线程。但是,我似乎无法将画布或上下文发送给工作人员。

我确实在 MDN 上找到了这个通知

注意:像往常一样,后台线程(包括工作线程)不能操作 DOM。如果后台线程采取的操作需要导致对 DOM 的更改,他们应该将消息发回给他们的创建者来完成这项工作。

但我想保留 DOM 原样;我只是想在画布元素上画东西。这可能吗,还是 Web Workers 真的只允许计算而不允许绘制?

(或者是否可以使用诸如drawImage操作 aCanvasPixelArray而不是在画布上绘图之类的功能?)

4

4 回答 4

42

[编辑〜5年后:其中一些开始发生变化,并且有新的Web平台功能实际上允许从Worker渲染到画布!有关更多信息,请参阅此博客:https ://hacks.mozilla.org/2016/01/webgl-off-the-main-thread/ - 其余答案提供给 2011 年的信息 ;)]

Web Worker 只能计算,不能修改 DOM 或进行任何调用以绘制到画布。但是,就像您说的那样,您可以将一组像素发布到网络工作者那里进行处理并将其发回。由于这是异步的,我不明白为什么这会导致 UI 线程变慢,除非您故意阻止直到 Web Worker 响应(您不应该这样做)。

drawImage因此,您的通话时间如此之长以至于影响了用户界面,这似乎很奇怪。如今,大多数画布都是硬件加速的,因此它们应该很好地跳过。我的猜测是,您每帧都通过网络工作者绘制到画布像素数组,这实际上意味着您正在用 javascript软件渲染画布。Javascript 仍然太慢,无法做到这一点——即使是 C++ 软件渲染器也有点慢,这就是硬件加速很重要的原因。因此,您可以一次将某些内容渲染到网络工作者中的画布像素数组,然后当您获得结果时将其缓存到Image 一次,然后根据需要将其绘制Image到画布上。那应该仍然非常快。

编辑:您可能想要查看 WebGL,您可以在其中编写片段着色器,这些着色器实际上是处理像素效果的小程序。它们完全在显卡上运行,因此速度非常快。

于 2011-11-28T19:21:25.223 回答
17

您可以将其发布ImageData到 Web Worker,它将被操纵的内容发送ImageData回调用者(主 UI)线程。

例如:

  1. 创建一个网络工作者:

    this.renderer = new Worker("renderer.js");
  2. ImageData创建的画布发布到 Web Worker:

    var ctx = this.canvas.getContext('2d');
    var imageData = ctx.createImageData(width, height);
    this.renderer.postMessage({ image: imageData });
  3. ImageDataWeb Worker 中进行操作并将其发布回主线程:

    onmessage = 函数(e){
       var processesImage = self.doImageProcessing(e.data.image);
       postMessage({ 图像: 处理图像 });
    };

  4. ImageData在主线程中将操作设置为画布:

    this.renderer.onmessage = function (e) {
       var ctx = this.canvas.getContext('2d');
       ctx.putImageData(e.data.image, 0, 0);
    }

于 2015-07-07T09:57:28.197 回答
12

有一个新的 API 可以做到这一点(如果您启用了首选项,目前仅在 Firefox 中支持)。

请参阅https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvashttps://hacks.mozilla.org/2016/01/webgl-off-the-main-thread/

于 2016-02-08T10:45:46.407 回答
10

[社区编辑:这个答案是在 2011 年编写并被接受的。其他技术已经出现(或正在出现),这可能会让 Web Workers 和 Canvas 更好地共存;除了这个答案,读者应该知道这个页面上的所有答案。]

您不能将画布对象或画布上下文传递给工作线程,因为画布是 DOM 的一部分。

于 2011-11-27T21:13:11.727 回答