Acked-by: Christophe Fergeau <cfergeau@xxxxxxxxxx> On Tue, Jul 25, 2017 at 06:33:33PM +0100, Frediano Ziglio wrote: > Signed-off-by: Frediano Ziglio <fziglio@xxxxxxxxxx> > --- > Makefile.am | 6 +- > configure.ac | 3 + > vdagent/image.cpp | 8 +- > vdagent/imagepng.cpp | 245 +++++++++++++++++++++++++++++++++++++++++++++++++++ > vdagent/imagepng.h | 25 ++++++ > 5 files changed, 278 insertions(+), 9 deletions(-) > create mode 100644 vdagent/imagepng.cpp > create mode 100644 vdagent/imagepng.h > > 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 > -- > 2.13.3 > > _______________________________________________ > Spice-devel mailing list > Spice-devel@xxxxxxxxxxxxxxxxxxxxx > https://lists.freedesktop.org/mailman/listinfo/spice-devel
Attachment:
signature.asc
Description: PGP signature
_______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel