3

我正在使用的模拟器在内部存储 RGB 值的一维帧缓冲区。但是,HTML5 画布在调用 putImageData 时使用 RGBA 值。为了显示帧缓冲区,我目前循环遍历 RGB 数组并创建一个新的 RGBA 数组,其方式与此类似

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

4

2 回答 2

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

然后对于每一帧 for 可以保持 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),尽管结果会因浏览器而异。

由于您的像素总数很可能是四的倍数,因此只需再重复该块 3 次,然后while将仅对每四个像素副本进行评估。

于 2013-07-08T18:42:17.680 回答
2

ctx.createImageData 和 ctx.getImageData 都会创建一个缓冲区,后者 (get) 会更慢,因为它还必须复制缓冲区。这个 jsperf: http: //jsperf.com/drawing-pixels-to-data
确认我们在 Chrome 上的速度降低了 33%,在 Firefox 上慢了 16 倍(当 Chrome 复制 32 或 64 时,FFF 似乎是字节复制位移动)。

我只记得您可以处理不同类型的类型化数组,甚至可以在缓冲区(image.data.buffer)上创建一个视图。
因此,这可能允许您将字节 4 写入 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 请 注意 ,这些中存在一个大问题测试:由于该测试在垃圾创建方面非常糟糕,因此准确性一般。仍然在多次发布之后,我们看到写入 4 与写入 1 相比,我们获得了大约 50% 的收益。

编辑:可能值得看看使用 DataView 读取源代码是否不会加快速度。但输入数组必须是缓冲区(或具有像 Uint8Array 这样的缓冲区属性)。( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays/DataView )

不要犹豫,用这样的尝试来更新小提琴。

编辑2:我不明白我重新运行了测试,现在写4更慢:???之后,再次更快:--------

无论如何,您非常有兴趣将 dest32 缓冲区放在您的手下,而不是每次都创建一个新缓冲区,因此由于此测试测量 Int32Array 的创建,因此它不符合您的用例。

于 2013-07-09T17:10:10.873 回答