package tool import ( "image" "image/png" "log" "os" "strings" "syscall" "unsafe" "github.com/kbinani/screenshot" ) // Windows API常量 const ( SRCCOPY = 0x00CC0020 // 复制操作的代码 ) // Windows API结构体定义 type RECT struct { // 矩形区域结构 Left, Top, Right, Bottom int32 } type BITMAPINFOHEADER struct { // 位图信息头 Size uint32 Width int32 Height int32 Planes uint16 BitCount uint16 Compression uint32 SizeImage uint32 XPelsPerMeter int32 YPelsPerMeter int32 ClrUsed uint32 ClrImportant uint32 } var ( user32 = syscall.NewLazyDLL("user32.dll") procEnumWindows = user32.NewProc("EnumWindows") procGetWindowText = user32.NewProc("GetWindowTextW") titless string ) // 定义回调函数的类型 type EnumWindowsProc func(hwnd uintptr, lParam uintptr) uintptr // 枚举窗口的回调函数 func enumWindowsProc(hwnd uintptr, lParam uintptr) uintptr { var buffer [256]uint16 length, _, _ := procGetWindowText.Call(hwnd, uintptr(unsafe.Pointer(&buffer[0])), uintptr(len(buffer))) if length > 0 { title := syscall.UTF16ToString(buffer[:length]) // fmt.Printf("Window Handle: %x, Title: %s\n", hwnd, title) if strings.Contains(title, "Chromium") && title != "GFoxChromiumCloseForm" { titless = title log.Println(titless) } } return 1 // 返回非零值以继续枚举 } func Jietu(path_img string) { // 将 Go 回调函数转换为 Windows 可调用的回调函数 cb := syscall.NewCallback(enumWindowsProc) // 调用 EnumWindows 函数 procEnumWindows.Call(cb, 0) // 需要截图的窗口标题(根据实际情况修改) windowTitle := titless // 加载Windows DLL user32 := syscall.NewLazyDLL("user32.dll") // gdi32 := syscall.NewLazyDLL("gdi32.dll") // 获取API函数指针 findWindow := user32.NewProc("FindWindowW") getWindowDC := user32.NewProc("GetWindowDC") getWindowRect := user32.NewProc("GetWindowRect") releaseDC := user32.NewProc("ReleaseDC") getDpiForWindow := user32.NewProc("GetDpiForWindow") // 获取窗口DPI // createCompatibleDC := gdi32.NewProc("CreateCompatibleDC") // createCompatibleBitmap := gdi32.NewProc("CreateCompatibleBitmap") // selectObject := gdi32.NewProc("SelectObject") // bitBlt := gdi32.NewProc("BitBlt") // deleteDC := gdi32.NewProc("DeleteDC") // deleteObject := gdi32.NewProc("DeleteObject") // getDIBits := gdi32.NewProc("GetDIBits") // 1. 查找目标窗口句柄 windowName := syscall.StringToUTF16Ptr(windowTitle) hwnd, _, _ := findWindow.Call(0, uintptr(unsafe.Pointer(windowName))) if hwnd == 0 { panic("找不到指定窗口") } // 2. 获取窗口设备上下文(DC) hdc, _, _ := getWindowDC.Call(hwnd) if hdc == 0 { panic("获取窗口DC失败") } defer releaseDC.Call(hwnd, hdc) // 确保释放DC // 3. 获取窗口尺寸 var rect RECT ret, _, _ := getWindowRect.Call(hwnd, uintptr(unsafe.Pointer(&rect))) if ret == 0 { panic("获取窗口尺寸失败") } // 4. 获取窗口DPI dpi, _, _ := getDpiForWindow.Call(hwnd) if dpi == 0 { dpi = 96 // 默认DPI } // 5. 计算实际窗口尺寸(考虑DPI缩放) scaleFactor := float64(dpi) / 216 width := int(float64(rect.Right-rect.Left) / scaleFactor) height := int(float64(rect.Bottom-rect.Top) / scaleFactor) log.Println(width, height) // // 6. 创建内存兼容DC // memHdc, _, _ := createCompatibleDC.Call(hdc) // if memHdc == 0 { // panic("创建兼容DC失败") // } // defer deleteDC.Call(memHdc) // // 7. 创建兼容位图 // hBitmap, _, _ := createCompatibleBitmap.Call(hdc, uintptr(width), uintptr(height)) // if hBitmap == 0 { // panic("创建兼容位图失败") // } // defer deleteObject.Call(hBitmap) // // 8. 将位图选入内存DC // oldObj, _, _ := selectObject.Call(memHdc, hBitmap) // if oldObj == 0 { // panic("选定位图失败") // } // defer selectObject.Call(memHdc, oldObj) // 恢复原始对象 // // 9. 执行位块传输(截图操作) // ret, _, _ = bitBlt.Call( // memHdc, // 目标DC // 0, 0, // 目标坐标 // uintptr(width), // 宽度 // uintptr(height), // 高度 // hdc, // 源DC // 0, 0, // 源坐标 // SRCCOPY, // 操作类型 // ) // if ret == 0 { // panic("截图操作失败") // } // // 10. 准备位图信息头(设置为top-down格式) // bmi := BITMAPINFOHEADER{ // Size: uint32(unsafe.Sizeof(BITMAPINFOHEADER{})), // Width: int32(width), // Height: -int32(height), // 负数表示top-down格式 // Planes: 1, // BitCount: 32, // 32位色深(BGRA) // Compression: 0, // 无压缩 // } // // 11. 创建像素缓冲区 // pixels := make([]byte, width*height*4) // // 12. 获取位图数据 // ret, _, _ = getDIBits.Call( // memHdc, // hBitmap, // 0, // uintptr(height), // uintptr(unsafe.Pointer(&pixels[0])), // uintptr(unsafe.Pointer(&bmi)), // 0, // ) // if ret == 0 { // panic("获取像素数据失败") // } // // 13. 创建图像对象并转换颜色格式 // img := image.NewRGBA(image.Rect(0, 0, width, height)) // for y := 0; y < height; y++ { // for x := 0; x < width; x++ { // idx := (y*width + x) * 4 // // Windows返回BGRA格式,转换为RGBA // img.Set(x, y, color.RGBA{ // R: pixels[idx+2], // G: pixels[idx+1], // B: pixels[idx], // A: pixels[idx+3], // }) // } // } // // 14. 保存为PNG文件 // file, err := os.Create("window_screenshot.png") // if err != nil { // panic("创建文件失败: " + err.Error()) // } // defer file.Close() // if err := png.Encode(file, img); err != nil { // panic("保存PNG失败: " + err.Error()) // } //自定义截图 // img, err := screenshot.Capture(0, 0, width, height) // if err != nil { // panic(err) // } // save(img, "自定义.png") //获取所有活动屏幕 // n := screenshot.NumActiveDisplays() // if n <= 0 { // panic("没有发现活动的显示器") // } // //全屏截取所有活动屏幕 // if n > 0 { // for i := 0; i < n; i++ { // img, err := screenshot.CaptureDisplay(i) // if err != nil { // panic(err) // } // fileName := fmt.Sprintf("第%d屏幕截图.png", i) // save(img, fileName) // } // } // 获取第一个屏幕显示范围 var new image.Rectangle = image.Rect(22, 15, width+5, height+3) img, err := screenshot.CaptureRect(new) if err != nil { panic(err) } save(img, path_img) // //使用Union获取指定屏幕 矩形最小点和最大点 // var all image.Rectangle = image.Rect(0, 0, 0, 0) // bounds1 := screenshot.GetDisplayBounds(0) // all = bounds1.Union(all) // fmt.Println(all.Min.X, all.Min.Y, all.Dx(), all.Dy()) } // save *image.RGBA to filePath with PNG format. func save(img *image.RGBA, filePath string) { file, err := os.Create(filePath) if err != nil { panic(err) } defer file.Close() png.Encode(file, img) }