Skip to content

Commit

Permalink
#909: initial support for r210 30-bpp colour mode:
Browse files Browse the repository at this point in the history
* generate test images (same as other RGB modes)
* add conversion to RGB / RGBA in argb helper module
* use argb module to convert r210 before using the data with PIL (or plain rgb)

git-svn-id: https://xpra.org/svn/Xpra/trunk@13741 3bb7dfac-3a0b-4e04-842a-767bc560f471
  • Loading branch information
totaam committed Sep 15, 2016
1 parent 56c5da6 commit e4b0ce5
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 13 deletions.
64 changes: 58 additions & 6 deletions src/xpra/codecs/argb/argb.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,64 @@ log = Logger("encoding")
def buffer_api_version():
return get_buffer_api_version()

cdef inline unsigned char clamp(int v):
if v>255:
return 255
return <unsigned char> v


def r210_to_rgba(buf):
assert len(buf) % 4 == 0, "invalid buffer size: %s is not a multiple of 4" % len(buf)
# buf is a Python buffer object
cdef const int* cbuf = <const int *> 0
cdef Py_ssize_t cbuf_len = 0
assert object_as_buffer(buf, <const void**> &cbuf, &cbuf_len)==0, "cannot convert %s to a readable buffer" % type(buf)
return r210data_to_rgba(cbuf, cbuf_len)

cdef r210data_to_rgba(const int* r210, const int r210_len):
if r210_len <= 0:
return None
assert r210_len>0 and r210_len % 4 == 0, "invalid buffer size: %s is not a multiple of 4" % r210_len
rgba = bytearray(r210_len)
#number of pixels:
cdef int i = 0
cdef int v
while i < r210_len:
v = r210[i//4]
rgba[i] = (v&0x000003ff) >> 2
rgba[i+1] = (v&0x000ffc00) >> 12
rgba[i+2] = (v&0x3ff00000) >> 22
rgba[i+3] = clamp(((v&0xc0000000) >> 30)*85)
i = i + 4
return rgba


def r210_to_rgb(buf):
assert len(buf) % 4 == 0, "invalid buffer size: %s is not a multiple of 4" % len(buf)
# buf is a Python buffer object
cdef const int* cbuf = <const int *> 0
cdef Py_ssize_t cbuf_len = 0
assert object_as_buffer(buf, <const void**> &cbuf, &cbuf_len)==0, "cannot convert %s to a readable buffer" % type(buf)
return r210data_to_rgb(cbuf, cbuf_len)

cdef r210data_to_rgb(const int* r210, const int r210_len):
if r210_len <= 0:
return None
assert r210_len>0 and r210_len % 4 == 0, "invalid buffer size: %s is not a multiple of 4" % r210_len
rgb = bytearray(r210_len//4*3)
#number of pixels:
cdef int s = 0
cdef int d = 0
cdef int v
while s < r210_len//4:
v = r210[s]
rgb[d] = (v&0x000003ff) >> 2
rgb[d+1] = (v&0x000ffc00) >> 12
rgb[d+2] = (v&0x3ff00000) >> 22
s += 1
d += 3
return rgb


def argb_to_rgba(buf):
assert len(buf) % 4 == 0, "invalid buffer size: %s is not a multiple of 4" % len(buf)
Expand All @@ -36,12 +94,6 @@ def argb_to_rgba(buf):
assert object_as_buffer(buf, <const void**> &cbuf, &cbuf_len)==0, "cannot convert %s to a readable buffer" % type(buf)
return argbdata_to_rgba(cbuf, cbuf_len)


cdef inline unsigned char clamp(int v):
if v>255:
return 255
return <unsigned char> v

cdef argbdata_to_rgba(const unsigned char* argb, const int argb_len):
if argb_len <= 0:
return None
Expand Down
2 changes: 1 addition & 1 deletion src/xpra/codecs/codec_checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def make_test_image(pixel_format, w, h):
v = makebuf(w//vdiv[0]*h//vdiv[1])
image = ImageWrapper(0, 0, w, h, [y, u, v], pixel_format, 32, [w//ydiv[0], w//udiv[0], w//vdiv[0]], planes=ImageWrapper._3_PLANES, thread_safe=True)
#l = len(y)+len(u)+len(v)
elif pixel_format in ("RGB", "BGR", "RGBX", "BGRX", "XRGB", "BGRA", "RGBA"):
elif pixel_format in ("RGB", "BGR", "RGBX", "BGRX", "XRGB", "BGRA", "RGBA", "r210"):
stride = w*len(pixel_format)
rgb_data = makebuf(stride*h)
image = ImageWrapper(0, 0, w, h, rgb_data, pixel_format, 32, stride, planes=ImageWrapper.PACKED, thread_safe=True)
Expand Down
7 changes: 6 additions & 1 deletion src/xpra/codecs/pillow/encode.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,18 @@ def encode(coding, image, quality, speed, supports_transparency):
try:
pixels = image.get_pixels()
assert pixels, "failed to get pixels from %s" % image
if pixel_format=="r210":
from xpra.codecs.argb.argb import r210_to_rgba
pixels = r210_to_rgba(pixels)
pixel_format = "RGBA"
rgb = "RGBA"
#PIL cannot use the memoryview directly:
if type(pixels)!=_buffer:
pixels = memoryview_to_bytes(pixels)
#it is safe to use frombuffer() here since the convert()
#calls below will not convert and modify the data in place
#and we save the compressed data then discard the image
im = PIL.Image.frombuffer(rgb, (w, h), pixels, "raw", pixel_format, image.get_rowstride())
im = PIL.Image.frombuffer(rgb, (w, h), pixels, "raw", pixel_format, image.get_rowstride(), 1)
if coding.startswith("png") and not supports_transparency and rgb=="RGBA":
im = im.convert("RGB")
rgb = "RGB"
Expand Down
21 changes: 17 additions & 4 deletions src/xpra/server/picture_encode.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
log = Logger("window", "compress")

from xpra.net import compression
from xpra.codecs.argb.argb import bgra_to_rgb, bgra_to_rgba, argb_to_rgb, argb_to_rgba #@UnresolvedImport
from xpra.codecs.argb.argb import bgra_to_rgb, bgra_to_rgba, argb_to_rgb, argb_to_rgba, r210_to_rgba, r210_to_rgb #@UnresolvedImport
from xpra.codecs.loader import get_codec
from xpra.os_util import memoryview_to_bytes, _memoryview
#"pixels_to_bytes" gets patched up by the OSX shadow server
Expand Down Expand Up @@ -160,7 +160,19 @@ def argb_swap(image, rgb_formats, supports_transparency):
pixels = image.get_pixels()
assert pixels, "failed to get pixels from %s" % image
rs = image.get_rowstride()
if pixel_format in ("BGRX", "BGRA"):
if pixel_format=="r210":
if supports_transparency and "RGBA" in rgb_formats:
log("argb_swap: r210_to_rgba for %s on %s", pixel_format, type(pixels))
image.set_pixels(r210_to_rgba(pixels))
image.set_pixel_format("RGBA")
return True
if "RGB" in rgb_formats:
log("argb_swap: r210_to_rgb for %s on %s", pixel_format, type(pixels))
image.set_pixels(r210_to_rgb(pixels))
image.set_pixel_format("RGB")
image.set_rowstride(rs*3//4)
return True
elif pixel_format in ("BGRX", "BGRA"):
if supports_transparency and "RGBA" in rgb_formats:
log("argb_swap: bgra_to_rgba for %s on %s", pixel_format, type(pixels))
image.set_pixels(bgra_to_rgba(pixels))
Expand All @@ -172,7 +184,7 @@ def argb_swap(image, rgb_formats, supports_transparency):
image.set_pixel_format("RGB")
image.set_rowstride(rs*3//4)
return True
if pixel_format in ("XRGB", "ARGB"):
elif pixel_format in ("XRGB", "ARGB"):
if supports_transparency and "RGBA" in rgb_formats:
log("argb_swap: argb_to_rgba for %s on %s", pixel_format, type(pixels))
image.set_pixels(argb_to_rgba(pixels))
Expand Down Expand Up @@ -213,8 +225,9 @@ def rgb_reformat(image, rgb_formats, supports_transparency):
pixel_format = image.get_pixel_format()
pixels = image.get_pixels()
assert pixels, "failed to get pixels from %s" % image
if not PIL:
if not PIL or pixel_format=="r210":
#try to fallback to argb module
#(required for r210 which is not handled by PIL directly)
log("rgb_reformat: using argb_swap for %s", image)
return argb_swap(image, rgb_formats, supports_transparency)
if supports_transparency:
Expand Down
9 changes: 8 additions & 1 deletion src/xpra/x11/bindings/ximage.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,10 @@ cdef const char *BGRA = "BGRA"
cdef const char *RGB = "RGB"
cdef const char *RGBA = "RGBA"
cdef const char *RGBX = "RGBX"
cdef const char *R210 = "R210"
cdef const char *r210 = "r210"

RGB_FORMATS = [XRGB, BGRX, ARGB, BGRA, RGB, RGBA, RGBX]
RGB_FORMATS = [XRGB, BGRX, ARGB, BGRA, RGB, RGBA, RGBX, R210, r210]


cdef int ximage_counter = 0
Expand Down Expand Up @@ -256,6 +258,11 @@ cdef class XImageWrapper(object):
self.pixel_format = ARGB
else:
self.pixel_format = BGRA
elif self.depth==30:
if image.byte_order==MSBFirst:
self.pixel_format = R210
else:
self.pixel_format = r210
else:
raise Exception("invalid image depth: %i bpp" % self.depth)

Expand Down

0 comments on commit e4b0ce5

Please sign in to comment.