Here is the patch (I hope it comes through as an attachment).
The JPEG compression stuff currently lives in server.py. Another option is to
put it in protocol.py, but that would mean moving knowledge about specific
packets into protocol.py.
----- Original Message ----
From: Antoine Martin <[email protected]>
To: lars hofhansl <[email protected]>
Cc: [email protected]
Sent: Wednesday, August 5, 2009 1:19:17 PM
Subject: Re: [Parti-discuss] jpeg compression
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
Hello,
Sounds great, please send it on!
Antoine
lars hofhansl wrote:
> Hello,
>
>
> I have a relatively clean patch to enable JPEG compression for Xpra.
> Is there general interest in that? If so, I'll forward a patch against
> Xpra-current to the list.
>
> The advantages of using jpeg compression are not necessarily obvious.
>
> In my tests I found that for "text only" traffic (emacs, terminals, etc) the
> message sizes sent over the wire actually *increase*
> unless a very low quality (with corresponding bad results) is chosen.
>
> For other traffic like web browsing, the savings are sometimes quite good
> (reducing traffic by 25-75%).
> For (natural) image intensive application (photo viewer, gimp, etc) traffic
> is often reduced by as much as 95%.
> (Boh depending on the quality chosen. At quality setting 60 the savings are
> quite good).
>
> Thanks.
>
> _______________________________________________
> Parti-discuss mailing list
> [email protected]
> http://lists.partiwm.org/cgi-bin/mailman/listinfo/parti-discuss
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
iEYEAREKAAYFAkp56UQACgkQGK2zHPGK1rvwHgCdFuLs47ca1JvWlmm4gY2oHCHQ
HFcAniAOUbw8/3bnXxxJkLteoukb6TIv
=mhfX
-----END PGP SIGNATURE-----
_______________________________________________
Parti-discuss mailing list
[email protected]
http://lists.partiwm.org/cgi-bin/mailman/listinfo/parti-discuss
diff -ur parti-orig/xpra/client.py parti/xpra/client.py
--- parti-orig/xpra/client.py 2009-08-05 19:27:26.000000000 -0700
+++ parti/xpra/client.py 2009-08-05 20:03:24.000000000 -0700
@@ -156,12 +156,19 @@
cr.set_source_rgb(1, 1, 1)
cr.fill()
- def draw(self, x, y, width, height, rgb_data):
- assert len(rgb_data) == width * height * 3
- (my_width, my_height) = self.window.get_size()
+ def draw(self, x, y, width, height, coding, img_data):
gc = self._backing.new_gc()
- self._backing.draw_rgb_image(gc, x, y, width, height,
- gtk.gdk.RGB_DITHER_NONE, rgb_data)
+ if coding != "rgb24":
+ loader = gtk.gdk.PixbufLoader(coding)
+ loader.write(img_data, len(img_data))
+ pixbuf = loader.get_pixbuf()
+ loader.close()
+ self._backing.draw_pixbuf(gc, pixbuf, 0, 0, x, y, width, height)
+ else:
+ assert len(img_data) == width * height * 3
+ self._backing.draw_rgb_image(gc, x, y, width, height,
+ gtk.gdk.RGB_DITHER_NONE, img_data)
+
self.window.invalidate_rect(gtk.gdk.Rectangle(x, y, width, height),
False)
@@ -271,7 +278,7 @@
gobject.type_register(ClientWindow)
class XpraClient(gobject.GObject):
- def __init__(self, sock, compression_level):
+ def __init__(self, sock, compression_level, jpegquality):
gobject.GObject.__init__(self)
self._window_to_id = {}
self._id_to_window = {}
@@ -281,6 +288,8 @@
capabilities_request = dict(default_capabilities)
if compression_level:
capabilities_request["deflate"] = compression_level
+ if jpegquality:
+ capabilities_request["jpeg"] = jpegquality
root_w, root_h = gtk.gdk.get_default_root_window().get_size()
capabilities_request["desktop_size"] = [root_w, root_h]
self.send(["hello", capabilities_request])
@@ -390,8 +399,7 @@
def _process_draw(self, packet):
(_, id, x, y, width, height, coding, data) = packet
window = self._id_to_window[id]
- assert coding == "rgb24"
- window.draw(x, y, width, height, data)
+ window.draw(x, y, width, height, coding, data)
def _process_window_metadata(self, packet):
(_, id, metadata) = packet
Only in parti/xpra: __init__.pyc
diff -ur parti-orig/xpra/protocol.py parti/xpra/protocol.py
--- parti-orig/xpra/protocol.py 2009-08-05 19:27:26.000000000 -0700
+++ parti/xpra/protocol.py 2009-08-05 19:32:12.000000000 -0700
@@ -38,6 +38,7 @@
self._write_buf = ""
self._compressor = None
self._decompressor = None
+ self.jpegquality = 0
self._watch_tag = None
self._update_watch(force=True)
diff -ur parti-orig/xpra/scripts/main.py parti/xpra/scripts/main.py
--- parti-orig/xpra/scripts/main.py 2009-08-05 19:27:26.000000000 -0700
+++ parti/xpra/scripts/main.py 2009-08-05 19:31:05.000000000 -0700
@@ -59,6 +59,10 @@
help="How hard to work on compressing data."
+ " 0 to disable compression,"
+ "9 for maximal (slowest) compression. Default: 3.")
+ parser.add_option("--jpeg-quality", action="store",
+ metavar="LEVEL",
+ dest="jpegquality", type="int", default="0",
+ help="Use jpeg compression with given quality (1-100), 0 disables jpeg compression. Default: disabled.")
parser.add_option("--ssh", action="store",
dest="ssh", default=None, metavar="CMD",
help="How to run 'xpra' on the remote host")
@@ -194,7 +198,9 @@
sock = connect(pick_display(parser, opts, extra_args))
if opts.compression_level < 0 or opts.compression_level > 9:
parser.error("Compression level must be between 0 and 9 inclusive.")
- app = XpraClient(sock, opts.compression_level)
+ if opts.jpegquality < 0 or opts.jpegquality > 100:
+ parser.error("Jpeg qualoty must be between 0 and 100 inclusive.")
+ app = XpraClient(sock, opts.compression_level, opts.jpegquality)
sys.stdout.write("Attached (press Control-C to detach)\n")
app.run()
diff -ur parti-orig/xpra/server.py parti/xpra/server.py
--- parti-orig/xpra/server.py 2009-08-05 19:27:26.000000000 -0700
+++ parti/xpra/server.py 2009-08-05 19:46:20.000000000 -0700
@@ -16,6 +16,8 @@
import os.path
import sys
import subprocess
+import Image
+import StringIO
from wimpiggy.wm import Wm
from wimpiggy.util import (LameStruct,
@@ -167,11 +169,11 @@
log.error("wtf, pixmap is None?")
packet = None
else:
- (x2, y2, w2, h2, data) = self._get_rgb_data(pixmap, x, y, w, h)
+ (x2, y2, w2, h2, coding, data) = self._get_rgb_data(pixmap, x, y, w, h)
if not w2 or not h2:
packet = None
else:
- packet = ["draw", id, x2, y2, w2, h2, "rgb24", data]
+ packet = ["draw", id, x2, y2, w2, h2, coding, data]
else:
packet = None
return packet, self._have_more()
@@ -203,7 +205,20 @@
for i in xrange(height):
rows.append(raw_data[i*rowstride : i*rowstride+rowwidth])
data = "".join(rows)
- return (x, y, width, height, data)
+ coding = "rgb24"
+
+ # should probably have some other conditions for
+ # enabling jpeg compression (for example len(data) > N and/or
+ # width*height > M)
+ if self._protocol.jpegquality > 0:
+ im = Image.fromstring("RGB", (width,height), data)
+ buf=StringIO.StringIO()
+ im.save(buf,"JPEG", quality=self._protocol.jpegquality)
+ data=buf.getvalue()
+ buf.close()
+ coding = "jpeg"
+
+ return (x, y, width, height, coding, data)
class XpraServer(gobject.GObject):
__gsignals__ = {
@@ -489,7 +504,7 @@
def _calculate_capabilities(self, client_capabilities):
capabilities = {}
- for cap in ("deflate", "__prerelease_version"):
+ for cap in ("deflate", "__prerelease_version", "jpeg"):
if cap in client_capabilities:
capabilities[cap] = client_capabilities[cap]
if "desktop_size" in client_capabilities:
@@ -517,6 +532,8 @@
self._send(["hello", capabilities])
if "deflate" in capabilities:
self._protocol.enable_deflate(capabilities["deflate"])
+ if "jpeg" in capabilities:
+ self._protocol.jpegquality = capabilities["jpeg"]
# We send the new-window packets sorted by id because this sorts them
# from oldest to newest -- and preserving window creation order means
# that the earliest override-redirect windows will be on the bottom,
_______________________________________________
Parti-discuss mailing list
[email protected]
http://lists.partiwm.org/cgi-bin/mailman/listinfo/parti-discuss