[gthumb: 32/129] flip, mirror, rotate left and right: use the cairo_surface instead of a GdkPixbuf



commit 9c5689aac673fbae964cadc577b31a9dcafc9b26
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Sat Apr 16 14:14:42 2011 +0200

    flip, mirror, rotate left and right: use the cairo_surface instead of a GdkPixbuf

 extensions/file_tools/gth-file-tool-flip.c         |   21 +-
 extensions/file_tools/gth-file-tool-mirror.c       |   21 +-
 extensions/file_tools/gth-file-tool-rotate-left.c  |   21 +-
 extensions/file_tools/gth-file-tool-rotate-right.c |   21 +-
 gthumb/cairo-utils.c                               |  252 ++++++++++++++++++++
 gthumb/cairo-utils.h                               |    9 +
 6 files changed, 301 insertions(+), 44 deletions(-)
---
diff --git a/extensions/file_tools/gth-file-tool-flip.c b/extensions/file_tools/gth-file-tool-flip.c
index b2cb0b1..c74e3d3 100644
--- a/extensions/file_tools/gth-file-tool-flip.c
+++ b/extensions/file_tools/gth-file-tool-flip.c
@@ -29,11 +29,11 @@
 static void
 gth_file_tool_flip_activate (GthFileTool *base)
 {
-	GtkWidget *window;
-	GtkWidget *viewer_page;
-	GtkWidget *viewer;
-	GdkPixbuf *src_pixbuf;
-	GdkPixbuf *dest_pixbuf;
+	GtkWidget       *window;
+	GtkWidget       *viewer_page;
+	GtkWidget       *viewer;
+	cairo_surface_t *old_image;
+	cairo_surface_t *new_image;
 
 	window = gth_file_tool_get_window (base);
 	viewer_page = gth_browser_get_viewer_page (GTH_BROWSER (window));
@@ -41,15 +41,14 @@ gth_file_tool_flip_activate (GthFileTool *base)
 		return;
 
 	viewer = gth_image_viewer_page_get_image_viewer (GTH_IMAGE_VIEWER_PAGE (viewer_page));
-	src_pixbuf = gth_image_viewer_get_current_pixbuf (GTH_IMAGE_VIEWER (viewer)); /* FIXME: use the cairo_surface directly */
-	if (src_pixbuf == NULL)
+	old_image = gth_image_viewer_get_current_image (GTH_IMAGE_VIEWER (viewer));
+	if (old_image == NULL)
 		return;
 
-	dest_pixbuf = _gdk_pixbuf_transform (src_pixbuf, GTH_TRANSFORM_FLIP_V);
-	gth_image_viewer_page_set_pixbuf (GTH_IMAGE_VIEWER_PAGE (viewer_page), dest_pixbuf, TRUE);
+	new_image = _cairo_image_surface_transform (old_image, GTH_TRANSFORM_FLIP_V);
+	gth_image_viewer_page_set_image (GTH_IMAGE_VIEWER_PAGE (viewer_page), new_image, TRUE);
 
-	g_object_unref (dest_pixbuf);
-	g_object_unref (src_pixbuf);
+	cairo_surface_destroy (new_image);
 }
 
 
diff --git a/extensions/file_tools/gth-file-tool-mirror.c b/extensions/file_tools/gth-file-tool-mirror.c
index 454caa5..fa0fe44 100644
--- a/extensions/file_tools/gth-file-tool-mirror.c
+++ b/extensions/file_tools/gth-file-tool-mirror.c
@@ -29,11 +29,11 @@
 static void
 gth_file_tool_mirror_activate (GthFileTool *base)
 {
-	GtkWidget *window;
-	GtkWidget *viewer_page;
-	GtkWidget *viewer;
-	GdkPixbuf *src_pixbuf;
-	GdkPixbuf *dest_pixbuf;
+	GtkWidget       *window;
+	GtkWidget       *viewer_page;
+	GtkWidget       *viewer;
+	cairo_surface_t *old_image;
+	cairo_surface_t *new_image;
 
 	window = gth_file_tool_get_window (base);
 	viewer_page = gth_browser_get_viewer_page (GTH_BROWSER (window));
@@ -41,15 +41,14 @@ gth_file_tool_mirror_activate (GthFileTool *base)
 		return;
 
 	viewer = gth_image_viewer_page_get_image_viewer (GTH_IMAGE_VIEWER_PAGE (viewer_page));
-	src_pixbuf = gth_image_viewer_get_current_pixbuf (GTH_IMAGE_VIEWER (viewer));
-	if (src_pixbuf == NULL)
+	old_image = gth_image_viewer_get_current_image (GTH_IMAGE_VIEWER (viewer));
+	if (old_image == NULL)
 		return;
 
-	dest_pixbuf = _gdk_pixbuf_transform (src_pixbuf, GTH_TRANSFORM_FLIP_H);
-	gth_image_viewer_page_set_pixbuf (GTH_IMAGE_VIEWER_PAGE (viewer_page), dest_pixbuf, TRUE);
+	new_image = _cairo_image_surface_transform (old_image, GTH_TRANSFORM_FLIP_H);
+	gth_image_viewer_page_set_image (GTH_IMAGE_VIEWER_PAGE (viewer_page), new_image, TRUE);
 
-	g_object_unref (dest_pixbuf);
-	g_object_unref (src_pixbuf);
+	cairo_surface_destroy (new_image);
 }
 
 
diff --git a/extensions/file_tools/gth-file-tool-rotate-left.c b/extensions/file_tools/gth-file-tool-rotate-left.c
index 596fd8f..517b6d8 100644
--- a/extensions/file_tools/gth-file-tool-rotate-left.c
+++ b/extensions/file_tools/gth-file-tool-rotate-left.c
@@ -29,11 +29,11 @@
 static void
 gth_file_tool_rotate_left_activate (GthFileTool *base)
 {
-	GtkWidget *window;
-	GtkWidget *viewer_page;
-	GtkWidget *viewer;
-	GdkPixbuf *src_pixbuf;
-	GdkPixbuf *dest_pixbuf;
+	GtkWidget       *window;
+	GtkWidget       *viewer_page;
+	GtkWidget       *viewer;
+	cairo_surface_t *old_image;
+	cairo_surface_t *new_image;
 
 	window = gth_file_tool_get_window (base);
 	viewer_page = gth_browser_get_viewer_page (GTH_BROWSER (window));
@@ -41,15 +41,14 @@ gth_file_tool_rotate_left_activate (GthFileTool *base)
 		return;
 
 	viewer = gth_image_viewer_page_get_image_viewer (GTH_IMAGE_VIEWER_PAGE (viewer_page));
-	src_pixbuf = gth_image_viewer_get_current_pixbuf (GTH_IMAGE_VIEWER (viewer));
-	if (src_pixbuf == NULL)
+	old_image = gth_image_viewer_get_current_image (GTH_IMAGE_VIEWER (viewer));
+	if (old_image == NULL)
 		return;
 
-	dest_pixbuf = _gdk_pixbuf_transform (src_pixbuf, GTH_TRANSFORM_ROTATE_270);
-	gth_image_viewer_page_set_pixbuf (GTH_IMAGE_VIEWER_PAGE (viewer_page), dest_pixbuf, TRUE);
+	new_image = _cairo_image_surface_transform (old_image, GTH_TRANSFORM_ROTATE_270);
+	gth_image_viewer_page_set_image (GTH_IMAGE_VIEWER_PAGE (viewer_page), new_image, TRUE);
 
-	g_object_unref (dest_pixbuf);
-	g_object_unref (src_pixbuf);
+	cairo_surface_destroy (new_image);
 }
 
 
diff --git a/extensions/file_tools/gth-file-tool-rotate-right.c b/extensions/file_tools/gth-file-tool-rotate-right.c
index 1e6bff6..99d71c7 100644
--- a/extensions/file_tools/gth-file-tool-rotate-right.c
+++ b/extensions/file_tools/gth-file-tool-rotate-right.c
@@ -29,11 +29,11 @@
 static void
 gth_file_tool_rotate_right_activate (GthFileTool *base)
 {
-	GtkWidget *window;
-	GtkWidget *viewer_page;
-	GtkWidget *viewer;
-	GdkPixbuf *src_pixbuf;
-	GdkPixbuf *dest_pixbuf;
+	GtkWidget       *window;
+	GtkWidget       *viewer_page;
+	GtkWidget       *viewer;
+	cairo_surface_t *old_image;
+	cairo_surface_t *new_image;
 
 	window = gth_file_tool_get_window (base);
 	viewer_page = gth_browser_get_viewer_page (GTH_BROWSER (window));
@@ -41,15 +41,14 @@ gth_file_tool_rotate_right_activate (GthFileTool *base)
 		return;
 
 	viewer = gth_image_viewer_page_get_image_viewer (GTH_IMAGE_VIEWER_PAGE (viewer_page));
-	src_pixbuf = gth_image_viewer_get_current_pixbuf (GTH_IMAGE_VIEWER (viewer));
-	if (src_pixbuf == NULL)
+	old_image = gth_image_viewer_get_current_image (GTH_IMAGE_VIEWER (viewer));
+	if (old_image == NULL)
 		return;
 
-	dest_pixbuf = _gdk_pixbuf_transform (src_pixbuf, GTH_TRANSFORM_ROTATE_90);
-	gth_image_viewer_page_set_pixbuf (GTH_IMAGE_VIEWER_PAGE (viewer_page), dest_pixbuf, TRUE);
+	new_image = _cairo_image_surface_transform (old_image, GTH_TRANSFORM_ROTATE_90);
+	gth_image_viewer_page_set_image (GTH_IMAGE_VIEWER_PAGE (viewer_page), new_image, TRUE);
 
-	g_object_unref (dest_pixbuf);
-	g_object_unref (src_pixbuf);
+	cairo_surface_destroy (new_image);
 }
 
 
diff --git a/gthumb/cairo-utils.c b/gthumb/cairo-utils.c
index 04b6d07..98c8e91 100644
--- a/gthumb/cairo-utils.c
+++ b/gthumb/cairo-utils.c
@@ -21,6 +21,7 @@
 
 #include <config.h>
 #include <math.h>
+#include <string.h>
 #include "cairo-utils.h"
 
 
@@ -30,6 +31,7 @@ typedef struct {
 
 
 static cairo_user_data_key_t surface_metadata_key;
+static cairo_user_data_key_t surface_pixels_key;
 
 
 static void
@@ -40,6 +42,13 @@ surface_metadata_free (void *data)
 }
 
 
+static void
+surface_pixels_free (void *data)
+{
+	g_free (data);
+}
+
+
 void
 _gdk_color_to_cairo_color (GdkColor      *g_color,
 			   cairo_color_t *c_color)
@@ -87,6 +96,90 @@ _cairo_image_surface_get_has_alpha (cairo_surface_t *surface)
 
 
 cairo_surface_t *
+_cairo_image_surface_copy (cairo_surface_t *surface)
+{
+	cairo_surface_t *result;
+	cairo_format_t   format;
+	int              width;
+	int              height;
+	int              stride;
+	unsigned char   *pixels;
+	cairo_status_t   status;
+
+	if (surface == NULL)
+		return NULL;
+
+	format = cairo_image_surface_get_format (surface);
+	width = cairo_image_surface_get_width (surface);
+	height = cairo_image_surface_get_height (surface);
+	stride = cairo_format_stride_for_width (format, width);
+	pixels = g_try_malloc (stride * height);
+        if (pixels == NULL)
+                return NULL;
+
+	result = cairo_image_surface_create_for_data (pixels, format, width, height, stride);
+	status = cairo_surface_status (result);
+	if (status != CAIRO_STATUS_SUCCESS) {
+		g_warning ("_cairo_image_surface_copy: could not create the surface: %s", cairo_status_to_string (status));
+		cairo_surface_destroy (result);
+		return NULL;
+	}
+
+	status = cairo_surface_set_user_data (result, &surface_pixels_key, pixels, surface_pixels_free);
+	if (status != CAIRO_STATUS_SUCCESS) {
+		g_warning ("_cairo_image_surface_copy: could not set the user data: %s", cairo_status_to_string (status));
+		cairo_surface_destroy (result);
+		return NULL;
+	}
+
+	return result;
+}
+
+
+cairo_surface_t *
+_cairo_image_surface_copy_subsurface (cairo_surface_t *source,
+				      int              src_x,
+				      int              src_y,
+				      int              width,
+				      int              height)
+{
+	cairo_surface_t *destination;
+	cairo_status_t   status;
+	int              source_stride;
+	int              destination_stride;
+	unsigned char   *p_source;
+	unsigned char   *p_destination;
+	int              row_size;
+
+	g_return_val_if_fail (source != NULL, NULL);
+	g_return_val_if_fail (src_x + width <= cairo_image_surface_get_width (source), NULL);
+	g_return_val_if_fail (src_y + height <= cairo_image_surface_get_height (source), NULL);
+
+	destination = cairo_image_surface_create (cairo_image_surface_get_format (source), width, height);
+	status = cairo_surface_status (destination);
+	if (status != CAIRO_STATUS_SUCCESS) {
+		g_warning ("_cairo_image_surface_copy_subsurface: could not create the surface: %s", cairo_status_to_string (status));
+		cairo_surface_destroy (destination);
+		return NULL;
+	}
+
+	source_stride = cairo_image_surface_get_stride (source);
+	destination_stride = cairo_image_surface_get_stride (destination);
+	p_source = cairo_image_surface_get_data (source) + (src_y * source_stride) + (src_x * 4);
+	p_destination = cairo_image_surface_get_data (destination);
+	row_size = width * 4;
+	while (height-- > 0) {
+		memcpy (p_destination, p_source, row_size);
+
+		p_source += source_stride;
+		p_destination += destination_stride;
+	}
+
+	return destination;
+}
+
+
+cairo_surface_t *
 _cairo_image_surface_create_from_pixbuf (GdkPixbuf *pixbuf)
 {
 	cairo_surface_t          *surface;
@@ -184,6 +277,165 @@ _cairo_image_surface_scale_to (cairo_surface_t *surface,
 }
 
 
+cairo_surface_t *
+_cairo_image_surface_transform (cairo_surface_t *source,
+				GthTransform     transform)
+{
+	cairo_surface_t *destination = NULL;
+	cairo_format_t   format;
+	int              width;
+	int              height;
+	int              source_stride;
+	int              destination_stride;
+	unsigned char   *p_source_line;
+	unsigned char   *p_destination_line;
+	unsigned char   *p_source;
+	unsigned char   *p_destination;
+	int              x;
+
+	if (source == NULL)
+		return NULL;
+
+	format = cairo_image_surface_get_format (source);
+	width = cairo_image_surface_get_width (source);
+	height = cairo_image_surface_get_height (source);
+	source_stride = cairo_image_surface_get_stride (source);
+
+	switch (transform) {
+	case GTH_TRANSFORM_NONE:
+		destination = _cairo_image_surface_copy (source);
+		break;
+
+	case GTH_TRANSFORM_FLIP_H:
+		destination = cairo_image_surface_create (format, width, height);
+		destination_stride = cairo_image_surface_get_stride (destination);
+		p_source_line = cairo_image_surface_get_data (source);
+		p_destination_line = cairo_image_surface_get_data (destination) + ((width - 1) * 4);
+		while (height-- > 0) {
+			p_source = p_source_line;
+			p_destination = p_destination_line;
+			for (x = 0; x < width; x++) {
+				memcpy (p_destination, p_source, 4);
+				p_source += 4;
+				p_destination -= 4;
+			}
+			p_source_line += source_stride;
+			p_destination_line += destination_stride;
+		}
+		break;
+
+	case GTH_TRANSFORM_ROTATE_180:
+		destination = cairo_image_surface_create (format, width, height);
+		destination_stride = cairo_image_surface_get_stride (destination);
+		p_source_line = cairo_image_surface_get_data (source);
+		p_destination_line = cairo_image_surface_get_data (destination) + ((height - 1) * destination_stride) + ((width - 1) * 4);
+		while (height-- > 0) {
+			p_source = p_source_line;
+			p_destination = p_destination_line;
+			for (x = 0; x < width; x++) {
+				memcpy (p_destination, p_source, 4);
+				p_source += 4;
+				p_destination -= 4;
+			}
+			p_source_line += source_stride;
+			p_destination_line -= destination_stride;
+		}
+		break;
+
+	case GTH_TRANSFORM_FLIP_V:
+		destination = cairo_image_surface_create (format, width, height);
+		destination_stride = cairo_image_surface_get_stride (destination);
+		g_return_val_if_fail (source_stride == destination_stride, NULL);
+		p_source_line = cairo_image_surface_get_data (source);
+		p_destination_line = cairo_image_surface_get_data (destination) + ((height - 1) * destination_stride);
+		while (height-- > 0) {
+			memcpy (p_destination_line, p_source_line, source_stride);
+			p_source_line += source_stride;
+			p_destination_line -= destination_stride;
+		}
+		break;
+
+	case GTH_TRANSFORM_TRANSPOSE:
+		destination = cairo_image_surface_create (format, height, width);
+		destination_stride = cairo_image_surface_get_stride (destination);
+		p_source_line = cairo_image_surface_get_data (source);
+		p_destination_line = cairo_image_surface_get_data (destination);
+		while (height-- > 0) {
+			p_source = p_source_line;
+			p_destination = p_destination_line;
+			for (x = 0; x < width; x++) {
+				memcpy (p_destination, p_source, 4);
+				p_source += 4;
+				p_destination += destination_stride;
+			}
+			p_source_line += source_stride;
+			p_destination_line += 4;
+		}
+		break;
+
+	case GTH_TRANSFORM_ROTATE_90:
+		destination = cairo_image_surface_create (format, height, width);
+		destination_stride = cairo_image_surface_get_stride (destination);
+		p_source_line = cairo_image_surface_get_data (source);
+		p_destination_line = cairo_image_surface_get_data (destination) + ((height - 1) * 4);
+		while (height-- > 0) {
+			p_source = p_source_line;
+			p_destination = p_destination_line;
+			for (x = 0; x < width; x++) {
+				memcpy (p_destination, p_source, 4);
+				p_source += 4;
+				p_destination += destination_stride;
+			}
+			p_source_line += source_stride;
+			p_destination_line -= 4;
+		}
+		break;
+
+	case GTH_TRANSFORM_TRANSVERSE:
+		destination = cairo_image_surface_create (format, height, width);
+		destination_stride = cairo_image_surface_get_stride (destination);
+		p_source_line = cairo_image_surface_get_data (source);
+		p_destination_line = cairo_image_surface_get_data (destination) + ((width - 1) * destination_stride) + ((height - 1) * 4);
+		while (height-- > 0) {
+			p_source = p_source_line;
+			p_destination = p_destination_line;
+			for (x = 0; x < width; x++) {
+				memcpy (p_destination, p_source, 4);
+				p_source += 4;
+				p_destination -= destination_stride;
+			}
+			p_source_line += source_stride;
+			p_destination_line -= 4;
+		}
+		break;
+
+	case GTH_TRANSFORM_ROTATE_270:
+		destination = cairo_image_surface_create (format, height, width);
+		destination_stride = cairo_image_surface_get_stride (destination);
+		p_source_line = cairo_image_surface_get_data (source);
+		p_destination_line = cairo_image_surface_get_data (destination) + ((width - 1) * destination_stride);
+		while (height-- > 0) {
+			p_source = p_source_line;
+			p_destination = p_destination_line;
+			for (x = 0; x < width; x++) {
+				memcpy (p_destination, p_source, 4);
+				p_source += 4;
+				p_destination -= destination_stride;
+			}
+			p_source_line += source_stride;
+			p_destination_line += 4;
+		}
+		break;
+
+	default:
+		g_warning ("_cairo_image_surface_transform: unknown transformation value %d", transform);
+		break;
+	}
+
+	return destination;
+}
+
+
 void
 _cairo_paint_full_gradient (cairo_surface_t *surface,
 			    GdkColor        *h_color1,
diff --git a/gthumb/cairo-utils.h b/gthumb/cairo-utils.h
index 8e8b551..a1f3d5c 100644
--- a/gthumb/cairo-utils.h
+++ b/gthumb/cairo-utils.h
@@ -26,6 +26,7 @@
 #include <gdk/gdk.h>
 #include <gdk-pixbuf/gdk-pixbuf.h>
 #include <cairo.h>
+#include "typedefs.h"
 
 
 #if G_BYTE_ORDER == G_LITTLE_ENDIAN /* BGRA */
@@ -114,11 +115,19 @@ void               _gdk_color_to_cairo_color_255            (GdkColor          *
 
 void               _cairo_clear_surface                     (cairo_surface_t  **surface);
 gboolean           _cairo_image_surface_get_has_alpha       (cairo_surface_t   *surface);
+cairo_surface_t *  _cairo_image_surface_copy                (cairo_surface_t   *surface);
+cairo_surface_t *  _cairo_image_surface_copy_subsurface     (cairo_surface_t   *surface,
+				      	      	      	     int                src_x,
+				      	      	      	     int                src_y,
+				      	      	      	     int                width,
+				      	      	      	     int                height);
 cairo_surface_t *  _cairo_image_surface_create_from_pixbuf  (GdkPixbuf         *pixbuf);
 cairo_surface_t *  _cairo_image_surface_scale_to            (cairo_surface_t   *surface,
 							     int                width,
 							     int                height,
 							     cairo_filter_t     filter);
+cairo_surface_t *  _cairo_image_surface_transform           (cairo_surface_t   *surface,
+							     GthTransform       transform);
 
 /* paint / draw */
 



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