b.sullender
b.sullender

Reputation: 341

Blend Pixel (Correct way to get a new alpha value for a blended pixel)

I have a function for blending pixels but the alpha value for the new pixel is wrong. Iv tried a few different approaches too fixing this in the past but could never figure out the correct algorithm for generating the correct alpha value.

An example of what I'm attempting to do. Draw testImage2 over testImage1. The problem may not be obvious when viewing the images on stackoverflow depending on the background color. Try viewing the images with an actual image viewer.

Would prefer to have a solution that doesn't use float or double types. The first parameter is a pointer to the background pixel while the second parameter is the actual pixel value of the front pixel. The 3rd parameter just adjusts the alpha value for the entire pixel.

testImage1:

testImage1

testImage2:

enter image description here

Expected result:

enter image description here

Actual result:

enter image description here

The code:

struct PIXEL
{
    unsigned char Blue;
    unsigned char Green;
    unsigned char Red;
    unsigned char Alpha;
};

void RenderAlphaPixel(PIXEL* pDestination, U32 Color, unsigned char Alpha)
{
    signed int Alpha2, Remainder, Red, Green, Blue, Alpha3;

    Alpha2 = (Color >> (8 * offsetof(PIXEL, Alpha)));
    Alpha2 -= 255;
    Alpha2 += Alpha;
    if (Alpha2 < 0) Alpha2 = 0;
    Remainder = 255 - Alpha2;

    Red = (unsigned char)(Color >> (8 * offsetof(PIXEL, Red)));
    Green = (unsigned char)(Color >> (8 * offsetof(PIXEL, Green)));
    Blue = (unsigned char)(Color >> (8 * offsetof(PIXEL, Blue)));
    Alpha3 = (unsigned char)(Color >> (8 * offsetof(PIXEL, Alpha)));

    pDestination->Red = (unsigned char)(((pDestination->Red * Remainder) + (Red * Alpha2)) / 255);
    pDestination->Green = (unsigned char)(((pDestination->Green * Remainder) + (Green * Alpha2)) / 255);
    pDestination->Blue = (unsigned char)(((pDestination->Blue * Remainder) + (Blue * Alpha2)) / 255);
    // todo. Fix me!
    pDestination->Alpha = (unsigned char)(((pDestination->Alpha * Remainder) + (Alpha3 * Alpha2)) / 255);
}

EDIT for WENDYN

When decreasing the alpha of the front image the image becomes very dark. Easy to see the problem when viewing in windows photo viewer.

Expected result:

enter image description here

Actual result:

enter image description here

Upvotes: 1

Views: 491

Answers (1)

WENDYN
WENDYN

Reputation: 740

I'd try

vec4 A, B;
out.rgb = A.rgb * A.a + B.rgb * (1.0 - A.a) * B.a;
out.a = A.a + B.a * (1.0 - A.a)

translated to 8 bit channels:

U8 aR, aG, aB, aA;
U8 bR, bG, bB, bA;
cR = ((U16)aR * aA + (U16)bR * (255 - aA) / 255 * bA) / 255;
cG = ((U16)aG * aA + (U16)bG * (255 - aA) / 255 * bA) / 255;
cB = ((U16)aB * aA + (U16)bB * (255 - aA) / 255 * bA) / 255;
cA = aA + (U16)bA * (255 - aA) / 255;

Upvotes: 2

Related Questions