[Spice-commits] 6 commits - Makefile.am configure.ac mingw-spice-vdagent.spec.in test-png vdagent/image.cpp vdagent/image.h vdagent/imagepng.cpp vdagent/imagepng.h vdagent/imagetest.cpp vdagent/vdagent.cpp

Frediano Ziglio fziglio at kemper.freedesktop.org
Wed Jul 26 09:55:17 UTC 2017


 Makefile.am                 |   28 +++
 configure.ac                |    5 
 mingw-spice-vdagent.spec.in |   37 +++-
 test-png                    |   58 +++++++
 vdagent/image.cpp           |  174 +++++++++++++++++++++
 vdagent/image.h             |   69 ++++++++
 vdagent/imagepng.cpp        |  357 ++++++++++++++++++++++++++++++++++++++++++++
 vdagent/imagepng.h          |   25 +++
 vdagent/imagetest.cpp       |   82 ++++++++++
 vdagent/vdagent.cpp         |   57 -------
 10 files changed, 831 insertions(+), 61 deletions(-)

New commits:
commit 6012db027c9788041b66eda85c98c829dbe2ce0b
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Thu Jul 20 11:09:35 2017 +0100

    spec: run tests during RPM build if possible
    
    Currently to fully run checks we need Wine for both 32 and 64 bit.
    Some distros (like RHEL 7) don't seem to allow installing
    both 32 and 64 bit versions so turn on checks based on distro
    versions.
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Christophe Fergeau <cfergeau at redhat.com>

diff --git a/mingw-spice-vdagent.spec.in b/mingw-spice-vdagent.spec.in
index f874e66..d25ea31 100644
--- a/mingw-spice-vdagent.spec.in
+++ b/mingw-spice-vdagent.spec.in
@@ -2,6 +2,19 @@
 
 #define _version_suffix -e198
 
+%if "%{_build_arch}" == "x86_64" && (0%{?fedora} && 0%{?fedora} >= 24)
+    %define can_do_check_x64 1
+    %define can_do_check_x86 1
+%else
+%if "%{_build_arch}" == "x86_64" && (0%{?epel} && 0%{?epel} >= 7)
+    %define can_do_check_x64 1
+    %define can_do_check_x86 0
+%else
+    %define can_do_check_x64 0
+    %define can_do_check_x86 0
+%endif
+%endif
+
 Name:           mingw-spice-vdagent
 Version:        @VERSION@
 Release:        1%{?dist}%{?extra_release}
@@ -22,6 +35,12 @@ BuildRequires:  mingw64-zlib-static
 BuildRequires:  mingw32-winpthreads-static
 BuildRequires:  mingw64-winpthreads-static
 BuildRequires:  pkgconfig
+%if 0%{can_do_check_x64}
+BuildRequires:  ImageMagick wine-core(x86-64)
+%endif
+%if 0%{can_do_check_x86}
+BuildRequires:  ImageMagick wine-core(x86-32)
+%endif
 
 BuildArch:      noarch
 
@@ -73,6 +92,14 @@ Features:
 %mingw_configure --enable-debug
 %mingw_make %{?_smp_mflags} V=1
 
+%if 0%{can_do_check_x86} || 0%{can_do_check_x64}
+%check
+%define mingw_build_win32 %{can_do_check_x86}
+%define mingw_build_win64 %{can_do_check_x64}
+%mingw_make check
+%define mingw_build_win32 1
+%define mingw_build_win64 1
+%endif
 
 %install
 %mingw_make_install DESTDIR=$RPM_BUILD_ROOT
commit fd4ea9fa36834c2ed8afd3cd143bc31ef52fd62d
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Fri Jul 14 12:42:45 2017 +0100

    Add test for PNG files
    
    Test various image and formats.
    The idea is to decode and encode again an image and
    check for differences. ImageMagick is used to create
    some test image and compare results.
    Wine is used to execute a test helper.
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Christophe Fergeau <cfergeau at redhat.com>

diff --git a/Makefile.am b/Makefile.am
index 175d8f7..411bf0d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -68,6 +68,26 @@ vdservice_rc.$(OBJEXT): vdservice/vdservice.rc
 
 MAINTAINERCLEANFILES += vdservice_rc.$(OBJEXT)
 
+check_PROGRAMS = imagetest
+
+imagetest_LDADD = $(LIBPNG_LIBS) $(ZLIB_LIBS) -lwtsapi32 -lgdi32
+imagetest_CXXFLAGS = $(AM_CXXFLAGS) $(LIBPNG_CFLAGS)
+imagetest_LDFLAGS = $(AM_LDFLAGS) -Wl,--subsystem,console
+imagetest_SOURCES =			\
+	common/vdcommon.cpp             \
+	common/vdcommon.h		\
+	common/vdlog.cpp		\
+	common/vdlog.h			\
+	vdagent/imagetest.cpp		\
+	vdagent/image.cpp		\
+	vdagent/image.h			\
+	vdagent/imagepng.cpp		\
+	vdagent/imagepng.h		\
+	$(NULL)
+
+TESTS = test-png
+EXTRA_DIST += test-png
+
 deps.txt:
 	$(AM_V_GEN)rpm -qa | grep $(host_os) | sort | unix2dos > $@
 
diff --git a/test-png b/test-png
new file mode 100755
index 0000000..ee9d86e
--- /dev/null
+++ b/test-png
@@ -0,0 +1,58 @@
+#!/bin/bash
+
+VERBOSE=${VERBOSE:-0}
+
+IN=in.png
+OUT=out.png
+OUT_BMP=out.bmp
+
+error() {
+    echo "$*" >&2
+    exit 1
+}
+
+verbose() {
+    if [ $VERBOSE != 0 ]; then
+        "$@"
+    fi
+}
+
+compare_images() {
+    DIFF=$(compare -metric AE $1 $2 - 2>&1 > /dev/null || true)
+    if [ "$DIFF" != "0" ]; then
+        error "Images $1 and $2 are too different, diff $DIFF"
+    fi
+}
+
+do_test() {
+    echo "Running image $IMAGE with '$*'..."
+    convert $IMAGE "$@" $IN
+    wine imagetest.exe $IN $OUT_BMP $OUT
+    verbose ls -lh $IN
+    verbose identify $IN
+    verbose identify $OUT_BMP
+    compare_images $IN $OUT
+    compare_images $IN $OUT_BMP
+    rm -f $IN $OUT $OUT_BMP
+}
+
+do_test_all() {
+    IMAGE="$1"
+    do_test
+    do_test -type Palette
+    do_test -type Palette -colors 14
+    do_test -type Palette -colors 3
+    do_test -type TrueColor
+    do_test -type Grayscale -depth 8
+    do_test -type Grayscale -depth 2
+    do_test -type Grayscale -depth 4
+}
+
+set -e
+# test with small image
+do_test_all rose:
+# test with larger image
+do_test_all logo:
+rm -f $IN $OUT $OUT_BMP
+
+verbose echo Finish
diff --git a/vdagent/imagetest.cpp b/vdagent/imagetest.cpp
new file mode 100644
index 0000000..319b188
--- /dev/null
+++ b/vdagent/imagetest.cpp
@@ -0,0 +1,82 @@
+/*
+   Copyright (C) 2017 Red Hat, Inc.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#undef NDEBUG
+#include <assert.h>
+#include <vector>
+
+#include "vdcommon.h"
+#include "image.h"
+#include "imagepng.h"
+
+int main(int argc, char **argv)
+{
+    ImageCoder *coder = create_png_coder();
+
+    assert(coder);
+    if (argc < 2) {
+        fprintf(stderr, "Usage: %s <in-image> [<out-bmp> [<out-png>]]\n", argv[0]);
+        return 1;
+    }
+
+    // read all file into memory
+    FILE *f = fopen(argv[1], "rb");
+    assert(f);
+    assert(fseek(f, 0, SEEK_END) == 0);
+    long len = ftell(f);
+    assert(len > 0);
+    assert(fseek(f, 0, SEEK_SET) == 0);
+
+    std::vector<uint8_t> data(len);
+    assert(fread(&data[0], 1, len, f) == (unsigned long) len);
+    fclose(f);
+
+    size_t dib_size = coder->get_dib_size(&data[0], len);
+    assert(dib_size);
+    std::vector<uint8_t> out(dib_size);
+    memset(&out[0], 0xcc, dib_size);
+    coder->get_dib_data(&out[0], &data[0], len);
+
+    // looks like many tools wants this header so craft it
+    BITMAPFILEHEADER head;
+    memset(&head, 0, sizeof(head));
+    head.bfType = 'B'+'M'*256u;
+    head.bfSize = sizeof(head) + dib_size;
+    BITMAPINFOHEADER& info(*(BITMAPINFOHEADER*)&out[0]);
+    head.bfOffBits = sizeof(head) + sizeof(BITMAPINFOHEADER) + 4 * info.biClrUsed;
+
+    f = fopen(argc > 2 ? argv[2] : "out.bmp", "wb");
+    assert(f);
+    assert(fwrite(&head, 1, sizeof(head), f) == sizeof(head));
+    assert(fwrite(&out[0], 1, dib_size, f) == dib_size);
+    fclose(f);
+
+    // convert back to PNG
+    long png_size = 0;
+    uint8_t *png = coder->from_bitmap(*((BITMAPINFO*)&out[0]), &out[sizeof(BITMAPINFOHEADER) + 4 * info.biClrUsed], png_size);
+    assert(png && png_size > 0);
+
+    f = fopen(argc > 3 ? argv[3] : "out.png", "wb");
+    assert(f);
+    assert(fwrite(png, 1, png_size, f) == (unsigned long) png_size);
+    fclose(f);
+    free(png);
+    png = NULL;
+
+    return 0;
+}
+
commit 868d347b910404b2c108f6c7c4f73967b0d29263
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Tue Nov 8 14:28:01 2016 +0000

    Support encoding PNG images
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Christophe Fergeau <cfergeau at redhat.com>

diff --git a/vdagent/imagepng.cpp b/vdagent/imagepng.cpp
index a89b7f7..78b4188 100644
--- a/vdagent/imagepng.cpp
+++ b/vdagent/imagepng.cpp
@@ -19,6 +19,7 @@
 
 #include <png.h>
 #include <algorithm>
+#include <vector>
 
 #include "imagepng.h"
 
@@ -50,6 +51,43 @@ static void read_from_bufio(png_structp png, png_bytep out, png_size_t size)
     io.pos += size;
 }
 
+struct WriteBufferIo {
+    uint8_t *buf;
+    uint32_t pos, size;
+    WriteBufferIo():
+        buf(NULL), pos(0), size(0)
+    {}
+    ~WriteBufferIo() { free(buf); }
+    uint8_t *release() {
+        uint8_t *res = buf;
+        buf = NULL;
+        pos = size = 0;
+        return res;
+    }
+};
+
+static void write_to_bufio(png_structp png, png_bytep in, png_size_t size)
+{
+    WriteBufferIo& io(*(WriteBufferIo*)png_get_io_ptr(png));
+    if (io.pos + size > io.size) {
+        uint32_t new_size = io.size ? io.size * 2 : 4096;
+        while (io.pos + size >= new_size) {
+            new_size *= 2;
+        }
+        uint8_t *p = (uint8_t*) realloc(io.buf, new_size);
+        if (!p)
+            png_error(png, "out of memory");
+        io.buf = p;
+        io.size = new_size;
+    }
+    memcpy(io.buf+io.pos, in, size);
+    io.pos += size;
+}
+
+static void flush_bufio(png_structp png)
+{
+}
+
 size_t PngCoder::get_dib_size(const uint8_t *data, size_t size)
 {
     return convert_to_dib(NULL, data, size);
@@ -233,10 +271,84 @@ void PngCoder::get_dib_data(uint8_t *dib, const uint8_t *data, size_t size)
     convert_to_dib(dib, data, size);
 }
 
-uint8_t *PngCoder::from_bitmap(const BITMAPINFO& info, const void *bits, long &size)
+uint8_t *PngCoder::from_bitmap(const BITMAPINFO& bmp_info, const void *bits, long &size)
 {
-    // TODO not implemented
-    return NULL;
+    // this vector is here to avoid leaking resources if libpng use setjmp/longjmp
+    std::vector<png_color> palette;
+    WriteBufferIo io;
+
+    png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+    if (!png)
+        return 0;
+
+    png_infop info = png_create_info_struct(png);
+    if (!info) {
+        png_destroy_write_struct(&png, &info);
+        return 0;
+    }
+
+    if (setjmp(png_jmpbuf(png))) {
+        png_destroy_write_struct(&png, &info);
+        return 0;
+    }
+
+    png_set_write_fn(png, &io, write_to_bufio, flush_bufio);
+
+    const BITMAPINFOHEADER& head(bmp_info.bmiHeader);
+    int color_type;
+    int out_bits = head.biBitCount;
+    switch (out_bits) {
+    case 1:
+    case 4:
+    case 8:
+        color_type = PNG_COLOR_TYPE_PALETTE;
+        break;
+    case 24:
+    case 32:
+        png_set_bgr(png);
+        color_type = PNG_COLOR_TYPE_RGB;
+        break;
+    default:
+        png_error(png, "BMP bit count not supported");
+        break;
+    }
+    // TODO detect gray
+    png_set_IHDR(png, info, head.biWidth, head.biHeight,
+                 out_bits > 8 ? 8 : out_bits, color_type,
+                 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
+                 PNG_FILTER_TYPE_DEFAULT);
+
+    // palette
+    if (color_type == PNG_COLOR_TYPE_PALETTE) {
+        palette.resize(head.biClrUsed);
+        const RGBQUAD *rgb = bmp_info.bmiColors;
+        for (unsigned int color = 0; color < head.biClrUsed; ++color) {
+            palette[color].red = rgb->rgbRed;
+            palette[color].green = rgb->rgbGreen;
+            palette[color].blue = rgb->rgbBlue;
+            ++rgb;
+        }
+        png_set_PLTE(png, info, &palette[0], palette.size());
+    }
+
+    png_write_info(png, info);
+
+    const unsigned int width = head.biWidth;
+    const unsigned int height = head.biHeight;
+    const size_t stride = compute_dib_stride(width, out_bits);
+    const size_t image_size = stride * height;
+
+    // now do the actual conversion!
+    const uint8_t *src = (const uint8_t*)bits + image_size;
+    for (unsigned int row = 0; row < height; ++row) {
+        src -= stride;
+        png_write_row(png, src);
+    }
+    png_write_end(png, NULL);
+
+    png_destroy_write_struct(&png, &info);
+    size = io.pos;
+    return io.release();
 }
 
 ImageCoder *create_png_coder()
commit 3dedcaa44e5a5b6450c8642e4721270a5ed08e54
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Tue Nov 8 13:26:28 2016 +0000

    Write code to decode PNG format
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Christophe Fergeau <cfergeau at redhat.com>

diff --git a/Makefile.am b/Makefile.am
index b35dd57..175d8f7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -23,8 +23,8 @@ LIBS = -lversion
 
 bin_PROGRAMS = vdagent vdservice
 
-vdagent_LDADD = -lwtsapi32 -lgdi32 vdagent_rc.$(OBJEXT)
-vdagent_CXXFLAGS = $(AM_CXXFLAGS)
+vdagent_LDADD = $(LIBPNG_LIBS) $(ZLIB_LIBS) -lwtsapi32 -lgdi32 vdagent_rc.$(OBJEXT)
+vdagent_CXXFLAGS = $(AM_CXXFLAGS) $(LIBPNG_CFLAGS)
 vdagent_LDFLAGS = $(AM_LDFLAGS) -Wl,--subsystem,windows
 vdagent_SOURCES =			\
 	common/vdcommon.cpp             \
@@ -44,6 +44,8 @@ vdagent_SOURCES =			\
 	vdagent/as_user.h		\
 	vdagent/image.cpp		\
 	vdagent/image.h			\
+	vdagent/imagepng.cpp		\
+	vdagent/imagepng.h		\
 	$(NULL)
 
 vdagent_rc.$(OBJEXT): vdagent/vdagent.rc
diff --git a/configure.ac b/configure.ac
index 4eac4b4..bb33075 100644
--- a/configure.ac
+++ b/configure.ac
@@ -101,6 +101,9 @@ dnl ---------------------------------------------------------------------------
 dnl - Check library dependencies
 dnl ---------------------------------------------------------------------------
 
+PKG_CHECK_MODULES(LIBPNG, [libpng])
+PKG_CHECK_MODULES(ZLIB, [zlib])
+
 dnl ---------------------------------------------------------------------------
 dnl - Makefiles, etc.
 dnl ---------------------------------------------------------------------------
diff --git a/vdagent/image.cpp b/vdagent/image.cpp
index faec18f..82cfb0e 100644
--- a/vdagent/image.cpp
+++ b/vdagent/image.cpp
@@ -21,9 +21,9 @@
 
 #include "vdcommon.h"
 #include "image.h"
+#include "imagepng.h"
 
 ImageCoder *create_bitmap_coder();
-ImageCoder *create_png_coder();
 
 static ImageCoder *get_coder(uint32_t vdagent_type)
 {
@@ -172,9 +172,3 @@ ImageCoder *create_bitmap_coder()
 {
     return new BitmapCoder();
 }
-
-// TODO
-ImageCoder *create_png_coder()
-{
-    return NULL;
-}
diff --git a/vdagent/imagepng.cpp b/vdagent/imagepng.cpp
new file mode 100644
index 0000000..a89b7f7
--- /dev/null
+++ b/vdagent/imagepng.cpp
@@ -0,0 +1,245 @@
+/*
+   Copyright (C) 2017 Red Hat, Inc.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "vdcommon.h"
+
+#include <png.h>
+#include <algorithm>
+
+#include "imagepng.h"
+
+class PngCoder: public ImageCoder
+{
+public:
+    PngCoder() {};
+    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);
+private:
+    size_t convert_to_dib(uint8_t *out_buf, const uint8_t *data, size_t size);
+};
+
+struct ReadBufferIo {
+    const uint8_t *buf;
+    uint32_t pos, size;
+    ReadBufferIo(const uint8_t *_buf, uint32_t _size):
+        buf(_buf), pos(0), size(_size)
+    {}
+};
+
+static void read_from_bufio(png_structp png, png_bytep out, png_size_t size)
+{
+    ReadBufferIo& io(*(ReadBufferIo*)png_get_io_ptr(png));
+    if (io.pos + size > io.size)
+        png_error(png, "read past end");
+    memcpy(out, io.buf+io.pos, size);
+    io.pos += size;
+}
+
+size_t PngCoder::get_dib_size(const uint8_t *data, size_t size)
+{
+    return convert_to_dib(NULL, data, size);
+}
+
+typedef void line_fixup_t(uint8_t *line, unsigned int width);
+
+static void line_fixup_none(uint8_t *line, unsigned int width)
+{
+}
+
+static void line_fixup_2bpp_to_4bpp(uint8_t *line, unsigned int width)
+{
+    width = (width + 3) / 4u;
+    while (width--) {
+        uint8_t from = line[width];
+        line[width*2+1] = ((from & 0x03) << 0) | ((from & 0x0c) << 2);
+        line[width*2+0] = ((from & 0x30) >> 4) | ((from & 0xc0) >> 2);
+    }
+}
+
+size_t PngCoder::convert_to_dib(uint8_t *out_buf, const uint8_t *data, size_t size)
+{
+    ReadBufferIo io(data, size);
+
+    png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+    if (!png)
+        return 0;
+
+    png_infop info = png_create_info_struct(png);
+    if (!info) {
+        png_destroy_read_struct(&png, &info, NULL);
+        return 0;
+    }
+
+    if (setjmp(png_jmpbuf(png))) {
+        png_destroy_read_struct(&png, &info, NULL);
+        return 0;
+    }
+
+    png_set_read_fn(png, &io, read_from_bufio);
+
+    png_read_info(png, info);
+
+    // not so much precision is supported
+    unsigned int bits = png_get_bit_depth(png, info);
+    if (bits == 16)
+        png_set_strip_16(png);
+
+    unsigned int out_bits;
+    bool is_gray = false;
+    line_fixup_t *line_fixup = line_fixup_none;
+    switch (png_get_color_type(png, info)) {
+    case PNG_COLOR_TYPE_GRAY:
+        is_gray = true;
+        if (bits == 16) {
+            out_bits = 8;
+        } else if (bits == 2) {
+            line_fixup = line_fixup_2bpp_to_4bpp;
+            out_bits = 4;
+        } else {
+            out_bits = bits;
+        }
+        break;
+    case PNG_COLOR_TYPE_PALETTE:
+        // should return 1, 4 and 8, BMP does not support 2
+        out_bits = bits;
+        if (bits == 2) {
+            line_fixup = line_fixup_2bpp_to_4bpp;
+            out_bits = 4;
+        }
+        break;
+    case PNG_COLOR_TYPE_RGB:
+        png_set_bgr(png);
+        out_bits = 24;
+        break;
+    case PNG_COLOR_TYPE_RGB_ALPHA:
+        png_set_bgr(png);
+        out_bits = 24;
+        png_set_strip_alpha(png);
+        break;
+    case PNG_COLOR_TYPE_GRAY_ALPHA:
+        is_gray = true;
+        // gray with alpha should always be 8 bit but make it sure
+        // in case format change
+        png_set_expand_gray_1_2_4_to_8(png);
+        out_bits = 8;
+        png_set_strip_alpha(png);
+        break;
+    default:
+        png_error(png, "PNG color type not supported");
+        break;
+    }
+
+    const unsigned int width = png_get_image_width(png, info);
+    const unsigned int height = png_get_image_height(png, info);
+    const size_t stride = compute_dib_stride(width, out_bits);
+    const size_t image_size = stride * height;
+    int palette_colors;
+    // no palette
+    if (out_bits > 8) {
+        palette_colors = 0;
+    // 2 bit PNG converted to 4 bit BMP
+    } else if (bits == 2) {
+        palette_colors = 4;
+    } else {
+        palette_colors = 1 << out_bits;
+    }
+    const size_t palette_size = palette_colors * sizeof(RGBQUAD);
+    const size_t dib_size = sizeof(BITMAPINFOHEADER) + palette_size + image_size;
+
+    // just called to get the size, return the information
+    if (!out_buf) {
+        png_destroy_read_struct(&png, &info, NULL);
+        return dib_size;
+    }
+
+    // TODO tests
+    // bits, 1, 2, 4, 8, 16
+    // all color types
+    // alpha/not alpha
+    // indexed with not all colors
+
+    // fill header
+    BITMAPINFOHEADER& head(*(BITMAPINFOHEADER *)out_buf);
+    memset(&head, 0, sizeof(head));
+    head.biSize = sizeof(head);
+    head.biWidth = width;
+    head.biHeight = height;
+    head.biPlanes = 1;
+    head.biBitCount = out_bits;
+    head.biCompression = BI_RGB;
+    head.biSizeImage = image_size;
+
+    // copy palette
+    RGBQUAD *rgb = (RGBQUAD *)(out_buf + sizeof(BITMAPINFOHEADER));
+    if (is_gray) {
+        const unsigned int mult = 255 / (palette_colors - 1);
+        for (int color = 0; color < palette_colors; ++color) {
+            rgb->rgbBlue = rgb->rgbGreen = rgb->rgbRed = color * mult;
+            rgb->rgbReserved = 0;
+            ++rgb;
+        }
+        head.biClrUsed = palette_colors;
+    } else if (out_bits <= 8) {
+        png_colorp palette = NULL;
+        int num_palette;
+        if (!png_get_PLTE(png, info, &palette, &num_palette)) {
+            png_error(png, "error getting palette");
+        }
+        for (int color = 0; color < palette_colors; ++color) {
+            if (color < num_palette) {
+                rgb->rgbBlue = palette->blue;
+                rgb->rgbGreen = palette->green;
+                rgb->rgbRed = palette->red;
+            } else {
+                rgb->rgbBlue = rgb->rgbGreen = rgb->rgbRed = 0;
+            }
+            rgb->rgbReserved = 0;
+            ++rgb;
+            ++palette;
+        }
+        head.biClrUsed = palette_colors;
+    }
+
+    // now do the actual conversion!
+    uint8_t *dst = out_buf + sizeof(BITMAPINFOHEADER) + palette_size + image_size;
+    for (unsigned int row = 0; row < height; ++row) {
+        ((uint32_t*)dst)[-1] = 0; // padding
+        dst -= stride;
+        png_read_row(png, dst, NULL);
+        line_fixup(dst, width);
+    }
+
+    png_destroy_read_struct(&png, &info, NULL);
+    return dib_size;
+}
+
+void PngCoder::get_dib_data(uint8_t *dib, const uint8_t *data, size_t size)
+{
+    convert_to_dib(dib, data, size);
+}
+
+uint8_t *PngCoder::from_bitmap(const BITMAPINFO& info, const void *bits, long &size)
+{
+    // TODO not implemented
+    return NULL;
+}
+
+ImageCoder *create_png_coder()
+{
+    return new PngCoder();
+}
diff --git a/vdagent/imagepng.h b/vdagent/imagepng.h
new file mode 100644
index 0000000..1d1f654
--- /dev/null
+++ b/vdagent/imagepng.h
@@ -0,0 +1,25 @@
+/*
+   Copyright (C) 2017 Red Hat, Inc.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef VDAGENT_IMAGEPNG_H_
+#define VDAGENT_IMAGEPNG_H_
+
+#include "image.h"
+
+ImageCoder *create_png_coder();
+
+#endif
commit 95f603bdb0f66c696acf2bcb26ca838265725c45
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Tue Nov 8 14:34:06 2016 +0000

    Initial rewrite of image conversion code
    
    Remove CxImage linking.
    Support Windows BMP format.
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Christophe Fergeau <cfergeau at redhat.com>

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.
  *
commit 0fd488247795103d7832f209494581b5e37700d6
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Mon Nov 7 15:04:07 2016 +0000

    Move image handling to a separate file
    
    This will make easier to change code that handle images.
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Christophe Fergeau <cfergeau at redhat.com>

diff --git a/Makefile.am b/Makefile.am
index b60a718..868199e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -42,6 +42,8 @@ vdagent_SOURCES =			\
 	vdagent/vdagent.cpp		\
 	vdagent/as_user.cpp		\
 	vdagent/as_user.h		\
+	vdagent/image.cpp		\
+	vdagent/image.h			\
 	$(NULL)
 
 vdagent_rc.$(OBJEXT): vdagent/vdagent.rc
diff --git a/vdagent/image.cpp b/vdagent/image.cpp
new file mode 100644
index 0000000..960058d
--- /dev/null
+++ b/vdagent/image.cpp
@@ -0,0 +1,88 @@
+/*
+   Copyright (C) 2013-2017 Red Hat, Inc.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <spice/macros.h>
+
+#include "vdcommon.h"
+#include "image.h"
+
+#include "ximage.h"
+
+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)
+{
+    for (unsigned int i = 0; i < SPICE_N_ELEMENTS(image_types); i++) {
+        if (image_types[i].type == type) {
+            return image_types[i].cximage_format;
+        }
+    }
+    return 0;
+}
+
+HANDLE get_image_handle(const VDAgentClipboard& clipboard, uint32_t size, UINT&)
+{
+    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();
+    return clip_data;
+}
+
+uint8_t* get_raw_clipboard_image(const VDAgentClipboardRequest& clipboard_request,
+                                 HANDLE clip_data, long& new_size)
+{
+    new_size = 0;
+
+    CxImage image;
+    uint8_t *new_data = NULL;
+    DWORD cximage_format = get_cximage_format(clipboard_request.type);
+    HPALETTE pal = 0;
+
+    ASSERT(cximage_format);
+    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;
+    }
+    if (!image.Encode(new_data, new_size, cximage_format)) {
+        vd_printf("Image encode to type %u failed", clipboard_request.type);
+        return NULL;
+    }
+    vd_printf("Image encoded to %lu bytes", new_size);
+    return new_data;
+}
+
+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);
+}
diff --git a/vdagent/image.h b/vdagent/image.h
new file mode 100644
index 0000000..b70f53a
--- /dev/null
+++ b/vdagent/image.h
@@ -0,0 +1,48 @@
+/*
+   Copyright (C) 2013-2017 Red Hat, Inc.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef VDAGENT_IMAGE_H_
+#define VDAGENT_IMAGE_H_
+
+/**
+ * Returns image to put in the clipboard.
+ *
+ * @param         clipboard  data to write in the clipboard
+ * @param         size       size of data
+ * @param[in,out] format     suggested clipboard format. This can be changed by
+ *                           the function to reflect a better format
+ */
+HANDLE get_image_handle(const VDAgentClipboard& clipboard, uint32_t size, UINT& format);
+
+/**
+ * Return raw data got from the clipboard.
+ *
+ * Function could use clip_data or get new data from the clipboard.
+ * You should free data returned with free_raw_clipboard_image.
+ * @param      clipboard_request  request
+ * @param      clip_data          clipboard data
+ * @param[out] new_size           size of returned data
+ */
+uint8_t* get_raw_clipboard_image(const VDAgentClipboardRequest& clipboard_request,
+                                 HANDLE clip_data, long& new_size);
+
+/**
+ * Free data returned by get_raw_clipboard_image
+ */
+void free_raw_clipboard_image(uint8_t *data);
+
+#endif
diff --git a/vdagent/vdagent.cpp b/vdagent/vdagent.cpp
index bb07e1d..f00fbf5 100644
--- a/vdagent/vdagent.cpp
+++ b/vdagent/vdagent.cpp
@@ -19,7 +19,7 @@
 #include "desktop_layout.h"
 #include "display_setting.h"
 #include "file_xfer.h"
-#include "ximage.h"
+#include "image.h"
 #undef max
 #undef min
 #include <spice/macros.h>
@@ -55,16 +55,6 @@ static const VDClipboardFormat clipboard_formats[] = {
 
 #define clipboard_formats_count SPICE_N_ELEMENTS(clipboard_formats)
 
-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},
-};
-
 typedef struct ALIGN_VC VDIChunk {
     VDIChunkHeader hdr;
     uint8_t data[0];
@@ -725,23 +715,19 @@ bool VDAgent::handle_clipboard(VDAgentClipboard* clipboard, uint32_t size)
     if (clipboard->type == VD_AGENT_CLIPBOARD_NONE) {
         goto fin;
     }
+    format = get_clipboard_format(clipboard->type);
     switch (clipboard->type) {
     case VD_AGENT_CLIPBOARD_UTF8_TEXT:
         clip_data = utf8_alloc((LPCSTR)clipboard->data, size);
         break;
     case VD_AGENT_CLIPBOARD_IMAGE_PNG:
-    case VD_AGENT_CLIPBOARD_IMAGE_BMP: {
-        DWORD cximage_format = get_cximage_format(clipboard->type);
-        ASSERT(cximage_format);
-        CxImage image(clipboard->data, size, cximage_format);
-        clip_data = image.CopyToHandle();
+    case VD_AGENT_CLIPBOARD_IMAGE_BMP:
+        clip_data = get_image_handle(*clipboard, size, format);
         break;
-    }
     default:
         vd_printf("Unsupported clipboard type %u", clipboard->type);
         goto fin;
     }
-    format = get_clipboard_format(clipboard->type);
     if (format == 0) {
         vd_printf("Unknown clipboard format, type %u", clipboard->type);
         goto fin;
@@ -1104,7 +1090,6 @@ bool VDAgent::handle_clipboard_request(VDAgentClipboardRequest* clipboard_reques
     uint8_t* new_data = NULL;
     long new_size = 0;
     size_t len = 0;
-    CxImage image;
     VDAgentClipboard* clipboard = NULL;
 
     if (_clipboard_owner != owner_guest) {
@@ -1135,28 +1120,12 @@ bool VDAgent::handle_clipboard_request(VDAgentClipboardRequest* clipboard_reques
         new_size = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR)new_data, (int)len, NULL, 0, NULL, NULL);
         break;
     case VD_AGENT_CLIPBOARD_IMAGE_PNG:
-    case VD_AGENT_CLIPBOARD_IMAGE_BMP: {
-        DWORD cximage_format = get_cximage_format(clipboard_request->type);
-        HPALETTE pal = 0;
-
-        ASSERT(cximage_format);
-        if (IsClipboardFormatAvailable(CF_PALETTE)) {
-            pal = (HPALETTE)GetClipboardData(CF_PALETTE);
-        }
-        if (!image.CreateFromHBITMAP((HBITMAP)clip_data, pal)) {
-            vd_printf("Image create from handle failed");
-            break;
-        }
-        if (!image.Encode(new_data, new_size, cximage_format)) {
-            vd_printf("Image encode to type %u failed", clipboard_request->type);
-            break;
-        }
-        vd_printf("Image encoded to %lu bytes", new_size);
+    case VD_AGENT_CLIPBOARD_IMAGE_BMP:
+        new_data = get_raw_clipboard_image(*clipboard_request, clip_data, new_size);
         break;
     }
-    }
 
-    if (!new_size) {
+    if (!new_size || !new_data) {
         vd_printf("clipboard is empty");
         goto handle_clipboard_request_fail;
     }
@@ -1184,7 +1153,7 @@ bool VDAgent::handle_clipboard_request(VDAgentClipboardRequest* clipboard_reques
     case VD_AGENT_CLIPBOARD_IMAGE_PNG:
     case VD_AGENT_CLIPBOARD_IMAGE_BMP:
         memcpy(clipboard->data, new_data, new_size);
-        image.FreeMemory(new_data);
+        free_raw_clipboard_image(new_data);
         break;
     }
     CloseClipboard();
@@ -1242,16 +1211,6 @@ uint32_t VDAgent::get_clipboard_type(uint32_t format) const
     return 0;
 }
 
-DWORD VDAgent::get_cximage_format(uint32_t type) const
-{
-    for (unsigned int i = 0; i < SPICE_N_ELEMENTS(image_types); i++) {
-        if (image_types[i].type == type) {
-            return image_types[i].cximage_format;
-        }
-    }
-    return 0;
-}
-
 void VDAgent::set_clipboard_owner(int new_owner)
 {
     // FIXME: Clear requests, clipboard data and state


More information about the Spice-commits mailing list