diff options
author | Yonit Halperin <yhalperi@redhat.com> | 2010-06-20 17:18:56 +0300 |
---|---|---|
committer | Alexander Larsson <alexl@redhat.com> | 2010-06-21 15:18:26 +0200 |
commit | 537280f183d3a35e8dee8a20238c71e7440cb28c (patch) | |
tree | fdec86a392b8cde474b8e1b5c85f03bb6caf441e /common | |
parent | 25bb38f643af6f0015df369a22176275b6ebfae0 (diff) | |
download | spice-537280f183d3a35e8dee8a20238c71e7440cb28c.tar.gz spice-537280f183d3a35e8dee8a20238c71e7440cb28c.tar.xz spice-537280f183d3a35e8dee8a20238c71e7440cb28c.zip |
Lossy compression of RGBA images (on WAN connection)
The RGB channels are compressed using JPEG.
The alpha channel is compressed using LZ.
Diffstat (limited to 'common')
-rw-r--r-- | common/canvas_base.c | 92 | ||||
-rw-r--r-- | common/lz.c | 12 | ||||
-rw-r--r-- | common/lz_common.h | 9 |
3 files changed, 107 insertions, 6 deletions
diff --git a/common/canvas_base.c b/common/canvas_base.c index 0148270f..2b00f09e 100644 --- a/common/canvas_base.c +++ b/common/canvas_base.c @@ -65,6 +65,10 @@ #define ROUND(_x) ((int)floor((_x) + 0.5)) +#define IS_IMAGE_LOSSY(descriptor) \ + (((descriptor)->type == SPICE_IMAGE_TYPE_JPEG) || \ + ((descriptor)->type == SPICE_IMAGE_TYPE_JPEG_ALPHA)) + #ifdef WIN32 typedef struct __declspec (align(1)) LZImage { #else @@ -607,6 +611,85 @@ static pixman_image_t *canvas_get_jpeg(CanvasBase *canvas, SpiceJPEGImage *image return surface; } +static pixman_image_t *canvas_get_jpeg_alpha(CanvasBase *canvas, + SpiceJPEGAlphaImage *image, int invers) +{ + pixman_image_t *surface = NULL; + int stride; + int width; + int height; + uint8_t *dest; + int alpha_top_down = FALSE; + LzData *lz_data = &canvas->lz_data; + LzImageType lz_alpha_type; + uint8_t *comp_alpha_buf = NULL; + uint8_t *decomp_alpha_buf = NULL; + int alpha_size; + int lz_alpha_width, lz_alpha_height, n_comp_pixels, lz_alpha_top_down; + + canvas->jpeg->ops->begin_decode(canvas->jpeg, image->jpeg_alpha.data, + image->jpeg_alpha.jpeg_size, + &width, &height); + ASSERT((uint32_t)width == image->descriptor.width); + ASSERT((uint32_t)height == image->descriptor.height); + + if (image->jpeg_alpha.flags & SPICE_JPEG_ALPHA_FLAGS_TOP_DOWN) { + alpha_top_down = TRUE; + } + +#ifdef WIN32 + lz_data->decode_data.dc = canvas->dc; +#endif + surface = alloc_lz_image_surface(&lz_data->decode_data, PIXMAN_a8r8g8b8, + width, height, width*height, alpha_top_down); + + if (surface == NULL) { + CANVAS_ERROR("create surface failed"); + } + + dest = (uint8_t *)pixman_image_get_data(surface); + stride = pixman_image_get_stride(surface); + + canvas->jpeg->ops->decode(canvas->jpeg, dest, stride, SPICE_BITMAP_FMT_32BIT); + + comp_alpha_buf = image->jpeg_alpha.data + image->jpeg_alpha.jpeg_size; + alpha_size = image->jpeg_alpha.data_size - image->jpeg_alpha.jpeg_size; + + lz_decode_begin(lz_data->lz, comp_alpha_buf, alpha_size, &lz_alpha_type, + &lz_alpha_width, &lz_alpha_height, &n_comp_pixels, + &lz_alpha_top_down, NULL); + ASSERT(lz_alpha_type == LZ_IMAGE_TYPE_XXXA); + ASSERT(lz_alpha_top_down == alpha_top_down); + ASSERT(lz_alpha_width == width); + ASSERT(lz_alpha_height == height); + ASSERT(n_comp_pixels == width * height); + + if (!alpha_top_down) { + decomp_alpha_buf = dest + stride * (height - 1); + } else { + decomp_alpha_buf = dest; + } + lz_decode(lz_data->lz, LZ_IMAGE_TYPE_XXXA, decomp_alpha_buf); + + if (invers) { + uint8_t *end = dest + height * stride; + for (; dest != end; dest += stride) { + uint32_t *pix; + uint32_t *end_pix; + + pix = (uint32_t *)dest; + end_pix = pix + width; + for (; pix < end_pix; pix++) { + *pix ^= 0x00ffffff; + } + } + } +#ifdef DUMP_JPEG + dump_jpeg(image->jpeg_alpha.data, image->jpeg_alpha.jpeg_size); +#endif + return surface; +} + static pixman_image_t *canvas_bitmap_to_surface(CanvasBase *canvas, SpiceBitmap* bitmap, SpicePalette *palette, int want_original) { @@ -1088,6 +1171,11 @@ static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRE surface = canvas_get_jpeg(canvas, image, 0); break; } + case SPICE_IMAGE_TYPE_JPEG_ALPHA: { + SpiceJPEGAlphaImage *image = (SpiceJPEGAlphaImage *)descriptor; + surface = canvas_get_jpeg_alpha(canvas, image, 0); + break; + } #if defined(SW_CANVAS_CACHE) case SPICE_IMAGE_TYPE_GLZ_RGB: { LZImage *image = (LZImage *)descriptor; @@ -1138,7 +1226,7 @@ static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRE #endif descriptor->type != SPICE_IMAGE_TYPE_FROM_CACHE ) { #ifdef SW_CANVAS_CACHE - if (descriptor->type != SPICE_IMAGE_TYPE_JPEG) { + if (!IS_IMAGE_LOSSY(descriptor)) { canvas->bits_cache->ops->put(canvas->bits_cache, descriptor->id, surface); } else { canvas->bits_cache->ops->put_lossy(canvas->bits_cache, descriptor->id, surface); @@ -1151,7 +1239,7 @@ static pixman_image_t *canvas_get_image_internal(CanvasBase *canvas, SPICE_ADDRE #endif #ifdef SW_CANVAS_CACHE } else if (descriptor->flags & SPICE_IMAGE_FLAGS_CACHE_REPLACE_ME) { - if (descriptor->type == SPICE_IMAGE_TYPE_JPEG) { + if (IS_IMAGE_LOSSY(descriptor)) { CANVAS_ERROR("invalid cache replace request: the image is lossy"); } canvas->bits_cache->ops->replace_lossy(canvas->bits_cache, descriptor->id, surface); diff --git a/common/lz.c b/common/lz.c index 73a797c7..e5635849 100644 --- a/common/lz.c +++ b/common/lz.c @@ -565,6 +565,9 @@ int lz_encode(LzContext *lz, LzImageType type, int width, int height, int top_do lz_rgb32_compress(encoder); lz_rgb_alpha_compress(encoder); break; + case LZ_IMAGE_TYPE_XXXA: + lz_rgb_alpha_compress(encoder); + break; case LZ_IMAGE_TYPE_INVALID: default: encoder->usr->error(encoder->usr, "bad image type\n"); @@ -661,6 +664,7 @@ void lz_decode(LzContext *lz, LzImageType to_type, uint8_t *buf) case LZ_IMAGE_TYPE_RGB24: case LZ_IMAGE_TYPE_RGB32: case LZ_IMAGE_TYPE_RGBA: + case LZ_IMAGE_TYPE_XXXA: case LZ_IMAGE_TYPE_INVALID: default: encoder->usr->error(encoder->usr, "bad image type\n"); @@ -705,6 +709,14 @@ void lz_decode(LzContext *lz, LzImageType to_type, uint8_t *buf) encoder->usr->error(encoder->usr, "unsupported output format\n"); } break; + case LZ_IMAGE_TYPE_XXXA: + if (encoder->type == to_type) { + alpha_size = lz_rgb_alpha_decompress(encoder, (rgb32_pixel_t *)buf, size); + out_size = alpha_size; + } else { + encoder->usr->error(encoder->usr, "unsupported output format\n"); + } + break; case LZ_IMAGE_TYPE_PLT1_LE: case LZ_IMAGE_TYPE_PLT1_BE: case LZ_IMAGE_TYPE_PLT4_LE: diff --git a/common/lz_common.h b/common/lz_common.h index d5019fd3..34276afb 100644 --- a/common/lz_common.h +++ b/common/lz_common.h @@ -39,17 +39,18 @@ typedef enum { LZ_IMAGE_TYPE_RGB16, LZ_IMAGE_TYPE_RGB24, LZ_IMAGE_TYPE_RGB32, - LZ_IMAGE_TYPE_RGBA + LZ_IMAGE_TYPE_RGBA, + LZ_IMAGE_TYPE_XXXA } LzImageType; #define LZ_IMAGE_TYPE_MASK 0x0f #define LZ_IMAGE_TYPE_LOG 4 // number of bits required for coding the image type /* access to the arrays is based on the image types */ -static const int IS_IMAGE_TYPE_PLT[] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0}; -static const int IS_IMAGE_TYPE_RGB[] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1}; +static const int IS_IMAGE_TYPE_PLT[] = {0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0}; +static const int IS_IMAGE_TYPE_RGB[] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1}; static const int PLT_PIXELS_PER_BYTE[] = {0, 8, 8, 2, 2, 1}; -static const int RGB_BYTES_PER_PIXEL[] = {0, 1, 1, 1, 1, 1, 2, 3, 4, 4}; +static const int RGB_BYTES_PER_PIXEL[] = {0, 1, 1, 1, 1, 1, 2, 3, 4, 4, 4}; #define LZ_MAGIC (*(uint32_t *)"LZ ") |