@@ -88,8 +88,8 @@ class XRRCrtcInfo(Structure):
8888 ('outputs' , POINTER (c_long )), ('rotations' , c_ushort ),
8989 ('npossible' , c_int ), ('possible' , POINTER (c_long ))]
9090elif system () == 'Windows' :
91- from ctypes import byref , c_void_p , create_string_buffer , pointer , \
92- sizeof , windll , Structure , POINTER , WINFUNCTYPE
91+ from ctypes import c_void_p , create_string_buffer , sizeof , \
92+ windll , Structure , POINTER , WINFUNCTYPE
9393 from ctypes .wintypes import BOOL , DOUBLE , DWORD , HBITMAP , HDC , \
9494 HGDIOBJ , HWND , INT , LPARAM , LONG , RECT , UINT , WORD
9595
@@ -442,10 +442,7 @@ def enum_display_monitors(self, screen=0):
442442 self .xrandr .XRRFreeScreenResources (mon )
443443
444444 def get_pixels (self , monitor ):
445- ''' Retrieve all pixels from a monitor. Pixels have to be RGB.
446-
447- @TODO: this function takes the most time. Need better solution.
448- '''
445+ ''' Retrieve all pixels from a monitor. Pixels have to be RGB. '''
449446
450447 self .debug ('get_pixels' )
451448
@@ -465,6 +462,7 @@ def get_pixels(self, monitor):
465462 if not ximage :
466463 raise ScreenshotError ('MSS: XGetImage() failed.' )
467464
465+ # @TODO: this part takes most of the time. Need a better solution.
468466 def pix (pixel , _resultats = {}, b = pack ):
469467 ''' Apply shifts to a pixel to get the RGB values.
470468 This method uses of memoization.
@@ -573,44 +571,50 @@ def _callback(monitor, dc, rect, data):
573571 yield mon
574572
575573 def get_pixels (self , monitor ):
576- ''' Retrieve all pixels from a monitor. Pixels have to be RGB. '''
574+ ''' Retrieve all pixels from a monitor. Pixels have to be RGB.
575+
576+ [1] A bottom-up DIB is specified by setting the height to a positive number,
577+ while a top-down DIB is specified by setting the height to a negative number.
578+ https://msdn.microsoft.com/en-us/library/ms787796.aspx
579+ https://msdn.microsoft.com/en-us/library/dd144879%28v=vs.85%29.aspx
580+ '''
577581
578582 self .debug ('get_pixels' )
579583
580584 width , height = monitor [b'width' ], monitor [b'height' ]
581585 left , top = monitor [b'left' ], monitor [b'top' ]
582- good_width = (width * 3 + 3 ) & - 4
583586 SRCCOPY = 0xCC0020
584- DIB_RGB_COLORS = 0
587+ DIB_RGB_COLORS = BI_RGB = 0
585588 srcdc = memdc = bmp = None
586589
587590 try :
591+ bmi = BITMAPINFO ()
592+ bmi .bmiHeader .biSize = sizeof (BITMAPINFOHEADER )
593+ bmi .bmiHeader .biWidth = width
594+ bmi .bmiHeader .biHeight = - height # Why minus? See [1]
595+ bmi .bmiHeader .biPlanes = 1 # Always 1
596+ bmi .bmiHeader .biBitCount = 24
597+ bmi .bmiHeader .biCompression = BI_RGB ;
598+ buffer_len = height * width * 3
599+ self .image = create_string_buffer (buffer_len )
588600 srcdc = windll .user32 .GetWindowDC (0 )
589601 memdc = windll .gdi32 .CreateCompatibleDC (srcdc )
590602 bmp = windll .gdi32 .CreateCompatibleBitmap (srcdc , width , height )
591603 windll .gdi32 .SelectObject (memdc , bmp )
592604 windll .gdi32 .BitBlt (memdc , 0 , 0 , width , height , srcdc , left , top ,
593605 SRCCOPY )
594- bmi = BITMAPINFO ()
595- bmi .bmiHeader .biSize = sizeof (BITMAPINFOHEADER )
596- bmi .bmiHeader .biWidth = width
597- bmi .bmiHeader .biHeight = height
598- bmi .bmiHeader .biBitCount = 24
599- bmi .bmiHeader .biPlanes = 1
600- buffer_len = height * good_width
601- pixels = create_string_buffer (buffer_len )
602- bits = windll .gdi32 .GetDIBits (memdc , bmp , 0 , height , byref (pixels ),
603- pointer (bmi ), DIB_RGB_COLORS )
606+ bits = windll .gdi32 .GetDIBits (memdc , bmp , 0 , height , self .image ,
607+ bmi , DIB_RGB_COLORS )
604608
605609 self .debug ('get_pixels' , 'srcdc' , srcdc )
606610 self .debug ('get_pixels' , 'memdc' , memdc )
607611 self .debug ('get_pixels' , 'bmp' , bmp )
608612 self .debug ('get_pixels' , 'buffer_len' , buffer_len )
613+ self .debug ('get_pixels' , 'len(self.image)' , len (self .image ))
609614 self .debug ('get_pixels' , 'bits' , bits )
610- self .debug ('get_pixels' , 'len(pixels.raw)' , len (pixels .raw ))
611615
612- if bits != height or len ( pixels . raw ) != buffer_len :
613- raise ScreenshotError ('GetDIBits() failed.' )
616+ if bits != height :
617+ raise ScreenshotError ('MSS: GetDIBits() failed.' )
614618 finally :
615619 # Clean up
616620 if srcdc :
@@ -620,47 +624,11 @@ def get_pixels(self, monitor):
620624 if bmp :
621625 windll .gdi32 .DeleteObject (bmp )
622626
623- # Note that the origin of the returned image is in the
624- # bottom-left corner, 32-bit aligned. And it is BGR.
625- # Need to "arrange" that.
626- return self ._arrange (pixels .raw , good_width , height )
627-
628- def _arrange (self , data , width , height ):
629- ''' Reorganises data when the origin of the image is in the
630- bottom-left corner and converts BGR triple to RGB. '''
631-
632- self .debug ('_arrange' )
633-
634- total = width * height
635- scanlines = [b'0' ] * total
636- # Here we do the same thing but in Python 3, the use of struct.pack
637- # slowns down the process by a factor of 2.5 or more.
638- if sys .version < '3' :
639- for y in range (height ):
640- shift = width * (y + 1 )
641- offset = total - shift
642- for x in range (0 , width - 2 , 3 ):
643- off = offset + x
644- scanlines [shift + x :shift + x + 3 ] = \
645- data [off + 2 ], data [off + 1 ], data [off ]
646- else :
647- def pix (pixel , _resultats = {}, b = pack ):
648- ''' Apply conversion to a pixel to get the right value.
649- This method uses of memoization.
650- '''
651- if pixel not in _resultats :
652- _resultats [pixel ] = b (b'<B' , pixel )
653- return _resultats [pixel ]
654-
655- for y in range (height ):
656- shift = width * (y + 1 )
657- offset = total - shift
658- for x in range (0 , width - 2 , 3 ):
659- off = offset + x
660- scanlines [shift + x :shift + x + 3 ] = \
661- pix (data [off + 2 ]), pix (data [off + 1 ]), pix (data [off ])
662-
663- return b'' .join (scanlines )
627+ # Replace pixels values: BGR to RGB
628+ # @TODO: this part takes most of the time. Need a better solution.
629+ for idx in range (0 , buffer_len - 2 , 3 ):
630+ self .image [idx + 2 ], self .image [idx ] = self .image [idx ], self .image [idx + 2 ]
631+ return self .image
664632
665633
666634def main ():
0 commit comments