不清楚你想要完成什么。
根据你的描述
每一行都是从左到右处理的。输出图像中像素的颜色计算公式为:
- 输入图像中当前位置的颜色
- 对于第一个像素之后的所有像素:输出图片在前一个位置的颜色,即左侧一个像素
听起来您只是要将第一列涂抹在整个图像上。
- 第 1 列 = 第 1 列,
- 第 2 列 = 第 1 列,
- 第 3 列 = 第 2 列,
- 第 4 列 = 第 3 列。
从左到右处理只是重复的第一列。如果是这样,只需调用ctx.drawImage(ctx.canvas, 0, 0, 1, ctx.canvas.height, 0, 0, ctx.canvas.width, ctx.canvas.height);,它将使用画布作为图像,取第一列并将其展开以填充整个画布。
否则我并没有真正理解你的算法。对不起
无论如何,假设您确实需要立即引用先前像素的结果,然后进行一些操作。
切片 imagedata.data 以获取像素会很慢。每个切片都是一个内存分配。如果你想要速度,最好不要为每个像素创建一个新对象。
至于写作,是的,使用fillRect 一次设置一个像素会非常慢。直接在ImageData 中设置像素,然后将 ImageData 放回画布中怎么样?
否则,请尽量减少内部循环中的工作。如果你只能计算一次,那就只计算一次。
这里有一些混合成一个圆圈的代码。这不是那么慢,虽然我认为虽然慢是主观的。
var ctx = document.querySelector("canvas").getContext("2d");
var width = ctx.canvas.width;
var height = ctx.canvas.height;
function r(min, max) {
if (max === undefined) {
max = min;
min = 0;
}
return Math.random() * (max - min) + min;
}
function drawRandomCircle(ctx) {
var color = "hsl(" + r(360) + ", " + r(50, 100) + "%, 50%)";
ctx.beginPath();
ctx.arc(r(width), r(height), r(100), 0, Math.PI * 2, false);
ctx.fillStyle = color;
ctx.fill();
}
// put some image into the canvas so have something to work with
ctx.fillStyle = "white";
ctx.fillRect(0, 0, width, height);
for (var ii = 0; ii < 200; ++ii) {
drawRandomCircle(ctx);
}
function process(time) {
time *= 0.001;
drawRandomCircle(ctx);
// get a copy of the image
var imageData = ctx.getImageData(0, 0, width, height);
var pixels = imageData.data;
var xoff = Math.sin(time) * 15 | 0;
var yoff = Math.cos(time) * 15 | 0;
// blur
for (var y = 0; y < height; ++y) {
var lineOffset = (y + yoff + height) % height * width;
for (var x = 0; x < width; ++x) {
var off0 = (y * width + x) * 4;
var off1 = (lineOffset + (x + xoff + width) % width) * 4;
var r0 = pixels[off0 + 0];
var g0 = pixels[off0 + 1];
var b0 = pixels[off0 + 2];
var r1 = pixels[off1 + 0];
var g1 = pixels[off1 + 1];
var b1 = pixels[off1 + 2];
pixels[off0 + 0] = (r0 * 9 + r1) / 10;
pixels[off0 + 1] = (g0 * 9 + g1) / 10;
pixels[off0 + 2] = (b0 * 9 + g1) / 10;
}
}
ctx.putImageData(imageData, 0, 0);
requestAnimationFrame(process);
}
requestAnimationFrame(process);
<canvas width="1000" height="1000"></canvas>
请注意,上面的代码在每一帧getImageData 都会获得一个新的画布副本。它这样做是为了可以看到刚刚绘制的新圆圈。这意味着每帧至少有一个大内存分配来获取画布中像素的新副本。如果您不需要这样做,请在初始化时制作副本并继续使用相同的数据。