1111 c_void_p , cast , cdll )
1212from ctypes .util import find_library
1313from sys import maxsize
14+ from math import ceil
1415
1516from .base import MSSBase
1617from .exception import ScreenshotError
@@ -138,11 +139,28 @@ def enum_display_monitors(self, force=False):
138139
139140 return self .monitors
140141
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+
141151 def get_pixels (self , monitor ):
142152 ''' Retrieve all pixels from a monitor. Pixels have to be RGB. '''
143153
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+
144162 rect = CGRect ((monitor ['left' ], monitor ['top' ]),
145- (monitor [ 'width' ] , monitor ['height' ]))
163+ (rounded_width , monitor ['height' ]))
146164
147165 image_ref = self .core .CGWindowListCreateImage (rect , 1 , 0 , 0 )
148166 if not image_ref :
@@ -158,4 +176,7 @@ def get_pixels(self, monitor):
158176 data = cast (data_ref , POINTER (c_ubyte * buf_len ))
159177 self .core .CGDataProviderRelease (prov )
160178 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' ]
161182 return self .image
0 commit comments