不清楚您想要实现什么。
根据您的描述
每一行从左到右进行处理。输出图像中像素的颜色计算方式为:
- 当前位置输入图像中的颜色
- 对于第一个像素之后的所有像素:前一个位置输出图片中的颜色,即向左移动一个像素
听起来你只是要将第一列涂抹在整个图像上。
- 第一列 = 第一列,
- 第二列 = 第一列,
- 第三列 = 第二列,
- 第四列 = 第三列。
从左到右处理就是重复第一列。如果是这样,只需调用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();
}
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);
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;
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
。这样做是为了能够看到刚刚绘制的新圆形。这意味着每帧至少有一个大内存分配来获取画布中像素的新副本。如果您不需要这样做,那么可以在初始化时进行复制,然后只需继续使用相同的数据。
outputImageContext.fillRect(x, y, 1, 1)
。因此,这应该是优化的第一件事情。 - feklee