Skip to content

Commit

Permalink
#637 and #389: capture screen contents using Pillow, fallback to GTK …
Browse files Browse the repository at this point in the history
…if ImageGrab module is not present (only available on win32)

git-svn-id: https://xpra.org/svn/Xpra/trunk@10002 3bb7dfac-3a0b-4e04-842a-767bc560f471
  • Loading branch information
totaam committed Jul 22, 2015
1 parent e5256e2 commit 277f126
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 6 deletions.
15 changes: 15 additions & 0 deletions src/xpra/client/gtk_base/bug_report.py
Expand Up @@ -27,6 +27,7 @@
from xpra.client.gtk_base.about import about
from xpra.platform.paths import get_icon_dir
from xpra.platform.info import get_user_info
from xpra.os_util import StringIOClass
from xpra.util import nonl, updict, strtobytes
from xpra.log import Logger, enable_debug_for
log = Logger("util")
Expand Down Expand Up @@ -143,6 +144,20 @@ def get_sys_info():
take_screenshot_fn = take_screenshot
except:
log("failed to load platfrom specific screenshot code", exc_info=True)
if not take_screenshot_fn:
#try with Pillow:
try:
from PIL import ImageGrab #@UnresolvedImport
def pillow_imagegrab_screenshot():
img = ImageGrab.grab()
out = StringIOClass()
img.save(out, format="PNG")
v = out.getvalue()
out.close()
return (img.width, img.height, "png", img.width*3, v)
take_screenshot_fn = pillow_imagegrab_screenshot
except Exception as e:
log("cannot use Pillow's ImageGrab: %s", e)
if not take_screenshot_fn:
#default: gtk screen capture
try:
Expand Down
39 changes: 33 additions & 6 deletions src/xpra/platform/win32/shadow_server.py
Expand Up @@ -14,10 +14,12 @@
log = Logger("shadow", "win32")
shapelog = Logger("shape")

from xpra.server.gtk_root_window_model import GTKRootWindowModel
from PIL import ImageGrab
from xpra.os_util import StringIOClass
from xpra.server.gtk_server_base import GTKServerBase
from xpra.server.shadow_server_base import ShadowServerBase
from xpra.server.shadow_server_base import ShadowServerBase, RootWindowModel
from xpra.platform.win32.keyboard_config import KeyboardConfig, fake_key
from xpra.codecs.image_wrapper import ImageWrapper

NOEVENT = object()
BUTTON_EVENTS = {
Expand All @@ -37,10 +39,10 @@
SEAMLESS = os.environ.get("XPRA_WIN32_SEAMLESS", "0")=="1"


class Win32RootWindowModel(GTKRootWindowModel):
class Win32RootWindowModel(RootWindowModel):

def __init__(self, root):
GTKRootWindowModel.__init__(self, root)
RootWindowModel.__init__(self, root)
if SEAMLESS:
self.property_names.append("shape")
self.dynamic_property_names.append("shape")
Expand All @@ -67,7 +69,7 @@ def connect(self, signal, cb, *args):
if signal=="notify::shape":
self.shape_notify.append((cb, args))
else:
GTKRootWindowModel.connect(self, signal, cb, *args)
RootWindowModel.connect(self, signal, cb, *args)

def get_shape_rectangles(self, logit=False):
#get the list of windows
Expand Down Expand Up @@ -146,12 +148,37 @@ def get_property(self, prop):
shape = {"Bounding.rectangles" : self.rectangles}
#provide clip rectangle? (based on workspace area?)
return shape
return GTKRootWindowModel.get_property(self, prop)
return RootWindowModel.get_property(self, prop)


def get_root_window_size(self):
w = win32api.GetSystemMetrics(win32con.SM_CXVIRTUALSCREEN)
h = win32api.GetSystemMetrics(win32con.SM_CYVIRTUALSCREEN)
return w, h


def get_image(self, x, y, width, height, logger=None):
img = ImageGrab.grab(bbox=(x, y, x+width, y+height))
data_fn = getattr(img, "tobytes", getattr(img, "tostring"))
pixels = data_fn("raw", "BGRX")
stride = img.width*4
return ImageWrapper(0, 0, img.width, img.height, pixels, "BGRX", 24, stride, planes=ImageWrapper.PACKED, thread_safe=True)

def take_screenshot(self):
log("taking screenshot using %s", ImageGrab.grab)
img = ImageGrab.grab()
out = StringIOClass()
img.save(out, format="PNG")
screenshot = (img.width, img.height, "png", img.width*3, out.getvalue())
out.close()
return screenshot


class ShadowServer(ShadowServerBase, GTKServerBase):

def __init__(self):
#TODO: root should be a wrapper for the win32 system metrics bits?
#(or even not bother passing root to ShadowServerBase?
import gtk.gdk
ShadowServerBase.__init__(self, gtk.gdk.get_default_root_window())
GTKServerBase.__init__(self)
Expand Down

0 comments on commit 277f126

Please sign in to comment.