Question

In general, the "normal" blend mode equation looks like this:

D = Sa * S + D * (1.0 - Sa)

where D is destination color, Sa is source alpha and S is source color.

Now, this works fine with fully opaque destination but I'd like to know how you would handle that with semi and fully transparent destination.

When blending the source over a fully transparent destination, the source pixel (a pixel being color and alpha) will be unchanged and not blended like in the equation before, and if the destination background is fully opaque, the above equation should be applied, but I can't find a nice way to handle the situations where destination alpha is in between 0 and 1.

For example, if you blend a white pixel with 50% alpha on a transparent background, the color should not tend to that transparent color value (which is more or less in an undefined state), the destination color should be full white, and not 50% (after alpha multiplication), which is what you get after applying the above equation (if D is made the same color as S, which was something I thought of).

Was it helpful?

Solution

This equation is a simplification of the general blending equation. It assumes the destination color is opaque, and therefore drops the destination color's alpha term.

D = C1 * C1a + C2 * C2a * (1 - C1a)

where D is the resultant color, C1 is the color of the first element, C1a is the alpha of the first element, C2 is the second element color, C2a is the alpha of the second element. The destination alpha is calculated with:

Da = C1a + C2a * (1 - C1a)

The resultant color is premultiplied with the alpha. To restore the color to the unmultiplied values, just divide by Da, the resultant alpha.

OTHER TIPS

I found this answer to be helpful, and it seems to work as expected when applying the same formula to the alpha channel.

Altered here to show the extended version:

int blend(unsigned char result[4], unsigned char fg[4], unsigned char bg[4] {
    unsigned int alpha = fg[3] + 1;
    unsigned int inv_alpha = 256 - fg[3];
    result[0] = (unsigned char)((alpha * fg[0] + inv_alpha * bg[0]) >> 8);
    result[1] = (unsigned char)((alpha * fg[1] + inv_alpha * bg[1]) >> 8);
    result[2] = (unsigned char)((alpha * fg[2] + inv_alpha * bg[2]) >> 8);
    result[3] = (unsigned char)((alpha * fg[3] + inv_alpha * bg[3]) >> 8);
    // result[3] = 0xff;
}

This works well for quick and dirty code, but there are faster approaches as well, as commented in the above answer, but also addressed here and here.

Most blending formulas are used on static images where the destination colors alpha is not stored. If the alpha is available then the final alpha is simply going to be the arithmetic mean of the source alpha and the destination alpha.

You can calculate the average alpha and then simply use that in the place of 'Sa' in your formula.

Mind telling us what this is for?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top