C# 将透明图片非透明区域转换为 Region

晚来风
晚来风
发布时间:2026-10-14 | 2人浏览过
原创

在 Windows Forms 或 WPF 开发中,有时需要精确识别透明图片(如 PNG)的非透明轮廓以实现自定义绘图、碰撞检测或点击穿透。本文将展示如何利用 C# 的指针运算和 System.Drawing 命名空间,高效地将图像中的可见像素转换为一个标准的 Region 实例。

前置条件:允许不安全代码

为了直接访问位图内存并进行指针操作以优化性能,项目必须启用“不安全”(unsafe)代码上下文。请在 Visual Studio 中依次执行以下设置:

项目属性 → 生成 → 勾选“允许不安全代码”

核心实现步骤

第1步:锁定图像内存并获取像素数据

直接使用索引器访问像素较慢且无法保证内存布局。我们使用 Bitmap.LockBits 方法将图像数据锁定到系统内存,指定 PixelFormat.Format32bppArgb 以便每个像素包含完整的 Alpha(透明度)通道信息。

private unsafe Region GetRegion(Bitmap bckImage)
{
    GraphicsPath path = new GraphicsPath();
    int w = bckImage.Width;
    int h = bckImage.Height;
    BitmapData bckdata = null;

    try
    {
        // 锁定整个图像区域为只读,格式为32位ARGB
        bckdata = bckImage.LockBits(
            new Rectangle(0, 0, w, h), 
            ImageLockMode.ReadOnly, 
            PixelFormat.Format32bppArgb);

        // 将内存起始地址转换为 uint 指针
        uint* bckInt = (uint*)bckdata.Scan0;

第2步:遍历像素并构建路径

在 32bppArgb 格式下,每个 uint 值代表一个像素。其结构为:A(8bit) | R(8bit) | G(8bit) | B(8bit)。Alpha 通道位于最高8位(掩码 0xff000000)。如果 Alpha 值不为0,说明该像素是不透明的。

        // 逐行逐列扫描
        for (int j = 0; j < h; j++)
        {
            for (int i = 0; i < w; i++)
            {
                // 检查 Alpha 通道是否非零(即非完全透明)
                if ((*bckInt & 0xff000000) != 0)
                {
                    // 将非透明像素坐标添加到图形路径
                    path.AddRectangle(new Rectangle(i, j, 1, 1));
                }
                bckInt++; // 移动到下一个像素
            }
        }

第3步:解锁资源并生成 Region

遍历完成后,必须立即调用 UnlockBits 释放对图像内存的锁定,否则会导致后续对该图像的编辑或保存出错。最后,使用构建好的 GraphicsPath 初始化 System.Drawing.Region 并返回。

        bckImage.UnlockBits(bckdata);
        bckdata = null;
    }
    catch
    {
        // 异常处理:确保即使出错也尝试解锁内存
        if (bckdata != null)
        {
            bckImage.UnlockBits(bckdata);
            bckdata = null;
        }
    }

    // 基于路径创建 Region 对象
    Region region = new System.Drawing.Region(path);
    
    // 清理路径资源
    path.Dispose();
    path = null;

    return region;
}

使用建议与注意事项

  • 性能考量:此方法逐像素扫描,对于超高分辨率图片可能耗时较长。若图片较大,建议先进行二值化或边缘检测预处理,或考虑使用 GPU 加速方案。
  • 资源管理:代码中使用了 try-catch 块来确保 UnlockBits 必定被执行,这是处理底层未托管内存的关键最佳实践。
  • 兼容性:该代码依赖 System.Drawing.Common 命名空间。若在 .NET Core / .NET 5+ 环境下使用,请确保已安装对应 NuGet 包并注意平台限制(Linux 需额外配置 libgdiplus)。

以上就是 C# 将透明图片的非透明区域转换成 Region 的详细内容,更多关于 C# 图像处理与 Region 应用的相关资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表