在Javascript中快速将RGB数组转换为RGBA数组

时间:2013-07-08 18:37:02

标签: javascript html5-canvas

我正在使用的模拟器内部存储RGB值的1维帧缓冲区。但是,HTML5 canvas在调用putImageData时使用RGBA值。为了显示帧缓冲,我当前循环遍历RGB数组并以similar to this的方式创建一个新的RGBA数组。

这似乎不是最理想的。有很多关于快速执行画布绘制的文章,但我仍然对如何提高应用程序性能感到失望。有没有办法更快地将这个RGB阵列转换为RGBA阵列? alpha通道始终是完全不透明的。此外,有没有办法与画布接口,以便它采用RGB而不是RGBA值的数组?

2 个答案:

答案 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的创建,它不符合你的用例。