我正在使用的模拟器内部存储RGB值的1维帧缓冲区。但是,HTML5 canvas在调用putImageData时使用RGBA值。为了显示帧缓冲,我当前循环遍历RGB数组并以similar to this的方式创建一个新的RGBA数组。
这似乎不是最理想的。有很多关于快速执行画布绘制的文章,但我仍然对如何提高应用程序性能感到失望。有没有办法更快地将这个RGB阵列转换为RGBA阵列? alpha通道始终是完全不透明的。此外,有没有办法与画布接口,以便它采用RGB而不是RGBA值的数组?
答案 0 :(得分:4)
无法使用普通RGB,但可以通过删除重复计算,数组差异等来稍微优化该代码中的循环。
通常,您不应使用ctx.getImageData
来获取目标缓冲区 - 您通常不关心那里已有的值,而应使用ctx.createImageData
。如果可能的话,为每一帧重复使用相同的原始缓冲区。
但是,由于你想要将alpha值预设为0xff
(它们默认为0x00
)并且只需要这样做一次,所以填充画布似乎是最有效的然后使用getImageData
获取原始值。
ctx.fillStyle = '#ffffff'; // implicit alpha of 1
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
dest = ctx.getImageData(0, 0).data
然后对于每个帧只能保持不变的alpha字节:
var n = 4 * w * h;
var s = 0, d = 0;
while (d < n) {
dest[d++] = src[s++];
dest[d++] = src[s++];
dest[d++] = src[s++];
d++; // skip the alpha byte
}
您还可以尝试“循环展开”(即在while
循环内多次重复四行阻止),但结果会因浏览器而异。
由于您的像素总数很可能是4的倍数,只需重复该块三次,然后while
将仅针对每四个像素副本进行评估。
答案 1 :(得分:2)
ctx.createImageData和ctx.getImageData都会创建一个缓冲区,后面的(get)会慢一些,因为它还要复制缓冲区。
这个jsperf:http://jsperf.com/drawing-pixels-to-data
确认我们在Chrome上放慢了33%,在Firefox上放慢了16倍(当有32位或64位的Chrome副本移动时,FFF似乎是字节复制)。
我只记得你可以处理不同类型的类型数组,甚至可以在缓冲区上创建一个视图(image.data.buffer)。
因此,这可能允许您将4字节写入。
var dest = ctx.createImageData(width, height);
var dest32 = new Int32Array(dest.data.buffer);
var i = 0, j=0, last = 3*width*height;
while (i<last) {
dest32[j] = src[i]<<24 + src[i+1] << 16
+ src[i+2] << 8 + 255;
i+=3;
j++;
}
你会在这个jsperf测试中看到我做的更快 使用32位整数写: http://jsperf.com/rgb-to-rgba-conversion-with-typed-arrays 注意这些测试中存在一个大问题:因为这个测试是 在垃圾创建方面非常糟糕,准确性也是如此。 经过多次推出后,我们发现我们有50%左右 写入4与写入1相比。
编辑:可能值得一看的是,使用DataView读取源代码是否会加快速度。 但是输入数组必须是缓冲区(或者具有像Uint8Array这样的缓冲区属性)。 (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays/DataView)
不要犹豫,试试这个小提琴。
编辑2: 我不明白我重新运行测试,现在写4更慢:???之后再快一点:-------
无论如何,你很有兴趣将dest32缓冲区保留在你手中而不是 每次都创建一个新的,所以由于这个测试测量Int32Array的创建,它不符合你的用例。