diff --git a/configure.ac b/configure.ac index b74bf97..b1522db 100644 --- a/configure.ac +++ b/configure.ac @@ -62,6 +62,15 @@ AS_IF([test "x$enable_libwebp" != "xno"], [ AC_CHECK_LIB([webp], [WebPDecodeRGBA], [], [AC_MSG_ERROR([no libwebp found, try --disable-libwebp, but stickers won't be displayed in the chat])]) ]) +AC_MSG_CHECKING([for libpng]) +AC_ARG_ENABLE([libpng], + AS_HELP_STRING([--disable-libpng], [Disable libpng, stickers won't be converted])) + +AS_IF([test "x$enable_libpng" != "xno"], [ + AC_MSG_RESULT([enabled]) + AC_CHECK_LIB([png], [png_write_png], [], [AC_MSG_ERROR([no libpng found, try --disable-libpng])]) + ]) + AC_ARG_ENABLE([icons], AS_HELP_STRING([--disable-icons], [Unsupported option. Use 'make noicon_install' instead.])) AS_IF([test "x$enable_icons" == "xno"], [ diff --git a/tgp-2prpl.c b/tgp-2prpl.c index 24b319b..5e9dd80 100644 --- a/tgp-2prpl.c +++ b/tgp-2prpl.c @@ -24,6 +24,10 @@ #include #endif +#ifdef HAVE_LIBPNG +#include +#endif + PurpleAccount *tls_get_pa (struct tgl_state *TLS) { return tls_get_data (TLS)->pa; } @@ -193,6 +197,88 @@ int p2tgl_imgstore_add_with_id_raw (const unsigned char *raw_bgra, unsigned widt return purple_imgstore_add_with_id (tga, tga_len, NULL); } +#ifdef HAVE_LIBPNG + +struct mem_encode +{ + char *buffer; + size_t size; +}; + +static void p2tgl_png_mem_write (png_structp png_ptr, png_bytep data, png_size_t length) { + struct mem_encode *p = (struct mem_encode *) png_get_io_ptr(png_ptr); + size_t nsize = p->size + length; + + if (p->buffer) + p->buffer = g_realloc(p->buffer, nsize); + else + p->buffer = g_malloc(nsize); + + memcpy(p->buffer + p->size, data, length); + p->size = nsize; +} + +int p2tgl_imgstore_add_with_id_png (const unsigned char *raw_bitmap, unsigned width, unsigned height) { + struct mem_encode state = {NULL, 0}; + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; + png_bytepp rows = NULL; + + // init png write struct + png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (png_ptr == NULL) { + warning ("error encoding png (create_write_struct failed)"); + return 0; + } + + // init png info struct + info_ptr = png_create_info_struct (png_ptr); + if (info_ptr == NULL) { + png_destroy_write_struct(&png_ptr, NULL); + warning ("error encoding png (create_info_struct failed)"); + return 0; + } + + // Set up error handling. + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_write_struct(&png_ptr, &info_ptr); + warning ("error while writing png"); + return 0; + } + + // set img attributes + png_set_IHDR (png_ptr, info_ptr, width, height, + 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + + // alloc row pointers + rows = (png_bytepp) malloc(height * sizeof(png_bytep)); + if (rows == NULL) { + png_destroy_write_struct(&png_ptr, &info_ptr); + warning ("error converting to png: malloc failed"); + return 0; + } + + unsigned i; + for (i = 0; i < height; i++) + rows[i] = (png_bytep)(raw_bitmap + (height - i) * width * 4); + + // set own png write function + png_set_write_fn (png_ptr, &state, p2tgl_png_mem_write, NULL); + + // write png + png_set_rows (png_ptr, info_ptr, rows); + png_write_png (png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); + + // cleanup + free(rows); + png_destroy_write_struct (&png_ptr, &info_ptr); + + return purple_imgstore_add_with_id (state.buffer, state.size, NULL); +} + +#endif /* HAVE_LIBPNG */ + #ifdef HAVE_LIBWEBP static const int MAX_W = 256; @@ -235,7 +321,11 @@ int p2tgl_imgstore_add_with_id_webp (const char *filename) { } config.options.use_scaling = 1; } +#ifdef HAVE_LIBPNG + config.output.colorspace = MODE_RGBA; +#else config.output.colorspace = MODE_BGRA; +#endif if (WebPDecode(data, len, &config) != VP8_STATUS_OK) { warning ("error decoding webp: %s", filename); g_free ((gchar *)data); @@ -245,7 +335,11 @@ int p2tgl_imgstore_add_with_id_webp (const char *filename) { const uint8_t *decoded = config.output.u.RGBA.rgba; // convert and add +#ifdef HAVE_LIBPNG + int imgStoreId = p2tgl_imgstore_add_with_id_png(decoded, config.options.scaled_width, config.options.scaled_height); +#else int imgStoreId = p2tgl_imgstore_add_with_id_raw(decoded, config.options.scaled_width, config.options.scaled_height); +#endif WebPFreeDecBuffer (&config.output); return imgStoreId; }