[eog] Render SVGs using librsvg when filtering is enabled
- From: Felix Riemann <friemann src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [eog] Render SVGs using librsvg when filtering is enabled
- Date: Sun, 18 Apr 2010 12:34:13 +0000 (UTC)
commit 21caf5f03041e236157e967bf2c07832b5ba551b
Author: Hiroyuki Ikezoe <hiikezoe gnome org>
Date: Sun Apr 18 14:12:17 2010 +0200
Render SVGs using librsvg when filtering is enabled
Redraws scaled SVGs correctly instead of just showing a scaled and
filtered pixbuf. Note that depending on the filters used by the image
rendering can be quite slow at large zoom factors. Fixes bug 108435.
configure.ac | 18 ++++
src/eog-image-private.h | 6 ++
src/eog-image.c | 68 +++++++++++++-
src/eog-image.h | 10 ++
src/eog-scroll-view.c | 226 ++++++++++++++++++++++++++++++++++++++++++-----
src/eog-transform.c | 11 +++
src/eog-transform.h | 2 +
src/main.c | 6 ++
8 files changed, 320 insertions(+), 27 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 48d6fca..ef51307 100644
--- a/configure.ac
+++ b/configure.ac
@@ -275,6 +275,24 @@ AM_CONDITIONAL([HAVE_DBUS], [test "x$have_dbus" = "xyes"])
LIBXML2_REQUIRED=2.0
PKG_CHECK_MODULES(LIBXML2, [libxml-2.0 >= $LIBXML2_REQUIRED])
+# ***************
+# RSVG (optional for scaling svg image)
+# ***************
+
+LIBRSVG_REQUIRED=2.26.0
+
+AC_ARG_WITH([librsvg], AC_HELP_STRING([--without-librsvg], [disable RSVG support]))
+have_rsvg=no
+if test x$with_librsvg != xno; then
+ PKG_CHECK_MODULES(RSVG, librsvg-2.0 >= $LIBRSVG_REQUIRED, have_rsvg=yes, have_rsvg=no)
+fi
+if test "x$have_rsvg" = "xyes"; then
+ AC_DEFINE(HAVE_RSVG, 1, [RSVG Support.])
+ EOG_MODULES="$EOG_MODULES librsvg-2.0 >= $LIBRSVG_REQUIRED"
+fi
+
+AM_CONDITIONAL([HAVE_RSVG], [test "x$have_rsvg" = "xyes"])
+
# ****************
# CFLAGS/LIBS init
# ****************
diff --git a/src/eog-image-private.h b/src/eog-image-private.h
index a28c0fa..3bf2e54 100644
--- a/src/eog-image-private.h
+++ b/src/eog-image-private.h
@@ -23,6 +23,9 @@
#define __EOG_IMAGE_PRIVATE_H__
#include "eog-image.h"
+#ifdef HAVE_RSVG
+#include <librsvg/rsvg.h>
+#endif
G_BEGIN_DECLS
@@ -39,6 +42,9 @@ struct _EogImagePrivate {
GdkPixbufAnimationIter *anim_iter;
gboolean is_playing;
GdkPixbuf *thumbnail;
+#ifdef HAVE_RSVG
+ RsvgHandle *svg;
+#endif
gint width;
gint height;
diff --git a/src/eog-image.c b/src/eog-image.c
index 850c8a0..e6297d7 100644
--- a/src/eog-image.c
+++ b/src/eog-image.c
@@ -111,6 +111,13 @@ eog_image_free_mem_private (EogImage *image)
priv->image = NULL;
}
+#ifdef HAVE_RSVG
+ if (priv->svg != NULL) {
+ g_object_unref (priv->svg);
+ priv->svg = NULL;
+ }
+#endif
+
#ifdef HAVE_EXIF
if (priv->exif != NULL) {
exif_data_unref (priv->exif);
@@ -295,6 +302,9 @@ eog_image_init (EogImage *img)
#ifdef HAVE_LCMS
img->priv->profile = NULL;
#endif
+#ifdef HAVE_RSVG
+ img->priv->svg = NULL;
+#endif
}
EogImage *
@@ -936,6 +946,17 @@ eog_image_real_load (EogImage *img,
if (read_image_data || read_only_dimension) {
gboolean checked_threadsafety = FALSE;
+#ifdef HAVE_RSVG
+ if (priv->svg != NULL) {
+ g_object_unref (priv->svg);
+ priv->svg = NULL;
+ }
+
+ if (!strcmp (mime_type, "image/svg+xml")) {
+ /* Keep the object for rendering */
+ priv->svg = rsvg_handle_new ();
+ }
+#endif
loader = gdk_pixbuf_loader_new_with_mime_type (mime_type, error);
if (error && *error) {
@@ -987,10 +1008,18 @@ eog_image_real_load (EogImage *img,
break;
}
- if ((read_image_data || read_only_dimension) &&
- !gdk_pixbuf_loader_write (loader, buffer, bytes_read, error)) {
- failed = TRUE;
- break;
+ if ((read_image_data || read_only_dimension)) {
+ if (!gdk_pixbuf_loader_write (loader, buffer, bytes_read, error)) {
+ failed = TRUE;
+ break;
+ }
+#ifdef HAVE_RSVG
+ if (eog_image_is_svg (img) &&
+ !rsvg_handle_write (priv->svg, buffer, bytes_read, error)) {
+ failed = TRUE;
+ break;
+ }
+#endif
}
bytes_read_total += bytes_read;
@@ -1060,6 +1089,10 @@ eog_image_real_load (EogImage *img,
g_clear_error (error);
}
}
+#ifdef HAVE_RSVG
+ if (eog_image_is_svg (img))
+ rsvg_handle_close (priv->svg, error);
+#endif
}
g_free (buffer);
@@ -2148,3 +2181,30 @@ eog_image_start_animation (EogImage *img)
return TRUE;
}
+
+#ifdef HAVE_RSVG
+gboolean
+eog_image_is_svg (EogImage *img)
+{
+ g_return_val_if_fail (EOG_IS_IMAGE (img), FALSE);
+
+ return (img->priv->svg != NULL);
+}
+
+RsvgHandle *
+eog_image_get_svg (EogImage *img)
+{
+ g_return_val_if_fail (EOG_IS_IMAGE (img), NULL);
+
+ return img->priv->svg;
+}
+
+EogTransform *
+eog_image_get_transform (EogImage *img)
+{
+ g_return_val_if_fail (EOG_IS_IMAGE (img), NULL);
+
+ return img->priv->trans;
+}
+
+#endif
diff --git a/src/eog-image.h b/src/eog-image.h
index 52dffc3..75181f9 100644
--- a/src/eog-image.h
+++ b/src/eog-image.h
@@ -44,6 +44,10 @@
#include <exempi/xmp.h>
#endif
+#ifdef HAVE_RSVG
+#include <librsvg/rsvg.h>
+#endif
+
G_BEGIN_DECLS
#ifndef __EOG_IMAGE_DECLR__
@@ -199,6 +203,12 @@ gboolean eog_image_is_animation (EogImage *img);
gboolean eog_image_start_animation (EogImage *img);
+#ifdef HAVE_RSVG
+gboolean eog_image_is_svg (EogImage *img);
+RsvgHandle *eog_image_get_svg (EogImage *img);
+EogTransform *eog_image_get_transform (EogImage *img);
+#endif
+
G_END_DECLS
#endif /* __EOG_IMAGE_H__ */
diff --git a/src/eog-scroll-view.c b/src/eog-scroll-view.c
index 3e50a31..52f3973 100644
--- a/src/eog-scroll-view.c
+++ b/src/eog-scroll-view.c
@@ -6,6 +6,10 @@
#include <math.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gdk/gdkkeysyms.h>
+#ifdef HAVE_RSVG
+#include <librsvg/rsvg.h>
+#include <librsvg/rsvg-cairo.h>
+#endif
#include "eog-marshal.h"
#include "eog-scroll-view.h"
@@ -133,6 +137,8 @@ struct _EogScrollViewPrivate {
/* the type of the cursor we are currently showing */
EogScrollViewCursor cursor;
+
+ cairo_surface_t *background_surface;
};
static void scroll_by (EogScrollView *view, int xofs, int yofs);
@@ -537,6 +543,190 @@ paint_background (EogScrollView *view, EogIRect *r, EogIRect *rect)
}
}
+static void
+get_transparency_params (EogScrollView *view, int *size, guint32 *color1, guint32 *color2)
+{
+ EogScrollViewPrivate *priv;
+
+ priv = view->priv;
+
+ /* Compute transparency parameters */
+ switch (priv->transp_style) {
+ case EOG_TRANSP_BACKGROUND: {
+ GdkColor color = gtk_widget_get_style (GTK_WIDGET (priv->display))->bg[GTK_STATE_NORMAL];
+
+ *color1 = *color2 = (((color.red & 0xff00) << 8)
+ | (color.green & 0xff00)
+ | ((color.blue & 0xff00) >> 8));
+ break; }
+
+ case EOG_TRANSP_CHECKED:
+ *color1 = CHECK_GRAY;
+ *color2 = CHECK_LIGHT;
+ break;
+
+ case EOG_TRANSP_COLOR:
+ *color1 = *color2 = priv->transp_color;
+ break;
+
+ default:
+ g_assert_not_reached ();
+ };
+
+ *size = CHECK_MEDIUM;
+}
+
+#ifdef HAVE_RSVG
+static cairo_surface_t *
+create_background_surface (EogScrollView *view)
+{
+ int check_size;
+ guint32 check_1 = 0;
+ guint32 check_2 = 0;
+ cairo_surface_t *surface;
+ cairo_t *check_cr;
+
+ get_transparency_params (view, &check_size, &check_1, &check_2);
+
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, check_size * 2, check_size * 2);
+ check_cr = cairo_create (surface);
+ cairo_set_source_rgba (check_cr,
+ ((check_1 & 0xff0000) >> 16) / 255.,
+ ((check_1 & 0x00ff00) >> 8) / 255.,
+ (check_1 & 0x0000ff) / 255.,
+ 1.);
+ cairo_rectangle (check_cr, 0., 0., check_size, check_size);
+ cairo_fill (check_cr);
+ cairo_translate (check_cr, check_size, check_size);
+ cairo_rectangle (check_cr, 0., 0., check_size, check_size);
+ cairo_fill (check_cr);
+
+ cairo_set_source_rgba (check_cr,
+ ((check_2 & 0xff0000) >> 16) / 255.,
+ ((check_2 & 0x00ff00) >> 8) / 255.,
+ (check_2 & 0x0000ff) / 255.,
+ 1.);
+ cairo_translate (check_cr, -check_size, 0);
+ cairo_rectangle (check_cr, 0., 0., check_size, check_size);
+ cairo_fill (check_cr);
+ cairo_translate (check_cr, check_size, -check_size);
+ cairo_rectangle (check_cr, 0., 0., check_size, check_size);
+ cairo_fill (check_cr);
+ cairo_destroy (check_cr);
+
+ return surface;
+}
+
+static void
+draw_svg_background (EogScrollView *view, cairo_t *cr, EogIRect *render_rect, EogIRect *image_rect)
+{
+ EogScrollViewPrivate *priv;
+
+ priv = view->priv;
+
+ if (priv->background_surface == NULL)
+ priv->background_surface = create_background_surface (view);
+
+ cairo_set_source_surface (cr, priv->background_surface,
+ - (render_rect->x0 - image_rect->x0) % (CHECK_MEDIUM * 2),
+ - (render_rect->y0 - image_rect->y0) % (CHECK_MEDIUM * 2));
+ cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT);
+ cairo_rectangle (cr,
+ 0,
+ 0,
+ render_rect->x1 - render_rect->x0,
+ render_rect->y1 - render_rect->y0);
+ cairo_fill (cr);
+}
+
+static cairo_surface_t *
+draw_svg_on_image_surface (EogScrollView *view, EogIRect *render_rect, EogIRect *image_rect)
+{
+ EogScrollViewPrivate *priv;
+ cairo_t *cr;
+ cairo_surface_t *surface;
+ cairo_matrix_t matrix, translate, scale;
+ EogTransform *transform;
+
+ priv = view->priv;
+
+ surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ render_rect->x1 - render_rect->x0,
+ render_rect->y1 - render_rect->y0);
+ cr = cairo_create (surface);
+
+ cairo_save (cr);
+ draw_svg_background (view, cr, render_rect, image_rect);
+ cairo_restore (cr);
+
+ cairo_matrix_init_identity (&matrix);
+ transform = eog_image_get_transform (priv->image);
+ if (transform) {
+ cairo_matrix_t affine;
+ double image_offset_x = 0., image_offset_y = 0.;
+
+ eog_transform_get_affine (transform, &affine);
+ cairo_matrix_multiply (&matrix, &affine, &matrix);
+
+ switch (eog_transform_get_transform_type (transform)) {
+ case EOG_TRANSFORM_ROT_90:
+ case EOG_TRANSFORM_FLIP_HORIZONTAL:
+ image_offset_x = (double) gdk_pixbuf_get_width (priv->pixbuf);
+ break;
+ case EOG_TRANSFORM_ROT_270:
+ case EOG_TRANSFORM_FLIP_VERTICAL:
+ image_offset_y = (double) gdk_pixbuf_get_height (priv->pixbuf);
+ break;
+ case EOG_TRANSFORM_ROT_180:
+ case EOG_TRANSFORM_TRANSPOSE:
+ case EOG_TRANSFORM_TRANSVERSE:
+ image_offset_x = (double) gdk_pixbuf_get_width (priv->pixbuf);
+ image_offset_y = (double) gdk_pixbuf_get_height (priv->pixbuf);
+ break;
+ case EOG_TRANSFORM_NONE:
+ default:
+ break;
+ }
+
+ cairo_matrix_init_translate (&translate, image_offset_x, image_offset_y);
+ cairo_matrix_multiply (&matrix, &matrix, &translate);
+ }
+
+ cairo_matrix_init_scale (&scale, priv->zoom, priv->zoom);
+ cairo_matrix_multiply (&matrix, &matrix, &scale);
+ cairo_matrix_init_translate (&translate, image_rect->x0, image_rect->y0);
+ cairo_matrix_multiply (&matrix, &matrix, &translate);
+ cairo_matrix_init_translate (&translate, -render_rect->x0, -render_rect->y0);
+ cairo_matrix_multiply (&matrix, &matrix, &translate);
+
+ cairo_set_matrix (cr, &matrix);
+
+ rsvg_handle_render_cairo (eog_image_get_svg (priv->image), cr);
+ cairo_destroy (cr);
+
+ return surface;
+}
+
+static void
+draw_svg (EogScrollView *view, EogIRect *render_rect, EogIRect *image_rect)
+{
+ EogScrollViewPrivate *priv;
+ cairo_t *cr;
+ cairo_surface_t *surface;
+ GdkWindow *window;
+
+ priv = view->priv;
+
+ window = gtk_widget_get_window (GTK_WIDGET (priv->display));
+ surface = draw_svg_on_image_surface (view, render_rect, image_rect);
+
+ cr = gdk_cairo_create (window);
+ cairo_set_source_surface (cr, surface, render_rect->x0, render_rect->y0);
+ cairo_paint (cr);
+ cairo_destroy (cr);
+}
+#endif
+
/* Paints a rectangle of the dirty region */
static void
paint_rectangle (EogScrollView *view, EogIRect *rect, GdkInterpType interp_type)
@@ -656,6 +846,12 @@ paint_rectangle (EogScrollView *view, EogIRect *rect, GdkInterpType interp_type)
eog_debug_message (DEBUG_WINDOW, "%s: x0: %i,\t y0: %i,\t x1: %i,\t y1: %i\n",
str, d.x0, d.y0, d.x1, d.y1);
+#ifdef HAVE_RSVG
+ if (eog_image_is_svg (view->priv->image) && interp_type != GDK_INTERP_NEAREST) {
+ draw_svg (view, &d, &r);
+ return;
+ }
+#endif
/* Short-circuit the fast case to avoid a memcpy() */
if (is_unity_zoom (view)
@@ -693,29 +889,7 @@ paint_rectangle (EogScrollView *view, EogIRect *rect, GdkInterpType interp_type)
}
/* Compute transparency parameters */
- switch (priv->transp_style) {
- case EOG_TRANSP_BACKGROUND: {
- GdkColor color = gtk_widget_get_style (GTK_WIDGET (priv->display))->bg[GTK_STATE_NORMAL];
-
- check_1 = check_2 = (((color.red & 0xff00) << 8)
- | (color.green & 0xff00)
- | ((color.blue & 0xff00) >> 8));
- break; }
-
- case EOG_TRANSP_CHECKED:
- check_1 = CHECK_GRAY;
- check_2 = CHECK_LIGHT;
- break;
-
- case EOG_TRANSP_COLOR:
- check_1 = check_2 = priv->transp_color;
- break;
-
- default:
- g_assert_not_reached ();
- };
-
- check_size = CHECK_MEDIUM;
+ get_transparency_params (view, &check_size, &check_1, &check_2);
/* Draw! */
gdk_pixbuf_composite_color (priv->pixbuf,
@@ -2010,6 +2184,7 @@ eog_scroll_view_init (EogScrollView *view)
priv->transp_color = 0;
priv->cursor = EOG_SCROLL_VIEW_CURSOR_NORMAL;
priv->menu = NULL;
+ priv->background_surface = NULL;
}
static void
@@ -2033,6 +2208,11 @@ eog_scroll_view_dispose (GObject *object)
priv->idle_id = 0;
}
+ if (priv->background_surface != NULL) {
+ cairo_surface_destroy (priv->background_surface);
+ priv->background_surface = NULL;
+ }
+
free_image_resources (view);
G_OBJECT_CLASS (eog_scroll_view_parent_class)->dispose (object);
diff --git a/src/eog-transform.c b/src/eog-transform.c
index 3c730b3..3a4c7f8 100644
--- a/src/eog-transform.c
+++ b/src/eog-transform.c
@@ -405,3 +405,14 @@ eog_transform_get_transform_type (EogTransform *trans)
return EOG_TRANSFORM_NONE;
}
+
+gboolean
+eog_transform_get_affine (EogTransform *trans, cairo_matrix_t *affine)
+{
+ g_return_val_if_fail (EOG_IS_TRANSFORM (trans), FALSE);
+
+ _eog_cairo_matrix_copy (&trans->priv->affine, affine);
+
+ return TRUE;
+}
+
diff --git a/src/eog-transform.h b/src/eog-transform.h
index 9b11c35..94c4222 100644
--- a/src/eog-transform.h
+++ b/src/eog-transform.h
@@ -66,6 +66,8 @@ EogTransform* eog_transform_new (EogTransformType trans);
EogTransformType eog_transform_get_transform_type (EogTransform *trans);
+gboolean eog_transform_get_affine (EogTransform *trans, cairo_matrix_t *affine);
+
G_END_DECLS
#endif /* _EOG_TRANSFORM_H_ */
diff --git a/src/main.c b/src/main.c
index 03c2241..ddc2d17 100644
--- a/src/main.c
+++ b/src/main.c
@@ -232,6 +232,9 @@ main (int argc, char **argv)
#ifdef HAVE_EXEMPI
xmp_init();
#endif
+#ifdef HAVE_RSVG
+ rsvg_init();
+#endif
eog_debug_init ();
eog_job_queue_init ();
gdk_threads_init ();
@@ -258,6 +261,9 @@ main (int argc, char **argv)
eog_plugin_engine_shutdown ();
+#ifdef HAVE_RSVG
+ rsvg_term();
+#endif
#ifdef HAVE_EXEMPI
xmp_terminate();
#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]