Remove CxImage linking. Support Windows BMP format. Signed-off-by: Frediano Ziglio <fziglio@xxxxxxxxxx> --- Makefile.am | 4 +- configure.ac | 4 +- mingw-spice-vdagent.spec.in | 6 +- vdagent/image.cpp | 170 ++++++++++++++++++++++++++++++++++---------- vdagent/image.h | 21 ++++++ 5 files changed, 157 insertions(+), 48 deletions(-) Changes since v4: - remove tiff dependency, was just for CxImage. 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..cdc8dba 100644 --- a/mingw-spice-vdagent.spec.in +++ b/mingw-spice-vdagent.spec.in @@ -13,16 +13,14 @@ 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-libpng-static BuildRequires: mingw64-libpng-static -BuildRequires: mingw32-libtiff-static -BuildRequires: mingw64-libtiff-static +BuildRequires: mingw32-gcc-c++ +BuildRequires: mingw64-gcc-c++ BuildRequires: mingw32-zlib-static BuildRequires: mingw64-zlib-static BuildRequires: mingw32-winpthreads-static diff --git a/vdagent/image.cpp b/vdagent/image.cpp index 0b9c750..b32da6f 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 &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..773999c 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 width, unsigned 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@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel