C#将图形快速处理成不规则区域

这段代码展示了如何使用C#将图像转换为不规则区域,通过DllImport导入gdi32.dll库,定义了多个与区域操作相关的常量和函数。核心方法ImageToRegion将图像转换为Region对象,支持指定颜色透明,并利用CombineRgn函数进行区域组合。
using System.Runtime.InteropServices;
 
[DllImport("gdi32.dll")]
public static extern IntPtr ExtCreateRegion(IntPtr lpXform, uint nCount,
    ref byte lpRgnData);
 
public static int RGN_AND= 1;
public static int RGN_OR = 2;
public static int RGN_XOR= 3;
public static int RGN_DIFF= 4;
public static int RGN_COPY= 5;
public static int RGN_MIN = RGN_AND;
public static int RGN_MAX= RGN_COPY;
 
[DllImport("gdi32.dll")]
public static extern int CombineRgn(IntPtr hrgnDest, IntPtr hrgnSrc1, IntPtr hrgnSrc2,
    int fnCombineMode);
 
[DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
 
public Region ImageToRegion(Image AImage, Color ATransparent)
{
    //转贴请注明出处ZswangY37(wjhu111#21cn.com) 时间2007-05-25
    if (AImage == null) return null;
    Bitmap vBitmap = new Bitmap(AImage);
    BitmapData vBitmapData = vBitmap.LockBits(
        new Rectangle(0, 0, vBitmap.Width, vBitmap.Height),
        ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb);
    int vAddress = (int)vBitmapData.Scan0;
    int vOffset = vBitmapData.Stride - vBitmap.Width * 4; // 每行多出的字节数
    int h = vBitmap.Height, w = vBitmap.Width;
    int vTransparent = ColorTranslator.ToWin32(ATransparent); // 透明色
    int vAllocRect = (0x1000 - sizeof(uint) * 8) / sizeof(int); // 预分配的矩形数
    if (h * w < vAllocRect) vAllocRect = h * w;
    Byte[] vBuffer = new byte[sizeof(uint) * 8 + sizeof(int) * 4 * vAllocRect];
    //头信息dwSize/iType/nCount/nRegSize
    uint vCount = 0;
    vBuffer[0] = sizeof(uint) * 8; //dwSize//头信息大小
    vBuffer[4] = 1; //iType//int RDH_RECTANGLES = 1;//数据类型
    IntPtr vResult = IntPtr.Zero;
 
    uint vPointer = sizeof(uint) * 8;
 
    bool vWriteRect = false;
    bool vWriteAlways = false;
 
    for (int y = 0; y < h; y++)
    {
        int vBlockStart = 0;
        bool vLastMaskBit = false;
       
        for (int x = 0; x < w; x++)
        {
            int i = Marshal.ReadInt32((IntPtr)vAddress) & 0x00FFFFFF;
            if (vTransparent == i) // 透明色
            {
                if (vLastMaskBit)
                    vWriteRect = true;
            }
            else
            {
                if (!vLastMaskBit)
                {
                    vBlockStart = x;
                    vLastMaskBit = true;
                }
            }
            if (x == w - 1)
            {
                if (y == h - 1)
                {
                    vWriteRect = true;
                    vWriteAlways = true;
                }
                else if (vLastMaskBit)
                {
                    vWriteRect = true;
                }
                x++;
            }
            if (vWriteRect)
            {
                if (vLastMaskBit)
                {
                    vCount++;
                    WriteRect(vBuffer, ref vPointer,
                        new Rectangle(vBlockStart, y, x - vBlockStart, 1));
                }
                if (vCount == vAllocRect || vWriteAlways)
                {
                   
                    vBuffer[8] = (byte)vCount;
                    vBuffer[9] = (byte)(vCount >> 8);
                    vBuffer[10] = (byte)(vCount >> 16);
                    vBuffer[11] = (byte)(vCount >> 24);
                    IntPtr hTemp = ExtCreateRegion(IntPtr.Zero,
                        sizeof(uint) * 8 + sizeof(int) * 4 * vCount,
                        ref vBuffer[0]);
                    if (vResult == IntPtr.Zero)
                        vResult = hTemp;
                    else
                    {
                        CombineRgn(vResult, vResult, hTemp, RGN_OR);
                        DeleteObject(hTemp);
                    }
                    vCount = 0;
                    vPointer = sizeof(uint) * 4;
                    vWriteAlways = false;
                }
                vWriteRect = false;
                vLastMaskBit = false;
            }
            vAddress += 4;
        }
        vAddress += vOffset;
    }
 
    vBitmap.UnlockBits(vBitmapData);
    return Region.FromHrgn(vResult);
}
 
private void WriteRect(byte[] ARGNData, ref uint ptr, Rectangle r)
{
    ARGNData[ptr] = (byte)r.X;
    ARGNData[ptr + 1] = (byte)(r.X >> 8);
    ARGNData[ptr + 2] = (byte)(r.X >> 16);
    ARGNData[ptr + 3] = (byte)(r.X >> 24);
    ARGNData[ptr + 4] = (byte)r.Y;
    ARGNData[ptr + 5] = (byte)(r.Y >> 8);
    ARGNData[ptr + 6] = (byte)(r.Y >> 16);
    ARGNData[ptr + 7] = (byte)(r.Y >> 24);
    ARGNData[ptr + 8] = (byte)r.Right;
    ARGNData[ptr + 9] = (byte)(r.Right >> 8);
    ARGNData[ptr + 10] = (byte)(r.Right >> 16);
    ARGNData[ptr + 11] = (byte)(r.Right >> 24);
    ARGNData[ptr + 12] = (byte)r.Bottom;
    ARGNData[ptr + 13] = (byte)(r.Bottom >> 8);
    ARGNData[ptr + 14] = (byte)(r.Bottom >> 16);
    ARGNData[ptr + 15] = (byte)(r.Bottom >> 24);
    ptr += 16;
}
 
private void button1_Click(object sender, EventArgs e)
{
    Region = ImageToRegion(pictureBox1.Image, Color.White);
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值