Skip to content Skip to sidebar Skip to footer

Blending Two Images With Html5 Canvas

I need to draw 2 variations of the same image on top of each other, whose alpha values add up to 1. For example : - imageA has an alpha of 0.4, while imageB has an alpha of 0.6.

Solution 1:

• If you look at the canvas'context2D specification about the default blending mode ('source-over'):

http://dev.w3.org/fxtf/compositing-1/#simplealphacompositing

You'll see the formula used is ( i renamed the variables for clarity) :

colorOut = prevColor x prevAlpha + newColor x newAlpha x (1 - prevAlpha)

And for resulting alpha :

αlphaOut = prevAlpha + newAlpha x(1 - prevAlpha)

Notice that, a) unexpectedly, the formula is not linear (due to : newAlpha x (1 - prevAlpha) factor ). b) a point has both smaller r,g,b values and reduced alpha. So when re-using it, it will contribute for square(0.6)==0.36 to the final image. (...completely counter-intuitive...)

• So what does happen for your 60% / 40% draws ?

1) image A is drawn with alpha = 60%. The formula above gives :

colorOut = color_A * 0.6;alphaOut = 0.6;

2) image B is drawn with alpha = 40%

colorOut = color_A * 0.6 * 0.6 + color_B x 0.4 x (0.4);alphaOut = 0.6 + 0.4 * 0.4;

So final formula is ==>

colorOut = 0.36 * color_A + 0.16 * color_B ;alphaOut = 0.76;

You see that's not at all the 60/40 mix you expected.

• How to fix ?

1) You can do it by hand using getImageData / putImageData. Be aware of the Cross-Origin issue : if your images don't come from your domain, their imageData will be empty. For performances, bet on a 50+ slow-down factor compared to the canvas (= the GPU) doing the job. 'real time' (=60fps) might not be possible depending on image size/computing power/browser. But you have full control.

2) But if you now look at the 'ligther' composite mode, it seems we have our guy :

http://dev.w3.org/fxtf/compositing-1/#porterduffcompositingoperators_plus

Formula is now :

colorOut = prevColor x prevAlpha + newColor x newAlpha 

And for resulting alpha :

 αlphaOut = prevAlpha + newAlpha 

You see that this is a simple 'plus' operator, perfect for your requirement. So solution is : - save ctx. - set lighter composite mode. - draw first image at 60% alpha. - draw second image at 40% alpha. - restore ctx.

Last words : if you want to check that the final alpha is right (==255), use that kind of function :

functionlogAlpha(ctx,x,y) {
    var imDt = ctx.getImageData(x,y,1,1).data;
    if (!(imDt[0] || imDt[1] || imDt[2])) console.log('null point. CORS issue ?'); 
    console.log(' point at (' +x+ ',' +y+ ') has an alpha of ' + imDt[3] ) ;
 }

Post a Comment for "Blending Two Images With Html5 Canvas"