2012-11-04 178 views
2

我试图将全屏背景图像加载到画布上,然后将图像过滤器应用到它,但有几个问题。我遇到严重的性能问题,但只有在调整窗口大小时才会发生。基本上,我的代码试图保持画布/图像匹配屏幕尺寸(效果很好)。HTML5画布图像过滤器延迟(JavaScript)

UPDATE帆布方法:

的updateCanvas方法称为负载到最初创建/加载图像对象,并将其放置在画布上。如果选择了过滤器,则会调用过滤器方法。它接受onResize参数,该参数通过窗口大小调整来缩放画布/图像。 MAIN是指用于引用元素的对象。

updateCanvas:function(onResize){ 
     // SETUP VARIABLES 
    var img=new Image(), 
      $this=Main.currentOBJ, // REFERENCE FOR .DATA 
      objData=$this.data, 
      canvas=Main.OBJ.$Canvas[0], 
     ctx=canvas.getContext("2d"), 
      winW=$(window).width(), winH=$(window).height(); 

    // SOURCE CAN BE SET IN .DATA OR DEFAULT 
    img.src=(objData.bg_pic_src!=='') ? objData.bg_pic_src : Main.ConSRC; 

    // LOAD THE IMAGE OBJECT 
    img.onload=function(){ 
     var imgW=img.width, imgH=img.height, 
      ratio=imgW/imgH, newW=winW, newH=Math.round(newW/ratio); 

     // SETUP IMAGE PROPORTIONS 
     if(newH < winH){ var newH=winH, newW=Math.round(newH*ratio); }; 

     // WHEN RESIZING THE BROWSER 
     if(!onResize){ // INTIAL DRAW 
      Main.OBJ.$Canvas.attr({'width':newW+'px', 'height':newH+'px'}); 
      ctx.drawImage(img,0,0,newW,newH); 

      // APPLY FILTERS 
     if(objData.bg_pic_filter > 0){ 
      Main.canvasFilter(ctx,newW,newH); // FILTER METHOD 
     }else{ 
      Main.OBJ.$OverlayPic.animate({opacity:parseFloat(objData.bg_pic_opacity,10)}, 
     {duration:objData.bg_pic_speed_in,queue:false}); 
      }; 
    }else{ // RESIZING 
     Main.OBJ.$Canvas.attr({'width':newW+'px', 'height':newH+'px'}); 
     ctx.drawImage(img,0,0,newW,newH); 

     if(objData.bg_pic_filter > 0){ 
      Main.canvasFilter(ctx,newW,newH); // FILTER METHOD 
     };  
    }; 
}; 

画布筛选方法: 如果图像滤波程序待应用于背景图像,所述方法canvasFilter从canvasUpdate方法调用。

canvasFilter:function(ctx,width,height){ 
     // SETUP VARIABLES 
     var objData=Main.currentOBJ.data, 
     canvasWidth=width, canvasHeight=height, 
     imgdata=ctx.getImageData(0, 0, canvasWidth, canvasHeight), 
     pix=imgdata.data, l=pix.length; 

    // APPLY THE CORRECT LOOP DEPENDING UPON THE FILTER NUMBER 
    switch(objData.bg_pic_filter){ 
    case 1: ... break; 
    case 2: 
     for(var i=l; i>0; i-=4){ 
      var cacher=pix[i+2]; 
      pix[i]=pix[i+1]; 
      pix[i+1]=cacher; 
      pix[i+2]=cacher; 
      pix[i+3]=cacher; 
     }; 
    break; 
    };   

    // APPLY THE FILER & FADE IN THE BACKGROUND 
    ctx.putImageData(imgdata, 0, 0); 
    Main.OBJ.$OverlayPic.fadeTo(parseInt(objData.bg_pic_speed_in,10),  
     parseFloat(objData.bg_pic_opacity,10)); 
}; 

所有这些工作,并且初始绘制/过滤器相当快。但是,当我调整窗口大小时,它非常缓慢。我暂时通过加入一个节流器来解决这个问题,它只是设置一个计时器来避免上述功能太快。这稍微有所帮助,但会保留背景图像(显示图像周围的开放固体背景区域),直到调节器计时器启动并触发方法 - 调整画布/图像大小并应用过滤器。

问题:

  1. 有一个更快的方法?我已经阅读过使用Typed Arrays/Bitwise进行像素操作循环的问题,但似乎支持对此很可怕。我也研究过CSS3过滤器来完成同样的事情,但是再一次,支持是非常可怕的。那么,这是否将成为全屏幕背景图像过滤器与“现代浏览器”兼容性的唯一方法?

  2. updateCanvas方法每次创建一个新的图像对象,我想这可能是一个瓶颈,但我不确定,也不确定如何解决它?

  3. 我读过其他人使用单独的画布作为缓冲区?这实际上会提高我的表现吗?

  4. 我真的认为在我的代码中有一个主要的逻辑问题。对我来说,我需要不止一次地遍历所有的像素信息,但这是我获得它的唯一方法。是不是有一种方法可以绘制/应用过滤器一次,然后调整大小,只需调整尺寸而无需重新绘制/重新放置/重新应用过滤器?我认为它会保持过滤后的图像,但如果我在窗口大小调整中删除了对canvasFilter方法的调用,它将完全删除过滤器效果。

  5. 我还没有使用memoization技术,因为我从来没有完全理解它,并从来不明白何时何地使用它。但是,从本质上讲,如果我有一个一次又一次返回相同结果的函数(例如canvasFilter方法),我可以记忆以提高性能 - 或者它会有所不同,因为它在窗口调整大小后拉动不同的像素信息?

  6. 我也听说webGL渲染可能有帮助吗?因为我对webGL一无所知,可能会走开。

所以对于这个loooonng问题感到抱歉,但希望这涵盖了其他人可以从中受益的一些主题。任何建议/提示将不胜感激。谢谢! :)

+0

我是否正确理解加载时的所有行为,只是调整窗口大小就是问题所在?如果是,为什么你重画画布而不是用canvas.style.width =“1234px”调整大小?如果不是这样,一个在线版本将有助于理解,因为您似乎期望上面没有描述的独特效果。 – noiv

+0

对于其他画布绘制循环,您可能还需要阅读有关window.requestAnimationFrame的内容。基本上,浏览器会让你知道什么时候可以工作,而不是等待任意时间。参见:http://paulirish.com/2011/requestanimationframe-for-smart-animating/ –

回答

1

因为它听起来像你的图像大多是静态的,你可能想尝试的方法是使用良好的旧CSS。

这里的关键技巧是使用background-size:cover。请参阅:http://css-tricks.com/perfect-full-page-background-image/

所以从广义上讲:

  1. 载入图片
  2. 应用您的过滤器中的画布。 (画布甚至不需要连接到页面)。
  3. 出口画布数据通过URL:ctx.toDataUrl("image/png");
  4. 添加样式到您的容器元素或身体: background-size:cover;background:url('data:image/png;yourcanvasdata');
  5. 通过JS或CSS的过渡性质
  6. 动画的容器元素/体的透明度
+0

不错!这听起来很棒,我仍然对使用Canvas操作非常陌生,并且不知道.toDataUrl。听起来很完美 :) – Aaron