feat: refactor screenshot capture implementation and update UI reload labels
This commit is contained in:
@@ -8,32 +8,18 @@ import (
|
||||
"image/png"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/kbinani/screenshot"
|
||||
)
|
||||
|
||||
var (
|
||||
user32 = syscall.NewLazyDLL("user32.dll")
|
||||
gdi32 = syscall.NewLazyDLL("gdi32.dll")
|
||||
dwmapi = syscall.NewLazyDLL("dwmapi.dll")
|
||||
user32 = syscall.NewLazyDLL("user32.dll")
|
||||
dwmapi = syscall.NewLazyDLL("dwmapi.dll")
|
||||
|
||||
// user32 functions
|
||||
getForegroundWindow = user32.NewProc("GetForegroundWindow")
|
||||
getWindowRect = user32.NewProc("GetWindowRect")
|
||||
getClientRect = user32.NewProc("GetClientRect")
|
||||
getDC = user32.NewProc("GetDC")
|
||||
releaseDC = user32.NewProc("ReleaseDC")
|
||||
findWindowW = user32.NewProc("FindWindowW")
|
||||
getWindowDC = user32.NewProc("GetWindowDC")
|
||||
printWindow = user32.NewProc("PrintWindow")
|
||||
clientToScreen = user32.NewProc("ClientToScreen")
|
||||
|
||||
// gdi32 functions
|
||||
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")
|
||||
getForegroundWindow = user32.NewProc("GetForegroundWindow")
|
||||
getWindowRect = user32.NewProc("GetWindowRect")
|
||||
findWindowW = user32.NewProc("FindWindowW")
|
||||
|
||||
// dwmapi functions
|
||||
dwmGetWindowAttribute = dwmapi.NewProc("DwmGetWindowAttribute")
|
||||
@@ -47,39 +33,7 @@ type RECT struct {
|
||||
Bottom int32
|
||||
}
|
||||
|
||||
// POINT structure for Windows API
|
||||
type POINT struct {
|
||||
X int32
|
||||
Y int32
|
||||
}
|
||||
|
||||
// BITMAPINFOHEADER structure
|
||||
type BITMAPINFOHEADER struct {
|
||||
BiSize uint32
|
||||
BiWidth int32
|
||||
BiHeight int32
|
||||
BiPlanes uint16
|
||||
BiBitCount uint16
|
||||
BiCompression uint32
|
||||
BiSizeImage uint32
|
||||
BiXPelsPerMeter int32
|
||||
BiYPelsPerMeter int32
|
||||
BiClrUsed uint32
|
||||
BiClrImportant uint32
|
||||
}
|
||||
|
||||
// BITMAPINFO structure
|
||||
type BITMAPINFO struct {
|
||||
BmiHeader BITMAPINFOHEADER
|
||||
BmiColors [1]uint32
|
||||
}
|
||||
|
||||
const (
|
||||
SRCCOPY = 0x00CC0020
|
||||
DIB_RGB_COLORS = 0
|
||||
BI_RGB = 0
|
||||
PW_CLIENTONLY = 1
|
||||
PW_RENDERFULLCONTENT = 2
|
||||
DWMWA_EXTENDED_FRAME_BOUNDS = 9
|
||||
)
|
||||
|
||||
@@ -113,82 +67,10 @@ func CaptureWindowByHandle(hwnd uintptr) (*image.RGBA, error) {
|
||||
return nil, fmt.Errorf("invalid window dimensions: %dx%d", width, height)
|
||||
}
|
||||
|
||||
// Get window DC
|
||||
hdcWindow, _, err := getWindowDC.Call(hwnd)
|
||||
if hdcWindow == 0 {
|
||||
return nil, fmt.Errorf("GetWindowDC failed: %v", err)
|
||||
}
|
||||
defer releaseDC.Call(hwnd, hdcWindow)
|
||||
|
||||
// Create compatible DC
|
||||
hdcMem, _, err := createCompatibleDC.Call(hdcWindow)
|
||||
if hdcMem == 0 {
|
||||
return nil, fmt.Errorf("CreateCompatibleDC failed: %v", err)
|
||||
}
|
||||
defer deleteDC.Call(hdcMem)
|
||||
|
||||
// Create compatible bitmap
|
||||
hBitmap, _, err := createCompatibleBitmap.Call(hdcWindow, uintptr(width), uintptr(height))
|
||||
if hBitmap == 0 {
|
||||
return nil, fmt.Errorf("CreateCompatibleBitmap failed: %v", err)
|
||||
}
|
||||
defer deleteObject.Call(hBitmap)
|
||||
|
||||
// Select bitmap into DC
|
||||
oldBitmap, _, _ := selectObject.Call(hdcMem, hBitmap)
|
||||
defer selectObject.Call(hdcMem, oldBitmap)
|
||||
|
||||
// Try PrintWindow first (works better with layered/composited windows)
|
||||
ret, _, _ = printWindow.Call(hwnd, hdcMem, PW_RENDERFULLCONTENT)
|
||||
if ret == 0 {
|
||||
// Fallback to BitBlt
|
||||
ret, _, err = bitBlt.Call(
|
||||
hdcMem, 0, 0, uintptr(width), uintptr(height),
|
||||
hdcWindow, 0, 0,
|
||||
SRCCOPY,
|
||||
)
|
||||
if ret == 0 {
|
||||
return nil, fmt.Errorf("BitBlt failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare BITMAPINFO
|
||||
bmi := BITMAPINFO{
|
||||
BmiHeader: BITMAPINFOHEADER{
|
||||
BiSize: uint32(unsafe.Sizeof(BITMAPINFOHEADER{})),
|
||||
BiWidth: int32(width),
|
||||
BiHeight: -int32(height), // Negative for top-down DIB
|
||||
BiPlanes: 1,
|
||||
BiBitCount: 32,
|
||||
BiCompression: BI_RGB,
|
||||
},
|
||||
}
|
||||
|
||||
// Allocate buffer for pixel data
|
||||
pixelDataSize := width * height * 4
|
||||
pixelData := make([]byte, pixelDataSize)
|
||||
|
||||
// Get the bitmap bits
|
||||
ret, _, err = getDIBits.Call(
|
||||
hdcMem,
|
||||
hBitmap,
|
||||
0,
|
||||
uintptr(height),
|
||||
uintptr(unsafe.Pointer(&pixelData[0])),
|
||||
uintptr(unsafe.Pointer(&bmi)),
|
||||
DIB_RGB_COLORS,
|
||||
)
|
||||
if ret == 0 {
|
||||
return nil, fmt.Errorf("GetDIBits failed: %v", err)
|
||||
}
|
||||
|
||||
// Convert BGRA to RGBA
|
||||
img := image.NewRGBA(image.Rect(0, 0, width, height))
|
||||
for i := 0; i < len(pixelData); i += 4 {
|
||||
img.Pix[i+0] = pixelData[i+2] // R <- B
|
||||
img.Pix[i+1] = pixelData[i+1] // G <- G
|
||||
img.Pix[i+2] = pixelData[i+0] // B <- R
|
||||
img.Pix[i+3] = pixelData[i+3] // A <- A
|
||||
// Using kbinani/screenshot to capture the rectangle on screen
|
||||
img, err := screenshot.CaptureRect(image.Rect(int(rect.Left), int(rect.Top), int(rect.Right), int(rect.Bottom)))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("screenshot.CaptureRect failed: %v", err)
|
||||
}
|
||||
|
||||
return img, nil
|
||||
|
||||
Reference in New Issue
Block a user