Skip to content

Commit

Permalink
prepare for #328: change ImageWrapper's rgb_format to pixel_format si…
Browse files Browse the repository at this point in the history
…nce we use it for all sorts of formats (yuv, etc)

Also add number of "planes".

git-svn-id: https://xpra.org/svn/Xpra/trunk@3544 3bb7dfac-3a0b-4e04-842a-767bc560f471
  • Loading branch information
totaam committed Jun 3, 2013
1 parent b9ede32 commit c218921
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 50 deletions.
30 changes: 24 additions & 6 deletions src/xpra/server/image_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,19 @@

class ImageWrapper(object):

def __init__(self, x, y, width, height, pixels, rgb_format, depth, rowstride):
def __init__(self, x, y, width, height, pixels, pixel_format, depth, rowstride, planes=1):
self.x = x
self.y = y
self.width = width
self.height = height
self.pixels = pixels
self.rgb_format = rgb_format
self.pixel_format = pixel_format
self.depth = depth
self.rowstride = rowstride
self.planes = planes

def __str__(self):
return "%s(%s:%s)" % (type(self), self.pixel_format, self.get_geometry())

def get_geometry(self):
return self.x, self.y, self.width, self.height, self.depth
Expand All @@ -41,18 +45,32 @@ def get_depth(self):
def get_size(self):
return self.rowstride * self.height

def get_rgb_format(self):
return self.rgb_format
def get_pixel_format(self):
return self.pixel_format

def get_pixels(self):
return self.pixels

def get_planes(self):
return self.planes


def set_planes(self, planes):
self.planes = planes

def set_rowstride(self, rowstride):
self.rowstride = rowstride

def set_rgb_format(self, rgb_format):
self.rgb_format = rgb_format
def set_pixel_format(self, pixel_format):
self.pixel_format = pixel_format

def set_pixels(self, pixels):
self.pixels = pixels

def __del__(self):
#print("ImageWrapper.__del__() calling %s" % self.free)
self.free()

def free(self):
pass
#print("ImageWrapper.free()")
50 changes: 26 additions & 24 deletions src/xpra/server/window_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -878,7 +878,7 @@ def make_data_packet(self, damage_time, process_damage_time, wid, image, coding,
data, client_options = self.webp_encode(image, options)
elif coding=="mmap":
#actual sending is already handled via mmap_send above
client_options = {"rgb_format" : image.get_rgb_format()}
client_options = {"rgb_format" : image.get_pixel_format()}
outstride = image.get_rowstride()
else:
raise Exception("invalid encoding: %s" % coding)
Expand Down Expand Up @@ -938,9 +938,9 @@ def webp_encode(self, image, options):
"BGRA": (BitmapHandler.BGRA, EncodeBGRA, EncodeLosslessBGRA, True),
"BGRX": (BitmapHandler.BGRA, EncodeBGRA, EncodeLosslessBGRA, False),
}
rgb_format = image.get_rgb_format()
h_e = handler_encs.get(rgb_format)
assert h_e is not None, "cannot handle rgb format %s with webp!" % rgb_format
pixel_format = image.get_pixel_format()
h_e = handler_encs.get(pixel_format)
assert h_e is not None, "cannot handle rgb format %s with webp!" % pixel_format
bh, lossy_enc, lossless_enc, has_alpha = h_e
q = self.get_current_quality()
if options:
Expand All @@ -950,24 +950,24 @@ def webp_encode(self, image, options):
enc = lossy_enc
kwargs = {"quality" : q}
client_options = {"quality" : q}
debug("webp_encode(%s, %s) using lossy encoder=%s with quality=%s for %s", image, options, enc, q, rgb_format)
debug("webp_encode(%s, %s) using lossy encoder=%s with quality=%s for %s", image, options, enc, q, pixel_format)
else:
enc = lossless_enc
kwargs = {}
client_options = {}
debug("webp_encode(%s, %s) using lossless encoder=%s for %s", image, options, enc, rgb_format)
debug("webp_encode(%s, %s) using lossless encoder=%s for %s", image, options, enc, pixel_format)
image = BitmapHandler(image.get_pixels(), bh, image.get_width(), image.get_height(), image.get_rowstride())
if has_alpha:
client_options["has_alpha"] = True
return Compressed("webp", str(enc(image, **kwargs).data)), client_options

def rgb_encode(self, coding, image):
rgb_format = image.get_rgb_format()
if rgb_format not in self.rgb_formats:
pixel_format = image.get_pixel_format()
if pixel_format not in self.rgb_formats:
if not self.rgb_reformat(image):
raise Exception("cannot find compatible rgb format to use for %s!" % rgb_format)
raise Exception("cannot find compatible rgb format to use for %s!" % pixel_format)
#get the new format:
rgb_format = image.get_rgb_format()
pixel_format = image.get_pixel_format()
#compress here and return a wrapper so network code knows it is already zlib compressed:
pixels = image.get_pixels()
if len(pixels)<512:
Expand All @@ -985,7 +985,7 @@ def rgb_encode(self, coding, image):
level = 0
zlib = str(pixels)
cdata = zlib
debug("rgb_encode using level=%s, compressed %sx%s in %s/%s: %s bytes down to %s", level, image.get_width(), image.get_height(), coding, rgb_format, len(pixels), len(cdata))
debug("rgb_encode using level=%s, compressed %sx%s in %s/%s: %s bytes down to %s", level, image.get_width(), image.get_height(), coding, pixel_format, len(pixels), len(cdata))
if not self.encoding_client_options or not self.supports_rgb24zlib:
return zlib, {}
#wrap it using "Compressed" so the network layer receiving it
Expand All @@ -995,19 +995,19 @@ def rgb_encode(self, coding, image):
def PIL_encode(self, coding, image, options):
assert coding in self.SERVER_CORE_ENCODINGS
assert Image is not None, "Python PIL is not available"
rgb_format = image.get_rgb_format()
pixel_format = image.get_pixel_format()
w = image.get_width()
h = image.get_height()
rgb = {
"XRGB" : "RGB",
"BGRX" : "RGB",
"RGBA" : "RGBA",
"BGRA" : "RGBA",
}.get(rgb_format, rgb_format)
}.get(pixel_format, pixel_format)
try:
im = Image.fromstring(rgb, (w, h), image.get_pixels(), "raw", rgb_format, image.get_rowstride())
im = Image.fromstring(rgb, (w, h), image.get_pixels(), "raw", pixel_format, image.get_rowstride())
except Exception, e:
log.error("PIL_encode(%s) converting to %s failed", (w, h, coding, "%s bytes" % len(image.get_size()), rgb_format, image.get_rowstride(), options), rgb, exc_info=True)
log.error("PIL_encode(%s) converting to %s failed", (w, h, coding, "%s bytes" % len(image.get_size()), pixel_format, image.get_rowstride(), options), rgb, exc_info=True)
raise e
buf = StringIOClass()
client_options = {}
Expand Down Expand Up @@ -1038,7 +1038,7 @@ def PIL_encode(self, coding, image, options):
kwargs = im.info
kwargs["optimize"] = optimize
im.save(buf, "PNG", **kwargs)
debug("sending %sx%s %s as %s, mode=%s, options=%s", w, h, rgb_format, coding, im.mode, kwargs)
debug("sending %sx%s %s as %s, mode=%s, options=%s", w, h, pixel_format, coding, im.mode, kwargs)
data = buf.getvalue()
buf.close()
return Compressed(coding, data), client_options
Expand Down Expand Up @@ -1103,33 +1103,35 @@ def video_encode(self, wid, coding, image, options):

def rgb_reformat(self, image):
#need to convert to a supported format!
rgb_format = image.get_rgb_format()
pixel_format = image.get_pixel_format()
target_format = {
"XRGB" : "RGB",
"BGRX" : "RGB",
"BGRA" : "RGBA"}.get(rgb_format)
"BGRA" : "RGBA"}.get(pixel_format)
if target_format not in self.rgb_formats:
warning_key = "%s/%s" % (rgb_format, "|".join(self.rgb_formats))
self.warn_encoding_once(warning_key, "cannot use mmap to send pixels: we would need to convert %s to one of: %s" % (rgb_format, self.rgb_formats))
warning_key = "rgb_reformats(%s)" % pixel_format
self.warn_encoding_once(warning_key, "cannot convert %s to one of: %s" % (pixel_format, self.rgb_formats))
return False
start = time.time()
w = image.get_width()
h = image.get_height()
pixels = image.get_pixels()
img = Image.frombuffer(target_format, (w, h), pixels, "raw", rgb_format, image.get_rowstride())
img = Image.frombuffer(target_format, (w, h), pixels, "raw", pixel_format, image.get_rowstride())
rowstride = w*len(target_format) #number of characters is number of bytes per pixel!
data = img.tostring("raw", target_format)
assert len(data)==rowstride*h, "expected %s bytes in %s format but got %s" % (rowstride*h, len(data))
image.set_pixels(data)
image.set_rowstride(rowstride)
image.set_rgb_format(target_format)
image.set_pixel_format(target_format)
end = time.time()
debug("rgb_reformat(%s) converted from %s (%s bytes) to %s (%s bytes) in %.1fms, rowstride=%s", image, rgb_format, len(pixels), target_format, len(data), (end-start)*1000.0, rowstride)
debug("rgb_reformat(%s) converted from %s (%s bytes) to %s (%s bytes) in %.1fms, rowstride=%s", image, pixel_format, len(pixels), target_format, len(data), (end-start)*1000.0, rowstride)
return True

def mmap_send(self, image):
if image.get_rgb_format() not in self.rgb_formats:
if image.get_pixel_format() not in self.rgb_formats:
if not self.rgb_reformat(image):
warning_key = "mmap_send(%s)" % image.get_pixel_format()
self.warn_encoding_once(warning_key, "cannot use mmap to send %s" % image.get_pixel_format())
return None
from xpra.net.mmap_pipe import mmap_write
start = time.time()
Expand Down
33 changes: 19 additions & 14 deletions src/xpra/x11/gtk_x11/gdk_bindings.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -755,7 +755,8 @@ cdef class XImageWrapper:
cdef int height #@DuplicatedSignature
cdef int depth #@DuplicatedSignature
cdef int rowstride
cdef char *rgb_format
cdef int planes
cdef char *pixel_format
cdef char *pixels
cdef object del_callback

Expand All @@ -769,29 +770,30 @@ cdef class XImageWrapper:
self.y = y
self.width = width
self.height = height
self.rgb_format = ""
self.pixel_format = ""
self.rowstride = 0
self.planes = 0

cdef set_image(self, XImage* image):
self.image = image
self.rowstride = self.image.bytes_per_line
self.depth = self.image.depth
if self.depth==24:
if self.image.byte_order==MSBFirst:
self.rgb_format = XRGB
self.pixel_format = XRGB
else:
self.rgb_format = BGRX
self.pixel_format = BGRX
elif self.depth==32:
if self.image.byte_order==MSBFirst:
self.rgb_format = ARGB
self.pixel_format = ARGB
else:
self.rgb_format = BGRA
self.pixel_format = BGRA
else:
raise Exception("invalid image depth: %s bpp" % self.depth)
assert self.rgb_format in RGB_FORMATS
assert self.pixel_format in RGB_FORMATS

def __str__(self):
return "XImageWrapper(%s, %s, %s, %s)" % (self.x, self.y, self.width, self.height)
return "XImageWrapper(%s: %s, %s, %s, %s)" % (self.pixel_format, self.x, self.y, self.width, self.height)

def get_geometry(self):
return self.x, self.y, self.width, self.height, self.depth
Expand All @@ -811,14 +813,17 @@ cdef class XImageWrapper:
def get_rowstride(self):
return self.rowstride

def get_planes(self):
return self.planes

def get_depth(self):
return self.depth

def get_size(self):
return self.rowstride * self.height

def get_rgb_format(self):
return self.rgb_format
def get_pixel_format(self):
return self.pixel_format

def get_pixels(self):
if self.pixels!=NULL:
Expand All @@ -829,12 +834,12 @@ cdef class XImageWrapper:
def set_rowstride(self, rowstride):
self.rowstride = rowstride

def set_rgb_format(self, rgb_format):
assert rgb_format in RGB_FORMATS, "invalid rgb_format: %s" % rgb_format
def set_pixel_format(self, pixel_format):
assert pixel_format in RGB_FORMATS, "invalid rgb_format: %s" % pixel_format
cdef int i =0
while RGB_FORMATS[i]!=rgb_format:
while RGB_FORMATS[i]!=pixel_format:
i +=1
self.rgb_format = RGB_FORMATS[i]
self.pixel_format = RGB_FORMATS[i]

def set_pixels(self, pixels):
cdef const unsigned char * buf = NULL
Expand Down
12 changes: 6 additions & 6 deletions src/xpra/x11/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -607,8 +607,8 @@ def do_make_screenshot_packet(self):
log.warn("screenshot: no pixels for window %s", wid)
continue
debug("screenshot: image=%s, size=%s", (img, img.get_size()))
if img.get_rgb_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_rgb_format())
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
item = (wid, x, y, img)
if window.is_OR():
Expand All @@ -634,15 +634,15 @@ def do_make_screenshot_packet(self):
import Image
screenshot = Image.new("RGBA", (width, height))
for wid, x, y, img in reversed(all_regions):
rgb_format = img.get_rgb_format()
pixel_format = img.get_pixel_format()
target_format = {
"XRGB" : "RGB",
"BGRX" : "RGB",
"BGRA" : "RGBA"}.get(rgb_format, rgb_format)
"BGRA" : "RGBA"}.get(pixel_format, pixel_format)
try:
window_image = Image.fromstring(target_format, (w, h), img.get_pixels(), "raw", rgb_format, img.get_rowstride())
window_image = Image.fromstring(target_format, (w, h), img.get_pixels(), "raw", pixel_format, img.get_rowstride())
except:
log.warn("failed to parse window pixels in %s format", rgb_format)
log.warn("failed to parse window pixels in %s format", pixel_format)
continue
tx = x-minx
ty = y-miny
Expand Down

0 comments on commit c218921

Please sign in to comment.