- objective-c - iOS 5 : Can you override UIAppearance customisations in specific classes?
- iphone - 如何将 CGFontRef 转换为 UIFont?
- ios - 以编程方式关闭标记的信息窗口 google maps iOS
- ios - Xcode 5 - 尝试验证存档时出现 "No application records were found"
我正在使用一个相对较大的 Canvas ,其中绘制了各种(复杂的)东西。然后我想保存 Canvas 的状态,以便稍后可以快速将其重置为现在的状态。我为此使用 getImageData 并将数据存储在变量中。然后,我在 Canvas 上绘制了更多内容,稍后将使用 putImageData 将 Canvas 重置为我保存它的状态时的状态。
但是,事实证明,putImageData 非常慢。事实上,它比简单地从头开始重新绘制整个 Canvas 要慢,后者涉及覆盖大部分表面的多个 drawImage,以及超过 40,000 次 lineTo 操作,然后是描边和填充。
从头开始重新绘制大约 2000 x 5000 像素的 Canvas 大约需要 170 毫秒,而使用 putImageData 则需要高达 240 毫秒。为什么 putImageData 与重绘 Canvas 相比如此慢,尽管重绘 Canvas 涉及用 drawImage 填充几乎整个 Canvas ,然后再次使用 lineTo、描边和填充用多边形填充大约 50% 的 Canvas 。所以基本上每个像素在重绘时至少被触及一次。
因为 drawImage 似乎比 putImageData 快得多(毕竟,重新绘制 Canvas 的 drawImage 部分只需要不到 30 毫秒)。我决定尝试不使用 getImageData 来保存 Canvas 的状态,而是使用 canvas.toDataURL,然后从数据 URL 创建一个图像,我会将其粘贴到 drawImage 中以将其绘制到 Canvas 上。事实证明,整个过程要快得多,只需要大约 35 毫秒即可完成。
那么为什么 putImageData 比替代方法(使用 getDataURL 或简单地重绘)慢得多?我怎样才能进一步加快速度?是否存在,如果存在,通常存储 Canvas 状态的最佳方式是什么?
(所有数字均使用 Firefox 中的 Firebug 测量)
最佳答案
只是关于执行此操作的最佳方法的小更新。我实际上在 High Performance ECMAScript and HTML5 Canvas 上写了我的学士论文(pdf,德语;密码:stackoverflow),所以我现在已经收集了一些关于这个主题的专业知识。显然最好的解决方案是使用多个 Canvas 元素。从一个 Canvas 绘制到另一个 Canvas 与将任意图像绘制到 Canvas 一样快。因此,当使用两个 Canvas 元素时,“存储” Canvas 的状态与稍后再次恢复它一样快。
This jsPerf testcase非常清楚地展示了各种方法及其优缺点。
只是为了完整起见,这里是您应该真正做到的:
// 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 倍。
关于performance - 为什么 putImageData 这么慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3952856/
我有一个 ImageData 对象,它包含所有监视器的屏幕截图,因此它是一个巨大的 ImageData。我现在想每次画一个显示器。我有所有的显示器尺寸。 所以我正在尝试使用 ctx.putImageD
我使用以下函数更新 Canvas 元素的内容,其中 frame_data 是 width*height*3 的数组。 function updateCanvas(frame_data, width,
在 Canvas 中恢复背景时遇到问题。我有一个 Canvas ,它可以根据选项的内容改变大小(它可以变得非常大),我在上面绘制图像,现在我想要一个指示器以类似网格的格式显示鼠标所在的位置。问题是绘制
我正在从文件中读取 RGB 值并尝试将它们放在 Canvas 上。 我尝试了许多不同的循环和增量值变体。 JavaScript: function parseData(data) { var p
我想制作一个使用此方法的分形生成器:https://www.johndcook.com/blog/2017/07/08/the-chaos-game-and-the-sierpinski-triang
我有一个 Canvas ,背景中有一个大图像,前面有一个较小的圆形图像。我通过像这样使用剪辑实现了这种圆形图像效果 ctx.save(); ctx.beginPath(); ctx.arc(x,y,r
似乎某些图 block 不会被绘制。我将一个 tileset 拆分为 32x32 的正方形,并使用 2D 100x100 数组将 map 绘制到 Canvas 上。 然后它为播放器设置“视口(view
在 html5 中,当您使用 putImageData() 绘制到 Canvas 时,如果您正在绘制的某些像素是透明的(或半透明的),您如何保持 Canvas 中的旧像素不受影响? 示例: var i
我正在使用一个相对较大的 Canvas ,其中绘制了各种(复杂的)东西。然后我想保存 Canvas 的状态,以便稍后可以快速将其重置为现在的状态。我为此使用 getImageData 并将数据存储在变
我正在处理 Angular 项目,我必须将图像放在 Canvas 上。图片不是本地存储的,我只有图片数据所以我用这个。 this.context.putImageData(imgData, first
我对虚拟 Canvas 的概念不熟悉,知道为什么下面的代码不起作用吗? $(document).ready(function () { var
我有以下代码: var img = new Image(); canvas = document.getElementById("c"); ctx = canvas.getContext('2d')
我正在尝试使用一些自定义代码绘制一个等距正方形来构建像素数据,然后使用 putImageData 将其放在 Canvas 上。 但我没有得到预期的结果,在快速浏览 Canvas 的原始像素数据后,我发
除了分别使用 getImageData 和 putImageData 之外,是否还有另一种方法可以将像素区域从(比如说) Canvas A 复制到 Canvas B。 此外,当复制到 Canvas B
我正在尝试从 websocket 读取像素(逐帧)并将其渲染到 Canvas 上(灰度)。数据显示正常,只是当前帧的像素与前一帧重叠显示。因此,几帧后图片就会被弄脏。 我想在渲染当前帧之前清除前一帧。
我想使用 HTML5 Canvas 绘制图像,转换图像,然后更改图像但保留我所做的转换。这可能吗? 这里有一些伪代码来说明我的问题: // initially draw an image and tr
我认为 putImageData 比 drawImage 快,但我需要证明这一点。 我想这与 Flash 及其 Bitmap 和 BitmapData 类的情况相同。基本上,BitmapData 有助
我知道 ctx.globalcompositeoperation=source-over 在使用 drawimage 时有效,但它可以与 putimagedata 一起使用吗? 最佳答案 简短的回答是
我正在尝试在 Node 服务器上托管 NES 模拟器 ( JSNES )。我知道您可以使用 unpkg 将 JSNES 嵌入网页中,但我希望它在服务器上运行,因为我希望多个客户端共享相同的状态。我 编
我最近一直在观看 Notch 在 twitch 上的一些直播,并对他几年前在 Ludum Dare 挑战赛中使用的一种渲染技术很感兴趣。我尝试将他的 java 代码转换为 javascript,但遇到
我是一名优秀的程序员,十分优秀!