def do_print_pdf(hdc, title="PDF Print Test", pdf_data=None): assert pdf_data, "no pdf data" from xpra.log import Logger log = Logger("printing", "win32") log("pdfium=%s", pdfium) buf = c_char_p(pdf_data) log("pdf data buffer: %s", repr_ellipsized(pdf_data)) log("FPDF_InitLibraryWithConfig=%s", FPDF_InitLibraryWithConfig) config = FPDF_LIBRARY_CONFIG() config.m_pUserFontPaths = None config.version = 2 config.m_pIsolate = None config.m_v8EmbedderSlot = 0 FPDF_InitLibraryWithConfig(config) x = 0 y = 0 w = GetDeviceCaps(hdc, win32con.HORZRES) h = GetDeviceCaps(hdc, win32con.VERTRES) rotate = 0 log("printer device size: %ix%i", w, h) flags = FPDF_PRINTING | FPDF_DEBUG_INFO try: doc = FPDF_LoadMemDocument(cast(buf, c_void_p), len(pdf_data), None) if not doc: log.error("Error: FPDF_LoadMemDocument failed, error: %s", get_error()) return -1 log("FPDF_LoadMemDocument(..)=%s", doc) count = FPDF_GetPageCount(doc) log("FPDF_GetPageCount(%s)=%s", doc, count) docinfo = DOCINFO() docinfo.lpszDocName = LPCSTR("%s\0" % title) jobid = StartDocA(hdc, pointer(docinfo)) if jobid < 0: log.error("Error: StartDocA failed: %i", jobid) return jobid log("StartDocA()=%i", jobid) try: for i in range(count): page = FPDF_LoadPage(doc, i) if not page: log.error( "Error: FPDF_LoadPage failed for page %i, error: %s", i, get_error()) return -2 log("FPDF_LoadPage()=%s page %i loaded", page, i) FPDF_RenderPage(hdc, page, x, y, w, h, rotate, flags) log("FPDF_RenderPage page %i rendered", i) finally: EndDoc(hdc) finally: FPDF_DestroyLibrary() return jobid
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 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
def get_image(self, x=0, y=0, width=0, height=0): start = time.time() x, y, width, height = self.get_capture_coords(x, y, width, height) if not self.dc: self.wnd = GetDesktopWindow() if not self.wnd: log.error("Error: cannot access the desktop window") log.error(" capturing the screen is not possible") return None self.dc = GetWindowDC(self.wnd) if not self.dc: log.error("Error: cannot get a drawing context") log.error(" capturing the screen is not possible") log.error(" desktop window=%#x", self.wnd) return None 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) if not bitmap: log.error("Error: failed to get a compatible bitmap") log.error(" from drawing context %#x with size %ix%i", self.dc, width, height) self.clean_dc() return None r = SelectObject(self.memdc, bitmap) if not r: 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 with BitBlt") log.error(" %s", e) self.clean_dc() 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 not r: log.error("Error: failed to copy screen bitmap data") self.clean_dc() 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" rgb_format = RGB_FORMATS.get(self.bit_depth) if not rgb_format: 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: palette = get_palette(self.dc) v.set_palette(palette) log("get_image%s=%s took %ims", (x, y, width, height), v, (time.time() - start) * 1000) return v