From 93ef0d2263b3b29d96170525d3173eeec87d2254 Mon Sep 17 00:00:00 2001 From: Gergely Polonkai Date: Sun, 14 Sep 2014 23:30:25 +0200 Subject: [PATCH 1/6] Rename action export to export-agc This is to unambiguate action and function names --- src/ag-window.c | 12 ++++++------ src/resources/ui/ag-window.ui | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ag-window.c b/src/ag-window.c index 5be051f..7fe567e 100644 --- a/src/ag-window.c +++ b/src/ag-window.c @@ -898,7 +898,7 @@ ag_window_export_svg_action(GSimpleAction *action, } static void -ag_window_export(AgWindow *window, GError **err) +ag_window_export_agc(AgWindow *window, GError **err) { const gchar *name; gchar *file_name; @@ -968,15 +968,15 @@ ag_window_export(AgWindow *window, GError **err) } static void -ag_window_export_action(GSimpleAction *action, - GVariant *parameter, - gpointer user_data) +ag_window_export_agc_action(GSimpleAction *action, + GVariant *parameter, + gpointer user_data) { AgWindow *window = AG_WINDOW(user_data); GError *err = NULL; ag_window_recalculate_chart(window, TRUE); - ag_window_export(window, &err); + ag_window_export_agc(window, &err); if (err) { ag_app_message_dialog( @@ -1614,7 +1614,7 @@ ag_window_connection_action(GSimpleAction *action, static GActionEntry win_entries[] = { { "close", ag_window_close_action, NULL, NULL, NULL }, { "save", ag_window_save_action, NULL, NULL, NULL }, - { "export", ag_window_export_action, NULL, NULL, NULL }, + { "export-agc", ag_window_export_agc_action, NULL, NULL, NULL }, { "export-svg", ag_window_export_svg_action, NULL, NULL, NULL }, { "view-menu", ag_window_view_menu_action, NULL, "false", NULL }, { "gear-menu", ag_window_gear_menu_action, NULL, "false", NULL }, diff --git a/src/resources/ui/ag-window.ui b/src/resources/ui/ag-window.ui index f4f4189..3c2a80f 100644 --- a/src/resources/ui/ag-window.ui +++ b/src/resources/ui/ag-window.ui @@ -39,7 +39,7 @@ Export… - win.export + win.export-agc <Primary><Shift>e From 8e60f5611cd1eb69f370b1089d77be8ee3be2116 Mon Sep 17 00:00:00 2001 From: Gergely Polonkai Date: Wed, 17 Sep 2014 10:38:00 +0200 Subject: [PATCH 2/6] Refactor SVG save action/dialog to be a general image saving function --- src/ag-chart.h | 2 + src/ag-window.c | 215 +++++++++++++++++++++++++++++----- src/astrognome.c | 6 + src/astrognome.h | 1 + src/resources/ui/ag-window.ui | 4 +- 5 files changed, 196 insertions(+), 32 deletions(-) diff --git a/src/ag-chart.h b/src/ag-chart.h index 12e97ec..03bb0d6 100644 --- a/src/ag-chart.h +++ b/src/ag-chart.h @@ -43,6 +43,8 @@ struct _AgChartClass { GsweMomentClass parent_class; }; +typedef void (*AgChartSaveImageFunc)(AgChart *, GFile *, GError **); + GType ag_chart_get_type(void) G_GNUC_CONST; AgChart *ag_chart_new_full(GsweTimestamp *timestamp, diff --git a/src/ag-window.c b/src/ag-window.c index 7fe567e..91f6dc9 100644 --- a/src/ag-window.c +++ b/src/ag-window.c @@ -808,12 +808,12 @@ ag_window_recalculate_chart(AgWindow *window, gboolean set_everything) } static void -ag_window_export_svg(AgWindow *window, GError **err) +ag_window_export_image(AgWindow *window, GError **err) { const gchar *name; - gchar *file_name; GtkWidget *fs; gint response; + GError *local_err = NULL; AgWindowPrivate *priv = ag_window_get_instance_private(window); ag_window_recalculate_chart(window, TRUE); @@ -851,41 +851,196 @@ ag_window_export_svg(AgWindow *window, GError **err) return; } - file_name = g_strdup_printf("%s.svg", name); - fs = gtk_file_chooser_dialog_new(_("Export Chart as SVG"), GTK_WINDOW(window), GTK_FILE_CHOOSER_ACTION_SAVE, _("_Cancel"), GTK_RESPONSE_CANCEL, _("_Save"), GTK_RESPONSE_ACCEPT, NULL); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(fs), filter_svg); + gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(fs), filter_svg); gtk_dialog_set_default_response(GTK_DIALOG(fs), GTK_RESPONSE_ACCEPT); gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(fs), FALSE); - gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(fs), TRUE); - gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(fs), file_name); - g_free(file_name); + // Due to file name modifying later (depending on the file type selection), + // we must do this manually + gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(fs), FALSE); + gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(fs), name); - response = gtk_dialog_run(GTK_DIALOG(fs)); - gtk_widget_hide(fs); + while (TRUE) { + response = gtk_dialog_run(GTK_DIALOG(fs)); + gtk_widget_hide(fs); - if (response == GTK_RESPONSE_ACCEPT) { - GFile *file = gtk_file_chooser_get_file(GTK_FILE_CHOOSER(fs)); + if (response == GTK_RESPONSE_ACCEPT) { + GFile *file = gtk_file_chooser_get_file( + GTK_FILE_CHOOSER(fs) + ); + GtkFileFilter *filter = gtk_file_chooser_get_filter( + GTK_FILE_CHOOSER(fs) + ); + gchar *filename = g_file_get_uri(file), + *extension, + *current_extension; + AgChartSaveImageFunc save_func = NULL; + gboolean can_save = FALSE; - ag_chart_export_svg_to_file(priv->chart, file, err); + if (filter == filter_svg) { + extension = ".svg"; + save_func = &ag_chart_export_svg_to_file; + } else { + g_warning("Unknown file type"); + gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(fs), filter_svg); + } + + current_extension = g_utf8_strrchr(filename, -1, '.'); + + if (current_extension == NULL) { + gchar *tmp; + + tmp = filename; + filename = g_strdup_printf("%s%s", tmp, extension); + g_free(tmp); + } else { + GFileInfo *fileinfo; + GFile *tmp_file; + gboolean valid; + GtkFileFilterInfo filter_info; + + tmp_file = g_file_new_for_uri(filename); + fileinfo = g_file_query_info( + tmp_file, + G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME, + G_FILE_QUERY_INFO_NONE, + NULL, + NULL + ); + g_object_unref(tmp_file); + + filter_info.contains = + GTK_FILE_FILTER_URI + | GTK_FILE_FILTER_DISPLAY_NAME; + filter_info.uri = filename; + filter_info.display_name = g_file_info_get_display_name( + fileinfo + ); + + valid = gtk_file_filter_filter(filter, &filter_info); + g_object_unref(fileinfo); + + if (!valid) { + GtkResponseType response; + gchar *message, + *new_filename; + + new_filename = g_strdup_printf("%s%s", filename, extension); + + message = g_strdup_printf( + "File extension doesn’t match the chosen format. " \ + "Do you want Astrognome to append the correct " \ + "extension (the new filename will be %s) or " \ + "choose a new name?", + new_filename + ); + + response = ag_app_buttoned_dialog( + GTK_WINDOW(window), + GTK_MESSAGE_QUESTION, + message, + "Cancel", GTK_RESPONSE_CANCEL, + "Append extension", GTK_RESPONSE_APPLY, + "Choose new file", GTK_RESPONSE_NO, + NULL + ); + + if (response == GTK_RESPONSE_APPLY) { + g_free(filename); + filename = new_filename; + } else { + g_free(filename); + g_clear_object(&file); + + if (response == GTK_RESPONSE_NO) { + continue; + } + + break; + } + } + } + + g_clear_object(&file); + file = g_file_new_for_uri(filename); + g_free(filename); + + // Now check if a file under the modified name exists + if (g_file_query_exists(file, NULL)) { + GtkResponseType sub_response; + gchar *message; + GFileInfo *fileinfo; + + fileinfo = g_file_query_info( + file, + G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME, + G_FILE_QUERY_INFO_NONE, + NULL, + NULL + ); + message = g_strdup_printf( + "File %s already exists. Do you want to overwrite it?", + g_file_info_get_display_name(fileinfo) + ); + g_object_unref(fileinfo); + + sub_response = ag_app_buttoned_dialog( + GTK_WINDOW(window), GTK_MESSAGE_QUESTION, + message, + _("No"), GTK_RESPONSE_NO, + _("Yes"), GTK_RESPONSE_YES, + NULL + ); + + g_free(message); + + can_save = (sub_response == GTK_RESPONSE_YES); + } else { + can_save = TRUE; + } + + if (can_save) { + g_clear_error(&local_err); + save_func(priv->chart, file, &local_err); + + if (local_err) { + ag_app_message_dialog( + GTK_WINDOW(window), + GTK_MESSAGE_ERROR, + "%s", + local_err->message + ); + } + + g_clear_object(&file); + + break; + } + + g_clear_object(&file); + } else { + break; + } } gtk_widget_destroy(fs); } static void -ag_window_export_svg_action(GSimpleAction *action, - GVariant *parameter, - gpointer user_data) +ag_window_export_image_action(GSimpleAction *action, + GVariant *parameter, + gpointer user_data) { AgWindow *window = AG_WINDOW(user_data); - GError *err = NULL; + GError *err = NULL; - ag_window_export_svg(window, &err); + ag_window_export_image(window, &err); if (err) { ag_app_message_dialog( @@ -1612,19 +1767,19 @@ ag_window_connection_action(GSimpleAction *action, } static GActionEntry win_entries[] = { - { "close", ag_window_close_action, NULL, NULL, NULL }, - { "save", ag_window_save_action, NULL, NULL, NULL }, - { "export-agc", ag_window_export_agc_action, NULL, NULL, NULL }, - { "export-svg", ag_window_export_svg_action, NULL, NULL, NULL }, - { "view-menu", ag_window_view_menu_action, NULL, "false", NULL }, - { "gear-menu", ag_window_gear_menu_action, NULL, "false", NULL }, - { "change-tab", ag_window_change_tab_action, "s", "'edit'", NULL }, - { "new-chart", ag_window_new_chart_action, NULL, NULL, NULL }, - { "back", ag_window_back_action, NULL, NULL, NULL }, - { "refresh", ag_window_refresh_action, NULL, NULL, NULL }, - { "selection", ag_window_selection_mode_action, NULL, "false", NULL }, - { "delete", ag_window_delete_action, NULL, NULL, NULL }, - { "connection", ag_window_connection_action, "s", "'aspects'", NULL }, + { "close", ag_window_close_action, NULL, NULL, NULL }, + { "save", ag_window_save_action, NULL, NULL, NULL }, + { "export-agc", ag_window_export_agc_action, NULL, NULL, NULL }, + { "export-image", ag_window_export_image_action, NULL, NULL, NULL }, + { "view-menu", ag_window_view_menu_action, NULL, "false", NULL }, + { "gear-menu", ag_window_gear_menu_action, NULL, "false", NULL }, + { "change-tab", ag_window_change_tab_action, "s", "'edit'", NULL }, + { "new-chart", ag_window_new_chart_action, NULL, NULL, NULL }, + { "back", ag_window_back_action, NULL, NULL, NULL }, + { "refresh", ag_window_refresh_action, NULL, NULL, NULL }, + { "selection", ag_window_selection_mode_action, NULL, "false", NULL }, + { "delete", ag_window_delete_action, NULL, NULL, NULL }, + { "connection", ag_window_connection_action, "s", "'aspects'", NULL }, }; static void diff --git a/src/astrognome.c b/src/astrognome.c index 85e71db..9f3c87c 100644 --- a/src/astrognome.c +++ b/src/astrognome.c @@ -24,6 +24,7 @@ GtkBuilder *builder; GtkFileFilter *filter_all = NULL; GtkFileFilter *filter_chart = NULL; GtkFileFilter *filter_hor = NULL; +GtkFileFilter *filter_svg = NULL; GtkTreeModel *country_list = NULL; GtkTreeModel *city_list = NULL; GHashTable *xinclude_positions; @@ -84,6 +85,11 @@ init_filters(void) gtk_file_filter_set_name(filter_hor, _("Placidus charts")); gtk_file_filter_add_pattern(filter_hor, "*.hor"); g_object_ref_sink(filter_hor); + + filter_svg = gtk_file_filter_new(); + gtk_file_filter_set_name(filter_svg, _("SVG image")); + gtk_file_filter_add_pattern(filter_svg, "*.svg"); + g_object_ref_sink(filter_svg); } static int diff --git a/src/astrognome.h b/src/astrognome.h index 9697c32..0288e9b 100644 --- a/src/astrognome.h +++ b/src/astrognome.h @@ -13,6 +13,7 @@ typedef struct { extern GtkFileFilter *filter_all; extern GtkFileFilter *filter_chart; extern GtkFileFilter *filter_hor; +extern GtkFileFilter *filter_svg; extern GtkTreeModel *country_list; extern GtkTreeModel *city_list; extern const GswePlanet used_planets[]; diff --git a/src/resources/ui/ag-window.ui b/src/resources/ui/ag-window.ui index 3c2a80f..9f0701f 100644 --- a/src/resources/ui/ag-window.ui +++ b/src/resources/ui/ag-window.ui @@ -45,8 +45,8 @@
- Export as SVG - win.export-svg + Export as image… + win.export-image
From e87adf84975cde2c0dffe6cf30a8a8e8bb077bc7 Mon Sep 17 00:00:00 2001 From: Gergely Polonkai Date: Wed, 17 Sep 2014 11:18:09 +0200 Subject: [PATCH 3/6] Fix chart XSL file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The resulting image didn’t comply with the SVG standard, as it accidentally had some IDs prefixed with ‘#’ --- src/resources/ui/chart-default.xsl | 72 +++++++++++++++--------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/src/resources/ui/chart-default.xsl b/src/resources/ui/chart-default.xsl index 168d77c..cdbe30d 100644 --- a/src/resources/ui/chart-default.xsl +++ b/src/resources/ui/chart-default.xsl @@ -8,7 +8,7 @@ method="xml" media-type="image/svg+xml" doctype-public="-//W3C//DTD SVG 1.0//EN" - doctype-system="http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd" + doctype-system="http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd" version="1.0" encoding="UTF-8" indent="yes"/> @@ -185,41 +185,41 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 2cf75ede55251a4ddcab2ea510eb513de24ceeb8 Mon Sep 17 00:00:00 2001 From: Gergely Polonkai Date: Wed, 17 Sep 2014 11:19:57 +0200 Subject: [PATCH 4/6] Add GDK-PixBuf and librsvg2 as a dependency They are required for JPEG exporting --- configure.ac | 2 ++ src/Makefile.am | 4 ++-- src/ag-chart.c | 5 +++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index ebd3401..f50537a 100644 --- a/configure.ac +++ b/configure.ac @@ -37,6 +37,8 @@ PKG_CHECK_MODULES([LIBXML], [libxml-2.0]) PKG_CHECK_MODULES([LIBXSLT], [libexslt]) PKG_CHECK_MODULES([WEBKIT], [webkit2gtk-4.0]) PKG_CHECK_MODULES([GDA], [libgda-5.0 libgda-sqlite-5.0]) +PKG_CHECK_MODULES([PIXBUF], [gdk-pixbuf-2.0]) +PKG_CHECK_MODULES([RSVG], [librsvg-2.0]) PKG_CHECK_MODULES([SWE_GLIB], [swe-glib >= 2.1.0]) LIBGD_INIT([ diff --git a/src/Makefile.am b/src/Makefile.am index e681b70..f7438cf 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -32,7 +32,7 @@ AM_CPPFLAGS = -DG_LOG_DOMAIN=\"Astrognome\" -DLOCALEDIR=\"$(localedir)\" -DPKGDA bin_PROGRAMS = astrognome astrognome_SOURCES = $(astrognome_source_files) $(BUILT_SOURCES) -astrognome_LDADD = $(SWE_GLIB_LIBS) $(GTK_LIBS) $(LIBXML_LIBS) $(LIBXSLT_LIBS) $(WEBKIT_LIBS) $(GDA_LIBS) $(top_builddir)/libgd/libgd.la +astrognome_LDADD = $(SWE_GLIB_LIBS) $(GTK_LIBS) $(LIBXML_LIBS) $(LIBXSLT_LIBS) $(WEBKIT_LIBS) $(GDA_LIBS) $(PIXBUF_LIBS) $(RSVG_LIBS) $(top_builddir)/libgd/libgd.la astrognome_LDFLAGS = -rdynamic -astrognome_CFLAGS = $(SWE_GLIB_CFLAGS) $(CFLAGS) $(GTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBXSLT_CFLAGS) $(WEBKIT_CFLAGS) $(GDA_CFLAGS) -Wall +astrognome_CFLAGS = $(SWE_GLIB_CFLAGS) $(CFLAGS) $(GTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBXSLT_CFLAGS) $(WEBKIT_CFLAGS) $(GDA_CFLAGS) $(PIXBUF_CFLAGS) $(RSVG_CFLAGS) -Wall diff --git a/src/ag-chart.c b/src/ag-chart.c index 2d73769..66a59b7 100644 --- a/src/ag-chart.c +++ b/src/ag-chart.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "config.h" #include "astrognome.h" @@ -41,6 +42,10 @@ typedef enum { XML_CONVERT_INT } XmlConvertType; +#if !LIBRSVG_HAVE_CSS +# error "We need RSVG CSS support to export charts as images!" +#endif + G_DEFINE_QUARK(ag_chart_error_quark, ag_chart_error); G_DEFINE_TYPE_WITH_PRIVATE(AgChart, ag_chart, GSWE_TYPE_MOMENT); From 7fe6a1640193acd3fe381696cde867ee0b63f05b Mon Sep 17 00:00:00 2001 From: Gergely Polonkai Date: Wed, 17 Sep 2014 11:22:17 +0200 Subject: [PATCH 5/6] Add a rendering parameter to ag_chart_create_svg() Based upon this parameter a is included in the resulting SVG document, providing a background color, and so is the chart CSS. --- src/ag-chart.c | 20 ++++++++++++++++---- src/ag-chart.h | 7 ++++--- src/ag-window.c | 1 + src/resources/ui/chart-default.css | 4 ++++ src/resources/ui/chart-default.xsl | 19 +++++++++++++++++++ 5 files changed, 44 insertions(+), 7 deletions(-) diff --git a/src/ag-chart.c b/src/ag-chart.c index 66a59b7..9b64ba0 100644 --- a/src/ag-chart.c +++ b/src/ag-chart.c @@ -1393,7 +1393,11 @@ ag_chart_sort_planets_by_position(GswePlanetData *planet1, } gchar * -ag_chart_create_svg(AgChart *chart, gsize *length, GError **err) +ag_chart_create_svg( + AgChart *chart, + gsize *length, + gboolean rendering, + GError **err) { xmlDocPtr doc = create_save_doc(chart), xslt_doc, @@ -1406,7 +1410,8 @@ ag_chart_create_svg(AgChart *chart, gsize *length, GError **err) antiscia_node = NULL, node = NULL; gchar *value, - *save_content = NULL; + *save_content = NULL, + **params; const gchar *xslt_content; GList *houses, *house, @@ -1710,15 +1715,22 @@ ag_chart_create_svg(AgChart *chart, gsize *length, GError **err) return NULL; } + params = g_new0(gchar *, 3); + params[0] = "rendering"; + params[1] = (rendering) ? "'yes'" : "'no'"; + // libxml2 messes up the output, as it prints decimal floating point // numbers in a localized format. It is not good in locales that use a // character for decimal separator other than a dot. So let's just use the // C locale until the SVG is generated. current_locale = uselocale(newlocale(LC_ALL, "C", 0)); - svg_doc = xsltApplyStylesheet(xslt_proc, doc, NULL); + + svg_doc = xsltApplyStylesheet(xslt_proc, doc, (const char **)params); + uselocale(current_locale); xsltFreeStylesheet(xslt_proc); xmlFreeDoc(doc); + g_free(params); // Now, svg_doc contains the generated SVG file @@ -1752,7 +1764,7 @@ ag_chart_export_svg_to_file(AgChart *chart, GFile *file, GError **err) gchar *svg; gsize length; - if ((svg = ag_chart_create_svg(chart, &length, err)) == NULL) { + if ((svg = ag_chart_create_svg(chart, &length, TRUE, err)) == NULL) { return; } diff --git a/src/ag-chart.h b/src/ag-chart.h index 03bb0d6..8149d73 100644 --- a/src/ag-chart.h +++ b/src/ag-chart.h @@ -84,9 +84,10 @@ void ag_chart_set_city(AgChart *chart, const gchar *ag_chart_get_city(AgChart *chart); -gchar *ag_chart_create_svg(AgChart *chart, - gsize *length, - GError **err); +gchar *ag_chart_create_svg(AgChart *chart, + gsize *length, + gboolean rendering, + GError **err); GList *ag_chart_get_planets(AgChart *chart); diff --git a/src/ag-window.c b/src/ag-window.c index 91f6dc9..b115a6b 100644 --- a/src/ag-window.c +++ b/src/ag-window.c @@ -496,6 +496,7 @@ ag_window_redraw_chart(AgWindow *window) gchar *svg_content = ag_chart_create_svg( priv->chart, &length, + FALSE, &err ); diff --git a/src/resources/ui/chart-default.css b/src/resources/ui/chart-default.css index cb74e88..dd3413f 100644 --- a/src/resources/ui/chart-default.css +++ b/src/resources/ui/chart-default.css @@ -134,3 +134,7 @@ line.antiscion { stroke: #000000; stroke-dasharray: 20,10; } + +#background { + fill: #ffffff; +} diff --git a/src/resources/ui/chart-default.xsl b/src/resources/ui/chart-default.xsl index cdbe30d..552d744 100644 --- a/src/resources/ui/chart-default.xsl +++ b/src/resources/ui/chart-default.xsl @@ -69,6 +69,15 @@ version="1.0"> + + + + + + + <xsl:value-of select="concat( 'Natal chart of ', @@ -116,6 +125,16 @@ <polygon points="0.0,0.0 7.0,-2.0 5.0,0.0 7.0,2.0" /> </marker> </defs> + + <xsl:choose> + <xsl:when test="$rendering='yes'"> + <rect id="background" x="0" y="0"> + <xsl:attribute name="width"><xsl:value-of select="$image_size"/></xsl:attribute> + <xsl:attribute name="height"><xsl:value-of select="$image_size"/></xsl:attribute> + </rect> + </xsl:when> + </xsl:choose> + <g id="chart"> <xsl:attribute name="transform"><xsl:value-of select="concat('translate(', $image_size div 2, ',', $image_size div 2, ')')" /></xsl:attribute> <g id="moonless_chart"> From 290d8c3f37dacb095f6a2a03750d75734d9d23d8 Mon Sep 17 00:00:00 2001 From: Gergely Polonkai <gergely@polonkai.eu> Date: Wed, 17 Sep 2014 11:22:49 +0200 Subject: [PATCH 6/6] Add JPEG export support --- src/ag-chart.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++ src/ag-chart.h | 5 ++++ src/ag-window.c | 4 +++ src/astrognome.c | 8 ++++++ src/astrognome.h | 1 + 5 files changed, 86 insertions(+) diff --git a/src/ag-chart.c b/src/ag-chart.c index 9b64ba0..e25cf7e 100644 --- a/src/ag-chart.c +++ b/src/ag-chart.c @@ -11,6 +11,8 @@ #include <math.h> #include <string.h> #include <librsvg/rsvg.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <glib/gi18n.h> #include "config.h" #include "astrognome.h" @@ -1781,6 +1783,72 @@ ag_chart_export_svg_to_file(AgChart *chart, GFile *file, GError **err) ); } +void +ag_chart_export_jpg_to_file(AgChart *chart, GFile *file, GError **err) +{ + gchar *svg, + *jpg; + gsize svg_length, + jpg_length; + RsvgHandle *svg_handle; + GdkPixbuf *pixbuf; + + if ((svg = ag_chart_create_svg(chart, &svg_length, TRUE, err)) == NULL) { + return; + } + + if ((svg_handle = rsvg_handle_new_from_data( + (const guint8 *)svg, + svg_length, + err + )) == NULL) { + g_free(svg); + + return; + } + + g_free(svg); + + if ((pixbuf = rsvg_handle_get_pixbuf(svg_handle)) == NULL) { + g_set_error( + err, + AG_CHART_ERROR, AG_CHART_ERROR_RENDERING_ERROR, + _("Unknown rendering error") + ); + + return; + } + + if (!gdk_pixbuf_save_to_buffer( + pixbuf, + &jpg, + &jpg_length, + "jpeg", + err, + NULL + )) { + g_object_unref(pixbuf); + + return; + } + + g_object_unref(pixbuf); + + g_file_replace_contents( + file, + (const gchar *)jpg, + jpg_length, + NULL, + FALSE, + G_FILE_CREATE_NONE, + NULL, + NULL, + err + ); + + g_free(jpg); +} + void ag_chart_set_note(AgChart *chart, const gchar *note) { diff --git a/src/ag-chart.h b/src/ag-chart.h index 8149d73..517ae43 100644 --- a/src/ag-chart.h +++ b/src/ag-chart.h @@ -17,6 +17,7 @@ typedef enum { AG_CHART_ERROR_NOT_IMPLEMENTED, AG_CHART_ERROR_INVALID_PLAC_FILE, AG_CHART_ERROR_UNSUPPORTED_PLAC_FILE, + AG_CHART_ERROR_RENDERING_ERROR, } AgChartError; #define AG_TYPE_CHART (ag_chart_get_type()) @@ -69,6 +70,10 @@ void ag_chart_export_svg_to_file(AgChart *chart, GFile *file, GError **err); +void ag_chart_export_jpg_to_file(AgChart *chart, + GFile *file, + GError **err); + void ag_chart_set_name(AgChart *chart, const gchar *name); diff --git a/src/ag-window.c b/src/ag-window.c index b115a6b..731e86f 100644 --- a/src/ag-window.c +++ b/src/ag-window.c @@ -859,6 +859,7 @@ ag_window_export_image(AgWindow *window, GError **err) _("_Save"), GTK_RESPONSE_ACCEPT, NULL); gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(fs), filter_svg); + gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(fs), filter_jpg); gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(fs), filter_svg); gtk_dialog_set_default_response(GTK_DIALOG(fs), GTK_RESPONSE_ACCEPT); gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(fs), FALSE); @@ -887,6 +888,9 @@ ag_window_export_image(AgWindow *window, GError **err) if (filter == filter_svg) { extension = ".svg"; save_func = &ag_chart_export_svg_to_file; + } else if (filter == filter_jpg) { + extension = ".jpg"; + save_func = &ag_chart_export_jpg_to_file; } else { g_warning("Unknown file type"); gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(fs), filter_svg); diff --git a/src/astrognome.c b/src/astrognome.c index 9f3c87c..039a783 100644 --- a/src/astrognome.c +++ b/src/astrognome.c @@ -25,6 +25,7 @@ GtkFileFilter *filter_all = NULL; GtkFileFilter *filter_chart = NULL; GtkFileFilter *filter_hor = NULL; GtkFileFilter *filter_svg = NULL; +GtkFileFilter *filter_jpg = NULL; GtkTreeModel *country_list = NULL; GtkTreeModel *city_list = NULL; GHashTable *xinclude_positions; @@ -90,6 +91,13 @@ init_filters(void) gtk_file_filter_set_name(filter_svg, _("SVG image")); gtk_file_filter_add_pattern(filter_svg, "*.svg"); g_object_ref_sink(filter_svg); + + filter_jpg = gtk_file_filter_new(); + gtk_file_filter_set_name(filter_jpg, _("JPEG image")); + gtk_file_filter_add_pattern(filter_jpg, "*.jpg"); + gtk_file_filter_add_pattern(filter_jpg, "*.jpe"); + gtk_file_filter_add_pattern(filter_jpg, "*.jpeg"); + g_object_ref_sink(filter_jpg); } static int diff --git a/src/astrognome.h b/src/astrognome.h index 0288e9b..e087a09 100644 --- a/src/astrognome.h +++ b/src/astrognome.h @@ -14,6 +14,7 @@ extern GtkFileFilter *filter_all; extern GtkFileFilter *filter_chart; extern GtkFileFilter *filter_hor; extern GtkFileFilter *filter_svg; +extern GtkFileFilter *filter_jpg; extern GtkTreeModel *country_list; extern GtkTreeModel *city_list; extern const GswePlanet used_planets[];