簡體   English   中英

使用Webworkers和Canvas合並png圖像

[英]Merge png images using webworkers and canvas

我正在嘗試利用網絡工作者,以便將png數組合並為具有透明度的單個圖像,就像合並多個圖層時的photoshop一樣。

我這樣做的原因是因為我將組合的結果全部保存到indexeddb中以供脫機使用,然后在我的three.js應用程序中使用該圖像創建紋理。

場景是大約有400種產品,並且紋理-3d平面(產品)上的圖像是3個圖像(產品標題,價格和產品圖像)的混合。

到目前為止,我已經實現了這一點,但是圖像處理並不是那么好,我想知道如果我將其傳遞給imageData.data話,我該如何對Web工作者進行處理?

這是我到目前為止所擁有的,但是我無法使其正常工作。 (現在無需網絡工作人員就可以嘗試使合並正常進行)

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

};

結果就像兩張都具有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 );

};

仍然需要一些改進,但是我想現在我可以在Web worker中合並圖像了:)

修改后的代碼是:

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混合) 如何混合兩個ARGB像素?

我寫了一個庫來處理這個問題 不僅如此,它還可以處理陰影和圖塊。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM