Code

SPDocument->Document
[inkscape.git] / src / main.cpp
index 5e1e6f64b357ce62f7ce185c6798f7aceefe6919..64fcb664dd431985aa5c35cbab3da214454d1dda 100644 (file)
@@ -28,6 +28,9 @@
 #endif
 #include "path-prefix.h"
 
+// This has to be included prior to anything that includes setjmp.h, it croaks otherwise
+#include <png.h>
+
 #include <gtk/gtkmessagedialog.h>
 
 #ifdef HAVE_IEEEFP_H
@@ -45,6 +48,7 @@
 
 #include <libxml/tree.h>
 #include <glib-object.h>
+#include <gtk/gtk.h>
 #include <gtk/gtkmain.h>
 #include <gtk/gtksignal.h>
 #include <gtk/gtkwindow.h>
@@ -68,8 +72,7 @@
 #include "svg/stringstream.h"
 
 #include "inkscape-private.h"
-#include "inkscape-stock.h"
-#include "inkscape_version.h"
+#include "inkscape-version.h"
 
 #include "sp-namedview.h"
 #include "sp-guide.h"
@@ -82,6 +85,7 @@
 #include "debug/log-display-config.h"
 
 #include "helper/png-write.h"
+#include "helper/geom.h"
 
 #include <extension/extension.h>
 #include <extension/system.h>
@@ -109,10 +113,10 @@ using Inkscape::Extension::Internal::PrintWin32;
 #endif
 
 #include "application/application.h"
-
 #include "main-cmdlineact.h"
+#include "widgets/icon.h"
+#include "ui/widget/panel.h"
 
-#include <png.h>
 #include <errno.h>
 
 enum {
@@ -142,6 +146,7 @@ enum {
     SP_ARG_EXPORT_EMF,
 #endif //WIN32
     SP_ARG_EXPORT_TEXT_TO_PATH,
+    SP_ARG_EXPORT_IGNORE_FILTERS,
     SP_ARG_EXTENSIONDIR,
     SP_ARG_QUERY_X,
     SP_ARG_QUERY_Y,
@@ -160,13 +165,13 @@ enum {
 
 int sp_main_gui(int argc, char const **argv);
 int sp_main_console(int argc, char const **argv);
-static void sp_do_export_png(SPDocument *doc);
-static void do_export_ps_pdf(SPDocument* doc, gchar const* uri, char const *mime);
+static void sp_do_export_png(Document *doc);
+static void do_export_ps_pdf(Document* doc, gchar const* uri, char const *mime);
 #ifdef WIN32
-static void do_export_emf(SPDocument* doc, gchar const* uri, char const *mime);
+static void do_export_emf(Document* doc, gchar const* uri, char const *mime);
 #endif //WIN32
-static void do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gchar *id);
-static void do_query_all (SPDocument *doc);
+static void do_query_dimension (Document *doc, bool extent, Geom::Dim2 const axis, const gchar *id);
+static void do_query_all (Document *doc);
 static void do_query_all_recurse (SPObject *o);
 
 static gchar *sp_global_printer = NULL;
@@ -191,6 +196,7 @@ static gchar *sp_export_pdf = NULL;
 static gchar *sp_export_emf = NULL;
 #endif //WIN32
 static gboolean sp_export_text_to_path = FALSE;
+static gboolean sp_export_ignore_filters = FALSE;
 static gboolean sp_export_font = FALSE;
 static gboolean sp_query_x = FALSE;
 static gboolean sp_query_y = FALSE;
@@ -233,6 +239,7 @@ static void resetCommandlineGlobals() {
         sp_export_emf = NULL;
 #endif //WIN32
         sp_export_text_to_path = FALSE;
+        sp_export_ignore_filters = FALSE;
         sp_export_font = FALSE;
         sp_query_x = FALSE;
         sp_query_y = FALSE;
@@ -284,7 +291,7 @@ struct poptOption options[] = {
 
     {"export-dpi", 'd',
      POPT_ARG_STRING, &sp_export_dpi, SP_ARG_EXPORT_DPI,
-     N_("The resolution used for exporting SVG into bitmap (default 90)"),
+     N_("Resolution for exporting to bitmap and for rasterization of filters in PS/EPS/PDF (default 90)"),
      N_("DPI")},
 
     {"export-area", 'a',
@@ -373,7 +380,12 @@ struct poptOption options[] = {
 
     {"export-text-to-path", 'T',
      POPT_ARG_NONE, &sp_export_text_to_path, SP_ARG_EXPORT_TEXT_TO_PATH,
-     N_("Convert text object to paths on export (EPS)"),
+     N_("Convert text object to paths on export (PS, EPS, PDF)"),
+     NULL},
+
+    {"export-ignore-filters", 0,
+     POPT_ARG_NONE, &sp_export_ignore_filters, SP_ARG_EXPORT_IGNORE_FILTERS,
+     N_("Render filtered objects without filters, instead of rasterizing (PS, EPS, PDF)"),
      NULL},
 
     {"query-x", 'X',
@@ -438,7 +450,7 @@ struct poptOption options[] = {
 
     {"shell", 0,
      POPT_ARG_NONE, &sp_shell, SP_ARG_SHELL,
-     N_("Start Inkscape in interative shell mode."),
+     N_("Start Inkscape in interactive shell mode."),
      NULL},
 
     POPT_AUTOHELP POPT_TABLEEND
@@ -457,10 +469,12 @@ gchar * blankParam = g_strdup("");
 static Glib::ustring _win32_getExePath()
 {
     char exeName[MAX_PATH+1];
+    // TODO these should use xxxW() calls explicitly and convert UTF-16 <--> UTF-8
     GetModuleFileName(NULL, exeName, MAX_PATH);
     char *slashPos = strrchr(exeName, '\\');
-    if (slashPos)
+    if (slashPos) {
         *slashPos = '\0';
+    }
     Glib::ustring s = exeName;
     return s;
 }
@@ -471,6 +485,7 @@ static Glib::ustring _win32_getExePath()
  */
 static int _win32_set_inkscape_env(const Glib::ustring &exePath)
 {
+    // TODO use g_getenv() and g_setenv() that use filename encoding, which is UTF-8 on Windows
 
     char *oldenv = getenv("PATH");
     Glib::ustring tmp = "PATH=";
@@ -519,7 +534,7 @@ static int set_extensions_env()
         tmp += oldenv;
     }
     g_setenv("PYTHONPATH", tmp.c_str(), TRUE);
-    
+
     return 0;
 }
 
@@ -547,12 +562,16 @@ main(int argc, char **argv)
       HKCR\svgfile\shell\open\command is a good example
     */
     Glib::ustring homedir = _win32_getExePath();
+    // TODO these should use xxxW() calls explicitly and convert UTF-16 <--> UTF-8
     SetCurrentDirectory(homedir.c_str());
     _win32_set_inkscape_env(homedir);
     RegistryTool rt;
     rt.setPathInfo();
 #endif
 
+    // Prevents errors like "Unable to wrap GdkPixbuf..." (in nr-filter-image.cpp for example)
+    Gtk::Main::init_gtkmm_internals();
+
     // Bug #197475
     set_extensions_env();
 
@@ -595,6 +614,7 @@ main(int argc, char **argv)
     gboolean use_gui;
 
 #ifndef WIN32
+    // TODO use g_getenv() and g_setenv() that use filename encoding, which is UTF-8 on Windows
     use_gui = (getenv("DISPLAY") != NULL);
 #else
     use_gui = TRUE;
@@ -786,7 +806,7 @@ int sp_common_main( int argc, char const **argv, GSList **flDest )
 
 static void
 snooper(GdkEvent *event, gpointer /*data*/) {
-    if(inkscape_mapalt())  /* returns the map of the keyboard modifier to map to Alt, zero if no mapping */
+    if (inkscape_mapalt())  /* returns the map of the keyboard modifier to map to Alt, zero if no mapping */
     {
         GdkModifierType mapping=(GdkModifierType)inkscape_mapalt();
         switch (event->type) {
@@ -809,9 +829,69 @@ snooper(GdkEvent *event, gpointer /*data*/) {
             break;
         }
     }
+
+    if (inkscape_trackalt()) {
+        // MacOS X with X11 has some problem with the default
+        // xmodmapping.  A ~/.xmodmap solution does not work reliably due
+        // to the way we package our executable in a .app that can launch
+        // X11 or use an already-running X11.  The same problem has been
+        // reported on Linux but there is no .app/X11 to get in the way
+        // of ~/.xmodmap fixes.  So we make this a preference.
+        //
+        // For some reason, Gdk senses changes in Alt (Mod1) state for
+        // many message types, but not for keystrokes!  So this ugly hack
+        // tracks what the state of Alt-pressing is, and ensures
+        // GDK_MOD1_MASK is in the event->key.state as appropriate.
+        //
+        static gboolean altL_pressed = FALSE;
+        static gboolean altR_pressed = FALSE;
+        static gboolean alt_pressed = FALSE;
+        guint get_group0_keyval(GdkEventKey* event);
+        guint keyval = 0;
+        switch (event->type) {
+        case GDK_MOTION_NOTIFY:
+            alt_pressed = TRUE && (event->motion.state & GDK_MOD1_MASK);
+            break;
+        case GDK_BUTTON_PRESS:
+            alt_pressed = TRUE && (event->button.state & GDK_MOD1_MASK);
+            break;
+        case GDK_KEY_PRESS:
+            keyval = get_group0_keyval(&event->key);
+            if (keyval == GDK_Alt_L) altL_pressed = TRUE;
+            if (keyval == GDK_Alt_R) altR_pressed = TRUE;
+            alt_pressed = alt_pressed || altL_pressed || altR_pressed;
+            alt_pressed = alt_pressed || (event->button.state & GDK_MOD1_MASK);
+            if (alt_pressed)
+                event->key.state |= GDK_MOD1_MASK;
+            else
+                event->key.state &= ~GDK_MOD1_MASK;
+            break;
+        case GDK_KEY_RELEASE:
+            keyval = get_group0_keyval(&event->key);
+            if (keyval == GDK_Alt_L) altL_pressed = FALSE;
+            if (keyval == GDK_Alt_R) altR_pressed = FALSE;
+            if (!altL_pressed && !altR_pressed)
+                alt_pressed = FALSE;
+            break;
+        default:
+            break;
+        }
+        //printf("alt_pressed: %s\n", alt_pressed? "+" : "-");
+    }
+
     gtk_main_do_event (event);
 }
 
+static std::vector<Glib::ustring> getDirectorySet(const gchar* userDir, const gchar* const * systemDirs) {
+    std::vector<Glib::ustring> listing;
+    listing.push_back(userDir);
+    for ( const char* const* cur = systemDirs; *cur; cur++ )
+    {
+        listing.push_back(*cur);
+    }
+    return listing;
+}
+
 int
 sp_main_gui(int argc, char const **argv)
 {
@@ -821,19 +901,33 @@ sp_main_gui(int argc, char const **argv)
     int retVal = sp_common_main( argc, argv, &fl );
     g_return_val_if_fail(retVal == 0, 1);
 
-    inkscape_gtk_stock_init();
+    // Add possible icon entry directories
+    std::vector<Glib::ustring> dataDirs = getDirectorySet( g_get_user_data_dir(),
+                                                           g_get_system_data_dirs() );
+    for (std::vector<Glib::ustring>::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it)
+    {
+        std::vector<Glib::ustring> listing;
+        listing.push_back(*it);
+        listing.push_back("inkscape");
+        listing.push_back("icons");
+        Glib::ustring dir = Glib::build_filename(listing);
+        gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), dir.c_str());
+    }
+
+    // Add our icon directory to the search path for icon theme lookups.
+    gchar *usericondir = profile_path("icons");
+    gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), usericondir);
+    gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), INKSCAPE_PIXMAPDIR);
+    g_free(usericondir);
 
     gdk_event_handler_set((GdkEventFunc)snooper, NULL, NULL);
-
     Inkscape::Debug::log_display_config();
 
-    /* Set default icon */
-    gchar *filename = (gchar *) g_build_filename (INKSCAPE_APPICONDIR, "inkscape.png", NULL);
-    if (Inkscape::IO::file_test(filename, (GFileTest)(G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_SYMLINK))) {
-        gtk_window_set_default_icon_from_file(filename, NULL);
-    }
-    g_free (filename);
-    filename = 0;
+    // Set default window icon. Obeys the theme.
+    gtk_window_set_default_icon_name("inkscape");
+    // Do things that were previously in inkscape_gtk_stock_init().
+    sp_icon_get_phys_size(GTK_ICON_SIZE_MENU);
+    Inkscape::UI::Widget::Panel::prep();
 
     gboolean create_new = TRUE;
 
@@ -868,7 +962,7 @@ void sp_process_file_list(GSList *fl)
 {
     while (fl) {
         const gchar *filename = (gchar *)fl->data;
-        SPDocument *doc = Inkscape::Extension::open(NULL, filename);
+        Document *doc = Inkscape::Extension::open(NULL, filename);
         if (doc == NULL) {
             doc = Inkscape::Extension::open(Inkscape::Extension::db.get(SP_MODULE_KEY_INPUT_SVG), filename);
         }
@@ -894,7 +988,8 @@ void sp_process_file_list(GSList *fl)
                 rdoc = sp_repr_document_new("svg:svg");
                 repr = rdoc->root();
                 repr = sp_document_root(doc)->updateRepr(rdoc, repr, SP_OBJECT_WRITE_BUILD);
-                sp_repr_save_file(repr->document(), sp_export_svg, SP_SVG_NS_URI);
+                sp_repr_save_rebased_file(repr->document(), sp_export_svg, SP_SVG_NS_URI,
+                                          doc->base, sp_export_svg);
             }
             if (sp_export_ps) {
                 do_export_ps_pdf(doc, sp_export_ps, "image/x-postscript");
@@ -913,9 +1008,9 @@ void sp_process_file_list(GSList *fl)
             if (sp_query_all) {
                 do_query_all (doc);
             } else if (sp_query_width || sp_query_height) {
-                do_query_dimension (doc, true, sp_query_width? NR::X : NR::Y, sp_query_id);
+                do_query_dimension (doc, true, sp_query_width? Geom::X : Geom::Y, sp_query_id);
             } else if (sp_query_x || sp_query_y) {
-                do_query_dimension (doc, false, sp_query_x? NR::X : NR::Y, sp_query_id);
+                do_query_dimension (doc, false, sp_query_x? Geom::X : Geom::Y, sp_query_id);
             }
 
             delete doc;
@@ -939,7 +1034,7 @@ int sp_main_shell(char const* command_name)
     gsize sizeLeft = buffer_size - offset;
     gchar *useme = command_line + offset;
 
-    fprintf(stdout, "Inkscape %s interactive shell mode. Type 'quit' to quit.\n", INKSCAPE_VERSION);
+    fprintf(stdout, "Inkscape %s interactive shell mode. Type 'quit' to quit.\n", Inkscape::version_string);
     fflush(stdout);
     char* linedata = 0;
     do {
@@ -1032,7 +1127,7 @@ int sp_main_console(int argc, char const **argv)
 }
 
 static void
-do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gchar *id)
+do_query_dimension (Document *doc, bool extent, Geom::Dim2 const axis, const gchar *id)
 {
     SPObject *o = NULL;
 
@@ -1056,7 +1151,7 @@ do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gch
         SPItem *item = ((SPItem *) o);
 
         // "true" SVG bbox for scripting
-        boost::optional<Geom::Rect> area = item->getBounds(sp_item_i2doc_affine(item));
+        Geom::OptRect area = item->getBounds(sp_item_i2doc_affine(item));
         if (area) {
             Inkscape::SVGOStringStream os;
             if (extent) {
@@ -1072,7 +1167,7 @@ do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gch
 }
 
 static void
-do_query_all (SPDocument *doc)
+do_query_all (Document *doc)
 {
     SPObject *o = NULL;
 
@@ -1089,7 +1184,7 @@ do_query_all_recurse (SPObject *o)
 {
     SPItem *item = ((SPItem *) o);
     if (o->id && SP_IS_ITEM(item)) {
-        boost::optional<Geom::Rect> area = item->getBounds(sp_item_i2doc_affine(item));
+        Geom::OptRect area = item->getBounds(sp_item_i2doc_affine(item));
         if (area) {
             Inkscape::SVGOStringStream os;
             os << o->id;
@@ -1110,7 +1205,7 @@ do_query_all_recurse (SPObject *o)
 
 
 static void
-sp_do_export_png(SPDocument *doc)
+sp_do_export_png(Document *doc)
 {
     const gchar *filename = NULL;
     gdouble dpi = 0.0;
@@ -1121,7 +1216,7 @@ sp_do_export_png(SPDocument *doc)
 
     GSList *items = NULL;
 
-    NRRect area;
+    Geom::Rect area;
     if (sp_export_id || sp_export_area_drawing) {
 
         SPObject *o = NULL;
@@ -1181,10 +1276,10 @@ sp_do_export_png(SPDocument *doc)
 
             // write object bbox to area
             sp_document_ensure_up_to_date (doc);
-            boost::optional<Geom::Rect> areaMaybe;
-            sp_item_invoke_bbox((SPItem *) o_area, areaMaybe, sp_item_i2r_affine((SPItem *) o_area), TRUE);
+            Geom::OptRect areaMaybe;
+            sp_item_invoke_bbox((SPItem *) o_area, areaMaybe, sp_item_i2d_affine((SPItem *) o_area), TRUE);
             if (areaMaybe) {
-                area = NRRect(areaMaybe);
+                area = *areaMaybe;
             } else {
                 g_warning("Unable to determine a valid bounding box. Nothing exported.");
                 return;
@@ -1197,21 +1292,17 @@ sp_do_export_png(SPDocument *doc)
 
     if (sp_export_area) {
         /* Try to parse area (given in SVG pixels) */
-        if (!sscanf(sp_export_area, "%lg:%lg:%lg:%lg", &area.x0, &area.y0, &area.x1, &area.y1) == 4) {
+        gdouble x0,y0,x1,y1;
+        if (!sscanf(sp_export_area, "%lg:%lg:%lg:%lg", &x0, &y0, &x1, &y1) == 4) {
             g_warning("Cannot parse export area '%s'; use 'x0:y0:x1:y1'. Nothing exported.", sp_export_area);
             return;
         }
-        if ((area.x0 >= area.x1) || (area.y0 >= area.y1)) {
-            g_warning("Export area '%s' has negative width or height. Nothing exported.", sp_export_area);
-            return;
-        }
+        area = Geom::Rect(Geom::Interval(x0,x1), Geom::Interval(y0,y1));
     } else if (sp_export_area_canvas || !(sp_export_id || sp_export_area_drawing)) {
         /* Export the whole canvas */
         sp_document_ensure_up_to_date (doc);
-        area.x0 = SP_ROOT(doc->root)->x.computed;
-        area.y0 = SP_ROOT(doc->root)->y.computed;
-        area.x1 = area.x0 + sp_document_width (doc);
-        area.y1 = area.y0 + sp_document_height (doc);
+        Geom::Point origin (SP_ROOT(doc->root)->x.computed, SP_ROOT(doc->root)->y.computed);
+        area = Geom::Rect(origin, origin + sp_document_dimensions(doc));
     }
 
     // set filename and dpi from options, if not yet set from the hints
@@ -1233,10 +1324,7 @@ sp_do_export_png(SPDocument *doc)
     }
 
     if (sp_export_area_snap) {
-        area.x0 = std::floor (area.x0);
-        area.y0 = std::floor (area.y0);
-        area.x1 = std::ceil (area.x1);
-        area.y1 = std::ceil (area.y1);
+        round_rectangle_outwards(area);
     }
 
     // default dpi
@@ -1254,7 +1342,7 @@ sp_do_export_png(SPDocument *doc)
             g_warning("Export width %lu out of range (1 - %lu). Nothing exported.", width, (unsigned long int)PNG_UINT_31_MAX);
             return;
         }
-        dpi = (gdouble) width * PX_PER_IN / (area.x1 - area.x0);
+        dpi = (gdouble) width * PX_PER_IN / area.width();
     }
 
     if (sp_export_height) {
@@ -1264,15 +1352,15 @@ sp_do_export_png(SPDocument *doc)
             g_warning("Export height %lu out of range (1 - %lu). Nothing exported.", height, (unsigned long int)PNG_UINT_31_MAX);
             return;
         }
-        dpi = (gdouble) height * PX_PER_IN / (area.y1 - area.y0);
+        dpi = (gdouble) height * PX_PER_IN / area.height();
     }
 
     if (!sp_export_width) {
-        width = (unsigned long int) ((area.x1 - area.x0) * dpi / PX_PER_IN + 0.5);
+        width = (unsigned long int) (area.width() * dpi / PX_PER_IN + 0.5);
     }
 
     if (!sp_export_height) {
-        height = (unsigned long int) ((area.y1 - area.y0) * dpi / PX_PER_IN + 0.5);
+        height = (unsigned long int) (area.height() * dpi / PX_PER_IN + 0.5);
     }
 
     guint32 bgcolor = 0x00000000;
@@ -1307,12 +1395,12 @@ sp_do_export_png(SPDocument *doc)
 
     g_print("Background RRGGBBAA: %08x\n", bgcolor);
 
-    g_print("Area %g:%g:%g:%g exported to %lu x %lu pixels (%g dpi)\n", area.x0, area.y0, area.x1, area.y1, width, height, dpi);
+    g_print("Area %g:%g:%g:%g exported to %lu x %lu pixels (%g dpi)\n", area[Geom::X][0], area[Geom::Y][0], area[Geom::X][1], area[Geom::Y][1], width, height, dpi);
 
     g_print("Bitmap saved as: %s\n", filename);
 
     if ((width >= 1) && (height >= 1) && (width <= PNG_UINT_31_MAX) && (height <= PNG_UINT_31_MAX)) {
-        sp_export_png_file(doc, filename, area.x0, area.y0, area.x1, area.y1, width, height, dpi, dpi, bgcolor, NULL, NULL, true, sp_export_id_only ? items : NULL);
+        sp_export_png_file(doc, filename, area, width, height, dpi, dpi, bgcolor, NULL, NULL, true, sp_export_id_only ? items : NULL);
     } else {
         g_warning("Calculated bitmap dimensions %lu %lu are out of range (1 - %lu). Nothing exported.", width, height, (unsigned long int)PNG_UINT_31_MAX);
     }
@@ -1329,7 +1417,7 @@ sp_do_export_png(SPDocument *doc)
  *  \param mime MIME type to export as.
  */
 
-static void do_export_ps_pdf(SPDocument* doc, gchar const* uri, char const* mime)
+static void do_export_ps_pdf(Document* doc, gchar const* uri, char const* mime)
 {
     Inkscape::Extension::DB::OutputList o;
     Inkscape::Extension::db.get_output_list(o);
@@ -1369,19 +1457,19 @@ static void do_export_ps_pdf(SPDocument* doc, gchar const* uri, char const* mime
     if (sp_export_area_canvas) {
         if (sp_export_eps) {
             g_warning ("EPS cannot have its bounding box extend beyond its content, so if your drawing is smaller than the canvas, --export-area-canvas will clip it to drawing.");
-        } 
+        }
         (*i)->set_param_bool ("areaCanvas", TRUE);
     } else {
         (*i)->set_param_bool ("areaCanvas", FALSE);
     }
 
-    if (!sp_export_area_drawing && !sp_export_area_canvas && !sp_export_id) { 
+    if (!sp_export_area_drawing && !sp_export_area_canvas && !sp_export_id) {
         // neither is set, set canvas as default for ps/pdf and drawing for eps
         if (sp_export_eps) {
             try {
                (*i)->set_param_bool("areaDrawing", TRUE);
             } catch (...) {}
-        } 
+        }
     }
 
     if (sp_export_text_to_path) {
@@ -1390,6 +1478,23 @@ static void do_export_ps_pdf(SPDocument* doc, gchar const* uri, char const* mime
         (*i)->set_param_bool("textToPath", FALSE);
     }
 
+    if (sp_export_ignore_filters) {
+        (*i)->set_param_bool("blurToBitmap", FALSE);
+    } else {
+        (*i)->set_param_bool("blurToBitmap", TRUE);
+
+        gdouble dpi = 90.0;
+        if (sp_export_dpi) {
+            dpi = atof(sp_export_dpi);
+            if ((dpi < 1) || (dpi > 10000.0)) {
+                g_warning("DPI value %s out of range [1 - 10000]. Using 90 dpi instead.", sp_export_dpi);
+                dpi = 90;
+            }
+        }
+
+        (*i)->set_param_int("resolution", (int) dpi);
+    }
+
     (*i)->save(doc, uri);
 }
 
@@ -1402,7 +1507,7 @@ static void do_export_ps_pdf(SPDocument* doc, gchar const* uri, char const* mime
  *  \param mime MIME type to export as (should be "image/x-emf")
  */
 
-static void do_export_emf(SPDocument* doc, gchar const* uri, char const* mime)
+static void do_export_emf(Document* doc, gchar const* uri, char const* mime)
 {
     Inkscape::Extension::DB::OutputList o;
     Inkscape::Extension::db.get_output_list(o);
@@ -1713,7 +1818,7 @@ sp_process_args(poptContext ctx)
                 break;
             }
             case SP_ARG_VERSION: {
-                printf("Inkscape %s (%s)\n", INKSCAPE_VERSION, __DATE__);
+                printf("Inkscape %s (%s)\n", Inkscape::version_string, __DATE__);
                 exit(0);
                 break;
             }