使用 webworkers 和 canvas 合并 png 图像
Merge png images using webworkers and canvas
我正在尝试利用 web worker 将 png 数组合并为具有透明度的单个图像,就像 photoshop 在合并多个图层时所做的那样。
我这样做的原因是因为我将 olny 组合的结果保存到 indexeddb 中以供离线使用,然后我在 three.js 应用程序中使用该图像创建纹理.
场景是大约有 400 个产品,3d 平面上的纹理图像(产品)是 3 个图像(产品名称、价格和产品图像)的混合。
到目前为止我已经实现了这个,但是图像处理不是很好,我想知道如果我将 imageData.data
这是我目前拥有的,但我无法让它发挥作用。 (这是在没有网络工作者的情况下完成的,现在只是试图使合并工作)
var images = [];
var imageData = [];
images.push( function ( callback ) {
var mobile = new Image();
mobile.onload = function () {
console.log( "mobile loaded" );
callback( null, mobile );
};
mobile.onerror = function ( e ) {
console.log( "mobile error" );
callback( e, null );
};
mobile.src = "mobile.png";
} );
images.push( function ( callback ) {
var text = new Image();
text.onload = function () {
console.log( "text loaded" );
callback( null, text );
};
text.onerror = function ( e ) {
console.log( "text error" );
callback( e, null );
};
text.src = "text.png";
} );
async.series( images, function ( err, results ) {
if ( err ) {
console.error( err );
} else {
console.log( results );
getImageData( results );
}
} );
var getImageData = function ( images ) {
for ( var i = 0; i < images.length; i++ ) {
var canvas = document.createElement( 'canvas' );
canvas.width = 512;
canvas.height = 512;
var ctx = canvas.getContext( '2d' );
ctx.drawImage( images[ i ], 0, 0 );
imageData.push( ctx.getImageData( 0, 0, canvas.width, canvas.height ).data );
}
merge( imageData );
};
var merge = function ( data ) {
var merged = [];
var mixFactor = 0.5;
//var newPixel = imageMainPixel * mixFactor + imageSecPixel * ( 1 - mixFactor )
//for ( var i = 0, len = data.length; i < len; i++ ) {
for ( var j = 0, byteLen = data[ 0 ].length; j < byteLen; j += 4 ) {
var r = data[ 0 ][ j ] * mixFactor + data[ 1 ][ j ] * ( 1 - mixFactor );
var g = data[ 0 ][ j + 1 ] * mixFactor + data[ 1 ][ j + 1 ] * ( 1 - mixFactor );
var b = data[ 0 ][ j + 2 ] * mixFactor + data[ 1 ][ j + 2 ] * ( 1 - mixFactor );
var a = data[ 0 ][ j + 3 ] * mixFactor + data[ 1 ][ j + 3 ] * ( 1 - mixFactor );
merged[ j ] = r;
merged[ j + 1 ] = g;
merged[ j + 2 ] = b;
merged[ j + 4 ] = a;
}
//}
var canvas = document.getElementById( 'canvas' );
canvas.width = 512;
canvas.height = 512;
var ctx = canvas.getContext( '2d' );
var imageData = ctx.createImageData( 512, 512 );
imageData.data.set( merged );
ctx.putImageData( imageData, 0, 0 );
};
我目前遇到的错误是:
Uncaught RangeError: Source is too large
更新
我通过将我的合并功能更改为这个来设法合并图像:
var merge = function ( data ) {
var canvas = document.getElementById( 'canvas' );
canvas.width = 512;
canvas.height = 512;
var ctx = canvas.getContext( '2d' );
var imageData = ctx.createImageData( 512, 512 );
var mixFactor = 0.5;
for ( var j = 0, byteLen = data[ 0 ].length; j < byteLen; j += 4 ) {
imageData.data[ j ] = data[ 0 ][ j ] * mixFactor + data[ 1 ][ j ] * ( 1 - mixFactor );
imageData.data[ j + 1 ] = data[ 0 ][ j + 1 ] * mixFactor + data[ 1 ][ j + 1 ] * ( 1 - mixFactor );
imageData.data[ j + 2 ] = data[ 0 ][ j + 2 ] * mixFactor + data[ 1 ][ j + 2 ] * ( 1 - mixFactor );
imageData.data[ j + 3 ] = data[ 0 ][ j + 3 ] * mixFactor + data[ 1 ][ j + 3 ] * ( 1 - mixFactor );
}
console.log( imageData.data.length );
ctx.putImageData( imageData, 0, 0 );
};
结果是 2 张不透明度均为 50% 的图像。但这不是想要的结果。我只希望图像充当图层,例如将多个 png 一个放在另一个之上......如果顶部的那个有透明的地方,你应该能够看到它下面的图像。
也许我应该根据 alpha 值绘制?
经过一番思考,我最终检查了每个像素的 alpha 值,并设法完成了我想要的。我这样重写了合并函数:
var merge = function ( data ) {
var canvas = document.getElementById( 'canvas' );
canvas.width = 512;
canvas.height = 512;
var ctx = canvas.getContext( '2d' );
var imageData = ctx.createImageData( 512, 512 );
var mixFactor = 0.5;
for ( var j = 0, byteLen = data[ 0 ].length; j < byteLen; j += 4 ) {
// imageData.data[ j ] = data[ 0 ][ j ] * mixFactor + data[ 1 ][ j ] * ( 1 - mixFactor );
// imageData.data[ j + 1 ] = data[ 0 ][ j + 1 ] * mixFactor + data[ 1 ][ j + 1 ] * ( 1 - mixFactor );
// imageData.data[ j + 2 ] = data[ 0 ][ j + 2 ] * mixFactor + data[ 1 ][ j + 2 ] * ( 1 - mixFactor );
// imageData.data[ j + 3 ] = data[ 0 ][ j + 3 ] * mixFactor + data[ 1 ][ j + 3 ] * ( 1 - mixFactor );
imageData.data[ j ] = ( data[ 1 ][ j + 3 ] === 0 ? data[ 0 ][ j ] : data[ 1 ][ j ] );
imageData.data[ j + 1 ] = ( data[ 1 ][ j + 3 ] === 0 ? data[ 0 ][ j + 1 ] : data[ 1 ][ j + 1 ] );
imageData.data[ j + 2 ] = ( data[ 1 ][ j + 3 ] === 0 ? data[ 0 ][ j + 2 ] : data[ 1 ][ j + 2 ] );
imageData.data[ j + 3 ] = ( data[ 1 ][ j + 3 ] === 0 ? data[ 0 ][ j + 3 ] : data[ 1 ][ j + 3 ] );
}
console.log( imageData.data.length );
ctx.putImageData( imageData, 0, 0 );
};
仍然需要一些改进,但我想现在我将能够在网络工作者中合并图像:)
我写了a lib that handles this。不仅如此,它还能处理阴影和平铺。
修改后的代码为:
for ( var j = 0, byteLen = data[0].length; j < byteLen; j += 4 )
{
var rA = data[0][j], rB = data[1][j];
var gA = data[0][j+1], gB = data[1][j+1];
var bA = data[0][j+2], bB = data[1][j+2];
var aA = data[0][j+3], aB = data[1][j+3];
var rOut = (rA * aA / 255) + (rB * aB * (255 - aA) / (255*255));
var gOut = (gA * aA / 255) + (gB * aB * (255 - aA) / (255*255));
var bOut = (bA * aA / 255) + (bB * aB * (255 - aA) / (255*255));
var aOut = aA + (aB * (255 - aA) / 255);
imageData.data[j] = rOut;
imageData.data[j+1] = gOut;
imageData.data[j+2] = bOut;
imageData.data[j+3] = aOut;
}
这是解决方案(Alpha 混合)How to mix two ARGB pixels?
我正在尝试利用 web worker 将 png 数组合并为具有透明度的单个图像,就像 photoshop 在合并多个图层时所做的那样。
我这样做的原因是因为我将 olny 组合的结果保存到 indexeddb 中以供离线使用,然后我在 three.js 应用程序中使用该图像创建纹理.
场景是大约有 400 个产品,3d 平面上的纹理图像(产品)是 3 个图像(产品名称、价格和产品图像)的混合。
到目前为止我已经实现了这个,但是图像处理不是很好,我想知道如果我将 imageData.data
这是我目前拥有的,但我无法让它发挥作用。 (这是在没有网络工作者的情况下完成的,现在只是试图使合并工作)
var images = [];
var imageData = [];
images.push( function ( callback ) {
var mobile = new Image();
mobile.onload = function () {
console.log( "mobile loaded" );
callback( null, mobile );
};
mobile.onerror = function ( e ) {
console.log( "mobile error" );
callback( e, null );
};
mobile.src = "mobile.png";
} );
images.push( function ( callback ) {
var text = new Image();
text.onload = function () {
console.log( "text loaded" );
callback( null, text );
};
text.onerror = function ( e ) {
console.log( "text error" );
callback( e, null );
};
text.src = "text.png";
} );
async.series( images, function ( err, results ) {
if ( err ) {
console.error( err );
} else {
console.log( results );
getImageData( results );
}
} );
var getImageData = function ( images ) {
for ( var i = 0; i < images.length; i++ ) {
var canvas = document.createElement( 'canvas' );
canvas.width = 512;
canvas.height = 512;
var ctx = canvas.getContext( '2d' );
ctx.drawImage( images[ i ], 0, 0 );
imageData.push( ctx.getImageData( 0, 0, canvas.width, canvas.height ).data );
}
merge( imageData );
};
var merge = function ( data ) {
var merged = [];
var mixFactor = 0.5;
//var newPixel = imageMainPixel * mixFactor + imageSecPixel * ( 1 - mixFactor )
//for ( var i = 0, len = data.length; i < len; i++ ) {
for ( var j = 0, byteLen = data[ 0 ].length; j < byteLen; j += 4 ) {
var r = data[ 0 ][ j ] * mixFactor + data[ 1 ][ j ] * ( 1 - mixFactor );
var g = data[ 0 ][ j + 1 ] * mixFactor + data[ 1 ][ j + 1 ] * ( 1 - mixFactor );
var b = data[ 0 ][ j + 2 ] * mixFactor + data[ 1 ][ j + 2 ] * ( 1 - mixFactor );
var a = data[ 0 ][ j + 3 ] * mixFactor + data[ 1 ][ j + 3 ] * ( 1 - mixFactor );
merged[ j ] = r;
merged[ j + 1 ] = g;
merged[ j + 2 ] = b;
merged[ j + 4 ] = a;
}
//}
var canvas = document.getElementById( 'canvas' );
canvas.width = 512;
canvas.height = 512;
var ctx = canvas.getContext( '2d' );
var imageData = ctx.createImageData( 512, 512 );
imageData.data.set( merged );
ctx.putImageData( imageData, 0, 0 );
};
我目前遇到的错误是:
Uncaught RangeError: Source is too large
更新
我通过将我的合并功能更改为这个来设法合并图像:
var merge = function ( data ) {
var canvas = document.getElementById( 'canvas' );
canvas.width = 512;
canvas.height = 512;
var ctx = canvas.getContext( '2d' );
var imageData = ctx.createImageData( 512, 512 );
var mixFactor = 0.5;
for ( var j = 0, byteLen = data[ 0 ].length; j < byteLen; j += 4 ) {
imageData.data[ j ] = data[ 0 ][ j ] * mixFactor + data[ 1 ][ j ] * ( 1 - mixFactor );
imageData.data[ j + 1 ] = data[ 0 ][ j + 1 ] * mixFactor + data[ 1 ][ j + 1 ] * ( 1 - mixFactor );
imageData.data[ j + 2 ] = data[ 0 ][ j + 2 ] * mixFactor + data[ 1 ][ j + 2 ] * ( 1 - mixFactor );
imageData.data[ j + 3 ] = data[ 0 ][ j + 3 ] * mixFactor + data[ 1 ][ j + 3 ] * ( 1 - mixFactor );
}
console.log( imageData.data.length );
ctx.putImageData( imageData, 0, 0 );
};
结果是 2 张不透明度均为 50% 的图像。但这不是想要的结果。我只希望图像充当图层,例如将多个 png 一个放在另一个之上......如果顶部的那个有透明的地方,你应该能够看到它下面的图像。
也许我应该根据 alpha 值绘制?
经过一番思考,我最终检查了每个像素的 alpha 值,并设法完成了我想要的。我这样重写了合并函数:
var merge = function ( data ) {
var canvas = document.getElementById( 'canvas' );
canvas.width = 512;
canvas.height = 512;
var ctx = canvas.getContext( '2d' );
var imageData = ctx.createImageData( 512, 512 );
var mixFactor = 0.5;
for ( var j = 0, byteLen = data[ 0 ].length; j < byteLen; j += 4 ) {
// imageData.data[ j ] = data[ 0 ][ j ] * mixFactor + data[ 1 ][ j ] * ( 1 - mixFactor );
// imageData.data[ j + 1 ] = data[ 0 ][ j + 1 ] * mixFactor + data[ 1 ][ j + 1 ] * ( 1 - mixFactor );
// imageData.data[ j + 2 ] = data[ 0 ][ j + 2 ] * mixFactor + data[ 1 ][ j + 2 ] * ( 1 - mixFactor );
// imageData.data[ j + 3 ] = data[ 0 ][ j + 3 ] * mixFactor + data[ 1 ][ j + 3 ] * ( 1 - mixFactor );
imageData.data[ j ] = ( data[ 1 ][ j + 3 ] === 0 ? data[ 0 ][ j ] : data[ 1 ][ j ] );
imageData.data[ j + 1 ] = ( data[ 1 ][ j + 3 ] === 0 ? data[ 0 ][ j + 1 ] : data[ 1 ][ j + 1 ] );
imageData.data[ j + 2 ] = ( data[ 1 ][ j + 3 ] === 0 ? data[ 0 ][ j + 2 ] : data[ 1 ][ j + 2 ] );
imageData.data[ j + 3 ] = ( data[ 1 ][ j + 3 ] === 0 ? data[ 0 ][ j + 3 ] : data[ 1 ][ j + 3 ] );
}
console.log( imageData.data.length );
ctx.putImageData( imageData, 0, 0 );
};
仍然需要一些改进,但我想现在我将能够在网络工作者中合并图像:)
我写了a lib that handles this。不仅如此,它还能处理阴影和平铺。
修改后的代码为:
for ( var j = 0, byteLen = data[0].length; j < byteLen; j += 4 )
{
var rA = data[0][j], rB = data[1][j];
var gA = data[0][j+1], gB = data[1][j+1];
var bA = data[0][j+2], bB = data[1][j+2];
var aA = data[0][j+3], aB = data[1][j+3];
var rOut = (rA * aA / 255) + (rB * aB * (255 - aA) / (255*255));
var gOut = (gA * aA / 255) + (gB * aB * (255 - aA) / (255*255));
var bOut = (bA * aA / 255) + (bB * aB * (255 - aA) / (255*255));
var aOut = aA + (aB * (255 - aA) / 255);
imageData.data[j] = rOut;
imageData.data[j+1] = gOut;
imageData.data[j+2] = bOut;
imageData.data[j+3] = aOut;
}
这是解决方案(Alpha 混合)How to mix two ARGB pixels?