I am currently trying to take a screenshot who include mouse cursor using PIL.ImageGrab.
This is my code:
import ctypes, win32gui, win32ui
from PIL import Image, ImageGrab
size = round(ctypes.windll.shcore.GetScaleFactorForDevice(0) / 100 * 32)
cursor = get_cursor()
pixdata = cursor.load()
minsize = [size, None]
width, height = cursor.size
for y in range(height):
for x in range(width):
if pixdata[x, y] == (0, 0, 0, 255):
pixdata[x, y] = (0, 0, 0, 0)
else:
if minsize[1] == None:
minsize[1] = y
if x < minsize[0]:
minsize[0] = x
ratio = ctypes.windll.shcore.GetScaleFactorForDevice(0) / 100
img = ImageGrab.grab(bbox=None, include_layered_windows=True)
pos_win = win32gui.GetCursorPos()
pos = (round(pos_win[0]*ratio), round(pos_win[1]*ratio))
img.paste(cursor, pos, cursor)
img.save("screenshot.png")
And this is my get_cursor() function:
def get_cursor():
hcursor = win32gui.GetCursorInfo()[1]
hdc = win32ui.CreateDCFromHandle(win32gui.GetDC(0))
hbmp = win32ui.CreateBitmap()
hbmp.CreateCompatibleBitmap(hdc, 36, 36)
hdc = hdc.CreateCompatibleDC()
hdc.SelectObject(hbmp)
hdc.DrawIcon((0,0), hcursor)
bmpinfo = hbmp.GetInfo()
bmpbytes = hbmp.GetBitmapBits()
bmpstr = hbmp.GetBitmapBits(True)
cursor = Image.frombuffer('RGB', (bmpinfo['bmWidth'], bmpinfo['bmHeight']), bmpstr, 'raw', 'BGRX', 0, 1).convert("RGBA")
win32gui.DestroyIcon(hcursor)
win32gui.DeleteObject(hbmp.GetHandle())
hdc.DeleteDC()
pixdata = cursor.load()
minsize = [32, None]
width, height = cursor.size
for y in range(height):
for x in range(width):
if pixdata[x, y] == (0, 0, 0, 255):
pixdata[x, y] = (0, 0, 0, 0)
else:
if minsize[1] == None:
minsize[1] = y
if x < minsize[0]:
minsize[0] = x
return cursor
The problem is that some cursors are not pasted at the right position because they have pixels to the left of their position like this (do not pay attention to the quality).
How can I place the cursor image correctly (or otherwise solve the problem)?
get_cursorfunction is placed. On both screenshots, the real cursor is exactly at the same position (and is not moving)win32gui.GetCursorInfo()result somewhere; try reading the documentation. In the worst case, you can just hard-code the offset yourself.