如何在不重新排序的情况下将 BGRA 数组放入 canvas

How to put BGRA array into canvas without re-ordering

我有一个 BGRA 数组,需要将它绘制到 canvas。

目前我是这样做的:

var aVal = returnedFromChromeWorker;
var can = doc.createElementNS(NS_HTML, 'canvas');
can.width = aVal.width;
can.height = aVal.height;
var ctx = can.getContext('2d');

ctx.putImageData(aVal, 0, 0);

doc.documentElement.appendChild(can);

有什么方法可以将 BGRA 阵列放到 canvas 上吗?我正在探索:https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/imgIEncoder

我无法重新排序阵列,因为我的目标是截屏,对于大屏幕,即使只有 1280x1024,也需要 2.3 秒才能完成并重新排序。

我尝试在 ctypes 端重新排序,但它给了我一些奇怪的问题:0,使整个图像不可见 >_< 哈哈 BITMAPV5HEADER getting RGBA keep A at 255

How to put BGRA array into canvas without re-ordering

有none.

重组字节顺序是必要的,因为 canvas 只能保存 RGBA 格式的数据(little-endian,即缓冲区中的 ABGR)。这是一种方法:

您可以为您的工作人员添加一个额外的步骤来处理重新排序。为原始字节缓冲区(ArrayBuffer)创建一个DataView,然后迭代每个Uint32值。

Uint32以下被读取为little-endian。这是因为在这种情况下,格式更容易交换,因为我们只需要右移 BGR 并将 A 放回前面。如果您的原始缓冲区是大端模式,您当然需要将其读取为大端模式并设置为小端模式 (getUint32(pos, false)):

例子

var uint32 = new Uint32Array(1), pos = 0;  // create some dummy data
var view = new DataView(uint32.buffer);    // create DataView for byte-buffer
var pos = 0;                               // byte-position (we'll skip 4 bytes each time)

// dummy data in BGRA format
uint32[0] = 0x7722ddff; // magenta-ish in BGRA format
document.write("BGRA: 0x" + (uint32[0]).toString(16) +  "<br>");

// --- Iterate buffer, for each: ---
var v = view.getUint32(pos, true); // BGRA -> RGBA, read as little-endian
var n = (v >>> 8) | (v << 24);     // rotate - move A from last to first position
view.setUint32(pos, n, true);      // set back
pos += 4;                          // do this when inside the loop

// result
document.write("ABGR: 0x" + (uint32[0]>>>0).toString(16));

Update 如果两端的字节顺序(字节顺序)相同,您可以跳过 DataView 并直接使用 Uint32Array也会加快速度:

var uint32 = new Uint32Array(1), pos = 0;  // create some dummy data

// inside loop:
var v = uint32[pos];
uint32[pos++] = (v >>> 8) | (v << 24);  // pos index is now per uint32