Examples¶
Basics¶
One screenshot per monitor¶
forfilenameinsct.save():print(filename)
Screenshot of the monitor 1¶
filename=sct.shot()print(filename)
A screenshot to grab them all¶
filename=sct.shot(mon=-1,output='fullscreen.png')print(filename)
Callback¶
Screenshot of the monitor 1 with a callback:
frompathlibimportPathimportmssdefon_exists(fname:str)->None:"""Callback example when we try to overwrite an existing screenshot."""file=Path(fname)iffile.is_file():newfile=file.with_name(f"{file.name}.old")print(f"{fname} →{newfile}")file.rename(newfile)withmss.mss()assct:filename=sct.shot(output="mon-{mon}.png",callback=on_exists)print(filename)
Part of the screen¶
You can capture only a part of the screen:
importmssimportmss.toolswithmss.mss()assct:# The screen part to capturemonitor={"top":160,"left":160,"width":160,"height":135}output="sct-{top}x{left}_{width}x{height}.png".format(**monitor)# Grab the datasct_img=sct.grab(monitor)# Save to the picture filemss.tools.to_png(sct_img.rgb,sct_img.size,output=output)print(output)
Added in version 3.0.0.
Part of the screen of the 2nd monitor¶
This is an example of capturing some part of the screen of the monitor 2:
importmssimportmss.toolswithmss.mss()assct:# Get information of monitor 2monitor_number=2mon=sct.monitors[monitor_number]# The screen part to capturemonitor={"top":mon["top"]+100,# 100px from the top"left":mon["left"]+100,# 100px from the left"width":160,"height":135,"mon":monitor_number,}output="sct-mon{mon}_{top}x{left}_{width}x{height}.png".format(**monitor)# Grab the datasct_img=sct.grab(monitor)# Save to the picture filemss.tools.to_png(sct_img.rgb,sct_img.size,output=output)print(output)
Added in version 3.0.0.
Use PIL bbox style and percent values¶
You can use the same value as you would do withPIL.ImageGrab(bbox=tuple(...))
.This is an example that uses it, but also using percentage values:
importmssimportmss.toolswithmss.mss()assct:# Use the 1st monitormonitor=sct.monitors[1]# Capture a bbox using percent valuesleft=monitor["left"]+monitor["width"]*5//100# 5% from the lefttop=monitor["top"]+monitor["height"]*5//100# 5% from the topright=left+400# 400px widthlower=top+400# 400px heightbbox=(left,top,right,lower)# Grab the picture# Using PIL would be something like:# im = ImageGrab(bbox=bbox)im=sct.grab(bbox)# Save it!mss.tools.to_png(im.rgb,im.size,output="screenshot.png")
Added in version 3.1.0.
PNG Compression¶
You can tweak the PNG compression level (seezlib.compress()
for details):
sct.compression_level=2
Added in version 3.2.0.
Get PNG bytes, no file output¶
You can get the bytes of the PNG image:
withmss.mss()assct:# The monitor or screen part to capturemonitor=sct.monitors[1]# or a region# Grab the datasct_img=sct.grab(monitor)# Generate the PNGpng=mss.tools.to_png(sct_img.rgb,sct_img.size)
Advanced¶
You can handle data using a custom class:
fromtypingimportAnyimportmssfrommss.modelsimportMonitorfrommss.screenshotimportScreenShotclassSimpleScreenShot(ScreenShot):"""Define your own custom method to deal with screenshot raw data. Of course, you can inherit from the ScreenShot class and change or add new methods. """def__init__(self,data:bytearray,monitor:Monitor,**_:Any)->None:self.data=dataself.monitor=monitorwithmss.mss()assct:sct.cls_image=SimpleScreenShotimage=sct.grab(sct.monitors[1])# ...
Added in version 3.1.0.
PIL¶
You can use the Python Image Library (aka Pillow) to do whatever you want with raw pixels.This is an example usingfrombytes():
fromPILimportImageimportmsswithmss.mss()assct:# Get rid of the first, as it represents the "All in One" monitor:fornum,monitorinenumerate(sct.monitors[1:],1):# Get raw pixels from the screensct_img=sct.grab(monitor)# Create the Imageimg=Image.frombytes("RGB",sct_img.size,sct_img.bgra,"raw","BGRX")# The same, but less efficient:# img = Image.frombytes('RGB', sct_img.size, sct_img.rgb)# And save it!output=f"monitor-{num}.png"img.save(output)print(output)
Added in version 3.0.0.
Playing with pixels¶
This is an example usingputdata():
fromPILimportImageimportmsswithmss.mss()assct:# Get a screenshot of the 1st monitorsct_img=sct.grab(sct.monitors[1])# Create an Imageimg=Image.new("RGB",sct_img.size)# Best solution: create a list(tuple(R, G, B), ...) for putdata()pixels=zip(sct_img.raw[2::4],sct_img.raw[1::4],sct_img.raw[::4])img.putdata(list(pixels))# But you can set individual pixels too (slower)""" pixels = img.load() for x in range(sct_img.width): for y in range(sct_img.height): pixels[x, y] = sct_img.pixel(x, y) """# Show it!img.show()
Added in version 3.0.0.
OpenCV/Numpy¶
See how fast you can record the screen.You can easily view a HD movie with VLC and see it too in the OpenCV window.And with __no__ lag please.
importtimeimportcv2importnumpyasnpimportmsswithmss.mss()assct:# Part of the screen to capturemonitor={"top":40,"left":0,"width":800,"height":640}while"Screen capturing":last_time=time.time()# Get raw pixels from the screen, save it to a Numpy arrayimg=np.array(sct.grab(monitor))# Display the picturecv2.imshow("OpenCV/Numpy normal",img)# Display the picture in grayscale# cv2.imshow('OpenCV/Numpy grayscale',# cv2.cvtColor(img, cv2.COLOR_BGRA2GRAY))print(f"fps:{1/(time.time()-last_time)}")# Press "q" to quitifcv2.waitKey(25)&0xFF==ord("q"):cv2.destroyAllWindows()break
Added in version 3.0.0.
FPS¶
Benchmark¶
Simple naive benchmark to compare withReading game frames in Python with OpenCV - Python Plays GTA V:
importtimeimportcv2importnumpyasnpfromPILimportImageGrabimportmssdefscreen_record()->int:# 800x600 windowed modemon=(0,40,800,640)title="[PIL.ImageGrab] FPS benchmark"fps=0last_time=time.time()whiletime.time()-last_time<1:img=np.asarray(ImageGrab.grab(bbox=mon))fps+=1cv2.imshow(title,cv2.cvtColor(img,cv2.COLOR_BGR2RGB))ifcv2.waitKey(25)&0xFF==ord("q"):cv2.destroyAllWindows()breakreturnfpsdefscreen_record_efficient()->int:# 800x600 windowed modemon={"top":40,"left":0,"width":800,"height":640}title="[MSS] FPS benchmark"fps=0sct=mss.mss()last_time=time.time()whiletime.time()-last_time<1:img=np.asarray(sct.grab(mon))fps+=1cv2.imshow(title,img)ifcv2.waitKey(25)&0xFF==ord("q"):cv2.destroyAllWindows()breakreturnfpsprint("PIL:",screen_record())print("MSS:",screen_record_efficient())
Added in version 3.0.0.
Multiprocessing¶
Performances can be improved by delegating the PNG file creation to a specific worker.This is a simple example using themultiprocessing
inspired by theTensorFlow Object Detection Introduction project:
frommultiprocessingimportProcess,Queueimportmssimportmss.toolsdefgrab(queue:Queue)->None:rect={"top":0,"left":0,"width":600,"height":800}withmss.mss()assct:for_inrange(1_000):queue.put(sct.grab(rect))# Tell the other worker to stopqueue.put(None)defsave(queue:Queue)->None:number=0output="screenshots/file_{}.png"to_png=mss.tools.to_pngwhile"there are screenshots":img=queue.get()ifimgisNone:breakto_png(img.rgb,img.size,output=output.format(number))number+=1if__name__=="__main__":# The screenshots queuequeue:Queue=Queue()# 2 processes: one for grabbing and one for saving PNG filesProcess(target=grab,args=(queue,)).start()Process(target=save,args=(queue,)).start()
Added in version 5.0.0.
BGRA to RGB¶
Different possibilities to convert raw BGRA values to RGB:
defmss_rgb(im):""" Better than Numpy versions, but slower than Pillow. """returnim.rgbdefnumpy_flip(im):""" Most efficient Numpy version as of now. """frame=numpy.array(im,dtype=numpy.uint8)returnnumpy.flip(frame[:,:,:3],2).tobytes()defnumpy_slice(im):""" Slow Numpy version. """returnnumpy.array(im,dtype=numpy.uint8)[...,[2,1,0]].tobytes()defpil_frombytes(im):""" Efficient Pillow version. """returnImage.frombytes('RGB',im.size,im.bgra,'raw','BGRX').tobytes()withmss.mss()assct:im=sct.grab(sct.monitors[1])rgb=pil_frombytes(im)...
Added in version 3.2.0.