55'''
66
77from ctypes import (
8- POINTER , Structure , byref , c_char_p , c_int , c_int32 , c_long , c_uint ,
9- c_uint32 , c_ulong , c_ushort , c_void_p , cast , cdll , create_string_buffer )
8+ POINTER , Structure , byref , c_char_p , c_int , c_int32 , c_long , c_ubyte ,
9+ c_uint , c_uint32 , c_ulong , c_ushort , c_void_p , cast , cdll )
1010from ctypes .util import find_library
1111from os import environ
12- from os .path import abspath , dirname , isfile , realpath
13- from struct import pack
1412from sys import maxsize , version
1513
1614from .base import MSSBase
@@ -85,11 +83,7 @@ class MSS(MSSBase):
8583 It uses intensively the Xlib and Xrandr extension.
8684 '''
8785
88- # pylint: disable=too-many-instance-attributes
89-
9086 display = None
91- use_mss = False
92- mss = None
9387 xlib = None
9488 xrandr = None
9589 display = None
@@ -127,15 +121,6 @@ def __init__(self, display=None):
127121 raise ScreenshotError ('No Xrandr extension found.' )
128122 self .xrandr = cdll .LoadLibrary (xrandr )
129123
130- # libmss = find_library('mss')
131- libmss = '{0}/linux/{1}/libmss.so' .format (
132- dirname (realpath (abspath (__file__ ))), arch ())
133- if isfile (libmss ):
134- self .mss = cdll .LoadLibrary (libmss )
135- self .use_mss = True
136- # else:
137- # print('No MSS library found. Using slow native function.')
138-
139124 self ._set_argtypes ()
140125 self ._set_restypes ()
141126
@@ -148,13 +133,7 @@ def __init__(self, display=None):
148133 self .root = self .xlib .XDefaultRootWindow (self .display , screen )
149134
150135 def _set_argtypes (self ):
151- ''' Functions arguments.
152-
153- Curiously, if we set up XGetPixel arguments type,
154- the entire process takes twice more time.
155- So, no need to waste this precious time :)
156- Note: this issue does not occur when using libmss.
157- '''
136+ ''' Functions arguments. '''
158137
159138 self .xlib .XOpenDisplay .argtypes = [c_char_p ]
160139 self .xlib .XDefaultScreen .argtypes = [POINTER (Display )]
@@ -166,7 +145,6 @@ def _set_argtypes(self):
166145 self .xlib .XGetImage .argtypes = [POINTER (Display ), POINTER (Display ),
167146 c_int , c_int , c_uint , c_uint , c_ulong ,
168147 c_int ]
169- # self.xlib.XGetPixel.argtypes = [POINTER(XImage), c_int, c_int]
170148 self .xlib .XDestroyImage .argtypes = [POINTER (XImage )]
171149 self .xlib .XCloseDisplay .argtypes = [POINTER (Display )]
172150 self .xrandr .XRRGetScreenResources .argtypes = [POINTER (Display ),
@@ -177,17 +155,9 @@ def _set_argtypes(self):
177155 self .xrandr .XRRFreeScreenResources .argtypes = \
178156 [POINTER (XRRScreenResources )]
179157 self .xrandr .XRRFreeCrtcInfo .argtypes = [POINTER (XRRCrtcInfo )]
180- if self .use_mss :
181- self .mss .GetXImagePixels .argtypes = [POINTER (XImage ), c_void_p ]
182158
183159 def _set_restypes (self ):
184- ''' Functions return type.
185-
186- Curiously, if we set up XGetPixel return type,
187- the entire process takes a little more time.
188- So, no need to waste this precious time :)
189- Note: this issue does not occur when using libmss.
190- '''
160+ ''' Functions return type. '''
191161
192162 def validate (value ):
193163 ''' Validate the returned value of xrandr.XRRGetScreenResources().
@@ -207,16 +177,13 @@ def validate(value):
207177 self .xlib .XGetWindowAttributes .restype = c_int
208178 self .xlib .XAllPlanes .restype = c_ulong
209179 self .xlib .XGetImage .restype = POINTER (XImage )
210- # self.xlib.XGetPixel.restype = c_ulong
211180 self .xlib .XDestroyImage .restype = c_void_p
212181 self .xlib .XCloseDisplay .restype = c_void_p
213182 self .xlib .XDefaultRootWindow .restype = POINTER (XWindowAttributes )
214183 self .xrandr .XRRGetScreenResources .restype = validate
215184 self .xrandr .XRRGetCrtcInfo .restype = POINTER (XRRCrtcInfo )
216185 self .xrandr .XRRFreeScreenResources .restype = c_void_p
217186 self .xrandr .XRRFreeCrtcInfo .restype = c_void_p
218- if self .use_mss :
219- self .mss .GetXImagePixels .restype = c_int
220187
221188 def enum_display_monitors (self , force = False ):
222189 ''' Get positions of monitors (see parent class). '''
@@ -277,52 +244,10 @@ def get_pixels(self, monitor):
277244 err = err .strip (', ' )
278245 raise ScreenshotError (err )
279246
280- if not self .use_mss :
281- self .get_pixels_slow (ximage )
282- else :
283- image = create_string_buffer (self .height * self .width * 3 )
284- ret = self .mss .GetXImagePixels (ximage , image )
285- if not ret :
286- self .xlib .XDestroyImage (ximage )
287- err = 'libmss.GetXImagePixels() failed (retcode={0}).'
288- raise ScreenshotError (err .format (ret ))
289- self .image = bytes (bytearray (image ))
290- self .xlib .XDestroyImage (ximage )
291- return self .image
292-
293- def get_pixels_slow (self , ximage ):
294- ''' Retrieve all pixels from a monitor. Pixels have to be RGB.
295-
296- (!) This version is damn slow, but if you consider that ~1 second
297- for a screenshot of decent monitor is not too long, you can
298- continue. There should be few things to tweak here to gain speed.
299- '''
300-
301- # @TODO: this part takes most of the time. Need a better solution.
302- def pix (pixel , _resultats = {}, p__ = pack ):
303- ''' Apply shifts to a pixel to get the RGB values.
304- This method uses of memoization.
305- '''
306-
307- # pylint: disable=dangerous-default-value
308-
309- try :
310- return _resultats [pixel ]
311- except KeyError :
312- _resultats [pixel ] = p__ ('<B' , (pixel & rmask ) >> 16 ) + \
313- p__ ('<B' , (pixel & gmask ) >> 8 ) + \
314- p__ ('<B' , pixel & bmask )
315- return _resultats [pixel ]
316-
317- self .width = ximage .contents .width
318- self .height = ximage .contents .height
319- rmask = ximage .contents .red_mask
320- bmask = ximage .contents .blue_mask
321- gmask = ximage .contents .green_mask
322- xgetpixel = self .xlib .XGetPixel
323- pixels = [pix (xgetpixel (ximage , x , y ))
324- for y in range (self .height ) for x in range (self .width )]
325- self .image = b'' .join (pixels )
247+ # Replace pixels values: BGRA to RGB.
248+ buf_len = self .height * self .width * 4
249+ data = cast (ximage .contents .data , POINTER (c_ubyte * buf_len ))
250+ self .image = self .bgra_to_rgb (bytearray (data .contents ))
326251 return self .image
327252
328253
0 commit comments