Javascript 用[rgba]颜色数组快速填充画布的方法

Javascript 用[rgba]颜色数组快速填充画布的方法,javascript,canvas,getimagedata,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,

如果您有一组颜色,并且希望用画布的内容填充画布,我所知道的最快方法是:

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);
var my_array=/*已经有了它*/;
var img_data=ctx.createImageData(canvas.width、canvas.height);

对于(var i=0;i使用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);
这意味着您还需要将
my_数组
作为32位数组提供。希望这对您有所帮助

更新地址“endianess”:

如果数据来自使用不同endian(LSB与MSB)的系统(或出于其他原因),则可以反转字节顺序(如果它们不同),或者使用
DataView
,其中可以通过使用其set/get方法的可选标志指定使用例如little endian

var my_buffer = new ArrayBuffer(size);
var dataView = new DataView(my_buffer);

var uint32lsb = dataView.getUint32(pos, true); // true = little-endian
根据源缓冲区中的内容切换标志

要测试目标系统的LSB/MSB(LSB=最低有效位优先或小尾数,MSB=最高有效位优先或大尾数),可以执行以下操作:

function isLSB() {
    var b = new Uint8Array([255, 0]);
    return ((new Uint16Array(b, b.buffer))[0] === 255);
}

对于主要计算,您应该直接使用类型化数组而不是javascript数组,这样以后就不必转换:

var myArray = new Uint8Array(pixelCount);

访问权限与标准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];
}
请注意,您可以检索此数组的缓冲区,并在此数组上拥有另一个视图。
这样,您还可以拥有一个32位的视图,一次执行4个字节的复制操作

var sourceBuffer32  = new UInt32Array(myArray.buffer);  
如果使用此32视图,请记住每个系统的端点可能不同,这会导致在阵列中加载ABGR(PC/mac)或RGBA。 这不会改变副本的任何内容,但在某些情况下可能会令人讨厌(:-)

不要忘记,还可以使用ArrayBuffer切片函数复制阵列缓冲区:

var myArrayCopy = new  new Uint8ClampedArray(myArray.buffer.slice(0));
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');
}

您可以通过这个小函数了解endianness:

var myArrayCopy = new  new Uint8ClampedArray(myArray.buffer.slice(0));
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');
}
您可以使用以下方法反转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);
};

为什么在循环的每次迭代中都要计算
canvas.width*canvas.height
?这只是一个例子,我实际上只是在使用
img\u data.data.set
。我也对JS引擎无法优化这一点感到愤怒,所以认为它是一个抗议。@ MaiViCor的原因可能不是优化的,你可能会改变<代码>的值:宽度<代码> >或>代码>高度>代码>循环内的属性。如果您不这样做,它很可能会得到优化。出于某种原因,使用它时,我的_数组应该遵循0xAABBGGRR格式。