【问题标题】:Animating with the `ImageData` data array causes very unexpected and glitch-like results使用“ImageData”数据数组制作动画会导致非常意外和类似故障的结果
【发布时间】:2018-10-24 06:38:37
【问题描述】:

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

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

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 );

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

所以缩小我的绘制区域更改了put ImageData 坐标以在绘制的图像和画布边缘之间获得一些空间,并且我更改了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,您将看到它的行为方式与第一个示例基本相同,但在预期的正方形和意外的线之间有空白。也就是说,我将 get 设置为 1,put 设置为零,这是迄今为止最有趣的行为。

【问题讨论】:

    标签: html5-canvas imagedata


    【解决方案1】:

    我稍微更改了您的代码。在您的双循环中,我声明了一个变量 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;。 当您对其进行动画处理时,由于imageDatatest() 函数内,因此您正在重新计算最后一帧底部的 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;
    }
    &lt;canvas id="canv" height="256" width="256"&gt;&lt;/canvas&gt;

    【讨论】:

    • 天啊 XD。所以我的嵌套循环的前四个循环是选择负索引位置?伙计,我为此感到很愚蠢。感谢您的回答。这解决了我的问题!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-04
    • 1970-01-01
    相关资源
    最近更新 更多