1

My current code is blit'ing a small Pbgra32 bitmap onto a larger Pbgra32 bitmap. Works fine. What I would like to do now is make that smaller one partly transparent. To do this, before the blit, I am passing the smaller one to a method that should edit each pixel by leaving the RGB values alone while writing 0x7F to each pixel's A value.

Instead of a 50% transparent image however, I am getting a grey square. What am I doing wrong?

private void MakeTransparent(ref WriteableBitmap bmp)
    {
        int width = bmp.PixelWidth;
        int height = bmp.PixelHeight;
        int stride = bmp.BackBufferStride;
        int bytesPerPixel = (bmp.Format.BitsPerPixel + 7)/8;

        unsafe
        {
            bmp.Lock();
            byte* pImgData = (byte*) bmp.BackBuffer;

            int cRowStart = 0;
            int cColStart = 0;
            for (int row = 0; row < height; row++)
            {
                cColStart = cRowStart;
                for (int col = 0; col < width; col++)
                {
                    byte* bPixel = pImgData + cColStart;
                    UInt32* iPixel = (UInt32*) bPixel;
                    bPixel[3] = 0x7F;
                    cColStart += bytesPerPixel;
                }
                cRowStart += stride;
            }
            bmp.Unlock();
        }
    }
davecove
  • 1,001
  • 4
  • 16
  • 36

1 Answers1

5

I figured it out. The key was realizing what a Pbgra32 really is and handling it right (see comments in solution). This method modifies a Pbgra32 so that the result can be used like this:

ChangeTransparency(ref wb_icon);
var iconSize = new Size(wb_icon.PixelWidth, wb_icon.PixelHeight);
wb_backgroundImage.Blit(new Rect(loc, iconSize), wb_icon, new Rect(iconSize),
   WriteableBitmapExtensions.BlendMode.Alpha);

Here is the method:

    private void ChangeTransparency(ref WriteableBitmap bmp, int newAlpha = 127)
    {
        try
        {
            int width = bmp.PixelWidth;
            int height = bmp.PixelHeight;
            int stride = bmp.BackBufferStride;
            int bytesPerPixel = (bmp.Format.BitsPerPixel + 7) / 8;

            unsafe
            {
                bmp.Lock();
                byte* pImgData = (byte*)bmp.BackBuffer;

                int cRowStart = 0;
                int cColStart = 0;
                for (int row = 0; row < height; row++)
                {
                    cColStart = cRowStart;
                    for (int col = 0; col < width; col++)
                    {
                        // the RGB values are pre-multiplied by the alpha in a Pbgra32 bitmap
                        // so I need to un-pre-multiply them with the current alpha
                        // and then re-pre-multiply them by the new alpha
                        byte* bPixel = pImgData + cColStart;

                        byte A = bPixel[3];
                        if (A > 0)
                        {
                            byte B = bPixel[0];
                            byte G = bPixel[1];
                            byte R = bPixel[2];

                            bPixel[0] = Convert.ToByte((B/A)*newAlpha);
                            bPixel[1] = Convert.ToByte((G/A)*newAlpha);
                            bPixel[2] = Convert.ToByte((R/A)*newAlpha);
                            bPixel[3] = Convert.ToByte(newAlpha);
                        }

                        cColStart += bytesPerPixel;
                    }
                    cRowStart += stride;
                }
                bmp.Unlock();
            }
        }
        catch (Exception ex)
        {

        }
    }
davecove
  • 1,001
  • 4
  • 16
  • 36