It works, but it is not 100% precise, in my opinion, since the alpha channel should work on 256 values, not 255.
Suppose you choose a 128 value for your alpha component. It should mean that you'd like to compose evenly your color with what already there, but this algorithm will have it providing 127/255 part of the color against 128/255 of the other. Then you assign the complementary alpha each cycle of the loop, not a big issue, but optimizable.
I changed all fill extensions this way:
As soon as possible:
Suppose you choose a 128 value for your alpha component. It should mean that you'd like to compose evenly your color with what already there, but this algorithm will have it providing 127/255 part of the color against 128/255 of the other. Then you assign the complementary alpha each cycle of the loop, not a big issue, but optimizable.
I changed all fill extensions this way:
As soon as possible:
int alpha = 1 + (int)((uint)color >> 24);
if (alpha == 1) return;
Then, before the cycle: int alphac = 256 - alpha, p, pal, par, pag, pab;
if (alphac > 0)
{
color &= 0xffffff;
par = alpha * ((color >> 16) & 255);
pag = alpha * ((color >> 8) & 255);
pab = alpha * (color & 255);
color = ((par >> 8) << 16)
| ((pag >> 8) << 8)
| (pab >> 8);
}
In the cycle: p = pixels[offset];
pal = 1 + (p >> 24);
par = alphac * pal * ((p >> 16) & 255);
pag = alphac * pal * ((p >> 8) & 255);
pab = alphac * pal * (p & 255);
pixels[offset] = (Math.Min(255, alpha + pal - 1) << 24)
| (par & (255 * 256 * 256))
| (pag & (255 * 256 * 256)) >> 8
| (pab >> 16) + color;
If I'm right, the compiler will optimize the 255256256 to its equivalent, but some people find it more understandable.