能用但性能极差,仅适合偶尔取色;GetPixel跨进程调用开销大,60fps循环中会导致卡顿;推荐Graphics.CopyFromScreen截1×1像素再读取,或BitBlt内存缓冲用于高频场景;WPF应改用RenderTargetBitmap。
用 GetPixel 快速读取鼠标坐标颜色,但别在循环里狂调
直接结论:能用,但性能极差,只适合偶尔点一下查色。windows api 的 getpixel 是最简单的方式,它接收屏幕坐标(x, y),返回一个 colorref,转成 color 就行。
常见错误是把它塞进 60fps 的鼠标跟踪循环里——CPU 占用瞬间飙高,还卡顿。因为每次调用都要跨进程、走 GDI、做坐标转换,本质是“截图单像素”,不是内存读取。
- 必须先用
GetCursorPos获取鼠标位置,再传给GetPixel -
GetPixel读的是**屏幕坐标系**,不是窗体客户区坐标,别忘了用ScreenToClient转换(如果真要读自己窗口某点,那得另说) - 返回的
COLORREF是 BGR 格式(低字节是蓝),不是 RGB,Color.FromArgb(ref)会自动处理,但手撕位运算时容易翻车
.NET 6+ 推荐用 Graphics.CopyFromScreen 截一小块再取色
比 GetPixel 稳得多,尤其要连续采样(比如做取色器吸管功能)。原理是先截 1×1 像素区域到 Bitmap,再用 GetPixel(0, 0) 读——这回是托管内存操作,快一个数量级。
关键点在于“截哪”:必须把鼠标屏幕坐标转成目标设备上下文的逻辑坐标。如果只是看当前屏幕颜色,就以 Graphics.FromHwnd(IntPtr.Zero) 创建全屏图面;如果限定在某个窗口内,得先 GetWindowRect 拿窗口边界,再做偏移计算。
- 截 1×1 比截大图快,但别截 0×0——会抛
ArgumentException - 记得
Dispose()Graphics和Bitmap,不然内存泄漏比颜色还显眼 - 多显示器环境下,鼠标可能在非主屏,
CopyFromScreen默认只对主屏有效,需用Screen.FromPoint判断并调整源坐标
高频采样场景必须上 BitBlt + 内存缓冲
要做实时色值监控(比如录屏分析、辅助瞄准),GetPixel 和小图截取都扛不住。真正靠谱的是用 BitBlt 把整屏或指定区域拷进内存 Bitmap,之后所有像素访问都是纯内存操作。
这不是加个引用就能跑的事:要手动创建兼容 DC、分配 DIB Section、管理位图句柄。.NET 没封装这个路径,得 P/Invoke CreateCompatibleDC、CreateDIBSection、SelectObject,最后 BitBlt 一次拷完。
- 缓冲区复用很关键——别每帧 new
Bitmap,重用同一块内存 - 拷贝区域越小越好,比如只要鼠标周围 5×5,就只拷那么大,别全屏
- 注意 GDI 对象泄漏:每个
CreateCompatibleDC都得配对DeleteDC,SelectObject返回的老位图也要DeleteObject
WPF 或 WinUI 项目?绕开 GDI,走 RenderTargetBitmap 路线
如果你不在 WinForms 里硬刚 GDI,而是用 WPF,别碰 GetPixel。WPF 渲染走 DirectX,GDI 读不到 WPF 窗口内容(会读到黑或旧画面)。正确姿势是用 RenderTargetBitmap 把目标 Visual(比如整个窗口或某个 Canvas)渲染成位图,再用 Pixels 数组取色。
限制也很明显:它只能抓 WPF 自己画的东西,抓不到其他进程窗口、任务栏、桌面图标——这点和 GDI 方案完全不同。所以“取鼠标下任意屏幕色”这个需求,在 WPF 里天然不成立,得切回 Win32 API。
-
RenderTargetBitmap构造时分辨率参数必须和目标控件实际像素尺寸一致,否则缩放失真 - 读
Pixels数组前,确保已调用Render并等待完成(它异步) - 数组是 BGRA 格式、每像素 4 字节、从左到右从上到下排布,索引计算别错位


















