views:

265

answers:

3

I have a color A that I'd like to transform into color C, by using color B. So I'd like to know the blending formula F in GDI+, where F = F(A, B) = C. A is the "bottom color" and B is an overlay color above A, which together with A yields C.

Cheers,

// Magnus

+2  A: 

This is called Alpha Blending.

Use the following algorithm for the R, G, and B components, where alpha is between 0 and 1.

newColor = MAX(255, (1 - alpha) * background + alpha * overlay)
SLaks
A single alpha value for both background and overlay? Or do you mean (1-alpha_background)*background + alpha_overlay * overlay?
Magnus Skog
Aaah ok, background is completely opaque here.
Magnus Skog
A: 

Hello,

Shouldn't it be the MINIMUM between the two? (I assume 255 represents the maximum value any colour component can have, i.e. 8 bits per colour channel -- thus it is the upper bound)

Another question: can this be done without having to resort to floating point operations? (to that end, the alpha value is mapped between 0 and 255 -- similar to any of the colour components)

NicAdi
A: 

Basically (alpha, red green and blue on a scale of 0 to 1):

Result.Alpha = BackColor.Alpha + ForeColor.Alpha - (BackColor.Alpha * ForeColor.Alpha)
Result.Red = ((ForeColor.Red * ForeColor.Alpha) + (BackColor.Red * BackColor.Alpha * (1 - ForeColor.Alpha))) / Result.Alpha
(Replace 'red' with 'green' and 'blue' above to get the corresponding functions.)

For 32 bit color, in VB.NET (somewhat optimized):

Shared Function Flatten(ByVal BackColor As Color, ByVal ForeColor As Color) As Color
    If ForeColor.A = 0 Then Return BackColor ' Prevent division by zero
    If ForeColor.A = 255 Then Return ForeColor ' Shortcut

    Dim BackAlphaDbl As Single = CSng(BackColor.A) ' Convert to single to prevent in-calculation 8 bit overflow 
    Dim ForeAlphaDbl As Single = CSng(ForeColor.A)

    Dim ForeAlphaNormalized As Single = ForeAlphaDbl / 255 ' Precalculate for triple use
    Dim BackcolorMultiplier As Single = BackAlphaDbl * (1 - ForeAlphaNormalized) ' Precalculate 

    Dim Alpha As Single = BackAlphaDbl + ForeAlphaDbl - BackAlphaDbl * ForeAlphaNormalized

    Return Color.FromArgb(Alpha, (ForeColor.R * ForeAlphaDbl + BackColor.R * BackcolorMultiplier) / Alpha, (ForeColor.G * ForeAlphaDbl + BackColor.G * BackcolorMultiplier) / Alpha, (ForeColor.B * ForeAlphaDbl + BackColor.B * BackcolorMultiplier) / Alpha)
End Function

I figured this out with paper and pencil and verified it by overlaying images with GDI+ and testing the resulting colors. The only difference between this function and GDI+ is that GDI+ rounds up and down inconsistently as the foreground alpha changes. This function is more precise.

pro.in.vbdnf