canvas如何管理数据?

时间:2013-11-28 11:37:06

标签: canvas preload

我是使用canvas元素的新手,我不得不说我对它的强大印象深刻。

我一直在阅读有关这个​​主题的内容,如果我不感到困惑,画布只会知道像素。因此,当应用程序执行如下代码时:

$.fn.reBuildScooter = function(canvas, ctx, scoPath, supPath, sustPath, colourPath) {
    var sco = new Image();
    sco.onload = function() {
        var sup = new Image();
        sup.onload = function() {
            var sust = new Image();
            sust.onload = function() {
                ctx.clearRect ( 0 , 0 , canvas.width , canvas.height );
                ctx.drawImage(sco, 0, 0);

                ctx.globalAlpha = 1;
                ctx.globalCompositeOperation = 'destination-out';
                ctx.drawImage(sup, 0, 0);
                console.log(sup.src + ' LOADED!');

                ctx.globalCompositeOperation = 'source-in';
                ctx.drawImage(sco, 0, 0);
                console.log(sco.src + ' LOADED!');

                ctx.globalCompositeOperation = 'source-over';
                ctx.drawImage(sust, 0, 0);
                console.log(sust.src + ' LOADED!');

                if (colourPath !== '') {
                    jQuery().paintScooter(canvas, ctx, colourPath);
                }
            }
            sust.src = sustPath;
        }
        sup.src = supPath;
    }
    sco.src = scoPath;
}

它正在将图像从服务器加载到客户端,并在加载时将其渲染到画布中。

如果scoPath与之前的通话图像相同,会发生什么? 它是从服务器再次提供的,还是自动从浏览器缓存中获取?

所以,

  • 如果我编写预加载功能,当我需要将它们添加到画布时,图像将可用...?
  • 当调用clearRect方法时,从画​​面加载的先前图像将从画布中删除,因此再次渲染它们意味着从服务器加载新的图像?

如果您感兴趣我正在开发一个应用程序,需要通过合成创建一个其他人的图像,就像设计师使用photoshop / gimp处理图层蒙版一样。所以总有一个基本图像使用相同。图像非常大(其中一些可能有~200KB),这是我无法改变的,但我需要管理。

完全应用程序现在有超过3000个图像,并计划使用双倍或更多。

我进入画布作为在服务器端创建图像的替代解决方案,图像库为GD,Imagick等......因为我们需要尽可能减少处理图像的时间。

我将非常感谢您从您的经历中得到的澄清和提示。

提前致谢, ·_-

1 个答案:

答案 0 :(得分:0)

通常,通过浏览器加载的图像保存在内存缓存中。除非内存非常少,否则图像通常会停留在那里,否则浏览器将不得不清除内存缓存(与处理未引用对象的GC无关)或部分内存缓存,并从本地重新加载图像一些磁盘缓存(如果已启用)或再次从服务器,如果由于某种原因本地磁盘缓存被禁用或已完全导致以前加载的图像被删除(注意:这取决于浏览器,这以简化的方式描述了该方法 - 一些浏览器拥有先进的加载系统,可以在一个页面中处理数千个图像,例如最近的Firefox)。

在任何情况下,如果这是你的意思,你不需要考虑再次设置src。浏览器将在内部处理所有加载。您只需要确保像在示例中一样处理第一个异步加载。如果图像有参考,它将可用。据说你可能必须处理特殊的浏览器,这些浏览器在这方面做了一些古怪的事情(hrm..IE..he)。

200 kb对图像的描述非常少。它可以是未压缩的PNG以及大量压缩的JPEG。什么是像素尺寸。由于浏览器中加载的所有图像都转换为未压缩的RGBA,因此内存使用量将是(最小值)width x height x 4。然后有用于它的临时存储器,并且很可能还有其他缓冲区,这取决于绘制的场景和方法等(通过浏览器)。但也要记住更高级的浏览器,它们可以在一个页面中处理成千上万的图像,所以这可能不会成为一个巨大的问题。

图像加载本身与canvas元素无关。无论是图像还是您绘制的形状,您在画布上绘制的内容都与此无关。除了实际绘制之外,画布不会以任何方式锁定/引用图像 - 之后从画布的角度来看图像被遗忘,但只要它具有对图像的引用,图像仍将如开头所述那样可用。它。图像通常是与DOM相关的资源,在某些情况下是JavaScript,即。作为类型化数组等。

当你触摸时,画布是无源的,所以它不知道像素来自何处或者在哪个区域,顺序等等中画出像素。它只是保持最终结果像素混合来自这些不同的操作。所有跟踪和机制都需要在画布外部使用自定义对象等完成。

3000 - 6000+图像对于浏览器应用程序(IMO)听起来有点多,但如果系统上有足够的内存,那么本身就不会有问题 - 只是不要指望用户与开发者机器具有相同的规格(或快速连接),因此准备好处理错误(一如既往)和住院用户......

你应该考虑缓存这些图像的组合和/或制作一个按需加载图像的加载/参考系统 - 效率如何取决于用户配置(缓存大小,缓存启用,内存,互联网连接等) 。)但是如何做到这一点超出了这里的范围。

另外,如果可以,你可以使用图片加载器作为我的YAIL bulk image loader,至少可以处理初始图像加载。

为避免GC移除图像,您需要确保始终保留对图像的引用。在您的示例代码中,某些图像的引用将超出范围,GC可能会从内存中删除该图像。

$.fn.reBuildScooter = function(canvas, ctx, scoPath, supPath, sustPath, colourPath) {

    /// this is only available inside reBuildScooter and to the children scopes
    var sco = new Image();
    sco.onload = function() {

        /// sup is only available inside this function and to children
        /// when function returns sup will be lost when sco.onload.. returns
        var sup = new Image();
        sup.onload = function() {

            /// same as with sup...
            var sust = new Image();
            sust.onload = function() {
                ctx.clearRect ( 0 , 0 , canvas.width , canvas.height );
...

为了保持对图像的引用,您必须将它们移动到全局范围或在对象的实例内“root” - 例如:

$.fn.reBuildScooter = function(canvas, ctx, scoPath, supPath, sustPath, colourPath) {

    var sup;
    var sust;
    var sco = new Image();

    sco.onload = function() {

        /// sup is now available within the reBuildScooter
        sup = new Image();
        sup.onload = function() {

            /// same as with sup...
            sust = new Image();
            sust.onload = function() {
                ctx.clearRect ( 0 , 0 , canvas.width , canvas.height );
...

只要您的reBuildScooter对象存在(在这种情况下可能会存在),内部变量也将保持活动状态,GC将不会收集。但是浏览器仍然可以清除内存缓存,但它在很大程度上是透明的(对于较低规格的系统,性能可能会降低)。

希望这能提供一些意见。