[librsvg] Add rsvg_cairo_surface_to_pixbuf and use it



commit 1bc03686b1baaf469f131014ca6f8fb4f4bf6cfa
Author: Christian Persch <chpe gnome org>
Date:   Sun Nov 27 22:29:37 2011 +0100

    Add rsvg_cairo_surface_to_pixbuf and use it

 rsvg-cairo-draw.c |  113 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 rsvg-private.h    |    1 +
 rsvg.c            |   36 ++++++-----------
 3 files changed, 127 insertions(+), 23 deletions(-)
---
diff --git a/rsvg-cairo-draw.c b/rsvg-cairo-draw.c
index 5bee4ca..e641469 100644
--- a/rsvg-cairo-draw.c
+++ b/rsvg-cairo-draw.c
@@ -1036,3 +1036,116 @@ rsvg_cairo_surface_from_pixbuf (const GdkPixbuf *pixbuf)
     cairo_surface_mark_dirty (surface);
     return surface;
 }
+
+/* Copied from gtk+/gdk/gdkpixbuf-drawable.c, LGPL 2+.
+ *
+ * Copyright (C) 1999 Michael Zucchi
+ *
+ * Authors: Michael Zucchi <zucchi zedzone mmc com au>
+ *          Cody Russell <bratsche dfw net>
+ *          Federico Mena-Quintero <federico gimp org>
+ */
+
+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++) {
+        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     width,
+                  int     height)
+{
+    int x, y;
+
+    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;
+    }
+}
+
+GdkPixbuf *
+rsvg_cairo_surface_to_pixbuf (cairo_surface_t *surface)
+{
+    cairo_content_t content;
+    GdkPixbuf *dest;
+    int width, height;
+
+    /* General sanity checks */
+    g_assert (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE);
+
+    width = cairo_image_surface_get_width (surface);
+    height = cairo_image_surface_get_height (surface);
+    if (width == 0 || height == 0)
+        return 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 (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),
+                    0, 0,
+                    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),
+                        0, 0,
+                        width, height);
+
+    return dest;
+}
diff --git a/rsvg-private.h b/rsvg-private.h
index 5251b0d..bb99b2b 100644
--- a/rsvg-private.h
+++ b/rsvg-private.h
@@ -377,6 +377,7 @@ void rsvg_render_surface        (RsvgDrawingCtx * ctx, cairo_surface_t *surface,
 void rsvg_render_free           (RsvgRender * render);
 void rsvg_add_clipping_rect     (RsvgDrawingCtx * ctx, double x, double y, double w, double h);
 cairo_surface_t *rsvg_cairo_surface_from_pixbuf (const GdkPixbuf *pixbuf);
+GdkPixbuf *rsvg_cairo_surface_to_pixbuf (cairo_surface_t *surface);
 cairo_surface_t *rsvg_get_surface_of_node (RsvgDrawingCtx * ctx, RsvgNode * drawable, double w, double h);
 
 void rsvg_node_set_atts (RsvgNode * node, RsvgHandle * ctx, RsvgPropertyBag * atts);
diff --git a/rsvg.c b/rsvg.c
index 38fe111..80fa213 100644
--- a/rsvg.c
+++ b/rsvg.c
@@ -86,36 +86,26 @@ rsvg_handle_get_pixbuf_sub (RsvgHandle * handle, const char *id)
     if (!(dimensions.width && dimensions.height))
         return NULL;
 
-    rowstride = dimensions.width * 4;
-
-    pixels = g_try_malloc0 (dimensions.width * dimensions.height * 4UL);
-    if (!pixels)
+    surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+                                          dimensions.width, dimensions.height);
+    if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) {
+        cairo_surface_destroy (surface);
         return NULL;
+    }
 
-    surface = cairo_image_surface_create_for_data (pixels,
-                                                   CAIRO_FORMAT_ARGB32,
-                                                   dimensions.width, dimensions.height, rowstride);
     cr = cairo_create (surface);
-    cairo_surface_destroy (surface);
 
-    if (rsvg_handle_render_cairo_sub (handle, cr, id)) {
-        rsvg_cairo_to_pixbuf (pixels, rowstride, dimensions.height);
-
-        output = gdk_pixbuf_new_from_data (pixels,
-                                           GDK_COLORSPACE_RGB,
-                                           TRUE,
-                                           8,
-                                           dimensions.width,
-                                           dimensions.height,
-                                           rowstride,
-                                           (GdkPixbufDestroyNotify) rsvg_pixmap_destroy, NULL);
-	} else {
-        g_free (pixels);
-        output = NULL;
-	}
+    if (!rsvg_handle_render_cairo_sub (handle, cr, id)) {
+        cairo_destroy (cr);
+        cairo_surface_destroy (surface);
+        return NULL;
+    }
 
     cairo_destroy (cr);
 
+    output = rsvg_cairo_surface_to_pixbuf (surface);
+    cairo_surface_destroy (surface);
+
     return output;
 }
 



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