Package: release.debian.org Severity: normal User: release.debian....@packages.debian.org Usertags: unblock X-Debbugs-Cc: webp-pixbuf-loa...@packages.debian.org Control: affects -1 + src:webp-pixbuf-loader
Please unblock package webp-pixbuf-loader [ Reason ] Version 0.0.5 contains multiple bugs and 0.2.0 [1] I pushed was solution to these problems. Sadly meanwhile 0.2.1 [2] was release with another fix, which we pushed, but it didn't got into timeframe for 10 days acceptance. [1] https://github.com/aruiz/webp-pixbuf-loader/releases/tag/0.2.0 [2] https://github.com/aruiz/webp-pixbuf-loader/releases/tag/0.2.1 [ Impact ] Buggy user experience on old codebase, multiple critical and not resolved bugs. [ Tests ] The package has autopkgtests, which has been extended in 0.2.0 and 0.2.1. [ Risks ] Package itself is very small and after codebase rework, the fixes are incremental and self-explaining covered with tests. [ Checklist ] [ ] all changes are documented in the d/changelog [x] I reviewed all changes and I approve them [p] attach debdiff against the package in testing [ Other info ] I attach diff against the previously sent 0.2.0, since that was targeted to get into bookworm. If requested, I can send debdiff against 0.0.5. ``` --- webp-pixbuf-loader-0.2.0/debian/changelog 2023-02-26 11:55:51.000000000 +0100 +++ webp-pixbuf-loader-0.2.1/debian/changelog 2023-03-04 01:30:48.000000000 +0100 @@ -1,3 +1,11 @@ +webp-pixbuf-loader (0.2.1-1) UNRELEASED; urgency=medium + + [ David Heidelberg ] + * New upstream version 0.2.1 (Closes: #1032334) + * d/tests: extend tests by two new upstream tests + + -- David Heidelberg <da...@ixit.cz> Sat, 04 Mar 2023 01:30:48 +0100 + webp-pixbuf-loader (0.2.0-1) unstable; urgency=medium * New upstream version 0.2.0 diff -Nru webp-pixbuf-loader-0.2.0/debian/tests/determinism-test webp-pixbuf-loader-0.2.1/debian/tests/determinism-test --- webp-pixbuf-loader-0.2.0/debian/tests/determinism-test 2023-02-26 11:55:51.000000000 +0100 +++ webp-pixbuf-loader-0.2.1/debian/tests/determinism-test 2023-03-04 01:30:48.000000000 +0100 @@ -4,7 +4,7 @@ set -eu -gdk-pixbuf-thumbnailer -s 128 tests/t1.webp test1.png +gdk-pixbuf-thumbnailer -s 128 tests/data/t1.webp test1.png file -i test1.png | grep -qFw image/png -gdk-pixbuf-thumbnailer -s 128 tests/t1.webp test2.png +gdk-pixbuf-thumbnailer -s 128 tests/data/t1.webp test2.png cmp -s test1.png test2.png diff -Nru webp-pixbuf-loader-0.2.0/debian/tests/upstream-tests webp-pixbuf-loader-0.2.1/debian/tests/upstream-tests --- webp-pixbuf-loader-0.2.0/debian/tests/upstream-tests 2023-02-26 11:55:51.000000000 +0100 +++ webp-pixbuf-loader-0.2.1/debian/tests/upstream-tests 2023-03-04 01:30:48.000000000 +0100 @@ -4,8 +4,10 @@ set -ex -TEST_FILE="./tests/t1.webp" ./obj*/tests/t1 -TEST_FILE="./tests/t2.webp" ./obj*/tests/t2 -TEST_FILE="./tests/t3.webp" ./obj*/tests/t3 -TEST_FILE="./tests/t1.webp" ./obj*/tests/t4 -TEST_FILE="./tests/t2.webp" ./obj*/tests/t_save +TEST_FILE="./tests/data/t1.webp" ./obj*/tests/t1 +TEST_FILE="./tests/data/t2.webp" ./obj*/tests/t2 +TEST_FILE="./tests/data/t3.webp" ./obj*/tests/t3 +TEST_FILE="./tests/data/t1.webp" ./obj*/tests/t4 +TEST_FILE="./tests/data/t2.webp" ./obj*/tests/t_save +TEST_FILE="./tests/data/t2.webp" ./obj*/tests/t_icc +TEST_FILE="./tests/data/t2.webp" ./obj*/tests/t_null_error diff -Nru webp-pixbuf-loader-0.2.0/io-webp.c webp-pixbuf-loader-0.2.1/io-webp.c --- webp-pixbuf-loader-0.2.0/io-webp.c 2023-02-23 23:30:45.000000000 +0100 +++ webp-pixbuf-loader-0.2.1/io-webp.c 2023-03-04 00:36:54.000000000 +0100 @@ -12,6 +12,7 @@ #include "io-webp.h" #include "io-webp-anim.h" +#include <webp/mux.h> static gpointer begin_load (GdkPixbufModuleSizeFunc size_func, @@ -192,7 +193,7 @@ write_file (const uint8_t *data, size_t data_size, const WebPPicture *const pic) { FILE *const out = (FILE *) pic->custom_ptr; - return data_size ? (fwrite (data, data_size, 1, out) == 1) : 1; + return data_size == fwrite (data, sizeof (guchar), data_size, out) ? TRUE : FALSE; } /* Encoder write callback to accumulate output data in a GByteArray */ @@ -207,7 +208,7 @@ static gboolean is_save_option_supported (const gchar *option_key) { - char *options[3] = { "quality", "preset", NULL }; + char *options[4] = { "quality", "preset", "icc-profile", NULL }; for (char **o = options; *o; o++) { if (g_strcmp0 (*o, option_key) == 0) @@ -216,6 +217,40 @@ return FALSE; } +/* Creates a new image data buffer with the ICC profile data in it */ +WebPData +add_icc_data (WebPData *image_data, WebPData *icc_data, GError **error) +{ + WebPMux *mux = WebPMuxCreate (image_data, FALSE); + + if (mux == NULL) + { + g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, + "Could not create WebPMux instance"); + return (WebPData){ 0 }; + } + + if (WebPMuxSetChunk (mux, "ICCP", icc_data, FALSE) != WEBP_MUX_OK) + { + g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, + "Could not set ICC profile data WebP using Muxer"); + WebPMuxDelete (mux); + return (WebPData){ 0 }; + } + + WebPData output = { 0 }; + if (WebPMuxAssemble (mux, &output) != WEBP_MUX_OK) + { + g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, + "Could not assemble WebP data using Muxer"); + WebPMuxDelete (mux); + return (WebPData){ 0 }; + } + + WebPMuxDelete (mux); + return output; +} + static gboolean save_webp (GdkPixbuf *pixbuf, gchar **keys, @@ -227,6 +262,10 @@ { WebPPicture picture; WebPConfig config; + uint8_t *icc_data = NULL; + gsize icc_data_len = 0; + + g_clear_error (error); if (! WebPPictureInit (&picture) || ! WebPConfigInit (&config)) { @@ -242,14 +281,18 @@ while (*kiter) { - if (strncmp (*kiter, "quality", 7) == 0) + if (g_strcmp0 (*kiter, "quality") == 0) { guint64 quality; if (! g_ascii_string_to_unsigned (*viter, 10, 0, 100, &quality, error)) return FALSE; config.quality = (float) quality; } - else if (strncmp (*kiter, "preset", 6) == 0) + else if (g_strcmp0 (*kiter, "icc-profile") == 0) + { + icc_data = g_base64_decode (*viter, &icc_data_len); + } + else if (g_strcmp0 (*kiter, "preset") == 0) { gchar *PRESET_KEYS[7] = { "default", "picture", "photo", "drawing", "icon", "text", @@ -314,12 +357,14 @@ return FALSE; } - if (save_func) + gboolean uses_array = save_func || icc_data; + + if (uses_array) { picture.writer = write_array; picture.custom_ptr = (void *) g_byte_array_new (); } - else if (f) + else if (f && ! icc_data) { picture.writer = write_file; picture.custom_ptr = (void *) f; @@ -336,26 +381,45 @@ { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_BAD_OPTION, "Could not encode WebP data"); - if (save_func && picture.custom_ptr) + if ((save_func || icc_data) && picture.custom_ptr) g_byte_array_free ((GByteArray *) picture.custom_ptr, TRUE); WebPPictureFree (&picture); return FALSE; } - if (save_func) + gpointer custom_ptr = picture.custom_ptr; + WebPPictureFree (&picture); + + if (uses_array) { - GByteArray *arr = (GByteArray *) picture.custom_ptr; - save_func ((const gchar *) arr->data, arr->len, error, user_data); - g_byte_array_free (arr, TRUE); + WebPData data; // NOTE We can't do field initialization since we can't get length after free + data.size = ((GByteArray *) custom_ptr)->len; + data.bytes = g_byte_array_free ((GByteArray *) custom_ptr, FALSE); - if (*error) + if (icc_data) { - WebPPictureFree (&picture); - return FALSE; + WebPData icc_wpdata = { .bytes = icc_data, .size = icc_data_len }; + + WebPData output = add_icc_data (&data, &icc_wpdata, error); + g_clear_pointer (&icc_data, g_free); + g_free ((gpointer) data.bytes); + + if (output.bytes == NULL) + return FALSE; + + data = output; } + + gboolean ret = FALSE; + if (save_func) + ret = save_func ((const gchar *) data.bytes, data.size, error, user_data); + else if (f) + ret = fwrite (data.bytes, sizeof (guchar), data.size, f) == data.size ? TRUE : FALSE; + + WebPDataClear (&data); + return ret; } - WebPPictureFree (&picture); return TRUE; } diff -Nru webp-pixbuf-loader-0.2.0/meson.build webp-pixbuf-loader-0.2.1/meson.build --- webp-pixbuf-loader-0.2.0/meson.build 2023-02-23 23:30:45.000000000 +0100 +++ webp-pixbuf-loader-0.2.1/meson.build 2023-03-04 00:36:54.000000000 +0100 @@ -8,10 +8,11 @@ webp = dependency('libwebp', version: '>0.4.3') webpdemux = dependency('libwebpdemux', version: '>0.4.3') +webpmux = dependency('libwebpmux', version: '>0.4.3') pbl_webp = shared_module('pixbufloader-webp', sources: ['io-webp.c', 'io-webp-anim.c', 'io-webp-anim-iter.c'], - dependencies: [gdkpb, webp, webpdemux], + dependencies: [gdkpb, webp, webpdemux, webpmux], # Workaround for https://gitlab.gnome.org/GNOME/glib/issues/1413 name_suffix: host_machine.system() == 'darwin' ? 'so' : [], install: true, Binary files /tmp/X5m3CJJqgJ/webp-pixbuf-loader-0.2.0/tests/data/t1.webp and /tmp/NfIwvAZLnM/webp-pixbuf-loader-0.2.1/tests/data/t1.webp differ Binary files /tmp/X5m3CJJqgJ/webp-pixbuf-loader-0.2.0/tests/data/t2.webp and /tmp/NfIwvAZLnM/webp-pixbuf-loader-0.2.1/tests/data/t2.webp differ Binary files /tmp/X5m3CJJqgJ/webp-pixbuf-loader-0.2.0/tests/data/t3.webp and /tmp/NfIwvAZLnM/webp-pixbuf-loader-0.2.1/tests/data/t3.webp differ diff -Nru webp-pixbuf-loader-0.2.0/tests/gtk3-animation-sample.c webp-pixbuf-loader-0.2.1/tests/gtk3-animation-sample.c --- webp-pixbuf-loader-0.2.0/tests/gtk3-animation-sample.c 2023-02-23 23:30:45.000000000 +0100 +++ webp-pixbuf-loader-0.2.1/tests/gtk3-animation-sample.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,97 +0,0 @@ -#include <gdk-pixbuf/gdk-pixbuf.h> -#include <gtk/gtk.h> - -/* This test is not an automated test. - * It is intended to allow one to eye-ball webp animated images - * in a debug environment, to see if there are problems with - * image reproduction, timing, etc. - */ - -typedef struct _AnimationStructure -{ - GtkWindow *window; - GdkPixbufAnimation *anim; - GdkPixbufAnimationIter *anim_iter; - GtkWidget *image; - int delay; -} AnimationStructure; - -gboolean -delete_objects (GtkWidget *widget, GdkEvent *event, gpointer data) -{ - AnimationStructure *ani = (AnimationStructure *) data; - if (ani->anim) - g_object_unref (ani->anim); - - g_free (ani); - return FALSE; -} - -static void -activate (GtkApplication *app, gpointer user_data) -{ - GtkWidget *window; - GtkWidget *label; - AnimationStructure *ani = (AnimationStructure *) user_data; - - window = gtk_application_window_new (app); - GtkWidget *box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - label = gtk_label_new ("Test WebP Animation"); - gtk_container_add (GTK_CONTAINER (box), label); - - GtkWidget *image = NULL; - - /*GdkPixbuf *staticPixbuf = NULL; - staticPixbuf = gdk_pixbuf_animation_get_static_image (ani->anim); - image = gtk_image_new_from_pixbuf (staticPixbuf); - */ - - image = gtk_image_new_from_animation (ani->anim); - gtk_container_add (GTK_CONTAINER (box), image); - gtk_container_add (GTK_CONTAINER (window), box); - gtk_window_set_title (GTK_WINDOW (window), "Test"); - gtk_window_set_default_size (GTK_WINDOW (window), 500, 500); - g_signal_connect (G_OBJECT (window), "delete-event", G_CALLBACK (delete_objects), ani); - gtk_widget_show_all (window); -} /* end of function activate */ - -gint -main (gint argc, gchar **argv) -{ - GError *error = NULL; - gchar **env = g_get_environ (); - g_warning ("%s", g_environ_getenv (env, "TEST_FILE")); - gtk_init (&argc, &argv); - - /* setup animation. */ - GdkPixbufAnimation *anim = NULL; - GdkPixbufAnimationIter *anim_iter = NULL; - anim = gdk_pixbuf_animation_new_from_file (g_environ_getenv (env, "TEST_" - "FILE"), - &error); - gboolean isStatic = gdk_pixbuf_animation_is_static_image (anim); - if (! isStatic) - { - GtkApplication *app; - - G_GNUC_BEGIN_IGNORE_DEPRECATIONS - GTimeVal curTime; - g_get_current_time (&curTime); - G_GNUC_END_IGNORE_DEPRECATIONS - - AnimationStructure *ani = g_new0 (AnimationStructure, 1); - ani->anim = anim; - - anim_iter = gdk_pixbuf_animation_get_iter (anim, &curTime); - int delay = gdk_pixbuf_animation_iter_get_delay_time (anim_iter); - ani->anim_iter = anim_iter; - ani->delay = delay; - app = gtk_application_new (NULL, G_APPLICATION_FLAGS_NONE); - g_signal_connect (app, "activate", G_CALLBACK (activate), ani); - (void) g_application_run (G_APPLICATION (app), argc, argv); - g_object_unref (app); - } - - g_strfreev (env); - return 0; -} diff -Nru webp-pixbuf-loader-0.2.0/tests/meson.build webp-pixbuf-loader-0.2.1/tests/meson.build --- webp-pixbuf-loader-0.2.0/tests/meson.build 2023-02-23 23:30:45.000000000 +0100 +++ webp-pixbuf-loader-0.2.1/tests/meson.build 2023-03-04 00:36:54.000000000 +0100 @@ -5,6 +5,8 @@ t3 = executable('t3', 't3.c', dependencies : [gdkpb, webp, webpdemux]) t4 = executable('t4', 't4.c', dependencies : [gdkpb, webp, webpdemux]) t_save = executable('t_save', 't_save.c', dependencies : [gdkpb, webp, webpdemux]) +t_icc = executable('t_icc', 't_icc.c', dependencies : [gdkpb, webp, webpdemux, webpmux]) +t_null_error = executable('t_null_error', 't_null_error.c', dependencies : [gdkpb, webp, webpdemux]) loaders_data = configuration_data() loaders_data.set('MODULE_PATH', fs.as_posix(pbl_webp.full_path())) @@ -13,10 +15,12 @@ configuration : loaders_data) test_env = ['GDK_PIXBUF_MODULE_FILE=' + meson.current_build_dir() / 'loaders.cache'] -test_file_base = 'TEST_FILE=' + meson.current_source_dir() +test_file_base = 'TEST_FILE=' + meson.current_source_dir() / 'data' test('load 1x1 image', t1, env : test_env + [ test_file_base / 't1.webp']) test('load 200x200 image', t2, env : test_env + [ test_file_base / 't2.webp']) test('load animation', t3, env : test_env + [ test_file_base / 't3.webp']) test('get file info', t4, env : test_env + [ test_file_base / 't1.webp']) -test('save data', t_save, env : test_env + [ test_file_base / 't2.webp']) \ No newline at end of file +test('save data', t_save, env : test_env + [ test_file_base / 't2.webp']) +test('icc data', t_icc, env : test_env + [ test_file_base / 't2.webp']) +test('NULL GError', t_null_error, env : test_env + [ test_file_base / 't2.webp']) \ No newline at end of file Binary files /tmp/X5m3CJJqgJ/webp-pixbuf-loader-0.2.0/tests/t1.webp and /tmp/NfIwvAZLnM/webp-pixbuf-loader-0.2.1/tests/t1.webp differ Binary files /tmp/X5m3CJJqgJ/webp-pixbuf-loader-0.2.0/tests/t2.webp and /tmp/NfIwvAZLnM/webp-pixbuf-loader-0.2.1/tests/t2.webp differ Binary files /tmp/X5m3CJJqgJ/webp-pixbuf-loader-0.2.0/tests/t3.webp and /tmp/NfIwvAZLnM/webp-pixbuf-loader-0.2.1/tests/t3.webp differ diff -Nru webp-pixbuf-loader-0.2.0/tests/t_icc.c webp-pixbuf-loader-0.2.1/tests/t_icc.c --- webp-pixbuf-loader-0.2.0/tests/t_icc.c 1970-01-01 01:00:00.000000000 +0100 +++ webp-pixbuf-loader-0.2.1/tests/t_icc.c 2023-03-04 00:36:54.000000000 +0100 @@ -0,0 +1,79 @@ +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <glib/gstdio.h> +#include <webp/decode.h> +#include <webp/mux.h> + +static gchar * +create_filename () +{ + GString *pathbuild = g_string_new (g_get_tmp_dir ()); + gchar *id = g_uuid_string_random (); + g_string_append_printf (pathbuild, "%s%s.webp", G_DIR_SEPARATOR_S, id); + g_free (id); + return g_string_free (pathbuild, FALSE); +} + +void +test_webp_icc_output (guchar *buffer, gsize buf_size, const gchar *base64_string) +{ + WebPData data = { .bytes = buffer, .size = buf_size }; + WebPData output = { 0 }; + WebPMux *mux = WebPMuxCreate (&data, FALSE); + WebPMuxGetChunk (mux, "ICCP", &output); + WebPMuxDelete (mux); + + g_assert (output.bytes != NULL); + gchar *encoded_icc = g_base64_encode (output.bytes, output.size); + g_assert (encoded_icc != NULL); + g_assert_cmpstr (encoded_icc, ==, base64_string); + + g_free (encoded_icc); +} + +gint +main (gint argc, gchar **argv) +{ + GError *error = NULL; + gchar **env = g_get_environ (); + + GdkPixbuf *pixbuf + = gdk_pixbuf_new_from_file (g_environ_getenv (env, "TEST_FILE"), &error); + if (error) + g_error ("%s", error->message); + + g_assert (! gdk_pixbuf_get_has_alpha (pixbuf)); + + g_assert (gdk_pixbuf_get_width (pixbuf) == 200); + g_assert (gdk_pixbuf_get_height (pixbuf) == 200); + + g_strfreev (env); + + /* Test on disk contents */ + gchar *path = create_filename (); + gdk_pixbuf_save (pixbuf, path, "webp", &error, "icc-profile", "MQo=", NULL); + if (error) + g_error ("%s", error->message); + + gchar *buffer; + gsize buf_size; + g_file_get_contents (path, &buffer, &buf_size, &error); + if (error) + g_error ("%s", error->message); + + test_webp_icc_output ((guchar *) buffer, buf_size, "MQo="); + g_remove (path); + g_clear_pointer (&buffer, g_free); + g_clear_pointer (&path, g_free); + + /* Test on memory contents */ + gdk_pixbuf_save_to_buffer (pixbuf, &buffer, &buf_size, "webp", &error, + "icc-profile", "MQo=", NULL); + if (error) + g_error ("%s", error->message); + + test_webp_icc_output ((guchar *) buffer, buf_size, "MQo="); + + g_free (buffer); + g_object_unref (pixbuf); + return 0; +} diff -Nru webp-pixbuf-loader-0.2.0/tests/t_null_error.c webp-pixbuf-loader-0.2.1/tests/t_null_error.c --- webp-pixbuf-loader-0.2.0/tests/t_null_error.c 1970-01-01 01:00:00.000000000 +0100 +++ webp-pixbuf-loader-0.2.1/tests/t_null_error.c 2023-03-04 00:36:54.000000000 +0100 @@ -0,0 +1,50 @@ +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <glib/gstdio.h> + +static gchar * +create_filename () +{ + GString *pathbuild = g_string_new (g_get_tmp_dir ()); + gchar *id = g_uuid_string_random (); + g_string_append_printf (pathbuild, "%s%s.webp", G_DIR_SEPARATOR_S, id); + g_free (id); + return g_string_free (pathbuild, FALSE); +} + +gboolean +save_func (const gchar *buffer, gsize count, GError **error, gpointer data) +{ + return TRUE; +} + +void +test_pixbufv (GdkPixbuf *pixbuf, gchar **keys, gchar **values) +{ + GStatBuf tmpstat = { 0 }; + gchar *path = create_filename (); + g_assert (gdk_pixbuf_savev (pixbuf, path, "webp", keys, values, NULL)); + g_stat (path, &tmpstat); + g_remove (path); + g_free (path); + + g_assert (gdk_pixbuf_save_to_callbackv (pixbuf, save_func, NULL, "webp", keys, values, NULL)); +} + +int +main () +{ + gchar **env = g_get_environ (); + + GdkPixbuf *pixbuf + = gdk_pixbuf_new_from_file (g_environ_getenv (env, "TEST_FILE"), NULL); + g_assert (pixbuf != NULL); + g_clear_pointer (&env, g_strfreev); + + gchar *keys[2] = { "icc-profile", NULL }; + gchar *values[2] = { "MQo=", NULL }; + + test_pixbufv (pixbuf, NULL, NULL); + test_pixbufv (pixbuf, keys, values); + + g_object_unref (pixbuf); +} \ No newline at end of file ``` unblock webp-pixbuf-loader/0.2.1-1