2

キャンバスタグを使用して少しフルスクリーンの背景オーバーレイを接続し終えましたが、パフォーマンスの壁にぶつかりました。私が行ったことは、#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)で、適用されたフィルターを維持するために、そうでない場合は、デフォルトで元の画像に戻りますか?

誰かが最適化の提案がありますか?ありがとう!

4

1 に答える 1

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 x / 2などの2の倍数で除算する場合は、ビット単位のシフトと呼ばれるx>>1またはx<<1を実行できます。一部のブラウザは乗算を大幅に強化しているため、これを実行するのは実際にはもう速くありません(chrome)

とはいえ、WebGLシェーダーを使用できないことを前提としています。これまでのところ、シングルスレッドで低速なプロセッサを介して、一度に1つずつ各ピクセルをループする関数がありました。

https://github.com/mrdoob/three.js/-THREE.jsが登場します。これを使用すると、シェーダーを使用して、ビデオカードを介して一度に複数のピクセルをレンダリングできます。これが実際に行う唯一の方法です。すべてのピクセルに触れる必要がある場合は、速度が向上します。これにはwebGL対応のブラウザが必要です。つまり、とにかくキャンバスをサポートする可能性があるため、この回答が機能することを願っています。

于 2012-10-19T16:09:21.620 に答える