def get_image(self, x, y, width, height, logger=None): start = time.time() desktop_wnd = win32gui.GetDesktopWindow() metrics = get_virtualscreenmetrics() if self.metrics is None or self.metrics != metrics: #new metrics, start from scratch: self.metrics = metrics self.ddc, self.cdc, self.memdc, self.bitmap = None, None, None, None dx, dy, dw, dh = metrics #clamp rectangle requested to the virtual desktop size: if x < dx: width -= x - dx x = dx if y < dy: height -= y - dy y = dy if width > dw: width = dw if height > dh: height = dh try: if not self.ddc: self.ddc = win32gui.GetWindowDC(desktop_wnd) assert self.ddc, "cannot get a drawing context from the desktop window %s" % desktop_wnd self.cdc = win32ui.CreateDCFromHandle(self.ddc) assert self.cdc, "cannot get a compatible drawing context from the desktop drawing context %s" % self.ddc self.memdc = self.cdc.CreateCompatibleDC() self.bitmap = win32ui.CreateBitmap() self.bitmap.CreateCompatibleBitmap(self.cdc, width, height) self.memdc.SelectObject(self.bitmap) select_time = time.time() log("get_image up to SelectObject took %ims", (select_time - start) * 1000) self.memdc.BitBlt((0, 0), (width, height), self.cdc, (x, y), win32con.SRCCOPY) bitblt_time = time.time() log("get_image BitBlt took %ims", (bitblt_time - select_time) * 1000) pixels = self.bitmap.GetBitmapBits(True) log("get_image GetBitmapBits took %ims", (time.time() - bitblt_time) * 1000) finally: pass assert pixels, "no pixels returned from GetBitmapBits" v = ImageWrapper(0, 0, width, height, pixels, "BGRX", 24, width * 4, planes=ImageWrapper.PACKED, thread_safe=True) if logger == None: logger = log log("get_image%s=%s took %ims", (x, y, width, height), v, (time.time() - start) * 1000) return v
def take_screenshot(self): from PIL import Image #@UnresolvedImport x, y, w, h = get_virtualscreenmetrics() image = self.get_image(x, y, w, h) assert image.get_width()==w and image.get_height()==h assert image.get_pixel_format()=="BGRX" img = Image.frombuffer("RGB", (w, h), image.get_pixels(), "raw", "BGRX", 0, 1) out = StringIOClass() img.save(out, format="PNG") screenshot = (img.width, img.height, "png", img.width*3, out.getvalue()) out.close() return screenshot
def take_screenshot(self): x, y, w, h = get_virtualscreenmetrics() image = self.get_image(x, y, w, h) if not image: return None assert image.get_width()==w and image.get_height()==h assert image.get_pixel_format()=="BGRX" img = Image.frombuffer("RGB", (w, h), image.get_pixels(), "raw", "BGRX", 0, 1) out = BytesIOClass() img.save(out, format="PNG") screenshot = (img.width, img.height, "png", img.width*3, out.getvalue()) out.close() return screenshot
def get_image(self, x, y, width, height, logger=None): start = time.time() desktop_wnd = win32gui.GetDesktopWindow() metrics = get_virtualscreenmetrics() if self.metrics is None or self.metrics!=metrics: #new metrics, start from scratch: self.metrics = metrics self.ddc, self.cdc, self.memdc, self.bitmap = None, None, None, None dx, dy, dw, dh = metrics #clamp rectangle requested to the virtual desktop size: if x<dx: width -= x-dx x = dx if y<dy: height -= y-dy y = dy if width>dw: width = dw if height>dh: height = dh try: if not self.ddc: self.ddc = win32gui.GetWindowDC(desktop_wnd) assert self.ddc, "cannot get a drawing context from the desktop window %s" % desktop_wnd self.cdc = win32ui.CreateDCFromHandle(self.ddc) assert self.cdc, "cannot get a compatible drawing context from the desktop drawing context %s" % self.ddc self.memdc = self.cdc.CreateCompatibleDC() self.bitmap = win32ui.CreateBitmap() self.bitmap.CreateCompatibleBitmap(self.cdc, width, height) self.memdc.SelectObject(self.bitmap) select_time = time.time() log("get_image up to SelectObject took %ims", (select_time-start)*1000) self.memdc.BitBlt((0, 0), (width, height), self.cdc, (x, y), win32con.SRCCOPY) bitblt_time = time.time() log("get_image BitBlt took %ims", (bitblt_time-select_time)*1000) pixels = self.bitmap.GetBitmapBits(True) log("get_image GetBitmapBits took %ims", (time.time()-bitblt_time)*1000) finally: pass assert pixels, "no pixels returned from GetBitmapBits" v = ImageWrapper(0, 0, width, height, pixels, "BGRX", 24, width*4, planes=ImageWrapper.PACKED, thread_safe=True) if logger==None: logger = log log("get_image%s=%s took %ims", (x, y, width, height), v, (time.time()-start)*1000) return v
def get_capture_coords(self, x, y, width, height): metrics = get_virtualscreenmetrics() if self.metrics is None or self.metrics != metrics: #new metrics, start from scratch: self.metrics = metrics self.clean() log("get_image%s metrics=%s", (x, y, width, height), metrics) dx, dy, dw, dh = metrics if width == 0: width = dw if height == 0: height = dh #clamp rectangle requested to the virtual desktop size: if x < dx: width -= x - dx x = dx if y < dy: height -= y - dy y = dy if width > dw: width = dw if height > dh: height = dh return x, y, width, height
def get_image(self, x=0, y=0, width=0, height=0): start = time.time() metrics = get_virtualscreenmetrics() if self.metrics is None or self.metrics != metrics: #new metrics, start from scratch: self.metrics = metrics self.clean() log("get_image%s metrics=%s", (x, y, width, height), metrics) dx, dy, dw, dh = metrics if width == 0: width = dw if height == 0: height = dh #clamp rectangle requested to the virtual desktop size: if x < dx: width -= x - dx x = dx if y < dy: height -= y - dy y = dy if width > dw: width = dw if height > dh: height = dh if not self.dc: self.wnd = GetDesktopWindow() self.dc = GetWindowDC(self.wnd) assert self.dc, "failed to get a drawing context from the desktop window %s" % self.wnd self.bit_depth = GetDeviceCaps(self.dc, win32con.BITSPIXEL) self.memdc = CreateCompatibleDC(self.dc) assert self.memdc, "failed to get a compatible drawing context from %s" % self.dc bitmap = CreateCompatibleBitmap(self.dc, width, height) assert bitmap, "failed to get a compatible bitmap from %s" % self.dc r = SelectObject(self.memdc, bitmap) if r == 0: log.error("Error: cannot select bitmap object") return None select_time = time.time() log("get_image up to SelectObject (%s) took %ims", REGION_CONSTS.get(r, r), (select_time - start) * 1000) try: if BitBlt(self.memdc, 0, 0, width, height, self.dc, x, y, win32con.SRCCOPY) == 0: e = ctypes.get_last_error() #rate limit the error message: now = time.time() if now - self.bitblt_err_time > 10: log.error("Error: failed to blit the screen, error %i", e) self.bitblt_err_time = now return None except Exception as e: log("BitBlt error", exc_info=True) log.error("Error: cannot capture screen") log.error(" %s", e) return None bitblt_time = time.time() log("get_image BitBlt took %ims", (bitblt_time - select_time) * 1000) rowstride = roundup(width * self.bit_depth // 8, 2) buf_size = rowstride * height pixels = ctypes.create_string_buffer(b"", buf_size) log("GetBitmapBits(%#x, %#x, %#x)", bitmap, buf_size, ctypes.addressof(pixels)) r = GetBitmapBits(bitmap, buf_size, ctypes.byref(pixels)) if r == 0: log.error("Error: failed to copy screen bitmap data") return None if r != buf_size: log.warn( "Warning: truncating pixel buffer, got %i bytes but expected %i", r, buf_size) pixels = pixels[:r] log("get_image GetBitmapBits took %ims", (time.time() - bitblt_time) * 1000) DeleteObject(bitmap) assert pixels, "no pixels returned from GetBitmapBits" if self.bit_depth == 32: rgb_format = "BGRX" elif self.bit_depth == 30: rgb_format = "r210" elif self.bit_depth == 24: rgb_format = "BGR" elif self.bit_depth == 16: rgb_format = "BGR565" elif self.bit_depth == 8: rgb_format = "RLE8" else: raise Exception("unsupported bit depth: %s" % self.bit_depth) bpp = self.bit_depth // 8 v = ImageWrapper(0, 0, width, height, pixels, rgb_format, self.bit_depth, rowstride, bpp, planes=ImageWrapper.PACKED, thread_safe=True) if self.bit_depth == 8: count = GetSystemPaletteEntries(self.dc, 0, 0, None) log("palette size: %s", count) palette = [] if count > 0: buf = (PALETTEENTRY * count)() r = GetSystemPaletteEntries(self.dc, 0, count, ctypes.byref(buf)) #we expect 16-bit values, so bit-shift them: for p in buf: palette.append( (p.peRed << 8, p.peGreen << 8, p.peBlue << 8)) v.set_palette(palette) log("get_image%s=%s took %ims", (x, y, width, height), v, (time.time() - start) * 1000) return v