画布图像像素操作优化

时间:2012-10-04 04:57:18

标签: jquery html5 canvas

我已经使用canvas标签完成了一个小小的全屏背景覆盖,但已经打到了性能墙。我所做的是创建一个名为#OverlayPic的容器,并将其设置为100%x 100%,display:none。在这个容器里面是我的canvas元素。

当被触发时,jQuery将图像加载到画布上并将像素信息作为数组获取。 switch语句接受用户为其所需的过滤器效果设置的选项。代码一切正常,但速度非常慢(我认为这主要是由于我的结构如何,但我不确定更好的方法)。

updateCanvas:function(onResize){
    var img=new Image(); img.src=Main.ConSRC,
    img.onload=function(){
        var canvas=document.getElementById('Box_Canvas'),  
            ctx=canvas.getContext("2d"),
        winW=$(window).width(), winH=$(window).height(), 
            imgW=this.width, imgH=this.height, smallestSide=Math.min(imgW,imgH);

    // SETUP IMAGE PROPORTIONS
    switch(smallestSide){
       case imgW: 
           var width=winW,height=width*(imgW/imgH);
           if(height < winH){ var height=winH, width=height*(imgW/imgH); };
        break;
        case imgH: 
           var height=winH,width=height*(imgW/imgH);
           if(width < winW){ var width=winW, height=width*(imgH/imgW); };
        break;
    };

        // DRAW IMAGE ON THE CANVAS
        ctx.clearRect(0, 0, width*1.3, height*1.3 );
    ctx.drawImage(img,0,0,width*1.3,height*1.3);

    // IMAGE FILTERS
    var imgdata=ctx.getImageData(0, 0, width, height), pix=imgdata.data, l=pix.length;
    switch($this.data.bg_pic_filter){
          // all filter code cases are here...
    };          

    // APPLY THE FILER
    ctx.putImageData(imgdata, 0, 0);

    // FADE IN OVERLAY
    if(!onResize){
           Main.OBJ.$OverlayPic.fadeTo( $this.data.bg_pic_speed, $this.data.bg_pic_opacity);
        };

    };
},

此功能在2个地方被调用。

  1. 当用户单击指定的元素时,叠加淡入并且画布将加载过滤后的图像。

  2. 在窗口调整大小事件(onResize arg)上,为了维护已应用的过滤器,否则它只是默认返回原始图像?

  3. 有没有人有任何优化建议?谢谢!

1 个答案:

答案 0 :(得分:1)

嗯,你看,你有一个巨大的图像,即使它只有600x600,仍然是36,000像素,所以即使你的//all filter code cases are here...有类似的东西

case default:
   var totalPixels = imagedata.data.length * .25; //divide by 4 now, since dividing is expensive compared to multiplication ( multiply by a decimal place is sometimes cheaper than dividing using /, most browsers have fixed this though[ this is important if you need to know multiple colors at once ] )
   _data = imagedata.data
   for( var i = totalPixels-1; i>=0; i-- ){

     var index = i * 4 // this might be slower (creating a variable inside the loop) -- see next 2 lines

     _data[i * 4] += 1 // these next 2 lines are identical
     _data[index] += 1 // it might be faster to create an index, so you don't have to multiply, though usually multiplying is cheap and creating a variable inside a loop is expensive, so even if you have to multiple i * 4 a bunch, it might be faster than creating index

      _data[index + 1] +=2 //green
      _data[index + 2] +=2 //blue
      _data[index + 3] +=2 //blue

   }

所以,如你所见,你做了多次3600次X 4次(每个像素1次)

这是测试很重要的地方 - 比较相同的东西以提高不同浏览器的性能

使用/ 4除以有时比乘以小数* .25慢 如果你除以2的倍数,例如x / 2,你可以做x&gt;&gt; 1或x&lt;&lt; 1,称为按位移位,虽然有些浏览器已经增加了它们的倍增,实际上不再那么快了(chrome)

所有人都说,假设你不能使用web gl着色器。看,到目前为止,我们已经有了一个函数来循环遍历每个像素,一次一个,通过处理器,这是单线程和慢速。

来自https://github.com/mrdoob/three.js/ - THREE.js,它允许您使用着色器,这样您就可以通过视频卡一次渲染多个像素,这是获得更快速度的唯一方法触摸每个像素。这需要一个支持webGL的浏览器,这意味着你可能无论如何都支持画布,所以希望这个答案有效。