Skip to main content
 首页 » 编程设计

c#之Alpha channel 无法按预期使用 WriteableBitmap

2024年02月13日33rubylouvre

我当前的代码是将一个小的 Pbgra32 位图 blit'ing 到一个更大的 Pbgra32 位图上。工作正常。我现在想做的是让那个较小的部分透明。为此,在 blit 之前,我将较小的一个传递给一种方法,该方法应该通过单独保留 RGB 值来编辑每个像素,同时将 0x7F 写入每个像素的 A 值。

然而,我得到的不是 50% 透明的图像,而是一个灰色方 block 。我做错了什么?

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(); 
        } 
    } 

请您参考如下方法:

我想通了。关键是了解 Pbgra32 的真正含义并正确处理它(请参阅解决方案中的注释)。此方法修改 Pbgra32,以便可以像这样使用结果:

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); 

方法如下:

    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) 
        { 
 
        } 
    }