0

ImageData我最近使用数据数组在画布上拉伸了一个渐变;即ctx.getImageData()andctx.putImageData()方法,我心想,“这可能是一种非常有效的方法来为充满移动对象的画布设置动画”。所以我将它与语句一起包装到我的 main 函数requestAnimationFrame(callback)中,但那是事情变得奇怪的时候。我能做的最好的描述就是说它就像画布上最左边的像素列被复制到最右边的像素列中,并且根据您为getput ctx方法指定的坐标,这可能会产生奇怪的后果。

我开始使用针对画布的 get 和 put 方法,0, 0如下所示:

imageData = ctx.getImageData( 0, 0, cvs.width, cvs.height );

//  here I set the pixel colors according to their location
//  on the canvas using nested for loops to target the
//  the correct imageData array indexes.

ctx.putImageData( imageData, 0, 0 );

但我立即注意到画布的右侧是错误的。就像渐变已经重新开始一样,最后一个像素由于某种原因没有被触及:

在此处输入图像描述

所以缩小我的绘制区域更改了putImageData 坐标以在绘制的图像和画布边缘之间获得一些空间,并且我更改了get坐标以消除画布右边缘的那条线:

imageData = ctx.getImageData( 1, 1, cvs.width, cvs.height );

for ( var x = 0; x < cvs.width - 92; x++ ) {
    for ( var y = 0; y < cvs.height - 92; y++ ) {
        // array[ x + y * width ] = value / x; // or similar
    }
}

ctx.putImageData( imageData, 2, 2 );

在此处输入图像描述

漂亮的!但是错了...所以我在codepen中复制了它。有人可以帮助我理解和克服这种行为吗?

注意:codepen 具有按比例缩小的绘图区域。如果将get坐标更改为 0,您将看到它的行为方式与第一个示例基本相同,但在预期的正方形和意外的线之间有空白。也就是说,我将getat 1 和putat 0 留给了最有趣的行为。

4

1 回答 1

0

我已经稍微改变了你的代码。在您的双循环中,我声明了一个变量var i = (x + y*cvs.width)*4;这只是减少了代码的冗长,以便我可以更好地看到它。i 变量表示您的像素在 imageData.data 数组中的索引。既然你在做

        imageData.data[i - 4 ] ...
        imageData.data[i - 3 ] ...
        imageData.data[i - 2 ] ...
        imageData.data[i - 1 ] ...

您将向后移动一个像素,每行的第一个像素显示为前一行的最后一个像素。所以我把它从var i = (x + y*cvs.width)*4;改为var i = 4 + (x + y*cvs.width)*4;。当您对其进行动画处理时,由于 位于函数imageData内部test(),因此您正在重新计算最后一帧基础中的 imageData.data 数组的值。因此,在第二帧中,您将第一帧的 1px 线再次复制并向上移动 1px 和向左移动 1px。

我希望这是你问的。

var ctx, cvs, imageData;
	cvs = document.getElementById('canv');
	ctx = cvs.getContext('2d');

function test() {
	
	// imageData = ctx.getImageData( 0, 0, cvs.width, cvs.height );
	  // produces a line on the right side of the screen
	
	imageData = ctx.getImageData( 1, 1, cvs.width, cvs.height );
	  // bizzar reverse cascading
	
	for (var x=0;x<cvs.width-92;x++) {
		for (var y=0;y<cvs.height-92;y++) {
			var i = 4+(x + y*cvs.width)*4;
			imageData.data[i - 4 ] = Math.floor((255-y)-Math.floor(x/55)*55);
			imageData.data[i - 3 ] = Math.floor(255/(cvs.height-92)*y);
			imageData.data[i - 2 ] = Math.floor(255/(cvs.width-92)*x);
			imageData.data[i - 1 ] = 255;
		}
	}
	
	ctx.putImageData( imageData, 0, 0 );
	
	requestAnimationFrame( test );
	
}

test();
canvas {
	box-shadow: 0 0 2.5px 0 black;
}
<canvas id="canv" height="256" width="256"></canvas>

于 2018-10-24T10:11:42.413 回答