shell: Avoid use of gdk_pixbuf_get_from_surface()
Unlike one might think, this function does not come from GdkPixbuf but GDK. Also adopt this conversion code between surface formats. Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2655>
This commit is contained in:
parent
d3545a3b53
commit
1a06d93e95
@ -104,6 +104,182 @@ on_screenshot_written (GObject *source,
|
|||||||
g_clear_pointer (&priv->datetime, g_date_time_unref);
|
g_clear_pointer (&priv->datetime, g_date_time_unref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static cairo_format_t
|
||||||
|
util_cairo_format_for_content (cairo_content_t content)
|
||||||
|
{
|
||||||
|
switch (content)
|
||||||
|
{
|
||||||
|
case CAIRO_CONTENT_COLOR:
|
||||||
|
return CAIRO_FORMAT_RGB24;
|
||||||
|
case CAIRO_CONTENT_ALPHA:
|
||||||
|
return CAIRO_FORMAT_A8;
|
||||||
|
case CAIRO_CONTENT_COLOR_ALPHA:
|
||||||
|
default:
|
||||||
|
return CAIRO_FORMAT_ARGB32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static cairo_surface_t *
|
||||||
|
util_cairo_surface_coerce_to_image (cairo_surface_t *surface,
|
||||||
|
cairo_content_t content,
|
||||||
|
int src_x,
|
||||||
|
int src_y,
|
||||||
|
int width,
|
||||||
|
int height)
|
||||||
|
{
|
||||||
|
cairo_surface_t *copy;
|
||||||
|
cairo_t *cr;
|
||||||
|
|
||||||
|
copy = cairo_image_surface_create (util_cairo_format_for_content (content),
|
||||||
|
width,
|
||||||
|
height);
|
||||||
|
|
||||||
|
cr = cairo_create (copy);
|
||||||
|
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
|
||||||
|
cairo_set_source_surface (cr, surface, -src_x, -src_y);
|
||||||
|
cairo_paint (cr);
|
||||||
|
cairo_destroy (cr);
|
||||||
|
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
convert_alpha (guchar *dest_data,
|
||||||
|
int dest_stride,
|
||||||
|
guchar *src_data,
|
||||||
|
int src_stride,
|
||||||
|
int src_x,
|
||||||
|
int src_y,
|
||||||
|
int width,
|
||||||
|
int height)
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
|
||||||
|
src_data += src_stride * src_y + src_x * 4;
|
||||||
|
|
||||||
|
for (y = 0; y < height; y++)
|
||||||
|
{
|
||||||
|
uint32_t *src = (guint32 *) src_data;
|
||||||
|
|
||||||
|
for (x = 0; x < width; x++)
|
||||||
|
{
|
||||||
|
unsigned int alpha = src[x] >> 24;
|
||||||
|
|
||||||
|
if (alpha == 0)
|
||||||
|
{
|
||||||
|
dest_data[x * 4 + 0] = 0;
|
||||||
|
dest_data[x * 4 + 1] = 0;
|
||||||
|
dest_data[x * 4 + 2] = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dest_data[x * 4 + 0] = (((src[x] & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
|
||||||
|
dest_data[x * 4 + 1] = (((src[x] & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
|
||||||
|
dest_data[x * 4 + 2] = (((src[x] & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
|
||||||
|
}
|
||||||
|
dest_data[x * 4 + 3] = alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
src_data += src_stride;
|
||||||
|
dest_data += dest_stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
convert_no_alpha (guchar *dest_data,
|
||||||
|
int dest_stride,
|
||||||
|
guchar *src_data,
|
||||||
|
int src_stride,
|
||||||
|
int src_x,
|
||||||
|
int src_y,
|
||||||
|
int width,
|
||||||
|
int height)
|
||||||
|
{
|
||||||
|
int x, y;
|
||||||
|
|
||||||
|
src_data += src_stride * src_y + src_x * 4;
|
||||||
|
|
||||||
|
for (y = 0; y < height; y++)
|
||||||
|
{
|
||||||
|
uint32_t *src = (uint32_t *) src_data;
|
||||||
|
|
||||||
|
for (x = 0; x < width; x++)
|
||||||
|
{
|
||||||
|
dest_data[x * 3 + 0] = src[x] >> 16;
|
||||||
|
dest_data[x * 3 + 1] = src[x] >> 8;
|
||||||
|
dest_data[x * 3 + 2] = src[x];
|
||||||
|
}
|
||||||
|
|
||||||
|
src_data += src_stride;
|
||||||
|
dest_data += dest_stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static GdkPixbuf *
|
||||||
|
util_pixbuf_from_surface (cairo_surface_t *surface,
|
||||||
|
gint src_x,
|
||||||
|
gint src_y,
|
||||||
|
gint width,
|
||||||
|
gint height)
|
||||||
|
{
|
||||||
|
cairo_content_t content;
|
||||||
|
GdkPixbuf *dest;
|
||||||
|
|
||||||
|
/* General sanity checks */
|
||||||
|
g_return_val_if_fail (surface != NULL, NULL);
|
||||||
|
g_return_val_if_fail (width > 0 && height > 0, NULL);
|
||||||
|
|
||||||
|
content = cairo_surface_get_content (surface) | CAIRO_CONTENT_COLOR;
|
||||||
|
dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
|
||||||
|
!!(content & CAIRO_CONTENT_ALPHA),
|
||||||
|
8,
|
||||||
|
width, height);
|
||||||
|
|
||||||
|
if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE &&
|
||||||
|
cairo_image_surface_get_format (surface) == util_cairo_format_for_content (content))
|
||||||
|
{
|
||||||
|
surface = cairo_surface_reference (surface);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
surface = util_cairo_surface_coerce_to_image (surface, content,
|
||||||
|
src_x, src_y,
|
||||||
|
width, height);
|
||||||
|
src_x = 0;
|
||||||
|
src_y = 0;
|
||||||
|
}
|
||||||
|
cairo_surface_flush (surface);
|
||||||
|
if (cairo_surface_status (surface) || dest == NULL)
|
||||||
|
{
|
||||||
|
cairo_surface_destroy (surface);
|
||||||
|
g_clear_object (&dest);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gdk_pixbuf_get_has_alpha (dest))
|
||||||
|
{
|
||||||
|
convert_alpha (gdk_pixbuf_get_pixels (dest),
|
||||||
|
gdk_pixbuf_get_rowstride (dest),
|
||||||
|
cairo_image_surface_get_data (surface),
|
||||||
|
cairo_image_surface_get_stride (surface),
|
||||||
|
src_x, src_y,
|
||||||
|
width, height);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
convert_no_alpha (gdk_pixbuf_get_pixels (dest),
|
||||||
|
gdk_pixbuf_get_rowstride (dest),
|
||||||
|
cairo_image_surface_get_data (surface),
|
||||||
|
cairo_image_surface_get_stride (surface),
|
||||||
|
src_x, src_y,
|
||||||
|
width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
cairo_surface_destroy (surface);
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
write_screenshot_thread (GTask *result,
|
write_screenshot_thread (GTask *result,
|
||||||
gpointer object,
|
gpointer object,
|
||||||
@ -123,10 +299,10 @@ write_screenshot_thread (GTask *result,
|
|||||||
|
|
||||||
stream = g_object_ref (priv->stream);
|
stream = g_object_ref (priv->stream);
|
||||||
|
|
||||||
pixbuf = gdk_pixbuf_get_from_surface (priv->image,
|
pixbuf = util_pixbuf_from_surface (priv->image,
|
||||||
0, 0,
|
0, 0,
|
||||||
cairo_image_surface_get_width (priv->image),
|
cairo_image_surface_get_width (priv->image),
|
||||||
cairo_image_surface_get_height (priv->image));
|
cairo_image_surface_get_height (priv->image));
|
||||||
creation_time = g_date_time_format (priv->datetime, "%c");
|
creation_time = g_date_time_format (priv->datetime, "%c");
|
||||||
|
|
||||||
if (!creation_time)
|
if (!creation_time)
|
||||||
@ -1167,11 +1343,11 @@ shell_screenshot_composite_to_stream (CoglTexture *texture,
|
|||||||
cairo_surface_destroy (cursor_surface);
|
cairo_surface_destroy (cursor_surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save to an image.
|
/* Save to an image. */
|
||||||
pixbuf = gdk_pixbuf_get_from_surface (surface,
|
pixbuf = util_pixbuf_from_surface (surface,
|
||||||
0, 0,
|
0, 0,
|
||||||
cairo_image_surface_get_width (surface),
|
cairo_image_surface_get_width (surface),
|
||||||
cairo_image_surface_get_height (surface));
|
cairo_image_surface_get_height (surface));
|
||||||
cairo_surface_destroy (surface);
|
cairo_surface_destroy (surface);
|
||||||
|
|
||||||
date_time = g_date_time_new_now_local ();
|
date_time = g_date_time_new_now_local ();
|
||||||
|
Loading…
Reference in New Issue
Block a user