@@ -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
0 commit comments