Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/403.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/html/80.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 使用drawImage将大型图像复制到画布会导致大量内存使用_Javascript_Html_Canvas - Fatal编程技术网

Javascript 使用drawImage将大型图像复制到画布会导致大量内存使用

Javascript 使用drawImage将大型图像复制到画布会导致大量内存使用,javascript,html,canvas,Javascript,Html,Canvas,我有一个23552px乘以8192px的大图像,用于将多个1024px×1024px的单个图像组合成一个图像,类似于精灵图像用于组合图标/资源的方式 我使用Javascriptimage对象加载该图像 然后我用drawImage将1024 x 1024个平铺中的一个从大图中复制出来,并复制到相同大小的屏幕外画布(1024 x 1024)中 然后,我使用drawImage将该屏幕外画布复制到另一个相同大小的屏幕外画布上。通常,在我的真实应用程序中,第二个画布实际上是屏幕上的画布,但为了简化问题的再

我有一个23552px乘以8192px的大图像,用于将多个1024px×1024px的单个图像组合成一个图像,类似于精灵图像用于组合图标/资源的方式

我使用Javascript
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 您可以提供另一个屏幕外画布来保存当前OSC的可见部分,以停止在向self渲染时可能出现的一些反馈工件,但您应该从可用的分幅RAM的经验法则中减去该画布的RAM(有关RAM预算的详细信息,请参阅本文档的后续部分)

更多信息请参见注释1、2

这是如何显示大格式图像数据集的基础

改进此解决方案的一些方法 加载并刷新屏幕外画布。

在OSC与完整图像具有相同分辨率的完美世界中,缩放将是平滑和实时的。不幸的是,所提供的解决方案存在一些不需要的瑕疵,当放大显示时可能会变得模糊,当平移和缩小边缘的像素时将丢失,并且需要等待平铺填充。这是不可避免的

预测和预加载瓷砖

您可以通过预测用户正在进行的操作来缩短刷新OSC的时间