I'd like to rewrite this method by using Graphics.DrawImage()
. No matter the PixelFormat
of bitmapToDrawOn
and bitmapDrawn
values (I tried all combinations) which should be typically PixelFormat.Format32bppRgb
and PixelFormat.Format32bppArgb
(or PixelFormat.Format32bppPArgb
), I cannot obtain this result.
This compose operation seems pretty obvious to me, so it looks like I am missing something.
private static void ComposeBitmapWithTransparency(Bitmap bitmapToDrawOn, Bitmap bitmapDrawn) {
Debug.Assert(bitmapToDrawOn != null);
Debug.Assert(bitmapToDrawOn.PixelFormat == PixelFormat.Format32bppRgb);
Debug.Assert(bitmapDrawn != null);
Debug.Assert(bitmapDrawn.PixelFormat == PixelFormat.Format32bppArgb);
var width = bitmapToDrawOn.Width;
Debug.Assert(bitmapDrawn.Width == width);
var height = bitmapToDrawOn.Height;
Debug.Assert(bitmapDrawn.Height == height);
var rect = new Rectangle(0, 0, width, height);
var bitmapToDrawOnData = bitmapToDrawOn.LockBits(
rect,
ImageLockMode.ReadWrite,
bitmapToDrawOn.PixelFormat);
var bitmapDrawnData = bitmapDrawn.LockBits(
rect,
ImageLockMode.ReadOnly,
bitmapDrawn.PixelFormat);
unsafe {
var pBitmapToDrawOn = (StructPixel*)bitmapToDrawOnData.Scan0;
var pBitmapDrawn = (StructPixel*)bitmapDrawnData.Scan0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
byte r = pBitmapToDrawOn->R;
byte g = pBitmapToDrawOn->G;
byte b = pBitmapToDrawOn->B;
byte rX = pBitmapDrawn->R;
byte gX = pBitmapDrawn->G;
byte bX = pBitmapDrawn->B;
// Only the transparency of bitmapDrawn is taken account.
byte alphaX = pBitmapDrawn->Alpha;
byte alphaXComplement = (byte)(255 - alphaX);
pBitmapToDrawOn->R = (byte)((r * alphaXComplement + rX * alphaX) >> 8);
pBitmapToDrawOn->G = (byte)((g * alphaXComplement + gX * alphaX) >> 8);
pBitmapToDrawOn->B = (byte)((b * alphaXComplement + bX * alphaX) >> 8);
pBitmapToDrawOn++;
pBitmapDrawn++;
}
}
}
bitmapDrawn.UnlockBits(bitmapDrawnData);
bitmapToDrawOn.UnlockBits(bitmapToDrawOnData);
}
The code for StructPixel
:
[StructLayout(LayoutKind.Explicit)]
public struct StructPixel {
[FieldOffset(0)]
public byte B;
[FieldOffset(1)]
public byte G;
[FieldOffset(2)]
public byte R;
[FieldOffset(3)]
public byte Alpha;
}