views:

172

answers:

2

With python 3, I'd like to get a handle to another window (not part of my application) such that I can either:

a) directly capture that window as a screenshot or

b) determine its position and size and capture it some other way

In case it is important, I am using Windows XP.

I found this solution, but it is not quite what I need since it is full screen and more importantly, PIL to the best of my knowledge does not support 3.x yet.

+1  A: 

Here's how you can do it using PIL on win32. Given a window handle (hwnd), you should only need the last 4 lines of code. The preceding simply search for a window with "firefox" in the title. Since PIL's source is available, you should be able to poke around the ImageGrab.grab(bbox) method and figure out the win32 code you need to make this happen.

from PIL import ImageGrab
import win32gui

toplist, winlist = [], []
def enum_cb(hwnd, results):
    winlist.append((hwnd, win32gui.GetWindowText(hwnd)))
win32gui.EnumWindows(enum_cb, toplist)

firefox = [(hwnd, title) for hwnd, title in winlist if 'firefox' in title.lower()]
# just grab the hwnd for first window matching firefox
firefox = firefox[0]
hwnd = firefox[0]

win32gui.SetForegroundWindow(hwnd)
bbox = win32gui.GetWindowRect(hwnd)
img = ImageGrab.grab(bbox)
img.show()
ars
That looks great if I understand it correctly. PIL won't work directly but I can use win32gui in Python 3k to get the window as you showed and then extract the win32 code from PIL to do the grab. Is that right? I'll try it out as soon as I can set aside the time.
yakiimo
I'm still new to both python and win32, but this certainly seems to be going the right direction. I'll post more specific code here if I figure it out for anyone else that might need it.
yakiimo
So this is not working out so well for me at the moment. I was able to get a handle to the window as you showed. Thanks very much for that. However, when I dug down, I believe ImageGrab ends up in a c file named display.c that comes with PIL. The function there is PyImaging_GrabScreenWin32. I'm going to research whether I can use that myself, but in the meantime, does anyone know a way to get a screenshot in Python 3k without needing to compile and interface to a c library myself?
yakiimo
You could try the code on this page, but I haven't done so myself: http://coding.derkeiler.com/Archive/Python/comp.lang.python/2004-05/2531.html
ars
That worked! Those are quite similar to what happens in display.c. I didn't realize that much of the interface was available in Python already through the other libraries. Thanks for the invaluable follow-up ars.
yakiimo
Glad it worked out, yakimo. :)
ars
A: 

Ars gave me all the pieces. I am just putting the pieces together here for anyone else who needs to get a screenshot in python 3.x. Next I need to figure out how to work with a win32 bitmap without having PIL to lean on.

Get a Screenshot (pass hwnd for a window instead of full screen):

def screenshot(hwnd = None):
    import win32gui
    import win32ui
    import win32con
    from time import sleep
    if not hwnd:
        hwnd=win32gui.GetDesktopWindow()
    l,t,r,b=win32gui.GetWindowRect(hwnd)
    h=b-t
    w=r-l
    hDC = win32gui.GetWindowDC(hwnd)
    myDC=win32ui.CreateDCFromHandle(hDC)
    newDC=myDC.CreateCompatibleDC()

    myBitMap = win32ui.CreateBitmap()
    myBitMap.CreateCompatibleBitmap(myDC, w, h)

    newDC.SelectObject(myBitMap)

    win32gui.SetForegroundWindow(hwnd)
    sleep(.2) #lame way to allow screen to draw before taking shot
    newDC.BitBlt((0,0),(w, h) , myDC, (0,0), win32con.SRCCOPY)
    myBitMap.Paint(newDC)
    myBitMap.SaveBitmapFile(newDC,'c:\\tmp.bmp')

Get a Window Handle by title (to pass to the above function):

def _get_windows_bytitle(title_text, exact = False):
    def _window_callback(hwnd, all_windows):
        all_windows.append((hwnd, win32gui.GetWindowText(hwnd)))
    windows = []
    win32gui.EnumWindows(_window_callback, windows)
    if exact:
        return [hwnd for hwnd, title in windows if title_text == title]
    else:
        return [hwnd for hwnd, title in windows if title_text in title]
yakiimo