为什么 putImageData 这么慢? [英] Why is putImageData so slow?

查看:45
本文介绍了为什么 putImageData 这么慢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用一个相对较大的画布,其中绘制了各种(复杂的)东西.然后我想保存 Canvas 的状态,以便我可以快速将其重置为以后的状态.我为此使用 getImageData 并将数据存储在变量中.然后我在画布上绘制更多的东西,稍后将使用 putImageData 将画布重置到我保存它的状态时的位置.

I am working with a relatively large Canvas where various (complex) stuff is drawn to. I then want to save the Canvas' state, so I can quickly reset it to the state it now is at a later point. I use getImageData for this and store the data in a variable. I then draw some more stuff to the canvas and will later reset the Canvas to where it was when I saved it's state, using putImageData.

然而,事实证明 putImageData 非常慢.事实上,它比简单地从头开始重绘整个 Canvas 要慢,这涉及覆盖大部分表面的几个 drawImage,以及超过 40.000 次 lineTo 操作,然后是笔触和填充.

However, it turns out, that putImageData is very slow. Infact, it is slower than simply redrawing the entire Canvas from scratch, which involves several drawImage covering most of the surface, and over 40.000 lineTo operations followed up by strokes and fills.

从头开始重绘大约 2000 x 5000 像素的画布需要大约 170 毫秒,而使用 putImageData 则需要高达 240 毫秒.为什么 putImageData 与重绘画布相比如此慢,尽管重绘画布涉及使用 drawImage 几乎填充整个画布,然后再次使用 lineTo、stroke 和 fill 用多边形填充大约 50% 的画布.所以基本上每个像素在重绘时至少会被触摸一次.

Redrawing the approx 2000 x 5000 pixel canvas from scratch takes ~ 170ms, using putImageData though takes whopping 240ms. Why is putImageData so slow compared to redrawing the canvas, although redrawing the canvas involves filling nearly the entire canvas with drawImage and then again filling roughly 50% of the canvas with polygons using lineTo, stroke and fill. So basicly every single pixel ist touched at least once when redrawing.

因为 drawImage 似乎比 putImageData 快得多(毕竟,重绘画布的 drawImage 部分需要不到 30 毫秒).我决定尝试不使用 getImageData 来保存画布的状态,而是使用 canvas.toDataURL 然后从数据 URL 创建一个图像,我会将其粘贴到 drawImage 中以将其绘制到画布上.事实证明,整个过程要快得多,只需大约 35 毫秒即可完成.

Because drawImage seems to be so much faster then putImageData (after all, the drawImage part of redrawing the canvas takes less than 30 ms). I decided to try to save the state of the canvas not using getImageData, but instead using canvas.toDataURL and then creating an Image from the data URL which I would stick into drawImage to draw it to the canvas. Turns out this whole procedure is much faster and only takes roughly 35ms to complete.

那么为什么 putImageData 比替代方法(使用 getDataURL 或简单地重绘)慢这么多?我怎样才能进一步加快速度?有没有,如果,一般来说,存储画布状态的最佳方式是什么?

So why is putImageData so much slower then the alternatives (using getDataURL or simply redrawing)? How could I speed things up further? Is there and if, what is in general the best way to store the state of a canvas?

(所有数字均使用 Firefox 中的 Firebug 测量)

(All the numbers are measured using Firebug from within Firefox)

推荐答案

只是关于执行此操作的最佳方法的一个小更新.我实际上是在 高性能 ECMAScript 和 HTML5 Canvas (pdf,德语;密码:stackoverflow),所以我现在收集了一些关于这个主题的专业知识.显然最好的解决方案是使用多个画布元素.从一个画布绘制到另一个画布与在画布上绘制任意图像一样快.因此存储"当使用两个画布元素时,画布的状态与稍后再次恢复它一样快.

Just a small update on what the best way is to do this. I actually wrote my Bachelor Thesis on High Performance ECMAScript and HTML5 Canvas (pdf, German; password: stackoverflow), so I gathered some expertise on this topic by now. The clearly best solution is to use multiple canvas elements. Drawing from one canvas onto another canvas is just as fast as drawing an arbitrary image to a canvas. Thus "storing" the state of a canvas is just as fast as restoring it later again when using two canvas elements.

这个 jsPerf 测试用例非常清楚地展示了各种方法及其优缺点.

This jsPerf testcase shows the various approaches and their benefits and drawbacks very clearly.

为了完整起见,这里是您应该如何做到的:

Just for completeness, here how you really should do it:

// setup
var buffer = document.createElement('canvas');
buffer.width = canvas.width;
buffer.height = canvas.height;


// save
buffer.getContext('2d').drawImage(canvas, 0, 0);

// restore
canvas.getContext('2d').drawImage(buffer, 0, 0);

根据浏览器的不同,此解决方案比获得赞成票的解决方案快 5000 倍.

This solution is, depending on browser, up to 5000x faster than the one getting the upvotes.

这篇关于为什么 putImageData 这么慢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆