[Spice-devel] [vdagent-win PATCH v8 2/5] Initial rewrite of image conversion code
Frediano Ziglio
fziglio at redhat.com
Wed Jul 19 08:42:40 UTC 2017
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
More information about the Spice-devel
mailing list