What's the fastest way to take a screenshot on windows? PIL.ImageGrab is rather slow.. it takes between 4-5 seconds to take 30 screenshots of the same small window. Taking screenshots of the whole desktop is even slower. 
- 
                    Sound like what you realy want are screen videos, a la CamStudio on Sourceforge. What's the use case? – Simon Hibbs Aug 27 '10 at 16:35
- 
                    8to get the highest score ever on [winterbells](http://www.ferryhalim.com/orisinal/g3/bells.htm) =P – Claudiu Aug 27 '10 at 17:25
- 
                    Just gave Winterbells a play and it's surprisingly addicting – jack.py Sep 06 '19 at 13:59
4 Answers
You could use win32 APIs directly .
- First give the focus to the App that you want to take screenshot of. link text 
- Win32 API can help with the screenshot: 
import win32gui
import win32ui
import win32con
w = 1920 # set this
h = 1080 # set this
bmpfilenamename = "out.bmp" #set this
hwnd = win32gui.FindWindow(None, windowname)
wDC = win32gui.GetWindowDC(hwnd)
dcObj=win32ui.CreateDCFromHandle(wDC)
cDC=dcObj.CreateCompatibleDC()
dataBitMap = win32ui.CreateBitmap()
dataBitMap.CreateCompatibleBitmap(dcObj, w, h)
cDC.SelectObject(dataBitMap)
cDC.BitBlt((0,0),(w, h) , dcObj, (0,0), win32con.SRCCOPY)
dataBitMap.SaveBitmapFile(cDC, bmpfilenamename)
# Free Resources
dcObj.DeleteDC()
cDC.DeleteDC()
win32gui.ReleaseDC(hwnd, wDC)
win32gui.DeleteObject(dataBitMap.GetHandle())
 
    
    - 12,186
- 6
- 68
- 106
 
    
    - 65,343
- 15
- 148
- 136
- 
                    14VERY IMPORTANT, as this recently bit me in the ass: you HAVE TO delete/release all the DCs created by this, or after taking ~90 images, you won't be able to anymore. in this case, `dcObj.DeleteDC(); cDC.DeleteDC(); win32gui.ReleaseDC(hwnd, wDC)` – Claudiu Sep 01 '10 at 15:39
- 
                    See this script for more details: http://bytes.com/topic/python/answers/576924-win32ui-vs-wxpy-screen-capture-multi-monitor – Alex L Jan 06 '13 at 07:33
- 
                    2As a followup from @Claudiu's comment (which is indeed necessary as he notes), I found `win32gui.DeleteObject(dataBitMap.GetHandle())` also necessary. I've edited the answer to include both comments. – jedwards Jul 15 '14 at 05:19
- 
                    
- 
                    1
- 
                    For some reason this isn't working for me. If I create a DC object like this `dcObj = win32ui.CreateDCFromHandle(wDC)` I can't access the functions of that object, so `dcObj.CreateCompatibleDC()` isn't working (I use VSCode and it usually gives suggestions when typing a dot after an object, but here it doesn't do that so I'm thinking I need to import something else? I installed pywin32 in my virtual environment and imported `win32gui, win32ui, win32con` in the program. Anyone an idea? – xvk Sep 05 '21 at 16:41
- 
                    To take a screenshot, yes. But in the case what you screenshot is a 3D rendered image, isn't it faster to grab the Framebuffer, instead of waiting that windows gets hold of it back? – Sandburg Jan 14 '22 at 16:10
Just found out how to do it with gtk. Seems fastest by far:
def image_grab_gtk(window):
    left, top, right, bot = get_rect(window)
    w = right - left
    h = bot - top
    s = gtk.gdk.Pixbuf(
        gtk.gdk.COLORSPACE_RGB, False, 8, w, h)
    s.get_from_drawable(
        gtk.gdk.get_default_root_window(),
        gtk.gdk.colormap_get_system(),
        left, top, 0, 0, w, h )
    final = Image.frombuffer(
        "RGB",
        (w, h),
        s.get_pixels(),
        "raw",
        "RGB",
        s.get_rowstride(), 1)
    return final
Without converting to a PIL Image, it's 8x faster than PIL on my test case. With converting, it's still ~2.7x faster.
 
    
    - 224,032
- 165
- 485
- 680
You can try my newly created project DXcam: I think for raw speed it's the fastest out there (in python, and without going too deep into the rabbit hole). It's originally created for a deep learning pipeline for FPS games where the higher FPS you get the better. Plus I (am trying to) design it to be user-friendly: For a screenshot just do
import dxcam
camera = dxcam.create()
frame = camera.grab()  # full screen
frame = camera.grab(region=(left, top, right, bottom))  # region
For screen capturing:
camera.start(target_fps=60)  # threaded
for i in range(1000):
    image = camera.get_latest_frame()  # Will block until new frame available
camera.stop()
I copied the part of the benchmarks section from the readme:
| DXcam | python-mss | D3DShot | |
|---|---|---|---|
| Average FPS | 238.79 | 75.87 | 118.36 | 
| Std Dev | 1.25 | 0.5447 | 0.3224 | 
The benchmarks is conducted through 5 trials on my 240hz monitor with a constant 240hz rendering rate synced w/the monitor (using blurbuster ufo test).
You can read more about the details here: https://github.com/ra1nty/DXcam
 
    
    - 61
- 1
- 
                    this is an interesting library! please get that on main PyPI. their testing repo is just for testing. – Christoph Rackwitz Jul 15 '22 at 13:06
- 
                    FWIW this was much slower than mss for my application, but the guarantee of every frame being new is nice. – Eric M. Sep 16 '22 at 08:32
You can use package mss:
Save screenshot to image file
import mss
with mss.mss() as sct:
    filename = sct.shot(output="output.png")
Get the numpy representation of screenshot
import mss
import numpy as np
with mss.mss() as sct:
    monitor = {"top": 160, "left": 160, "width": 160, "height": 135}
    img_array = np.array(sct.grab(monitor))
    # Do whatever you want...
 
    
    - 143
- 1
- 4
- 
                    How fast is this compared to other options, if you checked? TY for sharing, regardless! – Eric Carmichael Nov 02 '21 at 01:53
- 
                    
- 
                    Ty for sharing! Using other methods at 1440p I got 13fps, but with mss I was able to achieve 20fps. It's fast for sure :) – Eric Carmichael Nov 03 '21 at 06:07
