An ultra fast cross-platform multiple screenshots module in pure python using ctypes.
npx @tessl/cli install tessl/pypi-mss@10.1.0An ultra-fast cross-platform multiple screenshots module in pure Python using ctypes. MSS enables capturing screenshots from one or all monitors and saving them as PNG files, with seamless integration with PIL, NumPy, and OpenCV for image processing and computer vision applications. The library is optimized for performance using native platform APIs like BitBlt (Windows), Core Graphics (macOS), and X11 (Linux).
pip install mssfrom mss import mss, ScreenShotErrorfrom mss import mss
# The simplest use: save a screenshot of the 1st monitor
with mss() as sct:
sct.shot()
# Take a screenshot of all monitors
with mss() as sct:
for filename in sct.save():
print(filename)
# Take a screenshot of a specific region
with mss() as sct:
# Custom region
region = {"top": 100, "left": 100, "width": 400, "height": 300}
screenshot = sct.grab(region)
# Access pixel data
rgb_data = screenshot.rgb
pixel_value = screenshot.pixel(50, 50) # Get RGB value at (50, 50)MSS uses a factory pattern to provide cross-platform screenshot functionality:
mss): Detects the current platform and returns the appropriate implementationThe design enables zero-dependency operation while providing thread-safe, high-performance screenshot capture across all major platforms.
Creates a platform-specific MSS instance for taking screenshots.
def mss(
*,
compression_level: int = 6,
with_cursor: bool = False,
display: bytes | str | None = None, # Linux only
max_displays: int = 32 # macOS only
) -> MSSBase:
"""
Factory returning a proper MSS class instance.
Parameters:
- compression_level: PNG compression level (0-9, default 6)
- with_cursor: Include mouse cursor in screenshots (default False)
- display: X11 display string (Linux only, default None)
- max_displays: Maximum number of displays to detect (macOS only, default 32)
Returns:
Platform-specific MSS instance (MSSBase subclass)
Raises:
ScreenShotError: If platform is not supported
"""Capture screenshots from monitors or custom regions.
def grab(self, monitor: Monitor | tuple[int, int, int, int]) -> ScreenShot:
"""
Retrieve screen pixels for a given monitor or region.
Parameters:
- monitor: Monitor dict with keys: left, top, width, height
OR tuple (left, top, right, bottom) in PIL.Image.grab() style
Returns:
ScreenShot object containing pixel data and metadata
"""
def shot(self, **kwargs) -> str:
"""
Helper to save screenshot of the 1st monitor.
Parameters:
- Same as save() method
Returns:
Filename of saved screenshot
"""Access available monitors and their properties.
@property
def monitors(self) -> Monitors:
"""
Get positions of all monitors.
Returns:
List of Monitor dicts where:
- monitors[0]: Combined area of all monitors
- monitors[1:]: Individual monitor areas
Each Monitor dict contains:
- left: x-coordinate of upper-left corner
- top: y-coordinate of upper-left corner
- width: monitor width in pixels
- height: monitor height in pixels
"""Save screenshots to PNG files with flexible naming and callback support.
def save(
self,
*,
mon: int = 0,
output: str = "monitor-{mon}.png",
callback: Callable[[str], None] | None = None
) -> Iterator[str]:
"""
Grab screenshot(s) and save to file(s).
Parameters:
- mon: Monitor selection
-1: All monitors as single image
0: One screenshot per monitor (default)
N: Screenshot of monitor N only
- output: Filename pattern supporting format placeholders:
{mon}: monitor number
{top}, {left}, {width}, {height}: region coordinates
{date}: current timestamp (supports strftime formatting)
- callback: Function called before saving each file
Returns:
Generator yielding created filenames
Raises:
ScreenShotError: If no monitors found or invalid monitor number
"""MSS instances support context manager protocol for automatic resource cleanup.
def __enter__(self) -> MSSBase:
"""Context manager entry - returns self"""
def __exit__(self, *_) -> None:
"""Context manager exit - calls close()"""
def close(self) -> None:
"""Clean up resources (platform-specific implementation)"""Container for screenshot data with multiple format accessors.
class ScreenShot:
"""
Screenshot object containing pixel data and metadata.
Attributes:
- raw: bytearray of raw BGRA pixels from native API
- pos: Pos namedtuple with left, top coordinates
- size: Size namedtuple with width, height dimensions
"""
def __init__(self, data: bytearray, monitor: Monitor, *, size: Size | None = None):
"""
Initialize screenshot object.
Parameters:
- data: Raw BGRA pixel data from platform API
- monitor: Monitor dict with position and size
- size: Override size (optional)
"""
@classmethod
def from_size(cls, data: bytearray, width: int, height: int) -> ScreenShot:
"""
Create screenshot from data and dimensions only.
Parameters:
- data: Raw BGRA pixel data
- width: Image width in pixels
- height: Image height in pixels
Returns:
ScreenShot instance with zero position
"""
def pixel(self, coord_x: int, coord_y: int) -> Pixel:
"""
Get RGB pixel value at coordinates.
Parameters:
- coord_x: X coordinate (0 to width-1)
- coord_y: Y coordinate (0 to height-1)
Returns:
RGB tuple (red, green, blue) with values 0-255
Raises:
ScreenShotError: If coordinates are out of bounds
"""
# Properties for accessing pixel data in different formats
@property
def left(self) -> int:
"""Left coordinate of screenshot region"""
@property
def top(self) -> int:
"""Top coordinate of screenshot region"""
@property
def width(self) -> int:
"""Width of screenshot in pixels"""
@property
def height(self) -> int:
"""Height of screenshot in pixels"""
@property
def bgra(self) -> bytes:
"""Raw BGRA pixel data as bytes"""
@property
def rgb(self) -> bytes:
"""RGB pixel data converted from BGRA"""
@property
def pixels(self) -> Pixels:
"""2D list of RGB tuples organized as [row][column]"""
@property
def __array_interface__(self) -> dict[str, Any]:
"""
NumPy array interface for direct array creation.
Returns BGRA data in shape (height, width, 4).
Usage:
import numpy as np
screenshot = sct.grab(monitor)
array = np.array(screenshot) # Uses this interface
"""Helper functions for image processing and format conversion (internal use only).
# Note: to_png is not exported from main mss module
# Import directly from mss.tools
from mss.tools import to_png
def to_png(
data: bytes,
size: tuple[int, int],
*,
level: int = 6,
output: Path | str | None = None
) -> bytes | None:
"""
Convert RGB data to PNG format.
Note: This function is not exported from the main mss module.
Import directly from mss.tools if needed.
Parameters:
- data: RGB pixel data (3 bytes per pixel)
- size: (width, height) tuple
- level: PNG compression level (0-9, default 6)
- output: Output file path, or None to return PNG bytes
Returns:
PNG bytes if output is None, otherwise None after writing file
"""Custom exception class for screenshot-related errors.
class ScreenShotError(Exception):
"""
Exception raised for screenshot-related errors.
Attributes:
- details: dict containing additional error context
"""
def __init__(self, message: str, /, *, details: dict[str, Any] | None = None):
"""
Initialize exception.
Parameters:
- message: Error description
- details: Additional error context (optional)
"""# Type aliases for API clarity
Monitor = dict[str, int] # Keys: left, top, width, height
Monitors = list[Monitor] # List of Monitor dicts
Pixel = tuple[int, int, int] # RGB values (0-255)
Pixels = list[tuple[Pixel, ...]] # 2D pixel array
CFunctions = dict[str, tuple[str, list[Any], Any]] # ctypes function definitions
# Named tuples for structured data
class Pos(NamedTuple):
left: int
top: int
class Size(NamedTuple):
width: int
height: int
# Base class (abstract)
class MSSBase(metaclass=ABCMeta):
"""Abstract base class for platform-specific implementations"""
compression_level: int
with_cursor: bool
cls_image: type[ScreenShot]
# Module constants
__version__: str = "10.1.0" # Package version
__author__: str = "Mickaël Schoentgen" # Package author
__date__: str = "2013-2025" # Copyright date range
__copyright__: str # Full copyright notice
__all__: tuple = ("ScreenShotError", "mss") # Public API exportsfrom mss import mss
from PIL import Image
with mss() as sct:
# Take screenshot and convert to PIL Image
screenshot = sct.grab(sct.monitors[1])
img = Image.frombytes("RGB", screenshot.size, screenshot.rgb)
# Save in different formats
img.save("screenshot.jpg", "JPEG")
img.save("screenshot.bmp", "BMP")from mss import mss
import numpy as np
with mss() as sct:
# Screenshot as NumPy array (uses __array_interface__)
screenshot = sct.grab(sct.monitors[1])
array = np.array(screenshot) # Shape: (height, width, 4) BGRA
# Convert to RGB array
rgb_array = array[:, :, [2, 1, 0]] # Reverse BGR to RGBfrom mss import mss
import numpy as np
import cv2
with mss() as sct:
screenshot = sct.grab(sct.monitors[1])
# Convert to OpenCV format (BGR)
img = np.array(screenshot)
img = cv2.cvtColor(img, cv2.COLOR_BGRA2BGR)
# Process with OpenCV
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imwrite("screenshot.png", img)MSS provides a command-line interface for quick screenshots:
# Basic usage - screenshot all monitors
mss
# Screenshot specific monitor
mss --monitor 1
# Custom region (top,left,width,height)
mss --coordinates "100,100,800,600"
# With cursor and custom compression
mss --with-cursor --level 9 --output "my_screenshot.png"
# Quiet mode (no output)
mss --quietCommon error scenarios and handling:
from mss import mss, ScreenShotError
try:
with mss() as sct:
# Monitor out of range
screenshot = sct.grab(sct.monitors[99])
except ScreenShotError as e:
print(f"Screenshot error: {e}")
print(f"Details: {e.details}")
try:
with mss() as sct:
screenshot = sct.grab(sct.monitors[1])
# Pixel coordinates out of bounds
pixel = screenshot.pixel(9999, 9999)
except ScreenShotError as e:
print(f"Pixel access error: {e}")with mss()) are recommended for resource management