Blending two images with html5 canvas

冷暖自知 提交于 2019-12-24 03:56:24

问题


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.
- The desired result is a completely opaque image (alpha of 1.0 for each pixel), which appears as a 60% blend of imageB, and a 40% blend of imageA.

However, I believe that the html5 canvas by default uses a blend mode other than add on alpha blended images, so two things drawn with alphas below 1 will not add up to 1.
I've tried all the different compositing modes, along with the Adobe blend modes, but none of them have the desired result.
A simple test case is to draw a magenta rect twice, both with alpha of 0.5. My desire is for the resulting pixels to be rgb(255, 0, 255). However, the result is slightly transparent.

Does anyone know some way of achieving this result?


回答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 :

 function logAlpha(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] ) ;
 }


来源:https://stackoverflow.com/questions/26200800/blending-two-images-with-html5-canvas

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!