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_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 create_wgl_context(self, hwnd): bpc = 8 self.hwnd = hwnd self.pixel_format_props = {} self.hdc = GetDC(hwnd) log("create_wgl_context(%#x) hdc=%#x", hwnd, self.hdc) flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DEPTH_DONTCARE if self.alpha: flags |= PFD_SUPPORT_COMPOSITION if DOUBLE_BUFFERED: flags |= PFD_DOUBLEBUFFER pfd = PIXELFORMATDESCRIPTOR() pfd.nsize = sizeof(PIXELFORMATDESCRIPTOR) pfd.nVersion = 1 pfd.dwFlags = flags pfd.iPixelType = PFD_TYPE_RGBA pfd.cColorBits = bpc * (3 + int(self.alpha)) pfd.cRedBits = bpc pfd.cRedShift = 0 pfd.cGreenBits = bpc pfd.cGreenShift = 0 pfd.cBlueBits = bpc pfd.cBlueShift = 0 pfd.cAlphaBits = int(self.alpha) * 8 pfd.cAlphaShift = 0 pfd.cAccumBits = 0 pfd.cAccumRedBits = 0 pfd.cAccumGreenBits = 0 pfd.cAccumBlueBits = 0 pfd.cAccumAlphaBits = 0 pfd.cDepthBits = 24 pfd.cStencilBits = 2 pfd.cAuxBuffers = 0 pfd.iLayerType = PFD_MAIN_PLANE #ignored pfd.bReserved = 0 pfd.dwLayerMask = 0 pfd.dwVisibleMask = 0 pfd.dwDamageMask = 0 pf = ChoosePixelFormat(self.hdc, byref(pfd)) log("ChoosePixelFormat for window %#x and %i bpc: %#x", hwnd, bpc, pf) if not SetPixelFormat(self.hdc, pf, byref(pfd)): raise Exception("SetPixelFormat failed") if not DescribePixelFormat(self.hdc, pf, sizeof(PIXELFORMATDESCRIPTOR), byref(pfd)): raise Exception("DescribePixelFormat failed") self.pixel_format_props.update({ "rgba": pfd.iPixelType == PFD_TYPE_RGBA, "depth": pfd.cColorBits, "red-size": pfd.cRedBits, "green-size": pfd.cGreenBits, "blue-size": pfd.cBlueBits, "alpha-size": pfd.cAlphaBits, "red-shift": pfd.cRedShift, "green-shift": pfd.cGreenShift, "blue-shift": pfd.cBlueShift, "alpha-shift": pfd.cAlphaShift, "accum-red-size": pfd.cAccumRedBits, "accum-green-size": pfd.cAccumGreenBits, "accum-blue-size": pfd.cAccumBlueBits, "accum-size": pfd.cAccumBits, "depth-size": pfd.cDepthBits, "stencil-size": pfd.cStencilBits, "aux-buffers": pfd.cAuxBuffers, "visible-mask": int(pfd.dwVisibleMask), "double-buffered": bool(pfd.dwFlags & PFD_DOUBLEBUFFER) }) log("DescribePixelFormat: %s", self.pixel_format_props) context = wglCreateContext(self.hdc) assert context, "wglCreateContext failed" log("wglCreateContext(%#x)=%#x", self.hdc, context) return context
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)