主要是通过 P/Invoke 技术调用 Windows API 函数 gdi32.dll/user32.dll,同时定义了一些结构体来配合这些 API 函数的使用,常用于处理图形绘制、窗口显示等操作。

运行查看效果

局部放大,抗锯齿效果很不错,尾巴毛毛清晰可见。

cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using WindowsFormsApp7.Resources;
using static System.Net.Mime.MediaTypeNames;
namespace WindowsFormsApp1
{
public partial class Form1: Form
{
private const int WS_EX_LAYERED = 0x00080000;
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= WS_EX_LAYERED;
return cp;
}
}
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
InitializeComponent();
var bitmap = Properties.Resources.index00;
byte opacity = 255;//0-255 透明度调整
double scalePercentage = 70; // 背景图片按70%缩放
SetBitmap(bitmap, opacity, scalePercentage);
CenterWindow(); //窗口 绝对 居中
}
public void SetBitmap(Bitmap bitmap, byte opacity, double scalePercentage)
{
// 检查传入的位图的像素格式是否为 32 位包含 alpha 通道
if (bitmap.PixelFormat != PixelFormat.Format32bppArgb)
// 如果不是 32 位包含 alpha 通道的格式,抛出一个应用程序异常
throw new ApplicationException("位图必须是 32 位包含 alpha 通道");
// 计算缩放后的宽度和高度
int newWidth = (int)(bitmap.Width * scalePercentage / 100);
int newHeight = (int)(bitmap.Height * scalePercentage / 100);
// 更新窗口的大小
this.Size = new Size(newWidth, newHeight);
// 缩放位图
Bitmap resizedBitmap = new Bitmap(bitmap, newWidth, newHeight);
// 获取屏幕设备上下文的句柄。设备上下文(DC)是一个包含图形对象及其属性、影响输出的图形模式的结构
IntPtr screenDc = APIAliasing.GetDC(IntPtr.Zero);
// 创建一个与指定设备上下文(这里是屏幕设备上下文)兼容的内存设备上下文
IntPtr memDc = APIAliasing.CreateCompatibleDC(screenDc);
// 初始化一个 IntPtr 类型的变量,用于存储位图的句柄,初始值为 IntPtr.Zero 表示空句柄
IntPtr hBitmap = IntPtr.Zero;
// 初始化一个 IntPtr 类型的变量,用于存储之前选入内存设备上下文的对象的句柄,初始值为 IntPtr.Zero 表示空句柄
IntPtr oldBitmap = IntPtr.Zero;
try
{
// 将 Bitmap 对象转换为 GDI 位图,并返回该位图的句柄。Color.FromArgb(0) 表示使用透明颜色
hBitmap = resizedBitmap.GetHbitmap(Color.FromArgb(0));
// 将指定的位图选入指定的设备上下文,并返回之前选入该设备上下文的对象的句柄
oldBitmap = APIAliasing.SelectObject(memDc, hBitmap);
// 创建一个 APIAliasing.Size 结构体的实例,用于表示位图的宽度和高度
APIAliasing.Size size = new APIAliasing.Size(newWidth, newHeight);
// 创建一个 APIAliasing.Point 结构体的实例,用于表示位图的源点(这里是左上角,坐标为 (0, 0))
APIAliasing.Point pointSource = new APIAliasing.Point(0, 0);
// 创建一个 APIAliasing.Point 结构体的实例,用于表示要绘制位图的目标位置,Left 和 Top 应该是类的属性,表示控件的左上角坐标
APIAliasing.Point topPos = new APIAliasing.Point(Left, Top);
// 创建一个 APIAliasing.BLENDFUNCTION 结构体的实例,用于指定混合操作的参数
APIAliasing.BLENDFUNCTION blend = new APIAliasing.BLENDFUNCTION();
// 设置混合操作的模式为 AC_SRC_OVER,表示源位图覆盖目标位图
blend.BlendOp = APIAliasing.AC_SRC_OVER;
// 混合标志,这里设置为 0 表示没有特殊的混合标志
blend.BlendFlags = 0;
// 设置源位图的常量 alpha 值,取值范围是 0 - 255,由传入的 opacity 参数决定
blend.SourceConstantAlpha = opacity;
// 设置 alpha 通道的格式为 AC_SRC_ALPHA,表示使用源位图的 alpha 通道
blend.AlphaFormat = APIAliasing.AC_SRC_ALPHA;
// 更新分层窗口的内容,将位图绘制到指定的窗口上。
// Handle 是窗口的句柄,screenDc 是屏幕设备上下文,topPos 是目标位置,size 是位图大小,
// memDc 是内存设备上下文,pointSource 是源点,0 是颜色键(这里不使用),blend 是混合参数,
// APIAliasing.ULW_ALPHA 表示使用 alpha 混合模式
APIAliasing.UpdateLayeredWindow(Handle, screenDc, ref topPos, ref size, memDc, ref pointSource, 0, ref blend, APIAliasing.ULW_ALPHA);
}
finally
{
// 释放之前获取的屏幕设备上下文,将其返回给系统
APIAliasing.ReleaseDC(IntPtr.Zero, screenDc);
// 检查位图句柄是否不为空
if (hBitmap != IntPtr.Zero)
{
// 将之前选入内存设备上下文的对象重新选入,恢复设备上下文的状态
APIAliasing.SelectObject(memDc, oldBitmap);
// 删除之前创建的 GDI 位图对象,释放相关的系统资源
APIAliasing.DeleteObject(hBitmap);
}
// 删除之前创建的内存设备上下文,释放相关的系统资源
APIAliasing.DeleteDC(memDc);
// 释放缩放后的位图资源
resizedBitmap.Dispose();
}
}
public void CenterWindow()
{
// 获取屏幕的工作区域(不包括任务栏)
Rectangle screenBounds = Screen.PrimaryScreen.WorkingArea;
// 计算窗口居中时的左上角坐标
int left = (screenBounds.Width - Width) / 2 + screenBounds.Left;
int top = (screenBounds.Height - Height) / 2 + screenBounds.Top;
// 设置窗口的位置
Location = new Point(left, top);
}
}
}
添加类 类名:APIAliasing
cs
// 定义一个公共类 APIAliasing,用于封装一些 Windows API 相关的辅助功能
class APIAliasing
{
// 使用 StructLayout 属性指定结构体在内存中的布局方式为顺序布局
// 顺序布局意味着结构体的字段在内存中按照声明的顺序依次排列
[StructLayout(LayoutKind.Sequential)]
// 定义一个公共结构体 Size,用于表示二维平面上的大小,通常包含宽度和高度信息
public struct Size
{
// 定义一个 32 位有符号整数类型的字段 cx,用于表示宽度
public Int32 cx;
// 定义一个 32 位有符号整数类型的字段 cy,用于表示高度
public Int32 cy;
// 定义结构体的构造函数,用于初始化结构体的字段
// 参数 x 用于初始化 cx 字段,参数 y 用于初始化 cy 字段
public Size(Int32 x, Int32 y)
{
// 将参数 x 的值赋给字段 cx
cx = x;
// 将参数 y 的值赋给字段 cy
cy = y;
}
}
// 使用 StructLayout 属性指定结构体在内存中的布局方式为顺序布局,并且设置字节对齐方式为 1 字节
// 这样可以确保结构体的字段在内存中紧密排列,没有额外的填充字节
[StructLayout(LayoutKind.Sequential, Pack = 1)]
// 定义一个公共结构体 BLENDFUNCTION,用于表示混合操作的相关参数
public struct BLENDFUNCTION
{
// 定义一个字节类型的字段 BlendOp,用于指定混合操作的类型
public byte BlendOp;
// 定义一个字节类型的字段 BlendFlags,用于指定混合操作的标志位
public byte BlendFlags;
// 定义一个字节类型的字段 SourceConstantAlpha,用于指定源图像的常量透明度值
public byte SourceConstantAlpha;
// 定义一个字节类型的字段 AlphaFormat,用于指定源图像的透明度格式
public byte AlphaFormat;
}
// 使用 StructLayout 属性指定结构体在内存中的布局方式为顺序布局
[StructLayout(LayoutKind.Sequential)]
// 定义一个公共结构体 Point,用于表示二维平面上的一个点,通常包含 x 和 y 坐标信息
public struct Point
{
// 定义一个 32 位有符号整数类型的字段 x,用于表示点的 x 坐标
public Int32 x;
// 定义一个 32 位有符号整数类型的字段 y,用于表示点的 y 坐标
public Int32 y;
// 定义结构体的构造函数,用于初始化结构体的字段
// 参数 x 用于初始化字段 x,参数 y 用于初始化字段 y
public Point(Int32 x, Int32 y)
{
// 将参数 x 的值赋给字段 x
this.x = x;
// 将参数 y 的值赋给字段 y
this.y = y;
}
}
// 定义一个公共常量 AC_SRC_OVER,值为 0
// 该常量通常用于指定混合操作的模式,表示源图像覆盖目标图像
public const byte AC_SRC_OVER = 0;
// 定义一个公共常量 ULW_ALPHA,值为 2
// 该常量通常用于 UpdateLayeredWindow 函数,表示使用 alpha 混合
public const Int32 ULW_ALPHA = 2;
// 定义一个公共常量 AC_SRC_ALPHA,值为 1
// 该常量通常用于指定源图像包含 alpha 通道信息
public const byte AC_SRC_ALPHA = 1;
// 使用 DllImport 属性引入 gdi32.dll 动态链接库中的 CreateCompatibleDC 函数
// ExactSpelling = true 表示使用精确的函数名进行查找
// SetLastError = true 表示在调用函数失败时可以通过 GetLastError 函数获取错误代码
// 该函数用于创建一个与指定设备上下文兼容的内存设备上下文
[DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
// 定义一个公共静态外部方法 CreateCompatibleDC,用于调用 Windows API 中的同名函数
// 参数 hDC 表示要创建兼容设备上下文的源设备上下文句柄
// 返回值为创建的兼容设备上下文的句柄
public static extern IntPtr CreateCompatibleDC(IntPtr hDC);
// 使用 DllImport 属性引入 user32.dll 动态链接库中的 GetDC 函数
// ExactSpelling = true 表示使用精确的函数名进行查找
// SetLastError = true 表示在调用函数失败时可以通过 GetLastError 函数获取错误代码
// 该函数用于获取指定窗口的设备上下文句柄
[DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
// 定义一个公共静态外部方法 GetDC,用于调用 Windows API 中的同名函数
// 参数 hWnd 表示要获取设备上下文的窗口句柄
// 返回值为获取的设备上下文的句柄
public static extern IntPtr GetDC(IntPtr hWnd);
// 使用 DllImport 属性引入 gdi32.dll 动态链接库中的 SelectObject 函数
// ExactSpelling = true 表示使用精确的函数名进行查找
// 该函数用于将指定的对象(如位图、画笔等)选入指定的设备上下文中
[DllImport("gdi32.dll", ExactSpelling = true)]
// 定义一个公共静态外部方法 SelectObject,用于调用 Windows API 中的同名函数
// 参数 hDC 表示要选入对象的设备上下文句柄
// 参数 hObj 表示要选入设备上下文的对象句柄
// 返回值为之前选入该设备上下文的对象句柄
public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObj);
// 使用 DllImport 属性引入 user32.dll 动态链接库中的 ReleaseDC 函数
// ExactSpelling = true 表示使用精确的函数名进行查找
// 该函数用于释放之前通过 GetDC 函数获取的设备上下文
[DllImport("user32.dll", ExactSpelling = true)]
// 定义一个公共静态外部方法 ReleaseDC,用于调用 Windows API 中的同名函数
// 参数 hWnd 表示之前获取设备上下文的窗口句柄
// 参数 hDC 表示要释放的设备上下文句柄
// 返回值为操作结果,非零表示成功,零表示失败
public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
// 使用 DllImport 属性引入 gdi32.dll 动态链接库中的 DeleteDC 函数
// ExactSpelling = true 表示使用精确的函数名进行查找
// SetLastError = true 表示在调用函数失败时可以通过 GetLastError 函数获取错误代码
// 该函数用于删除指定的设备上下文
[DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
// 定义一个公共静态外部方法 DeleteDC,用于调用 Windows API 中的同名函数
// 参数 hDC 表示要删除的设备上下文句柄
// 返回值为操作结果,非零表示成功,零表示失败
public static extern int DeleteDC(IntPtr hDC);
// 使用 DllImport 属性引入 gdi32.dll 动态链接库中的 DeleteObject 函数
// ExactSpelling = true 表示使用精确的函数名进行查找
// SetLastError = true 表示在调用函数失败时可以通过 GetLastError 函数获取错误代码
// 该函数用于删除指定的图形对象(如位图、画笔等)
[DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
// 定义一个公共静态外部方法 DeleteObject,用于调用 Windows API 中的同名函数
// 参数 hObj 表示要删除的图形对象句柄
// 返回值为操作结果,非零表示成功,零表示失败
public static extern int DeleteObject(IntPtr hObj);
// 使用 DllImport 属性引入 user32.dll 动态链接库中的 UpdateLayeredWindow 函数
// ExactSpelling = true 表示使用精确的函数名进行查找
// SetLastError = true 表示在调用函数失败时可以通过 GetLastError 函数获取错误代码
// 该函数用于更新分层窗口的内容,支持 alpha 混合等效果
[DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
// 定义一个公共静态外部方法 UpdateLayeredWindow,用于调用 Windows API 中的同名函数
// 参数 hwnd 表示要更新的分层窗口句柄
// 参数 hdcDst 表示目标设备上下文句柄
// 参数 pptDst 表示目标窗口的左上角坐标,使用 Point 结构体
// 参数 psize 表示要更新的区域大小,使用 Size 结构体
// 参数 hdcSrc 表示源设备上下文句柄
// 参数 pptSrc 表示源图像的左上角坐标,使用 Point 结构体
// 参数 crKey 表示颜色键,用于指定透明颜色
// 参数 pblend 表示混合操作的参数,使用 BLENDFUNCTION 结构体
// 参数 dwFlags 表示更新操作的标志位
// 返回值为操作结果,非零表示成功,零表示失败
public static extern int UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, ref Point pptDst, ref Size psize, IntPtr hdcSrc, ref Point pptSrc, Int32 crKey, ref BLENDFUNCTION pblend, Int32 dwFlags);
// 使用 DllImport 属性引入 gdi32.dll 动态链接库中的 ExtCreateRegion 函数
// ExactSpelling = true 表示使用精确的函数名进行查找
// SetLastError = true 表示在调用函数失败时可以通过 GetLastError 函数获取错误代码
// 该函数用于创建一个复杂的区域对象
[DllImport("gdi32.dll", ExactSpelling = true, SetLastError = true)]
// 定义一个公共静态外部方法 ExtCreateRegion,用于调用 Windows API 中的同名函数
// 参数 lpXform 表示可选的变换矩阵指针
// 参数 nCount 表示区域数据的数量
// 参数 rgnData 表示区域数据的指针
// 返回值为创建的区域对象的句柄
public static extern IntPtr ExtCreateRegion(IntPtr lpXform, uint nCount, IntPtr rgnData);
}