Hi,

Please find attached a patch that adds experimental PDF/PS export
support via cairo renderer (if cairo is compiled with PDF/PS backends,
of course, which should be the default for next stable release...).

In the process, I've moved some image format related code from gnumeric
to goffice.

Ok to commit ?

        Emmanuel.
? po/fr.po.autosave
? src/gnm-graph-window.c
? src/gnm-graph-window.h
Index: src/sheet-object-graph.c
===================================================================
RCS file: /cvs/gnome/gnumeric/src/sheet-object-graph.c,v
retrieving revision 1.74
diff -u -p -r1.74 sheet-object-graph.c
--- src/sheet-object-graph.c	18 Nov 2005 15:54:51 -0000	1.74
+++ src/sheet-object-graph.c	29 Nov 2005 15:24:24 -0000
@@ -221,24 +221,9 @@ gnm_sog_get_object_target_list (SheetObj
 	return tl;
 }
 
-static gboolean
-sog_gsf_gdk_pixbuf_save (const gchar *buf,
-			 gsize count,
-			 GError **error,
-			 gpointer data)
-{
-	GsfOutput *output = GSF_OUTPUT (data);
-	gboolean ok = gsf_output_write (output, count, buf);
-
-	if (!ok && error)
-		*error = g_error_copy (gsf_output_error (output));
-
-	return ok;
-}
-
 static void
 gnm_sog_write_image (SheetObject const *so, const char *format,
-				GsfOutput *output, GError **err)
+		     GsfOutput *output, GError **err)
 {
 	SheetObjectGraph *sog = SHEET_OBJECT_GRAPH (so);
 	gboolean res = FALSE;
@@ -258,20 +243,10 @@ gnm_sog_write_image (SheetObject const *
 
 	g_return_if_fail (w > 0 && h > 0);
 
-	if (strcmp (format, "svg") == 0) {
-		res = gog_graph_export_to_svg (sog->graph, output, w, h, 1.0);
-	} else {
-		GdkPixbuf *pixbuf = gog_renderer_get_pixbuf (sog->renderer);
-
-		if (!pixbuf) {
-			gog_renderer_update (sog->renderer, w, h, 1.);
-			pixbuf = gog_renderer_get_pixbuf (sog->renderer);
-		}
-		res = gdk_pixbuf_save_to_callback (pixbuf,
-						   sog_gsf_gdk_pixbuf_save,
-						   output, format,
-						   err, NULL);
-	}
+	/* FIXME Add a dpi editor. Default dpi to 150 for now */
+	res = gog_graph_export_image (sog->graph, go_image_get_format_from_name (format),
+				      output, 150.0, 150.0);
+	
 	if (!res && err && *err == NULL)
 		*err = g_error_new (gsf_output_error_id (), 0,
 				    _("Unknown failure while saving image"));
@@ -308,49 +283,34 @@ gnm_sog_write_object (SheetObject const 
 	g_free (old_num_locale);
 }
 
-/* 
- * The following are useful formats to save in:
- *  png
- *  svg
- *  eps
- *
- * TODO: Possibly add an eps renderer.  We may also use a new instance of
- * pixbufrenderer to save as png. This would allow the user to specify size of
- * the saved image, if that's wanted.
- */
 static void
 sog_cb_save_as (SheetObject *so, SheetControl *sc)
 {
-	static GOImageType const fmts[] = {
-		{(char *) "svg",  (char *) N_("SVG (vector graphics)"), (char *) "svg", FALSE},
-		{(char *) "png",  (char *) N_("PNG (raster graphics)"), (char *) "png", TRUE},
-		{(char *) "jpeg", (char *) N_("JPEG (photograph)"),     (char *) "jpg", TRUE}
-	};
-
 	WorkbookControlGUI *wbcg;
 	char *uri;
 	GError *err = NULL;
 	GsfOutput *output;
-	GSList *l = NULL;
-	GOImageType const *sel_fmt = &fmts[0];
-	guint i;
+	GSList *l;
+	GOImageFormat selected_format;
+	GOImageFormatInfo const *format_info;
 	SheetObjectGraph *sog = SHEET_OBJECT_GRAPH (so);
 
 	g_return_if_fail (sog != NULL);
 
-	for (i = 0; i < G_N_ELEMENTS (fmts); i++)
-		l = g_slist_prepend (l, (gpointer) (fmts + i));
-	l = g_slist_reverse (l);
+	l = gog_graph_get_supported_image_formats ();
+	g_return_if_fail (l != NULL);
+	selected_format = GPOINTER_TO_UINT (l->data);
 
 #warning "This violates model gui barrier"
 	wbcg = scg_get_wbcg (SHEET_CONTROL_GUI (sc));
-	uri = gui_get_image_save_info (wbcg_toplevel (wbcg), l, &sel_fmt);
+	uri = gui_get_image_save_info (wbcg_toplevel (wbcg), l, &selected_format);
 	if (!uri)
 		goto out;
 	output = go_file_create (uri, &err);
 	if (!output)
 		goto out;
-	sheet_object_write_image (so, sel_fmt->name, output, &err);
+	format_info = go_image_get_format_info (selected_format);
+	sheet_object_write_image (so, format_info->name, output, &err);
 	g_object_unref (output);
 		
 	if (err != NULL)
Index: src/sheet-object-image.c
===================================================================
RCS file: /cvs/gnome/gnumeric/src/sheet-object-image.c,v
retrieving revision 1.61
diff -u -p -r1.61 sheet-object-image.c
--- src/sheet-object-image.c	7 Nov 2005 04:44:02 -0000	1.61
+++ src/sheet-object-image.c	29 Nov 2005 15:24:24 -0000
@@ -138,9 +138,9 @@ enum {
 void
 sheet_object_image_set_image (SheetObjectImage *soi,
 			      char const   *type,
-			guint8       *data,
+			      guint8       *data,
 			      unsigned      data_len,
-			gboolean      copy_data)
+			      gboolean      copy_data)
 {
 	g_return_if_fail (IS_SHEET_OBJECT_IMAGE (soi));
 	g_return_if_fail (soi->bytes.data == NULL && soi->bytes.len == 0);
@@ -345,77 +345,14 @@ soi_gdk_pixbuf_save (const gchar *buf,
 	return ok;
 }
 
-static GOImageType const std_fmts[] = {
-	{(char *) "png",  (char *) N_("PNG (raster graphics)"),   
-	 (char *) "png", TRUE},
-	{(char *) "jpeg", (char *) N_("JPEG (photograph)"),      
-	 (char *) "jpg", TRUE},
-	{(char *) "svg",  (char *) N_("SVG (vector graphics)"),  
-	 (char *) "svg", FALSE},
-	{(char *) "emf",  (char *) N_("EMF (extended metafile)"),
-	 (char *) "emf", FALSE},
-	{(char *) "wmf",  (char *) N_("WMF (windows metafile)"), 
-	 (char *) "wmf", FALSE}
+static GOImageFormat const standard_formats[] = {
+	GO_IMAGE_FORMAT_PNG,
+	GO_IMAGE_FORMAT_JPG,
+	GO_IMAGE_FORMAT_SVG,
+	GO_IMAGE_FORMAT_EMF,
+	GO_IMAGE_FORMAT_WMF
 };
 
-static GOImageType *
-soi_get_image_fmt (SheetObjectImage *soi)
-{
-	GOImageType *ret = g_new0 (GOImageType, 1);
-	GSList *l, *pixbuf_fmts;
-	guint i;
-	
-	ret->name = g_strdup (soi->type);
-	for (i = 0; i < G_N_ELEMENTS (std_fmts); i++) {
-		GOImageType const *fmt = &std_fmts[i];
-		
-		if (strcmp (soi->type, fmt->name) == 0) {
-			ret->desc = g_strdup (fmt->desc);
-			ret->ext  = g_strdup (fmt->ext);
-			ret->has_pixbuf_saver = fmt->has_pixbuf_saver;
-			return ret;
-		}
-	}
-
-	ret->desc = g_ascii_strup (ret->name, -1);
-	ret->has_pixbuf_saver = FALSE;
-
-	/* Not found in standard formats - look in gdk-pixbuf */
-	pixbuf_fmts = gdk_pixbuf_get_formats ();
-	for (l = pixbuf_fmts; l != NULL; l = l->next) {
-		GdkPixbufFormat *fmt = (GdkPixbufFormat *)l->data;
-		gchar *name = gdk_pixbuf_format_get_name (fmt);
-		int cmp = strcmp (soi->type, name);
-		
-		g_free (name);
-		if (cmp == 0) {
-			gchar **exts;
-			
-			exts = gdk_pixbuf_format_get_extensions (fmt);
-			ret->ext = g_strdup (exts[0]);
-			g_strfreev (exts);
-			break;
-		}
-	}
-	g_slist_free (pixbuf_fmts);
-
-	if (ret->ext == NULL)
-		ret->ext = g_strdup (ret->name);
-
-	return ret;
-}
-
-static void
-soi_free_image_fmt (gpointer data)
-{
-	GOImageType *fmt = (GOImageType *) data;
-
-	g_free (fmt->name);
-	g_free (fmt->desc);
-	g_free (fmt->ext);
-	g_free (fmt);
-}
-
 static GtkTargetList *
 gnm_soi_get_target_list (SheetObject const *so)
 {
@@ -447,14 +384,13 @@ gnm_soi_get_target_list (SheetObject con
 
 static void
 gnm_soi_write_image (SheetObject const *so, const char *format,
-				GsfOutput *output, GError **err)
+		     GsfOutput *output, GError **err)
 {
 	SheetObjectImage *soi = SHEET_OBJECT_IMAGE (so);
-	GOImageType const *orig_fmt = soi_get_image_fmt (soi);
 	gboolean res = FALSE;
 	GdkPixbuf *pixbuf = soi_get_pixbuf (soi, 1.0);
 
-	if (strcmp (format, orig_fmt->name) == 0)
+	if (strcmp (format, soi->type) == 0)
 		res = gsf_output_write (output, 
 					soi->bytes.len, soi->bytes.data);
 	else if (pixbuf)
@@ -476,36 +412,21 @@ soi_cb_save_as (SheetObject *so, SheetCo
 	char *uri;
 	GsfOutput *output;
 	GSList *l = NULL;
-	GOImageType const *orig_fmt, *sel_fmt;
-	GOImageType *fmt;
+	GOImageFormat sel_fmt;
+	GOImageFormatInfo const *format_info;
 	GdkPixbuf *pixbuf = NULL;
-	guint i;
 	GError *err = NULL;
 	SheetObjectImage *soi = SHEET_OBJECT_IMAGE (so);
 
 	g_return_if_fail (soi != NULL);
 
-	/* Put original format of image first in menu. */
-	orig_fmt = soi_get_image_fmt (soi);
-	sel_fmt  = orig_fmt;
-	l = g_slist_prepend (l, (gpointer)orig_fmt);
-
-	/* Put jpeg and png in menu if we were able to render */
-	if ((pixbuf = soi_get_pixbuf (soi, 1.0)) != NULL) {
-		for (i = 0; i < G_N_ELEMENTS (std_fmts); i++) {
-			if (strcmp (soi->type, std_fmts[i].name) != 0 &&
-			    std_fmts[i].has_pixbuf_saver) {
-				fmt = g_new0 (GOImageType, 1);
-				fmt->name = g_strdup (std_fmts[i].name); 
-				fmt->desc = g_strdup (std_fmts[i].desc);
-				fmt->ext  = g_strdup (std_fmts[i].ext);
-				fmt->has_pixbuf_saver = TRUE; 
-				l = g_slist_prepend (l, fmt);
-			}
-		}
-		l = g_slist_reverse (l);
-	}		
-
+	sel_fmt  = go_image_get_format_from_name (soi->type);
+	if ((pixbuf = soi_get_pixbuf (soi, 1.0)) != NULL) 
+		l = go_image_get_formats_with_pixbuf_saver ();
+	/* Move original format first in menu */
+	l = g_slist_remove (l, GUINT_TO_POINTER (sel_fmt));
+	l = g_slist_prepend (l, GUINT_TO_POINTER (sel_fmt));
+	
 	wbcg = scg_get_wbcg (SHEET_CONTROL_GUI (sc));
 
 	uri = gui_get_image_save_info (wbcg_toplevel (wbcg), l, &sel_fmt);
@@ -515,7 +436,8 @@ soi_cb_save_as (SheetObject *so, SheetCo
 	output = go_file_create (uri, &err);
 	if (!output)
 		goto out;
-	sheet_object_write_image (so, sel_fmt->name, output, &err);
+	format_info = go_image_get_format_info (sel_fmt);
+	sheet_object_write_image (so, format_info->name, output, &err);
 	gsf_output_close (output);
 	g_object_unref (output);
 
@@ -526,7 +448,7 @@ out:
 	if (pixbuf)
 		g_object_unref (pixbuf);
 	g_free (uri);
-	go_slist_free_custom (l, soi_free_image_fmt);
+	g_slist_free (l);
 }
 
 static void
? jhgen
? goffice/graph/.gog-renderer-cairo.c.swp
? goffice/graph/.gog-renderer-pixbuf.c.swp
? goffice/gtk/go-marshal.c
? goffice/gtk/go-marshal.h
? goffice/gtk/go-marshal.list
Index: configure.in
===================================================================
RCS file: /cvs/gnome/goffice/configure.in,v
retrieving revision 1.73
diff -u -p -r1.73 configure.in
--- configure.in	27 Nov 2005 18:35:37 -0000	1.73
+++ configure.in	29 Nov 2005 15:24:10 -0000
@@ -86,7 +86,7 @@ goffice_reqs="
 	pangoft2		>= 1.8.1
 "
 goffice_cairo_reqs="
-	cairo			>= 0.5.0
+	cairo			>= 1.0.0
 "
 goffice_gtk_reqs="
 	gtk+-2.0		>= 2.6.0
Index: goffice/graph/goffice-graph.h
===================================================================
RCS file: /cvs/gnome/goffice/goffice/graph/goffice-graph.h,v
retrieving revision 1.32
diff -u -p -r1.32 goffice-graph.h
--- goffice/graph/goffice-graph.h	15 Nov 2005 15:56:23 -0000	1.32
+++ goffice/graph/goffice-graph.h	29 Nov 2005 15:24:10 -0000
@@ -93,6 +93,7 @@ typedef enum {
 	GOG_AXIS_PSEUDO_3D,
 	GOG_AXIS_TYPES
 } GogAxisType;
+
 typedef enum {
 	GOG_AXIS_SET_UNKNOWN 	  = -1,
 	GOG_AXIS_SET_NONE   	  = 0,
Index: goffice/graph/gog-graph.c
===================================================================
RCS file: /cvs/gnome/goffice/goffice/graph/gog-graph.c,v
retrieving revision 1.38
diff -u -p -r1.38 gog-graph.c
--- goffice/graph/gog-graph.c	20 Nov 2005 15:29:08 -0000	1.38
+++ goffice/graph/gog-graph.c	29 Nov 2005 15:24:10 -0000
@@ -23,6 +23,7 @@
 #include <goffice/graph/gog-graph-impl.h>
 #include <goffice/graph/gog-chart-impl.h>
 #include <goffice/graph/gog-renderer.h>
+#include <goffice/graph/gog-renderer-cairo.h>
 #include <goffice/graph/gog-style.h>
 #include <goffice/graph/gog-theme.h>
 #include <goffice/data/go-data.h>
@@ -865,4 +866,46 @@ gog_graph_view_set_selection (GogGraphVi
 	g_signal_emit (G_OBJECT (gview), 
 		       gog_graph_view_signals [GRAPH_VIEW_SELECTION_CHANGED], 
 		       0, gobj);
+}
+
+GSList *
+gog_graph_get_supported_image_formats (void)
+{
+	static GOImageFormat supported_formats[] = {
+#ifdef CAIRO_HAS_PS_SURFACE
+		GO_IMAGE_FORMAT_PS,
+#endif
+#ifdef CAIRO_HAS_PDF_SURFACE
+		GO_IMAGE_FORMAT_PDF,
+#endif
+		GO_IMAGE_FORMAT_JPG,
+		GO_IMAGE_FORMAT_PNG,
+		GO_IMAGE_FORMAT_SVG
+	};
+	GSList *list = NULL;
+	unsigned i;
+
+	for (i = 0; i < G_N_ELEMENTS (supported_formats); i++)
+		list = g_slist_prepend (list, GUINT_TO_POINTER (supported_formats[i]));
+
+	return list;
+}
+
+gboolean
+gog_graph_export_image (GogGraph *graph, GOImageFormat format, GsfOutput *output,
+			double x_dpi, double y_dpi)
+{
+	GogRenderer *renderer;
+	gboolean result;
+		
+	g_return_val_if_fail (IS_GOG_GRAPH (graph), FALSE);
+	g_return_val_if_fail (format != GO_IMAGE_FORMAT_UNKNOWN, FALSE);
+	
+	renderer = gog_renderer_new_for_format (graph, format);
+	g_return_val_if_fail (renderer != NULL, FALSE);
+
+	result = gog_renderer_export_image (renderer, format, output, x_dpi, y_dpi);
+	g_object_unref (renderer);
+
+	return result;
 }
Index: goffice/graph/gog-graph.h
===================================================================
RCS file: /cvs/gnome/goffice/goffice/graph/gog-graph.h,v
retrieving revision 1.9
diff -u -p -r1.9 gog-graph.h
--- goffice/graph/gog-graph.h	15 Nov 2005 15:56:23 -0000	1.9
+++ goffice/graph/gog-graph.h	29 Nov 2005 15:24:10 -0000
@@ -23,8 +23,10 @@
 
 #include <goffice/graph/goffice-graph.h>
 #include <goffice/graph/gog-view.h>
-
 #include <goffice/data/goffice-data.h>
+#include <goffice/gtk/goffice-gtk.h>
+
+#include <gsf/gsf.h>
 
 #include <glib-object.h>
 
@@ -66,6 +68,11 @@ void  	 gog_graph_view_handle_event 	(Go
 GogView *gog_graph_view_get_selection 	(GogGraphView *view);
 void 	 gog_graph_view_set_selection   (GogGraphView *gview, GogObject *gobj);
 
+
+GSList 	 *gog_graph_get_supported_image_formats	(void);
+gboolean  gog_graph_export_image 		(GogGraph *graph, GOImageFormat format, 
+						 GsfOutput *output, double x_dpi, double y_dpi);
+	
 G_END_DECLS
 
 #endif /* GOG_GRAPH_H */
Index: goffice/graph/gog-renderer-cairo.c
===================================================================
RCS file: /cvs/gnome/goffice/goffice/graph/gog-renderer-cairo.c,v
retrieving revision 1.7
diff -u -p -r1.7 gog-renderer-cairo.c
--- goffice/graph/gog-renderer-cairo.c	18 Nov 2005 15:50:56 -0000	1.7
+++ goffice/graph/gog-renderer-cairo.c	29 Nov 2005 15:24:10 -0000
@@ -46,9 +46,13 @@
 #include <libart_lgpl/art_render_svp.h>
 #include <libart_lgpl/art_render_mask.h>
 #include <pango/pangoft2.h>
+
 #include <gsf/gsf-impl-utils.h>
+#include <gsf/gsf-output-stdio.h>
 
-#include <cairo/cairo.h>
+#include <cairo.h>
+#include <cairo-pdf.h>
+#include <cairo-ps.h>
 
 #include <math.h>
 
@@ -79,11 +83,8 @@ static void
 gog_renderer_cairo_finalize (GObject *obj)
 {
 	GogRendererCairo *crend = GOG_RENDERER_CAIRO (obj);
-	cairo_surface_t *surface;
 
 	if (crend->cairo != NULL){
-		surface = cairo_get_target (crend->cairo);
-		cairo_surface_destroy (surface);
 		cairo_destroy (crend->cairo);
 		crend->cairo = NULL;
 	}
@@ -617,6 +618,101 @@ gog_renderer_cairo_pop_style (GogRendere
 	}
 }
 
+static gboolean
+gcr_gsf_gdk_pixbuf_save (const gchar *buf,
+			 gsize count,
+			 GError **error,
+			 gpointer data)
+{
+	GsfOutput *output = GSF_OUTPUT (data);
+	gboolean ok = gsf_output_write (output, count, buf);
+
+	if (!ok && error)
+		*error = g_error_copy (gsf_output_error (output));
+
+	return ok;
+}
+
+static cairo_status_t
+cairo_write_func (void *closure,
+		  unsigned char *data,
+		  unsigned int length)
+{
+	gboolean result;
+	GsfOutput *output = GSF_OUTPUT (closure);
+
+	result = gsf_output_write (output, length, data);
+
+	return result ? CAIRO_STATUS_SUCCESS : CAIRO_STATUS_WRITE_ERROR;
+}
+
+static gboolean
+gog_renderer_cairo_export_image (GogRenderer *renderer, GOImageFormat format,
+				 GsfOutput *output, double x_dpi, double y_dpi)
+{
+	GogRendererCairo *crend = GOG_RENDERER_CAIRO (renderer);
+	GogViewAllocation allocation;
+	GOImageFormatInfo const *format_info;
+	cairo_surface_t *surface;
+	cairo_status_t status;
+	GdkPixbuf *pixbuf;
+	double width_in_pts, height_in_pts;
+
+	gog_graph_get_size (renderer->model, &width_in_pts, &height_in_pts);
+
+	switch (format) {
+		case GO_IMAGE_FORMAT_PNG:
+		case GO_IMAGE_FORMAT_JPG:
+			gog_renderer_cairo_update (crend, 
+						   width_in_pts * x_dpi / 72.0, 
+						   height_in_pts * y_dpi / 72.0, 1.0);
+			pixbuf = gog_renderer_cairo_get_pixbuf (crend);
+			if (pixbuf == NULL)
+				return FALSE;
+			format_info = go_image_get_format_info (format);
+			return gdk_pixbuf_save_to_callback (pixbuf,
+							    gcr_gsf_gdk_pixbuf_save,
+							    output, format_info->name,
+							    NULL, NULL);
+			break;
+		case GO_IMAGE_FORMAT_PDF:
+		case GO_IMAGE_FORMAT_PS:
+			crend->base.scale = 1.0;
+			if (format == GO_IMAGE_FORMAT_PDF) {
+				surface = cairo_pdf_surface_create_for_stream (cairo_write_func, output, 
+									       width_in_pts, height_in_pts);
+			} else {
+				surface = cairo_ps_surface_create_for_stream (cairo_write_func, output, 
+									      width_in_pts, height_in_pts);
+			}
+			crend->cairo = cairo_create (surface);
+			cairo_surface_destroy (surface);
+			cairo_set_line_join (crend->cairo, CAIRO_LINE_JOIN_ROUND);
+			cairo_set_line_cap (crend->cairo, CAIRO_LINE_CAP_ROUND);
+			crend->w = width_in_pts;
+			crend->h = height_in_pts;
+
+			allocation.x = 0.;
+			allocation.y = 0.;
+			allocation.w = width_in_pts;
+			allocation.h = height_in_pts;
+			gog_view_size_allocate (crend->base.view, &allocation);
+			gog_view_render	(crend->base.view, NULL);
+
+			cairo_show_page (crend->cairo);
+			status = cairo_status (crend->cairo);
+
+			cairo_destroy (crend->cairo);
+			crend->cairo = NULL;
+
+			return status == CAIRO_STATUS_SUCCESS;
+			break;
+		default:
+			g_warning ("[GogRendererCairo:export_image] unsupported format");
+			return FALSE;
+	}
+}
+
 static void
 gog_renderer_cairo_class_init (GogRendererClass *rend_klass)
 {
@@ -637,6 +733,7 @@ gog_renderer_cairo_class_init (GogRender
 	rend_klass->draw_marker	  	= gog_renderer_cairo_draw_marker;
 	rend_klass->get_text_OBR	= gog_renderer_cairo_get_text_OBR;
 	rend_klass->line_size		= gog_renderer_cairo_line_size;
+	rend_klass->export_image	= gog_renderer_cairo_export_image;
 }
 
 static void
@@ -653,55 +750,6 @@ GSF_CLASS (GogRendererCairo, gog_rendere
 	   gog_renderer_cairo_class_init, gog_renderer_cairo_init,
 	   GOG_RENDERER_TYPE)
 
-GdkPixbuf *
-gog_renderer_cairo_get_pixbuf (GogRendererCairo *crend)
-{
-	g_return_val_if_fail (crend != NULL, NULL);
-
-	return crend->pixbuf;
-}
-
-static gboolean
-grc_cairo_setup (GogRendererCairo *crend, int w, int h)
-{
-	cairo_surface_t *surface;
-
-	if (w == crend->w && h == crend->h)
-		return (w != 0 && h!= 0);
-		
-	if (crend->cairo != NULL) {
-		surface = cairo_get_target (crend->cairo);
-		cairo_surface_destroy (surface);
-		cairo_destroy (crend->cairo);
-		crend->cairo = NULL;
-	}
-	if (crend->pixbuf != NULL) {
-		g_object_unref (crend->pixbuf);
-		crend->pixbuf = NULL;
-	}
-	crend->w = w;
-	crend->h = h;
-
-	if (w ==0 || h == 0) 
-		return FALSE;
-	
-	crend->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, crend->w, crend->h);
-	if (crend->pixbuf == NULL) {
-		g_warning ("GogRendererCairo::cairo_setup: chart is too large");
-		return FALSE;
-	}
-
-	surface = cairo_image_surface_create_for_data (gdk_pixbuf_get_pixels (crend->pixbuf),
-						       CAIRO_FORMAT_ARGB32, 
-						       crend->w, crend->h,
-						       gdk_pixbuf_get_rowstride (crend->pixbuf));
-	crend->cairo = cairo_create (surface);
-	cairo_set_line_join (crend->cairo, CAIRO_LINE_JOIN_ROUND);
-	cairo_set_line_cap (crend->cairo, CAIRO_LINE_CAP_ROUND);
-
-	return TRUE;
-}
-
 /**
  * gog_renderer_update :
  * @prend :
@@ -716,22 +764,47 @@ gog_renderer_cairo_update (GogRendererCa
 	GogGraph *graph;
 	GogView *view;
 	GogViewAllocation allocation;
+	cairo_surface_t *surface;
 	gboolean redraw = TRUE;
 	gboolean size_changed;
 
-	g_return_val_if_fail (crend != NULL, FALSE);
-	g_return_val_if_fail (crend->base.view != NULL, FALSE);
+	g_return_val_if_fail (IS_GOG_RENDERER_CAIRO (crend), FALSE);
+	g_return_val_if_fail (IS_GOG_VIEW (crend->base.view), FALSE);
 
 	size_changed = crend->w != w || crend->h != h;
+	if (size_changed) {
+		if (crend->pixbuf != NULL)
+			g_object_unref (crend->pixbuf);
+		crend->pixbuf = NULL;
+		if (w == 0 || h == 0)
+			return FALSE;
+		crend->w = w;
+		crend->h = h;
+		crend->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, crend->w, crend->h);
+		if (crend->pixbuf == NULL) {
+			crend->w = 0;
+			crend->h = 0;
+			g_warning ("GogRendererCairo::cairo_setup: chart is too large");
+			return FALSE;
+		}
+	}
+	if (w == 0 || h == 0)
+		return FALSE;
 
 	view = crend->base.view;
 	graph = GOG_GRAPH (view->model);
 	gog_graph_force_update (graph);
+	
 	allocation.x = allocation.y = 0.;
 	allocation.w = w;
 	allocation.h = h;
-	if (!grc_cairo_setup (crend, w, h))
-		return redraw;
+	
+	surface = cairo_image_surface_create_for_data (gdk_pixbuf_get_pixels (crend->pixbuf),
+						       CAIRO_FORMAT_ARGB32, 
+						       crend->w, crend->h,
+						       gdk_pixbuf_get_rowstride (crend->pixbuf));
+	crend->cairo = cairo_create (surface);
+	cairo_surface_destroy (surface);
 
 	if (size_changed) {
 		crend->base.scale_x = w / graph->width;
@@ -755,6 +828,9 @@ gog_renderer_cairo_update (GogRendererCa
 	crend->base.needs_update = FALSE;
 
 	if (redraw) { 
+		cairo_set_line_join (crend->cairo, CAIRO_LINE_JOIN_ROUND);
+		cairo_set_line_cap (crend->cairo, CAIRO_LINE_CAP_ROUND);
+
 		cairo_rectangle (crend->cairo, 0, 0, w, h);
 		cairo_set_source_rgba (crend->cairo, 1, 1, 1, 0);
 		cairo_fill (crend->cairo);
@@ -765,5 +841,16 @@ gog_renderer_cairo_update (GogRendererCa
 				      gdk_pixbuf_get_rowstride (crend->pixbuf));
 	}
 
+	cairo_destroy (crend->cairo);
+	crend->cairo = NULL;
 	return redraw;
 }
+
+GdkPixbuf *
+gog_renderer_cairo_get_pixbuf (GogRendererCairo *crend)
+{
+	g_return_val_if_fail (crend != NULL, NULL);
+
+	return crend->pixbuf;
+}
+
Index: goffice/graph/gog-renderer-cairo.h
===================================================================
RCS file: /cvs/gnome/goffice/goffice/graph/gog-renderer-cairo.h,v
retrieving revision 1.2
diff -u -p -r1.2 gog-renderer-cairo.h
--- goffice/graph/gog-renderer-cairo.h	8 Aug 2005 08:56:59 -0000	1.2
+++ goffice/graph/gog-renderer-cairo.h	29 Nov 2005 15:24:10 -0000
@@ -22,6 +22,9 @@
 #define GOG_RENDERER_CAIRO_H
 
 #include <goffice/graph/goffice-graph.h>
+
+#include <gsf/gsf.h>
+
 #include <glib-object.h>
 #include <gdk-pixbuf/gdk-pixbuf.h>
 
@@ -37,6 +40,8 @@ GType      gog_renderer_cairo_get_type		
 GdkPixbuf *gog_renderer_cairo_get_pixbuf   	(GogRendererCairo *crend);
 gboolean   gog_renderer_cairo_update		(GogRendererCairo *crend, int w, int h, double zoom);
 
+gboolean   gog_renderer_cairo_export_to_pdf	(GogRendererCairo *crend, GogGraph *graph, GsfOutput *output, 
+						 double width, double height, double scale);
 G_END_DECLS
 
 #endif /* GOG_RENDERER_CAIRO_H */
Index: goffice/graph/gog-renderer-impl.h
===================================================================
RCS file: /cvs/gnome/goffice/goffice/graph/gog-renderer-impl.h,v
retrieving revision 1.27
diff -u -p -r1.27 gog-renderer-impl.h
--- goffice/graph/gog-renderer-impl.h	15 Nov 2005 15:56:23 -0000	1.27
+++ goffice/graph/gog-renderer-impl.h	29 Nov 2005 15:24:10 -0000
@@ -81,10 +81,13 @@ typedef struct {
 				 GogViewAllocation const *pos, GtkAnchorType anchor,
 				 GogViewAllocation *result);
 	void (*draw_marker)    	(GogRenderer *rend, double x, double y);
-	
+
 	void (*get_text_OBR)	(GogRenderer *rend, char const *text, GOGeometryOBR *obr);
-	
-	double (*line_size)		(GogRenderer const *rend, double width);
+
+	double (*line_size)	(GogRenderer const *rend, double width);
+
+	gboolean (*export_image)	(GogRenderer *renderer, GOImageFormat format, 
+					 GsfOutput *output, double x_dpi, double y_dpi);
 
 	/* Signals */
 	void (*request_update) (GogRenderer *renderer);
Index: goffice/graph/gog-renderer-pixbuf.c
===================================================================
RCS file: /cvs/gnome/goffice/goffice/graph/gog-renderer-pixbuf.c,v
retrieving revision 1.71
diff -u -p -r1.71 gog-renderer-pixbuf.c
--- goffice/graph/gog-renderer-pixbuf.c	25 Sep 2005 20:21:51 -0000	1.71
+++ goffice/graph/gog-renderer-pixbuf.c	29 Nov 2005 15:24:10 -0000
@@ -36,6 +36,7 @@
 #include <libart_lgpl/art_render_mask.h>
 #include <pango/pangoft2.h>
 #include <gsf/gsf-impl-utils.h>
+#include <gsf/gsf-output-stdio.h>
 
 #include <math.h>
 
@@ -943,6 +944,53 @@ gog_renderer_pixbuf_push_style (GogRende
 	}
 }
 
+static gboolean
+gcp_gsf_gdk_pixbuf_save (const gchar *buf,
+			 gsize count,
+			 GError **error,
+			 gpointer data)
+{
+	GsfOutput *output = GSF_OUTPUT (data);
+	gboolean ok = gsf_output_write (output, count, buf);
+
+	if (!ok && error)
+		*error = g_error_copy (gsf_output_error (output));
+
+	return ok;
+}
+
+static gboolean
+gog_renderer_pixbuf_export_image (GogRenderer *renderer, GOImageFormat format,
+				  GsfOutput *output, double x_dpi, double y_dpi)
+{
+	GogRendererPixbuf *prend = GOG_RENDERER_PIXBUF (renderer);
+	GdkPixbuf *pixbuf;
+	GOImageFormatInfo const *format_info;
+	double width_in_pts, height_in_pts;
+
+	gog_graph_get_size (renderer->model, &width_in_pts, &height_in_pts);
+
+	switch (format) {
+		case GO_IMAGE_FORMAT_PNG:
+		case GO_IMAGE_FORMAT_JPG:
+			gog_renderer_pixbuf_update (prend, 
+						    width_in_pts * x_dpi / 72.0, 
+						    height_in_pts * y_dpi / 72.0, 1.0);
+			pixbuf = gog_renderer_pixbuf_get (prend);
+			if (pixbuf == NULL)
+				return FALSE;
+			format_info = go_image_get_format_info (format);
+			return gdk_pixbuf_save_to_callback (pixbuf,
+							    gcp_gsf_gdk_pixbuf_save,
+							    output, format_info->name,
+							    NULL, NULL);
+			break;
+		default:
+			g_warning ("[GogRendererPixbuf:export_image] unsupported format");
+			return FALSE;
+	}
+}
+
 static void
 gog_renderer_pixbuf_class_init (GogRendererClass *rend_klass)
 {
@@ -963,6 +1011,7 @@ gog_renderer_pixbuf_class_init (GogRende
 	rend_klass->draw_marker	  	= gog_renderer_pixbuf_draw_marker;
 	rend_klass->get_text_OBR	= gog_renderer_pixbuf_get_text_OBR;
 	rend_klass->line_size		= gog_renderer_pixbuf_line_size;
+	rend_klass->export_image	= gog_renderer_pixbuf_export_image;
 }
 
 static void
Index: goffice/graph/gog-renderer-svg.c
===================================================================
RCS file: /cvs/gnome/goffice/goffice/graph/gog-renderer-svg.c,v
retrieving revision 1.32
diff -u -p -r1.32 gog-renderer-svg.c
--- goffice/graph/gog-renderer-svg.c	7 Oct 2005 14:36:42 -0000	1.32
+++ goffice/graph/gog-renderer-svg.c	29 Nov 2005 15:24:10 -0000
@@ -20,7 +20,7 @@
  */
 
 #include <goffice/goffice-config.h>
-#include <goffice/graph/gog-graph-impl.h>
+#include <goffice/graph/gog-graph.h>
 #include <goffice/graph/gog-renderer-svg.h>
 #include <goffice/graph/gog-renderer-impl.h>
 #include <goffice/graph/gog-style.h>
@@ -41,10 +41,6 @@
 
 #define CC2XML(s) ((const xmlChar *)(s))
 
-#define GOG_RENDERER_SVG_TYPE	(gog_renderer_svg_get_type ())
-#define GOG_RENDERER_SVG(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GOG_RENDERER_SVG_TYPE, GogRendererSvg))
-#define IS_GOG_RENDERER_SVG(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GOG_RENDERER_SVG_TYPE))
-
 typedef struct _GogRendererSvg GogRendererSvg;
 
 struct _GogRendererSvg {
@@ -64,8 +60,6 @@ typedef GogRendererClass GogRendererSvgC
 
 static GObjectClass *parent_klass;
 
-static GType gog_renderer_svg_get_type (void);
-
 static void 
 set_double_prop (xmlNodePtr node, const char *name, double value)
 {
@@ -729,54 +723,22 @@ gog_renderer_svg_draw_text (GogRenderer 
 	}
 }
 
-static void
-gog_renderer_svg_class_init (GogRendererClass *rend_klass)
-{
-	GObjectClass *gobject_klass   = (GObjectClass *) rend_klass;
-
-	parent_klass = g_type_class_peek_parent (rend_klass);
-	gobject_klass->finalize	  	= gog_renderer_svg_finalize;
-	rend_klass->push_clip		= gog_renderer_svg_push_clip;
-	rend_klass->pop_clip	 	= gog_renderer_svg_pop_clip;
-	rend_klass->draw_path	  	= gog_renderer_svg_draw_path;
-	rend_klass->draw_polygon  	= gog_renderer_svg_draw_polygon;
-	rend_klass->draw_bezier_path 	= gog_renderer_svg_draw_bezier_path;
-	rend_klass->draw_bezier_polygon = gog_renderer_svg_draw_bezier_polygon;
-	rend_klass->draw_text	  	= gog_renderer_svg_draw_text;
-	rend_klass->draw_marker	  	= gog_renderer_svg_draw_marker;
-	rend_klass->get_text_OBR	= gog_renderer_svg_get_text_OBR;
-}
-
-static GSF_CLASS (GogRendererSvg, gog_renderer_svg,
-		  gog_renderer_svg_class_init, NULL,
-		  GOG_RENDERER_TYPE)
-
-/**
- * gog_graph_export_to_svg :
- * @graph  : #GogGraph
- * @output : #GsfOutput
- * @width  :
- * @height :
- *
- * Renders @graph as SVG and stores it in @output.
- *
- * Returns TRUE on success.
- **/
-gboolean
-gog_graph_export_to_svg (GogGraph *graph, GsfOutput *output,
-			 double width, double height, double scale)
+static gboolean
+gog_renderer_svg_export_image (GogRenderer *renderer, GOImageFormat format,
+			       GsfOutput *output, double x_dpi, double y_dpi)
 {
 	GogViewAllocation allocation;
-	GogRendererSvg *prend;
+	GogRendererSvg *prend = GOG_RENDERER_SVG (renderer);
 	xmlNsPtr namespace;
+	double width_in_pts, height_in_pts;
 	gboolean success = TRUE;
 
-	gog_graph_force_update (graph);
+	if (format != GO_IMAGE_FORMAT_SVG) {
+		g_warning ("[GogRendererSVG::export_image] Unsupported format");
+		return FALSE;
+	}
 
-	prend = g_object_new (GOG_RENDERER_SVG_TYPE,
-			      "model", graph,
-			      NULL);
-	prend->base.scale = scale;
+	prend->base.scale = 1.0;
 	prend->doc = xmlNewDoc (CC2XML ("1.0"));
 
 	xmlNewDtd (prend->doc,
@@ -795,14 +757,15 @@ gog_graph_export_to_svg (GogGraph *graph
 
 	namespace = xmlNewNs (prend->doc->children, CC2XML ("http://www.w3.org/1999/xlink";), CC2XML ("xlink"));
 
-	set_double_prop (prend->doc->children, "width", width);
-	set_double_prop (prend->doc->children, "height", height);
+	gog_graph_get_size (renderer->model, &width_in_pts, &height_in_pts);
+	set_double_prop (prend->doc->children, "width", width_in_pts);
+	set_double_prop (prend->doc->children, "height", height_in_pts);
 
 	prend->clip_counter = 0;
 	allocation.x = 0.;
 	allocation.y = 0.;
-	allocation.w = width;
-	allocation.h = height;
+	allocation.w = width_in_pts;
+	allocation.h = height_in_pts;
 	gog_view_size_allocate (prend->base.view, &allocation);
 	gog_view_render	(prend->base.view, NULL);
 
@@ -816,8 +779,33 @@ gog_graph_export_to_svg (GogGraph *graph
 		success = FALSE;
 
 	xmlFreeDoc (prend->doc);
+	prend->doc = NULL;
 	g_hash_table_destroy (prend->table);
-	g_object_unref (prend);
+	prend->table = NULL;
 
 	return success;
 }
+
+static void
+gog_renderer_svg_class_init (GogRendererClass *rend_klass)
+{
+	GObjectClass *gobject_klass   = (GObjectClass *) rend_klass;
+
+	parent_klass = g_type_class_peek_parent (rend_klass);
+	gobject_klass->finalize	  	= gog_renderer_svg_finalize;
+	rend_klass->push_clip		= gog_renderer_svg_push_clip;
+	rend_klass->pop_clip	 	= gog_renderer_svg_pop_clip;
+	rend_klass->draw_path	  	= gog_renderer_svg_draw_path;
+	rend_klass->draw_polygon  	= gog_renderer_svg_draw_polygon;
+	rend_klass->draw_bezier_path 	= gog_renderer_svg_draw_bezier_path;
+	rend_klass->draw_bezier_polygon = gog_renderer_svg_draw_bezier_polygon;
+	rend_klass->draw_text	  	= gog_renderer_svg_draw_text;
+	rend_klass->draw_marker	  	= gog_renderer_svg_draw_marker;
+	rend_klass->get_text_OBR	= gog_renderer_svg_get_text_OBR;
+	rend_klass->export_image	= gog_renderer_svg_export_image;
+}
+
+GSF_CLASS (GogRendererSvg, gog_renderer_svg,
+	   gog_renderer_svg_class_init, NULL,
+	   GOG_RENDERER_TYPE)
+
Index: goffice/graph/gog-renderer-svg.h
===================================================================
RCS file: /cvs/gnome/goffice/goffice/graph/gog-renderer-svg.h,v
retrieving revision 1.4
diff -u -p -r1.4 gog-renderer-svg.h
--- goffice/graph/gog-renderer-svg.h	8 Aug 2005 08:56:59 -0000	1.4
+++ goffice/graph/gog-renderer-svg.h	29 Nov 2005 15:24:10 -0000
@@ -22,13 +22,18 @@
 #define GOG_RENDERER_SVG_H
 
 #include <goffice/graph/goffice-graph.h>
+
 #include <gsf/gsf.h>
 
+#include <glib-object.h>
+
 G_BEGIN_DECLS
 
-gboolean gog_graph_export_to_svg (GogGraph *graph,
-				  GsfOutput *output,
-				  double width, double height, double scale);
+#define GOG_RENDERER_SVG_TYPE	(gog_renderer_svg_get_type ())
+#define GOG_RENDERER_SVG(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), GOG_RENDERER_SVG_TYPE, GogRendererSvg))
+#define IS_GOG_RENDERER_SVG(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), GOG_RENDERER_SVG_TYPE))
+
+GType gog_renderer_svg_get_type (void);
 
 G_END_DECLS
 
Index: goffice/graph/gog-renderer.c
===================================================================
RCS file: /cvs/gnome/goffice/goffice/graph/gog-renderer.c,v
retrieving revision 1.43
diff -u -p -r1.43 gog-renderer.c
--- goffice/graph/gog-renderer.c	18 Nov 2005 15:50:56 -0000	1.43
+++ goffice/graph/gog-renderer.c	29 Nov 2005 15:24:10 -0000
@@ -23,13 +23,16 @@
 #include <goffice/graph/gog-renderer-impl.h>
 #include <goffice/graph/gog-renderer-pixbuf.h>
 #include <goffice/graph/gog-renderer-cairo.h>
+#include <goffice/graph/gog-renderer-svg.h>
 #include <goffice/graph/gog-style.h>
 #include <goffice/graph/gog-graph.h>
+#include <goffice/graph/gog-graph-impl.h>
 #include <goffice/graph/gog-view.h>
 #include <goffice/utils/go-units.h>
 #include <goffice/utils/go-font.h>
 #include <goffice/utils/go-math.h>
 
+#include <gsf/gsf.h>
 #include <gsf/gsf-impl-utils.h>
 
 /* We need to define an hair line width for the svg and gnome_print renderer. 
@@ -671,6 +674,7 @@ gog_renderer_class_init (GogRendererClas
 
 	renderer_klass->sharp_path = NULL;
 	renderer_klass->line_size = NULL;
+	renderer_klass->export_image = NULL;
 
 	g_object_class_install_property (gobject_klass, RENDERER_PROP_MODEL,
 		g_param_spec_object ("model", "model",
@@ -895,4 +899,63 @@ gog_renderer_get_pixbuf (GogRenderer *re
 	g_return_val_if_fail (IS_GOG_RENDERER_PIXBUF (renderer), NULL);
 	return gog_renderer_pixbuf_get (GOG_RENDERER_PIXBUF (renderer));
 #endif
+}
+
+GogRenderer *
+gog_renderer_new_for_format (GogGraph *graph, GOImageFormat format)
+{
+	GType type = G_TYPE_INVALID;
+	
+	switch (format) {
+		case GO_IMAGE_FORMAT_PNG:
+		case GO_IMAGE_FORMAT_JPG:
+#ifdef WITH_CAIRO
+			type = GOG_RENDERER_CAIRO_TYPE;
+#else
+			type = GOG_RENDERER_PIXBUF_TYPE;
+#endif
+			break;
+		case GO_IMAGE_FORMAT_SVG:
+			type = GOG_RENDERER_SVG_TYPE;
+			break;
+		case GO_IMAGE_FORMAT_PDF:
+#ifdef CAIRO_HAS_PDF_SURFACE
+			type = GOG_RENDERER_CAIRO_TYPE;
+#else
+#warning MISSING PDF SUPPORT
+#endif
+			break;
+		case GO_IMAGE_FORMAT_PS:
+#ifdef CAIRO_HAS_PS_SURFACE
+			type = GOG_RENDERER_CAIRO_TYPE;
+#else
+#warning MISSING PS SUPPORT
+#endif
+			break;
+		default:
+			break;
+	}
+	
+	if (type == G_TYPE_INVALID)
+		return NULL;
+	
+	return g_object_new (type, "model", graph, NULL);	
+}
+
+gboolean
+gog_renderer_export_image (GogRenderer *renderer, GOImageFormat format,
+			   GsfOutput *output, double x_dpi, double y_dpi)
+{
+	GogRendererClass *klass;
+
+	g_return_val_if_fail (IS_GOG_RENDERER (renderer), FALSE);
+       
+	gog_graph_force_update (renderer->model);
+
+	klass = GOG_RENDERER_GET_CLASS (renderer);
+
+	if (klass->export_image != NULL)
+		return (klass->export_image) (renderer, format, output, x_dpi, y_dpi);
+
+	return FALSE;
 }
Index: goffice/graph/gog-renderer.h
===================================================================
RCS file: /cvs/gnome/goffice/goffice/graph/gog-renderer.h,v
retrieving revision 1.26
diff -u -p -r1.26 gog-renderer.h
--- goffice/graph/gog-renderer.h	18 Nov 2005 15:50:56 -0000	1.26
+++ goffice/graph/gog-renderer.h	29 Nov 2005 15:24:10 -0000
@@ -23,6 +23,10 @@
 
 #include <goffice/graph/goffice-graph.h>
 #include <goffice/utils/go-geometry.h>
+#include <goffice/gtk/goffice-gtk.h>
+
+#include <gsf/gsf.h>
+
 #include <gtk/gtkenums.h>
 #include <libart_lgpl/libart.h>
 #include <gdk/gdk.h>
@@ -95,6 +99,10 @@ double gog_renderer_pt2r   	  	(GogRende
 GogRenderer 	*gog_renderer_new_for_pixbuf 	(GogGraph *graph);
 gboolean 	 gog_renderer_update 		(GogRenderer *renderer, double w, double h, double zoom);
 GdkPixbuf 	*gog_renderer_get_pixbuf 	(GogRenderer *renderer); 
+
+GogRenderer 	*gog_renderer_new_for_format 	(GogGraph *graph, GOImageFormat format);
+gboolean 	 gog_renderer_export_image 	(GogRenderer *renderer, GOImageFormat format,
+						 GsfOutput *output, double x_dpi, double y_dpi);
 
 G_END_DECLS
 
Index: goffice/gtk/goffice-gtk.c
===================================================================
RCS file: /cvs/gnome/goffice/goffice/gtk/goffice-gtk.c,v
retrieving revision 1.24
diff -u -p -r1.24 goffice-gtk.c
--- goffice/gtk/goffice-gtk.c	7 Oct 2005 16:15:01 -0000	1.24
+++ goffice/gtk/goffice-gtk.c	29 Nov 2005 15:24:10 -0000
@@ -554,10 +554,11 @@ go_gtk_select_image (GtkWindow *toplevel
 }
 
 char *
-gui_get_image_save_info (GtkWindow *toplevel, GSList *formats,
-			 GOImageType const **ret_format)
+gui_get_image_save_info (GtkWindow *toplevel, GSList *supported_formats,
+			 GOImageFormat *ret_format)
 {
-	GOImageType const *sel_format = NULL;
+	GOImageFormat format;
+	GOImageFormatInfo const *format_info;
 	GtkComboBox *format_combo = NULL;
 	char *uri = NULL;
 	GtkFileChooser *fsel = gui_image_chooser_new (TRUE);
@@ -565,21 +566,18 @@ gui_get_image_save_info (GtkWindow *topl
 	g_object_set (G_OBJECT (fsel), "title", _("Save as"), NULL);
 
 	/* Make format chooser */
-	if (formats && ret_format) {
+	if (supported_formats && ret_format) {
 		GtkWidget *label;
 		GtkWidget *box = gtk_hbox_new (FALSE, 5);
 		GSList *l;
 		int i;
 
 		format_combo = GTK_COMBO_BOX (gtk_combo_box_new_text ());
-		if (*ret_format)
-			sel_format = *ret_format;
-		for (l = formats, i = 0; l != NULL; l = l->next, i++) {
-#warning we must find a better solution for translating strings not in goffice domain
-			gtk_combo_box_append_text
-				(format_combo,
-				 gettext (((GOImageType *) (l->data))->desc));
-			if (l->data == (void *)sel_format)
+		for (l = supported_formats, i = 0; l != NULL; l = l->next, i++) {
+			format = GPOINTER_TO_UINT (l->data);
+			format_info = go_image_get_format_info (format);
+			gtk_combo_box_append_text (format_combo, _(format_info->desc)); 
+			if (format == *ret_format)
 				gtk_combo_box_set_active (format_combo, i);
 		}
 		if (gtk_combo_box_get_active (format_combo) < 0)
@@ -602,9 +600,11 @@ gui_get_image_save_info (GtkWindow *topl
 	if (format_combo) {
 		char *new_uri = NULL;
 
-		sel_format = g_slist_nth_data (
-			formats, gtk_combo_box_get_active (format_combo));
-		if (!go_url_check_extension (uri, sel_format->ext, &new_uri) &&
+		format = GPOINTER_TO_UINT (g_slist_nth_data 
+			(supported_formats, 
+			 gtk_combo_box_get_active (format_combo)));
+		format_info = go_image_get_format_info (format);
+		if (!go_url_check_extension (uri, format_info->ext, &new_uri) &&
 		    !go_gtk_query_yes_no (GTK_WINDOW (fsel), TRUE,
 		     _("The given file extension does not match the"
 		       " chosen file type. Do you want to use this name"
@@ -617,7 +617,7 @@ gui_get_image_save_info (GtkWindow *topl
 			g_free (uri);
 			uri = new_uri;
 		}
-		*ret_format = sel_format;
+		*ret_format = format;
 	}
 	if (!go_gtk_url_is_writeable (GTK_WINDOW (fsel), uri, TRUE)) {
 		g_free (uri);
@@ -691,6 +691,124 @@ go_image_format_to_mime (char const *for
 	g_slist_free (pixbuf_fmts);
 
 	return ret;
+}
+
+static GOImageFormatInfo const image_format_infos[GO_IMAGE_FORMAT_UNKNOWN] = {
+	{GO_IMAGE_FORMAT_SVG, (char *) "svg",  (char *) N_("SVG (vector graphics)"), 	 
+		(char *) "svg", FALSE, FALSE},
+	{GO_IMAGE_FORMAT_PNG, (char *) "png",  (char *) N_("PNG (raster graphics)"), 	 
+		(char *) "png", TRUE,  TRUE},
+	{GO_IMAGE_FORMAT_JPG, (char *) "jpeg", (char *) N_("JPEG (photograph)"),     	 
+		(char *) "jpg", TRUE,  TRUE},
+	{GO_IMAGE_FORMAT_PDF, (char *) "pdf",  (char *) N_("PDF (portable document format)"), 
+		(char *) "pdf", FALSE, TRUE},
+	{GO_IMAGE_FORMAT_PS,  (char *) "ps",   (char *) N_("PS (postscript)"), 		 
+		(char *) "ps",  FALSE, TRUE},
+	{GO_IMAGE_FORMAT_EMF, (char *) "emf",  (char *) N_("EMF (extended metafile)"),
+		(char *) "emf", FALSE, FALSE},
+	{GO_IMAGE_FORMAT_WMF, (char *) "wmf",  (char *) N_("WMF (windows metafile)"), 
+		(char *) "wmf", FALSE, FALSE}
+};
+
+static GOImageFormatInfo *pixbuf_image_format_infos = NULL;
+static unsigned pixbuf_format_nbr = 0;
+
+#define PIXBUF_IMAGE_FORMAT_OFFSET (1+GO_IMAGE_FORMAT_UNKNOWN)
+
+static void
+go_image_build_pixbuf_format_infos (void)
+{
+	GdkPixbufFormat *fmt;
+	GSList *l, *pixbuf_fmts;
+	GOImageFormatInfo *format_info;
+	gchar **exts;
+	unsigned i;
+
+	if (pixbuf_format_nbr > 0) 
+		return;
+	
+	pixbuf_fmts = gdk_pixbuf_get_formats ();
+	pixbuf_format_nbr = g_slist_length (pixbuf_fmts);
+	if (pixbuf_format_nbr == 0)
+		goto out;
+	pixbuf_image_format_infos = g_new (GOImageFormatInfo, pixbuf_format_nbr);
+				
+	for (l = pixbuf_fmts, i = 1, format_info = pixbuf_image_format_infos; 
+	     l != NULL; 
+	     l = l->next, i++, format_info++) {
+		fmt = (GdkPixbufFormat *)l->data;
+		
+		format_info->format = GO_IMAGE_FORMAT_UNKNOWN + i;
+		format_info->name = gdk_pixbuf_format_get_name (fmt);
+		format_info->desc = g_ascii_strup (format_info->name, -1);
+		exts = gdk_pixbuf_format_get_extensions (fmt);
+		format_info->ext = g_strdup (exts[0]);
+		if (format_info->ext == NULL)
+			format_info->ext = format_info->name;
+		g_strfreev (exts);
+		format_info->has_pixbuf_saver = gdk_pixbuf_format_is_writable (fmt);
+		format_info->is_dpi_useful = FALSE;
+	}
+
+out:
+	g_slist_free (pixbuf_fmts);
+}
+
+GOImageFormatInfo const *
+go_image_get_format_info (GOImageFormat format)
+{
+	if (format > GO_IMAGE_FORMAT_UNKNOWN)
+		go_image_build_pixbuf_format_infos ();
+		
+	g_return_val_if_fail (format >= 0 && 
+			      format != GO_IMAGE_FORMAT_UNKNOWN &&
+			      format <= GO_IMAGE_FORMAT_UNKNOWN + pixbuf_format_nbr, NULL);
+	if (format < GO_IMAGE_FORMAT_UNKNOWN)	
+		return &image_format_infos[format];
+
+	return &pixbuf_image_format_infos[format - PIXBUF_IMAGE_FORMAT_OFFSET];
+}
+
+GOImageFormat	 
+go_image_get_format_from_name (char const *name)
+{
+	unsigned i;
+
+	go_image_build_pixbuf_format_infos ();
+	
+	for (i = 0; i < GO_IMAGE_FORMAT_UNKNOWN; i++) {
+		if (strcmp (name, image_format_infos[i].name) == 0)
+			return image_format_infos[i].format;
+	}
+
+	for (i = 0; i < pixbuf_format_nbr; i++) {
+		if (strcmp (name, pixbuf_image_format_infos[i].name) == 0)
+			return pixbuf_image_format_infos[i].format;
+	}
+
+	g_warning ("[GOImage::get_format_from_name] Unknown format name (%s)", name);
+	return GO_IMAGE_FORMAT_UNKNOWN;
+}
+
+GSList *
+go_image_get_formats_with_pixbuf_saver (void)
+{
+	GSList *list = NULL;
+	unsigned i;
+
+	for (i = 0; i < GO_IMAGE_FORMAT_UNKNOWN; i++) 
+		if (image_format_infos[i].has_pixbuf_saver)
+			list = g_slist_prepend (list, GUINT_TO_POINTER (i));
+#if 0	
+	/* TODO: before enabling this code, we must remove duplicate in pixbuf_image_format_infos */
+	go_image_build_pixbuf_format_infos ();
+
+	for (i = 0; i < pixbuf_format_nbr; i++) {
+		if (pixbuf_image_format_infos[i].has_pixbuf_saver)
+			list = g_slist_prepend (list, GUINT_TO_POINTER (i + PIXBUF_IMAGE_FORMAT_OFFSET));
+	}
+#endif
+	return list;
 }
 
 static void
Index: goffice/gtk/goffice-gtk.h
===================================================================
RCS file: /cvs/gnome/goffice/goffice/gtk/goffice-gtk.h,v
retrieving revision 1.8
diff -u -p -r1.8 goffice-gtk.h
--- goffice/gtk/goffice-gtk.h	8 Aug 2005 08:57:01 -0000	1.8
+++ goffice/gtk/goffice-gtk.h	29 Nov 2005 15:24:10 -0000
@@ -26,12 +26,25 @@
 
 G_BEGIN_DECLS
 
+typedef enum {
+	GO_IMAGE_FORMAT_SVG,
+	GO_IMAGE_FORMAT_PNG,
+	GO_IMAGE_FORMAT_JPG,
+	GO_IMAGE_FORMAT_PDF,
+	GO_IMAGE_FORMAT_PS,
+	GO_IMAGE_FORMAT_EMF,
+	GO_IMAGE_FORMAT_WMF,
+	GO_IMAGE_FORMAT_UNKNOWN
+} GOImageFormat;
+
 typedef struct {
+	GOImageFormat format;
 	char *name;
 	char *desc;
 	char *ext;
 	gboolean has_pixbuf_saver;
-} GOImageType;
+	gboolean is_dpi_useful; 
+} GOImageFormatInfo;
 
 void	   go_editable_enters (GtkWindow *window, GtkWidget *w);
 
@@ -65,10 +78,15 @@ void	   go_gtk_help_button_init	(GtkWidg
 void       go_gtk_nonmodal_dialog	(GtkWindow *toplevel, GtkWindow *dialog);
 gboolean   go_gtk_file_sel_dialog	(GtkWindow *toplevel, GtkWidget *w);
 char	  *go_gtk_select_image		(GtkWindow *toplevel, const char *initial);
-char	  *gui_get_image_save_info	(GtkWindow *toplevel, GSList *formats, 
-					 GOImageType const **ret_format);
-char *go_mime_to_image_format     (char const *mime_type);
-char *go_image_format_to_mime     (char const *format);
+char      *gui_get_image_save_info 	(GtkWindow *toplevel, GSList *supported_formats,
+					 GOImageFormat *ret_format);
+char 	  *go_mime_to_image_format      (char const *mime_type);
+char 	  *go_image_format_to_mime      (char const *format);
+
+GOImageFormatInfo const *go_image_get_format_info       	(GOImageFormat format);
+GOImageFormat            go_image_get_format_from_name  	(char const *name);
+GSList 			*go_image_get_formats_with_pixbuf_saver (void);
+
 gboolean   go_gtk_url_is_writeable	(GtkWindow *parent, char const *url,
 					 gboolean overwrite_by_default);
 
_______________________________________________
gnumeric-list mailing list
[email protected]
http://mail.gnome.org/mailman/listinfo/gnumeric-list

Reply via email to