def paint_webp(self, img_data, x, y, width, height, options, callbacks): if not self.webp_decoder or WEBP_PILLOW: #if webp is enabled, then Pillow should be able to take care of it: return self.paint_image("webp", img_data, x, y, width, height, options, callbacks) rgb_format = options.strget("rgb_format") has_alpha = options.boolget("has_alpha", False) buffer_wrapper, width, height, stride, has_alpha, rgb_format = self.webp_decoder.decompress(img_data, has_alpha, rgb_format, self.RGB_MODES) def free_buffer(*_args): buffer_wrapper.free() callbacks.append(free_buffer) data = buffer_wrapper.get_pixels() #if the backing can't handle this format, #ie: tray only supports RGBA if rgb_format not in self.RGB_MODES: from xpra.codecs.rgb_transform import rgb_reformat from xpra.codecs.image_wrapper import ImageWrapper img = ImageWrapper(x, y, width, height, data, rgb_format, len(rgb_format)*8, stride, len(rgb_format), ImageWrapper.PACKED, True, None) #log("rgb_reformat(%s, %s, %s) %i bytes", img, self.RGB_MODES, has_alpha and self._alpha_enabled, len(img_data)) rgb_reformat(img, self.RGB_MODES, has_alpha and self._alpha_enabled) rgb_format = img.get_pixel_format() data = img.get_pixels() stride = img.get_rowstride() #replace with the actual rgb format we get from the decoder: options[b"rgb_format"] = rgb_format return self.paint_rgb(rgb_format, data, x, y, width, height, stride, options, callbacks)
def get_image(self, x, y, width, height): image = None if not self.capture: self.capture = setup_capture(self.window) assert self.capture, "no capture method available" ox, oy = self.geometry[:2] image = image or self.capture.get_image(ox + x, oy + y, width, height) if ox > 0 or oy > 0: #all we want to do here is adjust x and y... #FIXME: this is inefficient and may take a copy of the pixels: # but the XImageCapture cannot share buffers, so adjusting coordinates is not enough image = ImageWrapper(x, y, width, height, image.get_pixels(), image.get_pixel_format(), image.get_depth(), image.get_rowstride(), image.get_bytesperpixel(), image.get_planes(), thread_safe=True, palette=None) return image
def test_sub_image(self): X = 0 Y = 0 W = 640 H = 480 D = 24 buf = bytearray(W * H * 4) #the pixel value is derived from the sum of its coordinates (modulo 256) for x in range(W): for y in range(H): #4 bytes per pixel: for i in range(4): buf[y * (W * 4) + x * 4 + i] = (x + y) % 256 img = ImageWrapper(X, Y, W, H, buf, "RGBX", D, W * 4, planes=ImageWrapper.PACKED, thread_safe=True) #verify attributes: assert img.get_x() == X assert img.get_y() == Y assert img.get_target_x() == X assert img.get_target_y() == Y assert img.get_width() == W assert img.get_height() == H assert img.get_depth() == D assert img.get_bytesperpixel() == 4 assert img.get_rowstride() == W * 4 assert img.get_size() == W * 4 * H assert img.has_pixels() assert len(img.get_geometry()) == 5 assert img.get_pixel_format() == "RGBX" assert img.get_planes() == ImageWrapper.PACKED #print("image pixels head=%s" % (binascii.hexlify(img.get_pixels()[:128]), )) for x in range(3): SW, SH = 6, 6 sub = img.get_sub_image(x, 0, SW, SH) #print("%s.get_sub_image%s=%s" % (img, (x, 0, SW, SH), sub)) #this is only true for the pure python ImageWrapper: #(the X11 image wrapper references the same underlying XShm pixels, with the same rowstride) assert sub.get_rowstride() == (SW * 4) sub_buf = sub.get_pixels() #print("pixels for %ix%i: %i" % (SW, SH, len(sub_buf))) #print("pixels=%s" % (binascii.hexlify(sub_buf), )) #verify that the pixels are set to 1 / 0: for y in range(SH): v = (x + y) % 256 for i in range(4): av = sub_buf[y * (SW * 4) + i] if av != v: raise Exception("""expected value %#x for pixel (0, %i) of sub-image %s at (%i, 0), but got %#x""" % (v, y, sub, x, av)) start = monotonic_time() copy = img.get_sub_image(0, 0, W, H) end = monotonic_time() if SHOW_PERF: print("image wrapper full %ix%i copy speed: %iMB/s" % (W, H, (W * 4 * H) / (end - start) / 1024 / 1024)) assert copy.get_pixels() == img.get_pixels() total = 0 N = 10 for i in range(N): region = (W // 4 - N // 2 + i, H // 4 - N // 2 + i, W // 2, H // 2) start = monotonic_time() copy = img.get_sub_image(*region) end = monotonic_time() total += end - start if SHOW_PERF: print("image wrapper sub image %ix%i copy speed: %iMB/s" % (W // 2, H // 2, N * (W // 2 * 4 * H // 2) / total / 1024 / 1024)) #invalid sub-image should fail: for x, y, w, h in ( (-1, 0, 1, 1), (0, -1, 1, 1), (0, 0, 0, 1), (0, 0, 1, 0), (1, 0, W, 1), (0, 1, 1, H), ): try: img.get_sub_image(x, y, w, h) except Exception: pass else: raise Exception( "sub image of %s with coords %s should have failed" % (img, (x, y, w, h))) #freeze is a no-op in the default wrapper: assert img.freeze() is False img.clone_pixel_data()