forked from BoboTiG/python-mss
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathscreenshot.py
158 lines (123 loc) · 4.25 KB
/
screenshot.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
"""
This is part of the MSS Python's module.
Source: https://github.com/BoboTiG/python-mss
"""
from typing import TYPE_CHECKING
from .models import Size, Pos
from .exception import ScreenShotError
if TYPE_CHECKING:
from typing import Any, Dict, Iterator, Optional # noqa
from .models import Monitor, Pixel, Pixels # noqa
class ScreenShot:
"""
Screen shot object.
.. note::
A better name would have been *Image*, but to prevent collisions
with PIL.Image, it has been decided to use *ScreenShot*.
"""
__slots__ = {"__pixels", "__rgb", "pos", "raw", "size"}
def __init__(self, data, monitor, size=None):
# type: (bytearray, Monitor, Optional[Size]) -> None
self.__pixels = None # type: Optional[Pixels]
self.__rgb = None # type: Optional[bytes]
#: Bytearray of the raw BGRA pixels retrieved by ctypes
#: OS independent implementations.
self.raw = data
#: NamedTuple of the screen shot coordinates.
self.pos = Pos(monitor["left"], monitor["top"])
if size is not None:
#: NamedTuple of the screen shot size.
self.size = size
else:
self.size = Size(monitor["width"], monitor["height"])
def __repr__(self):
return ("<{!s} pos={cls.left},{cls.top} size={cls.width}x{cls.height}>").format(
type(self).__name__, cls=self
)
@property
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,
}
@classmethod
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)
@property
def bgra(self):
# type: () -> bytes
""" BGRA values from the BGRA raw pixels. """
return bytes(self.raw)
@property
def height(self):
# type: () -> int
""" Convenient accessor to the height size. """
return self.size.height
@property
def left(self):
# type: () -> int
""" Convenient accessor to the left position. """
return self.pos.left
@property
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
@property
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
@property
def top(self):
# type: () -> int
""" Convenient accessor to the top position. """
return self.pos.top
@property
def width(self):
# type: () -> int
""" Convenient accessor to the width size. """
return self.size.width
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)
)