11
11
c_void_p , cast , cdll )
12
12
from ctypes .util import find_library
13
13
from sys import maxsize
14
+ from math import ceil
14
15
15
16
from .base import MSSBase
16
17
from .exception import ScreenshotError
@@ -138,11 +139,28 @@ def enum_display_monitors(self, force=False):
138
139
139
140
return self .monitors
140
141
142
+ def crop_width (self , image , width_to ):
143
+ ''' Cut off the pixels from an image buffer at a particular width. '''
144
+ cropped = bytearray ()
145
+ for row in range (self .height ):
146
+ start = row * self .width * 3
147
+ end = start + width_to * 3
148
+ cropped .extend (image [start :end ])
149
+ return cropped
150
+
141
151
def get_pixels (self , monitor ):
142
152
''' Retrieve all pixels from a monitor. Pixels have to be RGB. '''
143
153
154
+ # When the monitor width is not divisible by 16, extra padding is
155
+ # added by MacOS in the form of black pixels, which results
156
+ # in a screenshot with shifted pixels.
157
+ # To counter this, we round the width to the nearest integer
158
+ # divisible by 16, and we remove the extra width from the
159
+ # image after taking the screenshot.
160
+ rounded_width = ceil (monitor ['width' ] / 16 ) * 16
161
+
144
162
rect = CGRect ((monitor ['left' ], monitor ['top' ]),
145
- (monitor [ 'width' ] , monitor ['height' ]))
163
+ (rounded_width , monitor ['height' ]))
146
164
147
165
image_ref = self .core .CGWindowListCreateImage (rect , 1 , 0 , 0 )
148
166
if not image_ref :
@@ -158,4 +176,7 @@ def get_pixels(self, monitor):
158
176
data = cast (data_ref , POINTER (c_ubyte * buf_len ))
159
177
self .core .CGDataProviderRelease (prov )
160
178
self .image = self .bgra_to_rgb (bytearray (data .contents ))
179
+ if rounded_width != monitor ['width' ]:
180
+ self .image = self .crop_width (self .image , monitor ['width' ])
181
+ self .width = monitor ['width' ]
161
182
return self .image
0 commit comments