我目前正在尝试使用
PIL.ImageGrab
截取包含鼠标光标的屏幕截图。
这是我的代码:
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")
这是我的
get_cursor()
功能:
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
问题是有些光标没有粘贴到正确的位置,因为它们的位置左侧有像素,如(不注意质量)。
如何正确放置光标图像(或以其他方式解决问题)?
鼠标光标有一个“热点”,即图像相对于光标位置放置的位置 这个“热点”可以这样获取:
import win32gui
hcursor = win32gui.GetCursorInfo()[1]
hotspot = win32gui.GetIconInfo(hcursor)[1:3]
所以完整的代码是:
import ctypes, win32gui, win32ui
from PIL import Image, ImageGrab
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()
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()
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)
hotspot = win32gui.GetIconInfo(hcursor)[1:3]
return (cursor, hotspot)
cursor, (hotspotx, hotspoty) = get_cursor()
cursor.save("cursor.png")
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 - hotspotx), round(pos_win[1]*ratio - hotspoty))
img.paste(cursor, pos, cursor)
img.save("screenshot.png")
您可以尝试使用指针和 pyautogui 来达到目的。这非常简单,可能会达到您的目的。
import pyautogui
from PIL import ImageGrab, ImageDraw
# Take the screenshot
img = ImageGrab.grab()
# Get the cursor position
x, y = pyautogui.position()
# Create an ImageDraw object
draw = ImageDraw.Draw(img)
# Draw a circle at the cursor position
draw.ellipse((x, y, x+15, y+15), fill='white')
# Save the screenshot
img.save('screenshot_with_cursor.png')