1 Star 0 Fork 0

橙子/screenshot

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
screenshot_windows.go 6.06 KB
一键复制 编辑 原始数据 按行查看 历史
橙子 提交于 2020-08-13 17:29 . .
package screenshot
import (
"errors"
"github.com/xuchengzhi/screenshot/internal/util"
win "github.com/xuchengzhi/win"
"image"
"syscall"
"unsafe"
)
var (
libUser32, _ = syscall.LoadLibrary("user32.dll")
funcGetDesktopWindow, _ = syscall.GetProcAddress(syscall.Handle(libUser32), "GetDesktopWindow")
funcEnumDisplayMonitors, _ = syscall.GetProcAddress(syscall.Handle(libUser32), "EnumDisplayMonitors")
funcGetMonitorInfo, _ = syscall.GetProcAddress(syscall.Handle(libUser32), "GetMonitorInfoW")
funcEnumDisplaySettings, _ = syscall.GetProcAddress(syscall.Handle(libUser32), "EnumDisplaySettingsW")
)
func Capture(x, y, width, height int) (*image.RGBA, error) {
rect := image.Rect(0, 0, width, height)
img, err := util.CreateImage(rect)
if err != nil {
return nil, err
}
hwnd := getDesktopWindow()
hdc := win.GetDC(hwnd)
if hdc == 0 {
return nil, errors.New("GetDC failed")
}
defer win.ReleaseDC(hwnd, hdc)
memory_device := win.CreateCompatibleDC(hdc)
if memory_device == 0 {
return nil, errors.New("CreateCompatibleDC failed")
}
defer win.DeleteDC(memory_device)
bitmap := win.CreateCompatibleBitmap(hdc, int32(width), int32(height))
if bitmap == 0 {
return nil, errors.New("CreateCompatibleBitmap failed")
}
defer win.DeleteObject(win.HGDIOBJ(bitmap))
var header win.BITMAPINFOHEADER
header.BiSize = uint32(unsafe.Sizeof(header))
header.BiPlanes = 1
header.BiBitCount = 32
header.BiWidth = int32(width)
header.BiHeight = int32(-height)
header.BiCompression = win.BI_RGB
header.BiSizeImage = 0
// GetDIBits balks at using Go memory on some systems. The MSDN example uses
// GlobalAlloc, so we'll do that too. See:
// https://docs.microsoft.com/en-gb/windows/desktop/gdi/capturing-an-image
bitmapDataSize := uintptr(((int64(width)*int64(header.BiBitCount) + 31) / 32) * 4 * int64(height))
hmem := win.GlobalAlloc(win.GMEM_MOVEABLE, bitmapDataSize)
defer win.GlobalFree(hmem)
memptr := win.GlobalLock(hmem)
defer win.GlobalUnlock(hmem)
old := win.SelectObject(memory_device, win.HGDIOBJ(bitmap))
if old == 0 {
return nil, errors.New("SelectObject failed")
}
defer win.SelectObject(memory_device, old)
if !win.BitBlt(memory_device, 0, 0, int32(width), int32(height), hdc, int32(x), int32(y), win.SRCCOPY) {
return nil, errors.New("BitBlt failed")
}
if win.GetDIBits(hdc, bitmap, 0, uint32(height), (*uint8)(memptr), (*win.BITMAPINFO)(unsafe.Pointer(&header)), win.DIB_RGB_COLORS) == 0 {
return nil, errors.New("GetDIBits failed")
}
i := 0
src := uintptr(memptr)
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
v0 := *(*uint8)(unsafe.Pointer(src))
v1 := *(*uint8)(unsafe.Pointer(src + 1))
v2 := *(*uint8)(unsafe.Pointer(src + 2))
// BGRA => RGBA, and set A to 255
img.Pix[i], img.Pix[i+1], img.Pix[i+2], img.Pix[i+3] = v2, v1, v0, 255
i += 4
src += 4
}
}
return img, nil
}
func NumActiveDisplays() int {
var count int = 0
enumDisplayMonitors(win.HDC(0), nil, syscall.NewCallback(countupMonitorCallback), uintptr(unsafe.Pointer(&count)))
return count
}
func GetDisplayBounds(displayIndex int) image.Rectangle {
var ctx getMonitorBoundsContext
ctx.Index = displayIndex
ctx.Count = 0
enumDisplayMonitors(win.HDC(0), nil, syscall.NewCallback(getMonitorBoundsCallback), uintptr(unsafe.Pointer(&ctx)))
return image.Rect(
int(ctx.Rect.Left), int(ctx.Rect.Top),
int(ctx.Rect.Right), int(ctx.Rect.Bottom))
}
func getDesktopWindow() win.HWND {
ret, _, _ := syscall.Syscall(funcGetDesktopWindow, 0, 0, 0, 0)
return win.HWND(ret)
}
func enumDisplayMonitors(hdc win.HDC, lprcClip *win.RECT, lpfnEnum uintptr, dwData uintptr) bool {
ret, _, _ := syscall.Syscall6(funcEnumDisplayMonitors, 4,
uintptr(hdc),
uintptr(unsafe.Pointer(lprcClip)),
lpfnEnum,
dwData,
0,
0)
return int(ret) != 0
}
func countupMonitorCallback(hMonitor win.HMONITOR, hdcMonitor win.HDC, lprcMonitor *win.RECT, dwData uintptr) uintptr {
var count *int
count = (*int)(unsafe.Pointer(dwData))
*count = *count + 1
return uintptr(1)
}
type getMonitorBoundsContext struct {
Index int
Rect win.RECT
Count int
}
func getMonitorBoundsCallback(hMonitor win.HMONITOR, hdcMonitor win.HDC, lprcMonitor *win.RECT, dwData uintptr) uintptr {
var ctx *getMonitorBoundsContext
ctx = (*getMonitorBoundsContext)(unsafe.Pointer(dwData))
if ctx.Count != ctx.Index {
ctx.Count = ctx.Count + 1
return uintptr(1)
}
if realSize := getMonitorRealSize(hMonitor); realSize != nil {
ctx.Rect = *realSize
} else {
ctx.Rect = *lprcMonitor
}
return uintptr(0)
}
type _MONITORINFOEX struct {
win.MONITORINFO
DeviceName [win.CCHDEVICENAME]uint16
}
const _ENUM_CURRENT_SETTINGS = 0xFFFFFFFF
type _DEVMODE struct {
_ [68]byte
DmSize uint16
_ [6]byte
DmPosition win.POINT
_ [86]byte
DmPelsWidth uint32
DmPelsHeight uint32
_ [40]byte
}
// getMonitorRealSize makes a call to GetMonitorInfo
// to obtain the device name for the monitor handle
// provided to the method.
//
// With the device name, EnumDisplaySettings is called to
// obtain the current configuration for the monitor, this
// information includes the real resolution of the monitor
// rather than the scaled version based on DPI.
//
// If either handle calls fail, it will return a nil
// allowing the calling method to use the bounds information
// returned by EnumDisplayMonitors which may be affected
// by DPI.
func getMonitorRealSize(hMonitor win.HMONITOR) *win.RECT {
info := _MONITORINFOEX{}
info.CbSize = uint32(unsafe.Sizeof(info))
ret, _, _ := syscall.Syscall(funcGetMonitorInfo, 2, uintptr(hMonitor), uintptr(unsafe.Pointer(&info)), 0)
if ret == 0 {
return nil
}
devMode := _DEVMODE{}
devMode.DmSize = uint16(unsafe.Sizeof(devMode))
if ret, _, _ := syscall.Syscall(funcEnumDisplaySettings, 3, uintptr(unsafe.Pointer(&info.DeviceName[0])), _ENUM_CURRENT_SETTINGS, uintptr(unsafe.Pointer(&devMode))); ret == 0 {
return nil
}
return &win.RECT{
Left: devMode.DmPosition.X,
Right: devMode.DmPosition.X + int32(devMode.DmPelsWidth),
Top: devMode.DmPosition.Y,
Bottom: devMode.DmPosition.Y + int32(devMode.DmPelsHeight),
}
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/xuchengzhi/screenshot.git
[email protected]:xuchengzhi/screenshot.git
xuchengzhi
screenshot
screenshot
master

搜索帮助