def rgb_to_bitmap(rgb_data, bytes_per_pixel: int, w: int, h: int): log("rgb_to_bitmap%s", (rgb_data, bytes_per_pixel, w, h)) assert bytes_per_pixel in (3, 4) #only BGRA or BGR are supported assert w > 0 and h > 0 header = BITMAPV5HEADER() header.bV5Size = sizeof(BITMAPV5HEADER) header.bV5Width = w header.bV5Height = -h header.bV5Planes = 1 header.bV5BitCount = bytes_per_pixel * 8 header.bV5Compression = BI_RGB #BI_BITFIELDS #header.bV5RedMask = 0x000000ff #header.bV5GreenMask = 0x0000ff00 #header.bV5BlueMask = 0x00ff0000 #header.bV5AlphaMask = 0xff000000 bitmap = 0 try: hdc = GetDC(None) dataptr = c_void_p() log("GetDC()=%#x", hdc) bitmap = CreateDIBSection(hdc, byref(header), win32con.DIB_RGB_COLORS, byref(dataptr), None, 0) finally: ReleaseDC(None, hdc) if not dataptr or not bitmap: raise ctypes.WinError(ctypes.get_last_error()) log("CreateDIBSection(..) got bitmap=%#x, dataptr=%s", int(bitmap), dataptr) img_data = create_string_buffer(rgb_data) ctypes.memmove(dataptr, byref(img_data), w * h * bytes_per_pixel) return bitmap
def rgba_to_bitmap(rgba, w, h): header = BITMAPV5HEADER() header.bV5Size = sizeof(BITMAPV5HEADER) header.bV5Width = w header.bV5Height = -h header.bV5Planes = 1 header.bV5BitCount = 32 header.bV5Compression = BI_RGB #BI_BITFIELDS #header.bV5RedMask = 0x000000ff #header.bV5GreenMask = 0x0000ff00 #header.bV5BlueMask = 0x00ff0000 #header.bV5AlphaMask = 0xff000000 bitmap = 0 try: hdc = GetDC(None) dataptr = c_void_p() log("GetDC()=%#x", hdc) bitmap = CreateDIBSection(hdc, byref(header), win32con.DIB_RGB_COLORS, byref(dataptr), None, 0) finally: ReleaseDC(None, hdc) assert dataptr and bitmap, "failed to create DIB section" log("CreateDIBSection(..) got bitmap=%#x, dataptr=%s", int(bitmap), dataptr) img_data = create_string_buffer(rgba) ctypes.memmove(dataptr, byref(img_data), w * 4 * h) return bitmap
def get_desktop_bit_depth(): desktop_wnd = GetDesktopWindow() dc = GetWindowDC(desktop_wnd) assert dc, "failed to get a drawing context from the desktop window %s" % desktop_wnd bit_depth = GetDeviceCaps(dc, win32con.BITSPIXEL) log("get_desktop_bit_depth()=%i", bit_depth) ReleaseDC(desktop_wnd, dc) return bit_depth
def _get_device_caps(constant): dc = None try: dc = GetDC(None) return GetDeviceCaps(dc, constant) finally: if dc: ReleaseDC(None, dc)
def set_clipboard_image(self, img_format, img_data): image_formats = {} if COMPRESSED_IMAGES: #first save it as binary compressed data: fmt_name = LPCSTR(img_format.upper().encode("latin1")+b"\0") #ie: "PNG" fmt = RegisterClipboardFormatA(fmt_name) if fmt: buf = create_string_buffer(img_data) pbuf = cast(byref(buf), c_void_p) l = len(img_data) data_handle = GlobalAlloc(GMEM_MOVEABLE, l) if not data_handle: log.error("Error: failed to allocate %i bytes of global memory", l) return True data = GlobalLock(data_handle) if not data: log("failed to lock data handle %#x (may try again)", data_handle) return False log("got data handle lock %#x for %i bytes of '%s' data", data, l, img_format) try: memmove(data, pbuf, l) finally: GlobalUnlock(data) image_formats[fmt] = data_handle #also convert it to a bitmap: from PIL import Image buf = BytesIO(img_data) img = Image.open(buf) if img.mode!="RGBA": img = img.convert("RGBA") rgb_data = img.tobytes("raw", "BGRA") w, h = img.size log("set_clipboard_image(%s, %s) image size=%s, BGR buffer=%i bytes", img_format, ellipsizer(data), img.size, len(rgb_data)) header = BITMAPINFOHEADER() memset(byref(header), 0, sizeof(BITMAPINFOHEADER )) header.biSize = sizeof(BITMAPINFOHEADER) header.biWidth = w header.biHeight = -h header.biPlanes = 1 header.biBitCount = 32 header.biCompression = BI_RGB header.biSizeImage = 0 header.biXPelsPerMeter = 10 header.biYPelsPerMeter = 10 bitmapinfo = BITMAPINFO() bitmapinfo.bmiColors = 0 memmove(byref(bitmapinfo.bmiHeader), byref(header), sizeof(BITMAPINFOHEADER)) rgb_buf = create_string_buffer(rgb_data) pbuf = cast(byref(rgb_buf), c_void_p) hdc = GetDC(None) CBM_INIT = 4 bitmap = CreateDIBitmap(hdc, byref(header), CBM_INIT, pbuf, byref(bitmapinfo), win32con.DIB_RGB_COLORS) ReleaseDC(None, hdc) image_formats[win32con.CF_BITMAP] = bitmap self.do_set_clipboard_image(image_formats)
def clean_dc(self): dc = self.dc wnd = self.wnd if dc and wnd: self.dc = None self.wnd = None ReleaseDC(wnd, dc) memdc = self.memdc if memdc: self.memdc = None DeleteDC(memdc)
def cleanup(self): if self.disabled_dwm_composition: set_dwm_composition(DWM_EC_ENABLECOMPOSITION) dc = self.dc if dc: self.dc = None ReleaseDC(dc) memdc = self.memdc if memdc: self.memdc = None DeleteDC(memdc)
def clean(self): if self.disabled_dwm_composition: set_dwm_composition(DWM_EC_ENABLECOMPOSITION) dc = self.dc wnd = self.wnd if dc and wnd: self.dc = None self.wnd = None ReleaseDC(wnd, dc) memdc = self.memdc if memdc: self.memdc = None DeleteDC(memdc)
def get_cursor_data(hCursor): #w, h = get_fixed_cursor_size() if not hCursor: return None x, y = 0, 0 dc = None memdc = None bitmap = None old_handle = None pixels = None try: ii = ICONINFO() ii.cbSize = sizeof(ICONINFO) if not GetIconInfo(hCursor, byref(ii)): raise WindowsError() #@UndefinedVariable x = ii.xHotspot y = ii.yHotspot cursorlog( "get_cursor_data(%#x) hotspot at %ix%i, hbmColor=%#x, hbmMask=%#x", hCursor, x, y, ii.hbmColor or 0, ii.hbmMask or 0) if not ii.hbmColor: #FIXME: we don't handle black and white cursors return None iie = ICONINFOEXW() iie.cbSize = sizeof(ICONINFOEXW) if not GetIconInfoExW(hCursor, byref(iie)): raise WindowsError() #@UndefinedVariable name = iie.szResName[:MAX_PATH] cursorlog("wResID=%#x, sxModName=%s, szResName=%s", iie.wResID, iie.sxModName[:MAX_PATH], name) bm = Bitmap() if not GetObjectA(ii.hbmColor, sizeof(Bitmap), byref(bm)): raise WindowsError() #@UndefinedVariable cursorlog( "cursor bitmap: type=%i, width=%i, height=%i, width bytes=%i, planes=%i, bits pixel=%i, bits=%#x", bm.bmType, bm.bmWidth, bm.bmHeight, bm.bmWidthBytes, bm.bmPlanes, bm.bmBitsPixel, bm.bmBits or 0) w = bm.bmWidth h = bm.bmHeight dc = GetDC(None) assert dc, "failed to get a drawing context" memdc = CreateCompatibleDC(dc) assert memdc, "failed to get a compatible drawing context from %s" % dc bitmap = CreateCompatibleBitmap(dc, w, h) assert bitmap, "failed to get a compatible bitmap from %s" % dc old_handle = SelectObject(memdc, bitmap) #check if icon is animated: UINT_MAX = 2**32 - 1 if not DrawIconEx(memdc, 0, 0, hCursor, w, h, UINT_MAX, 0, 0): cursorlog("cursor is animated!") #if not DrawIcon(memdc, 0, 0, hCursor): if not DrawIconEx(memdc, 0, 0, hCursor, w, h, 0, 0, win32con.DI_NORMAL): raise WindowsError() #@UndefinedVariable buf_size = bm.bmWidthBytes * h buf = create_string_buffer(b"", buf_size) r = GetBitmapBits(bitmap, buf_size, byref(buf)) cursorlog("get_cursor_data(%#x) GetBitmapBits(%#x, %#x, %#x)=%i", hCursor, bitmap, buf_size, addressof(buf), r) if not r: cursorlog.error("Error: failed to copy screen bitmap data") return None elif r != buf_size: cursorlog.warn( "Warning: invalid cursor buffer size, got %i bytes but expected %i", r, buf_size) return None else: #32-bit data: pixels = bytearray(strtobytes(buf.raw)) has_alpha = False has_pixels = False for i in range(len(pixels) // 4): has_pixels = has_pixels or pixels[i * 4] != 0 or pixels[ i * 4 + 1] != 0 or pixels[i * 4 + 2] != 0 has_alpha = has_alpha or pixels[i * 4 + 3] != 0 if has_pixels and has_alpha: break if has_pixels and not has_alpha: #generate missing alpha - don't ask me why for i in range(len(pixels) // 4): if pixels[i * 4] != 0 or pixels[i * 4 + 1] != 0 or pixels[i * 4 + 2] != 0: pixels[i * 4 + 3] = 0xff return [0, 0, w, h, x, y, hCursor, bytes(pixels), strtobytes(name)] except Exception as e: cursorlog("get_cursor_data(%#x)", hCursor, exc_info=True) cursorlog.error("Error: failed to grab cursor:") cursorlog.error(" %s", str(e) or type(e)) return None finally: if old_handle: SelectObject(memdc, old_handle) if bitmap: DeleteObject(bitmap) if memdc: DeleteDC(memdc) if dc: ReleaseDC(None, dc)