The BitBlt blending rule Form blendAlphaScaled (34) doesn't blend the colors 0x00000000 (source; fully transparent) and 0xFFFFFFFF (destination; white) correctly. The output is 0xFEFEFEFE (slightly transparent white), whereas it should be 0xFFFFFFFF (fully opaque white).

I think the problem lies in the implementation of BitBltSimulation>>#alphaBlendScaled:with:. When calculating the summand containing the destinationWord, a right bit shift by 8 is performed to normalize the result after multiplying with unAlpha (semantically a division by 256). However, unAlpha is in the range 0x00 - 0xFF and thus a division by 0xFF = 255 should be used instead. I think that the other bit shifts by 8 in the function are ok, as they are only used to extract or compose certain bytes and not to (semantically) divide a value by 256.

This problem causes the described behavior, because the following computation is performed in each channel:
((0xFF * 0xFF) >> 8) + 0x00 = 0xFE01 >> 8 = 0xFE
A division by 0xFF produces the expected result:
((0xFF * 0xFF) / 0xFF) + 0x00 = 0xFE01 / 0xFF = 0xFF

Code to reproduce:

| src dst |
src := (Form extent: 1 @ 1 depth: 1)
    colorAt: 0 @ 0 put: Color black; "transparency is applied with the fillColor:"
    yourself.
dst := (Form extent: 1 @ 1 depth: 32)
    colorAt: 0 @ 0 put: Color white; "16rFFFFFFFF"
    yourself.
dst
    copyBits: (0 @ 0 corner: 1 @ 1)
    from: src
    at: 0 @ 0
    clippingBox: (0 @ 0 corner: 1 @ 1)
    rule: Form blendAlphaScaled
    fillColor: Color transparent. "16r00000000"
(dst pixelValueAt: 0 @ 0) hex "16rFEFEFEFE"

Notes:


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <OpenSmalltalk/opensmalltalk-vm/issues/643@github.com>