PictureBox加载透明png图片后透明部分显示的是容器背景色,无法透明显示背景图,以下方法可以实现透明(缺点:有锯齿,无半透明效果)
原理:抠除alpha为0的像素点,重新计算控件region
private unsafe static GraphicsPath SubGraphicsPath(System.Drawing.Image img)
{
if (img == null) return null;
// 建立GraphicsPath, 给我们的位图路径计算使用
GraphicsPath g = new GraphicsPath(FillMode.Alternate);
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(img);
int width = bitmap.Width;
int height = bitmap.Height;
BitmapData bmData = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
byte* p = (byte*)bmData.Scan0;
int offset = bmData.Stride - width * 4;
int start = -1;
// 行座标 ( Y col )
for (int Y = 0; Y < height; Y++)
{
// 列座标 ( X row )
for (int X = 0; X < width; X++)
{
if (start == -1 && p[3] > 0) //如果 之前的点没有不透明 且 不透明
{
start = X; //记录这个点
}
else if (start > -1 && p[3] == 0) //如果 之前的点是不透明 且 透明
{
g.AddRectangle(new System.Drawing.Rectangle(start, Y, X - start, 1)); //添加之前的矩形到
start = -1;
}
if (X == width - 1 && start > -1) //如果 之前的点是不透明 且 是最后一个点
{
g.AddRectangle(new System.Drawing.Rectangle(start, Y, X - start + 1, 1)); //添加之前的矩形到
start = -1;
}
p += 4; //下一个内存地址
}
p += offset;
}
bitmap.UnlockBits(bmData);
bitmap.Dispose();
// 返回计算出来的不透明图片路径
return g;
}
/// <summary>
/// 调用此函数后使图片透明
/// </summary>
/// <param name="control">需要处理的控件</param>
/// <param name="img">控件的背景或图片,如PictureBox.Image
/// 或PictureBox.BackgroundImage</param>
public static void ControlTrans(System.Windows.Forms.Control control, System.Drawing.Image img)
{
GraphicsPath g;
g = SubGraphicsPath(img);
if (g == null)
return;
control.Region = new System.Drawing.Region(g);
}