Skip to content

Commit 96b18f6

Browse files
author
Mickaël Schoentgen
committed
Mac: Fix for the fix about 16 rounded width
Original patch by @DavideBecker and @redodo.
1 parent 63fdfaa commit 96b18f6

File tree

5 files changed

+46
-31
lines changed

5 files changed

+46
-31
lines changed

CHANGES.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ base.py
88
darwin.py
99
---------
1010
- Removed `get_infinity()` function
11+
- Removed `resize()` method. Use `_crop_width()` method instead.
1112

1213
windows.py
1314
----------

docs/source/examples.rst

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,23 @@ Examples
55
Basics
66
======
77

8-
One screenshot per monitor::
8+
One screenshot per monitor
9+
--------------------------
10+
::
911

1012
for filename in sct.save():
1113
print(filename)
1214

13-
Screenshot of the monitor 1::
15+
Screenshot of the monitor 1
16+
---------------------------
17+
::
1418

1519
filename = sct.shot()
1620
print(filename)
1721

18-
A screenshot to grab them all::
22+
A screenshot to grab them all
23+
-----------------------------
24+
::
1925

2026
filename = sct.shot(mon=-1, output='fullscreen.png')
2127
print(filename)
@@ -28,13 +34,6 @@ Screenshot of the monitor 1 with a callback:
2834
.. literalinclude:: examples/callback.py
2935
:lines: 9-
3036

31-
GNU/Linux
32-
---------
33-
34-
On GNU/Linux, you can specify which display to use (useful for distant screenshots via SSH):
35-
36-
.. literalinclude:: examples/linux_display_keyword.py
37-
:lines: 9-
3837

3938
Part of the screen
4039
------------------

docs/source/usage.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,17 @@ So the module can be used as simply as::
3333
Or::
3434

3535
sct = mss()
36+
37+
38+
GNU/Linux
39+
---------
40+
41+
On GNU/Linux, you can specify which display to use (useful for distant screenshots via SSH)::
42+
43+
with mss(display=':0.0') as sct:
44+
# ...
45+
46+
A more specific example to only target GNU/Linux:
47+
48+
.. literalinclude:: examples/linux_display_keyword.py
49+
:lines: 9-

mss/darwin.py

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ def _set_argtypes(self):
9393
ctypes.c_uint32,
9494
ctypes.c_uint32,
9595
ctypes.c_uint32]
96+
self.core.CGImageGetWidth.argtypes = [ctypes.c_void_p]
9697
self.core.CGImageGetDataProvider.argtypes = [ctypes.c_void_p]
9798
self.core.CGDataProviderCopyData.argtypes = [ctypes.c_void_p]
9899
self.core.CFDataGetBytePtr.argtypes = [ctypes.c_void_p]
@@ -110,6 +111,7 @@ def _set_restypes(self):
110111
self.core.CGRectUnion.restype = CGRect
111112
self.core.CGDisplayRotation.restype = ctypes.c_float
112113
self.core.CGWindowListCreateImage.restype = ctypes.c_void_p
114+
self.core.CGImageGetWidth.restype = ctypes.c_uint32
113115
self.core.CGImageGetDataProvider.restype = ctypes.c_void_p
114116
self.core.CGDataProviderCopyData.restype = ctypes.c_void_p
115117
self.core.CFDataGetBytePtr.restype = ctypes.c_void_p
@@ -168,10 +170,6 @@ def grab(self, monitor):
168170
# type: (Dict[str, int]) -> ScreenShot
169171
"""
170172
See :meth:`MSSBase.grab <mss.base.MSSBase.grab>` for full details.
171-
172-
When the monitor width is not divisible by 16, its width is reduced
173-
to the previous number divisible by 16. So we need to add extra
174-
black pixels.
175173
"""
176174

177175
# Convert PIL bbox style
@@ -183,7 +181,13 @@ def grab(self, monitor):
183181
'height': monitor[3] - monitor[1],
184182
}
185183

186-
rounded_width = int(math.ceil(monitor['width'] // 16) * 16)
184+
# When the monitor width is not divisible by 16, extra padding
185+
# is added by macOS in the form of black pixels, which results
186+
# in a screenshot with shifted pixels. To counter this, we
187+
# round the width to the nearest integer divisible by 16, and
188+
# we remove the extra width from the image after taking the
189+
# screenshot.
190+
rounded_width = math.ceil(monitor['width'] / 16) * 16
187191

188192
rect = CGRect((monitor['left'], monitor['top']),
189193
(rounded_width, monitor['height']))
@@ -193,6 +197,7 @@ def grab(self, monitor):
193197
raise ScreenShotError(
194198
'CoreGraphics.CGWindowListCreateImage() failed.', locals())
195199

200+
width = int(self.core.CGImageGetWidth(image_ref))
196201
prov = self.core.CGImageGetDataProvider(image_ref)
197202
copy_data = self.core.CGDataProviderCopyData(prov)
198203
data_ref = self.core.CFDataGetBytePtr(copy_data)
@@ -203,24 +208,18 @@ def grab(self, monitor):
203208
self.core.CFRelease(copy_data)
204209

205210
if rounded_width != monitor['width']:
206-
data = self.resize(data, monitor)
211+
data = self._crop_width(data, monitor, width)
207212

208213
return self.cls_image(data, monitor)
209214

210215
@staticmethod
211-
def resize(data, monitor):
212-
# type: (bytearray, Dict[str, int]) -> bytearray
213-
""" Extend a 16 width-rounded screenshot to its original width. """
216+
def _crop_width(image, monitor, width_to):
217+
# type: (bytearray, Dict[str, int], int) -> bytearray
218+
""" Cut off the pixels from an image buffer at a particular width. """
214219

215-
rounded_width = int(math.ceil(monitor['width'] // 16) * 16)
216220
cropped = bytearray()
217-
218221
for row in range(monitor['height']):
219-
start = row * rounded_width * 4
222+
start = row * width_to * 4
220223
end = start + monitor['width'] * 4
221-
cropped.extend(data[start:end])
222-
223-
if len(cropped) < monitor['width'] * monitor['width'] * 4:
224-
cropped.extend(b'\00' * (monitor['width'] - rounded_width) * 4)
225-
224+
cropped.extend(image[start:end])
226225
return cropped

mss/screenshot.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,12 @@ def __array_interface__(self):
5353
See https://docs.scipy.org/doc/numpy/reference/arrays.interface.html
5454
"""
5555

56-
return dict(version=3,
57-
shape=(self.height, self.width, 4),
58-
typestr='|u1',
59-
data=self.raw)
56+
return {
57+
'version': 3,
58+
'shape': (self.height, self.width, 4),
59+
'typestr': '|u1',
60+
'data': self.raw,
61+
}
6062

6163
@classmethod
6264
def from_size(cls, data, width, height):

0 commit comments

Comments
 (0)