You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF Canvas中Image控件无法正确显示带透明区域的PNG图像

问题

我将一张带有透明区域的PNG图像加载到System.Drawing.Bitmap中,已确认其PixelFormat为Format32bppArgb,且通过image.Save("img.png")验证了图像Alpha值正确。

我通过以下代码将System.Drawing.Bitmap转换为BitmapSource:

BitmapData bitmapData = image.LockBits(new Rectangle(0, 0, image.Width, image.Height),
                ImageLockMode.ReadOnly, image.PixelFormat);
bitmapSource = BitmapSource.Create(image.Width, image.Height,
                    image.HorizontalResolution, image.VerticalResolution,
                    pf, null,
                    bitmapData.Scan0, bitmapData.Stride * bitmapData.Height, bitmapData.Stride);
image.UnlockBits(bitmapData);

顺带一提,为确保无误,我通过Marshal.Copy()将bitmapData.Scan0复制到byte[]中,验证了索引3及之后每4个字节的值为255或0,两者占比约50%,符合预期。

随后我将BitmapSource添加到Canvas中的Image控件:

Image im = new()
{
   Source = bmpSource
};
TheCanvas.Children.Add(im);
Canvas.SetLeft(im, 0);
Canvas.SetTop(im, 0);

尽管Canvas的Background为LightGray,但图像透明区域始终显示为白色。

我尝试使用以下辅助函数转换:

BitmapSource bs = Imaging.CreateBitmapSourceFromHBitmap(image.GetHbitmap(), IntPtr.Zero,
    new System.Windows.Int32Rect(0, 0, image.Width, image.Height),
    BitmapSizeOptions.FromEmptyOptions());

但结果并无变化。

Image控件没有Background属性,但似乎将其放入Canvas后,透明像素会被强制绘制成白色。

请问如何让图像正确显示,使Canvas的浅灰色背景在图像透明区域透出?

解决方案

1. 匹配WPF的预乘Alpha像素格式

WPF默认使用预乘Alpha的Pbgra32格式,而System.Drawing.Bitmap的Format32bppArgb是非预乘格式,格式不匹配会导致透明通道解析错误。修改转换代码中的像素格式参数:

// 明确指定WPF支持的预乘Alpha格式
var pf = PixelFormats.Pbgra32;
BitmapData bitmapData = image.LockBits(new Rectangle(0, 0, image.Width, image.Height),
                ImageLockMode.ReadOnly, image.PixelFormat);
bitmapSource = BitmapSource.Create(image.Width, image.Height,
                    image.HorizontalResolution, image.VerticalResolution,
                    pf, null,
                    bitmapData.Scan0, bitmapData.Stride * bitmapData.Height, bitmapData.Stride);
image.UnlockBits(bitmapData);

2. 正确释放HBitmap资源(若使用CreateBitmapSourceFromHBitmap方法)

使用Imaging.CreateBitmapSourceFromHBitmap时,系统会创建GDI位图对象,未手动释放会引发资源泄漏和显示异常,修改后的代码如下:

// 引入GDI资源释放方法
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
private static extern bool DeleteObject(IntPtr hObject);

// 转换并释放资源
IntPtr hBitmap = image.GetHbitmap();
try
{
    BitmapSource bs = Imaging.CreateBitmapSourceFromHBitmap(
        hBitmap, 
        IntPtr.Zero,
        new System.Windows.Int32Rect(0, 0, image.Width, image.Height),
        BitmapSizeOptions.FromEmptyOptions());
    // 冻结BitmapSource提升性能并确保透明度正常
    bs.Freeze();
    bmpSource = bs;
}
finally
{
    DeleteObject(hBitmap);
}

3. 检查控件渲染设置

  • 确保Image控件未设置OpacityMask等干扰透明度的属性;
  • 可尝试设置Image.Stretch="None",避免拉伸过程中透明通道被破坏;
  • 确认Canvas没有设置ClipToBounds或其他遮挡背景的属性。

内容的提问来源于stack exchange,提问作者Betty Crokker

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 02:43:14