forked from vova616/screenshot
-
Notifications
You must be signed in to change notification settings - Fork 3
/
screenshot_windows.go
90 lines (75 loc) · 2.56 KB
/
screenshot_windows.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package screenshot
import (
"fmt"
"github.com/AllenDang/w32"
"image"
"reflect"
"unsafe"
)
func ScreenRect() (image.Rectangle, error) {
hDC := w32.GetDC(0)
if hDC == 0 {
return image.Rectangle{}, fmt.Errorf("Could not Get primary display err:%d\n", w32.GetLastError())
}
defer w32.ReleaseDC(0, hDC)
x := w32.GetDeviceCaps(hDC, w32.HORZRES)
y := w32.GetDeviceCaps(hDC, w32.VERTRES)
return image.Rect(0, 0, x, y), nil
}
func CaptureScreen() (*image.RGBA, error) {
r, e := ScreenRect()
if e != nil {
return nil, e
}
return CaptureRect(r)
}
func CaptureRect(rect image.Rectangle) (*image.RGBA, error) {
hDC := w32.GetDC(0)
if hDC == 0 {
return nil, fmt.Errorf("Could not Get primary display err:%d.\n", w32.GetLastError())
}
defer w32.ReleaseDC(0, hDC)
m_hDC := w32.CreateCompatibleDC(hDC)
if m_hDC == 0 {
return nil, fmt.Errorf("Could not Create Compatible DC err:%d.\n", w32.GetLastError())
}
defer w32.DeleteDC(m_hDC)
x, y := rect.Dx(), rect.Dy()
bt := w32.BITMAPINFO{}
bt.BmiHeader.BiSize = uint32(reflect.TypeOf(bt.BmiHeader).Size())
bt.BmiHeader.BiWidth = int32(x)
bt.BmiHeader.BiHeight = int32(-y)
bt.BmiHeader.BiPlanes = 1
bt.BmiHeader.BiBitCount = 32
bt.BmiHeader.BiCompression = w32.BI_RGB
ptr := unsafe.Pointer(uintptr(0))
m_hBmp := w32.CreateDIBSection(m_hDC, &bt, w32.DIB_RGB_COLORS, &ptr, 0, 0)
if m_hBmp == 0 {
return nil, fmt.Errorf("Could not Create DIB Section err:%d.\n", w32.GetLastError())
}
if m_hBmp == w32.InvalidParameter {
return nil, fmt.Errorf("One or more of the input parameters is invalid while calling CreateDIBSection.\n")
}
defer w32.DeleteObject(w32.HGDIOBJ(m_hBmp))
obj := w32.SelectObject(m_hDC, w32.HGDIOBJ(m_hBmp))
if obj == 0 {
return nil, fmt.Errorf("error occurred and the selected object is not a region err:%d.\n", w32.GetLastError())
}
if obj == 0xffffffff { //GDI_ERROR
return nil, fmt.Errorf("GDI_ERROR while calling SelectObject err:%d.\n", w32.GetLastError())
}
defer w32.DeleteObject(obj)
//Note:BitBlt contains bad error handling, we will just assume it works and if it doesn't it will panic :x
w32.BitBlt(m_hDC, 0, 0, x, y, hDC, rect.Min.X, rect.Min.Y, w32.SRCCOPY)
var slice []byte
hdrp := (*reflect.SliceHeader)(unsafe.Pointer(&slice))
hdrp.Data = uintptr(ptr)
hdrp.Len = x * y * 4
hdrp.Cap = x * y * 4
imageBytes := make([]byte, len(slice))
for i := 0; i < len(imageBytes); i += 4 {
imageBytes[i], imageBytes[i+2], imageBytes[i+1], imageBytes[i+3] = slice[i+2], slice[i], slice[i+1], slice[i+3]
}
img := &image.RGBA{imageBytes, 4 * x, image.Rect(0, 0, x, y)}
return img, nil
}