Skip to content

Commit

Permalink
#1247 refactor screenshot code so we can re-use it in the desktop server
Browse files Browse the repository at this point in the history
git-svn-id: https://xpra.org/svn/Xpra/trunk@13578 3bb7dfac-3a0b-4e04-842a-767bc560f471
  • Loading branch information
totaam committed Sep 6, 2016
1 parent 83e349c commit 7ffd674
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 43 deletions.
36 changes: 36 additions & 0 deletions src/xpra/x11/desktop_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
X11Window = X11WindowBindings()
from xpra.x11.bindings.keyboard_bindings import X11KeyboardBindings #@UnresolvedImport
X11Keyboard = X11KeyboardBindings()
from xpra.gtk_common.error import xsync

from xpra.log import Logger
log = Logger("server")
Expand Down Expand Up @@ -374,4 +375,39 @@ def init_dbus_server(self):
log.error(" %s", e)


def do_make_screenshot_packet(self):
log.enable_debug()
log("grabbing screenshot")
regions = []
offset_x, offset_y = 0, 0
for wid in reversed(sorted(self._id_to_window.keys())):
window = self._id_to_window.get(wid)
log("screenshot: window(%s)=%s", wid, window)
if window is None:
continue
if not window.is_managed():
log("screenshot: window %s is not/no longer managed", wid)
continue
x, y, w, h = window.get_geometry()
log("screenshot: geometry(%s)=%s", window, (x, y, w, h))
try:
with xsync:
img = window.get_image(0, 0, w, h)
except:
log.warn("screenshot: window %s could not be captured", wid)
continue
if img is None:
log.warn("screenshot: no pixels for window %s", wid)
continue
log("screenshot: image=%s, size=%s", img, img.get_size())
if img.get_pixel_format() not in ("RGB", "RGBA", "XRGB", "BGRX", "ARGB", "BGRA"):
log.warn("window pixels for window %s using an unexpected rgb format: %s", wid, img.get_pixel_format())
continue
regions.append((wid, offset_x+x, offset_y+y, img))
#tile them horizontally:
offset_x += w
offset_y += 0
return self.make_screenshot_packet_from_regions(regions)


gobject.type_register(XpraDesktopServer)
46 changes: 3 additions & 43 deletions src/xpra/x11/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from collections import deque

from xpra.util import AdHocStruct, updict, rindex, iround
from xpra.os_util import memoryview_to_bytes, _memoryview
from xpra.os_util import memoryview_to_bytes
from xpra.gtk_common.gobject_util import one_arg_signal
from xpra.gtk_common.gtk_util import get_default_root_window, get_xwindow
from xpra.x11.xsettings import XSettingsManager, XSettingsHelper
Expand Down Expand Up @@ -54,9 +54,7 @@

import xpra
from xpra.util import nonl, typedict
from xpra.os_util import StringIOClass
from xpra.x11.x11_server_base import X11ServerBase, mouselog
from xpra.net.compression import Compressed

REPARENT_ROOT = os.environ.get("XPRA_REPARENT_ROOT", "0")=="1"
SCALED_FONT_ANTIALIAS = os.environ.get("XPRA_SCALED_FONT_ANTIALIAS", "0")=="1"
Expand Down Expand Up @@ -1078,7 +1076,7 @@ def do_make_screenshot_packet(self):
if img is None:
log.warn("screenshot: no pixels for window %s", wid)
continue
log("screenshot: image=%s, size=%s", (img, img.get_size()))
log("screenshot: image=%s, size=%s", img, img.get_size())
if img.get_pixel_format() not in ("RGB", "RGBA", "XRGB", "BGRX", "ARGB", "BGRA"):
log.warn("window pixels for window %s using an unexpected rgb format: %s", wid, img.get_pixel_format())
continue
Expand All @@ -1090,46 +1088,8 @@ def do_make_screenshot_packet(self):
regions.insert(0, item)
else:
regions.append(item)
all_regions = OR_regions+regions
if len(all_regions)==0:
log("screenshot: no regions found, returning empty 0x0 image!")
return ["screenshot", 0, 0, "png", -1, ""]
log("screenshot: found regions=%s, OR_regions=%s", len(regions), len(OR_regions))
#in theory, we could run the rest in a non-UI thread since we're done with GTK..
minx = min([x for (_,x,_,_) in all_regions])
miny = min([y for (_,_,y,_) in all_regions])
maxx = max([(x+img.get_width()) for (_,x,_,img) in all_regions])
maxy = max([(y+img.get_height()) for (_,_,y,img) in all_regions])
width = maxx-minx
height = maxy-miny
log("screenshot: %sx%s, min x=%s y=%s", width, height, minx, miny)
from PIL import Image #@UnresolvedImport
screenshot = Image.new("RGBA", (width, height))
for wid, x, y, img in reversed(all_regions):
pixel_format = img.get_pixel_format()
target_format = {
"XRGB" : "RGB",
"BGRX" : "RGB",
"BGRA" : "RGBA"}.get(pixel_format, pixel_format)
pixels = img.get_pixels()
#PIL cannot use the memoryview directly:
if _memoryview and isinstance(pixels, _memoryview):
pixels = pixels.tobytes()
try:
window_image = Image.frombuffer(target_format, (w, h), pixels, "raw", pixel_format, img.get_rowstride())
except:
log.error("Error parsing window pixels in %s format", pixel_format, exc_info=True)
continue
tx = x-minx
ty = y-miny
screenshot.paste(window_image, (tx, ty))
buf = StringIOClass()
screenshot.save(buf, "png")
data = buf.getvalue()
buf.close()
packet = ["screenshot", width, height, "png", width*4, Compressed("png", data)]
log("screenshot: %sx%s %s", packet[1], packet[2], packet[-1])
return packet
return self.make_screenshot_packet_from_regions(OR_regions+regions)


def reset_settings(self):
Expand Down
48 changes: 48 additions & 0 deletions src/xpra/x11/x11_server_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
from xpra.gtk_common.gtk_util import get_xwindow
from xpra.server.server_uuid import save_uuid, get_uuid
from xpra.x11.fakeXinerama import find_libfakeXinerama, save_fakeXinerama_config, cleanup_fakeXinerama
from xpra.os_util import StringIOClass, _memoryview
from xpra.net.compression import Compressed


from xpra.log import Logger
log = Logger("x11", "server")
Expand Down Expand Up @@ -651,3 +654,48 @@ def _process_button_action(self, proto, packet):
if button>=4:
err += " (perhaps your Xvfb does not support mousewheels?)"
log.warn(err)


def make_screenshot_packet_from_regions(self, regions):
#regions = array of (wid, x, y, PIL.Image)
if len(regions)==0:
log("screenshot: no regions found, returning empty 0x0 image!")
return ["screenshot", 0, 0, "png", -1, ""]
#in theory, we could run the rest in a non-UI thread since we're done with GTK..
minx = min([x for (_,x,_,_) in regions])
miny = min([y for (_,_,y,_) in regions])
maxx = max([(x+img.get_width()) for (_,x,_,img) in regions])
maxy = max([(y+img.get_height()) for (_,_,y,img) in regions])
width = maxx-minx
height = maxy-miny
log("screenshot: %sx%s, min x=%s y=%s", width, height, minx, miny)
from PIL import Image #@UnresolvedImport
screenshot = Image.new("RGBA", (width, height))
for wid, x, y, img in reversed(regions):
pixel_format = img.get_pixel_format()
target_format = {
"XRGB" : "RGB",
"BGRX" : "RGB",
"BGRA" : "RGBA"}.get(pixel_format, pixel_format)
pixels = img.get_pixels()
w = img.get_width()
h = img.get_height()
#PIL cannot use the memoryview directly:
if _memoryview and isinstance(pixels, _memoryview):
pixels = pixels.tobytes()
try:
window_image = Image.frombuffer(target_format, (w, h), pixels, "raw", pixel_format, img.get_rowstride())
except:
log.error("Error parsing window pixels in %s format for window %i", pixel_format, wid, exc_info=True)
continue
tx = x-minx
ty = y-miny
screenshot.paste(window_image, (tx, ty))
buf = StringIOClass()
screenshot.save(buf, "png")
data = buf.getvalue()
buf.close()
packet = ["screenshot", width, height, "png", width*4, Compressed("png", data)]
log("screenshot: %sx%s %s", packet[1], packet[2], packet[-1])
return packet

0 comments on commit 7ffd674

Please sign in to comment.