[gnome-shell] screenshot: Add API to get PNG stream from a texture



commit 71c6918588042e878b325af1735d9a792b490b69
Author: Ivan Molodetskikh <yalterz gmail com>
Date:   Sat Jan 15 18:20:51 2022 +0300

    screenshot: Add API to get PNG stream from a texture
    
    With the new screenshot UI we're introducing, we'll be capturing all
    screenshots to textures on the GPU at first, and then create a PNG
    stream from those textures at a later point. This will allow us to
    present screenshots immediately to the user so they can inspect them and
    select the right area before actually saving them to disk.
    
    As a first step to make this work, introduce a new ShellScreenshot API
    that writes an existing CoglTexture to a PNG output stream:
    shell_screenshot_composite_to_stream ()
    
    Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1954>

 src/shell-screenshot.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/shell-screenshot.h |  11 +++++
 2 files changed, 129 insertions(+)
---
diff --git a/src/shell-screenshot.c b/src/shell-screenshot.c
index 100429f217..34494185a6 100644
--- a/src/shell-screenshot.c
+++ b/src/shell-screenshot.c
@@ -804,6 +804,124 @@ shell_screenshot_pick_color_finish (ShellScreenshot  *screenshot,
 #undef INDEX_G
 #undef INDEX_B
 
+static void
+composite_to_stream_on_png_saved (GObject      *source,
+                                  GAsyncResult *result,
+                                  gpointer      user_data)
+{
+  GTask *task = G_TASK (user_data);
+  GError *error = NULL;
+
+  if (!gdk_pixbuf_save_to_stream_finish (result, &error))
+    g_task_return_error (task, error);
+  else
+    g_task_return_boolean (task, TRUE);
+
+  g_object_unref (task);
+}
+
+/**
+ * shell_screenshot_composite_to_stream:
+ * @texture: the source texture
+ * @x: x coordinate of the rectangle
+ * @y: y coordinate of the rectangle
+ * @width: width of the rectangle, or -1 to use the full texture
+ * @height: height of the rectangle, or -1 to use the full texture
+ * @stream: the stream to write the PNG image into
+ * @callback: (scope async): function to call returning success or failure
+ * @user_data: the data to pass to callback function
+ *
+ * Composite a rectangle defined by x, y, width, height from the texture to a
+ * pixbuf and write it as a PNG image into the stream.
+ *
+ */
+void
+shell_screenshot_composite_to_stream (CoglTexture         *texture,
+                                      int                  x,
+                                      int                  y,
+                                      int                  width,
+                                      int                  height,
+                                      GOutputStream       *stream,
+                                      GAsyncReadyCallback  callback,
+                                      gpointer             user_data)
+{
+  CoglContext *ctx;
+  CoglTexture *sub_texture;
+  cairo_surface_t *surface;
+  g_autoptr (GTask) task = NULL;
+  g_autoptr (GdkPixbuf) pixbuf = NULL;
+  g_autofree char *creation_time = NULL;
+  g_autoptr (GDateTime) date_time = NULL;
+
+  task = g_task_new (NULL, NULL, callback, user_data);
+  g_task_set_source_tag (task, shell_screenshot_composite_to_stream);
+
+  if (width == -1 || height == -1)
+    {
+      x = 0;
+      y = 0;
+      width = cogl_texture_get_width (texture);
+      height = cogl_texture_get_height (texture);
+    }
+
+  ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
+  sub_texture = cogl_sub_texture_new (ctx, texture, x, y, width, height);
+
+  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+                                        cogl_texture_get_width (sub_texture),
+                                        cogl_texture_get_height (sub_texture));
+
+  cogl_texture_get_data (sub_texture, CLUTTER_CAIRO_FORMAT_ARGB32,
+                         cairo_image_surface_get_stride (surface),
+                         cairo_image_surface_get_data (surface));
+  cairo_surface_mark_dirty (surface);
+
+  cogl_object_unref (sub_texture);
+
+  // Save to an image.
+  pixbuf = gdk_pixbuf_get_from_surface (surface,
+                                        0, 0,
+                                        cairo_image_surface_get_width (surface),
+                                        cairo_image_surface_get_height (surface));
+  cairo_surface_destroy (surface);
+
+  date_time = g_date_time_new_now_local ();
+  creation_time = g_date_time_format (date_time, "%c");
+
+  if (!creation_time)
+    creation_time = g_date_time_format (date_time, "%FT%T%z");
+
+  gdk_pixbuf_save_to_stream_async (pixbuf, stream, "png", NULL,
+                                   composite_to_stream_on_png_saved,
+                                   g_steal_pointer (&task),
+                                   "tEXt::Software", "gnome-screenshot",
+                                   "tEXt::Creation Time", creation_time,
+                                   NULL);
+}
+
+/**
+ * shell_screenshot_composite_to_stream_finish:
+ * @result: the #GAsyncResult that was provided to the callback
+ * @error: #GError for error reporting
+ *
+ * Finish the asynchronous operation started by
+ * shell_screenshot_composite_to_stream () and obtain its result.
+ *
+ * Returns: whether the operation was successful
+ *
+ */
+gboolean
+shell_screenshot_composite_to_stream_finish (GAsyncResult  *result,
+                                             GError       **error)
+{
+  g_return_val_if_fail (G_IS_TASK (result), FALSE);
+  g_return_val_if_fail (g_async_result_is_tagged (result,
+                                                  shell_screenshot_composite_to_stream),
+                        FALSE);
+
+  return g_task_propagate_boolean (G_TASK (result), error);
+}
+
 ShellScreenshot *
 shell_screenshot_new (void)
 {
diff --git a/src/shell-screenshot.h b/src/shell-screenshot.h
index 18c6667e1b..838e910a7e 100644
--- a/src/shell-screenshot.h
+++ b/src/shell-screenshot.h
@@ -60,4 +60,15 @@ gboolean shell_screenshot_pick_color_finish (ShellScreenshot      *screenshot,
                                              ClutterColor         *color,
                                              GError              **error);
 
+void shell_screenshot_composite_to_stream (CoglTexture         *texture,
+                                           int                  x,
+                                           int                  y,
+                                           int                  width,
+                                           int                  height,
+                                           GOutputStream       *stream,
+                                           GAsyncReadyCallback  callback,
+                                           gpointer             user_data);
+gboolean shell_screenshot_composite_to_stream_finish (GAsyncResult  *result,
+                                                      GError       **error);
+
 #endif /* ___SHELL_SCREENSHOT_H__ */


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