I want to retrieve an image from a specific application and convert it to image.Image for later use.
What I have now is a HBITMAP from windows API call. After trying a lots, I can't manage to convert the created HBITMAP to an image.Image (or at least an []byte).
rc := w32.GetClientRect(hwnd)
if rc != nil {
// create
HDCScreen := w32.GetWindowDC(hwnd)
hdc := w32.CreateCompatibleDC(HDCScreen)
hbmp := w32.CreateCompatibleBitmap(HDCScreen, int(rc.Right)-int(rc.Left), int(rc.Bottom)-int(rc.Top))
w32.SelectObject(hdc, w32.HGDIOBJ(hbmp))
// Print to memory hdc
w32.PrintWindow(hwnd, hdc, 0x00000002)
// ------------------------------------------------
var bmpInfo *w32.BITMAPINFO = &w32.BITMAPINFO{}
bmpInfo.BmiHeader.BiSize = uint32(unsafe.Sizeof(bmpInfo.BmiHeader))
firstDIBits := w32.GetDIBits(HDCScreen, hbmp, 0, 0, nil, bmpInfo, w32.DIB_RGB_COLORS)
fmt.Printf("firstDIBits: %v\n", firstDIBits)
var lpPixels *[]byte
bmpInfo.BmiHeader.BiBitCount = 32
bmpInfo.BmiHeader.BiCompression = w32.BI_RGB
bmpInfo.BmiHeader.BiHeight = int32(math.Abs(float64(bmpInfo.BmiHeader.BiHeight)))
bmpInfo.BmiHeader.BiCompression = w32.BI_RGB
secondDIBits := w32.GetDIBits(hdc, hbmp, 0, uint(bmpInfo.BmiHeader.BiHeight), unsafe.Pointer(lpPixels), bmpInfo, w32.DIB_RGB_COLORS)
fmt.Printf("secondDIBits: %v\n", secondDIBits)
fmt.Printf("lpPixels: %v\n", lpPixels)
// ------------------------------------------------
// copy to clipBoard
w32.OpenClipboard(0)
w32.EmptyClipboard()
w32.SetClipboardData(w32.CF_BITMAP, w32.HANDLE(hbmp))
w32.CloseClipboard()
// release
w32.DeleteDC(hdc)
w32.DeleteObject(w32.HGDIOBJ(hbmp))
w32.ReleaseDC(0, HDCScreen)
}
Both of GetDIBits() call return 1 but lpPixels is always nil.
CodePudding user response:
The Bitmap class inherits from the Image class.In my opinion, you couldn't need the conversion.
According to the Doc:GetDIBits function
[out] lpvBits
A pointer to a buffer to receive the bitmap data. If this parameter is NULL, the function passes the dimensions and format of the bitmap to the BITMAPINFO structure pointed to by the lpbi parameter.
I don't know much about Go language, but the lpvBits parameter of GetDIBits seem incorrect. I suggest you could refer to the threads:
Using GetDIBits to load a bitmap
How should I use the GetDIBits function
CodePudding user response:
Finally made it. Posting the code in case it can help someone else. :)
rect := image.Rect(0, 0, 1920, 1080)
img := image.NewRGBA(rect)
rc := w32.GetClientRect(hwnd)
if rc != nil {
width := int(rc.Right) - int(rc.Left)
height := int(rc.Bottom) - int(rc.Top)
hwndwin := win.HWND(hwnd)
hdc := win.GetDC(hwndwin)
if hdc == 0 {
panic("GetDC failed")
}
defer win.ReleaseDC(hwndwin, hdc)
memory_device := win.CreateCompatibleDC(hdc)
if memory_device == 0 {
panic("CreateCompatibleDC failed")
}
defer win.DeleteDC(memory_device)
bitmap := win.CreateCompatibleBitmap(hdc, int32(width), int32(height))
if bitmap == 0 {
panic("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
// 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 {
panic("SelectObject failed")
}
defer win.SelectObject(memory_device, old)
if !win.BitBlt(memory_device, 0, 0, int32(width), int32(height), hdc, int32(0), int32(0), win.SRCCOPY) {
panic("BitBlt failed")
}
if win.GetDIBits(hdc, bitmap, 0, uint32(height), (*uint8)(memptr), (*win.BITMAPINFO)(unsafe.Pointer(&header)), win.DIB_RGB_COLORS) == 0 {
panic("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
}
}