[gthumb: 5/129] image viewer: store the image in a cairo_surface instead of a GdkPixbuf



commit 9c24b9c41c2eef1616c3af84c7a948ea8e38ab94
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Thu Apr 14 16:38:20 2011 +0200

    image viewer: store the image in a cairo_surface instead of a GdkPixbuf
    
    to speed-up image drawing avoid to convert a GdkPixbuf to a cairo_image_surface on every expose event and store the image data in a cairo_image_surface directly.

 .../contact_sheet/gth-contact-sheet-creator.c      |    2 +-
 extensions/contact_sheet/gth-contact-sheet-theme.c |    2 +-
 extensions/file_tools/gth-image-rotator.c          |    8 +-
 gthumb/cairo-utils.c                               |   11 +
 gthumb/cairo-utils.h                               |    1 +
 gthumb/gth-image-dragger.c                         |   12 +-
 gthumb/gth-image-selector.c                        |  174 ++++++------
 gthumb/gth-image-viewer.c                          |  300 ++++++++++----------
 gthumb/gth-image-viewer.h                          |    7 +-
 gthumb/pixbuf-utils.c                              |   29 ++-
 gthumb/pixbuf-utils.h                              |    3 +-
 11 files changed, 279 insertions(+), 270 deletions(-)
---
diff --git a/extensions/contact_sheet/gth-contact-sheet-creator.c b/extensions/contact_sheet/gth-contact-sheet-creator.c
index 969f8fa..bbfd578 100644
--- a/extensions/contact_sheet/gth-contact-sheet-creator.c
+++ b/extensions/contact_sheet/gth-contact-sheet-creator.c
@@ -352,7 +352,7 @@ end_page (GthContactSheetCreator  *self,
 	char      *buffer;
 	gsize      size;
 
-	pixbuf = _gdk_pixbuf_new_from_cairo_surface (self->priv->cr);
+	pixbuf = _gdk_pixbuf_new_from_cairo_context (self->priv->cr);
 	if (! gth_pixbuf_saver_save_pixbuf (self->priv->pixbuf_saver,
 					    pixbuf,
 					    &buffer,
diff --git a/extensions/contact_sheet/gth-contact-sheet-theme.c b/extensions/contact_sheet/gth-contact-sheet-theme.c
index 027bc75..d307356 100644
--- a/extensions/contact_sheet/gth-contact-sheet-theme.c
+++ b/extensions/contact_sheet/gth-contact-sheet-theme.c
@@ -645,7 +645,7 @@ gth_contact_sheet_theme_create_preview (GthContactSheetTheme *theme,
 	cr = cairo_create (surface);
 	cairo_surface_destroy (surface);
 	gth_contact_sheet_theme_paint_preview (theme, cr, preview_size, preview_size);
-	pixbuf = _gdk_pixbuf_new_from_cairo_surface (cr);
+	pixbuf = _gdk_pixbuf_new_from_cairo_context (cr);
 
 	cairo_destroy (cr);
 
diff --git a/extensions/file_tools/gth-image-rotator.c b/extensions/file_tools/gth-image-rotator.c
index 3e3fab1..9f81a4a 100644
--- a/extensions/file_tools/gth-image-rotator.c
+++ b/extensions/file_tools/gth-image-rotator.c
@@ -281,9 +281,6 @@ gth_image_rotator_expose (GthImageViewerTool *base,
 	GtkStyle        *style;
 	GtkAllocation    allocation;
 
-	if (self->priv->preview_image == NULL)
-		return;
-
 	cairo_save (cr);
 
   	cairo_rectangle (cr,
@@ -301,6 +298,9 @@ gth_image_rotator_expose (GthImageViewerTool *base,
 	cairo_rectangle (cr, 0, 0, allocation.width, allocation.height);
 	cairo_fill (cr);
 
+	if (self->priv->preview_image == NULL)
+		return;
+
 	/* clip box */
 
   	cairo_rectangle (cr,
@@ -644,7 +644,7 @@ gth_image_rotator_get_result (GthImageRotator *self)
   	cairo_rectangle (cr, image_area.x, image_area.y, image_area.width, image_area.height);
   	cairo_fill (cr);
 
-	pixbuf = _gdk_pixbuf_new_from_cairo_surface (cr);
+	pixbuf = _gdk_pixbuf_new_from_cairo_context (cr);
 
 	cairo_destroy (cr);
 	cairo_surface_destroy (output);
diff --git a/gthumb/cairo-utils.c b/gthumb/cairo-utils.c
index 47ced00..e48a76c 100644
--- a/gthumb/cairo-utils.c
+++ b/gthumb/cairo-utils.c
@@ -126,6 +126,14 @@ _cairo_paint_full_gradient (cairo_surface_t *surface,
 }
 
 
+void
+_cairo_clear_surface (cairo_surface_t  **surface)
+{
+	cairo_surface_destroy (*surface);
+	*surface = NULL;
+}
+
+
 cairo_surface_t *
 _cairo_image_surface_create_from_pixbuf (GdkPixbuf *pixbuf)
 {
@@ -139,6 +147,9 @@ _cairo_image_surface_create_from_pixbuf (GdkPixbuf *pixbuf)
 	unsigned char   *s_pixels;
 	int              h, w;
 
+	if (pixbuf == NULL)
+		return NULL;
+
 	g_object_get (G_OBJECT (pixbuf),
 		      "width", &width,
 		      "height", &height,
diff --git a/gthumb/cairo-utils.h b/gthumb/cairo-utils.h
index be1d010..4496832 100644
--- a/gthumb/cairo-utils.h
+++ b/gthumb/cairo-utils.h
@@ -50,6 +50,7 @@ void         _cairo_paint_full_gradient         (cairo_surface_t   *surface,
 				 	 	 GdkColor          *h_color2,
 				 	 	 GdkColor          *v_color1,
 				 	 	 GdkColor          *v_color2);
+void         _cairo_clear_surface               (cairo_surface_t  **surface);
 cairo_surface_t *
 	     _cairo_image_surface_create_from_pixbuf
 	     	     	     	     	        (GdkPixbuf         *pixbuf);
diff --git a/gthumb/gth-image-dragger.c b/gthumb/gth-image-dragger.c
index 15d216a..c7e571d 100644
--- a/gthumb/gth-image-dragger.c
+++ b/gthumb/gth-image-dragger.c
@@ -137,7 +137,7 @@ gth_image_dragger_expose (GthImageViewerTool *self,
 {
 	GthImageDragger *dragger;
 	GthImageViewer  *viewer;
-	GdkInterpType    interp_type;
+	cairo_filter_t   filter;
 
 	dragger = (GthImageDragger *) self;
 	viewer = dragger->priv->viewer;
@@ -146,21 +146,21 @@ gth_image_dragger_expose (GthImageViewerTool *self,
 		return;
 
 	if (gth_image_viewer_get_zoom_quality (viewer) == GTH_ZOOM_QUALITY_LOW)
-		interp_type = GDK_INTERP_TILES;
+		filter = CAIRO_FILTER_FAST;
 	else
-		interp_type = GDK_INTERP_BILINEAR;
+		filter = CAIRO_FILTER_GOOD;
 
 	if (gth_image_viewer_get_zoom (viewer) == 1.0)
-		interp_type = GDK_INTERP_NEAREST;
+		filter = CAIRO_FILTER_FAST;
 
 	gth_image_viewer_paint_region (viewer,
 				       cr,
-				       gth_image_viewer_get_current_pixbuf (viewer),
+				       gth_image_viewer_get_current_image (viewer),
 				       viewer->x_offset - viewer->image_area.x,
 				       viewer->y_offset - viewer->image_area.y,
 				       &viewer->image_area,
 				       event->region,
-				       interp_type);
+				       filter);
 
 	gth_image_viewer_apply_painters (viewer, event, cr);
 }
diff --git a/gthumb/gth-image-selector.c b/gthumb/gth-image-selector.c
index c113476..a0f9f23 100644
--- a/gthumb/gth-image-selector.c
+++ b/gthumb/gth-image-selector.c
@@ -194,8 +194,8 @@ struct _GthImageSelectorPrivate {
 	GthImageViewer  *viewer;
 	GthSelectorType  type;
 
-	GdkPixbuf       *pixbuf;
-	GdkRectangle     pixbuf_area;
+	cairo_surface_t *surface;
+	GdkRectangle     surface_area;
 
 	gboolean         use_ratio;
 	double           ratio;
@@ -490,21 +490,21 @@ init_selection (GthImageSelector *self)
 
 	/*
 	if (! self->priv->use_ratio) {
-		area.width = IROUND (self->priv->pixbuf_area.width * 0.5);
-		area.height = IROUND (self->priv->pixbuf_area.height * 0.5);
+		area.width = IROUND (self->priv->surface_area.width * 0.5);
+		area.height = IROUND (self->priv->surface_area.height * 0.5);
 	}
 	else {
 		if (self->priv->ratio > 1.0) {
-			area.width = IROUND (self->priv->pixbuf_area.width * 0.5);
+			area.width = IROUND (self->priv->surface_area.width * 0.5);
 			area.height = IROUND (area.width / self->priv->ratio);
 		}
 		else {
-			area.height = IROUND (self->priv->pixbuf_area.height * 0.5);
+			area.height = IROUND (self->priv->surface_area.height * 0.5);
 			area.width = IROUND (area.height * self->priv->ratio);
 		}
 	}
-	area.x = IROUND ((self->priv->pixbuf_area.width - area.width) / 2.0);
-	area.y = IROUND ((self->priv->pixbuf_area.height - area.height) / 2.0);
+	area.x = IROUND ((self->priv->surface_area.width - area.width) / 2.0);
+	area.y = IROUND ((self->priv->surface_area.height - area.height) / 2.0);
 	*/
 
 	area.x = 0;
@@ -564,7 +564,7 @@ gth_image_selector_size_allocate (GthImageViewerTool *base,
 {
 	GthImageSelector *self = GTH_IMAGE_SELECTOR (base);
 
-	if (self->priv->pixbuf != NULL)
+	if (self->priv->surface != NULL)
 		selection_changed (self);
 }
 
@@ -590,12 +590,12 @@ paint_background (GthImageSelector *self,
 {
 	gth_image_viewer_paint_region (self->priv->viewer,
 				       cr,
-				       self->priv->pixbuf,
+				       self->priv->surface,
 				       self->priv->viewer->x_offset - self->priv->viewer->image_area.x,
 				       self->priv->viewer->y_offset - self->priv->viewer->image_area.y,
 				       &self->priv->viewer->image_area,
 				       event->region,
-				       GDK_INTERP_TILES);
+				       CAIRO_FILTER_GOOD);
 
 	/* make the background darker */
 	{
@@ -634,12 +634,12 @@ paint_selection (GthImageSelector *self,
 	if (! self->priv->viewer->dragging)
 		gth_image_viewer_paint_region (self->priv->viewer,
 					       cr,
-					       self->priv->pixbuf,
+					       self->priv->surface,
 					       self->priv->viewer->x_offset - self->priv->viewer->image_area.x,
 					       self->priv->viewer->y_offset - self->priv->viewer->image_area.y,
 					       &selection_area,
 					       event->region,
-					       GDK_INTERP_TILES);
+					       CAIRO_FILTER_GOOD);
 
 	cairo_save (cr);
 #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 9, 2)
@@ -722,12 +722,12 @@ paint_image (GthImageSelector *self,
 {
 	gth_image_viewer_paint_region (self->priv->viewer,
 				       cr,
-				       self->priv->pixbuf,
+				       self->priv->surface,
 				       self->priv->viewer->x_offset - self->priv->viewer->image_area.x,
 				       self->priv->viewer->y_offset - self->priv->viewer->image_area.y,
 				       &self->priv->viewer->image_area,
 				       event->region,
-				       GDK_INTERP_TILES);
+				       CAIRO_FILTER_GOOD);
 }
 
 
@@ -924,7 +924,7 @@ check_and_set_new_selection (GthImageSelector *self,
 	     || (self->priv->current_area->id != C_SELECTION_AREA))
 	    && self->priv->use_ratio)
 	{
-		if (! rectangle_in_rectangle (new_selection, self->priv->pixbuf_area))
+		if (! rectangle_in_rectangle (new_selection, self->priv->surface_area))
 			return FALSE;
 
 		set_selection (self, new_selection, FALSE);
@@ -937,15 +937,15 @@ check_and_set_new_selection (GthImageSelector *self,
 		new_selection.x = 0;
 	if (new_selection.y < 0)
 		new_selection.y = 0;
-	if (new_selection.width > self->priv->pixbuf_area.width)
-		new_selection.width = self->priv->pixbuf_area.width;
-	if (new_selection.height > self->priv->pixbuf_area.height)
-		new_selection.height = self->priv->pixbuf_area.height;
+	if (new_selection.width > self->priv->surface_area.width)
+		new_selection.width = self->priv->surface_area.width;
+	if (new_selection.height > self->priv->surface_area.height)
+		new_selection.height = self->priv->surface_area.height;
 
-	if (new_selection.x + new_selection.width > self->priv->pixbuf_area.width)
-		new_selection.x = self->priv->pixbuf_area.width - new_selection.width;
-	if (new_selection.y + new_selection.height > self->priv->pixbuf_area.height)
-		new_selection.y = self->priv->pixbuf_area.height - new_selection.height;
+	if (new_selection.x + new_selection.width > self->priv->surface_area.width)
+		new_selection.x = self->priv->surface_area.width - new_selection.width;
+	if (new_selection.y + new_selection.height > self->priv->surface_area.height)
+		new_selection.y = self->priv->surface_area.height - new_selection.height;
 
 	set_selection (self, new_selection, FALSE);
 
@@ -1070,36 +1070,36 @@ update_mouse_selection (GthImageSelector *self)
 		break;
 
 	case C_TOP_AREA:
-		grow_upward (&self->priv->pixbuf_area, &new_selection, dy, check);
+		grow_upward (&self->priv->surface_area, &new_selection, dy, check);
 		if (self->priv->use_ratio)
-			grow_rightward (&self->priv->pixbuf_area,
+			grow_rightward (&self->priv->surface_area,
 					&new_selection,
 					IROUND (-dy * self->priv->ratio),
 					check);
 		break;
 
 	case C_BOTTOM_AREA:
-		grow_downward (&self->priv->pixbuf_area, &new_selection, dy, check);
+		grow_downward (&self->priv->surface_area, &new_selection, dy, check);
 		if (self->priv->use_ratio)
-			grow_rightward (&self->priv->pixbuf_area,
+			grow_rightward (&self->priv->surface_area,
 				        &new_selection,
 				        IROUND (dy * self->priv->ratio),
 				        check);
 		break;
 
 	case C_LEFT_AREA:
-		grow_leftward (&self->priv->pixbuf_area, &new_selection, dx, check);
+		grow_leftward (&self->priv->surface_area, &new_selection, dx, check);
 		if (self->priv->use_ratio)
-			grow_downward (&self->priv->pixbuf_area,
+			grow_downward (&self->priv->surface_area,
 				       &new_selection,
 				       IROUND (-dx / self->priv->ratio),
 				       check);
 		break;
 
 	case C_RIGHT_AREA:
-		grow_rightward (&self->priv->pixbuf_area, &new_selection, dx, check);
+		grow_rightward (&self->priv->surface_area, &new_selection, dx, check);
 		if (self->priv->use_ratio)
-			grow_downward (&self->priv->pixbuf_area,
+			grow_downward (&self->priv->surface_area,
 				       &new_selection,
 				       IROUND (dx / self->priv->ratio),
 				       check);
@@ -1119,8 +1119,8 @@ update_mouse_selection (GthImageSelector *self)
 			else
 				dx = IROUND (dy * self->priv->ratio);
 		}
-		grow_upward (&self->priv->pixbuf_area, &new_selection, dy, check);
-		grow_leftward (&self->priv->pixbuf_area, &new_selection, dx, check);
+		grow_upward (&self->priv->surface_area, &new_selection, dy, check);
+		grow_leftward (&self->priv->surface_area, &new_selection, dx, check);
 		break;
 
 	case C_TOP_RIGHT_AREA:
@@ -1137,8 +1137,8 @@ update_mouse_selection (GthImageSelector *self)
 			else
 				dy = IROUND (-dx / self->priv->ratio);
 		}
-		grow_upward (&self->priv->pixbuf_area, &new_selection, dy, check);
-		grow_rightward (&self->priv->pixbuf_area, &new_selection, dx, check);
+		grow_upward (&self->priv->surface_area, &new_selection, dy, check);
+		grow_rightward (&self->priv->surface_area, &new_selection, dx, check);
 		break;
 
 	case C_BOTTOM_LEFT_AREA:
@@ -1155,8 +1155,8 @@ update_mouse_selection (GthImageSelector *self)
 			else
 				dy = IROUND (-dx / self->priv->ratio);
 		}
-		grow_downward (&self->priv->pixbuf_area, &new_selection, dy, check);
-		grow_leftward (&self->priv->pixbuf_area, &new_selection, dx, check);
+		grow_downward (&self->priv->surface_area, &new_selection, dy, check);
+		grow_leftward (&self->priv->surface_area, &new_selection, dx, check);
 		break;
 
 	case C_BOTTOM_RIGHT_AREA:
@@ -1174,8 +1174,8 @@ update_mouse_selection (GthImageSelector *self)
 			else
 				dx = IROUND (dy * self->priv->ratio);
 		}
-		grow_downward (&self->priv->pixbuf_area, &new_selection, dy, check);
-		grow_rightward (&self->priv->pixbuf_area, &new_selection, dx, check);
+		grow_downward (&self->priv->surface_area, &new_selection, dy, check);
+		grow_rightward (&self->priv->surface_area, &new_selection, dx, check);
 		break;
 
 	default:
@@ -1188,19 +1188,19 @@ update_mouse_selection (GthImageSelector *self)
 
 	if ((area_type != C_SELECTION_AREA)
 	    && self->priv->use_ratio
-	    && ! rectangle_in_rectangle (new_selection, self->priv->pixbuf_area))
+	    && ! rectangle_in_rectangle (new_selection, self->priv->surface_area))
 	{
 		switch (area_type) {
 		case C_TOP_AREA:
-			if (new_selection.y < self->priv->pixbuf_area.y) {
+			if (new_selection.y < self->priv->surface_area.y) {
 				dy = new_selection.y + new_selection.height;
 				dx = IROUND (dy * self->priv->ratio);
 				new_selection.y = new_selection.y + new_selection.height - dy;
 				new_selection.width = dx;
 				new_selection.height = dy;
 			}
-			if (new_selection.x + new_selection.width > self->priv->pixbuf_area.width) {
-				dx = self->priv->pixbuf_area.width - new_selection.x;
+			if (new_selection.x + new_selection.width > self->priv->surface_area.width) {
+				dx = self->priv->surface_area.width - new_selection.x;
 				dy = IROUND (dx / self->priv->ratio);
 				new_selection.y = new_selection.y + new_selection.height - dy;
 				new_selection.width = dx;
@@ -1209,14 +1209,14 @@ update_mouse_selection (GthImageSelector *self)
 			break;
 
 		case C_RIGHT_AREA:
-			if (new_selection.x + new_selection.width > self->priv->pixbuf_area.width) {
-				dx = self->priv->pixbuf_area.width - new_selection.x;
+			if (new_selection.x + new_selection.width > self->priv->surface_area.width) {
+				dx = self->priv->surface_area.width - new_selection.x;
 				dy = IROUND (dx / self->priv->ratio);
 				new_selection.width = dx;
 				new_selection.height = dy;
 			}
-			if (new_selection.y + new_selection.height > self->priv->pixbuf_area.height) {
-				dy = self->priv->pixbuf_area.height - new_selection.y;
+			if (new_selection.y + new_selection.height > self->priv->surface_area.height) {
+				dy = self->priv->surface_area.height - new_selection.y;
 				dx = IROUND (dy * self->priv->ratio);
 				new_selection.width = dx;
 				new_selection.height = dy;
@@ -1224,22 +1224,22 @@ update_mouse_selection (GthImageSelector *self)
 			break;
 
 		case C_TOP_RIGHT_AREA:
-			if (new_selection.x + new_selection.width > self->priv->pixbuf_area.width) {
-				dx = self->priv->pixbuf_area.width - new_selection.x;
+			if (new_selection.x + new_selection.width > self->priv->surface_area.width) {
+				dx = self->priv->surface_area.width - new_selection.x;
 				dy = IROUND (dx / self->priv->ratio);
 				new_selection.y = new_selection.y + new_selection.height - dy;
 				new_selection.width = dx;
 				new_selection.height = dy;
 			}
-			if (new_selection.y < self->priv->pixbuf_area.y) {
+			if (new_selection.y < self->priv->surface_area.y) {
 				dy = new_selection.y + new_selection.height;
 				dx = IROUND (dy * self->priv->ratio);
 				new_selection.y = new_selection.y + new_selection.height - dy;
 				new_selection.width = dx;
 				new_selection.height = dy;
 			}
-			if (new_selection.x + new_selection.width > self->priv->pixbuf_area.width) {
-				dx = self->priv->pixbuf_area.width - new_selection.x;
+			if (new_selection.x + new_selection.width > self->priv->surface_area.width) {
+				dx = self->priv->surface_area.width - new_selection.x;
 				dy = IROUND (dx / self->priv->ratio);
 				new_selection.y = new_selection.y + new_selection.height - dy;
 				new_selection.width = dx;
@@ -1248,7 +1248,7 @@ update_mouse_selection (GthImageSelector *self)
 			break;
 
 		case C_TOP_LEFT_AREA:
-			if (new_selection.x < self->priv->pixbuf_area.y) {
+			if (new_selection.x < self->priv->surface_area.y) {
 				dx = new_selection.x + new_selection.width;
 				dy = IROUND (dx / self->priv->ratio);
 				new_selection.x = new_selection.x + new_selection.width - dx;
@@ -1256,7 +1256,7 @@ update_mouse_selection (GthImageSelector *self)
 				new_selection.width = dx;
 				new_selection.height = dy;
 			}
-			if (new_selection.y < self->priv->pixbuf_area.y) {
+			if (new_selection.y < self->priv->surface_area.y) {
 				dy = new_selection.y + new_selection.height;
 				dx = IROUND (dy * self->priv->ratio);
 				new_selection.x = new_selection.x + new_selection.width - dx;
@@ -1264,7 +1264,7 @@ update_mouse_selection (GthImageSelector *self)
 				new_selection.width = dx;
 				new_selection.height = dy;
 			}
-			if (new_selection.x < self->priv->pixbuf_area.y) {
+			if (new_selection.x < self->priv->surface_area.y) {
 				dx = new_selection.x + new_selection.width;
 				dy = IROUND (dx / self->priv->ratio);
 				new_selection.x = new_selection.x + new_selection.width - dx;
@@ -1275,20 +1275,20 @@ update_mouse_selection (GthImageSelector *self)
 			break;
 
 		case C_BOTTOM_RIGHT_AREA:
-			if (new_selection.x + new_selection.width > self->priv->pixbuf_area.width) {
-				dx = self->priv->pixbuf_area.width - new_selection.x;
+			if (new_selection.x + new_selection.width > self->priv->surface_area.width) {
+				dx = self->priv->surface_area.width - new_selection.x;
 				dy = IROUND (dx / self->priv->ratio);
 				new_selection.width = dx;
 				new_selection.height = dy;
 			}
-			if (new_selection.y + new_selection.height > self->priv->pixbuf_area.height) {
-				dy = self->priv->pixbuf_area.height - new_selection.y;
+			if (new_selection.y + new_selection.height > self->priv->surface_area.height) {
+				dy = self->priv->surface_area.height - new_selection.y;
 				dx = IROUND (dy * self->priv->ratio);
 				new_selection.width = dx;
 				new_selection.height = dy;
 			}
-			if (new_selection.x + new_selection.width > self->priv->pixbuf_area.width) {
-				dx = self->priv->pixbuf_area.width - new_selection.x;
+			if (new_selection.x + new_selection.width > self->priv->surface_area.width) {
+				dx = self->priv->surface_area.width - new_selection.x;
 				dy = IROUND (dx / self->priv->ratio);
 				new_selection.width = dx;
 				new_selection.height = dy;
@@ -1296,14 +1296,14 @@ update_mouse_selection (GthImageSelector *self)
 			break;
 
 		case C_BOTTOM_AREA:
-			if (new_selection.y + new_selection.height > self->priv->pixbuf_area.height) {
-				dy = self->priv->pixbuf_area.height - new_selection.y;
+			if (new_selection.y + new_selection.height > self->priv->surface_area.height) {
+				dy = self->priv->surface_area.height - new_selection.y;
 				dx = IROUND (dy * self->priv->ratio);
 				new_selection.width = dx;
 				new_selection.height = dy;
 			}
-			if (new_selection.x + new_selection.width > self->priv->pixbuf_area.width) {
-				dx = self->priv->pixbuf_area.width - new_selection.x;
+			if (new_selection.x + new_selection.width > self->priv->surface_area.width) {
+				dx = self->priv->surface_area.width - new_selection.x;
 				dy = IROUND (dx / self->priv->ratio);
 				new_selection.width = dx;
 				new_selection.height = dy;
@@ -1311,15 +1311,15 @@ update_mouse_selection (GthImageSelector *self)
 			break;
 
 		case C_LEFT_AREA:
-			if (new_selection.x < self->priv->pixbuf_area.y) {
+			if (new_selection.x < self->priv->surface_area.y) {
 				dx = new_selection.x + new_selection.width;
 				dy = IROUND (dx / self->priv->ratio);
 				new_selection.x = new_selection.x + new_selection.width - dx;
 				new_selection.width = dx;
 				new_selection.height = dy;
 			}
-			if (new_selection.y + new_selection.height > self->priv->pixbuf_area.height) {
-				dy = self->priv->pixbuf_area.height - new_selection.y;
+			if (new_selection.y + new_selection.height > self->priv->surface_area.height) {
+				dy = self->priv->surface_area.height - new_selection.y;
 				dx = IROUND (dy * self->priv->ratio);
 				new_selection.x = new_selection.x + new_selection.width - dx;
 				new_selection.width = dx;
@@ -1328,21 +1328,21 @@ update_mouse_selection (GthImageSelector *self)
 			break;
 
 		case C_BOTTOM_LEFT_AREA:
-			if (new_selection.x < self->priv->pixbuf_area.y) {
+			if (new_selection.x < self->priv->surface_area.y) {
 				dx = new_selection.x + new_selection.width;
 				dy = IROUND (dx / self->priv->ratio);
 				new_selection.x = new_selection.x + new_selection.width - dx;
 				new_selection.width = dx;
 				new_selection.height = dy;
 			}
-			if (new_selection.y + new_selection.height > self->priv->pixbuf_area.height) {
-				dy = self->priv->pixbuf_area.height - new_selection.y;
+			if (new_selection.y + new_selection.height > self->priv->surface_area.height) {
+				dy = self->priv->surface_area.height - new_selection.y;
 				dx = IROUND (dy * self->priv->ratio);
 				new_selection.x = new_selection.x + new_selection.width - dx;
 				new_selection.width = dx;
 				new_selection.height = dy;
 			}
-			if (new_selection.x < self->priv->pixbuf_area.y) {
+			if (new_selection.x < self->priv->surface_area.y) {
 				dx = new_selection.x + new_selection.width;
 				dy = IROUND (dx / self->priv->ratio);
 				new_selection.x = new_selection.x + new_selection.width - dx;
@@ -1413,7 +1413,7 @@ gth_image_selector_motion_notify (GthImageViewerTool *base,
 	if (self->priv->type == GTH_SELECTOR_TYPE_POINT) {
 		x = selector_to_real (self, x - self->priv->viewer->image_area.x);
 		y = selector_to_real (self, y - self->priv->viewer->image_area.y);
-		if (point_in_rectangle (x, y, self->priv->pixbuf_area))
+		if (point_in_rectangle (x, y, self->priv->surface_area))
 			g_signal_emit (G_OBJECT (self), signals[MOTION_NOTIFY], 0, x, y);
 		return TRUE;
 	}
@@ -1501,18 +1501,18 @@ gth_image_selector_image_changed (GthImageViewerTool *base)
 {
 	GthImageSelector *self = GTH_IMAGE_SELECTOR (base);
 
-	_g_object_unref (self->priv->pixbuf);
-	self->priv->pixbuf = gth_image_viewer_get_current_pixbuf (self->priv->viewer);
+	_g_object_unref (self->priv->surface);
+	self->priv->surface = gth_image_viewer_get_current_image (self->priv->viewer);
 
-	if (self->priv->pixbuf == NULL) {
-		self->priv->pixbuf_area.width = 0;
-		self->priv->pixbuf_area.height = 0;
+	if (self->priv->surface == NULL) {
+		self->priv->surface_area.width = 0;
+		self->priv->surface_area.height = 0;
 		return;
 	}
 
-	self->priv->pixbuf = g_object_ref (self->priv->pixbuf);
-	self->priv->pixbuf_area.width = gdk_pixbuf_get_width (self->priv->pixbuf);
-	self->priv->pixbuf_area.height = gdk_pixbuf_get_height (self->priv->pixbuf);
+	self->priv->surface = cairo_surface_reference (self->priv->surface);
+	self->priv->surface_area.width = cairo_image_surface_get_width (self->priv->surface);
+	self->priv->surface_area.height = cairo_image_surface_get_height (self->priv->surface);
 
 	init_selection (self);
 }
@@ -1552,7 +1552,7 @@ gth_image_selector_finalize (GObject *object)
 	g_return_if_fail (GTH_IS_IMAGE_SELECTOR (object));
 
 	self = (GthImageSelector *) object;
-	_g_object_unref (self->priv->pixbuf);
+	cairo_surface_destroy (self->priv->surface);
 
 	/* Chain up */
 	G_OBJECT_CLASS (parent_class)->finalize (object);
@@ -1762,8 +1762,8 @@ gth_image_selector_get_selection (GthImageSelector *self,
 {
 	selection->x = MAX (self->priv->selection.x, 0);
 	selection->y = MAX (self->priv->selection.y, 0);
-	selection->width = MIN (self->priv->selection.width, self->priv->pixbuf_area.width - self->priv->selection.x);
-	selection->height = MIN (self->priv->selection.height, self->priv->pixbuf_area.height - self->priv->selection.y);
+	selection->width = MIN (self->priv->selection.width, self->priv->surface_area.width - self->priv->selection.x);
+	selection->height = MIN (self->priv->selection.height, self->priv->surface_area.height - self->priv->selection.y);
 }
 
 
@@ -1877,7 +1877,7 @@ gth_image_selector_center (GthImageSelector *self)
 	GdkRectangle new_selection;
 
 	new_selection = self->priv->selection;
-	new_selection.x = (self->priv->pixbuf_area.width - new_selection.width) / 2;
-	new_selection.y = (self->priv->pixbuf_area.height - new_selection.height) / 2;
+	new_selection.x = (self->priv->surface_area.width - new_selection.width) / 2;
+	new_selection.y = (self->priv->surface_area.height - new_selection.height) / 2;
 	check_and_set_new_selection (self, new_selection);
 }
diff --git a/gthumb/gth-image-viewer.c b/gthumb/gth-image-viewer.c
index 662d657..8300d3e 100644
--- a/gthumb/gth-image-viewer.c
+++ b/gthumb/gth-image-viewer.c
@@ -3,7 +3,7 @@
 /*
  *  GThumb
  *
- *  Copyright (C) 2001-2009 Free Software Foundation, Inc.
+ *  Copyright (C) 2001-2011 Free Software Foundation, Inc.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -25,11 +25,13 @@
 #include <glib/gi18n.h>
 #include <gdk/gdkkeysyms.h>
 #include <gtk/gtk.h>
+#include "cairo-utils.h"
 #include "gth-enum-types.h"
 #include "gth-image-dragger.h"
 #include "gth-image-viewer.h"
 #include "gth-marshal.h"
 #include "glib-utils.h"
+#include "pixbuf-utils.h"
 
 #define COLOR_GRAY_00   0x00000000
 #define COLOR_GRAY_33   0x00333333
@@ -60,7 +62,7 @@ enum {
 
 
 struct _GthImageViewerPrivate {
-	GdkPixbuf              *pixbuf;
+	cairo_surface_t        *surface;
 	GdkPixbufAnimation     *animation;
 	int                     original_width;
 	int                     original_height;
@@ -68,6 +70,8 @@ struct _GthImageViewerPrivate {
 	GdkPixbufAnimationIter *iter;
 	GTimeVal                time;               /* Timer used to get the current frame. */
 	guint                   anim_id;
+	cairo_surface_t        *iter_surface;
+	GdkPixbufAnimationIter *last_iter;
 
 	gboolean                is_animation;
 	gboolean                play_animation;
@@ -103,12 +107,6 @@ struct _GthImageViewerPrivate {
 	gboolean                double_click;
 	gboolean                just_focused;
 
-	GdkPixbuf              *paint_pixbuf;
-	int                     paint_max_width;
-	int                     paint_max_height;
-	int                     paint_bps;
-	GdkColorspace           paint_color_space;
-
 	gboolean                black_bg;
 
 	gboolean                skip_zoom_change;
@@ -170,8 +168,8 @@ gth_image_viewer_finalize (GObject *object)
 
 	_g_clear_object (&self->priv->animation);
 	_g_clear_object (&self->priv->iter);
-	_g_clear_object (&self->priv->pixbuf);
-	_g_clear_object (&self->priv->paint_pixbuf);
+	_cairo_clear_surface (&self->priv->iter_surface);
+	_cairo_clear_surface (&self->priv->surface);
 
 	G_OBJECT_CLASS (parent_class)->finalize (object);
 }
@@ -218,7 +216,7 @@ _gth_image_viewer_get_zoomed_size (GthImageViewer *self,
 		 	 	   int            *width,
 		 	 	   int            *height)
 {
-	if (gth_image_viewer_get_current_pixbuf (self) == NULL) {
+	if (gth_image_viewer_get_current_image (self) == NULL) {
 		*width = 0;
 		*height = 0;
 	}
@@ -442,17 +440,14 @@ gth_image_viewer_unmap (GtkWidget *widget)
 static void
 zoom_to_fit (GthImageViewer *self)
 {
-	GdkPixbuf     *pixbuf;
-	GtkAllocation  allocation;
-	int            gdk_width;
-	int            gdk_height;
-	int            original_width;
-	int            original_height;
-	double         x_level;
-	double         y_level;
-	double         new_zoom_level;
-
-	pixbuf = gth_image_viewer_get_current_pixbuf (self);
+	GtkAllocation allocation;
+	int           gdk_width;
+	int           gdk_height;
+	int           original_width;
+	int           original_height;
+	double        x_level;
+	double        y_level;
+	double        new_zoom_level;
 
 	gtk_widget_get_allocation (GTK_WIDGET (self), &allocation);
 	gdk_width = allocation.width - self->priv->frame_border2;
@@ -475,13 +470,11 @@ zoom_to_fit (GthImageViewer *self)
 static void
 zoom_to_fit_width (GthImageViewer *self)
 {
-	GdkPixbuf     *pixbuf;
-	GtkAllocation  allocation;
-	int            gdk_width;
-	int            original_width;
-	double         new_zoom_level;
+	GtkAllocation allocation;
+	int           gdk_width;
+	int           original_width;
+	double        new_zoom_level;
 
-	pixbuf = gth_image_viewer_get_current_pixbuf (self);
 	gtk_widget_get_allocation (GTK_WIDGET (self), &allocation);
 	gdk_width = allocation.width - self->priv->frame_border2;
 
@@ -501,12 +494,12 @@ static void
 gth_image_viewer_size_allocate (GtkWidget     *widget,
 				GtkAllocation *allocation)
 {
-	GthImageViewer *self;
-	int             gdk_width;
-	int             gdk_height;
-	int             original_width;
-	int             original_height;
-	GdkPixbuf      *current_pixbuf;
+	GthImageViewer  *self;
+	int              gdk_width;
+	int              gdk_height;
+	int              original_width;
+	int              original_height;
+	cairo_surface_t *current_image;
 
 	self = GTH_IMAGE_VIEWER (widget);
 
@@ -518,13 +511,13 @@ gth_image_viewer_size_allocate (GtkWidget     *widget,
 	if ((gdk_width < 0) || (gdk_height < 0))
 		return;
 
-	current_pixbuf = gth_image_viewer_get_current_pixbuf (self);
+	current_image = gth_image_viewer_get_current_image (self);
 
 	gth_image_viewer_get_original_size (self, &original_width, &original_height);
 
 	/* If a fit type is active update the zoom level. */
 
-	if (! self->priv->is_void && (current_pixbuf != NULL)) {
+	if (! self->priv->is_void && (current_image != NULL)) {
 		switch (self->priv->fit) {
 		case GTH_FIT_SIZE:
 			zoom_to_fit (self);
@@ -563,7 +556,7 @@ gth_image_viewer_size_allocate (GtkWidget     *widget,
 
 	/* Check whether the offset is still valid. */
 
-	if (current_pixbuf != NULL) {
+	if (current_image != NULL) {
 		int width;
 		int height;
 
@@ -973,7 +966,7 @@ scroll_to (GthImageViewer *self,
 
 	g_return_if_fail (self != NULL);
 
-	if (gth_image_viewer_get_current_pixbuf (self) == NULL)
+	if (gth_image_viewer_get_current_image (self) == NULL)
 		return;
 
 	_gth_image_viewer_get_zoomed_size (self, &width, &height);
@@ -1604,6 +1597,8 @@ gth_image_viewer_instance_init (GthImageViewer *self)
 
 	self->priv->anim_id = 0;
 	self->priv->iter = NULL;
+	self->priv->last_iter = NULL;
+	self->priv->iter_surface = NULL;
 
 	self->priv->enable_zoom_with_keys = TRUE;
 	self->priv->zoom_level = 1.0;
@@ -1624,12 +1619,6 @@ gth_image_viewer_instance_init (GthImageViewer *self)
 
 	self->priv->black_bg = FALSE;
 
-	self->priv->paint_pixbuf = NULL;
-	self->priv->paint_max_width = 0;
-	self->priv->paint_max_height = 0;
-	self->priv->paint_bps = 0;
-	self->priv->paint_color_space = GDK_COLORSPACE_RGB;
-
 	self->priv->cursor = NULL;
 	self->priv->cursor_void = NULL;
 
@@ -1699,19 +1688,19 @@ _gth_image_viewer_set_original_size (GthImageViewer *self,
 				     int             original_width,
 				     int             original_height)
 {
-	GdkPixbuf *pixbuf;
+	cairo_surface_t *image;
 
-	pixbuf = gth_image_viewer_get_current_pixbuf (self);
+	image = gth_image_viewer_get_current_image (self);
 
 	if (original_width > 0)
 		self->priv->original_width = original_width;
 	else
-		self->priv->original_width = (pixbuf != NULL) ? gdk_pixbuf_get_width (pixbuf) : 0;
+		self->priv->original_width = (image != NULL) ? cairo_image_surface_get_width (image) : 0;
 
 	if (original_height > 0)
 		self->priv->original_height = original_height;
 	else
-		self->priv->original_height = (pixbuf != NULL) ? gdk_pixbuf_get_height (pixbuf) : 0;
+		self->priv->original_height = (image != NULL) ? cairo_image_surface_get_height (image) : 0;
 }
 
 
@@ -1773,7 +1762,7 @@ _set_animation (GthImageViewer     *self,
 {
 	g_return_if_fail (self != NULL);
 
-	_g_clear_object (&self->priv->pixbuf);
+	_cairo_clear_surface (&self->priv->surface);
 
 	_g_object_unref (self->priv->animation);
 	self->priv->animation = _g_object_ref (animation);
@@ -1816,14 +1805,31 @@ gth_image_viewer_set_pixbuf (GthImageViewer *self,
 			     int             original_width,
 			     int             original_height)
 {
+	cairo_surface_t *surface;
+
+	g_return_if_fail (self != NULL);
+
+	surface = _cairo_image_surface_create_from_pixbuf (pixbuf);
+	gth_image_viewer_set_surface (self, surface, original_width, original_height);
+
+	cairo_surface_destroy (surface);
+}
+
+
+void
+gth_image_viewer_set_surface (GthImageViewer  *self,
+			      cairo_surface_t *surface,
+			      int              original_width,
+			      int              original_height)
+{
 	g_return_if_fail (self != NULL);
 
 	_g_clear_object (&self->priv->animation);
 	_g_clear_object (&self->priv->iter);
 
-	_g_object_unref (self->priv->pixbuf);
-	self->priv->pixbuf = _g_object_ref (pixbuf);
-	self->priv->is_void = (self->priv->pixbuf == NULL);
+	cairo_surface_destroy (self->priv->surface);
+	self->priv->surface = cairo_surface_reference (surface);
+	self->priv->is_void = (self->priv->surface == NULL);
 	self->priv->is_animation = FALSE;
 	_gth_image_viewer_set_original_size (self, original_width, original_height);
 
@@ -1836,7 +1842,7 @@ gth_image_viewer_set_void (GthImageViewer *self)
 {
 	g_return_if_fail (self != NULL);
 
-	_g_clear_object (&self->priv->pixbuf);
+	_cairo_clear_surface (&self->priv->surface);
 	_g_clear_object (&self->priv->animation);
 	_g_clear_object (&self->priv->iter);
 
@@ -1925,13 +1931,13 @@ gth_image_viewer_remove_painter (GthImageViewer          *self,
 int
 gth_image_viewer_get_image_width (GthImageViewer *self)
 {
-	GdkPixbuf *pixbuf;
+	cairo_surface_t *image;
 
 	g_return_val_if_fail (self != NULL, 0);
 
-	pixbuf = gth_image_viewer_get_current_pixbuf (self);
-	if (pixbuf != NULL)
-		return gdk_pixbuf_get_width (pixbuf);
+	image = gth_image_viewer_get_current_image (self);
+	if (image != NULL)
+		return cairo_image_surface_get_width (image);
 
 	return 0;
 }
@@ -1940,13 +1946,13 @@ gth_image_viewer_get_image_width (GthImageViewer *self)
 int
 gth_image_viewer_get_image_height (GthImageViewer *self)
 {
-	GdkPixbuf *pixbuf;
+	cairo_surface_t *image;
 
 	g_return_val_if_fail (self != NULL, 0);
 
-	pixbuf = gth_image_viewer_get_current_pixbuf (self);
-	if (pixbuf != NULL)
-		return gdk_pixbuf_get_height (pixbuf);
+	image = gth_image_viewer_get_current_image (self);
+	if (image != NULL)
+		return cairo_image_surface_get_height (image);
 
 	return 0;
 }
@@ -1966,21 +1972,6 @@ gth_image_viewer_get_original_size (GthImageViewer *self,
 }
 
 
-int
-gth_image_viewer_get_image_bps (GthImageViewer *self)
-{
-	GdkPixbuf *pixbuf;
-
-	g_return_val_if_fail (self != NULL, 0);
-
-	pixbuf = gth_image_viewer_get_current_pixbuf (self);
-	if (pixbuf != NULL)
-		return gdk_pixbuf_get_bits_per_sample (pixbuf);
-
-	return 0;
-}
-
-
 gboolean
 gth_image_viewer_get_has_alpha (GthImageViewer *self)
 {
@@ -2004,8 +1995,8 @@ gth_image_viewer_get_current_pixbuf (GthImageViewer *self)
 	if (self->priv->is_void)
 		return NULL;
 
-	if (self->priv->pixbuf != NULL)
-		return self->priv->pixbuf;
+	if (self->priv->surface != NULL)
+		return _gdk_pixbuf_new_from_cairo_surface (self->priv->surface);
 
 	if (self->priv->iter != NULL)
 		return gdk_pixbuf_animation_iter_get_pixbuf (self->priv->iter);
@@ -2014,6 +2005,30 @@ gth_image_viewer_get_current_pixbuf (GthImageViewer *self)
 }
 
 
+cairo_surface_t *
+gth_image_viewer_get_current_image (GthImageViewer *self)
+{
+	g_return_val_if_fail (self != NULL, NULL);
+
+	if (self->priv->is_void)
+		return NULL;
+
+	if (self->priv->surface != NULL)
+		return self->priv->surface;
+
+	if (self->priv->iter != NULL) {
+		if ((self->priv->iter_surface == NULL) || (self->priv->iter != self->priv->last_iter)) {
+			self->priv->last_iter = self->priv->iter;
+			_cairo_clear_surface (&self->priv->iter_surface);
+			self->priv->iter_surface = _cairo_image_surface_create_from_pixbuf (gdk_pixbuf_animation_iter_get_pixbuf (self->priv->iter));
+		}
+		return self->priv->iter_surface;
+	}
+
+	return NULL;
+}
+
+
 void
 gth_image_viewer_start_animation (GthImageViewer *self)
 {
@@ -2120,7 +2135,7 @@ gth_image_viewer_get_zoom_change (GthImageViewer *self)
 void
 gth_image_viewer_zoom_in (GthImageViewer *self)
 {
-	if (gth_image_viewer_get_current_pixbuf (self) == NULL)
+	if (gth_image_viewer_get_current_image (self) == NULL)
 		return;
 	gth_image_viewer_set_zoom (self, get_next_zoom (self->priv->zoom_level));
 }
@@ -2129,7 +2144,7 @@ gth_image_viewer_zoom_in (GthImageViewer *self)
 void
 gth_image_viewer_zoom_out (GthImageViewer *self)
 {
-	if (gth_image_viewer_get_current_pixbuf (self) == NULL)
+	if (gth_image_viewer_get_current_image (self) == NULL)
 		return;
 	gth_image_viewer_set_zoom (self, get_prev_zoom (self->priv->zoom_level));
 }
@@ -2352,7 +2367,7 @@ gth_image_viewer_scroll_to (GthImageViewer *self,
 {
 	g_return_if_fail (self != NULL);
 
-	if (gth_image_viewer_get_current_pixbuf (self) == NULL)
+	if (gth_image_viewer_get_current_image (self) == NULL)
 		return;
 
 	scroll_to (self, &x_offset, &y_offset);
@@ -2513,91 +2528,62 @@ gth_image_viewer_is_frame_visible (GthImageViewer *self)
 
 
 void
-gth_image_viewer_paint (GthImageViewer *self,
-			cairo_t        *cr,
-			GdkPixbuf      *pixbuf,
-			int             src_x,
-			int             src_y,
-			int             dest_x,
-			int             dest_y,
-			int             width,
-			int             height,
-			int             interp_type)
-{
-	int           original_width;
-	double        zoom_level;
-	int           bits_per_sample;
-	GdkColorspace color_space;
+gth_image_viewer_paint (GthImageViewer  *self,
+			cairo_t         *cr,
+			cairo_surface_t *surface,
+			int              src_x,
+			int              src_y,
+			int              dest_x,
+			int              dest_y,
+			int              width,
+			int              height,
+			cairo_filter_t   filter)
+{
+	int    original_width;
+	double zoom_level;
+	double src_dx;
+	double src_dy;
+	double dest_dx;
+	double dest_dy;
+	double dwidth;
+	double dheight;
+
+	cairo_save (cr);
 
 	gth_image_viewer_get_original_size (self, &original_width, NULL);
-	zoom_level = self->priv->zoom_level * ((double) original_width / gdk_pixbuf_get_width (pixbuf));
+	zoom_level = self->priv->zoom_level * ((double) original_width / cairo_image_surface_get_width (surface));
+	src_dx = (double) src_x / zoom_level;
+	src_dy = (double) src_y / zoom_level;
+	dest_dx = (double) dest_x / zoom_level;
+	dest_dy = (double) dest_y / zoom_level;
+	dwidth = (double) width / zoom_level;
+	dheight = (double) height / zoom_level;
 
-	color_space = gdk_pixbuf_get_colorspace (pixbuf);
-	bits_per_sample = gdk_pixbuf_get_bits_per_sample (pixbuf);
+	cairo_scale (cr, zoom_level, zoom_level);
 
-	if ((self->priv->paint_pixbuf == NULL)
-	    || (self->priv->paint_max_width < width)
-	    || (self->priv->paint_max_height < height)
-	    || (self->priv->paint_bps != bits_per_sample)
-	    || (self->priv->paint_color_space != color_space))
-	{
-		if (self->priv->paint_pixbuf != NULL)
-			g_object_unref (self->priv->paint_pixbuf);
-		self->priv->paint_pixbuf = gdk_pixbuf_new (color_space,
-							   FALSE,
-							   bits_per_sample,
-							   width,
-							   height);
-		g_return_if_fail (self->priv->paint_pixbuf != NULL);
-
-		self->priv->paint_max_width = width;
-		self->priv->paint_max_height = height;
-		self->priv->paint_color_space = color_space;
-		self->priv->paint_bps = bits_per_sample;
-	}
+	/* FIXME: paint the background for images with a transparency */
 
-	if (gdk_pixbuf_get_has_alpha (pixbuf))
-		gdk_pixbuf_composite_color (pixbuf,
-					    self->priv->paint_pixbuf,
-					    0, 0,
-					    width, height,
-					    (double) -src_x,
-					    (double) -src_y,
-					    zoom_level,
-					    zoom_level,
-					    interp_type,
-					    255,
-					    src_x, src_y,
-					    self->priv->check_size,
-					    self->priv->check_color1,
-					    self->priv->check_color2);
-	else
-		gdk_pixbuf_scale (pixbuf,
-				  self->priv->paint_pixbuf,
-				  0, 0,
-				  width, height,
-				  (double) -src_x,
-				  (double) -src_y,
-				  zoom_level,
-				  zoom_level,
-				  interp_type);
+	/* g_print ("src: (%d, %d) -- dest: (%d, %d) [%d, %d]\n", src_x, src_y, dest_x, dest_y, width, height); */
 
-	cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
-	gdk_cairo_set_source_pixbuf (cr, self->priv->paint_pixbuf, dest_x, dest_y);
-  	cairo_rectangle (cr, dest_x, dest_y, width, height);
+	cairo_set_source_surface (cr, surface, dest_dx - src_dx, dest_dy - src_dy);
+	cairo_pattern_set_filter (cairo_get_source (cr), filter);
+	cairo_rectangle (cr, dest_dx, dest_dy, dwidth, dheight);
+  	cairo_clip_preserve (cr);
   	cairo_fill (cr);
+
+  	cairo_restore (cr);
 }
 
 
 void
-gth_image_viewer_paint_region (GthImageViewer *self,
-			       cairo_t        *cr,
-			       GdkPixbuf      *pixbuf,
-			       int             src_x,
-			       int             src_y,
-			       GdkRectangle   *pixbuf_area,
-			       GdkRegion      *region,
-			       int             interp_type)
+gth_image_viewer_paint_region (GthImageViewer  *self,
+			       cairo_t         *cr,
+			       cairo_surface_t *surface,
+			       int              src_x,
+			       int              src_y,
+			       GdkRectangle    *pixbuf_area,
+			       GdkRegion       *region,
+			       cairo_filter_t   filter)
 {
 	GdkRectangle *rects;
 	int           n_rects;
@@ -2615,14 +2601,14 @@ gth_image_viewer_paint_region (GthImageViewer *self,
 		if (gdk_rectangle_intersect (pixbuf_area, &rects[i], &paint_area))
 			gth_image_viewer_paint (self,
 						cr,
-						pixbuf,
+						surface,
 						src_x + paint_area.x,
 						src_y + paint_area.y,
 						paint_area.x,
 						paint_area.y,
 						paint_area.width,
 						paint_area.height,
-						interp_type);
+						filter);
 	}
 
 	cairo_restore (cr);
diff --git a/gthumb/gth-image-viewer.h b/gthumb/gth-image-viewer.h
index 253849b..a57d641 100644
--- a/gthumb/gth-image-viewer.h
+++ b/gthumb/gth-image-viewer.h
@@ -161,6 +161,10 @@ void           gth_image_viewer_set_pixbuf               (GthImageViewer     *vi
 							  GdkPixbuf          *pixbuf,
 							  int                 original_width,
 							  int                 original_height);
+void           gth_image_viewer_set_surface              (GthImageViewer     *viewer,
+							  cairo_surface_t    *image,
+							  int                 original_width,
+							  int                 original_height);
 void           gth_image_viewer_set_better_quality       (GthImageViewer     *viewer,
 							  GdkPixbufAnimation *animation,
 							  int                 original_width,
@@ -181,9 +185,10 @@ void           gth_image_viewer_remove_painter           (GthImageViewer     *vi
 
 int            gth_image_viewer_get_image_width          (GthImageViewer     *viewer);
 int            gth_image_viewer_get_image_height         (GthImageViewer     *viewer);
-int            gth_image_viewer_get_image_bps            (GthImageViewer     *viewer);
 gboolean       gth_image_viewer_get_has_alpha            (GthImageViewer     *viewer);
 GdkPixbuf *    gth_image_viewer_get_current_pixbuf       (GthImageViewer     *viewer);
+cairo_surface_t *
+	       gth_image_viewer_get_current_image      (GthImageViewer     *viewer);
 void           gth_image_viewer_get_original_size        (GthImageViewer     *viewer,
 				    	    	    	  int                *width,
 				    	    	    	  int                *height);
diff --git a/gthumb/pixbuf-utils.c b/gthumb/pixbuf-utils.c
index e53b3b2..6310a6c 100644
--- a/gthumb/pixbuf-utils.c
+++ b/gthumb/pixbuf-utils.c
@@ -58,22 +58,27 @@ _gdk_pixbuf_new_compatible (GdkPixbuf *src)
 }
 
 
+GdkPixbuf *
+_gdk_pixbuf_new_from_cairo_context (cairo_t *cr)
+{
+	return _gdk_pixbuf_new_from_cairo_surface (cairo_get_target (cr));
+}
+
+
 /* Taken from http://www.gtkforums.com/about5204.html
  * Author: tadeboro */
 GdkPixbuf *
-_gdk_pixbuf_new_from_cairo_surface (cairo_t *cr)
+_gdk_pixbuf_new_from_cairo_surface (cairo_surface_t *surface)
 {
-	cairo_surface_t *surface;
-	int              width;
-	int              height;
-	int              s_stride;
-	unsigned char   *s_pixels;
-	GdkPixbuf       *pixbuf;
-	int              p_stride;
-	guchar          *p_pixels;
-	int              p_n_channels;
-
-	surface = cairo_get_target (cr);
+	int            width;
+	int            height;
+	int            s_stride;
+	unsigned char *s_pixels;
+	GdkPixbuf     *pixbuf;
+	int            p_stride;
+	guchar        *p_pixels;
+	int            p_n_channels;
+
 	if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)
 		return NULL;
 
diff --git a/gthumb/pixbuf-utils.h b/gthumb/pixbuf-utils.h
index 116fd35..08014e4 100644
--- a/gthumb/pixbuf-utils.h
+++ b/gthumb/pixbuf-utils.h
@@ -33,7 +33,8 @@ G_BEGIN_DECLS
 GdkPixbuf * _gdk_pixbuf_new_void               (int              width,
 					        int              height);
 GdkPixbuf *  _gdk_pixbuf_new_compatible        (GdkPixbuf       *src);
-GdkPixbuf * _gdk_pixbuf_new_from_cairo_surface (cairo_t         *cr);
+GdkPixbuf * _gdk_pixbuf_new_from_cairo_context (cairo_t         *cr);
+GdkPixbuf * _gdk_pixbuf_new_from_cairo_surface (cairo_surface_t *surface);
 GdkPixbuf * _gdk_pixbuf_scale_simple_safe      (const GdkPixbuf *src,
 					        int              dest_width,
 					        int              dest_height,



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