44Source: https://github.com/BoboTiG/python-mss
55"""
66
7+ from __future__ import division
8+
79import ctypes
810import ctypes .wintypes
911
@@ -41,6 +43,8 @@ class BITMAPINFO(ctypes.Structure):
4143class MSS (MSSBase ):
4244 """ Multiple ScreenShots implementation for Microsoft Windows. """
4345
46+ __scale_factor = None # type: float
47+
4448 def __init__ (self ):
4549 # type: () -> None
4650 """ Windows initialisations. """
@@ -55,6 +59,32 @@ def __init__(self):
5559 set_argtypes (self .monitorenumproc )
5660 set_restypes ()
5761
62+ @property
63+ def scale_factor (self ):
64+ """ Compute the scale factor. """
65+
66+ if not self .__scale_factor :
67+ display = None
68+ try :
69+ display = ctypes .windll .user32 .GetWindowDC (0 )
70+ width = ctypes .windll .gdi32 .GetDeviceCaps (display , 8 )
71+ width_orig = ctypes .windll .gdi32 .GetDeviceCaps (display , 118 )
72+ scale = (100 + 100 - width * 100 // width_orig ) / 100
73+ self .__scale_factor = round (scale * 4 ) / 4
74+ finally :
75+ if display :
76+ ctypes .windll .gdi32 .DeleteObject (display )
77+
78+ return self .__scale_factor
79+
80+ def scale (self , value ):
81+ # type: (float) -> int
82+ """ Compute a monitor value at scale, rounded to 2. """
83+
84+ if self .scale_factor == 1.0 :
85+ return int (value )
86+ return int (value * self .scale_factor * 2 + 0.5 ) // 2
87+
5888 @property
5989 def monitors (self ):
6090 # type: () -> List[Dict[str, int]]
@@ -69,10 +99,11 @@ def monitors(self):
6999 top = ctypes .windll .user32 .GetSystemMetrics (sm_yvirtualscreen )
70100 bottom = ctypes .windll .user32 .GetSystemMetrics (sm_cyvirtualscreen )
71101 self ._monitors .append ({
72- 'left' : int (left ),
73- 'top' : int (top ),
74- 'width' : int (right - left ),
75- 'height' : int (bottom - top ),
102+ 'left' : self .scale (left ),
103+ 'top' : self .scale (top ),
104+ 'width' : self .scale (right - left ),
105+ 'height' : self .scale (bottom - top ),
106+ 'scale' : self .scale_factor ,
76107 })
77108
78109 # Each monitors
@@ -86,10 +117,11 @@ def _callback(monitor, data, rect, dc_):
86117 del monitor , data , dc_
87118 rct = rect .contents
88119 self ._monitors .append ({
89- 'left' : int (rct .left ),
90- 'top' : int (rct .top ),
91- 'width' : int (rct .right - rct .left ),
92- 'height' : int (rct .bottom - rct .top ),
120+ 'left' : self .scale (rct .left ),
121+ 'top' : self .scale (rct .top ),
122+ 'width' : self .scale (rct .right - rct .left ),
123+ 'height' : self .scale (rct .bottom - rct .top ),
124+ 'scale' : self .scale_factor ,
93125 })
94126 return 1
95127
@@ -145,6 +177,7 @@ def grab(self, monitor):
145177 buf_len = monitor ['width' ] * monitor ['height' ] * 4 # See [2]
146178 data = ctypes .create_string_buffer (buf_len )
147179 srcdc = ctypes .windll .user32 .GetWindowDC (0 )
180+
148181 memdc = ctypes .windll .gdi32 .CreateCompatibleDC (srcdc )
149182 bmp = ctypes .windll .gdi32 .CreateCompatibleBitmap (
150183 srcdc , monitor ['width' ], monitor ['height' ])
@@ -184,6 +217,8 @@ def set_argtypes(callback):
184217 callback ,
185218 ctypes .wintypes .LPARAM ]
186219 ctypes .windll .user32 .GetWindowDC .argtypes = [ctypes .wintypes .HWND ]
220+ ctypes .windll .gdi32 .GetDeviceCaps .argtypes = [ctypes .wintypes .HWND ,
221+ ctypes .wintypes .INT ]
187222 ctypes .windll .gdi32 .CreateCompatibleDC .argtypes = [ctypes .wintypes .HDC ]
188223 ctypes .windll .gdi32 .CreateCompatibleBitmap .argtypes = [
189224 ctypes .wintypes .HDC ,
@@ -219,6 +254,7 @@ def set_restypes():
219254 ctypes .windll .user32 .GetSystemMetrics .restype = ctypes .wintypes .INT
220255 ctypes .windll .user32 .EnumDisplayMonitors .restype = ctypes .wintypes .BOOL
221256 ctypes .windll .user32 .GetWindowDC .restype = ctypes .wintypes .HDC
257+ ctypes .windll .gdi32 .GetDeviceCaps .restype = ctypes .wintypes .INT
222258 ctypes .windll .gdi32 .CreateCompatibleDC .restype = ctypes .wintypes .HDC
223259 ctypes .windll .gdi32 .CreateCompatibleBitmap .restype = \
224260 ctypes .wintypes .HBITMAP
0 commit comments