By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,231 Members | 1,636 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,231 IT Pros & Developers. It's quick & easy.

win32ui vs wxPy screen capture multi monitor

P: 4
Just posting a solution to the problem of capturing the whole virtual screen area, including all monitors with python and pywin32.
Because this doesn't work even with PIL's imagegrab module.

Expand|Select|Wrap|Line Numbers
  1. import win32gui,  win32ui,  win32con, win32api
  2.  
  3. hwnd = win32gui.GetDesktopWindow()
  4. print hwnd
  5.  
  6. # you can use this to capture only a specific window
  7. #l, t, r, b = win32gui.GetWindowRect(hwnd)
  8. #w = r - l
  9. #h = b - t
  10.  
  11. # get complete virtual screen including all monitors
  12. SM_XVIRTUALSCREEN = 76
  13. SM_YVIRTUALSCREEN = 77
  14. SM_CXVIRTUALSCREEN = 78
  15. SM_CYVIRTUALSCREEN = 79
  16. w = vscreenwidth = win32api.GetSystemMetrics(SM_CXVIRTUALSCREEN)
  17. h = vscreenheigth = win32api.GetSystemMetrics(SM_CYVIRTUALSCREEN)
  18. l = vscreenx = win32api.GetSystemMetrics(SM_XVIRTUALSCREEN)
  19. t = vscreeny = win32api.GetSystemMetrics(SM_YVIRTUALSCREEN)
  20. r = l + w
  21. b = t + h
  22.  
  23. print l, t, r, b, ' -> ', w, h
  24.  
  25. hwndDC = win32gui.GetWindowDC(hwnd)
  26. mfcDC  = win32ui.CreateDCFromHandle(hwndDC)
  27. saveDC = mfcDC.CreateCompatibleDC()
  28.  
  29. saveBitMap = win32ui.CreateBitmap()
  30. saveBitMap.CreateCompatibleBitmap(mfcDC, w, h)
  31. saveDC.SelectObject(saveBitMap)
  32. saveDC.BitBlt((0, 0), (w, h),  mfcDC,  (l, t),  win32con.SRCCOPY)
  33. saveBitMap.SaveBitmapFile(saveDC,  'screencapture.bmp')
  34.  
Dec 14 '06 #1
Share this Question
Share on Google+
5 Replies


P: 4
and to save that file as jpg, png... you can use PIL:

Expand|Select|Wrap|Line Numbers
  1. bmpinfo = saveBitMap.GetInfo()
  2. print bmpinfo
  3. bmpstr = saveBitMap.GetBitmapBits(True)
  4.  
  5. import Image
  6. im = Image.frombuffer('RGB', (bmpinfo['bmWidth'], bmpinfo['bmHeight']), bmpstr, 'raw', 'BGRX', 0, 1)
  7. #im.save('screencapture.jpg', format = 'jpeg', quality = 85)
  8. im.save('screencapture.png', format = 'png')
  9.  
Dec 14 '06 #2

P: 4
to do the whole thing even easier use wx:

Expand|Select|Wrap|Line Numbers
  1. import wx
  2.  
  3. app = wx.PySimpleApp()
  4.  
  5. context = wx.ScreenDC()
  6. r, b = context.GetSize()
  7.  
  8. # i have a second monitor left of my primary, so these value are negativ
  9. l, t = (-1280, -256) # coulfn't find a wx function to get these
  10.  
  11. w, h = (r - l, b - t)
  12. bitmap = wx.EmptyBitmap(w, h, -1)
  13.  
  14. memory = wx.MemoryDC()
  15. memory.SelectObject(bitmap)
  16. memory.Blit(0, 0, w, h, context, l, t)
  17. memory.SelectObject(wx.NullBitmap)
  18.  
  19. #bitmap.SaveFile("screencapture.bmp", wx.BITMAP_TYPE_BMP)
  20. #bitmap.SaveFile("screencapture.jpg", wx.BITMAP_TYPE_JPEG)
  21. bitmap.SaveFile("screencapture.png", wx.BITMAP_TYPE_PNG)
  22.  
Dec 14 '06 #3

bartonc
Expert 5K+
P: 6,596
Wow. Thanks nobugus. This is very useful.
Dec 14 '06 #4

bartonc
Expert 5K+
P: 6,596
Wow. Thanks nobugus. This is very useful.
This one is really worth a bump to the top.
Dec 17 '06 #5

P: 1
First, many thanks to nobugus for this post, I had been hunting around for a way to do this for a while now, and this post was a huge boon!

It's worth noting though, that the code as is in the first post has a memory leak, and that if you wrap his code in a function take enough screenshots it will eventually crash with a windows error code 8. (On my system, this happens somewhere between 100 and 200 screenshots).

Adding the following after saving the screenshot (or doing whatever you like with it) seems to close the leak:

Expand|Select|Wrap|Line Numbers
  1. saveDC.DeleteDC()
  2. win32gui.DeleteObject(saveBitMap.GetHandle())
I don't understand the details of why python/pywin32 garbage collection isn't handling this when the variables leave scope, but I thought I'd post this in case anyone else had the same problem. I experimented with leaving out just one line or the other, but both seem necessary. If anyone wants to explain to me why this works, I'm all ears!
Sep 20 '10 #6

Post your reply

Sign in to post your reply or Sign up for a free account.