windows-mcp 0.6.0__py3-none-any.whl → 0.6.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
windows_mcp/uia/core.py CHANGED
@@ -101,6 +101,10 @@ class _AutomationClient:
101
101
  return cls._instance
102
102
 
103
103
  def __init__(self):
104
+ try:
105
+ ctypes.windll.ole32.CoInitialize(None)
106
+ except Exception:
107
+ pass
104
108
  tryCount = 3
105
109
  for retry in range(tryCount):
106
110
  try:
@@ -111,62 +115,9 @@ class _AutomationClient:
111
115
  break
112
116
  except Exception as ex:
113
117
  if retry + 1 == tryCount:
114
- Logger.WriteLine('''
115
- {}
116
- Can not load UIAutomationCore.dll.
117
- 1, You may need to install Windows Update KB971513 if your OS is Windows XP, see https://github.com/yinkaisheng/WindowsUpdateKB971513ForIUIAutomation
118
- 2, You need to use an UIAutomationInitializerInThread object if use uiautomation in a thread, see demos/uiautomation_in_thread.py'''.format(ex), ConsoleColor.Yellow)
119
118
  raise ex
120
119
 
121
120
 
122
- class _DllClient:
123
- _instance = None
124
-
125
- @classmethod
126
- def instance(cls) -> '_DllClient':
127
- """Singleton instance (this prevents com creation on import)."""
128
- if cls._instance is None:
129
- cls._instance = cls()
130
- return cls._instance
131
-
132
- def __init__(self):
133
- binPath = os.path.join(os.path.dirname(os.path.abspath(__file__)), "bin")
134
- os.environ["PATH"] = binPath + os.pathsep + os.environ["PATH"]
135
- load = False
136
- if IsPy38OrHigher and IsNT6orHigher:
137
- os.add_dll_directory(binPath)
138
- if CurrentProcessIs64Bit:
139
- try:
140
- self.dll = ctypes.cdll.UIAutomationClient_VC140_X64
141
- load = True
142
- except Exception as ex:
143
- print(ex)
144
- else:
145
- try:
146
- self.dll = ctypes.cdll.UIAutomationClient_VC140_X86
147
- load = True
148
- except Exception as ex:
149
- print(ex)
150
- if load:
151
- self.dll.BitmapCreate.restype = ctypes.c_size_t
152
- self.dll.BitmapGetWidthAndHeight.restype = ctypes.c_uint64
153
- self.dll.BitmapFromWindow.restype = ctypes.c_size_t
154
- self.dll.BitmapFromHBITMAP.restype = ctypes.c_size_t
155
- self.dll.BitmapToHBITMAP.restype = ctypes.c_size_t
156
- self.dll.BitmapFromFile.restype = ctypes.c_size_t
157
- self.dll.BitmapFromBytes.restype = ctypes.c_size_t
158
- self.dll.BitmapResize.restype = ctypes.c_size_t
159
- self.dll.BitmapRotate.restype = ctypes.c_size_t
160
- self.dll.BitmapGetPixel.restype = ctypes.c_uint32
161
- self.dll.Initialize()
162
- else:
163
- self.dll = None
164
- Logger.WriteLine('Can not load dll.\nFunctionalities related to Bitmap are not available.\nYou may need to install Microsoft Visual C++ 2015 Redistributable Package.', ConsoleColor.Yellow)
165
-
166
- def __del__(self):
167
- if self.dll:
168
- self.dll.Uninitialize()
169
-
170
121
 
171
122
  # set Windows dll restype
172
123
  ctypes.windll.user32.GetAncestor.restype = ctypes.c_void_p
@@ -178,7 +129,6 @@ ctypes.windll.user32.GetWindowLongW.restype = ctypes.wintypes.LONG
178
129
  ctypes.windll.user32.OpenDesktopW.restype = ctypes.c_void_p
179
130
  ctypes.windll.user32.SendMessageW.restype = ctypes.wintypes.LONG
180
131
  ctypes.windll.user32.WindowFromPoint.restype = ctypes.c_void_p
181
- ctypes.windll.gdi32.CreateBitmap.restype = ctypes.c_void_p
182
132
  ctypes.windll.gdi32.CreateCompatibleDC.restype = ctypes.c_void_p
183
133
  ctypes.windll.gdi32.SelectObject.restype = ctypes.c_void_p
184
134
  ctypes.windll.kernel32.GetConsoleWindow.restype = ctypes.c_void_p
@@ -188,7 +138,6 @@ ctypes.windll.kernel32.GlobalLock.restype = ctypes.c_void_p
188
138
  ctypes.windll.kernel32.OpenProcess.restype = ctypes.c_void_p
189
139
  ctypes.windll.ntdll.NtQueryInformationProcess.restype = ctypes.c_uint32
190
140
 
191
-
192
141
  def _GetDictKeyName(theDict: Dict[str, Any], theValue: Any, keyCondition: Optional[Callable[[str], bool]] = None) -> str:
193
142
  for key, value in theDict.items():
194
143
  if keyCondition:
@@ -588,6 +537,21 @@ def GetVirtualScreenSize() -> Tuple[int, int]:
588
537
  return w, h
589
538
 
590
539
 
540
+ def GetVirtualScreenRect() -> Tuple[int, int, int, int]:
541
+ """Returns (left, top, width, height) of the virtual screen."""
542
+ SM_XVIRTUALSCREEN = 76
543
+ SM_YVIRTUALSCREEN = 77
544
+ SM_CXVIRTUALSCREEN = 78
545
+ SM_CYVIRTUALSCREEN = 79
546
+ return (
547
+ ctypes.windll.user32.GetSystemMetrics(SM_XVIRTUALSCREEN),
548
+ ctypes.windll.user32.GetSystemMetrics(SM_YVIRTUALSCREEN),
549
+ ctypes.windll.user32.GetSystemMetrics(SM_CXVIRTUALSCREEN),
550
+ ctypes.windll.user32.GetSystemMetrics(SM_CYVIRTUALSCREEN)
551
+ )
552
+
553
+
554
+
591
555
  def GetMonitorsRect() -> List[Rect]:
592
556
  """
593
557
  Get monitors' rect.
@@ -1765,837 +1729,6 @@ def _ExitHandler():
1765
1729
  atexit.register(_ExitHandler)
1766
1730
 
1767
1731
 
1768
- class RotateFlipType:
1769
- RotateNoneFlipNone = 0
1770
- Rotate90FlipNone = 1
1771
- Rotate180FlipNone = 2
1772
- Rotate270FlipNone = 3
1773
- RotateNoneFlipX = 4
1774
- Rotate90FlipX = 5
1775
- Rotate180FlipX = 6
1776
- Rotate270FlipX = 7
1777
- RotateNoneFlipY = Rotate180FlipX
1778
- Rotate90FlipY = Rotate270FlipX
1779
- Rotate180FlipY = RotateNoneFlipX
1780
- Rotate270FlipY = Rotate90FlipX
1781
- RotateNoneFlipXY = Rotate180FlipNone
1782
- Rotate90FlipXY = Rotate270FlipNone
1783
- Rotate180FlipXY = RotateNoneFlipNone
1784
- Rotate270FlipXY = Rotate90FlipNone
1785
-
1786
-
1787
- class RawFormat:
1788
- Undefined = 0
1789
- MemoryBMP = 1
1790
- BMP = 2
1791
- EMF = 3
1792
- WMF = 4
1793
- JPEG = 5
1794
- PNG = 6
1795
- GIF = 7 # MultiFrameBitmap
1796
- TIFF = 8 # MultiFrameBitmap
1797
- EXIF = 9
1798
- Icon = 10
1799
-
1800
-
1801
- class Bitmap:
1802
- """
1803
- A simple Bitmap class wraps Windows GDI+ Gdiplus::Bitmap, but may not have high efficiency.
1804
- The color format is Gdiplus::PixelFormat32bppARGB 0xAARRGGBB, byte order is B G R A.
1805
- """
1806
-
1807
- def __init__(self, width: int = 0, height: int = 0):
1808
- """
1809
- Create a black transparent(ARGB=0x00000000) bimap of size(width, height).
1810
- """
1811
- self._width = width
1812
- self._height = height
1813
- self._bitmap = 0
1814
- self._format = RawFormat.Undefined
1815
- self._formatStr = ''
1816
- if width > 0 and height > 0:
1817
- self._bitmap = _DllClient.instance().dll.BitmapCreate(width, height)
1818
-
1819
- def __del__(self):
1820
- self.Close()
1821
-
1822
- def __enter__(self):
1823
- return self
1824
-
1825
- def __exit__(self, exceptionType, exceptionValue, exceptionTraceback):
1826
- self.Close()
1827
-
1828
- def __bool__(self):
1829
- return self._bitmap > 0
1830
-
1831
- def _GetSize(self) -> None:
1832
- size = _DllClient.instance().dll.BitmapGetWidthAndHeight(ctypes.c_size_t(self._bitmap))
1833
- self._width = size & 0xFFFFFFFF
1834
- self._height = size >> 32
1835
-
1836
- def Close(self) -> None:
1837
- """Close the underlying Gdiplus::Bitmap object."""
1838
- if self._bitmap:
1839
- _DllClient.instance().dll.BitmapRelease(ctypes.c_size_t(self._bitmap))
1840
- self._bitmap = 0
1841
- self._width = 0
1842
- self._height = 0
1843
-
1844
- Release = Close
1845
-
1846
- @property
1847
- def Width(self) -> int:
1848
- """
1849
- Property Width.
1850
- Return int.
1851
- """
1852
- return self._width
1853
-
1854
- @property
1855
- def Height(self) -> int:
1856
- """
1857
- Property Height.
1858
- Return int.
1859
- """
1860
- return self._height
1861
-
1862
- @staticmethod
1863
- def FromHandle(handle: int, left: int, top: int, right: int, bottom: int,
1864
- captureCursor: bool = False) -> Optional['MemoryBMP']:
1865
- """
1866
- Create a `Bitmap` from a native window handle.
1867
- handle: int, the handle of a native window.
1868
- left: int.
1869
- top: int.
1870
- right: int.
1871
- bottom: int.
1872
- left, top, right and bottom are control's internal postion(from 0,0).
1873
- Return `Bitmap` or None.
1874
- """
1875
- rect = None
1876
- toplevelHandle = GetAncestor(handle, GAFlag.Root)
1877
- if toplevelHandle and toplevelHandle == handle:
1878
- if DwmIsCompositionEnabled():
1879
- rect = DwmGetWindowExtendFrameBounds(handle)
1880
- if rect is None:
1881
- rect = GetWindowRect(handle)
1882
- if rect is None:
1883
- return None
1884
- root = GetRootControl()
1885
- left, top, right, bottom = left + rect.left, top + rect.top, right + rect.left, bottom + rect.top
1886
- cbmp = _DllClient.instance().dll.BitmapFromWindow(ctypes.c_size_t(root.NativeWindowHandle),
1887
- left, top, right, bottom,
1888
- 0, 0, int(captureCursor))
1889
- return Bitmap._FromGdiplusBitmap(cbmp)
1890
-
1891
- @staticmethod
1892
- def FromControl(control: 'Control', x: int = 0, y: int = 0, width: int = 0, height: int = 0,
1893
- captureCursor: bool = False) -> Optional['MemoryBMP']:
1894
- """
1895
- Create a `Bitmap` from a `Control`.
1896
- control: `Control` or its subclass.
1897
- x: int.
1898
- y: int.
1899
- width: int.
1900
- height: int.
1901
- x, y: the point in control's internal position(from 0,0)
1902
- width, height: image's width and height from x, y, use 0 for entire area,
1903
- If width(or height) < 0, image size will be control's width(or height) - width(or height).
1904
- Return `Bitmap` or None.
1905
- """
1906
- rect = control.BoundingRectangle
1907
- while rect.width() == 0 or rect.height() == 0:
1908
- # some controls maybe visible but their BoundingRectangle are all 0, capture its parent until valid
1909
- control = control.GetParentControl()
1910
- if not control:
1911
- return None
1912
- rect = control.BoundingRectangle
1913
- handle = control.NativeWindowHandle
1914
- if handle:
1915
- toplevelHandle = GetAncestor(handle, GAFlag.Root)
1916
- if toplevelHandle and toplevelHandle == handle:
1917
- if DwmIsCompositionEnabled():
1918
- rect = DwmGetWindowExtendFrameBounds(handle) or rect
1919
- if width <= 0:
1920
- width = rect.width() + width
1921
- if height <= 0:
1922
- height = rect.height() + height
1923
- root = GetRootControl()
1924
- left, top = rect.left + x, rect.top + y
1925
- right, bottom = left + width, top + height
1926
- cbmp = _DllClient.instance().dll.BitmapFromWindow(ctypes.c_size_t(root.NativeWindowHandle),
1927
- left, top, right, bottom,
1928
- 0, 0, int(captureCursor))
1929
- return Bitmap._FromGdiplusBitmap(cbmp)
1930
- if width <= 0:
1931
- width = rect.width() + width
1932
- if height <= 0:
1933
- height = rect.height() + height
1934
- while True:
1935
- control = control.GetParentControl()
1936
- handle = control.NativeWindowHandle
1937
- if handle:
1938
- pRect = control.BoundingRectangle
1939
- toplevelHandle = GetAncestor(handle, GAFlag.Root)
1940
- if toplevelHandle and toplevelHandle == handle:
1941
- if DwmIsCompositionEnabled():
1942
- pRect = DwmGetWindowExtendFrameBounds(handle) or pRect
1943
- left = rect.left - pRect.left + x
1944
- top = rect.top - pRect.top + y
1945
- right = left + width
1946
- bottom = top + height
1947
- break
1948
- return Bitmap.FromHandle(handle, left, top, right, bottom, captureCursor)
1949
-
1950
- @staticmethod
1951
- def _FromGdiplusBitmap(cbmp: int) -> 'Bitmap':
1952
- """
1953
- Return `Bitmap`'s subclass instance or None.
1954
- """
1955
- if not cbmp:
1956
- return None
1957
- formatType = ctypes.c_uint()
1958
- _DllClient.instance().dll.BitmapGetRawFormat(ctypes.c_size_t(cbmp), ctypes.byref(formatType))
1959
- if formatType.value == RawFormat.JPEG:
1960
- bitmap = JPEG()
1961
- elif formatType.value == RawFormat.PNG:
1962
- bitmap = PNG()
1963
- elif formatType.value == RawFormat.GIF:
1964
- bitmap = GIF()
1965
- bitmap._bitmap = cbmp
1966
- bitmap._frameCount = _DllClient.instance().dll.MultiBitmapGetFrameCount(ctypes.c_size_t(cbmp))
1967
- bitmap._GetGifDealy()
1968
- elif formatType.value == RawFormat.TIFF:
1969
- bitmap = TIFF()
1970
- bitmap._frameCount = _DllClient.instance().dll.MultiBitmapGetFrameCount(ctypes.c_size_t(cbmp))
1971
- elif formatType.value == RawFormat.BMP:
1972
- bitmap = BMP()
1973
- elif formatType.value == RawFormat.MemoryBMP:
1974
- bitmap = MemoryBMP()
1975
- elif formatType.value == RawFormat.Icon:
1976
- bitmap = ICON()
1977
- elif formatType.value == RawFormat.EMF:
1978
- bitmap = EMF()
1979
- elif formatType.value == RawFormat.WMF:
1980
- bitmap = WMF()
1981
- elif formatType.value == RawFormat.EXIF:
1982
- bitmap = EXIF()
1983
- else:
1984
- bitmap = Bitmap()
1985
- bitmap._bitmap = cbmp
1986
- bitmap._format = formatType.value
1987
- bitmap._GetSize()
1988
- return bitmap
1989
-
1990
- @staticmethod
1991
- def FromBytes(data: Union[bytes, bytearray], format: str = None, width: int = None, height: int = None) -> Optional['Bitmap']:
1992
- """
1993
- Create a `Bitmap` instance from raw BGRA pixel data or image file byte content.
1994
- data: bytes or bytearray.
1995
- format (str, optional): Specifies the format of the input data.
1996
- - Use 'BGRA' for raw pixel data, byte order is B G R A.
1997
- - Use None for standard image file data (e.g., PNG, JPEG).
1998
- width (int, optional): The width of the image. Required only when `format` is 'BGRA'.
1999
- height (int, optional): The height of the image. Required only when `format` is 'BGRA'.
2000
- Return `Bitmap`'s subclass instance or None.
2001
- """
2002
- if format is not None:
2003
- assert format == 'bgra' or format == 'BGRA'
2004
- assert len(data) == width * height * 4
2005
- if isinstance(data, bytearray):
2006
- pixelBytes = data
2007
- else:
2008
- pixelBytes = bytearray(data)
2009
- pixelArrayType = (ctypes.c_uint32 * (len(pixelBytes) // 4))
2010
- pixelArray = pixelArrayType.from_buffer(pixelBytes)
2011
- bitmap = Bitmap(width, height)
2012
- bitmap.SetAllPixelColors(pixelArray)
2013
- return bitmap
2014
- cbmp = _DllClient.instance().dll.BitmapFromBytes(ctypes.c_char_p(data), len(data), 0)
2015
- return Bitmap._FromGdiplusBitmap(cbmp)
2016
-
2017
- @staticmethod
2018
- def FromFile(filePath: str) -> Optional['Bitmap']:
2019
- """
2020
- Create a `Bitmap` from a file path.
2021
- filePath: str.
2022
- Return `Bitmap`'s subclass instance or None.
2023
- """
2024
- cbmp = _DllClient.instance().dll.BitmapFromFile(ctypes.c_wchar_p(filePath))
2025
- return Bitmap._FromGdiplusBitmap(cbmp)
2026
-
2027
- @staticmethod
2028
- def FromNDArray(image: 'numpy.ndarray') -> 'MemoryBMP':
2029
- """
2030
- Create a `MemoryBMP` from a numpy.ndarray(BGR or BGRA).
2031
- """
2032
- import numpy as np
2033
- assert len(image.shape) == 3 and (image.shape[2] == 3 or image.shape[2] == 4)
2034
- height, width = image.shape[:2]
2035
- if image.shape[2] == 3:
2036
- bgraArray = np.zeros((height, width, 4), dtype=np.uint8)
2037
- bgraArray[:, :, :3] = image[:, :, :]
2038
- bgraArray[:, :, 3] = 0xFF
2039
- else: # 4
2040
- bgraArray = image
2041
- pixelBytes = bytearray(bgraArray.tobytes())
2042
- pixelArrayType = (ctypes.c_uint32 * (len(pixelBytes) // 4))
2043
- pixelArray = pixelArrayType.from_buffer(pixelBytes)
2044
- bitmap = MemoryBMP(width, height)
2045
- bitmap.SetAllPixelColors(pixelArray)
2046
- return bitmap
2047
-
2048
- @staticmethod
2049
- def FromPILImage(image: 'PIL.Image.Image') -> 'MemoryBMP':
2050
- """
2051
- Create a `MemoryBMP` from a PIL Image.
2052
- """
2053
- assert image.mode == 'RGB' or image.mode == 'RGBA'
2054
- try:
2055
- import numpy as np
2056
- imgArray = np.array(image)
2057
- if image.mode == 'RGB':
2058
- imgArray = imgArray[:, :, ::-1]
2059
- else: # 'RGBA'
2060
- imgArray = imgArray[:, :, [2, 1, 0, 3]]
2061
- return Bitmap.FromNDArray(imgArray)
2062
- except:
2063
- if image.mode == 'RGB':
2064
- rgbaImg = image.convert('RGBA')
2065
- rgbaBytes = rgbaImg.tobytes()
2066
- else: # 'RGBA'
2067
- rgbaBytes = image.tobytes()
2068
- pixelBytes = bytearray(rgbaBytes)
2069
- for i in range(0, len(pixelBytes), 4):
2070
- pixel = pixelBytes[i:i+4]
2071
- pixelBytes[i:i+4] = pixel[2], pixel[1], pixel[0], pixel[3]
2072
- pixelArrayType = (ctypes.c_uint32 * (len(pixelBytes) // 4))
2073
- pixelArray = pixelArrayType.from_buffer(pixelBytes)
2074
- bitmap = MemoryBMP(image.width, image.height)
2075
- bitmap.SetAllPixelColors(pixelArray)
2076
- return bitmap
2077
-
2078
- def ToFile(self, savePath: str, *, quality: int = None) -> bool:
2079
- """
2080
- Save to a file.
2081
- savePath: str, should end with .bmp, .jpg, .jpeg, .png, .gif, .tif, .tiff.
2082
- quality: int, 1-100, only used when save to jpeg.
2083
- Return bool, True if succeed otherwise False.
2084
- Note: If file extension is .gif or .tiff, it is only saved as a single frame.
2085
- If you want to save a gif or a tiff file with multiple frames, use `GIF.ToGifFile` or `TIFF.ToTiffFile`.
2086
- """
2087
- name, ext = os.path.splitext(savePath)
2088
- extMap = {'.bmp': 'image/bmp',
2089
- '.jpg': 'image/jpeg',
2090
- '.jpeg': 'image/jpeg',
2091
- '.gif': 'image/gif',
2092
- '.tif': 'image/tiff',
2093
- '.tiff': 'image/tiff',
2094
- '.png': 'image/png',
2095
- }
2096
- gdiplusImageFormat = extMap.get(ext.lower(), 'image/png')
2097
- gdiStatus = _DllClient.instance().dll.BitmapToFile(ctypes.c_size_t(self._bitmap), ctypes.c_wchar_p(savePath), ctypes.c_wchar_p(gdiplusImageFormat), quality or 80)
2098
- return gdiStatus == 0
2099
-
2100
- def ToBytes(self, format: str, *, quality: int = None) -> bytearray:
2101
- """
2102
- Convert to a bytearray in the specified format.
2103
- format: str, The desired output format. Supported formats include:
2104
- - 'BGRA': Raw pixel data without any file header, byte order is B G R A.
2105
- - 'bmp', 'jpg', 'jpeg', 'gif', 'tif', 'tiff', 'png':
2106
- Standard image file formats with corresponding file headers.
2107
- quality: int, 1-100, only used when format is jpg and jpeg.
2108
- Note: If format is gif or tiff, only the active single frame is saved to a bytearray.
2109
- Currently multiple frames are not supported.
2110
- """
2111
- format = format.lower()
2112
- if format == 'bgra':
2113
- return bytearray(memoryview(self.GetAllPixelColors()))
2114
-
2115
- if format[0] != '.':
2116
- format = '.' + format
2117
- extMap = {'.bmp': 'image/bmp',
2118
- '.jpg': 'image/jpeg',
2119
- '.jpeg': 'image/jpeg',
2120
- '.gif': 'image/gif',
2121
- '.tif': 'image/tiff',
2122
- '.tiff': 'image/tiff',
2123
- '.png': 'image/png',
2124
- }
2125
- gdiplusImageFormat = extMap.get(format.lower(), 'image/png')
2126
- stream = ctypes.c_size_t()
2127
- gdiStatus = _DllClient.instance().dll.BitmapToStream(
2128
- ctypes.c_size_t(self._bitmap), ctypes.byref(stream), ctypes.c_wchar_p(gdiplusImageFormat), quality or 80)
2129
- if stream.value == 0:
2130
- return None
2131
- streamSize = _DllClient.instance().dll.GetStreamSize(stream)
2132
- if streamSize == 0:
2133
- return None
2134
- data = bytearray(streamSize)
2135
- cdata = (ctypes.c_ubyte * streamSize).from_buffer(data)
2136
- streamSize = _DllClient.instance().dll.CopyStreamData(stream, cdata, streamSize)
2137
- _DllClient.instance().dll.ReleaseStream(stream)
2138
- return data
2139
-
2140
- def ToPILImage(self) -> 'PIL.Image.Image':
2141
- """
2142
- Convert to a PIL image.
2143
- usage:
2144
- image = bitmap.ToPILImage()
2145
- image.save("pil.png")
2146
- image.save("pil.png")
2147
- image.convert('RGB').save('pil.jpg', quality=80, optimize=True)
2148
- """
2149
- from PIL import Image
2150
- return Image.frombytes('RGBA', (self.Width, self.Height), self.ToBytes('BGRA'), 'raw', 'BGRA')
2151
-
2152
- def ToNDArray(self) -> 'numpy.ndarray':
2153
- """
2154
- Convert to a numpy.ndarray(shape=(height,width,4), compatible with OpenCV).
2155
- usage:
2156
- bgraImage = bitmap.ToNDArray()
2157
- bgrImage = cv2.cvtColor(bgraImage, cv2.COLOR_BGRA2BGR)
2158
- """
2159
- import numpy as np
2160
- npArray = np.frombuffer(self.ToBytes('BGRA'), dtype=np.uint8)
2161
- return npArray.reshape((self.Height, self.Width, 4))
2162
-
2163
- def GetRawFormat(self) -> int:
2164
- """
2165
- return a int value in class `RawFormat`
2166
- """
2167
- if self._format == RawFormat.Undefined:
2168
- formatType = ctypes.c_uint()
2169
- _DllClient.instance().dll.BitmapGetRawFormat(ctypes.c_size_t(self._bitmap), ctypes.byref(formatType))
2170
- self._format = formatType.value
2171
- return self._format
2172
-
2173
- def GetRawFormatStr(self) -> str:
2174
- """
2175
- return the string description of `RawFormat` value
2176
- """
2177
- if not self._formatStr:
2178
- self._formatStr = _GetDictKeyName(RawFormat.__dict__, self.GetRawFormat())
2179
- return self._formatStr
2180
-
2181
- def GetPixelColor(self, x: int, y: int) -> int:
2182
- """
2183
- Get color value of a pixel.
2184
- x: int.
2185
- y: int.
2186
- Return int, ARGB(0xAARRGGBB) color format.
2187
- b = argb & 0x0000_00FF
2188
- g = (argb & 0x0000_FF00) >> 8
2189
- r = (argb & 0x00FF_0000) >> 16
2190
- a = (argb & 0xFF00_0000) >> 24
2191
- """
2192
- return _DllClient.instance().dll.BitmapGetPixel(ctypes.c_size_t(self._bitmap), x, y)
2193
-
2194
- def SetPixelColor(self, x: int, y: int, argb: int) -> bool:
2195
- """
2196
- Set color value of a pixel.
2197
- x: int.
2198
- y: int.
2199
- argb: int, ARGB(0xAARRGGBB) color format.
2200
- Return bool, True if succeed otherwise False.
2201
- """
2202
- gdiStatus = _DllClient.instance().dll.BitmapSetPixel(ctypes.c_size_t(self._bitmap), x, y, argb)
2203
- return gdiStatus == 0
2204
-
2205
- def GetPixelColorsHorizontally(self, x: int, y: int, count: int) -> ctypes.Array:
2206
- """
2207
- x: int.
2208
- y: int.
2209
- count: int.
2210
- Return `ctypes.Array`, an iterable array of int values in ARGB(0xAARRGGBB) color format form point x,y horizontally.
2211
- """
2212
- #assert count <= self.Width * (self.Height - y) - x, 'count > max available from x,y'
2213
- arrayType = ctypes.c_uint32 * count
2214
- values = arrayType()
2215
- gdiStatus = _DllClient.instance().dll.BitmapGetPixelsHorizontally(ctypes.c_size_t(self._bitmap), x, y, values, count)
2216
- return values
2217
-
2218
- def SetPixelColorsHorizontally(self, x: int, y: int, colors: Sequence[int]) -> bool:
2219
- """
2220
- Set pixel colors form x,y horizontally.
2221
- x: int.
2222
- y: int.
2223
- colors: Sequence[int], an iterable list of int color values in ARGB(0xAARRGGBB) color format,
2224
- use ctypes.Array for better performance, such as `ctypes.c_uint32 * length`.
2225
- Return bool, True if succeed otherwise False.
2226
- """
2227
- count = len(colors)
2228
- #assert count <= self.Width * (self.Height - y) - x, 'len(colors) > max available from x,y'
2229
- if not isinstance(colors, ctypes.Array):
2230
- arrayType = ctypes.c_uint32 * count
2231
- colors = arrayType(*colors)
2232
- gdiStatus = _DllClient.instance().dll.BitmapSetPixelsHorizontally(ctypes.c_size_t(self._bitmap), x, y, colors, count)
2233
- return gdiStatus == 0
2234
-
2235
- def GetPixelColorsVertically(self, x: int, y: int, count: int) -> ctypes.Array:
2236
- """
2237
- x: int.
2238
- y: int.
2239
- count: int.
2240
- Return `ctypes.Array`, an iterable array of int values in ARGB(0xAARRGGBB) color format form point x,y vertically.
2241
- """
2242
- #assert count <= self.Height * (self.Width - x) - y, 'count > max available from x,y'
2243
- arrayType = ctypes.c_uint32 * count
2244
- values = arrayType()
2245
- gdiStatus = _DllClient.instance().dll.BitmapGetPixelsVertically(ctypes.c_size_t(self._bitmap), x, y, values, count)
2246
- return values
2247
-
2248
- def SetPixelColorsVertically(self, x: int, y: int, colors: Sequence[int]) -> bool:
2249
- """
2250
- Set pixel colors form x,y vertically.
2251
- x: int.
2252
- y: int.
2253
- colors: Sequence[int], an iterable list of int color values in ARGB(0xAARRGGBB) color format,
2254
- use ctypes.Array for better performance, such as `ctypes.c_uint32 * length`.
2255
- Return bool, True if succeed otherwise False.
2256
- """
2257
- count = len(colors)
2258
- #assert count <= self.Height * (self.Width - x) - y, 'len(colors) > max available from x,y'
2259
- if not isinstance(colors, ctypes.Array):
2260
- arrayType = ctypes.c_uint32 * count
2261
- colors = arrayType(*colors)
2262
- gdiStatus = _DllClient.instance().dll.BitmapSetPixelsVertically(ctypes.c_size_t(self._bitmap), x, y, colors, count)
2263
- return gdiStatus == 0
2264
-
2265
- def GetPixelColorsOfRow(self, y: int) -> ctypes.Array:
2266
- """
2267
- y: int, row index.
2268
- Return `ctypes.Array`, an iterable array of int values in ARGB(0xAARRGGBB) color format of y row.
2269
- """
2270
- return self.GetPixelColorsOfRect(0, y, self.Width, 1)
2271
-
2272
- def GetPixelColorsOfColumn(self, x: int) -> ctypes.Array:
2273
- """
2274
- x: int, column index.
2275
- Return `ctypes.Array`, an iterable array of int values in ARGB(0xAARRGGBB) color format of x column.
2276
- """
2277
- return self.GetPixelColorsOfRect(x, 0, 1, self.Height)
2278
-
2279
- def GetPixelColorsOfRect(self, x: int, y: int, width: int, height: int) -> ctypes.Array:
2280
- """
2281
- x: int.
2282
- y: int.
2283
- width: int.
2284
- height: int.
2285
- Return `ctypes.Array`, an iterable array of int values in ARGB(0xAARRGGBB) color format of the input rect.
2286
- """
2287
- arrayType = ctypes.c_uint32 * (width * height)
2288
- values = arrayType()
2289
- gdiStatus = _DllClient.instance().dll.BitmapGetPixelsOfRect(ctypes.c_size_t(self._bitmap), x, y, width, height, values)
2290
- return values
2291
-
2292
- def SetPixelColorsOfRect(self, x: int, y: int, width: int, height: int, colors: Sequence[int]) -> bool:
2293
- """
2294
- x: int.
2295
- y: int.
2296
- width: int.
2297
- height: int.
2298
- colors: Sequence[int], a sequence of int values in ARGB(0xAARRGGBB) color format, it's length must equal to width*height,
2299
- use ctypes.Array for better performance, such as `ctypes.c_uint32 * (width*height)`.
2300
- Return bool.
2301
- """
2302
- #assert len(colors) == width * height, 'len(colors) != width * height'
2303
- if not isinstance(colors, ctypes.Array):
2304
- arrayType = ctypes.c_uint32 * (width * height)
2305
- colors = arrayType(*colors)
2306
- gdiStatus = _DllClient.instance().dll.BitmapSetPixelsOfRect(ctypes.c_size_t(self._bitmap), x, y, width, height, colors)
2307
- return gdiStatus == 0
2308
-
2309
- def GetPixelColorsOfRects(self, rects: List[Tuple[int, int, int, int]]) -> List[ctypes.Array]:
2310
- """
2311
- rects: List[Tuple[int, int, int, int]], such as [(0,0,10,10), (10,10,20,20), (x,y,width,height)].
2312
- Return List[ctypes.Array], a list whose elements are ctypes.Array which is an iterable array of
2313
- int values in ARGB(0xAARRGGBB) color format.
2314
- """
2315
- return [self.GetPixelColorsOfRect(x, y, width, height) for x, y, width, height in rects]
2316
-
2317
- def GetAllPixelColors(self) -> ctypes.Array:
2318
- """
2319
- Return `ctypes.Array`, an iterable array of int values in ARGB(0xAARRGGBB) color format.
2320
- """
2321
- return self.GetPixelColorsOfRect(0, 0, self.Width, self.Height)
2322
-
2323
- def SetAllPixelColors(self, colors: Sequence[int]) -> bool:
2324
- """
2325
- colors: Sequence[int], a sequence of int values in ARGB(0xAARRGGBB) color format, it's length must equal to width*height,
2326
- use ctypes.Array for better performance, such as `ctypes.c_uint32 * (width*height)`.
2327
- Return bool.
2328
- """
2329
- return self.SetPixelColorsOfRect(0, 0, self.Width, self.Height, colors)
2330
-
2331
- def Clear(self, color: int = 0xFFFFFFFF, x: int = 0, y: int = 0, width: int = 0, height: int = 0) -> bool:
2332
- """
2333
- Set the color of rect(x,y,width,height).
2334
- color: int, ARGB(0xAARRGGBB) color format.
2335
- x: int.
2336
- y: int.
2337
- width: int, if == 0, the width will be self.Width-x
2338
- height: int, if == 0, the height will be self.Height-y
2339
- Return bool.
2340
- """
2341
- if width == 0:
2342
- width = self.Width - x
2343
- if height == 0:
2344
- height = self.Height - y
2345
- arrayType = ctypes.c_uint * (width * height)
2346
- nativeArray = arrayType(*[color]*(width * height))
2347
- return self.SetPixelColorsOfRect(x, y, width, height, nativeArray)
2348
-
2349
- def Clone(self) -> 'MemoryBMP':
2350
- """
2351
- Return `Bitmap`'s subclass instance.
2352
- The cloned Bitmap's RawFormat is same as original Bitmap.
2353
- If Bitmap is multiple frames, the cloned Bitmap is also multiple frames.
2354
- """
2355
- cbmp = _DllClient.instance().dll.BitmapClone(ctypes.c_size_t(self._bitmap), 0, 0, self._width, self._height)
2356
- return Bitmap._FromGdiplusBitmap(cbmp)
2357
-
2358
- def Copy(self, x: int = 0, y: int = 0, width: int = 0, height: int = 0) -> 'MemoryBMP':
2359
- """
2360
- x: int, must >= 0.
2361
- y: int, must >= 0.
2362
- width: int, must <= self.Width-x.
2363
- height: int, must <= self.Height-y.
2364
- Return `MemoryBMP`, a new Bitmap copied from (x,y,width,height).
2365
- If Bitmap is multiple frames, the cloned Bitmap is only single frame of the active frame.
2366
- """
2367
- if width == 0:
2368
- width = self.Width - x
2369
- if height == 0:
2370
- height = self.Height - y
2371
- nativeArray = self.GetPixelColorsOfRect(x, y, width, height)
2372
- bitmap = MemoryBMP(width, height)
2373
- bitmap.SetPixelColorsOfRect(0, 0, width, height, nativeArray)
2374
- return bitmap
2375
- # cbmp = _DllClient.instance().dll.BitmapClone(ctypes.c_size_t(self._bitmap), x, y, width, height)
2376
- # return Bitmap._FromGdiplusBitmap(cbmp)
2377
-
2378
- def Paste(self, x: int, y: int, bitmap: 'Bitmap') -> bool:
2379
- """
2380
- Paste bitmap to (x,y) of self, modify the original Bitmap,
2381
- if x < 0 or x+bitmap.Width > self.Width, only the intersection part of bitmap is pasted,
2382
- if y < 0 or y+bitmap.Height > self.Height, only the intersection part of bitmap is pasted.
2383
- x: int, can < 0.
2384
- y: int, can < 0.
2385
- bitmap: `Bitmap`.
2386
- Return bool, True if bitmap or a part of bitmap is pasted.
2387
- """
2388
- left, top, right, bottom = max(0, x), max(0, y), min(self.Width, x + bitmap.Width), min(self.Height, y + bitmap.Height)
2389
- width, height = right - left, bottom - top
2390
- if width <= 0 or height <= 0:
2391
- return False
2392
- srcX = 0 if x >= 0 else -x
2393
- srcY = 0 if y >= 0 else -y
2394
- nativeArray = bitmap.GetPixelColorsOfRect(srcX, srcY, width, height)
2395
- return self.SetPixelColorsOfRect(left, top, width, height, nativeArray)
2396
-
2397
- def PastePart(self, dstX: int, dstY: int, srcBitmap: 'Bitmap', srcX: int = 0, srcY: int = 0, srcWidth: int = 0, srcHeight: int = 0) -> bool:
2398
- """
2399
- Paste (srcX, srcY, srcWidth, srcHeight) of bitmap to (dstX, dstY) of self, modify the original Bitmap,
2400
- only the intersection part of the bitmap is pasted.
2401
- dstX: int, must >= 0.
2402
- dstY: int, must >= 0.
2403
- srcBitmap: `Bitmap`.
2404
- srcX: int, must >= 0.
2405
- srcY: int, must >= 0.
2406
- srcWidth: int, must >= 0 and <= srcBitmap.Width - srcX.
2407
- srcHeight: int, must >= 0 and <= srcBitmap.Height - srcY.
2408
- Return bool, True if a part of srcBitmap is pasted.
2409
- """
2410
- if srcWidth == 0:
2411
- srcWidth = srcBitmap.Width - srcX
2412
- if srcHeight == 0:
2413
- srcHeight = srcBitmap.Height - srcY
2414
- left, top, right, bottom = max(0, dstX), max(0, dstY), min(self.Width, dstX + srcWidth), min(self.Height, dstY + srcHeight)
2415
- width, height = right - left, bottom - top
2416
- if width <= 0 or height <= 0:
2417
- return False
2418
- nativeArray = srcBitmap.GetPixelColorsOfRect(srcX, srcY, width, height)
2419
- return self.SetPixelColorsOfRect(dstX, dstY, width, height, nativeArray)
2420
-
2421
- def Resize(self, width: int, height: int) -> 'MemoryBMP':
2422
- """
2423
- Resize a copy of the original to size (width, height), the original Bitmap is not modified.
2424
- width: int.
2425
- height: int.
2426
- Return a new `MemoryBMP`, the original is not modified.
2427
- """
2428
- cbmp = _DllClient.instance().dll.BitmapResize(ctypes.c_size_t(self._bitmap), width, height)
2429
- return Bitmap._FromGdiplusBitmap(cbmp)
2430
-
2431
- def Rotate(self, angle: float, backgroundColor: int = 0xFFFFFFFF) -> 'MemoryBMP':
2432
- """
2433
- Rotate angle degrees clockwise around the center point.
2434
- Return a copy of the original with angle, the original Bitmap is not modified.
2435
- angle: float, closewise.
2436
- backgroundColor: int, ARGB(0xAARRGGBB) color format.
2437
- Return a new `MemoryBMP`, the new Bitmap size may not be the same as the original.
2438
- """
2439
- cbmp = _DllClient.instance().dll.BitmapRotate(ctypes.c_size_t(self._bitmap), ctypes.c_float(angle), backgroundColor)
2440
- return Bitmap._FromGdiplusBitmap(cbmp)
2441
-
2442
- def RotateFlip(self, rotateFlip: int) -> 'MemoryBMP':
2443
- """
2444
- Rotate 90*n or Filp a copy of the original, the original Bitmap is not modified.
2445
- rotateFlip: int, a value in class `RotateFlipType`.
2446
- Return a new `MemoryBMP`, the original is not modified.
2447
- """
2448
- bitmap = self.Copy()
2449
- gdiStatus = _DllClient.instance().dll.BitmapRotateFlip(ctypes.c_size_t(bitmap._bitmap), rotateFlip)
2450
- bitmap._GetSize()
2451
- return bitmap
2452
-
2453
- def RotateWithSameSize(self, dx: float, dy: float, angle: float, backgroundColor: int = 0xFFFFFFFF) -> 'MemoryBMP':
2454
- """
2455
- Rotate angle degrees clockwise around the point (dx, dy) from a copy, the original Bitmap is not modified.
2456
- angle: float, closewise.
2457
- backgroundColor: int, ARGB(0xAARRGGBB) color format.
2458
- Return a new `MemoryBMP`, the original is not modified.
2459
- """
2460
- cbmp = _DllClient.instance().dll.BitmapRotateWithSameSize(ctypes.c_size_t(self._bitmap),
2461
- ctypes.c_float(dx), ctypes.c_float(dy), ctypes.c_float(angle), backgroundColor)
2462
- return Bitmap._FromGdiplusBitmap(cbmp)
2463
-
2464
- def __str__(self) -> str:
2465
- return '{}(Width={}, Height={})'.format(self.__class__.__name__, self._width, self._height)
2466
-
2467
- def __repr__(self) -> str:
2468
- return '<{}(Width={}, Height={}) at 0x{:X}>'.format(self.__class__.__name__, self._width, self._height, id(self))
2469
-
2470
-
2471
- class MultiFrameBitmap(Bitmap):
2472
- def __init__(self, width: int = 0, height: int = 0):
2473
- super().__init__(width, height)
2474
- self._frameCount = 0
2475
- self._index = 0
2476
-
2477
- def SelectActiveFrame(self, index: int) -> bool:
2478
- gdiStatus = _DllClient.instance().dll.MultiBitmapSelectActiveFrame(ctypes.c_size_t(self._bitmap), index)
2479
- return gdiStatus == 0
2480
-
2481
- def GetFrameCount(self) -> int:
2482
- return self._frameCount
2483
-
2484
- def __iter__(self):
2485
- self._index = 0
2486
- return self
2487
-
2488
- def __next__(self) -> Bitmap:
2489
- if self._index < self._frameCount:
2490
- self.SelectActiveFrame(self._index)
2491
- self._GetSize()
2492
- self._index += 1
2493
- return self.Copy()
2494
- else:
2495
- raise StopIteration
2496
-
2497
- def __str__(self) -> str:
2498
- return '{}(Width={}, Height={}, FrameCount={})'.format(self.__class__.__name__, self._width, self._height, self._frameCount)
2499
-
2500
- def __repr__(self) -> str:
2501
- return '<{}(Width={}, Height={}, FrameCount={}) at 0x{:X}>'.format(self.__class__.__name__, self._width, self._height, self._frameCount, id(self))
2502
-
2503
-
2504
- class MemoryBMP(Bitmap):
2505
- pass
2506
-
2507
-
2508
- class BMP(Bitmap):
2509
- pass
2510
-
2511
-
2512
- class JPEG(Bitmap):
2513
- pass
2514
-
2515
-
2516
- class PNG(Bitmap):
2517
- pass
2518
-
2519
-
2520
- class EMF(Bitmap):
2521
- pass
2522
-
2523
-
2524
- class WMF(Bitmap):
2525
- pass
2526
-
2527
-
2528
- class ICON(Bitmap):
2529
- pass
2530
-
2531
-
2532
- class EXIF(Bitmap):
2533
- pass
2534
-
2535
-
2536
- class TIFF(MultiFrameBitmap):
2537
- @staticmethod
2538
- def ToTiffFile(path: str, bitmaps: List['Bitmap']) -> bool:
2539
- '''
2540
- Save a list of bitmaps to a multi frame tiff file.
2541
- path: str, file path.
2542
- bitmaps: List[Bitmap].
2543
- '''
2544
- cbitmaps = (ctypes.c_size_t * len(bitmaps))()
2545
- for i, bmp in enumerate(bitmaps):
2546
- cbitmaps[i] = bmp._bitmap
2547
- gdiStatus = _DllClient.instance().dll.MultiBitmapToFile(cbitmaps, None, len(bitmaps),
2548
- ctypes.c_wchar_p(path), "image/tiff")
2549
- return gdiStatus == 0
2550
-
2551
-
2552
- class GIF(MultiFrameBitmap):
2553
- def __init__(self, width: int = 0, height: int = 0):
2554
- super().__init__(width, height)
2555
- self._frameDelay = ()
2556
-
2557
- def _GetGifDealy(self):
2558
- if self._bitmap:
2559
- delayDataSize = _DllClient.instance().dll.MultiBitmapGetFrameDelaySize(ctypes.c_size_t(self._bitmap))
2560
- delayData = (ctypes.c_byte * delayDataSize)()
2561
- valueOffset = ctypes.c_int()
2562
- gdiStatus = _DllClient.instance().dll.MultiBitmapGetFrameDelay(ctypes.c_size_t(self._bitmap), delayData, delayDataSize, ctypes.byref(valueOffset))
2563
- if gdiStatus == 0:
2564
- valueOffset = valueOffset.value
2565
- # the uint of frame delay is 1/100 second
2566
- self._frameDelay = tuple(10*int.from_bytes(delayData[i:i+4], byteorder='little') for i in range(valueOffset, valueOffset+4*self._frameCount, 4))
2567
-
2568
- def GetFrameDelay(self, index: int) -> int:
2569
- '''
2570
- return frame delay in milliseconds
2571
- '''
2572
- return self._frameDelay[index]
2573
-
2574
- def GetFrameDelays(self) -> List[int]:
2575
- '''
2576
- return a list of frame delays in milliseconds
2577
- '''
2578
- return list(self._frameDelay)
2579
-
2580
- @staticmethod
2581
- def ToGifFile(path: str, bitmaps: List[Bitmap], delays: List[int] = None) -> bool:
2582
- '''
2583
- Save a list of bitmaps to a multi frame gif file.
2584
- path: str, file path.
2585
- bitmaps: List[Bitmap].
2586
- delays: List[int], frame delay time in milliseconds.
2587
- Note: every frame delay must be > 10 ms.
2588
- '''
2589
- assert len(bitmaps) == len(delays)
2590
- blen = len(bitmaps)
2591
- cbitmaps = (ctypes.c_size_t * blen)()
2592
- cdelays = (ctypes.c_uint32 * blen)()
2593
- for i, bmp in enumerate(bitmaps):
2594
- cbitmaps[i] = bmp._bitmap
2595
- cdelays[i] = delays[i] // 10
2596
- gdiStatus = _DllClient.instance().dll.SaveGif(cbitmaps, cdelays, blen, ctypes.c_wchar_p(path))
2597
- return gdiStatus == 0
2598
-
2599
1732
 
2600
1733
  _ClipboardLock = threading.Lock()
2601
1734
 
@@ -2728,49 +1861,6 @@ def SetClipboardHtml(htmlText: str) -> bool:
2728
1861
  return ret
2729
1862
 
2730
1863
 
2731
- def GetClipboardBitmap() -> Optional[Bitmap]:
2732
- with _ClipboardLock:
2733
- if _OpenClipboard(0):
2734
- if ctypes.windll.user32.IsClipboardFormatAvailable(ClipboardFormat.CF_BITMAP):
2735
- hClipboardData = ctypes.windll.user32.GetClipboardData(ClipboardFormat.CF_BITMAP)
2736
- cbmp = _DllClient.instance().dll.BitmapFromHBITMAP(ctypes.c_size_t(hClipboardData), 0, 0, 0, 0)
2737
- bitmap = Bitmap._FromGdiplusBitmap(cbmp)
2738
- ctypes.windll.user32.CloseClipboard()
2739
- return bitmap
2740
- return None
2741
-
2742
-
2743
- def SetClipboardBitmap(bitmap: Bitmap) -> bool:
2744
- """
2745
- Return bool, True if succeed otherwise False.
2746
- """
2747
- ret = False
2748
- with _ClipboardLock:
2749
- if bitmap._bitmap and _OpenClipboard(0):
2750
- ctypes.windll.user32.EmptyClipboard()
2751
- hBitmap = _DllClient.instance().dll.BitmapToHBITMAP(ctypes.c_size_t(bitmap._bitmap), 0xFFFFFFFF)
2752
- hBitmap2 = ctypes.windll.gdi32.CreateBitmap(bitmap.Width, bitmap.Height, 1, 32, 0)
2753
- hdc = ctypes.windll.user32.GetDC(0)
2754
- hdc1 = ctypes.windll.gdi32.CreateCompatibleDC(ctypes.c_void_p(hdc))
2755
- hdc2 = ctypes.windll.gdi32.CreateCompatibleDC(ctypes.c_void_p(hdc))
2756
- ctypes.windll.user32.ReleaseDC(0, ctypes.c_void_p(hdc))
2757
- hOldBmp1 = ctypes.windll.gdi32.SelectObject(ctypes.c_void_p(hdc1), ctypes.c_void_p(hBitmap))
2758
- hOldBmp2 = ctypes.windll.gdi32.SelectObject(ctypes.c_void_p(hdc2), ctypes.c_void_p(hBitmap2))
2759
- ctypes.windll.gdi32.BitBlt(ctypes.c_void_p(hdc2), 0, 0, bitmap.Width, bitmap.Height, ctypes.c_void_p(hdc1), 0, 0, 0x00CC0020) # SRCCOPY
2760
- ctypes.windll.gdi32.SelectObject(ctypes.c_void_p(hdc1), ctypes.c_void_p(hOldBmp1))
2761
- ctypes.windll.gdi32.SelectObject(ctypes.c_void_p(hdc2), ctypes.c_void_p(hOldBmp2))
2762
- ctypes.windll.gdi32.DeleteDC(ctypes.c_void_p(hdc1))
2763
- ctypes.windll.gdi32.DeleteDC(ctypes.c_void_p(hdc2))
2764
- ctypes.windll.gdi32.DeleteObject(ctypes.c_void_p(hBitmap))
2765
- # system owns hClipboardData after calling SetClipboardData,
2766
- # application can not write to or free the data once ownership has been transferred to the system
2767
- if ctypes.windll.user32.SetClipboardData(ctypes.c_uint(ClipboardFormat.CF_BITMAP), ctypes.c_void_p(hBitmap2)):
2768
- ret = True
2769
- else:
2770
- ctypes.windll.gdi32.DeleteObject(ctypes.c_void_p(hBitmap2))
2771
- ctypes.windll.user32.CloseClipboard()
2772
- return ret
2773
-
2774
1864
 
2775
1865
  def Input(prompt: str, consoleColor: int = ConsoleColor.Default) -> str:
2776
1866
  Logger.Write(prompt, consoleColor, writeToFile=False)