[Spice-devel] [vdagent-win PATCH v10 2/6] Initial rewrite of image conversion code

Christophe Fergeau cfergeau at redhat.com
Mon Jul 24 10:09:08 UTC 2017


Acked-by: Christophe Fergeau <cfergeau at redhat.com>

On Fri, Jul 21, 2017 at 02:51:37PM +0100, Frediano Ziglio wrote:
> Remove CxImage linking.
> Support Windows BMP format.
> 
> Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
> ---
>  Makefile.am                 |   4 +-
>  configure.ac                |   4 +-
>  mingw-spice-vdagent.spec.in |  10 +--
>  vdagent/image.cpp           | 172 +++++++++++++++++++++++++++++++++-----------
>  vdagent/image.h             |  21 ++++++
>  5 files changed, 158 insertions(+), 53 deletions(-)
> 
> diff --git a/Makefile.am b/Makefile.am
> index 868199e..b35dd57 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -23,8 +23,8 @@ LIBS = -lversion
>  
>  bin_PROGRAMS = vdagent vdservice
>  
> -vdagent_LDADD = -lwtsapi32 $(CXIMAGE_LIBS) vdagent_rc.$(OBJEXT)
> -vdagent_CXXFLAGS = $(AM_CXXFLAGS) $(CXIMAGE_CFLAGS)
> +vdagent_LDADD = -lwtsapi32 -lgdi32 vdagent_rc.$(OBJEXT)
> +vdagent_CXXFLAGS = $(AM_CXXFLAGS)
>  vdagent_LDFLAGS = $(AM_LDFLAGS) -Wl,--subsystem,windows
>  vdagent_SOURCES =			\
>  	common/vdcommon.cpp             \
> diff --git a/configure.ac b/configure.ac
> index ff489cc..4eac4b4 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -42,6 +42,7 @@ AC_DEFINE_UNQUOTED([BUILD_YEAR], "$BUILD_YEAR", [Build year])
>  # Check for programs
>  AC_PROG_CC
>  AC_PROG_CXX
> +AX_CXX_COMPILE_STDCXX_11
>  AM_PROG_CC_C_O
>  AC_PROG_INSTALL
>  AC_CHECK_TOOL(WINDRES, [windres])
> @@ -100,9 +101,6 @@ dnl ---------------------------------------------------------------------------
>  dnl - Check library dependencies
>  dnl ---------------------------------------------------------------------------
>  
> -PKG_CHECK_MODULES(CXIMAGE, [cximage])
> -CXIMAGE_LIBS=`$PKG_CONFIG --static --libs cximage`
> -
>  dnl ---------------------------------------------------------------------------
>  dnl - Makefiles, etc.
>  dnl ---------------------------------------------------------------------------
> diff --git a/mingw-spice-vdagent.spec.in b/mingw-spice-vdagent.spec.in
> index 563341d..f874e66 100644
> --- a/mingw-spice-vdagent.spec.in
> +++ b/mingw-spice-vdagent.spec.in
> @@ -13,16 +13,10 @@ Source0:        vdagent-win-%{version}%{?_version_suffix}.tar.xz
>  
>  BuildRequires:  mingw32-filesystem >= 23
>  BuildRequires:  mingw64-filesystem >= 23
> -BuildRequires:  mingw32-cximage-static
> -BuildRequires:  mingw64-cximage-static
> -BuildRequires:  mingw32-jasper-static
> -BuildRequires:  mingw64-jasper-static
> -BuildRequires:  mingw32-libjpeg-turbo-static
> -BuildRequires:  mingw64-libjpeg-turbo-static
> +BuildRequires:  mingw32-gcc-c++
> +BuildRequires:  mingw64-gcc-c++
>  BuildRequires:  mingw32-libpng-static
>  BuildRequires:  mingw64-libpng-static
> -BuildRequires:  mingw32-libtiff-static
> -BuildRequires:  mingw64-libtiff-static
>  BuildRequires:  mingw32-zlib-static
>  BuildRequires:  mingw64-zlib-static
>  BuildRequires:  mingw32-winpthreads-static
> diff --git a/vdagent/image.cpp b/vdagent/image.cpp
> index 960058d..faec18f 100644
> --- a/vdagent/image.cpp
> +++ b/vdagent/image.cpp
> @@ -16,39 +16,48 @@
>  */
>  
>  #include <spice/macros.h>
> +#include <memory>
> +#include <vector>
>  
>  #include "vdcommon.h"
>  #include "image.h"
>  
> -#include "ximage.h"
> +ImageCoder *create_bitmap_coder();
> +ImageCoder *create_png_coder();
>  
> -typedef struct ImageType {
> -    uint32_t type;
> -    DWORD cximage_format;
> -} ImageType;
> -
> -static const ImageType image_types[] = {
> -    {VD_AGENT_CLIPBOARD_IMAGE_PNG, CXIMAGE_FORMAT_PNG},
> -    {VD_AGENT_CLIPBOARD_IMAGE_BMP, CXIMAGE_FORMAT_BMP},
> -};
> -
> -static DWORD get_cximage_format(uint32_t type)
> +static ImageCoder *get_coder(uint32_t vdagent_type)
>  {
> -    for (unsigned int i = 0; i < SPICE_N_ELEMENTS(image_types); i++) {
> -        if (image_types[i].type == type) {
> -            return image_types[i].cximage_format;
> -        }
> +    switch (vdagent_type) {
> +    case VD_AGENT_CLIPBOARD_IMAGE_BMP:
> +        return create_bitmap_coder();
> +    case VD_AGENT_CLIPBOARD_IMAGE_PNG:
> +        return create_png_coder();
>      }
> -    return 0;
> +    return NULL;
>  }
>  
> -HANDLE get_image_handle(const VDAgentClipboard& clipboard, uint32_t size, UINT&)
> +HANDLE get_image_handle(const VDAgentClipboard& clipboard, uint32_t size, UINT& format)
>  {
> -    HANDLE clip_data;
> -    DWORD cximage_format = get_cximage_format(clipboard.type);
> -    ASSERT(cximage_format);
> -    CxImage image((BYTE*)clipboard.data, size, cximage_format);
> -    clip_data = image.CopyToHandle();
> +    std::unique_ptr<ImageCoder> coder(get_coder(clipboard.type));
> +    if (!coder) {
> +        return NULL;
> +    }
> +
> +    format = CF_DIB;
> +    size_t dib_size = coder->get_dib_size(clipboard.data, size);
> +    if (!dib_size) {
> +        return NULL;
> +    }
> +    HANDLE clip_data = GlobalAlloc(GMEM_MOVEABLE, dib_size);
> +    if (clip_data) {
> +        uint8_t* dst = (uint8_t*)GlobalLock(clip_data);
> +        if (!dst) {
> +            GlobalFree(clip_data);
> +            return NULL;
> +        }
> +        coder->get_dib_data(dst, clipboard.data, size);
> +        GlobalUnlock(clip_data);
> +    }
>      return clip_data;
>  }
>  
> @@ -57,32 +66,115 @@ uint8_t* get_raw_clipboard_image(const VDAgentClipboardRequest& clipboard_reques
>  {
>      new_size = 0;
>  
> -    CxImage image;
> -    uint8_t *new_data = NULL;
> -    DWORD cximage_format = get_cximage_format(clipboard_request.type);
> -    HPALETTE pal = 0;
> +    if (GetObjectType(clip_data) != OBJ_BITMAP) {
> +        return NULL;
> +    }
> +
> +    std::unique_ptr<ImageCoder> coder(get_coder(clipboard_request.type));
> +    if (!coder) {
> +        return NULL;
> +    }
>  
> -    ASSERT(cximage_format);
> +    HPALETTE pal = 0;
>      if (IsClipboardFormatAvailable(CF_PALETTE)) {
>          pal = (HPALETTE)GetClipboardData(CF_PALETTE);
>      }
> -    if (!image.CreateFromHBITMAP((HBITMAP)clip_data, pal)) {
> -        vd_printf("Image create from handle failed");
> -        return NULL;
> +
> +    // extract DIB
> +    BITMAP bitmap;
> +    GetObject(clip_data, sizeof(bitmap), &bitmap);
> +
> +    struct {
> +        BITMAPINFOHEADER head;
> +        RGBQUAD colors[256];
> +    } info;
> +
> +    BITMAPINFOHEADER& head(info.head);
> +    memset(&head, 0, sizeof(head));
> +    head.biSize = sizeof(head);
> +    head.biWidth = bitmap.bmWidth;
> +    head.biHeight = bitmap.bmHeight;
> +    head.biPlanes = bitmap.bmPlanes;
> +    head.biBitCount = bitmap.bmBitsPixel >= 16 ? 24 : bitmap.bmBitsPixel;
> +    head.biCompression = BI_RGB;
> +
> +    HDC dc = GetDC(NULL);
> +    HPALETTE old_pal = NULL;
> +    if (pal) {
> +        old_pal = (HPALETTE)SelectObject(dc, pal);
> +        RealizePalette(dc);
> +    }
> +    size_t stride = compute_dib_stride(head.biWidth, head.biBitCount);
> +    std::vector<uint8_t> bits(stride * head.biHeight);
> +    int res = GetDIBits(dc, (HBITMAP) clip_data, 0, head.biHeight,
> +                        &bits[0], (LPBITMAPINFO)&info, DIB_RGB_COLORS);
> +    if (pal) {
> +        SelectObject(dc, old_pal);
>      }
> -    if (!image.Encode(new_data, new_size, cximage_format)) {
> -        vd_printf("Image encode to type %u failed", clipboard_request.type);
> +    ReleaseDC(NULL, dc);
> +    if (!res) {
>          return NULL;
>      }
> -    vd_printf("Image encoded to %lu bytes", new_size);
> -    return new_data;
> +
> +    // convert DIB to desired format
> +    return coder->from_bitmap(*(LPBITMAPINFO)&info, &bits[0], new_size);
>  }
>  
>  void free_raw_clipboard_image(uint8_t *data)
>  {
> -    // this is really just a free however is better to make
> -    // the free from CxImage code as on Windows the free
> -    // can be different between libraries
> -    CxImage image;
> -    image.FreeMemory(data);
> +    free(data);
> +}
> +
> +class BitmapCoder: public ImageCoder
> +{
> +public:
> +    BitmapCoder() {};
> +    size_t get_dib_size(const uint8_t *data, size_t size);
> +    void get_dib_data(uint8_t *dib, const uint8_t *data, size_t size);
> +    uint8_t *from_bitmap(const BITMAPINFO& info, const void *bits, long &size);
> +};
> +
> +size_t BitmapCoder::get_dib_size(const uint8_t *data, size_t size)
> +{
> +    if (memcmp(data, "BM", 2) == 0)
> +        return size > 14 ? size - 14 : 0;
> +    return size;
> +}
> +
> +void BitmapCoder::get_dib_data(uint8_t *dib, const uint8_t *data, size_t size)
> +{
> +    // just strip the file header if present, images can be either BMP or DIB
> +    size_t new_size = get_dib_size(data, size);
> +    memcpy(dib, data + (size - new_size), new_size);
> +}
> +
> +uint8_t *BitmapCoder::from_bitmap(const BITMAPINFO& info, const void *bits, long &size)
> +{
> +    const BITMAPINFOHEADER& head(info.bmiHeader);
> +
> +    const DWORD max_palette_colors = head.biBitCount <= 8 ? 1 << head.biBitCount : 0;
> +    size_t palette_size = sizeof(RGBQUAD) * std::min(head.biClrUsed, max_palette_colors);
> +
> +    const size_t stride = compute_dib_stride(head.biWidth, head.biBitCount);
> +    const size_t image_size = stride * head.biHeight;
> +    size = sizeof(head) + palette_size + image_size;
> +
> +    uint8_t *data = (uint8_t *) malloc(size);
> +    if (!data) {
> +        return NULL;
> +    }
> +    memcpy(data, &info, sizeof(head) + palette_size);
> +    memcpy(data + sizeof(head) + palette_size, bits, image_size);
> +    return data;
> +}
> +
> +ImageCoder *create_bitmap_coder()
> +{
> +    return new BitmapCoder();
> +}
> +
> +// TODO
> +ImageCoder *create_png_coder()
> +{
> +    return NULL;
>  }
> diff --git a/vdagent/image.h b/vdagent/image.h
> index b70f53a..da549d3 100644
> --- a/vdagent/image.h
> +++ b/vdagent/image.h
> @@ -18,6 +18,27 @@
>  #ifndef VDAGENT_IMAGE_H_
>  #define VDAGENT_IMAGE_H_
>  
> +class ImageCoder
> +{
> +public:
> +    ImageCoder() {};
> +    virtual ~ImageCoder() {}
> +    virtual size_t get_dib_size(const uint8_t *data, size_t size)=0;
> +    virtual void get_dib_data(uint8_t *dib, const uint8_t *data, size_t size)=0;
> +    virtual uint8_t *from_bitmap(const BITMAPINFO& info, const void *bits, long &size)=0;
> +private:
> +    ImageCoder(const ImageCoder& rhs);
> +    void operator=(const ImageCoder &rhs);
> +};
> +
> +/**
> + * Compute stride in bytes of a DIB
> + */
> +static inline size_t compute_dib_stride(unsigned int width, unsigned int bit_count)
> +{
> +    return ((width * bit_count + 31u) & ~31u) / 8u;
> +}
> +
>  /**
>   * Returns image to put in the clipboard.
>   *
> -- 
> 2.13.3
> 
> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/spice-devel
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: not available
URL: <https://lists.freedesktop.org/archives/spice-devel/attachments/20170724/bb91ccf5/attachment-0001.sig>


More information about the Spice-devel mailing list