gpt4 book ai didi

javascript - 手动混合图像数据

转载 作者:行者123 更新时间:2023-12-01 02:54:45 24 4
gpt4 key购买 nike

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

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

从某种意义上说,这是 Canvas globalCompositeOperation“更轻”的手动实现。

"use strict";

let canvas = document.getElementById("canvas");
let width = canvas.width = window.innerWidth;
let height = canvas.height = window.innerHeight;
let ctx = canvas.getContext("2d");
ctx.fillStyle="black";
ctx.fillRect(0, 0, width, height);
let imageData = ctx.getImageData(0,0,width,height);
let data = imageData.data;

function random(min, max) {
let num = Math.floor(Math.random() * (max - min + 1)) + min;
return num;
}

function createColorArray(size, color) {

let arrayLength = (size*size)*4;
let array = new Uint8ClampedArray(arrayLength);

for (let i = 0; i < arrayLength; i+=4) {

switch (color) {
case 1:

array[i+0] = 255; // r
array[i+1] = 0; // g
array[i+2] = 0; // b
array[i+3] = 255; // a

break;

case 2:

array[i+0] = 0; // r
array[i+1] = 255; // g
array[i+2] = 0; // b
array[i+3] = 255; // a

break;

case 3:

array[i+0] = 0; // r
array[i+1] = 0; // g
array[i+2] = 255; // b
array[i+3] = 255; // a
}

}

return array;
}

function picture() {
this.size = random(10, 500);
this.x = random(0, width);
this.y = random(0, height);
this.color = random(1,3);
this.colorArray = createColorArray(this.size, this.color);
}

picture.prototype.updatePixels = function() {
let imageData = ctx.getImageData(this.x, this.y, this.size, this.size);
let data = imageData.data;

for (let i = 0; i < data.length; ++i) {
data[i]+=this.colorArray[i];
}

ctx.putImageData(imageData, this.x, this.y);
}

let pictures = [];
let numPictures = 50;

for (let i = 0; i < numPictures; ++i) {
let pic = new picture();
pictures.push(pic);
}

function drawPictures() {
for (let i = 0; i < pictures.length; ++i) {
pictures[i].updatePixels();
}
}

drawPictures();
<!DOCTYPE html>
<html>

<head>
<title>...</title>

<style type="text/css">
body {margin: 0px}
#canvas {position: absolute}
</style>

</head>

<body>
<div>
<canvas id="canvas"></canvas>
</div>

<script type="text/javascript" src="js\script.js"></script>
</body>

</html>

这个解决方案工作正常,但速度很慢。我不知道逐像素混合是否可以变得非常高效,但性能缓慢的一个原因可能是我需要获取 ImageData 并将其放回每次新图像混合到 Canvas 中。

因此,主要问题是我如何才能在开始时获取整个 Canvas ImageData 一次,然后根据需要混合到 Canvas 中的每张图片的位置和大小查找正确的像素进行更新,最后将更新的 ImageData 返回到 Canvas ?此外,非常感谢有关如何使混合更高效的任何其他想法。

最佳答案

使用数组方法。

填充数组的最快方法是使用 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;
}

使用|快速固定添加

如果您将 0xFF 添加到任何 channel ,并将 0 添加到其他 channel ,则可以使用 |和一个 32 位数组。对于 updatePixels 函数

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);

按位或| 类似于算术加法,可用于使用 32 位字来增加值。这些值将作为按位运算的一部分被钳位。

// dark
var red = 0xFF000088;
var green = 0xFF008800;
var yellow = red | green; // 0xFF008888

只要您仅使用 1 或 2 个运算符,就有许多其他方法可以使用 32 位运算来提高性能。更多,您最好使用字节。

如果你知道每个 channel 不会溢出一点,你也可以添加

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 Uint8ClampedArray

Uint8ArrayUint8ClampedArray 稍快,因为 Uint8Array 跳过了钳位,因此如果不需要钳位,请使用它结果。此外,int typedArray 在分配给它们时不需要舍入值。

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

您可以将数据从一个数组复制到另一个数组

var imageDataSource =  // some other source
var dataS = new Uint32Array(imageData.data.buffer);
var imageData = ctx.getImageData(this.x, this.y, this.size, this.size);
var data = new Uint32Array(imageData.data.buffer);

data.set(dataS); // copies all data

// or to copy a row of pixels
// from coords
var x = 10;
var y = 10;
var width = 20; // number of pixels to copy

// to coords
var xx = 30
var yy = 30

var start = y * this.size + x;
data.set(dataS.subArray(start, start + width), xx + yy * this.size);

不要转储缓冲区

如果不需要,不要继续获取像素数据。如果 putImageDatagetImageData 之间没有变化,则无需再次获取数据。保留一个缓冲区比不断创建新缓冲区要好。这样也能缓解内存压力,减少GC的工作量。

您确定不能使用GPU

您可以使用全局复合操作对像素数据执行各种操作。加、减、乘、除、反转这些速度要快得多,到目前为止,在您的代码中我看不出您需要访问像素数据的原因。

关于javascript - 手动混合图像数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46769789/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com