最可靠的方式是通过 cgo 调用系统原生截图 api:windows 用 bitblt/getdc,macos 用 cgdisplaycreateimage,linux 用 x11 的 xgetimage 或 libpipewire;推荐 robotgo 库封装各平台调用,需注意 dpi 缩放、多屏适配与异步执行避免卡顿。

Go 调用系统原生截图 API 是最可靠的方式
纯 Go 标准库不提供屏幕捕获能力,image 和 golang.org/x/image 等包只能处理图像数据,无法获取屏幕像素。必须通过 CGO 调用操作系统底层接口:Windows 用 BitBlt/GetDC,macOS 用 CGDisplayCreateImage,Linux 用 X11 的 XGetImage 或更现代的 libpipewire(Wayland 下推荐)。绕过系统 API 的“纯 Go 截图”方案(如读取 framebuffer)在桌面环境基本不可用,权限、多屏、缩放、HDR 都会出问题。
推荐直接使用 robotgo 库快速上手
它封装了各平台原生调用,API 简洁且持续维护。安装:
go get github.com/go-vgo/robotgo基础截图示例:
package main
import (
"github.com/go-vgo/robotgo"
)
func main() {
// 全屏截图(返回 *robotgo.CaptureImg)
img := robotgo.CaptureScreen()
// 保存为 PNG
robotgo.SaveCapture(img, "screenshot.png")
}
-
robotgo.CaptureScreen()默认截主屏;传入x, y, w, h可截指定区域,例如robotgo.CaptureScreen(100, 100, 800, 600) - 多显示器需先用
robotgo.GetMonitors()获取屏幕列表,再对指定id调用robotgo.CaptureScreenWithId(id) - macOS 上首次运行可能弹出「屏幕录制」权限提示,需手动在「系统设置 → 隐私与安全性 → 屏幕录制」中启用你的程序
- Linux 下依赖
xorg-xwininfo和x11-utils,Wayland 用户需确认是否启用 XWayland(否则robotgo会失败)
自定义截图时务必处理 DPI 缩放和坐标偏移
高分屏(如 macOS Retina、Windows 缩放 125%/150%)下,robotgo.CaptureScreen() 返回的图像尺寸 ≠ 物理像素尺寸,也 ≠ 逻辑坐标系尺寸。常见错误是直接用鼠标坐标去裁剪,结果截图错位或模糊。
- Windows:用
robotgo.GetScaleX()/robotgo.GetScaleY()获取当前缩放比,将逻辑坐标乘以该值再传入截图函数 - macOS:
robotgo.GetScreenSize()返回的是点(points),不是像素;实际图像宽高需乘以robotgo.GetScaleX()得到真实像素 - Linux(X11):通常无全局缩放,但多屏不同 DPI 时,需对每块屏单独调用
robotgo.GetScreenSizeByIndex(i)并结合XRandR查询物理 DPI
避免在 GUI 主线程中阻塞式截图
如果用 robotgo 在 Fyne / Walk / Gio 等 GUI 框架中调用 CaptureScreen,注意它是同步阻塞操作,长时间截图(如大屏+高分辨率)会导致界面卡顿甚至假死。
- 改用 goroutine 异步执行:
go func() { img := robotgo.CaptureScreen() // 处理或保存 img... }() - 若需实时预览(如截图工具框选),优先用
robotgo.GetMousePos()+robotgo.GetPixelColor(x, y)做轻量采样,而非频繁全屏抓取 - 保存图像时避开
png.Encode直接写文件——它在大图下较慢;可先用robotgo.SaveCapture(内部已优化),或转成*image.RGBA后用jpeg.Encode降低体积
真正难的不是“怎么截”,而是“截得准、不卡、适配各种屏幕配置”。很多 bug 出现在 macOS 多屏拖拽窗口后坐标未重算,或 Windows 远程桌面会话里 GetDC 返回空句柄——这些都得靠运行时探测和 fallback 逻辑兜底。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











