如何查看 canvas html5 上每个像素的变化

how to see each pixel being changed on the canvas html5

我在 javascript 中创建了一个滤镜,它反转了图像的颜色,即创建了一个负片图像,现在当我 运行 在浏览器中处理它时,它需要时间来处理,然后 returns 最后的底片图像。我怎样才能看到图像的每个像素都被反转而不仅仅是最终的反转图像?我不想等待代码在整个像素阵列上实现然后查看其效果,而是希望看到代码更改每个像素直到最后一个像素。

var imgData = ctx.getImageData(0,0,x.width,x.height);
var d = imgData.data;
        for (var i=0; i< d.length; i+=4) {
        d[i] = 255 - d[i];
       d[i+1] = 255 - d[i+1];
       d[i+2] = 255 - d[i+2];

        }
ctx.putImageData(imgData,0,0);

新代码

invert(d,0);
function invert(d,i){
    if(i < d.length){
         d[i] = 255 - d[i];
               d[i+1] = 255 - d[i+1];
               d[i+2] = 255 - d[i+2];
               d[i+3] = d[i+3];
               //alert(i);
               var n=i/4;
            var h=parseInt(n/x.width);

            var w = n - h*x.width;

            ctx.fillStyle='rgba('+d[i]+','+d[i+1]+','+d[i+2]+','+d[i+3]/255+')';

            ctx.fillRect(w,h,1,1);

            //if(i>91000){alert(i);}
          setTimeout(invert(d,i+4),50);
    }
    else{return ;}
    }

您可以 context.fillRect 在 canvas 上计算每个新更改的像素。

类似这样的东西(警告:未经测试的代码,可能需要两周时间!):

var n=i/4;
var y=parseInt(n/canvas.width);
var x=n-y*canvas.width;
context.fillStyle='rgba('+d[i]+','+d[i+1]+','+d[i+2]+','+d[i+3]/255')';
context.fillRect(x,y,1,1);

这里是演示代码,首先进行反相,然后显示随时间变化的效果:

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


var nextTime=0;
// a new line of converted image will be displayed
// after this delay
var delay=1000/60*2;
var y=0;

var imgData,d;

var img=new Image();
img.crossOrigin='anonymous';
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/sun.png";
function start(){

    cw=canvas.width=img.width;
    ch=canvas.height=img.height;
    
    ctx.drawImage(img,0,0);
    
    imgData=ctx.getImageData(0,0,cw,ch);
    d=imgData.data;
    
    for (var i=0; i< d.length; i+=4) {
        d[i] = 255 - d[i];
        d[i+1] = 255 - d[i+1];
        d[i+2] = 255 - d[i+2];
    }

    requestAnimationFrame(animate);
}

function animate(time){

    if(time<nextTime){requestAnimationFrame(animate); return;}
    nextTime=time+delay;
   
    for(var x=0;x<cw;x++){
        var i=(y*cw+x)*4;
        ctx.fillStyle='rgba('+d[i]+','+d[i+1]+','+d[i+2]+','+d[i+3]/255+')';
        ctx.fillRect(x,y,1,1);
    }

    if(++y<ch){
        requestAnimationFrame(animate);
    }else{
        ctx.putImageData(imgData,0,0);
    }

}
body{ background-color: ivory; }
#canvas{border:1px solid red;}
<canvas id="canvas" width=300 height=300></canvas>

您需要使用异步"loop"以便您可以更新一些像素,让显示器更新结果,然后继续。

JavaScript 是单线程的,因此在当前循环完成之前不会更新任何内容,因为线程已被该线程占用。

看着油漆变干

这是您可以使用的一种方法。您定义了一个 "batch" 大小,以要反转的像素数为单位(如果您想查看每个像素,1 是有效的,但这可能需要很长时间:

ie. 16.67ms x total number of pixels.

因此,如果您想使用 640x400 的图像显示每个像素更新(如下面的演示所示),则需要:

640 x 400 x 16.67ms = 4,267,520 ms, or more than an hour

注意事项(显示更新速度不能超过每 16.67 毫秒 = 60 fps)。下面我们每批使用 128 个像素。

实例

请注意,批处理值必须与图像的宽度匹配。 F.ex。如果您的图像是 640 像素宽,您可以使用 1、5、10、20、.. 64、128 等

如果您想要除 1 或分数值外的宽度不一定除以任何值,则必须进行简单计算以限制一行的最后一批,因为 getImageData() 需要参数来定义区域在图像中。或者,逐行执行...

您还可以对垂直图块使用 "batch" 值(在这种情况下,框可能是一个更好的术语)。

var img = new Image();
img.crossOrigin = "";
img.onload = painter;
img.src = "http://i.imgur.com/Hl3I0cx.jpg";

function painter() {

  // setup canvas and image
  var canvas = document.querySelector("canvas"),
      ctx = canvas.getContext("2d");
  
  // set canvas size = image size
  canvas.width = this.naturalWidth; canvas.height = this.naturalHeight;

  // draw in image
  ctx.drawImage(this, 0, 0);
  
  // prepare loop
  var batch = 128,
      x = 0, y = 0,
      w = canvas.width - batch,
      h = canvas.height;
  
  (function asyncUpdate() {
  
    // do one batch only
    var idata = ctx.getImageData(x, y, batch, 1),  // get a bacth of pixels
        data = idata.data,
        i = 0, len = data.length;
    
    while(i < len) {                               // invert the batch
      data[i] = 255 - data[i++];
      data[i] = 255 - data[i++];
      data[i] = 255 - data[i++];
      i++
    }
    
    ctx.putImageData(idata, x, y);                 // update bitmap
    
    x += batch;
    if (x > w) {                                   // check x pos
      x = 0;
      y++;
    }
    
    if (y < h) {                                  // new batch?
      requestAnimationFrame(asyncUpdate);         // let display update before next
    }
    else {
      // use a callback here...
      console.log("Done");
    }
  })();
}
<canvas></canvas>