[gtk/image-loading: 10/15] Use our own loaders for content (de)serialization




commit b66fa84161aa05c6b0d5ed1051eae3a61ddfea16
Author: Matthias Clasen <mclasen redhat com>
Date:   Thu Sep 9 22:23:37 2021 -0400

    Use our own loaders for content (de)serialization
    
    Use our own loader to (de)serialiaze textures
    to and from png and tiff.
    
    We still fall back to gdk-pixbuf for handling all
    the other image formats, and for pixbufs.

 gdk/gdkcontentdeserializer.c | 135 +++++++++++++++++++++++++++++++++++++------
 gdk/gdkcontentserializer.c   | 131 +++++++++++++++++++++++++++++++++++------
 2 files changed, 231 insertions(+), 35 deletions(-)
---
diff --git a/gdk/gdkcontentdeserializer.c b/gdk/gdkcontentdeserializer.c
index 4959b5af4d..6731b47e24 100644
--- a/gdk/gdkcontentdeserializer.c
+++ b/gdk/gdkcontentdeserializer.c
@@ -25,6 +25,8 @@
 #include "filetransferportalprivate.h"
 #include "gdktexture.h"
 #include "gdkrgbaprivate.h"
+#include "loaders/gdkpngprivate.h"
+#include "loaders/gdktiffprivate.h"
 
 #include <gdk-pixbuf/gdk-pixbuf.h>
 
@@ -655,6 +657,88 @@ pixbuf_deserializer (GdkContentDeserializer *deserializer)
                                     deserializer);
 }
 
+static void
+texture_deserializer_finish (GObject      *source,
+                             GAsyncResult *res,
+                             gpointer      data)
+{
+  GdkContentDeserializer *deserializer = GDK_CONTENT_DESERIALIZER (source);
+  GdkTexture *texture;
+  GValue *value;
+  GError *error = NULL;
+
+  texture = g_task_propagate_pointer (G_TASK (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 GBytes *
+read_all_data (GInputStream  *source,
+               GError       **error)
+{
+  GOutputStream *output;
+  gssize size;
+  GBytes *bytes;
+
+  output = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
+  size = g_output_stream_splice (output, source, 0, NULL, error);
+  if (size == -1)
+    {
+      g_object_unref (output);
+      return NULL;
+    }
+
+  g_output_stream_close (output, NULL, NULL);
+  bytes = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (output));
+  g_object_unref (output);
+
+  return bytes;
+}
+
+static void
+deserialize_texture_in_thread (GTask        *task,
+                               gpointer      source_object,
+                               gpointer      task_data,
+                               GCancellable *cancellable)
+{
+  GdkContentDeserializer *deserializer = source_object;
+  GBytes *bytes;
+  GError *error = NULL;
+  GdkTexture *texture = NULL;
+
+  bytes = read_all_data (gdk_content_deserializer_get_input_stream (deserializer), &error);
+  if (bytes)
+    {
+      texture = gdk_texture_new_from_bytes (bytes, &error);
+      g_bytes_unref (bytes);
+    }
+
+  if (texture)
+    g_task_return_pointer (task, texture, g_object_unref);
+  else
+    g_task_return_error (task, error);
+}
+
+static void
+texture_deserializer (GdkContentDeserializer *deserializer)
+{
+  GTask *task;
+
+  task = g_task_new (deserializer,
+                     gdk_content_deserializer_get_cancellable (deserializer),
+                     texture_deserializer_finish,
+                     NULL);
+  g_task_run_in_thread (task, deserialize_texture_in_thread);
+  g_object_unref (task);
+}
+
 static void
 string_deserializer_finish (GObject      *source,
                             GAsyncResult *result,
@@ -863,48 +947,65 @@ init (void)
 
   initialized = TRUE;
 
+  gdk_content_register_deserializer ("image/png",
+                                     GDK_TYPE_TEXTURE,
+                                     texture_deserializer,
+                                     NULL,
+                                     NULL);
+
+  gdk_content_register_deserializer ("image/tiff",
+                                     GDK_TYPE_TEXTURE,
+                                     texture_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);
-
-         g_free (name);
+        {
+          formats = g_slist_delete_link (formats, f);
+          formats = g_slist_prepend (formats, fmt);
 
-         break;
-       }
+          g_free (name);
+          break;
+        }
 
       g_free (name);
-    }  
+    }
 
   for (f = formats; f; f = f->next)
     {
       GdkPixbufFormat *fmt = f->data;
       char **mimes, **m;
+      char *name;
 
+      name = gdk_pixbuf_format_get_name (fmt);
       mimes = gdk_pixbuf_format_get_mime_types (fmt);
       for (m = mimes; *m; m++)
-       {
-          gdk_content_register_deserializer (*m,
-                                             GDK_TYPE_TEXTURE,
-                                             pixbuf_deserializer,
-                                             NULL,
-                                             NULL);
+        {
+          /* Turning pngs and tiffs into textures is handled above */
+          if (!g_str_equal (name, "png") &&
+              !g_str_equal (name, "tiff"))
+            gdk_content_register_deserializer (*m,
+                                               GDK_TYPE_TEXTURE,
+                                               pixbuf_deserializer,
+                                               NULL,
+                                               NULL);
           gdk_content_register_deserializer (*m,
                                              GDK_TYPE_PIXBUF,
                                              pixbuf_deserializer,
                                              NULL,
                                              NULL);
-       }
+        }
       g_strfreev (mimes);
+      g_free (name);
     }
 
   g_slist_free (formats);
diff --git a/gdk/gdkcontentserializer.c b/gdk/gdkcontentserializer.c
index bc9deeb8d5..316f6ad9c0 100644
--- a/gdk/gdkcontentserializer.c
+++ b/gdk/gdkcontentserializer.c
@@ -26,6 +26,9 @@
 #include "filetransferportalprivate.h"
 #include "gdktextureprivate.h"
 #include "gdkrgba.h"
+#include "loaders/gdkpngprivate.h"
+#include "loaders/gdktiffprivate.h"
+#include "gdkmemorytextureprivate.h"
 
 #include <gdk-pixbuf/gdk-pixbuf.h>
 #include <string.h>
@@ -606,6 +609,7 @@ gdk_content_serialize_finish (GAsyncResult  *result,
 
 /*** SERIALIZERS ***/
 
+
 static void
 pixbuf_serializer_finish (GObject      *source,
                           GAsyncResult *res,
@@ -658,6 +662,82 @@ pixbuf_serializer (GdkContentSerializer *serializer)
   g_object_unref (pixbuf);
 }
 
+static void
+texture_serializer_finish (GObject      *source,
+                           GAsyncResult *res,
+                           gpointer      user_data)
+{
+  GdkContentSerializer *serializer = GDK_CONTENT_SERIALIZER (source);
+  GError *error = NULL;
+
+  if (!g_task_propagate_boolean (G_TASK (res), &error))
+    gdk_content_serializer_return_error (serializer, error);
+  else
+    gdk_content_serializer_return_success (serializer);
+}
+
+static void
+serialize_texture_in_thread (GTask        *task,
+                             gpointer      source_object,
+                             gpointer      task_data,
+                             GCancellable *cancellable)
+{
+  GdkContentSerializer *serializer = source_object;
+  const GValue *value;
+  GdkTexture *texture;
+  GBytes *bytes = NULL;
+  GError *error = NULL;
+  gboolean result = FALSE;
+
+  value = gdk_content_serializer_get_value (serializer);
+  texture = g_value_get_object (value);
+
+  if (strcmp (gdk_content_serializer_get_mime_type (serializer), "image/png") == 0)
+    bytes = gdk_save_png (texture);
+  else if (strcmp (gdk_content_serializer_get_mime_type (serializer), "image/tiff") == 0)
+    bytes = gdk_save_tiff (texture);
+  else
+    g_assert_not_reached ();
+
+  if (bytes)
+    {
+      GInputStream *input = g_memory_input_stream_new_from_bytes (bytes);
+      gssize spliced;
+
+      spliced = g_output_stream_splice (gdk_content_serializer_get_output_stream (serializer),
+                                        input,
+                                        G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
+                                        gdk_content_serializer_get_cancellable (serializer),
+                                        &error);
+      g_object_unref (input);
+      g_bytes_unref (bytes);
+
+      result = spliced != -1;
+    }
+  else
+    g_set_error_literal (&error,
+                         G_IO_ERROR, G_IO_ERROR_FAILED,
+                         "Saving png failed");
+
+  if (result)
+    g_task_return_boolean (task, result);
+  else
+    g_task_return_error (task, error);
+}
+
+static void
+texture_serializer (GdkContentSerializer *serializer)
+{
+  GTask *task;
+
+  task = g_task_new (serializer,
+                     gdk_content_serializer_get_cancellable (serializer),
+                     texture_serializer_finish,
+                     NULL);
+  g_task_run_in_thread (task, serialize_texture_in_thread);
+  g_object_unref (task);
+}
+
 static void
 string_serializer_finish (GObject      *source,
                           GAsyncResult *result,
@@ -877,51 +957,66 @@ init (void)
 
   initialized = TRUE;
 
+  gdk_content_register_serializer (GDK_TYPE_TEXTURE,
+                                   "image/png",
+                                   texture_serializer,
+                                   NULL, NULL);
+
+  gdk_content_register_serializer (GDK_TYPE_TEXTURE,
+                                   "image/tiff",
+                                   texture_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);
-
-         g_free (name);
+        {
+          formats = g_slist_delete_link (formats, f);
+          formats = g_slist_prepend (formats, fmt);
 
-         break;
-       }
+          g_free (name);
+          break;
+        }
 
       g_free (name);
-    }  
+    }
 
   for (f = formats; f; f = f->next)
     {
       GdkPixbufFormat *fmt = f->data;
       char **mimes, **m;
+      char *name;
 
       if (!gdk_pixbuf_format_is_writable (fmt))
-       continue;
+        continue;
 
+      name = gdk_pixbuf_format_get_name (fmt);
       mimes = gdk_pixbuf_format_get_mime_types (fmt);
       for (m = mimes; *m; m++)
-       {
-          gdk_content_register_serializer (GDK_TYPE_TEXTURE,
-                                           *m,
-                                           pixbuf_serializer,
-                                           gdk_pixbuf_format_get_name (fmt),
-                                           g_free);
+        {
+          /* Turning textures into pngs or tiffs is handled above */
+          if (!g_str_equal (name, "png") &&
+              !g_str_equal (name, "tiff"))
+            gdk_content_register_serializer (GDK_TYPE_TEXTURE,
+                                             *m,
+                                             pixbuf_serializer,
+                                             gdk_pixbuf_format_get_name (fmt),
+                                             g_free);
           gdk_content_register_serializer (GDK_TYPE_PIXBUF,
                                            *m,
                                            pixbuf_serializer,
                                            gdk_pixbuf_format_get_name (fmt),
                                            g_free);
-       }
+        }
       g_strfreev (mimes);
+      g_free (name);
     }
 
   g_slist_free (formats);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]