移动设备上糟糕的 Canvas GetImageData() / PutImageData() 性能
Posted
技术标签:
【中文标题】移动设备上糟糕的 Canvas GetImageData() / PutImageData() 性能【英文标题】:Horrible Canvas GetImageData() / PutImageData() performance on mobile 【发布时间】:2012-01-17 05:32:19 【问题描述】:我正在做一个 html5 小游戏,在地图开头加载我的精灵时,我使用 GetImageData()/循环遍历所有图像/PutImageData() 进行了一些处理。
这在我的 PC 上运行得非常好,但是在我的手机上却非常慢。
PC: 5-6 ms
iPhone 4: 300-600 ms
android HTC Desire S: 2500-3000 ms
我一直在做一些非常基本的基准测试,GetImageData 和 PutImageData 都运行得非常快,需要很长时间才能循环遍历内容。
现在,我显然预计手机会变慢,但 1000x 听起来有点过分,而且在我的 HTC 上加载大约需要 4 分钟,所以这行不通。此外,游戏中的其他一切都以非常合理的速度运行(主要是因为屏幕小得离谱,但对于手机上的 JS 来说,它仍然可以正常运行)
我在此处理中所做的基本上是将精灵“变暗”到一定程度。我只是循环遍历所有像素,然后将它们乘以
由于这太慢了...有没有更好的方法来做同样的事情,使用 Canvas 功能(合成、不透明度等),而不需要逐个循环遍历所有像素?
注意:该层有一些 100% 透明像素和一些 100% 不透明像素。两者都需要保持 100% 不透明或 100% 透明。
我认为行不通的事情: 1)在新的画布上绘制精灵,不透明度较低。这不起作用,因为我需要精灵保持不透明,只是更暗。 2)绘制精灵,并在它们上面绘制一个半透明的黑色矩形。这会使它们变暗,但它也会使我的透明像素不再透明......
有什么想法吗?
这是我正在使用的代码,以防万一你在其中看到一些非常愚蠢的东西:
function DarkenCanvas(baseImage, ratio)
var tmpCanvas = document.createElement("canvas");
tmpCanvas.width = baseImage.width;
tmpCanvas.height = baseImage.height;
var ctx = tmpCanvas.getContext("2d");
ctx.drawImage(baseImage, 0, 0);
var pixelData = ctx.getImageData(0, 0, tmpCanvas.width, tmpCanvas.height);
var length = pixelData.data.length;
for (var i = 0; i < length; i+= 4)
pixelData.data[i] = pixelData.data[i] * ratio;
pixelData.data[i + 1] = pixelData.data[i + 1] * ratio;
pixelData.data[i + 2] = pixelData.data[i + 2] * ratio;
ctx.putImageData(pixelData, 0, 0);
return tmpCanvas
编辑:这是我尝试对图像执行的操作的示例: 原文:http://www.crystalgears.com/isoengine/sprites-ground.png 变暗:http://www.crystalgears.com/isoengine/sprites-ground_darkened.png
谢谢! 丹尼尔
【问题讨论】:
请向我们展示您想要达到的效果前后的照片? 刚刚在问题底部添加了链接。谢谢! 你只是想让一些精灵变暗?看在上帝的份上,不要为此使用每像素图像数据。只需在顶部绘制半透明黑色(使用不同的globalCompositeOperation
以保留 alpha)。
谢谢!这正是我正在寻找的答案!我这样做是因为这是我在网络前时代的做法,所以我只知道这些。我应该使用哪种成分?另外,您能否将其发布为答案,以便我尽可能多地投票给您?谢谢!
【参考方案1】:
Phrogz 的想法是正确的。您真的只想使用“source-atop”globalCompositeOperation 在整个事物上绘制一个半透明(或比率透明)的黑色。
像这样:http://jsfiddle.net/F4cNg/
实际上有一个关于像这样复杂的变暗的好问题,但作者删除了它,这是一个真正的耻辱。当然可以在绘制的东西上制作深色蒙版,即使是复杂的形状。它们可能对您没有帮助,但为了完整起见,以及任何搜索“深色画布”的人,其中某些部分保持亮光(禁区),可以使用“xor”globalCompositeOperation 来完成,如下所示:
http://jsfiddle.net/k6Xwy/1/
【讨论】:
非常感谢,这正是我所需要的。我考虑使绘图的最终结果变暗。 XOR 技巧很酷,比我计划做的要简单得多,但即使没有它,我也可以画一个带有“孔”的矩形。那时,我不再关心我的透明像素了。但是,我没有采用这种方法,因为我使用的是 ISO 视角,而我的方法虽然速度较慢,但让我对我关心的一些事情有更高的准确性。不过,感谢您的提示,我一定会在某个时候派上用场。谢谢!!!【参考方案2】:您是否看过这个性能提示?: http://ajaxian.com/archives/canvas-image-data-optimization-tip
他们谈论减少对 DOM 的调用以提高性能。
因此,基于此提示,您可以尝试:
var pixel = ctx.getImageData(0, 0, tmpCanvas.width, tmpCanvas.height);
pixelData=pixel.data; // detach the pixel array from DOM
var length = pixelData.length;
for (var i = 0; i < length; i+= 4)
pixelData[i] = pixelData[i] * ratio;
pixelData[i + 1] = pixelData[i + 1] * ratio;
pixelData[i + 2] = pixelData[i + 2] * ratio;
您的 .data 调用可能会拖慢您的速度。
【讨论】:
绝对正确。虽然差别不大,但肯定会节省一些毫秒。?以上是关于移动设备上糟糕的 Canvas GetImageData() / PutImageData() 性能的主要内容,如果未能解决你的问题,请参考以下文章
Canvas getImageData在某些移动设备上返回不正确的数据