2016-05-16 12 views
1

学習目的のために、画像をキャンバスにピクセル単位でランダムに描画するコードを記述しています。以下のコードにはlinkがあります。キャンバス:画像をピクセル単位で描画し、requestAnimationFrameのタイミングを

アニメーションを1秒以内に終了します。しかし、コンソールから見ると、約7秒かかります。私は小さい画像を試して、その数は1秒に近づいています。

この場合、requestAnimationFrameのタイミングは信頼できません。私はその原因を知りたい。それはputImageDataは、そのデータ配列のピクセルの1つを探しているので、あまりにも多くの時間がかかりますか?それとも他の何かが原因です。私はrequestAnimationFrameのタイミングが信頼できないときを知っていると思います。良いアニメーションを作るためには重要です。

さらに、私がやりたいことをするためのより良い方法はありますか?

// At first, I get the image's data, then I build an array whose 
// length is equal to the number of pixels of the image, each element 
// of the array represents one of the image's pixel. Then I shuffle 
// this array and pop a certain number of elements for 
// `ctx.putImageData` to draw the corresponding pixel per frame. 

var ctx = c.getContext("2d"), 
    img = new Image(); 
img.onload = init; 
img.src = "download.png"; //placehold.it's 300x200 image 

function formArr(w,h){ //Build image pixel outputting sequence array based on image's width and height 
    var arr = []; 
    for (i=0;i<w*h;i++){ 
    arr.push(i); 
    } 
    return arr; 
} 

function Point(i,w){ //locate pixel's X and Y base on image width 
    this.x = i%w; 
    this.y = Math.floor(i/w); 
} 

function shuffleRect(arr){ //shuffle the output sequence array 
    .... 
} 

function init(){ 
    var w = ctx.canvas.width = img.width*2; 
    var h = ctx.canvas.height = img.height*2; 
    //form Image Data 
    ctx.drawImage(img,0,0,w,h); 
    var imageData = ctx.getImageData(0,0,w,h); 
    ctx.clearRect(0,0,w,h); 

    //build output sequence 
    var sequence = formArr(w,h); 
    shuffleRect(sequence); 

    var sec = 1; //animation duration 
    var t1 = Date.now(); 
    function animate(){ 
    var pointsPerFrame = Math.floor(w*h/sec/60)+1; 
    for (i=0;i<Math.min(pointsPerFrame,sequence.length);i++){ 
     var j = sequence.pop(); 
     ctx.putImageData(imageData,0,0,new Point(j,w).x,new Point(j,w).y,1,1); //draw points for next frame 

    } 
    if(sequence.length){requestAnimationFrame(animate)}else{ 
     var t2 = Date.now(); 
     console.log(t2-t1); 

    } 
    } 
    animate(); 
} 
+0

あなたは実証するstacksnippetsまたはjsfiddleを作成できますか? – guest271314

答えて

3

drawImageのクリッピングバージョンを使用すると、putImageData

// directly copy from image to canvas 1 pixel at a time 
context.drawImage(image,x,y,1,1,x,y,1,1); 

しかし、合成がputImageData &のdrawImageより速いかもしれません使用してより高速になります...

第一、第二を作成メモリ内のキャンバスはイメージのサイズです。各アニメーションループに続い

:各新しいピクセル+ memoryContext.fill() + memoryContext.rect(x,y,1,1)memoryContext.beginPath

  • 第キャンバス上に新しいランダムな画素の必要な数を埋めます。
  • メインキャンバスを消去します。
  • メインキャンバスに補助キャンバスを描画します。drawImage(memoryCanvas,0,0)
  • メインキャンバスに合成を設定します。source-atop
  • drawImage画像をメインキャンバスに貼り付けます。合成すると、塗りつぶされたピクセルが存在する場所にのみイメージが表示されます。
  • メインキャンバスでsource-overに合成を戻します。

var canvas=document.getElementById("canvas"); 
 
var ctx=canvas.getContext("2d"); 
 
var canvas2=document.createElement("canvas"); 
 
var ctx2=canvas2.getContext("2d"); 
 
var cw=canvas.width; 
 
var ch=canvas.height; 
 

 
var newPixelCount; 
 
var accumPixelCount=0; 
 
var totPixels; 
 
var img=new Image(); 
 
img.onload=start; 
 
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/annotateMe.jpg"; 
 
function start(){ 
 
    cw=canvas.width=canvas2.width=img.width; 
 
    ch=canvas.height=canvas2.height=img.height; 
 
    newPixelCount=cw*ch/60; 
 
    totPixels=cw*ch; 
 
    t1=performance.now(); 
 
    requestAnimationFrame(animate); 
 
} 
 

 
function animate(){ 
 
    ctx2.beginPath(); 
 
    for(var i=0;i<newPixelCount;i++){ 
 
     accumPixelCount++; 
 
     if(accumPixelCount<totPixels){ 
 
      var y=parseInt(accumPixelCount/cw); 
 
      var x=accumPixelCount-y*cw; 
 
      ctx2.rect(x,y,1,1); 
 
     } 
 
    } 
 
    ctx2.fill(); 
 
    ctx.clearRect(0,0,cw,ch); 
 
    ctx.drawImage(canvas2,0,0); 
 
    ctx.globalCompositeOperation='source-atop'; 
 
    ctx.drawImage(img,0,0); 
 
    ctx.globalCompositeOperation='source-over'; 
 
    // 
 
    if(accumPixelCount<totPixels){ 
 
     requestAnimationFrame(animate); 
 
    }else{ 
 
     alert('Complete: '+parseInt(performance.now()-t1)+'ms'); 
 
    } 
 
} 
 

 
function animateDrawImage(){ 
 
    ctx2.beginPath(); 
 
    for(var i=0;i<newPixelCount;i++){ 
 
     accumPixelCount++; 
 
     if(accumPixelCount<totPixels){ 
 
      var y=parseInt(accumPixelCount/cw); 
 
      var x=accumPixelCount-y*cw; 
 
      ctx.drawImage(img,x,y,1,1,x,y,1,1); 
 
     } 
 
    } 
 
    // 
 
    if(accumPixelCount<totPixels){ 
 
     requestAnimationFrame(animate); 
 
    }else{ 
 
     alert('Complete: '+parseInt(performance.now()-t1)+'ms'); 
 

 
    } 
 
}
<canvas id="canvas" width=300 height=300></canvas>

+1

ありがとうございます。実際に私は以前に作曲を使っていたと思っていましたが、すでに描かれ放棄されているポイントを復元する方法を見つけることができませんでした。 – shenkwen

関連する問題