summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCaleb Michael Moore <cmoore@src.gnome.org>2005-10-18 17:32:55 +0000
committerCaleb Michael Moore <cmoore@src.gnome.org>2005-10-18 17:32:55 +0000
commitc1ea9819232fbda9b9722e51d5703a19bfe883e3 (patch)
treed8dd02b25ae2b3dd5085c814285563c697cd6d02
parenta72f363438521d56f83c74b65cfab0f6b5d027e6 (diff)
downloadlibrsvg-c1ea9819232fbda9b9722e51d5703a19bfe883e3.tar.gz
filters with cairo
-rw-r--r--ChangeLog5
-rw-r--r--rsvg-cairo-draw.c162
-rw-r--r--rsvg-cairo-draw.h3
-rw-r--r--rsvg-cairo-render.c2
-rw-r--r--rsvg-cairo-render.h1
-rw-r--r--rsvg.c26
6 files changed, 144 insertions, 55 deletions
diff --git a/ChangeLog b/ChangeLog
index 5676238d..02f26ec5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2005-10-19 Caleb Moore <c.moore@student.unsw.edu.au>
+
+ * rsvg-cairo-draw.c: series of hacks to make filters work
+
+
2005-10-16 Dom Lachowicz <cinamod@hotmail.com>
* rsvg-cairo-draw.c: No need to new0() image data, it just wastes CPU
diff --git a/rsvg-cairo-draw.c b/rsvg-cairo-draw.c
index 24de990c..f9ad404f 100644
--- a/rsvg-cairo-draw.c
+++ b/rsvg-cairo-draw.c
@@ -39,6 +39,13 @@
#include <math.h>
#include <string.h>
+
+static void
+rsvg_pixmap_destroy (gchar *pixels, gpointer data)
+{
+ g_free (pixels);
+}
+
static void
_pattern_add_rsvg_color_stops (cairo_pattern_t *pattern,
GPtrArray *stops,
@@ -390,8 +397,8 @@ rsvg_cairo_render_path (RsvgDrawingCtx *ctx, const RsvgBpathDef *bpath_def)
return;
need_tmpbuf = ((state->fill != NULL) && (state->stroke != NULL) &&
- state->opacity != 0xff) || state->clip_path_ref
- || state->mask;
+ state->opacity != 0xff)
+ || state->clip_path_ref || state->mask || state->filter;
if (need_tmpbuf)
rsvg_cairo_push_discrete_layer (ctx);
@@ -685,7 +692,6 @@ rsvg_cairo_generate_mask(RsvgMask * self, RsvgDrawingCtx *ctx,
state->opacity);
}
}
-
cairo_destroy (mask_cr);
return surface;
@@ -719,12 +725,36 @@ rsvg_cairo_push_render_stack (RsvgDrawingCtx *ctx)
objectBoundingBox)
lateclip = TRUE;
- if (state->opacity == 0xFF && !state->mask && !lateclip){
+ if (state->opacity == 0xFF && !state->filter && !state->mask && !lateclip){
return;
}
- surface = cairo_surface_create_similar (cairo_get_target (render->cr),
- CAIRO_CONTENT_COLOR_ALPHA,
- render->width, render->height);
+ if (!state->filter)
+ surface = cairo_surface_create_similar (cairo_get_target (render->cr),
+ CAIRO_CONTENT_COLOR_ALPHA,
+ render->width, render->height);
+ else
+ {
+ guchar * pixels;
+ int rowstride = render->width * 4;
+ pixels = g_new0(guint8, render->width * render->height * 4);
+
+ surface = cairo_image_surface_create_for_data (pixels,
+ CAIRO_FORMAT_ARGB32,
+ render->width,
+ render->height,
+ rowstride);
+ render->pixbuf_stack =
+ g_list_prepend(render->pixbuf_stack,
+ gdk_pixbuf_new_from_data (pixels,
+ GDK_COLORSPACE_RGB,
+ TRUE,
+ 8,
+ render->width,
+ render->height,
+ rowstride,
+ (GdkPixbufDestroyNotify)rsvg_pixmap_destroy,
+ NULL));
+ }
child_cr = cairo_create (surface);
cairo_surface_destroy (surface);
@@ -752,22 +782,60 @@ rsvg_cairo_pop_render_stack (RsvgDrawingCtx *ctx)
RsvgState *state;
state = rsvg_state_current(ctx);
gboolean lateclip = FALSE;
+ GdkPixbuf * output = NULL;
+ cairo_surface_t *surface = NULL;
if (rsvg_state_current(ctx)->clip_path_ref)
if (((RsvgClipPath *)rsvg_state_current(ctx)->clip_path_ref)->units ==
objectBoundingBox)
lateclip = TRUE;
- if (state->opacity == 0xFF && !state->mask && !lateclip)
+ if (state->opacity == 0xFF && !state->filter && !state->mask && !lateclip)
return;
render->cr = (cairo_t *)render->cr_stack->data;
render->cr_stack = g_list_remove_link (render->cr_stack, render->cr_stack);
- cairo_set_source_surface (render->cr,
- cairo_get_target (child_cr),
- 0, 0);
-
+ if (state->filter)
+ {
+ GdkPixbuf * pixbuf = render->pixbuf_stack->data;
+ RsvgIRect bounds;
+ RsvgCairoBbox bbox;
+ double affine[6];
+ _rsvg_affine_identity(affine);
+ rsvg_cairo_bbox_init(&bbox, affine);
+ rsvg_cairo_bbox_insert(&bbox, &render->bbox);
+ bounds.x0 = bbox.x;
+ bounds.y0 = bbox.y;
+ bounds.x1 = bbox.w + bbox.x;
+ bounds.y1 = bbox.h + bbox.y;
+ render->pixbuf_stack = g_list_remove_link (render->pixbuf_stack,
+ render->pixbuf_stack);
+
+
+ rsvg_cairo_to_pixbuf(gdk_pixbuf_get_pixels(pixbuf),
+ gdk_pixbuf_get_rowstride(pixbuf),
+ gdk_pixbuf_get_height(pixbuf));
+ output = rsvg_filter_render (state->filter, pixbuf, pixbuf,
+ ctx, &bounds);
+ gdk_pixbuf_unref(pixbuf);
+ rsvg_pixbuf_to_cairo(gdk_pixbuf_get_pixels(output),
+ gdk_pixbuf_get_rowstride(output),
+ gdk_pixbuf_get_height(output));
+
+ surface = cairo_image_surface_create_for_data (gdk_pixbuf_get_pixels(output),
+ CAIRO_FORMAT_ARGB32,
+ gdk_pixbuf_get_width(output),
+ gdk_pixbuf_get_height(output),
+ gdk_pixbuf_get_rowstride(output));
+ cairo_set_source_surface (render->cr,
+ surface,
+ 0, 0);
+ }
+ else
+ cairo_set_source_surface (render->cr,
+ cairo_get_target (child_cr),
+ 0, 0);
if (lateclip)
{
cairo_save(render->cr);
@@ -797,6 +865,12 @@ rsvg_cairo_pop_render_stack (RsvgDrawingCtx *ctx)
render->bb_stack = g_list_remove_link (render->bb_stack, render->bb_stack);
if (lateclip)
cairo_restore(render->cr);
+
+ if (state->filter)
+ {
+ gdk_pixbuf_unref(output);
+ cairo_surface_destroy(surface);
+ }
}
void
@@ -824,12 +898,6 @@ rsvg_cairo_add_clipping_rect (RsvgDrawingCtx *ctx,
cairo_set_matrix (cr, &save);
}
-static void
-rsvg_pixmap_destroy (gchar *pixels, gpointer data)
-{
- g_free (pixels);
-}
-
GdkPixbuf *
rsvg_cairo_get_image_of_node (RsvgDrawingCtx *ctx,
RsvgNode *drawable,
@@ -842,7 +910,7 @@ rsvg_cairo_get_image_of_node (RsvgDrawingCtx *ctx,
cairo_surface_t * surface;
cairo_t * cr;
guint8 *pixels;
- int row, rowstride;
+ int rowstride;
RsvgCairoRender *save_render = (RsvgCairoRender *)ctx->render;
RsvgCairoRender *render;
@@ -856,6 +924,8 @@ rsvg_cairo_get_image_of_node (RsvgDrawingCtx *ctx,
cr = cairo_create (surface);
cairo_surface_destroy (surface);
+ rsvg_cairo_to_pixbuf(pixels, rowstride, height);
+
render = rsvg_cairo_render_new(cr, width, height);
ctx->render = (RsvgRender *)render;
@@ -863,6 +933,25 @@ rsvg_cairo_get_image_of_node (RsvgDrawingCtx *ctx,
rsvg_node_draw (drawable, ctx, 0);
rsvg_state_pop(ctx);
+ img = gdk_pixbuf_new_from_data (pixels,
+ GDK_COLORSPACE_RGB,
+ TRUE,
+ 8,
+ width,
+ height,
+ rowstride,
+ (GdkPixbufDestroyNotify)rsvg_pixmap_destroy,
+ NULL);
+
+ cairo_destroy (cr);
+ ctx->render = (RsvgRender *)save_render;
+
+ return img;
+}
+
+void rsvg_cairo_to_pixbuf(guint8 *pixels, int rowstride, int height)
+{
+ int row;
/* un-premultiply data */
for(row = 0; row < height; row++) {
guint8 *row_data = (pixels + (row * rowstride));
@@ -885,19 +974,30 @@ rsvg_cairo_get_image_of_node (RsvgDrawingCtx *ctx,
}
}
}
+}
- img = gdk_pixbuf_new_from_data (pixels,
- GDK_COLORSPACE_RGB,
- TRUE,
- 8,
- width,
- height,
- rowstride,
- (GdkPixbufDestroyNotify)rsvg_pixmap_destroy,
- NULL);
+void rsvg_pixbuf_to_cairo(guint8 *pixels, int rowstride, int height)
+{
+ int row;
+ /* un-premultiply data */
+ for(row = 0; row < height; row++) {
+ guint8 *row_data = (pixels + (row * rowstride));
+ int i;
- cairo_destroy (cr);
- ctx->render = (RsvgRender *)save_render;
+ for(i = 0; i < rowstride; i += 4) {
+ guint32 *b = (guint32 *)&row_data[i];
+ guint8 pixel[4];
+ int alpha;
- return img;
+ memcpy(&pixel, b, sizeof(guint32));
+ alpha = pixel[3];
+ if(alpha == 0)
+ *b = 0;
+ else
+ *b = alpha << 24 |
+ (int)pixel[0] * alpha / 255 << 16 |
+ (int)pixel[1] * alpha / 255 << 8 |
+ (int)pixel[2] * alpha / 255;
+ }
+ }
}
diff --git a/rsvg-cairo-draw.h b/rsvg-cairo-draw.h
index 6a3e5a76..5065482b 100644
--- a/rsvg-cairo-draw.h
+++ b/rsvg-cairo-draw.h
@@ -57,6 +57,9 @@ rsvg_cairo_get_image_of_node (RsvgDrawingCtx *ctx,
double width,
double height);
+void rsvg_cairo_to_pixbuf(guint8 *pixels, int rowstride, int height);
+void rsvg_pixbuf_to_cairo(guint8 *pixels, int rowstride, int height);
+
G_END_DECLS
#endif /*RSVG_CAIRO_DRAW_H*/
diff --git a/rsvg-cairo-render.c b/rsvg-cairo-render.c
index ab5fdab5..d7446428 100644
--- a/rsvg-cairo-render.c
+++ b/rsvg-cairo-render.c
@@ -62,7 +62,7 @@ rsvg_cairo_render_new(cairo_t * cr, double width, double height)
cairo_render->cr = cr;
cairo_render->cr_stack = NULL;
cairo_render->bb_stack = NULL;
-
+ cairo_render->pixbuf_stack = NULL;
return cairo_render;
}
diff --git a/rsvg-cairo-render.h b/rsvg-cairo-render.h
index 729f62fc..52151bba 100644
--- a/rsvg-cairo-render.h
+++ b/rsvg-cairo-render.h
@@ -50,6 +50,7 @@ struct _RsvgCairoRender {
RsvgCairoBbox bbox;
GList *bb_stack;
+ GList *pixbuf_stack;
};
RsvgCairoRender * rsvg_cairo_render_new(cairo_t * cr, double width, double height);
diff --git a/rsvg.c b/rsvg.c
index 814e75c2..0b944a7c 100644
--- a/rsvg.c
+++ b/rsvg.c
@@ -115,6 +115,7 @@ static GdkPixbuf * _rsvg_handle_get_pixbuf (RsvgHandle *handle)
#elif defined(WITH_CAIRO_BACKEND)
#include "rsvg-cairo.h"
+#include "rsvg-cairo-draw.h"
static void
rsvg_pixmap_destroy (gchar *pixels, gpointer data)
@@ -129,7 +130,7 @@ static GdkPixbuf * _rsvg_handle_get_pixbuf (RsvgHandle *handle)
guint8 *pixels;
cairo_surface_t *surface;
cairo_t *cr;
- int row, rowstride;
+ int rowstride;
rsvg_handle_get_dimensions (handle, &dimensions);
rowstride = dimensions.width * 4;
@@ -145,28 +146,7 @@ static GdkPixbuf * _rsvg_handle_get_pixbuf (RsvgHandle *handle)
rsvg_cairo_render (cr, handle);
- /* un-premultiply data */
- for(row = 0; row < dimensions.height; row++) {
- guint8 *row_data = (pixels + (row * rowstride));
- int i;
-
- for(i = 0; i < rowstride; i += 4) {
- guint8 *b = &row_data[i];
- guint32 pixel;
- guint8 alpha;
-
- memcpy(&pixel, b, sizeof(guint32));
- alpha = (pixel & 0xff000000) >> 24;
- if(alpha == 0) {
- b[0] = b[1] = b[2] = b[3] = 0;
- } else {
- b[0] = (((pixel & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
- b[1] = (((pixel & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
- b[2] = (((pixel & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
- b[3] = alpha;
- }
- }
- }
+ rsvg_cairo_to_pixbuf(pixels, rowstride, dimensions.height);
output = gdk_pixbuf_new_from_data (pixels,
GDK_COLORSPACE_RGB,