我不认为代码正在做你认为它正在做的事情
首先,据我所知,您不能将新数据分配给 ImageData 所以这条线
cached_frame.data = frame.data;
什么都不做。我们可以测试表明它不起作用的那个
var ctx = document.createElement("canvas").getContext("2d");
document.body.appendChild(ctx.canvas);
var imageData = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);
var data = new Uint8ClampedArray(imageData.length);
// fill imageData.data with red
fillWithColor(255, 0, 0, 255, imageData.data);
// fill data with green
fillWithColor(0, 255, 0, 255, data);
// assign imageData.data to data
imageData.data = data;
// Draw. If assigning imageData.data works result will
// be green, if not result will be red
ctx.putImageData(imageData, 0, 0);
function fillWithColor(r, g, b, a, dst) {
for (ii = 0; ii < dst.length; ii += 4) {
dst[ii + 0] = r;
dst[ii + 1] = g;
dst[ii + 2] = b;
dst[ii + 3] = a;
}
}
其次,你的draw
函数是连续绘制的,至少从你发布的代码cached_frame
开始,它是在第 2 行设置的,所以它总是正确的并且总是在绘制。如果您以某种方式部分更新了实际数据,cached_frame
那么当只有部分结果时它将绘制。
我想你想要这样的东西
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var frame;
var framerate = 30;
function draw() {
context.putImageData(frame, 0, 0);
}
setInterval(function() {
frame = context.getImageData(0, 0, canvas.width, canvas.height);
// Do things to manipulate frame.data
// frame is ready, draw it at next rAF
requestAnimationFrame(draw);
}, 1000 / framerate);
如果您认为解码会比 raf 更快地发生,您可能想检查抽签是否已经排队。不过,在这种情况下,我认为您实际上并不需要 rAF。我很确定您可以在 setInterval 结束时进行绘制,它将显示在下一帧,不会撕裂。
这是一个测试,对我来说不会撕裂。
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var frame;
var framerate = 30;
var frameCount = 0;
setInterval(function() {
++frameCount;
frame = context.getImageData(0, 0, canvas.width, canvas.height);
var data = frame.data;
var width = frame.width;
var height = frame.height;
// Do things to manipulate frame.data
for (var yy = 0; yy < height; ++yy) {
for (var xx = 0; xx < width; ++xx) {
var offset = (yy * width + xx) * 4;
data[offset + 0] = ((xx >> 2 & 0x1) ^ frameCount & 0x1) ? 255 : 0;
data[offset + 3] = 255;
}
}
// frame is ready, draw it at next rAF
context.putImageData(frame, 0, 0);
}, 1000 / framerate);
<canvas id="canvas" width="1280" height="720"></canvas>