-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ImageGrab.grab() doesn't ignore windows layered on top (tooltip, pop-ups, etc.) #8456
Comments
Could you attach an image to show what you're seeing? |
@nulano did you have any insight here? |
I can confirm that tooltips are included with both
Do you know which build of Win 10 you were running before you upgraded? |
Unfortunately not. |
Do these popups come from the same application that you are trying to see in your screenshot, or a different one? I'm wondering if the request of #4415 could be a potential solution. |
I think that might solve it! |
I've created #8516 to resolve this by adding a With that, you could do something like import win32gui
from PIL import ImageGrab
window = win32gui.FindWindow(None, "Insert window title here")
handle = win32gui.GetDC(window)
ImageGrab.grab(handle=handle) |
Amazing! Thank you @radarhere! |
Pillow releases occur every three months - the next one is scheduled for January 2nd. If you would like to try out the PR in the meantime, I've put together a wheel - pillow-11.1.0.dev0-cp310-cp310-win_amd64.whl.zip |
Amazing! Thanks @radarhere! I am curious whether the tooltip issue can be solved as well? |
I expect it is something that people would want - I'm just not convinced that Windows makes that feature available. https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-bitblt is the API that we use to get the screenshot, and #8456 (comment) was our attempt to test if there was a change between Windows 10 and 11, and we didn't find any difference. |
Thanks for sharing! |
Yep, that unfortunately matches what I found also, some applications don't seem to be able to be captured in this way: #8516 (review) (worth noting that instead of using win32gui I used Microsoft Spy++; I saw that some applications have multiple windows and can only be captured by the outer-most one, but that is the one that has a title so it should also be selected by win32gui) |
I wonder if there's another way to solve your problem of these popups covering your application - by moving your application to the foreground? https://stackoverflow.com/questions/66164926/in-python-how-do-i-make-a-specific-window-stay-on-top |
Unfortunately the pop-up is somehow forced as foreground, so even though I try to pull target window to the front, it will not work. Anyway, my colleague wrote this short script that works and does not have a black window: import time
import ctypes
import win32gui
import win32ui
import win32con
from PIL import Image
# Window Title
window_title = 'SOME TITLE'
# Find the window by title
hwnd = win32gui.FindWindow(None, window_title)
if hwnd:
# Get the window's dimensions
left, top, right, bottom = win32gui.GetWindowRect(hwnd)
width = right - left
height = bottom - top
# Get the window's device context (DC)
window_dc = win32gui.GetWindowDC(hwnd)
mfc_dc = win32ui.CreateDCFromHandle(window_dc)
save_dc = mfc_dc.CreateCompatibleDC()
# Create a bitmap object
bitmap = win32ui.CreateBitmap()
bitmap.CreateCompatibleBitmap(mfc_dc, width, height)
save_dc.SelectObject(bitmap)
# Use ctypes to call PrintWindow
PW_RENDERFULLCONTENT = 2
result = ctypes.windll.user32.PrintWindow(hwnd, save_dc.GetSafeHdc(), PW_RENDERFULLCONTENT)
if result == 1:
# Save the bitmap to a file
bitmap.SaveBitmapFile(save_dc, 'screenshot.bmp')
# Convert the bitmap to a PIL image and save as PNG
bmp_info = bitmap.GetInfo()
bmp_str = bitmap.GetBitmapBits(True)
img = Image.frombuffer(
'RGB',
(bmp_info['bmWidth'], bmp_info['bmHeight']),
bmp_str, 'raw', 'BGRX', 0, 1
)
img.save('screenshot.png')
# Display the screenshot
img.show()
else:
print("Failed to capture the window content.")
# Clean up
win32gui.DeleteObject(bitmap.GetHandle())
save_dc.DeleteDC()
mfc_dc.DeleteDC()
win32gui.ReleaseDC(hwnd, window_dc)
else:
print(f"No window found with title: {window_title}") I have a hard time figuring out what the difference between your C implementation and the above implementation is, but maybe this could help figuring out the reason for the black screens? |
The difference is almost certainly the use of the |
The black screen is the right size for the window though, yes? Something that may or may not be related to your initial report that Windows 10 and Windows 11 behave differently - https://stackoverflow.com/a/54572219/4093019
But I expect you'll tell me that the window you're trying to capture is always entirely on-screen? |
That was what I observed, yes. A black box of the correct size while capturing a window that is visible and focused. |
If both Does that sound like a good idea, or it is too expensive/convoluted? |
What did you do?
Run PIL.ImageGrab.grab() without arguments.
What did you expect to happen?
Until now this has not included pop-ups and tooltips in the screenshot.
I just updated to windows 11.
I can see in issue #2569 that it is the expected behavior to not include layered windows, and that the option to include them was added, but not as a default.
I suppose the underlying API has changed in windows 11.
Anyone that can share some knowledge about this?
What are your OS, Python and Pillow versions?
The text was updated successfully, but these errors were encountered: