From caca14036c0b26df6eef4cdaef9cb7811545d52b Mon Sep 17 00:00:00 2001 From: Přemysl Eric Janouch Date: Sat, 11 Dec 2021 18:25:25 +0100 Subject: Add preliminary direct support for WebP --- fastiv-io.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) (limited to 'fastiv-io.c') diff --git a/fastiv-io.c b/fastiv-io.c index 87e26b3..e637d1d 100644 --- a/fastiv-io.c +++ b/fastiv-io.c @@ -33,6 +33,9 @@ #ifdef HAVE_XCURSOR #include #endif // HAVE_XCURSOR +#ifdef HAVE_LIBWEBP +#include +#endif // HAVE_LIBWEBP #ifdef HAVE_LIBHEIF #include #endif // HAVE_LIBHEIF @@ -1110,6 +1113,67 @@ open_xcursor(const gchar *data, gsize len, GError **error) } #endif // HAVE_XCURSOR -------------------------------------------------------- +#ifdef HAVE_LIBWEBP //--------------------------------------------------------- + +static cairo_surface_t * +open_libwebp(const gchar *data, gsize len, GError **error) +{ + // It is wholly zero-initialized by libwebp. + WebPDecoderConfig config = {}; + if (!WebPInitDecoderConfig(&config)) { + set_error(error, "libwebp version mismatch"); + return NULL; + } + + // TODO(p): Differentiate between a bad WebP, and not a WebP. + VP8StatusCode err = 0; + if ((err = WebPGetFeatures((const uint8_t *) data, len, &config.input))) { + set_error(error, "WebP decoding error"); + return NULL; + } + + cairo_surface_t *result = NULL; + + cairo_surface_t *surface = cairo_image_surface_create( + config.input.has_alpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24, + config.input.width, config.input.height); + cairo_status_t surface_status = cairo_surface_status(surface); + if (surface_status != CAIRO_STATUS_SUCCESS) { + set_error(error, cairo_status_to_string(surface_status)); + goto fail; + } + + config.options.use_threads = true; + + config.output.width = config.input.width; + config.output.height = config.input.height; + config.output.is_external_memory = true; + config.output.u.RGBA.rgba = cairo_image_surface_get_data(surface); + config.output.u.RGBA.stride = cairo_image_surface_get_stride(surface); + config.output.u.RGBA.size = + config.output.u.RGBA.stride * cairo_image_surface_get_height(surface); + if (G_BYTE_ORDER == G_LITTLE_ENDIAN) + config.output.colorspace = MODE_bgrA; + else + config.output.colorspace = MODE_Argb; + + if ((err = WebPDecode((const uint8_t *) data, len, &config))) { + set_error(error, "WebP decoding error"); + goto fail; + } + + // TODO(p): Extract metadata, support animations (has_animation). + result = surface; + +fail: + if (!result) + cairo_surface_destroy(surface); + + WebPFreeDecBuffer(&config.output); + return result; +} + +#endif // HAVE_LIBWEBP -------------------------------------------------------- #ifdef HAVE_LIBHEIF //--------------------------------------------------------- static cairo_surface_t * @@ -1683,6 +1747,14 @@ fastiv_io_open_from_data(const char *data, size_t len, const gchar *path, g_clear_error(error); } #endif // HAVE_XCURSOR -------------------------------------------------------- +#ifdef HAVE_LIBWEBP //--------------------------------------------------------- + if ((surface = open_libwebp(data, len, error))) + break; + if (error) { + g_debug("%s", (*error)->message); + g_clear_error(error); + } +#endif // HAVE_LIBWEBP -------------------------------------------------------- #ifdef HAVE_LIBHEIF //--------------------------------------------------------- if ((surface = open_libheif(data, len, path, error))) break; -- cgit v1.2.3-54-g00ecf