From 7725c8439c03bfeeab6faa9dc7abc1368499a534 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Thu, 9 Sep 2021 22:23:37 -0400 Subject: [PATCH] Use our png loader for content (de)serialization We still fall back to gdk-pixbuf for handling all the other image formats. But with this in place, we no longer need to tweak the pixbuf formats to ensure that png comes first. --- gdk/gdkcontentdeserializer.c | 56 ++++++++++++++++++---- gdk/gdkcontentserializer.c | 90 ++++++++++++++++++++++++++++++++---- 2 files changed, 126 insertions(+), 20 deletions(-) diff --git a/gdk/gdkcontentdeserializer.c b/gdk/gdkcontentdeserializer.c index 4959b5af4d..158ec23f6e 100644 --- a/gdk/gdkcontentdeserializer.c +++ b/gdk/gdkcontentdeserializer.c @@ -25,6 +25,7 @@ #include "filetransferportalprivate.h" #include "gdktexture.h" #include "gdkrgbaprivate.h" +#include "gdkpng.h" #include @@ -655,6 +656,36 @@ pixbuf_deserializer (GdkContentDeserializer *deserializer) deserializer); } +static void +png_deserializer_finish (GObject *source, + GAsyncResult *res, + gpointer deserializer) +{ + GdkTexture *texture; + GValue *value; + GError *error = NULL; + + texture = gdk_load_png_finish (res, &error); + if (texture == NULL) + { + gdk_content_deserializer_return_error (deserializer, error); + return; + } + + value = gdk_content_deserializer_get_value (deserializer); + g_value_take_object (value, texture); + gdk_content_deserializer_return_success (deserializer); +} + +static void +png_deserializer (GdkContentDeserializer *deserializer) +{ + gdk_load_png_async (gdk_content_deserializer_get_input_stream (deserializer), + gdk_content_deserializer_get_cancellable (deserializer), + png_deserializer_finish, + deserializer); +} + static void string_deserializer_finish (GObject *source, GAsyncResult *result, @@ -863,27 +894,32 @@ init (void) initialized = TRUE; + gdk_content_register_deserializer ("image/png", + GDK_TYPE_TEXTURE, + png_deserializer, + NULL, + NULL); + formats = gdk_pixbuf_get_formats (); /* Make sure png comes first */ for (f = formats; f; f = f->next) { GdkPixbufFormat *fmt = f->data; - char *name; - + char *name; + name = gdk_pixbuf_format_get_name (fmt); if (g_str_equal (name, "png")) - { - formats = g_slist_delete_link (formats, f); - formats = g_slist_prepend (formats, fmt); + { + formats = g_slist_delete_link (formats, f); + formats = g_slist_prepend (formats, fmt); - g_free (name); - - break; - } + g_free (name); + break; + } g_free (name); - } + } for (f = formats; f; f = f->next) { diff --git a/gdk/gdkcontentserializer.c b/gdk/gdkcontentserializer.c index bc9deeb8d5..f2a0e8930c 100644 --- a/gdk/gdkcontentserializer.c +++ b/gdk/gdkcontentserializer.c @@ -26,6 +26,8 @@ #include "filetransferportalprivate.h" #include "gdktextureprivate.h" #include "gdkrgba.h" +#include "gdkpng.h" +#include "gdkmemorytextureprivate.h" #include #include @@ -606,6 +608,7 @@ gdk_content_serialize_finish (GAsyncResult *result, /*** SERIALIZERS ***/ + static void pixbuf_serializer_finish (GObject *source, GAsyncResult *res, @@ -658,6 +661,69 @@ pixbuf_serializer (GdkContentSerializer *serializer) g_object_unref (pixbuf); } +typedef struct { + GdkContentSerializer *serializer; + GBytes *bytes; +} PngSerializerData; + +static void +png_serializer_finish (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + PngSerializerData *data = user_data; + GError *error = NULL; + + if (!gdk_save_png_finish (res, &error)) + gdk_content_serializer_return_error (data->serializer, error); + else + gdk_content_serializer_return_success (data->serializer); + + g_bytes_unref (data->bytes); + g_free (data); +} + +static void +png_serializer (GdkContentSerializer *serializer) +{ + const GValue *value; + GdkTexture *texture; + GdkMemoryFormat format; + GBytes *bytes = NULL; + PngSerializerData *data; + + value = gdk_content_serializer_get_value (serializer); + + texture = g_value_get_object (value); + + for (int i = 0; i < GDK_MEMORY_N_FORMATS; i++) + { + bytes = gdk_texture_download_format (texture, i); + if (bytes) + { + format = i; + break; + } + } + + g_assert (bytes != NULL); + + data = g_new0 (PngSerializerData, 1); + data->serializer = serializer; + data->bytes = bytes; + + gdk_save_png_async (gdk_content_serializer_get_output_stream (serializer), + g_bytes_get_data (bytes, NULL), + gdk_texture_get_width (texture), + gdk_texture_get_height (texture), + gdk_texture_get_width (texture) * gdk_memory_format_bytes_per_pixel (format), + format, + gdk_content_serializer_get_cancellable (serializer), + png_serializer_finish, + data); + g_object_unref (texture); +} + static void string_serializer_finish (GObject *source, GAsyncResult *result, @@ -877,27 +943,31 @@ init (void) initialized = TRUE; + gdk_content_register_serializer (GDK_TYPE_TEXTURE, + "image/png", + png_serializer, + NULL, NULL); + formats = gdk_pixbuf_get_formats (); /* Make sure png comes first */ for (f = formats; f; f = f->next) { GdkPixbufFormat *fmt = f->data; - char *name; - + char *name; + name = gdk_pixbuf_format_get_name (fmt); if (g_str_equal (name, "png")) - { - formats = g_slist_delete_link (formats, f); - formats = g_slist_prepend (formats, fmt); + { + formats = g_slist_delete_link (formats, f); + formats = g_slist_prepend (formats, fmt); - g_free (name); - - break; - } + g_free (name); + break; + } g_free (name); - } + } for (f = formats; f; f = f->next) {