Javascript 使用drawImage将大型图像复制到画布会导致大量内存使用
我有一个23552px乘以8192px的大图像,用于将多个1024px×1024px的单个图像组合成一个图像,类似于精灵图像用于组合图标/资源的方式 我使用JavascriptJavascript 使用drawImage将大型图像复制到画布会导致大量内存使用,javascript,html,canvas,Javascript,Html,Canvas,我有一个23552px乘以8192px的大图像,用于将多个1024px×1024px的单个图像组合成一个图像,类似于精灵图像用于组合图标/资源的方式 我使用Javascriptimage对象加载该图像 然后我用drawImage将1024 x 1024个平铺中的一个从大图中复制出来,并复制到相同大小的屏幕外画布(1024 x 1024)中 然后,我使用drawImage将该屏幕外画布复制到另一个相同大小的屏幕外画布上。通常,在我的真实应用程序中,第二个画布实际上是屏幕上的画布,但为了简化问题的再
image
对象加载该图像
然后我用drawImage将1024 x 1024个平铺中的一个从大图中复制出来,并复制到相同大小的屏幕外画布(1024 x 1024)中
然后,我使用drawImage将该屏幕外画布复制到另一个相同大小的屏幕外画布上。通常,在我的真实应用程序中,第二个画布实际上是屏幕上的画布,但为了简化问题的再现,我只是将第二个画布保留在屏幕外
从第一个画布到第二个画布的drawImage导致Mac上Chrome和Firefox的内存使用量增加了约700MB。我还没有弄清楚为什么会有这么大的数量,但是有一个非常简单的用例导致了它
几秒钟后700MB的使用被垃圾收集,所以我不认为这是内存泄漏,只是一个巨大的内存使用。在我的现实世界中,700MB的使用量使一些人的机器内存不足,并导致他们在Chrome中出现可怕的“Aw Snap!”
这里有一个链接,指向下面的代码,我正在使用的图像已打开。在Plunker上,您可以调出Activity Monitor或任何用于监视内存使用情况的工具,然后单击按钮开始运行下面的代码,并观察进程的内存使用情况增加>700MB
function drawcanvas() {
var oImage = new Image();
oImage.onload = function() {
console.log('image loaded');
// tile size in pixels, the image loaded is 23552 x 8192, which has 23 x 8 tiles
var tileSize = 1024;
// create a canvas that is not on DOM
var hiddenCanvas = document.createElement('canvas');
hiddenCanvas.width = tileSize;
hiddenCanvas.height = tileSize;
var hiddenContext = hiddenCanvas.getContext('2d');
// create another canvas that is not on DOM
var masterCanvas = document.createElement('canvas');
masterCanvas.width = tileSize;
masterCanvas.height = tileSize;
var masterContext = masterCanvas.getContext('2d');
// 1) drawing one tile, 1024 x 1024, from the big image into a canvas that is 1024 x 1024
// this causes negligible memory increaase by itself
hiddenContext.drawImage(oImage, 0, 0, tileSize, tileSize, 0, 0, tileSize, tileSize);
// 2) copy the 1024 x 1024 canvas into another canvas that is 1024 x 1024
// this causes about 700MB of memory usage in both Chrome & Firefox on Mac
masterContext.drawImage(hiddenContext.canvas, 0, 0, tileSize, tileSize, 0, 0, tileSize, tileSize);
console.log('processing done');
};
oImage.src = "http://i.imgur.com/VcIOEJF.png";
}
23552乘8192太大了
就像大家说的。太大了。一次看不到比设备显示分辨率更多的像素也是不可能的。因此,不仅RAM的使用量很大,使用的大部分RAM甚至不能作为像素查看,或者在缩小时组合成单个像素,或者在放大时关闭屏幕
总有解决方案
任何浏览器都可以显示任何分辨率的图像,例如,任何浏览器都可以用于创建任何分辨率的图像(如果您准备等待)
我对canvas的浏览器和客户端脚本编写有很多经验,但我不是这一特定领域的专家。请参阅最后一段,了解解决问题的第一站应该是什么。我提出的其余部分是一个概念性的解决方案,只是许多可能的解决方案中的一个
可能的解决方案
Op您说过要可视化包含在23*8 184块中的数据
除了最高端的机器,您不能将那么多的磁贴存储为Image
。但是,您可以根据需要加载它们,一旦缓存加载就会很快
用户只能看到显示器所能显示的像素数,因此用于显示数据的图像不应超过显示分辨率。您有一个宽的图像格式(Aspect 2.875:1),所以我假设您希望水平平移。我们可以适应宽格式,因为它不太可能出现问题(超过显示最大分辨率2-3倍的图像应视为太大)
由于图像具有如此高的分辨率,因此可以公平地假设用户能够以一对一的分辨率放大和查看像素
因此,全分辨率(全屏)下的1080HD显示器就是这种情况
以正确的角度创建屏幕外画布(OSC),以适合1080*2.875 3105*1080(屏幕外画布的像素预算)。由于我假设所有缩放都是均匀的,我们可以使用自然图像垂直分辨率(VR=8192)作为计算参考,即8192。我们将通过虚拟垂直分辨率VVR参考变焦。对于VVR=8192的全变焦(像素一对一),对于一半,则为VVR=4096,以查看图像,以便使用VVR=1080(显示分辨率)的所有显示像素(按比例填充)。要查看所有图像(按比例调整),VVR=Math.min(显示分辨率Hor/23552,显示分辨率垂直/8192)*VR=~0.0815(注意,在这种情况下,显示器的顶部和底部将为空)
使用VR计算平铺比例TS=VVR/VR。然后将每个磁贴作为图像加载,并在OSC上使用at scale TS渲染该图像。在(VVR