Mai*_*tor 2 javascript canvas getimagedata
为您提供一系列颜色,并且您希望用其内容填充画布,我知道的最快方式是:
var my_array = /* already have it */;
var img_data = ctx.createImageData(canvas.width, canvas.height);
for (var i=0; i<canvas.width*canvas.height; ++i)
img_data[i] = my_array[i];
ctx.putImageData(img_data,0,0);
Run Code Online (Sandbox Code Playgroud)
这似乎太慢了,因为我复制整个数组两次!一个让它img_data和另一个把它放在画布上.有没有办法简单地将原件my_array插入元素?
小智 5
请改用32位类型的数组.这将允许您为每次迭代复制整个"像素"(4个字节),从而将迭代次数减少到25%:
var buffer32 = new Uint32Array(img_data.data.buffer),
len = buffer32.length;
while(len--)
buffer32[len] = my_array[len];
ctx.putImageData(img_data,0,0);
Run Code Online (Sandbox Code Playgroud)
这意味着您还需要提供my_array32位数组.希望这可以帮助.
更新以解决"endianess":
如果您的数据来自系统(或其他原因)使用不同的字节顺序(LSB与MSB),您可以反转字节顺序(如果它们不同)或使用DataView代替您可以指定使用的字节顺序 - 例如endian由可选标志使用其set/get方法.
var my_buffer = new ArrayBuffer(size);
var dataView = new DataView(my_buffer);
var uint32lsb = dataView.getUint32(pos, true); // true = little-endian
Run Code Online (Sandbox Code Playgroud)
根据源缓冲区中的内容切换标志.
要测试目标系统的LSB/MSB(LSB =最低有效位优先或小端,MSB =最高有效位优先或大端),您可以:
function isLSB() {
var b = new Uint8Array([255, 0]);
return ((new Uint16Array(b, b.buffer))[0] === 255);
}
Run Code Online (Sandbox Code Playgroud)
您应该直接使用类型化数组而不是javascript数组进行主计算,因此您不必在以后进行转换:
var myArray = new Uint8Array(pixelCount);
Run Code Online (Sandbox Code Playgroud)
要么
var myArray = new Uint8ClampedArray(pixelCount);
Run Code Online (Sandbox Code Playgroud)
访问与标准js数组相同:
for (var pxIndex = 0; pxIndex<myArray.length; pxIndex+=4 ) {
// component for the (pxIndex >>2)th pixel :
var r = myArray[pxIndex ];
var g = myArray[pxIndex+1];
var b = myArray[pxIndex+2];
var a = myArray[pxIndex+3];
}
Run Code Online (Sandbox Code Playgroud)
这样你只需要复制这个数组来更新屏幕:
ctx.putImageData(my_array,0,0);
Run Code Online (Sandbox Code Playgroud)
请注意,您可以检索此数组的缓冲区,并在此数组上拥有另一个视图.
这样,您也可以使用32位视图一次执行4个字节的复制操作.
var sourceBuffer32 = new UInt32Array(myArray.buffer);
Run Code Online (Sandbox Code Playgroud)
如果您使用的是32视图,请记住每个系统的字节顺序可能不同,这会导致在阵列中加载ABGR(PC/mac)或RGBA.这对副本没有任何改变,但在某些情况下可能会令人讨厌(:-)).
不要忘记也可以使用ArrayBuffer切片功能复制数组缓冲区:
var myArrayCopy = new new Uint8ClampedArray(myArray.buffer.slice(0));
Run Code Online (Sandbox Code Playgroud)
你可以通过这个小函数知道字节序:
function isLittleEndian() {
// from TooTallNate / endianness.js. https://gist.github.com/TooTallNate/4750953
var b = new ArrayBuffer(4);
var a = new Uint32Array(b);
var c = new Uint8Array(b);
a[0] = 0xdeadbeef;
if (c[0] == 0xef) { isLittleEndian = function() {return true }; return true; }
if (c[0] == 0xde) { isLittleEndian = function() {return false }; return false; }
throw new Error('unknown endianness');
}
Run Code Online (Sandbox Code Playgroud)
您可以使用以下内容反转32位(ABCD - > DCBA):
function reverseUint32 (uint32) {
var s32 = new Uint32Array(4);
var s8 = new Uint8Array(s32.buffer);
var t32 = new Uint32Array(4);
var t8 = new Uint8Array(t32.buffer);
reverseUint32 = function (x) {
s32[0] = x;
t8[0] = s8[3];
t8[1] = s8[2];
t8[2] = s8[1];
t8[3] = s8[0];
return t32[0];
}
return reverseUint32(uint32);
};
Run Code Online (Sandbox Code Playgroud)