Javascript 手动混合图像数据

Javascript 手动混合图像数据,javascript,arrays,canvas,getimagedata,putimagedata,Javascript,Arrays,Canvas,Getimagedata,Putimagedata,我有一个任务,我正试图以最有效的方式完成:我有不同数量不同大小的图片作为像素阵列,需要逐像素添加到画布中。必须将每个像素的值添加到画布的ImageData中,以便结果是两个或多个图像的混合 我目前的解决方案是从图片需要与图片大小混合的位置检索图像数据。然后我将图片的ImageData添加到检索到的ImageData中,并将其复制回同一位置 从某种意义上说,这是canvas GlobalComposite操作“打火机”的手动实现 “严格使用”; 让canvas=document.getEleme

我有一个任务,我正试图以最有效的方式完成:我有不同数量不同大小的图片作为像素阵列,需要逐像素添加到画布中。必须将每个像素的值添加到画布的ImageData中,以便结果是两个或多个图像的混合

我目前的解决方案是从图片需要与图片大小混合的位置检索图像数据。然后我将图片的ImageData添加到检索到的ImageData中,并将其复制回同一位置

从某种意义上说,这是canvas GlobalComposite操作“打火机”的手动实现

“严格使用”;
让canvas=document.getElementById(“canvas”);
让宽度=canvas.width=window.innerWidth;
let height=canvas.height=window.innerHeight;
设ctx=canvas.getContext(“2d”);
ctx.fillStyle=“黑色”;
ctx.fillRect(0,0,宽度,高度);
设imageData=ctx.getImageData(0,0,宽度,高度);
设data=imageData.data;
随机函数(最小值、最大值){
设num=Math.floor(Math.random()*(max-min+1))+min;
返回num;
}
函数createColorArray(大小、颜色){
设arrayLength=(大小*大小)*4;
让数组=新的Uint8ClampedArray(数组长度);
for(设i=0;i

...
正文{margin:0px}
#画布{位置:绝对}
使用数组方法。 填充数组的最快方法是使用
array.fill
函数

const colors = new Uint32Array([0xFF0000FF,0xFF00FF00,0xFFFF00]); // red, green, blue
function createColorArray(size, color) {
    const array32 = new Uint32Array(size*size);
    array32.fill(colors[color]);
    return array32;
}
var imageData = ctx.getImageData(this.x, this.y, this.size, this.size);
var data = new Uint32Array(imageData.data.buffer);
var i = 0;
var pic = this.colorArray;   // use a local scope for faster access
do{ 
    data[i] |= pic[i] ;  // only works for 0 and FF chanel values
}while(++i < data.length);
ctx.putImageData(imageData, this.x, this.y);
使用
|
如果要将0xFF添加到任何通道,将0添加到其他通道,则可以使用|和32位数组。对于
updatePixels
函数

const colors = new Uint32Array([0xFF0000FF,0xFF00FF00,0xFFFF00]); // red, green, blue
function createColorArray(size, color) {
    const array32 = new Uint32Array(size*size);
    array32.fill(colors[color]);
    return array32;
}
var imageData = ctx.getImageData(this.x, this.y, this.size, this.size);
var data = new Uint32Array(imageData.data.buffer);
var i = 0;
var pic = this.colorArray;   // use a local scope for faster access
do{ 
    data[i] |= pic[i] ;  // only works for 0 and FF chanel values
}while(++i < data.length);
ctx.putImageData(imageData, this.x, this.y);
只要只使用1或2个运算符,就有许多其他方法可以使用32位运算来提高性能。越多,使用字节就越好

如果您知道每个通道不会有一点溢出,也可以添加

a = 0xFF101010;  // very dark gray
b = 0xFF000080;  // dark red

// non overflowing add
c = a + b; // result is 0xFF000090 correct 

// as 0x90 + 0x80 will overflow = 0x110 the add will not work
c += b; // result overflows bit to green  0xFF000110 // incorrect
Uint8Array
V
uint8clampedaray
Uint8Array
uint8clampedaray
稍快,因为对
Uint8Array
跳过夹紧操作,因此如果不需要夹紧结果,请使用它。此外,int
typedArray
s在赋值时不需要对值进行舍入

var data = Uint8Array(1);
data[0] = Math.random() * 255; // will floor for you

var data = Uint8Array(1);
data[0] = 256; // result is 0
data[0] = -1; // result is 255

var data = Uint8ClampedArray(1); 
data[0] = 256; // result is 255
data[0] = -1; // result is 0
您可以将数据从一个数组复制到另一个数组 不要转储缓冲区 如果不需要,不要继续获取像素数据。如果它在
putImageData
getImageData
之间没有变化,则无需再次获取数据。与其持续创建新的缓冲区,不如保留一个缓冲区。这还将减轻内存压力并减少GC的工作负载

你确定不能使用GPU吗 您可以使用全局合成操作对像素数据执行广泛的操作。加法、减法、乘法、除法、求逆这些都要快得多,到目前为止,在您的代码中,我看不出您需要访问像素数据的原因。

使用数组方法。 填充数组的最快方法是使用
array.fill
函数

const colors = new Uint32Array([0xFF0000FF,0xFF00FF00,0xFFFF00]); // red, green, blue
function createColorArray(size, color) {
    const array32 = new Uint32Array(size*size);
    array32.fill(colors[color]);
    return array32;
}
var imageData = ctx.getImageData(this.x, this.y, this.size, this.size);
var data = new Uint32Array(imageData.data.buffer);
var i = 0;
var pic = this.colorArray;   // use a local scope for faster access
do{ 
    data[i] |= pic[i] ;  // only works for 0 and FF chanel values
}while(++i < data.length);
ctx.putImageData(imageData, this.x, this.y);
使用
|
如果要将0xFF添加到任何通道,将0添加到其他通道,则可以使用|和32位数组。对于
updatePixels
函数

const colors = new Uint32Array([0xFF0000FF,0xFF00FF00,0xFFFF00]); // red, green, blue
function createColorArray(size, color) {
    const array32 = new Uint32Array(size*size);
    array32.fill(colors[color]);
    return array32;
}
var imageData = ctx.getImageData(this.x, this.y, this.size, this.size);
var data = new Uint32Array(imageData.data.buffer);
var i = 0;
var pic = this.colorArray;   // use a local scope for faster access
do{ 
    data[i] |= pic[i] ;  // only works for 0 and FF chanel values
}while(++i < data.length);
ctx.putImageData(imageData, this.x, this.y);
只要只使用1或2个运算符,就有许多其他方法可以使用32位运算来提高性能。越多,使用字节就越好

如果您知道每个通道不会有一点溢出,也可以添加

a = 0xFF101010;  // very dark gray
b = 0xFF000080;  // dark red

// non overflowing add
c = a + b; // result is 0xFF000090 correct 

// as 0x90 + 0x80 will overflow = 0x110 the add will not work
c += b; // result overflows bit to green  0xFF000110 // incorrect
Uint8Array
V
uint8clampedaray
Uint8Array
uint8clampedaray
稍快,因为对
Uint8Array
跳过夹紧操作,因此如果不需要夹紧结果,请使用它。此外,int
typedArray
s在赋值时不需要对值进行舍入

var data = Uint8Array(1);
data[0] = Math.random() * 255; // will floor for you

var data = Uint8Array(1);
data[0] = 256; // result is 0
data[0] = -1; // result is 255

var data = Uint8ClampedArray(1); 
data[0] = 256; // result is 255
data[0] = -1; // result is 0
您可以将数据从一个数组复制到另一个数组 不要转储缓冲区 如果不需要,不要继续获取像素数据。如果它在
putImageData
getImageData
之间没有变化,则无需再次获取数据。与其持续创建新的缓冲区,不如保留一个缓冲区。这还将减轻内存压力并减少GC的工作负载

你确定不能使用GPU吗 您可以使用全局合成操作对像素数据执行广泛的操作。加、减、乘、除、反这些运算要快得多