def __init__(self, **_):
        # type: (Any) -> None
        """ Windows initialisations. """

        super().__init__()

        self.user32 = ctypes.WinDLL("user32")
        self.gdi32 = ctypes.WinDLL("gdi32")
        self._set_cfunctions()
        self._set_dpi_awareness()

        self._bbox = {"height": 0, "width": 0}
        self._data = ctypes.create_string_buffer(0)  # type: ctypes.Array[ctypes.c_char]

        srcdc = self._get_srcdc()
        if not MSS.memdc:
            MSS.memdc = self.gdi32.CreateCompatibleDC(srcdc)

        bmi = BITMAPINFO()
        bmi.bmiHeader.biSize = ctypes.sizeof(BITMAPINFOHEADER)
        bmi.bmiHeader.biPlanes = 1  # Always 1
        bmi.bmiHeader.biBitCount = 32  # See grab.__doc__ [2]
        bmi.bmiHeader.biCompression = 0  # 0 = BI_RGB (no compression)
        bmi.bmiHeader.biClrUsed = 0  # See grab.__doc__ [3]
        bmi.bmiHeader.biClrImportant = 0  # See grab.__doc__ [3]
        self._bmi = bmi

def
__init__
(
self
,
*
*
_
)
:
# type: (Any) -> None
super
(
)
.
__init__
(
)
self
.
user32
=
ctypes
.
WinDLL
(
"user32"
)
self
.
gdi32
=
ctypes
.
WinDLL
(
"gdi32"
)
self
.
_set_cfunctions
(
)
self
.
_set_dpi_awareness
(
)
self
.
_bbox
=
{
"height"
:
0
,
"width"
:
0
}
self
.
_data
=
ctypes
.
create_string_buffer
(
0
)
# type: ctypes.Array[ctypes.c_char]
srcdc
=
self
.
_get_srcdc
(
)
if
not
MSS
.
memdc
:
MSS
.
memdc
=
self
.
gdi32
.
CreateCompatibleDC
(
srcdc
)
bmi
=
BITMAPINFO
(
)
bmi
.
bmiHeader
.
biSize
=
ctypes
.
sizeof
(
BITMAPINFOHEADER
)
bmi
.
bmiHeader
.
biPlanes
=
1
# Always 1
bmi
.
bmiHeader
.
biBitCount
=
32
# See grab.__doc__ [2]
bmi
.
bmiHeader
.
biCompression
=
0
# 0 = BI_RGB (no compression)
bmi
.
bmiHeader
.
biClrUsed
=
0
# See grab.__doc__ [3]
bmi
.
bmiHeader
.
biClrImportant
=
0
# See grab.__doc__ [3]
self
.
_bmi
=
bmi


Set all ctypes functions and attach them to attributes .

def _set_cfunctions(self):
        """ Set all ctypes functions and attach them to attributes. """

        cfactory = self._cfactory
        attrs = {
            "gdi32": self.gdi32,
            "user32": self.user32,
        }
        for func, (attr, argtypes, restype) in CFUNCTIONS.items():
            cfactory(
                attr=attrs[attr],
                func=func,
                argtypes=argtypes,
                restype=restype,
            )

def _set_cfunctions ( self ) : cfactory = self . _cfactory attrs = { "gdi32" : self . gdi32 , "user32" : self . user32 , } for func , ( attr , argtypes , restype ) in CFUNCTIONS . items ( ) : cfactory ( attr = attrs [ attr ] , func = func , argtypes = argtypes , restype = restype , )


Set DPI awareness to capture full screen on Hi - DPI monitors .

def _set_dpi_awareness(self):
        """ Set DPI awareness to capture full screen on Hi-DPI monitors. """

        version = sys.getwindowsversion()[:2]  # pylint: disable=no-member
        if version >= (6, 3):
            # Windows 8.1+
            # Here 2 = PROCESS_PER_MONITOR_DPI_AWARE, which means:
            #     per monitor DPI aware. This app checks for the DPI when it is
            #     created and adjusts the scale factor whenever the DPI changes.
            #     These applications are not automatically scaled by the system.
            ctypes.windll.shcore.SetProcessDpiAwareness(2)
        elif (6, 0) <= version < (6, 3):
            # Windows Vista, 7, 8 and Server 2012
            self.user32.SetProcessDPIAware()


Retrieve a thread - safe HDC from GetWindowDC () . In multithreading if the thread that creates * srcdc * is dead * srcdc * will no longer be valid to grab the screen . The * srcdc * attribute is replaced with * _srcdc_dict * to maintain the * srcdc * values in multithreading . Since the current thread and main thread are always alive reuse their * srcdc * value first .

def _get_srcdc(self):
        """
        Retrieve a thread-safe HDC from GetWindowDC().
        In multithreading, if the thread that creates *srcdc* is dead, *srcdc* will
        no longer be valid to grab the screen. The *srcdc* attribute is replaced
        with *_srcdc_dict* to maintain the *srcdc* values in multithreading.
        Since the current thread and main thread are always alive, reuse their *srcdc* value first.
        """
        cur_thread, main_thread = threading.current_thread(), threading.main_thread()
        srcdc = MSS._srcdc_dict.get(cur_thread) or MSS._srcdc_dict.get(main_thread)
        if not srcdc:
            srcdc = MSS._srcdc_dict[cur_thread] = self.user32.GetWindowDC(0)
        return srcdc

def _get_srcdc ( self ) : cur_thread , main_thread = threading . current_thread ( ) , threading . main_thread ( ) srcdc = MSS . _srcdc_dict . get ( cur_thread ) or MSS . _srcdc_dict . get ( main_thread ) if not srcdc : srcdc = MSS . _srcdc_dict [ cur_thread ] = self . user32 . GetWindowDC ( 0 ) return srcdc


Get positions of monitors . It will populate self . _monitors .

def _monitors_impl(self):
        # type: () -> None
        """ Get positions of monitors. It will populate self._monitors. """

        int_ = int
        user32 = self.user32
        get_system_metrics = user32.GetSystemMetrics

        # All monitors
        self._monitors.append(
            {
                "left": int_(get_system_metrics(76)),  # SM_XVIRTUALSCREEN
                "top": int_(get_system_metrics(77)),  # SM_YVIRTUALSCREEN
                "width": int_(get_system_metrics(78)),  # SM_CXVIRTUALSCREEN
                "height": int_(get_system_metrics(79)),  # SM_CYVIRTUALSCREEN
            }
        )

        # Each monitor
        def _callback(monitor, data, rect, dc_):
            # types: (int, HDC, LPRECT, LPARAM) -> int
            """
            Callback for monitorenumproc() function, it will return
            a RECT with appropriate values.
            """
            # pylint: disable=unused-argument

            rct = rect.contents
            self._monitors.append(
                {
                    "left": int_(rct.left),
                    "top": int_(rct.top),
                    "width": int_(rct.right - rct.left),
                    "height": int_(rct.bottom - rct.top),
                }
            )
            return 1

        callback = MONITORNUMPROC(_callback)
        user32.EnumDisplayMonitors(0, 0, callback, 0)


Retrieve all pixels from a monitor . Pixels have to be RGB .

def _grab_impl(self, monitor):
        # type: (Monitor) -> ScreenShot
        """
        Retrieve all pixels from a monitor. Pixels have to be RGB.

        In the code, there are a few interesting things:

        [1] bmi.bmiHeader.biHeight = -height

        A bottom-up DIB is specified by setting the height to a
        positive number, while a top-down DIB is specified by
        setting the height to a negative number.
        https://msdn.microsoft.com/en-us/library/ms787796.aspx
        https://msdn.microsoft.com/en-us/library/dd144879%28v=vs.85%29.aspx

        [2] bmi.bmiHeader.biBitCount = 32
            image_data = create_string_buffer(height * width * 4)

        We grab the image in RGBX mode, so that each word is 32bit
        and we have no striding.
        Inspired by https://github.com/zoofIO/flexx

        [3] bmi.bmiHeader.biClrUsed = 0
            bmi.bmiHeader.biClrImportant = 0

        When biClrUsed and biClrImportant are set to zero, there
        is "no" color table, so we can read the pixels of the bitmap
        retrieved by gdi32.GetDIBits() as a sequence of RGB values.
        Thanks to http://stackoverflow.com/a/3688682
        """

        srcdc, memdc = self._get_srcdc(), MSS.memdc
        width, height = monitor["width"], monitor["height"]

        if (self._bbox["height"], self._bbox["width"]) != (height, width):
            self._bbox = monitor
            self._bmi.bmiHeader.biWidth = width
            self._bmi.bmiHeader.biHeight = -height  # Why minus? [1]
            self._data = ctypes.create_string_buffer(width * height * 4)  # [2]
            if MSS.bmp:
                self.gdi32.DeleteObject(MSS.bmp)
            MSS.bmp = self.gdi32.CreateCompatibleBitmap(srcdc, width, height)
            self.gdi32.SelectObject(memdc, MSS.bmp)

        self.gdi32.BitBlt(
            memdc,
            0,
            0,
            width,
            height,
            srcdc,
            monitor["left"],
            monitor["top"],
            SRCCOPY | CAPTUREBLT,
        )
        bits = self.gdi32.GetDIBits(
            memdc, MSS.bmp, 0, height, self._data, self._bmi, DIB_RGB_COLORS
        )
        if bits != height:
            raise ScreenShotError("gdi32.GetDIBits() failed.")

        return self.cls_image(bytearray(self._data), monitor)

def
_grab_impl
(
self
,
monitor
)
:
# type: (Monitor) -> ScreenShot
srcdc
,
memdc
=
self
.
_get_srcdc
(
)
,
MSS
.
memdc
width
,
height
=
monitor
[
"width"
]
,
monitor
[
"height"
]
if
(
self
.
_bbox
[
"height"
]
,
self
.
_bbox
[
"width"
]
)
!=
(
height
,
width
)
:
self
.
_bbox
=
monitor
self
.
_bmi
.
bmiHeader
.
biWidth
=
width
self
.
_bmi
.
bmiHeader
.
biHeight
=
height
# Why minus? [1]
self
.
_data
=
ctypes
.
create_string_buffer
(
width
*
height
*
4
)
# [2]
if
MSS
.
bmp
:
self
.
gdi32
.
DeleteObject
(
MSS
.
bmp
)
MSS
.
bmp
=
self
.
gdi32
.
CreateCompatibleBitmap
(
srcdc
,
width
,
height
)
self
.
gdi32
.
SelectObject
(
memdc
,
MSS
.
bmp
)
self
.
gdi32
.
BitBlt
(
memdc
,
0
,
0
,
width
,
height
,
srcdc
,
monitor
[
"left"
]
,
monitor
[
"top"
]
,
SRCCOPY
|
CAPTUREBLT
,
)
bits
=
self
.
gdi32
.
GetDIBits
(
memdc
,
MSS
.
bmp
,
0
,
height
,
self
.
_data
,
self
.
_bmi
,
DIB_RGB_COLORS
)
if
bits
!=
height
:
raise
ScreenShotError
(
"gdi32.GetDIBits() failed."
)
return
self
.
cls_image
(
bytearray
(
self
.
_data
)
,
monitor
)


Numpy array interface support . It uses raw data in BGRA form .

def __array_interface__(self):
        # type: () -> Dict[str, Any]
        """
        Numpy array interface support.
        It uses raw data in BGRA form.

        See https://docs.scipy.org/doc/numpy/reference/arrays.interface.html
        """

        return {
            "version": 3,
            "shape": (self.height, self.width, 4),
            "typestr": "|u1",
            "data": self.raw,
        }

def
__array_interface__
(
self
)
:
# type: () -> Dict[str, Any]
return
{
"version"
:
3
,
"shape"
:
(
self
.
height
,
self
.
width
,
4
)
,
"typestr"
:
"|u1"
,
"data"
:
self
.
raw
,
}


Instantiate a new class given only screen shot s data and size .

def from_size(cls, data, width, height):
        # type: (bytearray, int, int) -> ScreenShot
        """ Instantiate a new class given only screen shot's data and size. """

        monitor = {"left": 0, "top": 0, "width": width, "height": height}
        return cls(data, monitor)


def bgra(self):
        # type: () -> bytes
        """ BGRA values from the BGRA raw pixels. """
        return bytes(self.raw)

def
bgra
(
self
)
:
# type: () -> bytes
return
bytes
(
self
.
raw
)


Convenient accessor to the height size .

def height(self):
        # type: () -> int
        """ Convenient accessor to the height size. """
        return self.size.height

def
height
(
self
)
:
# type: () -> int
return
self
.
size
.
height


Convenient accessor to the left position .

def left(self):
        # type: () -> int
        """ Convenient accessor to the left position. """
        return self.pos.left

def
left
(
self
)
:
# type: () -> int
return
self
.
pos
.
left


def pixels(self):
        # type: () -> Pixels
        """
        :return list: RGB tuples.
        """

        if not self.__pixels:
            rgb_tuples = zip(
                self.raw[2::4], self.raw[1::4], self.raw[0::4]
            )  # type: Iterator[Pixel]
            self.__pixels = list(zip(*[iter(rgb_tuples)] * self.width))  # type: ignore

        return self.__pixels

def
pixels
(
self
)
:
# type: () -> Pixels
if
not
self
.
__pixels
:
rgb_tuples
=
zip
(
self
.
raw
[
2
:
:
4
]
,
self
.
raw
[
1
:
:
4
]
,
self
.
raw
[
0
:
:
4
]
)
# type: Iterator[Pixel]
self
.
__pixels
=
list
(
zip
(
*
[
iter
(
rgb_tuples
)
]
*
self
.
width
)
)
# type: ignore
return
self
.
__pixels


Compute RGB values from the BGRA raw pixels .

def rgb(self):
        # type: () -> bytes
        """
        Compute RGB values from the BGRA raw pixels.

        :return bytes: RGB pixels.
        """

        if not self.__rgb:
            rgb = bytearray(self.height * self.width * 3)
            raw = self.raw
            rgb[0::3] = raw[2::4]
            rgb[1::3] = raw[1::4]
            rgb[2::3] = raw[0::4]
            self.__rgb = bytes(rgb)

        return self.__rgb

def
rgb
(
self
)
:
# type: () -> bytes
if
not
self
.
__rgb
:
rgb
=
bytearray
(
self
.
height
*
self
.
width
*
3
)
raw
=
self
.
raw
rgb
[
0
:
:
3
]
=
raw
[
2
:
:
4
]
rgb
[
1
:
:
3
]
=
raw
[
1
:
:
4
]
rgb
[
2
:
:
3
]
=
raw
[
0
:
:
4
]
self
.
__rgb
=
bytes
(
rgb
)
return
self
.
__rgb


Convenient accessor to the top position .

def top(self):
        # type: () -> int
        """ Convenient accessor to the top position. """
        return self.pos.top

def
top
(
self
)
:
# type: () -> int
return
self
.
pos
.
top


def width(self):
        # type: () -> int
        """ Convenient accessor to the width size. """
        return self.size.width

def
width
(
self
)
:
# type: () -> int
return
self
.
size
.
width


Returns the pixel value at a given position .

def pixel(self, coord_x, coord_y):
        # type: (int, int) -> Pixel
        """
        Returns the pixel value at a given position.

        :param int coord_x: The x coordinate.
        :param int coord_y: The y coordinate.
        :return tuple: The pixel value as (R, G, B).
        """

        try:
            return self.pixels[coord_y][coord_x]  # type: ignore
        except IndexError:
            # pylint: disable=raise-missing-from
            raise ScreenShotError(
                "Pixel location ({}, {}) is out of range.".format(coord_x, coord_y)
            )


Factory returning a proper MSS class instance .

def mss(**kwargs):
    # type: (Any) -> MSSBase
    """ Factory returning a proper MSS class instance.

        It detects the platform we are running on
        and chooses the most adapted mss_class to take
        screenshots.

        It then proxies its arguments to the class for
        instantiation.
    """
    # pylint: disable=import-outside-toplevel

    os_ = platform.system().lower()

    if os_ == "darwin":
        from . import darwin

        return darwin.MSS(**kwargs)

    if os_ == "linux":
        from . import linux

        return linux.MSS(**kwargs)

    if os_ == "windows":
        from . import windows

        return windows.MSS(**kwargs)

    raise ScreenShotError("System {!r} not (yet?) implemented.".format(os_))


For the cool call with MSS () as mss : .

def __enter__(self):
        # type: () -> MSSBase
        """ For the cool call `with MSS() as mss:`. """

        return self

def
__enter__
(
self
)
:
# type: () -> MSSBase
return
self


def __exit__(self, *_):
        """ For the cool call `with MSS() as mss:`. """

        self.close()

def __exit__ ( self , * _ ) : self . close ( )


Retrieve all pixels from a monitor . Pixels have to be RGB . That method has to be run using a threading lock .

def _grab_impl(self, monitor):
        # type: (Monitor) -> ScreenShot
        """
        Retrieve all pixels from a monitor. Pixels have to be RGB.
        That method has to be run using a threading lock.
        """

def
_grab_impl
(
self
,
monitor
)
:
# type: (Monitor) -> ScreenShot


Get positions of monitors ( has to be run using a threading lock ) . It must populate self . _monitors .

def _monitors_impl(self):
        # type: () -> None
        """
        Get positions of monitors (has to be run using a threading lock).
        It must populate self._monitors.
        """

def
_monitors_impl
(
self
)
:
# type: () -> None


def close(self):
        # type: () -> None
        """ Clean-up. """


Retrieve screen pixels for a given monitor .

def grab(self, monitor):
        # type: (Monitor) -> ScreenShot
        """
        Retrieve screen pixels for a given monitor.

        Note: *monitor* can be a tuple like the one PIL.Image.grab() accepts.

        :param monitor: The coordinates and size of the box to capture.
                        See :meth:`monitors <monitors>` for object details.
        :return :class:`ScreenShot <ScreenShot>`.
        """

        # Convert PIL bbox style
        if isinstance(monitor, tuple):
            monitor = {
                "left": monitor[0],
                "top": monitor[1],
                "width": monitor[2] - monitor[0],
                "height": monitor[3] - monitor[1],
            }

        with lock:
            return self._grab_impl(monitor)

def
grab
(
self
,
monitor
)
:
# type: (Monitor) -> ScreenShot
# Convert PIL bbox style
if
isinstance
(
monitor
,
tuple
)
:
monitor
=
{
"left"
:
monitor
[
0
]
,
"top"
:
monitor
[
1
]
,
"width"
:
monitor
[
2
]
monitor
[
0
]
,
"height"
:
monitor
[
3
]
monitor
[
1
]
,
}
with
lock
:
return
self
.
_grab_impl
(
monitor
)


Get positions of all monitors . If the monitor has rotation you have to deal with it inside this method .

def monitors(self):
        # type: () -> Monitors
        """
        Get positions of all monitors.
        If the monitor has rotation, you have to deal with it
        inside this method.

        This method has to fill self._monitors with all information
        and use it as a cache:
            self._monitors[0] is a dict of all monitors together
            self._monitors[N] is a dict of the monitor N (with N > 0)

        Each monitor is a dict with:
        {
            'left':   the x-coordinate of the upper-left corner,
            'top':    the y-coordinate of the upper-left corner,
            'width':  the width,
            'height': the height
        }
        """

        if not self._monitors:
            with lock:
                self._monitors_impl()

        return self._monitors

def
monitors
(
self
)
:
# type: () -> Monitors
if
not
self
.
_monitors
:
with
lock
:
self
.
_monitors_impl
(
)
return
self
.
_monitors


Grab a screen shot and save it to a file .

def save(self, mon=0, output="monitor-{mon}.png", callback=None):
        # type: (int, str, Callable[[str], None]) -> Iterator[str]
        """
        Grab a screen shot and save it to a file.

        :param int mon: The monitor to screen shot (default=0).
                        -1: grab one screen shot of all monitors
                         0: grab one screen shot by monitor
                        N: grab the screen shot of the monitor N

        :param str output: The output filename.

            It can take several keywords to customize the filename:
            - `{mon}`: the monitor number
            - `{top}`: the screen shot y-coordinate of the upper-left corner
            - `{left}`: the screen shot x-coordinate of the upper-left corner
            - `{width}`: the screen shot's width
            - `{height}`: the screen shot's height
            - `{date}`: the current date using the default formatter

            As it is using the `format()` function, you can specify
            formatting options like `{date:%Y-%m-%s}`.

        :param callable callback: Callback called before saving the
            screen shot to a file.  Take the `output` argument as parameter.

        :return generator: Created file(s).
        """

        monitors = self.monitors
        if not monitors:
            raise ScreenShotError("No monitor found.")

        if mon == 0:
            # One screen shot by monitor
            for idx, monitor in enumerate(monitors[1:], 1):
                fname = output.format(mon=idx, date=datetime.now(), **monitor)
                if callable(callback):
                    callback(fname)
                sct = self.grab(monitor)
                to_png(sct.rgb, sct.size, level=self.compression_level, output=fname)
                yield fname
        else:
            # A screen shot of all monitors together or
            # a screen shot of the monitor N.
            mon = 0 if mon == -1 else mon
            try:
                monitor = monitors[mon]
            except IndexError:
                # pylint: disable=raise-missing-from
                raise ScreenShotError("Monitor {!r} does not exist.".format(mon))

            output = output.format(mon=mon, date=datetime.now(), **monitor)
            if callable(callback):
                callback(output)
            sct = self.grab(monitor)
            to_png(sct.rgb, sct.size, level=self.compression_level, output=output)
            yield output


Helper to save the screen shot of the 1st monitor by default . You can pass the same arguments as for save .

def shot(self, **kwargs):
        # type: (Any) -> str
        """
        Helper to save the screen shot of the 1st monitor, by default.
        You can pass the same arguments as for ``save``.
        """

        kwargs["mon"] = kwargs.get("mon", 1)
        return next(self.save(**kwargs))

def
shot
(
self
,
*
*
kwargs
)
:
# type: (Any) -> str
kwargs
[
"mon"
]
=
kwargs
.
get
(
"mon"
,
1
)
return
next
(
self
.
save
(
*
*
kwargs
)
)


Factory to create a ctypes function and automatically manage errors .

def _cfactory(attr, func, argtypes, restype, errcheck=None):
        # type: (Any, str, List[Any], Any, Optional[Callable]) -> None
        """ Factory to create a ctypes function and automatically manage errors. """

        meth = getattr(attr, func)
        meth.argtypes = argtypes
        meth.restype = restype
        if errcheck:
            meth.errcheck = errcheck


def cgfloat():
    # type: () -> Union[Type[c_double], Type[c_float]]
    """ Get the appropriate value for a float. """

    return c_double if sys.maxsize > 2 ** 32 else c_float


def __init__(self, **_):
        """ macOS initialisations. """

        super().__init__()

        self.max_displays = 32

        self._init_library()
        self._set_cfunctions()

def __init__ ( self , * * _ ) : super ( ) . __init__ ( ) self . max_displays = 32 self . _init_library ( ) self . _set_cfunctions ( )


def _init_library(self):
        """ Load the CoreGraphics library. """
        version = float(".".join(mac_ver()[0].split(".")[:2]))
        if version < 10.16:
            coregraphics = ctypes.util.find_library("CoreGraphics")
        else:
            # macOS Big Sur and newer
            # pylint: disable=line-too-long
            coregraphics = "/System/Library/Frameworks/CoreGraphics.framework/Versions/Current/CoreGraphics"

        if not coregraphics:
            raise ScreenShotError("No CoreGraphics library found.")
        self.core = ctypes.cdll.LoadLibrary(coregraphics)


Set all ctypes functions and attach them to attributes .

def _set_cfunctions(self):
        # type: () -> None
        """ Set all ctypes functions and attach them to attributes. """

        cfactory = self._cfactory
        attrs = {"core": self.core}
        for func, (attr, argtypes, restype) in CFUNCTIONS.items():
            cfactory(
                attr=attrs[attr],
                func=func,
                argtypes=argtypes,  # type: ignore
                restype=restype,
            )

def
_set_cfunctions
(
self
)
:
# type: () -> None
cfactory
=
self
.
_cfactory
attrs
=
{
"core"
:
self
.
core
}
for
func
,
(
attr
,
argtypes
,
restype
)
in
CFUNCTIONS
.
items
(
)
:
cfactory
(
attr
=
attrs
[
attr
]
,
func
=
func
,
argtypes
=
argtypes
,
# type: ignore
restype
=
restype
,
)


Get positions of monitors . It will populate self . _monitors .

def _monitors_impl(self):
        # type: () -> None
        """ Get positions of monitors. It will populate self._monitors. """

        int_ = int
        core = self.core

        # All monitors
        # We need to update the value with every single monitor found
        # using CGRectUnion.  Else we will end with infinite values.
        all_monitors = CGRect()
        self._monitors.append({})

        # Each monitor
        display_count = c_uint32(0)
        active_displays = (c_uint32 * self.max_displays)()
        core.CGGetActiveDisplayList(
            self.max_displays, active_displays, ctypes.byref(display_count)
        )
        rotations = {0.0: "normal", 90.0: "right", -90.0: "left"}
        for idx in range(display_count.value):
            display = active_displays[idx]
            rect = core.CGDisplayBounds(display)
            rect = core.CGRectStandardize(rect)
            width, height = rect.size.width, rect.size.height
            rot = core.CGDisplayRotation(display)
            if rotations[rot] in ["left", "right"]:
                width, height = height, width
            self._monitors.append(
                {
                    "left": int_(rect.origin.x),
                    "top": int_(rect.origin.y),
                    "width": int_(width),
                    "height": int_(height),
                }
            )

            # Update AiO monitor's values
            all_monitors = core.CGRectUnion(all_monitors, rect)

        # Set the AiO monitor's values
        self._monitors[0] = {
            "left": int_(all_monitors.origin.x),
            "top": int_(all_monitors.origin.y),
            "width": int_(all_monitors.size.width),
            "height": int_(all_monitors.size.height),
        }


Retrieve all pixels from a monitor . Pixels have to be RGB .

def _grab_impl(self, monitor):
        # type: (Monitor) -> ScreenShot
        """ Retrieve all pixels from a monitor. Pixels have to be RGB. """

        # pylint: disable=too-many-locals

        core = self.core
        rect = CGRect(
            (monitor["left"], monitor["top"]), (monitor["width"], monitor["height"])
        )

        image_ref = core.CGWindowListCreateImage(rect, 1, 0, 0)
        if not image_ref:
            raise ScreenShotError("CoreGraphics.CGWindowListCreateImage() failed.")

        width = core.CGImageGetWidth(image_ref)
        height = core.CGImageGetHeight(image_ref)
        prov = copy_data = None
        try:
            prov = core.CGImageGetDataProvider(image_ref)
            copy_data = core.CGDataProviderCopyData(prov)
            data_ref = core.CFDataGetBytePtr(copy_data)
            buf_len = core.CFDataGetLength(copy_data)
            raw = ctypes.cast(data_ref, POINTER(c_ubyte * buf_len))
            data = bytearray(raw.contents)

            # Remove padding per row
            bytes_per_row = core.CGImageGetBytesPerRow(image_ref)
            bytes_per_pixel = core.CGImageGetBitsPerPixel(image_ref)
            bytes_per_pixel = (bytes_per_pixel + 7) // 8

            if bytes_per_pixel * width != bytes_per_row:
                cropped = bytearray()
                for row in range(height):
                    start = row * bytes_per_row
                    end = start + width * bytes_per_pixel
                    cropped.extend(data[start:end])
                data = cropped
        finally:
            if prov:
                core.CGDataProviderRelease(prov)
            if copy_data:
                core.CFRelease(copy_data)

        return self.cls_image(data, monitor, size=Size(width, height))


def main(args=None):
    # type: (Optional[List[str]]) -> int
    """ Main logic. """

    cli_args = ArgumentParser()
    cli_args.add_argument(
        "-c",
        "--coordinates",
        default="",
        type=str,
        help="the part of the screen to capture: top, left, width, height",
    )
    cli_args.add_argument(
        "-l",
        "--level",
        default=6,
        type=int,
        choices=list(range(10)),
        help="the PNG compression level",
    )
    cli_args.add_argument(
        "-m", "--monitor", default=0, type=int, help="the monitor to screen shot"
    )
    cli_args.add_argument(
        "-o", "--output", default="monitor-{mon}.png", help="the output file name"
    )
    cli_args.add_argument(
        "-q",
        "--quiet",
        default=False,
        action="store_true",
        help="do not print created files",
    )
    cli_args.add_argument("-v", "--version", action="version", version=__version__)

    options = cli_args.parse_args(args)
    kwargs = {"mon": options.monitor, "output": options.output}
    if options.coordinates:
        try:
            top, left, width, height = options.coordinates.split(",")
        except ValueError:
            print("Coordinates syntax: top, left, width, height")
            return 2

        kwargs["mon"] = {
            "top": int(top),
            "left": int(left),
            "width": int(width),
            "height": int(height),
        }
        if options.output == "monitor-{mon}.png":
            kwargs["output"] = "sct-{top}x{left}_{width}x{height}.png"

    try:
        with mss() as sct:
            if options.coordinates:
                output = kwargs["output"].format(**kwargs["mon"])
                sct_img = sct.grab(kwargs["mon"])
                to_png(sct_img.rgb, sct_img.size, level=options.level, output=output)
                if not options.quiet:
                    print(os.path.realpath(output))
            else:
                for file_name in sct.save(**kwargs):
                    if not options.quiet:
                        print(os.path.realpath(file_name))
            return 0
    except ScreenShotError:
        return 1


Specifies the program s supplied error handler .

def error_handler(_, event):
    # type: (Any, Any) -> int
    """ Specifies the program's supplied error handler. """

    evt = event.contents
    ERROR.details = {
        "type": evt.type,
        "serial": evt.serial,
        "error_code": evt.error_code,
        "request_code": evt.request_code,
        "minor_code": evt.minor_code,
    }
    return 0

def
error_handler
(
_
,
event
)
:
# type: (Any, Any) -> int
evt
=
event
.
contents
ERROR
.
details
=
{
"type"
:
evt
.
type
,
"serial"
:
evt
.
serial
,
"error_code"
:
evt
.
error_code
,
"request_code"
:
evt
.
request_code
,
"minor_code"
:
evt
.
minor_code
,
}
return
0


Validate the returned value of a Xlib or XRANDR function .

def validate(retval, func, args):
    # type: (int, Any, Tuple[Any, Any]) -> Optional[Tuple[Any, Any]]
    """ Validate the returned value of a Xlib or XRANDR function. """

    if retval != 0 and not ERROR.details:
        return args

    err = "{}() failed".format(func.__name__)
    details = {"retval": retval, "args": args}
    raise ScreenShotError(err, details=details)


def __init__(self, display=None):
        # type: (Optional[Union[bytes, str]]) -> None
        """ GNU/Linux initialisations. """

        super().__init__()

        if not display:
            try:
                display = os.environ["DISPLAY"].encode("utf-8")
            except KeyError:
                # pylint: disable=raise-missing-from
                raise ScreenShotError("$DISPLAY not set.")

        if not isinstance(display, bytes):
            display = display.encode("utf-8")

        if b":" not in display:
            raise ScreenShotError("Bad display value: {!r}.".format(display))

        x11 = ctypes.util.find_library("X11")
        if not x11:
            raise ScreenShotError("No X11 library found.")
        self.xlib = ctypes.cdll.LoadLibrary(x11)

        # Install the error handler to prevent interpreter crashes:
        # any error will raise a ScreenShotError exception.
        self.xlib.XSetErrorHandler(error_handler)

        xrandr = ctypes.util.find_library("Xrandr")
        if not xrandr:
            raise ScreenShotError("No Xrandr extension found.")
        self.xrandr = ctypes.cdll.LoadLibrary(xrandr)

        self._set_cfunctions()

        self.root = self.xlib.XDefaultRootWindow(self._get_display(display))

        if not self.has_extension("RANDR"):
            raise ScreenShotError("No Xrandr extension found.")

        # Fix for XRRGetScreenResources and XGetImage:
        #     expected LP_Display instance instead of LP_XWindowAttributes
        self.drawable = ctypes.cast(self.root, POINTER(Display))


Return True if the given * extension * is part of the extensions list of the server .

def has_extension(self, extension):
        # type: (str) -> bool
        """Return True if the given *extension* is part of the extensions list of the server."""
        with lock:
            major_opcode_return = c_int()
            first_event_return = c_int()
            first_error_return = c_int()

            try:
                self.xlib.XQueryExtension(
                    self._get_display(),
                    extension.encode("latin1"),
                    ctypes.byref(major_opcode_return),
                    ctypes.byref(first_event_return),
                    ctypes.byref(first_error_return),
                )
            except ScreenShotError:
                return False
            else:
                return True

def
has_extension
(
self
,
extension
)
:
# type: (str) -> bool
with
lock
:
major_opcode_return
=
c_int
(
)
first_event_return
=
c_int
(
)
first_error_return
=
c_int
(
)
try
:
self
.
xlib
.
XQueryExtension
(
self
.
_get_display
(
)
,
extension
.
encode
(
"latin1"
)
,
ctypes
.
byref
(
major_opcode_return
)
,
ctypes
.
byref
(
first_event_return
)
,
ctypes
.
byref
(
first_error_return
)
,
)
except
ScreenShotError
:
return
False
else
:
return
True


Retrieve a thread - safe display from XOpenDisplay () . In multithreading if the thread that creates * display * is dead * display * will no longer be valid to grab the screen . The * display * attribute is replaced with * _display_dict * to maintain the * display * values in multithreading . Since the current thread and main thread are always alive reuse their * display * value first .

def _get_display(self, disp=None):
        """
        Retrieve a thread-safe display from XOpenDisplay().
        In multithreading, if the thread that creates *display* is dead, *display* will
        no longer be valid to grab the screen. The *display* attribute is replaced
        with *_display_dict* to maintain the *display* values in multithreading.
        Since the current thread and main thread are always alive, reuse their
        *display* value first.
        """
        cur_thread, main_thread = threading.current_thread(), threading.main_thread()
        display = MSS._display_dict.get(cur_thread) or MSS._display_dict.get(
            main_thread
        )
        if not display:
            display = MSS._display_dict[cur_thread] = self.xlib.XOpenDisplay(disp)
        return display

def _get_display ( self , disp = None ) : cur_thread , main_thread = threading . current_thread ( ) , threading . main_thread ( ) display = MSS . _display_dict . get ( cur_thread ) or MSS . _display_dict . get ( main_thread ) if not display : display = MSS . _display_dict [ cur_thread ] = self . xlib . XOpenDisplay ( disp ) return display


def _set_cfunctions(self):
        """ Set all ctypes functions and attach them to attributes. """

        cfactory = self._cfactory
        attrs = {
            "xlib": self.xlib,
            "xrandr": self.xrandr,
        }
        for func, (attr, argtypes, restype) in CFUNCTIONS.items():
            try:
                cfactory(
                    attr=attrs[attr],
                    errcheck=validate,
                    func=func,
                    argtypes=argtypes,
                    restype=restype,
                )  # type: ignore
            except AttributeError:
                pass

def
_set_cfunctions
(
self
)
:
cfactory
=
self
.
_cfactory
attrs
=
{
"xlib"
:
self
.
xlib
,
"xrandr"
:
self
.
xrandr
,
}
for
func
,
(
attr
,
argtypes
,
restype
)
in
CFUNCTIONS
.
items
(
)
:
try
:
cfactory
(
attr
=
attrs
[
attr
]
,
errcheck
=
validate
,
func
=
func
,
argtypes
=
argtypes
,
restype
=
restype
,
)
# type: ignore
except
AttributeError
:
pass


Get more information about the latest X server error .

def get_error_details(self):
        # type: () -> Optional[Dict[str, Any]]
        """ Get more information about the latest X server error. """

        details = {}  # type: Dict[str, Any]

        if ERROR.details:
            details = {"xerror_details": ERROR.details}
            ERROR.details = None
            xserver_error = ctypes.create_string_buffer(1024)
            self.xlib.XGetErrorText(
                self._get_display(),
                details.get("xerror_details", {}).get("error_code", 0),
                xserver_error,
                len(xserver_error),
            )
            xerror = xserver_error.value.decode("utf-8")
            if xerror != "0":
                details["xerror"] = xerror

        return details

def
get_error_details
(
self
)
:
# type: () -> Optional[Dict[str, Any]]
details
=
{
}
# type: Dict[str, Any]
if
ERROR
.
details
:
details
=
{
"xerror_details"
:
ERROR
.
details
}
ERROR
.
details
=
xserver_error
=
ctypes
.
create_string_buffer
(
1024
)
self
.
xlib
.
XGetErrorText
(
self
.
_get_display
(
)
,
details
.
get
(
"xerror_details"
,
{
}
)
.
get
(
"error_code"
,
0
)
,
xserver_error
,
len
(
xserver_error
)
,
)
xerror
=
xserver_error
.
value
.
decode
(
"utf-8"
)
if
xerror
!=
"0"
:
details
[
"xerror"
]
=
xerror
return
details


def _monitors_impl(self):
        # type: () -> None
        """ Get positions of monitors. It will populate self._monitors. """

        display = self._get_display()
        int_ = int
        xrandr = self.xrandr

        # All monitors
        gwa = XWindowAttributes()
        self.xlib.XGetWindowAttributes(display, self.root, ctypes.byref(gwa))
        self._monitors.append(
            {
                "left": int_(gwa.x),
                "top": int_(gwa.y),
                "width": int_(gwa.width),
                "height": int_(gwa.height),
            }
        )

        # Each monitor
        # A simple benchmark calling 10 times those 2 functions:
        # XRRGetScreenResources():        0.1755971429956844 s
        # XRRGetScreenResourcesCurrent(): 0.0039125580078689 s
        # The second is faster by a factor of 44! So try to use it first.
        try:
            mon = xrandr.XRRGetScreenResourcesCurrent(display, self.drawable).contents
        except AttributeError:
            mon = xrandr.XRRGetScreenResources(display, self.drawable).contents

        crtcs = mon.crtcs
        for idx in range(mon.ncrtc):
            crtc = xrandr.XRRGetCrtcInfo(display, mon, crtcs[idx]).contents
            if crtc.noutput == 0:
                xrandr.XRRFreeCrtcInfo(crtc)
                continue

            self._monitors.append(
                {
                    "left": int_(crtc.x),
                    "top": int_(crtc.y),
                    "width": int_(crtc.width),
                    "height": int_(crtc.height),
                }
            )
            xrandr.XRRFreeCrtcInfo(crtc)
        xrandr.XRRFreeScreenResources(mon)


def _grab_impl(self, monitor):
        # type: (Monitor) -> ScreenShot
        """ Retrieve all pixels from a monitor. Pixels have to be RGB. """

        ximage = self.xlib.XGetImage(
            self._get_display(),
            self.drawable,
            monitor["left"],
            monitor["top"],
            monitor["width"],
            monitor["height"],
            PLAINMASK,
            ZPIXMAP,
        )

        try:
            bits_per_pixel = ximage.contents.bits_per_pixel
            if bits_per_pixel != 32:
                raise ScreenShotError(
                    "[XImage] bits per pixel value not (yet?) implemented: {}.".format(
                        bits_per_pixel
                    )
                )

            raw_data = ctypes.cast(
                ximage.contents.data,
                POINTER(c_ubyte * monitor["height"] * monitor["width"] * 4),
            )
            data = bytearray(raw_data.contents)
        finally:
            # Free
            self.xlib.XDestroyImage(ximage)

        return self.cls_image(data, monitor)


Dump data to a PNG file . If output is None create no file but return the whole PNG data .

def to_png(data, size, level=6, output=None):
    # type: (bytes, Tuple[int, int], int, Optional[str]) -> Optional[bytes]
    """
    Dump data to a PNG file.  If `output` is `None`, create no file but return
    the whole PNG data.

    :param bytes data: RGBRGB...RGB data.
    :param tuple size: The (width, height) pair.
    :param int level: PNG compression level.
    :param str output: Output file name.
    """
    # pylint: disable=too-many-locals

    pack = struct.pack
    crc32 = zlib.crc32

    width, height = size
    line = width * 3
    png_filter = pack(">B", 0)
    scanlines = b"".join(
        [png_filter + data[y * line : y * line + line] for y in range(height)]
    )

    magic = pack(">8B", 137, 80, 78, 71, 13, 10, 26, 10)

    # Header: size, marker, data, CRC32
    ihdr = [b"", b"IHDR", b"", b""]
    ihdr[2] = pack(">2I5B", width, height, 8, 2, 0, 0, 0)
    ihdr[3] = pack(">I", crc32(b"".join(ihdr[1:3])) & 0xFFFFFFFF)
    ihdr[0] = pack(">I", len(ihdr[2]))

    # Data: size, marker, data, CRC32
    idat = [b"", b"IDAT", zlib.compress(scanlines, level), b""]
    idat[3] = pack(">I", crc32(b"".join(idat[1:3])) & 0xFFFFFFFF)
    idat[0] = pack(">I", len(idat[2]))

    # Footer: size, marker, None, CRC32
    iend = [b"", b"IEND", b"", b""]
    iend[3] = pack(">I", crc32(iend[1]) & 0xFFFFFFFF)
    iend[0] = pack(">I", len(iend[2]))

    if not output:
        # Returns raw bytes of the whole PNG data
        return magic + b"".join(ihdr + idat + iend)

    with open(output, "wb") as fileh:
        fileh.write(magic)
        fileh.write(b"".join(ihdr))
        fileh.write(b"".join(idat))
        fileh.write(b"".join(iend))

        # Force write of file to disk
        fileh.flush()
        os.fsync(fileh.fileno())

    return None


Callback example when we try to overwrite an existing screenshot .

def on_exists(fname):
    # type: (str) -> None
    """
    Callback example when we try to overwrite an existing screenshot.
    """

    if os.path.isfile(fname):
        newfile = fname + ".old"
        print("{} -> {}".format(fname, newfile))
        os.rename(fname, newfile)

def
on_exists
(
fname
)
:
# type: (str) -> None
if
os
.
path
.
isfile
(
fname
)
:
newfile
=
fname
+
".old"
print
(
"{} -> {}"
.
format
(
fname
,
newfile
)
)
os
.
rename
(
fname
,
newfile
)