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>
This commit is contained in:
Ivan Molodetskikh 2022-01-15 18:20:51 +03:00 committed by Marge Bot
parent 7245f95165
commit 71c6918588
2 changed files with 129 additions and 0 deletions

View File

@ -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)
{

View File

@ -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__ */