On Fri, 2017-07-14 at 13:57 +0100, Frediano Ziglio wrote: > 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 | 2 - > vdagent/image.cpp | 182 ++++++++++++++++++++++++++++++++++--------- > - > vdagent/image.h | 13 ++++ > 5 files changed, 159 insertions(+), 46 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..8cfd01a 100644 > --- a/mingw-spice-vdagent.spec.in > +++ b/mingw-spice-vdagent.spec.in > @@ -13,8 +13,6 @@ 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 > diff --git a/vdagent/image.cpp b/vdagent/image.cpp > index 598a742..6f7608d 100644 > --- a/vdagent/image.cpp > +++ b/vdagent/image.cpp > @@ -16,71 +16,175 @@ > */ > > #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; so it is just an output parameter (and always set to 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; > } > > uint8_t* get_raw_clipboard_image(const VDAgentClipboardRequest& > clipboard_request, > HANDLE clip_data, long& new_size) > { > - 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 = ((head.biWidth * head.biBitCount + 31u) & ~31u) / 8u; > + 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 (*(const WORD*)data == 'B'+'M'*256u) isn't nicer to compare byte by byte instead of casting and multiplication ? (or do the shift instead of the multiplication???). > + 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); > + > + size_t palette_size = 0; > + DWORD max_colors = 0; > + switch (head.biBitCount) { > + case 1: > + max_colors = 2; > + break; > + case 4: > + max_colors = 16; > + break; > + case 8: > + max_colors = 256; > + break; what about other values? cannot be reached? > + } > + palette_size = sizeof(RGBQUAD) * std::min(head.biClrUsed, max_colors); > + > + const size_t stride = ((head.biWidth * head.biBitCount + 31u) & ~31u) / > 8u; maybe it can be a function to "hide" the math (and avoid repeating it) > + const size_t image_size = stride * head.biHeight; also it is possible to return the image_size. the stride is not used after that (same in get_raw_clipboard_image()) > + 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 379c5cc..75e2268 100644 > --- a/vdagent/image.h > +++ b/vdagent/image.h > @@ -18,6 +18,19 @@ > #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); > +}; > + > /** > * Returns image to put in the clipboard. > * It is a nice improvement. Thanks, Pavel _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel