0

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;
   }
Patrick from NDepend team
  • 13,237
  • 6
  • 61
  • 92
  • Can you post the code of `StructPixel`? – Alessandro D'Andria Mar 21 '14 at 10:32
  • code of StructPixel posted. – Patrick from NDepend team Mar 21 '14 at 10:35
  • What is the actual problem here? You want to draw with Graphics.DrawBitmap()? That method doesn't exist. – Hans Passant Mar 21 '14 at 14:29
  • Oups I meant DrawImage() and not DrawBitmap() sorry for the confusion. The problem is that I can't find a way to use DrawImage() to obtain the obvious *compose with transparency effect* coded by this method. I already read your answer http://stackoverflow.com/a/10661333/27194 but the compose effect I obtain is different than the obvious one and I don't known why. It looks like the composing algorithm is using [255] modulus on each RGB channel, so with an alpha of 50%, when composing the two channel values 100 and 200, instead of getting 150, DrawBitmap() ends up with 100+200=300 [255] = 45 – Patrick from NDepend team Mar 21 '14 at 15:09

0 Answers0