[gtk+/rendering-cleanup: 14/75] API: Add gdk_pixbuf_get_from_surface()
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/rendering-cleanup: 14/75] API: Add gdk_pixbuf_get_from_surface()
- Date: Wed, 4 Aug 2010 22:02:05 +0000 (UTC)
commit 8d9211951f25c7c36687c02d28a7db2a4b551aa0
Author: Benjamin Otte <otte redhat com>
Date: Tue Jul 13 19:44:41 2010 +0200
API: Add gdk_pixbuf_get_from_surface()
New API to copy any cairo surface into a pixbuf.
docs/reference/gdk/gdk3-sections.txt | 1 +
gdk/gdk.symbols | 1 +
gdk/gdkpixbuf-drawable.c | 226 ++++++++++++++++++++++++++++++++++
gdk/gdkpixbuf.h | 9 ++
4 files changed, 237 insertions(+), 0 deletions(-)
---
diff --git a/docs/reference/gdk/gdk3-sections.txt b/docs/reference/gdk/gdk3-sections.txt
index eddea9a..b16e477 100644
--- a/docs/reference/gdk/gdk3-sections.txt
+++ b/docs/reference/gdk/gdk3-sections.txt
@@ -319,6 +319,7 @@ gdk_pixbuf_render_pixmap_and_mask
gdk_pixbuf_render_pixmap_and_mask_for_colormap
gdk_pixbuf_get_from_drawable
gdk_pixbuf_get_from_image
+gdk_pixbuf_get_from_surface
</SECTION>
<SECTION>
diff --git a/gdk/gdk.symbols b/gdk/gdk.symbols
index ddf1efd..b177259 100644
--- a/gdk/gdk.symbols
+++ b/gdk/gdk.symbols
@@ -940,6 +940,7 @@ gdk_pango_renderer_set_stipple
#if IN_FILE(__GDK_PIXBUF_DRAWABLE_C__)
gdk_pixbuf_get_from_drawable
gdk_pixbuf_get_from_image
+gdk_pixbuf_get_from_surface
#endif
#endif
diff --git a/gdk/gdkpixbuf-drawable.c b/gdk/gdkpixbuf-drawable.c
index 470d450..1d5c817 100644
--- a/gdk/gdkpixbuf-drawable.c
+++ b/gdk/gdkpixbuf-drawable.c
@@ -1413,3 +1413,229 @@ gdk_pixbuf_get_from_image (GdkPixbuf *dest,
return dest;
}
+
+static cairo_format_t
+gdk_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 *
+gdk_cairo_surface_coerce_to_image (cairo_surface_t *surface,
+ cairo_content_t content,
+ int width,
+ int height)
+{
+ cairo_surface_t *copy;
+ cairo_t *cr;
+
+ if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE &&
+ cairo_surface_get_content (surface) == content &&
+ cairo_image_surface_get_width (surface) >= width &&
+ cairo_image_surface_get_height (surface) >= height)
+ return cairo_surface_reference (surface);
+
+ copy = cairo_image_surface_create (gdk_cairo_format_for_content (content),
+ width,
+ height);
+
+ cr = cairo_create (copy);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_set_source_surface (cr, surface, 0, 0);
+ 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 dest_x,
+ int dest_y,
+ int width,
+ int height)
+{
+ int x, y;
+
+ dest_data += dest_stride * dest_y + dest_x * 4;
+ src_data += src_stride * src_y + src_x * 4;
+
+ for (y = 0; y < height; y++) {
+ guint32 *src = (guint32 *) src_data;
+
+ for (x = 0; x < width; x++) {
+ guint 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 dest_x,
+ int dest_y,
+ int width,
+ int height)
+{
+ int x, y;
+
+ dest_data += dest_stride * dest_y + dest_x * 3;
+ src_data += src_stride * src_y + src_x * 4;
+
+ for (y = 0; y < height; y++) {
+ guint32 *src = (guint32 *) 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;
+ }
+}
+
+/**
+ * gdk_pixbuf_get_from_surface:
+ * @dest: (allow-none): Destination pixbuf, or %NULL if a new pixbuf should be created.
+ * @surface: surface to copy from
+ * @src_x: Source X coordinate within drawable.
+ * @src_y: Source Y coordinate within drawable.
+ * @dest_x: Destination X coordinate in pixbuf, or 0 if @dest is NULL.
+ * @dest_y: Destination Y coordinate in pixbuf, or 0 if @dest is NULL.
+ * @width: Width in pixels of region to get.
+ * @height: Height in pixels of region to get.
+ *
+ * Transfers image data from a #cairo_surface_t and converts it to an RGB(A)
+ * representation inside a #GdkPixbuf. This allows you to efficiently read individual
+ * pixels from Cairo surfaces. For #GdkWindows, use gdk_pixbuf_get_from_drawable()
+ * instead.
+ *
+ * If the specified destination pixbuf @dest is %NULL, then this
+ * function will create an RGB pixbuf with 8 bits per channel. The pixbuf will
+ * contain an alpha channel if the @surface contains one. In this case, the @dest_x
+ * and @dest_y arguments must be specified as 0.
+ *
+ * If the specified drawable is a window, and the window is off the
+ * screen, then there is no image data in the obscured/offscreen
+ * regions to be placed in the pixbuf. The contents of portions of the
+ * pixbuf corresponding to the offscreen region are undefined.
+ *
+ * If the window you're obtaining data from is partially obscured by
+ * other windows, then the contents of the pixbuf areas corresponding
+ * to the obscured regions are undefined.
+ *
+ * If memory can't be allocated for the return value, %NULL will be returned
+ * instead.
+ *
+ * (In short, there are several ways this function can fail, and if it fails
+ * it returns %NULL; so check the return value.)
+ *
+ * Return value: The same pixbuf as @dest if it was non-%NULL, or a newly-created
+ * pixbuf with a reference count of 1 if no destination pixbuf was specified, or %NULL on error
+ **/
+GdkPixbuf *
+gdk_pixbuf_get_from_surface (GdkPixbuf *dest,
+ cairo_surface_t *surface,
+ int src_x,
+ int src_y,
+ int dest_x,
+ int dest_y,
+ int width,
+ int height)
+{
+ cairo_content_t content;
+
+ /* General sanity checks */
+ g_return_val_if_fail (surface != NULL, NULL);
+ g_return_val_if_fail (src_x >= 0 && src_y >= 0, NULL);
+ g_return_val_if_fail (width > 0 && height > 0, NULL);
+
+ if (!dest)
+ {
+ g_return_val_if_fail (dest_x == 0 && dest_y == 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);
+ }
+ else
+ {
+ g_return_val_if_fail (gdk_pixbuf_get_colorspace (dest) == GDK_COLORSPACE_RGB, NULL);
+ g_return_val_if_fail (gdk_pixbuf_get_n_channels (dest) == 3 ||
+ gdk_pixbuf_get_n_channels (dest) == 4, NULL);
+ g_return_val_if_fail (gdk_pixbuf_get_bits_per_sample (dest) == 8, NULL);
+ g_return_val_if_fail (dest_x >= 0 && dest_y >= 0, NULL);
+ g_return_val_if_fail (dest_x + width <= gdk_pixbuf_get_width (dest), NULL);
+ g_return_val_if_fail (dest_y + height <= gdk_pixbuf_get_height (dest), NULL);
+
+ content = gdk_pixbuf_get_has_alpha (dest) ? CAIRO_CONTENT_COLOR_ALPHA : CAIRO_CONTENT_COLOR;
+ }
+
+ surface = gdk_cairo_surface_coerce_to_image (surface, content, src_x + width, src_y + height);
+ cairo_surface_flush (surface);
+ if (cairo_surface_status (surface) || dest == NULL)
+ {
+ cairo_surface_destroy (surface);
+ 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,
+ dest_x, dest_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,
+ dest_x, dest_y,
+ width, height);
+
+ cairo_surface_destroy (surface);
+ return dest;
+}
+
diff --git a/gdk/gdkpixbuf.h b/gdk/gdkpixbuf.h
index 830d6eb..b599c0b 100644
--- a/gdk/gdkpixbuf.h
+++ b/gdk/gdkpixbuf.h
@@ -72,6 +72,15 @@ GdkPixbuf *gdk_pixbuf_get_from_drawable (GdkPixbuf *dest,
int width,
int height);
+GdkPixbuf *gdk_pixbuf_get_from_surface (GdkPixbuf *dest,
+ cairo_surface_t *surface,
+ int src_x,
+ int src_y,
+ int dest_x,
+ int dest_y,
+ int width,
+ int height);
+
GdkPixbuf *gdk_pixbuf_get_from_image (GdkPixbuf *dest,
GdkImage *src,
GdkColormap *cmap,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]