diff --git a/io-webp.c b/io-webp.c index a156729..c67e0a9 100644 --- a/io-webp.c +++ b/io-webp.c @@ -28,13 +28,10 @@ typedef struct GdkPixbufModuleUpdatedFunc update_func; GdkPixbufModulePreparedFunc prepare_func; gpointer user_data; - WebPDecoderConfig deccfg; gboolean got_header; gboolean is_animation; gboolean has_alpha; GByteArray *buffer; - WebPIDecoder *idec; - GdkPixbuf *pb; gint width; gint height; } WebPContext; @@ -51,13 +48,10 @@ begin_load (GdkPixbufModuleSizeFunc size_func, context->prepare_func = prepare_func; context->update_func = update_func; context->user_data = user_data; - context->deccfg = (WebPDecoderConfig){ 0 }; context->got_header = FALSE; context->is_animation = FALSE; context->has_alpha = FALSE; context->buffer = NULL; - context->idec = NULL; - context->pb = NULL; context->width = 0; context->height = 0; @@ -116,88 +110,11 @@ load_increment (gpointer data, const guchar *buf, guint size, GError **error) context->has_alpha = features.has_alpha; context->is_animation = features.has_animation; - if (! context->is_animation) - { - gchar *icc_data = NULL; - WebPData wp_data = { .bytes = buf, .size = size }; - WebPMux *mux = WebPMuxCreate (&wp_data, FALSE); - if (mux) - { - WebPData icc_profile = { 0 }; - if (WebPMuxGetChunk (mux, "ICCP", &icc_profile) == WEBP_MUX_OK - && icc_profile.bytes) - icc_data = g_base64_encode (icc_profile.bytes, icc_profile.size); - g_clear_pointer (&mux, WebPMuxDelete); - } - - context->pb = gdk_pixbuf_new (GDK_COLORSPACE_RGB, context->has_alpha, - 8, context->width, context->height); - - if (! context->pb) - { - g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, - "Could not allocate GdkPixbuf"); - return FALSE; - } - - if (icc_data) - { - gdk_pixbuf_set_option (context->pb, "icc-profile", icc_data); - g_clear_pointer (&icc_data, g_free); - } - - WebPDecoderConfig config; - init_dec_config (&config, context->pb); - - context->idec = WebPIDecode (NULL, 0, &config); - - if (! context->idec) - { - g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, - "Could not allocate WebP incremental decoder"); - return FALSE; - } - - if (context->prepare_func && context->pb) - { - context->prepare_func (context->pb, NULL, context->user_data); - } - } - else - { - context->buffer = g_byte_array_new (); - } + context->buffer = g_byte_array_new (); } if (context->buffer) - { - g_byte_array_append (context->buffer, buf, size); - } - else if (context->pb && context->idec) - { - VP8StatusCode status = WebPIAppend (context->idec, buf, (size_t) size); - if (status != VP8_STATUS_OK && status != VP8_STATUS_SUSPENDED) - { - g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, - "Could not incrementally decode WebP stream chunk"); - return FALSE; - } - - gint last_y = 0; - gint w = 0; - if (WebPIDecGetRGB (context->idec, &last_y, &w, NULL, NULL) == NULL - && status != VP8_STATUS_SUSPENDED) - { - g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, - "Bad inputs to WebP decoder."); - return FALSE; - } - - if (status != VP8_STATUS_SUSPENDED && context->update_func) - { - context->update_func (context->pb, 0, 0, w, last_y, context->user_data); - } - } + g_byte_array_append (context->buffer, buf, size); return TRUE; } @@ -232,9 +149,55 @@ stop_load (gpointer data, GError **error) g_clear_object (&iter); g_clear_object (&anim); } - else if (context->got_header && context->pb) + else if (context->got_header && context->buffer) { - ret = TRUE; + gchar *icc_data = NULL; + WebPData wp_data = { .bytes = context->buffer->data, + .size = context->buffer->len }; + WebPMux *mux = WebPMuxCreate (&wp_data, FALSE); + if (mux) + { + WebPData icc_profile = { 0 }; + if (WebPMuxGetChunk (mux, "ICCP", &icc_profile) == WEBP_MUX_OK + && icc_profile.bytes) + icc_data = g_base64_encode (icc_profile.bytes, icc_profile.size); + g_clear_pointer (&mux, WebPMuxDelete); + } + + GdkPixbuf *pb = gdk_pixbuf_new (GDK_COLORSPACE_RGB, context->has_alpha, 8, + context->width, context->height); + + if (! pb) + { + g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, + "Could not allocate GdkPixbuf"); + return FALSE; + } + + if (icc_data) + { + gdk_pixbuf_set_option (pb, "icc-profile", icc_data); + g_clear_pointer (&icc_data, g_free); + } + + WebPDecoderConfig config; + init_dec_config (&config, pb); + + VP8StatusCode status = WebPDecode (context->buffer->data, + context->buffer->len, &config); + if (status == VP8_STATUS_OK) + { + if (context->prepare_func) + context->prepare_func (pb, NULL, context->user_data); + + g_clear_object (&pb); + + ret = TRUE; + } + else { + g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, + "WebP decoder failed with VP8 status code: %d", status); + } } if (context->buffer) @@ -243,8 +206,6 @@ stop_load (gpointer data, GError **error) context->buffer = NULL; } - g_clear_object (&context->pb); - g_clear_pointer (&context->idec, WebPIDelete); g_clear_pointer (&context, g_free); return ret; } diff --git a/meson.build b/meson.build index 6fc1127..f4c96f1 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,6 @@ project('webp-pixbuf-loader', 'c', meson_version: '>=0.54') cc = meson.get_compiler('c') +gio = dependency('gio-2.0', method: 'pkg-config') gdkpb = dependency('gdk-pixbuf-2.0', version: '>2.22.0', method: 'pkg-config') gdk_pb_moddir = get_option('gdk_pixbuf_moduledir') if gdk_pb_moddir == '' diff --git a/tests/meson.build b/tests/meson.build index b20621c..f78a94b 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -9,7 +9,7 @@ t_icc = executable('t_icc', 't_icc.c', dependencies : [gdk t_null_error = executable('t_null_error', 't_null_error.c', dependencies : [gdkpb, webp, webpdemux]) t_scaled = executable('t_scaled', 't_scaled.c', dependencies : [gdkpb, webp, webpdemux]) t_jpeg = executable('t_jpeg', 't_jpeg.c', dependencies : [gdkpb, webp, webpdemux]) -t_large = executable('t_large', 't_large.c', dependencies : [gdkpb, webp, webpdemux]) +t_large = executable('t_large', 't_large.c', dependencies : [gdkpb, webp, webpdemux, gio]) loaders_data = configuration_data() loaders_data.set('MODULE_PATH', fs.as_posix(pbl_webp.full_path())) diff --git a/tests/t_large.c b/tests/t_large.c index f7bf041..a83db2e 100644 --- a/tests/t_large.c +++ b/tests/t_large.c @@ -1,5 +1,7 @@ #include +#define READ_BUFFER_SIZE 65535 + gint main (gint argc, gchar **argv) { @@ -10,14 +12,12 @@ main (gint argc, gchar **argv) = gdk_pixbuf_new_from_file (g_environ_getenv (env, "TEST_FILE"), &error); if (error) - g_error ("%s", error->message); - - g_assert (error == NULL); + g_error ("%s", error->message); g_assert_cmpint (gdk_pixbuf_get_width (pixbuf), ==, 4096); g_assert_cmpint (gdk_pixbuf_get_height (pixbuf), ==, 4096); + g_clear_object (&pixbuf); g_strfreev (env); - g_object_unref (pixbuf); return 0; } \ No newline at end of file