summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTavmjong Bah <tavmjong@free.fr>2018-11-12 20:22:44 +0000
committerAlexander Valavanis <valavanisalex@gmail.com>2018-11-18 12:39:15 +0000
commit408cb49b5559a81ea803df64bf58457a5dd4bf16 (patch)
treece3eac6a8bf8f641ba1c71b72f228080d201bb6d /src
parentFix stream class locations (diff)
downloadinkscape-408cb49b5559a81ea803df64bf58457a5dd4bf16.tar.gz
inkscape-408cb49b5559a81ea803df64bf58457a5dd4bf16.zip
Rewrite of main.cpp using InkscapeApplication (Gtk::Application)
Use Gio::File for accessing files. Use Gio options to handle command line arguments. Use Gio::Actions for some command line arguments. Move file export code to src/io/file-export-cmd.h/.cpp. Make into class.
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt9
-rw-r--r--src/actions/CMakeLists.txt10
-rw-r--r--src/actions/actions-base.cpp277
-rw-r--r--src/actions/actions-base.h18
-rw-r--r--src/inkscape-application.cpp575
-rw-r--r--src/inkscape-application.h80
-rw-r--r--src/inkscape-main.cpp36
-rw-r--r--src/inkscape.cpp7
-rw-r--r--src/io/CMakeLists.txt4
-rw-r--r--src/io/file-export-cmd.cpp678
-rw-r--r--src/io/file-export-cmd.h79
-rw-r--r--src/io/file.cpp64
-rw-r--r--src/io/file.h26
-rw-r--r--src/main.cpp2251
14 files changed, 1859 insertions, 2255 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index ba3fc37d1..e2ccea569 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -245,6 +245,7 @@ list(APPEND inkscape_SRC
# All folders for internal inkscape
# these call add_inkscape_source
+add_subdirectory(actions)
add_subdirectory(debug)
add_subdirectory(display)
add_subdirectory(extension)
@@ -278,7 +279,13 @@ set(inkscape_SRC
# -----------------------------------------------------------------------------
# Setup the executable
# -----------------------------------------------------------------------------
-set(main_SRC main.cpp)
+set(main_SRC
+ inkscape-main.cpp
+ inkscape-application.h
+ inkscape-application.cpp
+ actions/actions-base.h
+ actions/actions-base.cpp
+)
set(view_SRC
inkview-main.cpp
inkview-application.h
diff --git a/src/actions/CMakeLists.txt b/src/actions/CMakeLists.txt
new file mode 100644
index 000000000..e16dbc505
--- /dev/null
+++ b/src/actions/CMakeLists.txt
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+set(actions_SRC
+ # actions-base.cpp
+
+ # HEADERS
+ # actions-base.h
+ )
+
+add_inkscape_source("${actions_SRC}")
diff --git a/src/actions/actions-base.cpp b/src/actions/actions-base.cpp
new file mode 100644
index 000000000..a3ff363a7
--- /dev/null
+++ b/src/actions/actions-base.cpp
@@ -0,0 +1,277 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Gio::Actions tied to the application and independent of GUI.
+ *
+ * Copyright (C) 2018 Tavmjong Bah
+ *
+ * The contents of this file may be used under the GNU General Public License Version 2 or later.
+ *
+ */
+
+#include <iostream>
+
+#include <giomm.h> // Not <gtkmm.h>! To eventually allow a headless version!
+
+#include "actions-base.h"
+
+#include "inkscape-application.h"
+
+#include "inkscape.h" // Inkscape::Application
+#include "inkscape-version.h" // Inkscape version
+#include "path-prefix.h" // Extension directory
+#include "extension/init.h" // List verbs
+#include "verbs.h" // List verbs
+#include "selection.h" // Selection
+#include "object/sp-root.h" // query_all()
+#include "file.h" // dpi convert method
+
+void
+print_inkscape_version()
+{
+ std::cout << "Inkscape " << Inkscape::version_string << std::endl;
+}
+
+void
+print_extension_directory()
+{
+ std::cout << INKSCAPE_EXTENSIONDIR << std::endl;
+}
+
+void
+print_verb_list()
+{
+ // This really shouldn't go here, we should init the app.
+ // But, since we're just exiting in this path, there is
+ // no harm, and this is really a better place to put
+ // everything else.
+ Inkscape::Extension::init(); // extension/init.h
+ Inkscape::Verb::list(); // verbs.h
+}
+
+// Helper function: returns true if both document and selection found.
+bool
+get_document_and_selection(InkscapeApplication* app, SPDocument** document, Inkscape::Selection** selection)
+{
+ *document = app->get_active_document();
+ if (!(*document)) {
+ std::cerr << "get_document_and_selection: No document!" << std::endl;
+ return false;
+ }
+
+ Inkscape::ActionContext context = INKSCAPE.action_context_for_document(*document);
+ *selection = context.getSelection();
+ if (!*selection) {
+ std::cerr << "get_document_and_selection: No selection!" << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+void
+select_via_id(Glib::ustring ids, InkscapeApplication* app)
+{
+ SPDocument* document = nullptr;
+ Inkscape::Selection* selection = nullptr;
+ if (!get_document_and_selection(app, &document, &selection)) {
+ return;
+ }
+
+ auto tokens = Glib::Regex::split_simple("\\s*,\\s*", ids);
+ for (auto id : tokens) {
+ SPObject* object = document->getObjectById(id);
+ if (object) {
+ selection->add(object);
+ } else {
+ std::cerr << "select: did not find object with id: " << id << std::endl;
+ }
+ }
+}
+
+// Helper function for query_x(), query_y(), query_width(), and query_height().
+void
+query_dimension(InkscapeApplication* app, bool extent, Geom::Dim2 const axis)
+{
+ SPDocument* document = nullptr;
+ Inkscape::Selection* selection = nullptr;
+ if (!get_document_and_selection(app, &document, &selection)) {
+ return;
+ }
+
+ if (selection->isEmpty()) {
+ selection->add(document->getRoot());
+ }
+
+ bool first = true;
+ auto items = selection->items();
+ for (auto item : items) {
+ if (!first) {
+ std::cout << ",";
+ }
+ first = false;
+ Geom::OptRect area = item->documentVisualBounds();
+ if (area) {
+ if (extent) {
+ std::cout << area->dimensions()[axis];
+ } else {
+ std::cout << area->min()[axis];
+ }
+ } else {
+ std::cout << "0";
+ }
+ }
+ std::cout << std::endl;
+}
+
+void
+query_x(InkscapeApplication* app)
+{
+ query_dimension(app, false, Geom::X);
+}
+
+void
+query_y(InkscapeApplication* app)
+{
+ query_dimension(app, false, Geom::Y);
+}
+
+void
+query_width(InkscapeApplication* app)
+{
+ query_dimension(app, true, Geom::X);
+}
+
+void
+query_height(InkscapeApplication* app)
+{
+ query_dimension(app, true, Geom::Y);
+}
+
+// Helper for query_all()
+void
+query_all_recurse (SPObject *o)
+{
+ SPItem *item = dynamic_cast<SPItem*>(o);
+ if (item && item->getId()) {
+ Geom::OptRect area = item->documentVisualBounds();
+ if (area) {
+ std::cout << item->getId() << ","
+ << area->min()[Geom::X] << ","
+ << area->min()[Geom::Y] << ","
+ << area->dimensions()[Geom::X] << ","
+ << area->dimensions()[Geom::Y] << std::endl;
+ }
+
+ for (auto& child: o->children) {
+ query_all_recurse (&child);
+ }
+ }
+}
+
+void
+query_all(InkscapeApplication* app)
+{
+ SPDocument* doc = app->get_active_document();
+ if (!doc) {
+ std::cerr << "query_all: no document!" << std::endl;
+ return;
+ }
+
+ SPObject *o = doc->getRoot();
+ if (o) {
+ query_all_recurse(o);
+ }
+}
+
+void
+pdf_page(int page)
+{
+ INKSCAPE.set_pdf_page(page);
+}
+
+void
+convert_dpi_method(Glib::ustring method)
+{
+ if (method == "none") {
+ sp_file_convert_dpi_method_commandline = FILE_DPI_UNCHANGED;
+ } else if (method == "scale-viewbox") {
+ sp_file_convert_dpi_method_commandline = FILE_DPI_VIEWBOX_SCALED;
+ } else if (method == "scale-document") {
+ sp_file_convert_dpi_method_commandline = FILE_DPI_DOCUMENT_SCALED;
+ } else {
+ std::cerr << "dpi_convert_method: invalid option" << std::endl;
+ }
+}
+
+void
+no_convert_baseline()
+{
+ sp_no_convert_text_baseline_spacing = true;
+}
+
+// Temporary: Verbs are to be replaced by Gio::Actions!
+void
+verbs(Glib::ustring verblist, InkscapeApplication* app)
+{
+ auto tokens = Glib::Regex::split_simple("\\s*,\\s*", verblist);
+ for (auto token : tokens) {
+ std::vector<Glib::ustring> parts = Glib::Regex::split_simple("\\s*:\\s*", token); // Second part is always ignored... we could implement it but better to switch to Gio::Actions
+ if (!parts[0].empty()) {
+ Inkscape::Verb* verb = Inkscape::Verb::getbyid(parts[0].c_str());
+ if (verb == nullptr) {
+ std::cerr << "verbs_action: Invalid verb: " << parts[0] << std::endl;
+ break;
+ }
+ // Inkscape::ActionContext context = INKSCAPE.action_context_for_document(*document);
+ SPAction* action = verb->get_action(INKSCAPE.active_action_context());
+ sp_action_perform(action, nullptr); // Data is ignored!
+ }
+ }
+}
+
+void
+vacuum_defs(InkscapeApplication* app)
+{
+ SPDocument* document = nullptr;
+ Inkscape::Selection* selection = nullptr;
+ if (!get_document_and_selection(app, &document, &selection)) {
+ return;
+ }
+ document->vacuumDocument();
+}
+
+void
+add_actions_base(InkscapeApplication* app)
+{
+ // Note: "radio" actions are just an easy way to set type without using templating.
+ app->add_action("inkscape-version", sigc::ptr_fun(&print_inkscape_version ));
+ app->add_action("extension-directory", sigc::ptr_fun(&print_extension_directory));
+ app->add_action("verb-list", sigc::ptr_fun(&print_verb_list ));
+
+ app->add_action_radio_integer( "open-page", sigc::ptr_fun(&pdf_page), 0);
+ app->add_action_radio_string( "convert-dpi-method", sigc::ptr_fun(&convert_dpi_method), "none");
+ app->add_action( "no-convert-baseline", sigc::ptr_fun(&no_convert_baseline) );
+
+ app->add_action( "vacuum-defs", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&vacuum_defs), app) );
+ app->add_action_radio_string( "select", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&select_via_id), app), "null");
+ app->add_action_radio_string( "verb", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&verbs), app), "null");
+
+ app->add_action_radio_string( "query-id", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&select_via_id), app), "null"); // For backwards compatibility.
+ app->add_action( "query-x", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&query_x), app) );
+ app->add_action( "query-y", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&query_y), app) );
+ app->add_action( "query-width", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&query_width), app) );
+ app->add_action( "query-height", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&query_height), app) );
+ app->add_action( "query-all", sigc::bind<InkscapeApplication*>(sigc::ptr_fun(&query_all), app) );
+
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/actions/actions-base.h b/src/actions/actions-base.h
new file mode 100644
index 000000000..a52078881
--- /dev/null
+++ b/src/actions/actions-base.h
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Gio::Actions tied to the application and without GUI.
+ *
+ * Copyright (C) 2018 Tavmjong Bah
+ *
+ * The contents of this file may be used under the GNU General Public License Version 2 or later.
+ *
+ */
+
+#ifndef INK_ACTIONS_BASE_H
+#define INK_ACTIONS_BASE_H
+
+class InkscapeApplication;
+
+void add_actions_base(InkscapeApplication* app);
+
+#endif // INK_ACTIONS_BASE_H
diff --git a/src/inkscape-application.cpp b/src/inkscape-application.cpp
new file mode 100644
index 000000000..3a4721963
--- /dev/null
+++ b/src/inkscape-application.cpp
@@ -0,0 +1,575 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * The main Inkscape application.
+ *
+ * Copyright (C) 2018 Tavmjong Bah
+ *
+ * The contents of this file may be used under the GNU General Public License Version 2 or later.
+ *
+ */
+
+#include <iostream>
+
+#include <glibmm/i18n.h> // Internationalization
+
+#include "inkscape-application.h"
+
+#include "inkscape.h" // Inkscape::Application
+#include "inkgc/gc-core.h" // Garbage Collecting init
+#include "ui/widget/panel.h" // Panel prep
+#include "file.h" // File open and window creation.
+#include "io/file.h" // File open (command line).
+#include "desktop.h" // Access to window
+#include "actions/actions-base.h" // Actions
+
+#ifdef ENABLE_NLS
+// Native Language Support - shouldn't this always be used?
+#include "helper/gettext.h" // gettext init
+#endif // ENABLE_NLS
+
+// This is a bit confusing as there are two ways to handle command line arguments and files
+// depending on if the Gio::APPLICATION_HANDLES_OPEN and/or Gio::APPLICATION_HANDLES_COMMAND_LINE
+// flags are set. If the open flag is set and the command line not, the all the remainng arguments
+// after calling on_handle_local_options() are assumed to be filenames.
+
+InkscapeApplication::InkscapeApplication()
+ : Gtk::Application("org.inkscape.application.with_gui",
+ Gio::APPLICATION_HANDLES_OPEN | // Use default file opening.
+ Gio::APPLICATION_NON_UNIQUE ) // Allows different instances of Inkscape to run at same time.
+ , _with_gui(true)
+{
+
+ // ==================== Initializations =====================
+ // Garbage Collector
+ Inkscape::GC::init();
+
+#ifdef ENABLE_NLS
+ // Native Language Support (shouldn't this always be used?).
+ Inkscape::initialize_gettext();
+#endif
+
+ Glib::set_application_name(N_("Inkscape - A Vector Drawing Program")); // After gettext() init.
+
+ // ======================== Actions =========================
+ add_actions_base(this); // actions that are GUI independent
+
+ // ====================== Command Line ======================
+
+ // Will automatically handle character conversions.
+ // Note: OPTION_TYPE_FILENAME => std::string, OPTION_TYPE_STRING => Glib::ustring.
+
+ // Actions
+ add_main_option_entry(OPTION_TYPE_STRING, "actions", 'a', N_("Actions (with optional arguments), semi-colon separated."), N_("ACTION(:ARGUMENT)"));
+ add_main_option_entry(OPTION_TYPE_BOOL, "action-list", '\0', N_("Actions: List available actions."), "");
+
+ // Query
+ add_main_option_entry(OPTION_TYPE_BOOL, "version", 'v', N_("Print: Inkscape version."), "");
+ add_main_option_entry(OPTION_TYPE_BOOL, "extensions-directory",'x', N_("Print: Extensions directory."), "");
+ add_main_option_entry(OPTION_TYPE_BOOL, "verb-list", '\0', N_("Print: List verbs."), "");
+
+ // Interface
+ add_main_option_entry(OPTION_TYPE_BOOL, "with-gui", 'g', N_("GUI: With graphical interface."), "");
+ add_main_option_entry(OPTION_TYPE_BOOL, "without-gui", 'G', N_("GUI: Console only."), "");
+
+ // Open/Import
+ add_main_option_entry(OPTION_TYPE_INT, "pdf-page", '\0', N_("Open: PDF page to import"), N_("PAGE"));
+ add_main_option_entry(OPTION_TYPE_STRING, "convert-dpi-method", '\0', N_("Open: Method used to convert pre-0.92 document dpi, if needed: [none|scale-viewbox|scale-document]."), "[...]");
+ add_main_option_entry(OPTION_TYPE_BOOL, "no-convert-text-baseline-spacing", 0, N_("Open: Do not fix pre-0.92 document's text baseline spacing on opening."), "");
+
+ // Query - Geometry
+ add_main_option_entry(OPTION_TYPE_STRING, "query-id", 'I', N_("Query: ID of object to be queried."), N_("ID"));
+ add_main_option_entry(OPTION_TYPE_BOOL, "query-all", 'S', N_("Query: Print bounding boxes of all objects."), "");
+ add_main_option_entry(OPTION_TYPE_BOOL, "query-x", 'X', N_("Query: X coordinate of drawing or object (if specified by --query-id)."), "");
+ add_main_option_entry(OPTION_TYPE_BOOL, "query-y", 'Y', N_("Query: Y coordinate of drawing or object (if specified by --query-id)."), "");
+ add_main_option_entry(OPTION_TYPE_BOOL, "query-width", 'W', N_("Query: Width of drawing or object (if specified by --query-id)."), "");
+ add_main_option_entry(OPTION_TYPE_BOOL, "query-height", 'H', N_("Query: Heightof drawing or object (if specified by --query-id)."), "");
+
+ // Processing
+ add_main_option_entry(OPTION_TYPE_BOOL, "vacuum-defs", '\0', N_("Process: Remove unused definitions from the <defs> section(s) of document."), "");
+ add_main_option_entry(OPTION_TYPE_STRING, "select", '\0', N_("Process: Select objects: comma separated list of IDs."), N_("OBJECT-ID[,OBJECT-ID]*"));
+ add_main_option_entry(OPTION_TYPE_STRING, "verb", '\0', N_("Process: Verb(s) to call when Inkscape opens."), N_("VERB-ID[,VERB-ID]*"));
+ //add_main_option_entry(OPTION_TYPE_BOOL, "shell", '\0', N_("Process: Start Inkscape in interative shell mode."), "");
+
+ // Export - File and File Type
+ add_main_option_entry(OPTION_TYPE_STRING, "export-type", '\0', N_("Export: File type:[svg,png,ps,psf,tex,emf,wmf,xaml]"), "[...]");
+ add_main_option_entry(OPTION_TYPE_FILENAME, "export-file", 'o', N_("Export: File name"), N_("EXPORT-FILENAME"));
+ add_main_option_entry(OPTION_TYPE_BOOL, "export-overwrite", '\0', N_("Export: Overwrite input file."), ""); // BSP
+
+ // B = PNG, S = SVG, P = PS/EPS/PDF
+ // Export - Geometry
+ add_main_option_entry(OPTION_TYPE_STRING, "export-area", 'a', N_("Export: Area to export in SVG user units."), N_("x0:y0:x1:y1")); // BSP
+ add_main_option_entry(OPTION_TYPE_BOOL, "export-drawing", 'D', N_("Export: Area to export is drawing (not page)."), ""); // BSP
+ add_main_option_entry(OPTION_TYPE_BOOL, "export-page", 'C', N_("Export: Area to export is page."), ""); // BSP
+ add_main_option_entry(OPTION_TYPE_INT, "export-margin", '\0', N_("Export: Margin around export area: units of page size for SVG, mm for PS/EPS/PDF."), ""); // xSP
+ add_main_option_entry(OPTION_TYPE_BOOL, "export-area-snap", '\0', N_("Export: Snap the bitmap export area outwards to the nearest integer values."), ""); // Bxx
+ add_main_option_entry(OPTION_TYPE_INT, "export-width", 'w', N_("Export: Bitmap width in pixels (overrides --export-dpi)."), N_("WIDTH")); // Bxx
+ add_main_option_entry(OPTION_TYPE_INT, "export-height", 'h', N_("Export: Bitmap height in pixels (overrides --export-dpi)."), N_("HEIGHT")); // Bxx
+
+ // Export - Options
+ add_main_option_entry(OPTION_TYPE_STRING, "export-id", 'i', N_("Export: ID of object to export."), N_("OBJECT-ID")); // BSP
+ add_main_option_entry(OPTION_TYPE_BOOL, "export-id-only", 'j', N_("Export: Hide all objects except object with ID selected by export-id."), ""); // BSx
+ add_main_option_entry(OPTION_TYPE_BOOL, "export-plain-svg", 'l', N_("Export: Remove items in the Inkscape namespace."), ""); // xSx
+ add_main_option_entry(OPTION_TYPE_INT, "export-dpi", 'd', N_("Export: Resolution for rasterization bitmaps and filters (default is 96)."), N_("DPI")); // BxP
+ add_main_option_entry(OPTION_TYPE_BOOL, "export-ignore-filters", '\0', N_("Export: Render objects without filters instead of rasterizing. (PS/EPS/PDF)"), ""); // xxP
+ add_main_option_entry(OPTION_TYPE_BOOL, "export-text-to-path", 'T', N_("Export: Convert text to paths. (PS/EPS/PDF/SVG)."), ""); // xxP
+ add_main_option_entry(OPTION_TYPE_INT, "export-ps-level", '\0', N_("Export: Postscript level (2 or 3). Default is 3."), N_("PS-Level")); // xxP
+ add_main_option_entry(OPTION_TYPE_STRING, "export-pdf-level", '\0', N_("Export: PDF level (1.4 or 1.5)"), N_("PDF-Level")); // xxP
+ add_main_option_entry(OPTION_TYPE_BOOL, "export-latex", '\0', N_("Export: Export text separately to LaTeX file (PS/EPS/PDF). Include via \\input{file.tex}"), ""); // xxP
+ add_main_option_entry(OPTION_TYPE_BOOL, "export-use-hints", 't', N_("Export: Use stored filename and DPI hints when exporting object selected by --export-id."), ""); // Bxx
+ add_main_option_entry(OPTION_TYPE_STRING, "export-background", 'b', N_("Export: Background color for exported bitmaps (any SVG color string)."), N_("COLOR")); // Bxx
+ add_main_option_entry(OPTION_TYPE_DOUBLE, "export-background-opacity", 'y', N_("Export: Background opacity for exported bitmaps (either 0.0 to 1.0 or 1 to 255)."), N_("VALUE")); // Bxx
+
+#ifdef WITH_YAML
+ add_main_option_entry(OPTION_TYPE_FILENAME, "xverbs", '\0', N_("Process: xverb command file."), N_("XVERBS-FILENAME"));
+#endif // WITH_YAML
+
+#ifdef WITH_DBUS
+ add_main_option_entry(OPTION_TYPE_BOOL, "dbus-listen", '\0', N_("D-Bus: Enter a listening loop for D-Bus messages in console mode."), "");
+ add_main_option_entry(OPTION_TYPE_STRING, "dbus-name", '\0', N_("D-Bus: Specify the D-Bus name (default is 'org.inkscape')."), N_("BUS-NAME"));
+#endif // WITH_DBUS
+
+ signal_handle_local_options().connect(sigc::mem_fun(*this, &InkscapeApplication::on_handle_local_options));
+
+ // This is normally called for us... but after the "handle_local_options" signal is emitted. If
+ // we want to rely on actions for handling options, we need to call it here. This appears to
+ // have no unwanted side-effect. It will also trigger the call to on_startup().
+ register_application();
+}
+
+Glib::RefPtr<InkscapeApplication> InkscapeApplication::create()
+{
+ return Glib::RefPtr<InkscapeApplication>(new InkscapeApplication());
+}
+
+SPDocument*
+InkscapeApplication::get_active_document()
+{
+ // This should change based on last document window in focus if with GUI. But for now we're
+ // only using it for command line mode so return last document (the one currently be read in).
+ return _documents.back();
+}
+
+void
+InkscapeApplication::on_startup()
+{
+ Gtk::Application::on_startup();
+}
+
+// Here are things that should be in on_startup() but cannot be as we don't set _with_gui until
+// on_handle_local_options() is called.
+void
+InkscapeApplication::on_startup2()
+{
+ // This should be completely rewritten.
+ Inkscape::Application::create(nullptr, _with_gui); // argv appears to not be used.
+
+ if (!_with_gui) {
+ return;
+ }
+
+ // ======================= Actions (GUI) ======================
+ add_action("new", sigc::mem_fun(*this, &InkscapeApplication::on_new ));
+ add_action("quit", sigc::mem_fun(*this, &InkscapeApplication::on_quit ));
+
+ // ========================= GUI Init =========================
+ Gtk::Window::set_default_icon_name("inkscape");
+ Inkscape::UI::Widget::Panel::prep();
+
+ // ========================= Builder ==========================
+ _builder = Gtk::Builder::create();
+
+ try
+ {
+ _builder->add_from_file("ink-application.xml");
+ }
+ catch (const Glib::Error& ex)
+ {
+ std::cerr << "InkscapeApplication: ink_application.xml file not read! " << ex.what() << std::endl;
+ }
+
+ auto object = _builder->get_object("menu-application");
+ auto menu = Glib::RefPtr<Gio::Menu>::cast_dynamic(object);
+ if (!menu) {
+ std::cerr << "InkscapeApplication: failed to load application menu!" << std::endl;
+ } else {
+ set_app_menu(menu);
+ }
+}
+
+// Open document window with default document. Either this or on_open() is called.
+void
+InkscapeApplication::on_activate()
+{
+ on_startup2();
+
+ if (_with_gui) {
+ create_window();
+ } else {
+ std::cerr << "InkscapeApplication::on_activate: Without GUI" << std::endl;
+ // Create blank document?
+ }
+}
+
+// Open document window for each file. Either this or on_activate() is called.
+// type_vec_files == std::vector<Glib::RefPtr<Gio::File> >
+void
+InkscapeApplication::on_open(const Gio::Application::type_vec_files& files, const Glib::ustring& hint)
+{
+ on_startup2();
+
+ for (auto file : files) {
+ if (_with_gui) {
+ // Create a window for each file.
+
+ create_window(file);
+
+ // Process each file.
+ for (auto action: _command_line_actions) {
+ activate_action( action.first, action.second );
+ }
+
+ } else {
+
+ // Open file
+ SPDocument *doc = ink_file_open(file);
+ if (!doc) continue;
+
+ // Add to Inkscape::Application...
+ INKSCAPE.add_document(doc);
+
+ doc->ensureUpToDate(); // Or queries don't work!
+
+ // Add to our application
+ _documents.push_back(doc);
+
+ // process_file(file);
+ for (auto action: _command_line_actions) {
+ activate_action( action.first, action.second );
+ }
+
+ // Save... can't use action yet.
+ _file_export.do_export(doc, file->get_path());
+
+ // Remove from our application... we only have one in command-line mode.
+ _documents.pop_back();
+
+ // Close file
+ INKSCAPE.remove_document(doc);
+ delete doc;
+ }
+ }
+
+ //Call the base class's implementation:
+ // Gtk::Application::on_open(files, hint);
+}
+
+void
+InkscapeApplication::create_window(const Glib::RefPtr<Gio::File>& file)
+{
+ SPDesktop* desktop = nullptr;
+ if (file) {
+ desktop = sp_file_new_default();
+ sp_file_open(file->get_parse_name(), nullptr, false, true);
+ } else {
+ desktop = sp_file_new_default();
+ }
+
+ _documents.push_back(desktop->getDocument());
+
+ // Add to Gtk::Window to app window list.
+ add_window(*desktop->getToplevel());
+}
+
+// ========================= Callbacks ==========================
+
+/*
+ * Handle command line options.
+ *
+ * Options are processed in the order they appear in this function.
+ * We process in order: Print -> GUI -> Open -> Query -> Process -> Export.
+ * For each file without GUI: Open -> Query -> Process -> Export
+ * More flexible processing can be done via actions or xverbs.
+ */
+int
+InkscapeApplication::on_handle_local_options(const Glib::RefPtr<Glib::VariantDict>& options)
+{
+ if (!options) {
+ std::cerr << "InkscapeApplication::on_handle_local_options: options is null!" << std::endl;
+ return -1; // Keep going
+ }
+
+ // ===================== QUERY =====================
+ // These are processed first as they result in immediate program termination.
+ if (options->contains("version")) {
+ activate_action("inkscape-version");
+ return EXIT_SUCCESS;
+ }
+
+ if (options->contains("extensions-directory")) {
+ activate_action("extensions-directory");
+ return EXIT_SUCCESS;
+ }
+
+ if (options->contains("verb-list")) {
+ activate_action("verb-list");
+ return EXIT_SUCCESS;
+ }
+
+ if (options->contains("action-list")) {
+ std::cerr << "action-list: not implemented" << std::endl;
+ list_actions(); // Doesn't work... member of Gio::ActionGroup, not Gio::ActionMap.
+ return EXIT_SUCCESS;
+ }
+
+ // For options without arguments.
+ auto base = Glib::VariantBase();
+
+ // ====================== GUI =====================
+ if (options->contains("without-gui")) _with_gui = false;
+ if (options->contains("with-gui")) _with_gui = true;
+
+ // Some options should preclude using gui!
+ if (options->contains("query-id") ||
+ options->contains("query-x") ||
+ options->contains("query-all") ||
+ options->contains("query-y") ||
+ options->contains("query-width") ||
+ options->contains("query-height") ||
+ options->contains("export-type") ||
+ options->contains("export-file") ||
+ options->contains("export-overwrite")
+ ) {
+ _with_gui = false;
+ }
+
+ // ==================== ACTIONS ====================
+ // Actions as an argument string: e.g.: --actions="query-id:rect1;query-x".
+ // Actions will be processed in order that they are given in argument.
+ Glib::ustring actions;
+ if (options->contains("actions")) {
+ options->lookup_value("actions", actions);
+
+ // Split action list
+ std::vector<Glib::ustring> tokens = Glib::Regex::split_simple("\\s*;\\s*", actions);
+ for (auto token : tokens) {
+ std::cout << token << std::endl;
+ std::vector<Glib::ustring> tokens2 = Glib::Regex::split_simple("\\s*:\\s*", token);
+ std::string action;
+ std::string value;
+ if (tokens2.size() > 0) {
+ action = tokens2[0];
+ }
+ if (tokens2.size() > 1) {
+ value = tokens2[1];
+ }
+
+ Glib::RefPtr<Gio::Action> action_ptr = lookup_action(action);
+ if (action_ptr) {
+ // Doesn't seem to be a way to test this using the C++ binding without Glib-CRITICAL errors.
+ const GVariantType* gtype = g_action_get_parameter_type(action_ptr->gobj());
+ if (gtype) {
+ // With value.
+ Glib::VariantType type = action_ptr->get_parameter_type();
+ if (type.get_string() == "s") {
+ _command_line_actions.push_back(
+ std::make_pair( action, Glib::Variant<Glib::ustring>::create(value) ));
+ } else if (type.get_string() == "i") {
+ _command_line_actions.push_back(
+ std::make_pair( action, Glib::Variant<int>::create(std::stoi(value))));
+ } else if (type.get_string() == "d") {
+ _command_line_actions.push_back(
+ std::make_pair( action, Glib::Variant<double>::create(std::stod(value))));
+ } else {
+ std::cerr << "InkscapeApplication::on_handle_local_options: unhandled action value: "
+ << action << ": " << type.get_string() << std::endl;
+ }
+ } else {
+ // Stateless (i.e. no value).
+ _command_line_actions.push_back( std::make_pair( action, Glib::VariantBase() ) );
+ }
+ } else {
+ std::cerr << "InkscapeApplication::on_handle_local_options: '"
+ << action << "' is not a valid action!" << std::endl;
+ }
+ }
+ }
+
+
+ // ================= OPEN/IMPORT ===================
+
+ if (options->contains("pdf-page")) { // Maybe useful for other file types?
+ int page = 0;
+ options->lookup_value("pdf-page", page);
+ _command_line_actions.push_back(
+ std::make_pair("open-page", Glib::Variant<int>::create(page)));
+ }
+
+ if (options->contains("convert-dpi-method")) {
+ Glib::ustring method;
+ options->lookup_value("convert-dpi-method", method);
+ if (!method.empty()) {
+ _command_line_actions.push_back(
+ std::make_pair("convert-dpi-method", Glib::Variant<Glib::ustring>::create(method)));
+ }
+ }
+
+ if (options->contains("no-convert-text-baseline-spacing")) _command_line_actions.push_back(std::make_pair("no-convert-baseline", base));
+
+
+ // ===================== QUERY =====================
+
+ // 'query-id' should be processed first! Idea: We could turn this into a comma separated list.
+ if (options->contains("query-id")) {
+ Glib::ustring query_id;
+ options->lookup_value("query-id", query_id);
+ if (!query_id.empty()) {
+ _command_line_actions.push_back(
+ std::make_pair("query-id", Glib::Variant<Glib::ustring>::create(query_id)));
+ }
+ }
+
+ if (options->contains("query-all")) _command_line_actions.push_back(std::make_pair("query-all", base));
+ if (options->contains("query-x")) _command_line_actions.push_back(std::make_pair("query-x", base));
+ if (options->contains("query-y")) _command_line_actions.push_back(std::make_pair("query-y", base));
+ if (options->contains("query-width")) _command_line_actions.push_back(std::make_pair("query-width", base));
+ if (options->contains("query-height")) _command_line_actions.push_back(std::make_pair("query-height",base));
+
+
+ // =================== PROCESS =====================
+
+ // Note: this won't work with --verb="FileSave,FileClose" unless some additional verb changes the file. FIXME
+ // One can use --verb="FileVacuum,FileSave,FileClose".
+ if (options->contains("vacuum-defs")) _command_line_actions.push_back(std::make_pair("vacuum-defs", base));
+
+ if (options->contains("select")) {
+ Glib::ustring select;
+ options->lookup_value("select", select);
+ if (!select.empty()) {
+ _command_line_actions.push_back(
+ std::make_pair("select", Glib::Variant<Glib::ustring>::create(select)));
+ }
+ }
+
+ if (options->contains("verb")) {
+ Glib::ustring verb;
+ options->lookup_value("verb", verb);
+ if (!verb.empty()) {
+ _command_line_actions.push_back(
+ std::make_pair("verb", Glib::Variant<Glib::ustring>::create(verb)));
+ }
+ }
+
+ // ==================== EXPORT =====================
+ if (options->contains("export-file")) {
+ options->lookup_value("export-file", _file_export.export_filename);
+ }
+
+ if (options->contains("export-type")) {
+ options->lookup_value("export-type", _file_export.export_type);
+ }
+
+ if (options->contains("export-overwrite")) _file_export.export_overwrite = true;
+
+ // Export - Geometry
+ if (options->contains("export-area")) {
+ options->lookup_value("export-area", _file_export.export_area);
+ }
+
+ if (options->contains("export-area-drawing")) _file_export.export_area_drawing = true;
+ if (options->contains("export-area-page")) _file_export.export_area_page = true;
+
+ if (options->contains("export-margin")) {
+ options->lookup_value("export-margin", _file_export.export_margin);
+ }
+
+ if (options->contains("export-area-snap")) _file_export.export_area_snap = true;
+
+ if (options->contains("export-width")) {
+ options->lookup_value("export-width", _file_export.export_width);
+ }
+
+ if (options->contains("export-height")) {
+ options->lookup_value("export-height", _file_export.export_height);
+ }
+
+ // Export - Options
+ if (options->contains("export-id")) {
+ options->lookup_value("export-id", _file_export.export_id);
+ }
+
+ if (options->contains("export-id-only")) _file_export.export_id_only = true;
+ if (options->contains("export-plain-svg")) _file_export.export_plain_svg = true;
+
+ if (options->contains("export-dpi")) {
+ options->lookup_value("export-dpi", _file_export.export_dpi);
+ }
+
+ if (options->contains("export-ignore-filters")) _file_export.export_ignore_filters = true;
+ if (options->contains("export-text-to-path")) _file_export.export_text_to_path = true;
+
+ if (options->contains("export-ps-level")) {
+ options->lookup_value("export-ps-level", _file_export.export_ps_level);
+ }
+
+ if (options->contains("export-pdf-level")) {
+ options->lookup_value("export-pdf-level", _file_export.export_pdf_level);
+ }
+
+ if (options->contains("export-latex")) _file_export.export_latex = true;
+ if (options->contains("export-use-hints")) _file_export.export_use_hints = true;
+
+ if (options->contains("export-background")) {
+ options->lookup_value("export-background",_file_export.export_background);
+ }
+
+ if (options->contains("export-background-opacity")) {
+ options->lookup_value("export-background-opacity", _file_export.export_background_opacity);
+ }
+
+
+ // ==================== D-BUS ======================
+
+#ifdef WITH_DBUS
+ // Before initializing extensions, we must set the DBus bus name if required
+ if (options->contains("dbus-listen")) {
+ std::string dbus_name;
+ options->lookup_value("dbus-name", dbus_name);
+ if (!dbus_name.empty()) {
+ Inkscape::Extension::Dbus::dbus_set_bus_name(dbus_name.c_str());
+ }
+ }
+#endif
+
+ return -1; // Keep going
+}
+
+// ======================== Actions =========================
+
+void
+InkscapeApplication::on_new()
+{
+ create_window();
+}
+
+void
+InkscapeApplication::on_quit()
+{
+ // Delete all windows (quit() doesn't do this).
+ std::vector<Gtk::Window*> windows = get_windows();
+ for (auto window: windows) {
+ // Do something
+ }
+
+ quit();
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/inkscape-application.h b/src/inkscape-application.h
new file mode 100644
index 000000000..b176c2921
--- /dev/null
+++ b/src/inkscape-application.h
@@ -0,0 +1,80 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * The main Inkscape application.
+ *
+ * Copyright (C) 2018 Tavmjong Bah
+ *
+ * The contents of this file may be used under the GNU General Public License Version 2 or later.
+ *
+ */
+
+#ifndef INKSCAPE_APPLICATION_H
+#define INKSCAPE_APPLICATION_H
+
+/*
+ * The main Inkscape application.
+ *
+ * Copyright (C) 2018 Tavmjong Bah
+ *
+ * The contents of this file may be used under the GNU General Public License Version 2 or later.
+ *
+ */
+
+#include <gtkmm.h>
+
+#include "document.h"
+#include "helper/action.h"
+#include "io/file-export-cmd.h" // File export (non-verb)
+
+class InkscapeApplication : public Gtk::Application
+{
+protected:
+ InkscapeApplication();
+
+public:
+ static Glib::RefPtr<InkscapeApplication> create();
+
+ SPDocument* get_active_document();
+
+protected:
+ void on_startup() override;
+ void on_startup2();
+ void on_activate() override;
+ void on_open(const Gio::Application::type_vec_files& files, const Glib::ustring& hint) override;
+
+private:
+ void create_window(const Glib::RefPtr<Gio::File>& file = Glib::RefPtr<Gio::File>());
+
+private:
+ // Callbacks
+ int on_handle_local_options(const Glib::RefPtr<Glib::VariantDict>& options);
+
+ // Actions
+ void on_new();
+ void on_quit();
+ void on_about();
+
+ Glib::RefPtr<Gtk::Builder> _builder;
+
+ bool _with_gui;
+ InkFileExportCmd _file_export;
+
+ // Documents are owned by the application which is responsible for opening/saving/exporting. WIP
+ std::vector<SPDocument*> _documents;
+
+ // Actions from the command line or file.
+ std::vector<std::pair<std::string, Glib::VariantBase> > _command_line_actions;
+};
+
+#endif // INKSCAPE_APPLICATION_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/inkscape-main.cpp b/src/inkscape-main.cpp
new file mode 100644
index 000000000..52d3e7873
--- /dev/null
+++ b/src/inkscape-main.cpp
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Inkscape - an ambitious vector drawing program
+ *
+ * Authors:
+ * Tavmjong Bah
+ *
+ * (C) 2018 Tavmjong Bah
+ *
+ * Released under GNU GPL v2+, read the file 'COPYING' for more information.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "inkscape-application.h"
+
+
+int main(int argc, char *argv[])
+{
+ auto application = InkscapeApplication::create();
+
+ return application->run(argc, argv);
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/inkscape.cpp b/src/inkscape.cpp
index 19438b437..acac67649 100644
--- a/src/inkscape.cpp
+++ b/src/inkscape.cpp
@@ -67,7 +67,7 @@
Inkscape::Application * Inkscape::Application::_S_inst = nullptr;
bool Inkscape::Application::_crashIsHappening = false;
-#define DESKTOP_IS_ACTIVE(d) (!INKSCAPE._desktops->empty() && ((d) == INKSCAPE._desktops->front()))
+#define DESKTOP_IS_ACTIVE(d) (INKSCAPE._desktops != nullptr && !INKSCAPE._desktops->empty() && ((d) == INKSCAPE._desktops->front()))
static void (* segv_handler) (int) = SIG_DFL;
static void (* abrt_handler) (int) = SIG_DFL;
@@ -609,7 +609,7 @@ Application::~Application()
_S_inst = nullptr; // this will probably break things
refCount = 0;
- gtk_main_quit ();
+ // gtk_main_quit ();
}
/** Sets the keyboard modifer to map to Alt.
@@ -1279,6 +1279,7 @@ Application::action_context_for_document(SPDocument *doc)
// Document is not associated with any desktops - maybe we're in command-line mode
std::map<SPDocument *, AppSelectionModel *>::iterator sel_iter = _selection_models.find(doc);
if (sel_iter == _selection_models.end()) {
+ std::cout << "Application::action_context_for_document: no selection model" << std::endl;
return Inkscape::ActionContext();
}
return Inkscape::ActionContext(sel_iter->second->getSelection());
@@ -1309,7 +1310,7 @@ Application::exit ()
signal_shut_down.emit();
Inkscape::Preferences::unload();
- gtk_main_quit ();
+ //gtk_main_quit ();
}
diff --git a/src/io/CMakeLists.txt b/src/io/CMakeLists.txt
index 8c1322b94..cef86f637 100644
--- a/src/io/CMakeLists.txt
+++ b/src/io/CMakeLists.txt
@@ -2,6 +2,8 @@
set(io_SRC
dir-util.cpp
+ file.cpp
+ file-export-cmd.cpp
resource.cpp
resource-manager.cpp
stream/bufferstream.cpp
@@ -16,6 +18,8 @@ set(io_SRC
# -------
# Headers
dir-util.h
+ file.h
+ file-export-cmd.h
resource.h
resource-manager.h
stream/bufferstream.h
diff --git a/src/io/file-export-cmd.cpp b/src/io/file-export-cmd.cpp
new file mode 100644
index 000000000..46847634b
--- /dev/null
+++ b/src/io/file-export-cmd.cpp
@@ -0,0 +1,678 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * File export from the command line. This code, greatly modified, use to be in main.cpp. It should
+ * be replaced by code shared code shared with the file dialog (Gio::Actions?).
+ *
+ * Copyright (C) 2018 Tavmjong Bah
+ *
+ * Git blame shows that bulia byak is the main author of the orignal export code from
+ * main.cpp. Other authors of note include Nicolas Dufour, Vinicius dos Santos Oliveira, and Bob
+ * Jamison; none of whom bothered to add their names to the copyright of main.cc.
+ *
+ * The contents of this file may be used under the GNU General Public License Version 2 or later.
+ *
+ */
+
+#include "file-export-cmd.h"
+
+#include <png.h> // PNG export
+
+#include "document.h"
+#include "object/sp-item.h"
+#include "object/sp-root.h"
+#include "object/sp-text.h"
+#include "object/sp-flowtext.h"
+#include "object/sp-namedview.h"
+#include "object/sp-object-group.h"
+#include "path-chemistry.h" // sp_item_list_to_curves
+#include "text-editing.h" // te_update_layout_now_recursive
+#include "selection-chemistry.h" // fit_canvas_to_drawing
+#include "svg/svg-color.h" // Background color
+#include "helper/png-write.h" // PNG Export
+
+#include "extension/extension.h"
+#include "extension/system.h"
+#include "extension/db.h"
+#include "extension/output.h"
+#include "extension/init.h"
+
+InkFileExportCmd::InkFileExportCmd()
+ : over_write(false)
+ , export_type("svg")
+ , export_overwrite(false)
+ , export_area_drawing(false)
+ , export_area_page(false)
+ , export_margin(0)
+ , export_area_snap(false)
+ , export_use_hints(false)
+ , export_width(0)
+ , export_height(0)
+ , export_dpi(0)
+ , export_ignore_filters(false)
+ , export_text_to_path(false)
+ , export_ps_level(3)
+ , export_pdf_level("1.5")
+ , export_latex(false)
+ , export_id_only(false)
+ , export_background_opacity(1.0)
+ , export_plain_svg(false)
+{
+}
+
+void
+InkFileExportCmd::do_export(SPDocument* doc, std::string filename_in)
+{
+
+ std::string filename_out = get_filename_out(filename_in);
+
+ // We need a valid file name to write to unless we're using PNG export hints.
+ if (!(export_type == "png" && export_use_hints)) {
+
+ // Check for file name.
+ if (filename_out.empty()) {
+ std::cerr << "InkFileExportCmd::do_export: Could not determine ouput file name!" << std::endl;
+ return;
+ }
+
+ // Check if directory exists.
+ std::string directory = Glib::path_get_dirname(filename_out);
+ if (!Glib::file_test(directory, Glib::FILE_TEST_IS_DIR)) {
+ std::cerr << "InkFileExportCmd::do_export: File path includes directory that does not exist! " << directory << std::endl;
+ return;
+ }
+ }
+
+ if (export_type == "svg") {
+
+ do_export_svg(doc, filename_out);
+
+ } else if (export_type == "png") {
+
+ do_export_png(doc, filename_out);
+
+ } else if (export_type == "ps") {
+
+ do_export_ps_pdf(doc, filename_out, "image/x-postscript");
+
+ } else if (export_type == "eps") {
+
+ do_export_ps_pdf(doc, filename_out, "image/x-e-postscript");
+
+ } else if (export_type == "pdf") {
+
+ do_export_ps_pdf(doc, filename_out, "application/pdf");
+
+ } else if (export_type == "emf") {
+
+ do_export_win_metafile(doc, filename_out, "image/x-emf");
+
+ } else if (export_type == "wmf") {
+
+ do_export_win_metafile(doc, filename_out, "image/x-wmf");
+
+ } else if (export_type == "xaml") {
+
+ do_export_win_metafile(doc, filename_out, "text/xml+xaml");
+
+ } else {
+
+ std::cerr << "InkFileExportCmd::export: Unknown export type: " << export_type << std::endl;
+ }
+}
+
+std::string
+InkFileExportCmd::get_filename_out(std::string filename_in)
+{
+
+ if (export_type != "svg" &&
+ export_type != "png" &&
+ export_type != "ps" &&
+ export_type != "eps" &&
+ export_type != "pdf" &&
+ export_type != "emf" &&
+ export_type != "wmf" &&
+ export_type != "xaml" &&
+ export_type != "svg" ) {
+ std::cerr << "InkFileExportCmd::get_filename_out: Invalid export-type: " << export_type
+ << " Allowed values: [svg,png,ps,eps,pdf,emf,wmf,xaml]." << std::endl;
+ return (std::string());
+ }
+
+ // Writing to pipe.
+ if (export_filename == "-") {
+ return export_filename;
+ }
+
+ // Use export_filename if given.
+ if (!export_filename.empty()) {
+ // Check file extension matches file_type.
+ auto extension_pos = export_filename.find_last_of('.');
+
+ if (extension_pos == std::string::npos) {
+ std::cerr << "InkFileExportCmd::get_filename_out: no export_filename extension: " << export_filename << std::endl;
+ return (std::string());
+ }
+
+ std::string extension = export_filename.substr(extension_pos+1);
+ if (export_type != extension) {
+ std::cerr << "InkFileExportCmd::get_filename_out: mismatch between export_filename extension and export_type: "
+ << extension << ", " << export_type << std::endl;
+ return (std::string());
+ }
+
+ return export_filename;
+ }
+
+ // Construct output filename from input filename and export_type.
+ auto extension_pos = filename_in.find_last_of('.');
+ if (extension_pos == std::string::npos) {
+ std::cerr << "InkFileExportCmd::get_filename_out: cannot determine input file type from filename extension: " << filename_in << std::endl;
+ return (std::string());
+ }
+
+ std::string extension = filename_in.substr(extension_pos+1);
+ if (export_type == extension) {
+ if (export_overwrite) {
+ return filename_in;
+ } else {
+ // Add extra characters to filename.
+ filename_in.insert(extension_pos, "_out");
+ return filename_in;
+ }
+ } else {
+ return (filename_in.substr(0,extension_pos+1) + export_type);
+ }
+}
+
+/**
+ * Perform an SVG export
+ *
+ * \param doc Document to export.
+ */
+int
+InkFileExportCmd::do_export_svg(SPDocument* doc, std::string filename_out)
+{
+ if (export_text_to_path) {
+ std::vector<SPItem*> items;
+ SPRoot *root = doc->getRoot();
+ doc->ensureUpToDate();
+ for (auto& iter: root->children) {
+ SPItem* item = (SPItem*) &iter;
+ if (! (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item) || SP_IS_GROUP(item))) {
+ continue;
+ }
+
+ te_update_layout_now_recursive(item);
+ items.push_back(item);
+ }
+
+ std::vector<SPItem*> selected; // Not used
+ std::vector<Inkscape::XML::Node*> to_select; // Not used
+
+ sp_item_list_to_curves(items, selected, to_select);
+ }
+
+ if (export_margin != 0) {
+ gdouble margin = export_margin;
+ doc->ensureUpToDate();
+ SPNamedView *nv;
+ Inkscape::XML::Node *nv_repr;
+ if ((nv = sp_document_namedview(doc, nullptr)) && (nv_repr = nv->getRepr())) {
+ sp_repr_set_svg_double(nv_repr, "fit-margin-top", margin);
+ sp_repr_set_svg_double(nv_repr, "fit-margin-left", margin);
+ sp_repr_set_svg_double(nv_repr, "fit-margin-right", margin);
+ sp_repr_set_svg_double(nv_repr, "fit-margin-bottom", margin);
+ }
+ }
+
+ if(export_area_drawing) {
+ fit_canvas_to_drawing(doc, export_margin != 0 ? true : false);
+ }
+
+ if(!export_id.empty()) {
+ doc->ensureUpToDate();
+
+ // "crop" the document to the specified object, cleaning as we go.
+ SPObject *obj = doc->getObjectById(export_id);
+ if (export_id_only) {
+ // If -j then remove all other objects to complete the "crop"
+ doc->getRoot()->cropToObject(obj);
+ }
+ Inkscape::ObjectSet s(doc);
+ s.set(obj);
+ if (!export_area_page) {
+ s.fitCanvas(export_margin ? true : false);
+ }
+ }
+
+ int ret = 0;
+ if (export_plain_svg) {
+
+ try {
+ Inkscape::Extension::save(Inkscape::Extension::db.get("org.inkscape.output.svg.plain"), doc, filename_out.c_str(), false,
+ false, false, Inkscape::Extension::FILE_SAVE_METHOD_SAVE_COPY);
+ } catch (Inkscape::Extension::Output::save_failed &e) {
+ std::cerr << "InkFileExportCmd::do_export_svg: Failed to save SVG to: " << filename_out << std::endl;
+ ret = 1;
+ }
+
+ } else {
+
+ // Export as inkscape SVG.
+ try {
+ Inkscape::Extension::save(Inkscape::Extension::db.get("org.inkscape.output.svg.inkscape"), doc, filename_out.c_str(), false,
+ false, false, Inkscape::Extension::FILE_SAVE_METHOD_INKSCAPE_SVG);
+ } catch (Inkscape::Extension::Output::save_failed &e) {
+ std::cerr << "InkFileExportCmd::do_export_svg: Failed to save Inkscape SVG to: " << filename_out << std::endl;
+ ret = 1;
+ }
+ }
+ return ret;
+}
+
+
+/**
+ * Perform a PNG export
+ *
+ * \param doc Document to export.
+ */
+int
+InkFileExportCmd::do_export_png(SPDocument *doc, std::string filename_in)
+{
+ std::string filename = filename_in;
+
+ bool filename_from_hint = false;
+ gdouble dpi = 0.0;
+
+ if (export_use_hints && (export_id.empty() && !export_area_drawing)) {
+ g_warning ("--export-use-hints can only be used with --export-id or --export-area-drawing; ignored.");
+ }
+
+ std::vector<SPItem*> items;
+
+ // Find export area.
+ Geom::Rect area;
+ if (!export_id.empty() || export_area_drawing) {
+
+ SPObject *o = nullptr;
+ SPObject *o_area = nullptr;
+ if (!export_id.empty() && export_area_drawing) {
+ o = doc->getObjectById(export_id);
+ o_area = doc->getRoot();
+ } else if (!export_id.empty()) {
+ o = doc->getObjectById(export_id);
+ o_area = o;
+ } else if (export_area_drawing) {
+ o = doc->getRoot();
+ o_area = o;
+ }
+
+ if (o) {
+ if (!SP_IS_ITEM (o)) {
+ g_warning("Object with id=\"%s\" is not a visible item. Nothing exported.", export_id);
+ return 1;
+ }
+
+ items.push_back(SP_ITEM(o));
+
+ if (export_id_only) {
+// do_print_message("Exporting only object with id=\"%s\"; all other objects hidden\n", export_id);
+ }
+
+ if (export_use_hints) {
+
+ // retrieve export filename hint
+ const gchar *fn_hint = o->getRepr()->attribute("inkscape:export-filename");
+ if (fn_hint) {
+ if (!filename.empty()) {
+ g_warning ("Using export filename from the command line. Filename hint %s is ignored.", fn_hint);
+ } else {
+ filename = fn_hint;
+ filename_from_hint = true;
+ }
+ } else {
+ g_warning ("Export filename hint not found for the object.");
+ }
+
+ // retrieve export dpi hints
+ const gchar *dpi_hint = o->getRepr()->attribute("inkscape:export-xdpi"); // only xdpi, ydpi is always the same now
+ if (dpi_hint) {
+ if (export_dpi || export_width || export_height) {
+ g_warning ("Using bitmap dimensions from the command line (--export-dpi, --export-width, or --export-height). DPI hint %s is ignored.", dpi_hint);
+ } else {
+ dpi = atof(dpi_hint);
+ }
+ } else {
+ g_warning ("Export DPI hint not found for the object.");
+ }
+ }
+
+ // write object bbox to area
+ doc->ensureUpToDate();
+ Geom::OptRect areaMaybe = static_cast<SPItem *>(o_area)->desktopVisualBounds();
+ if (areaMaybe) {
+ area = *areaMaybe;
+ } else {
+ g_warning("Unable to determine a valid bounding box. Nothing exported.");
+ return 1;
+ }
+ } else {
+ g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", export_id);
+ return 1;
+ }
+ }
+
+ if (!export_area.empty()) {
+ /* Try to parse area (given in SVG pixels) */
+ gdouble x0,y0,x1,y1;
+ if (sscanf(export_area.c_str(), "%lg:%lg:%lg:%lg", &x0, &y0, &x1, &y1) != 4) {
+ g_warning("Cannot parse export area '%s'; use 'x0:y0:x1:y1'. Nothing exported.", export_area);
+ return 1;
+ }
+ area = Geom::Rect(Geom::Interval(x0,x1), Geom::Interval(y0,y1));
+ } else if (export_area_page || !(!export_id.empty() || export_area_drawing)) {
+ /* Export the whole page: note: Inkscape uses 'page' in all menus and dialogs, not 'canvas' */
+ doc->ensureUpToDate();
+ Geom::Point origin(doc->getRoot()->x.computed, doc->getRoot()->y.computed);
+ area = Geom::Rect(origin, origin + doc->getDimensions());
+ }
+ // End finding area.
+
+ // Check we have a filename.
+ if (filename.empty()) {
+ g_warning ("No export filename given and no filename hint. Nothing exported.");
+ return 1;
+ }
+
+ if (export_dpi != 0.0 && dpi == 0.0) {
+ dpi = export_dpi;
+ if ((dpi < 0.1) || (dpi > 10000.0)) {
+ g_warning("DPI value %s out of range [0.1 - 10000.0]. Nothing exported.", export_dpi);
+ return 1;
+ }
+// do_print_message("DPI: %g\n", dpi);
+ }
+
+ if (export_area_snap) {
+ area = area.roundOutwards();
+ }
+
+ // default dpi
+ if (dpi == 0.0) {
+ dpi = Inkscape::Util::Quantity::convert(1, "in", "px");
+ }
+
+ unsigned long int width = 0;
+ unsigned long int height = 0;
+
+ if (export_width != 0) {
+ errno=0;
+ width = export_width;
+ if ((width < 1) || (width > PNG_UINT_31_MAX) || (errno == ERANGE) ) {
+ g_warning("Export width %lu out of range (1 - %lu). Nothing exported.", width, (unsigned long int)PNG_UINT_31_MAX);
+ return 1;
+ }
+ dpi = (gdouble) Inkscape::Util::Quantity::convert(width, "in", "px") / area.width();
+ } else {
+ width = (unsigned long int) (Inkscape::Util::Quantity::convert(area.width(), "px", "in") * dpi + 0.5);
+ }
+
+ if (export_height != 0) {
+ errno=0;
+ height = export_height;
+ if ((height < 1) || (height > PNG_UINT_31_MAX)) {
+ g_warning("Export height %lu out of range (1 - %lu). Nothing exported.", height, (unsigned long int)PNG_UINT_31_MAX);
+ return 1;
+ }
+ dpi = (gdouble) Inkscape::Util::Quantity::convert(height, "in", "px") / area.height();
+ } else {
+ height = (unsigned long int) (Inkscape::Util::Quantity::convert(area.height(), "px", "in") * dpi + 0.5);
+ }
+
+ guint32 bgcolor = 0x00000000;
+ if (!export_background.empty()) {
+ // override the page color
+ bgcolor = sp_svg_read_color(export_background.c_str(), 0xffffff00);
+ bgcolor |= 0xff; // default is no opacity
+ } else {
+ // read from namedview
+ Inkscape::XML::Node *nv = sp_repr_lookup_name (doc->rroot, "sodipodi:namedview");
+ if (nv && nv->attribute("pagecolor")){
+ bgcolor = sp_svg_read_color(nv->attribute("pagecolor"), 0xffffff00);
+ }
+ if (nv && nv->attribute("inkscape:pageopacity")){
+ double opacity = 1.0;
+ sp_repr_get_double (nv, "inkscape:pageopacity", &opacity);
+ bgcolor |= SP_COLOR_F_TO_U(opacity);
+ }
+ }
+ bgcolor &= (guint32) 0xffffff00;
+
+ if (export_background_opacity > 1.0) {
+ float value = CLAMP (export_background_opacity, 1.0f, 255.0f);
+ bgcolor |= (guint32) floor(value);
+ } else {
+ float value = CLAMP (export_background_opacity, 0.0f, 1.0f);
+ bgcolor |= SP_COLOR_F_TO_U(value);
+ }
+
+ std::string path = filename; // File names are std::string, not Glib::ustring!
+ if (filename_from_hint) {
+ //Make relative paths go from the document location, if possible:
+ if (!Glib::path_is_absolute(filename) && doc->getURI()) {
+ std::string dirname = Glib::path_get_dirname(doc->getURI());
+ if (!dirname.empty()) {
+ path = Glib::build_filename(dirname, filename);
+ }
+ }
+ }
+
+ // Check if directory exists
+ std::string directory = Glib::path_get_dirname(path);
+ if (!Glib::file_test(directory, Glib::FILE_TEST_IS_DIR)) {
+ std::cerr << "File path " << path << " includes directory that doesn't exist." << std::endl;
+ return 1;
+ }
+
+ // Do we really need to print this?
+ std::cerr << "Background RRGGBBAA: " << std::hex << bgcolor << std::dec << std::endl;
+ std::cerr << "Area "
+ << area[Geom::X][0] << ":" << area[Geom::Y][0] << ":"
+ << area[Geom::X][1] << ":" << area[Geom::Y][1] << " exported to "
+ << width << " x " << height << " pixels (" << dpi << " dpi)" << std::endl;
+
+ reverse(items.begin(),items.end());
+
+ if ((width >= 1) && (height >= 1) && (width <= PNG_UINT_31_MAX) && (height <= PNG_UINT_31_MAX)) {
+ if( sp_export_png_file(doc, path.c_str(), area, width, height, dpi,
+ dpi, bgcolor, nullptr, nullptr, true, export_id_only ? items : std::vector<SPItem*>()) == 1 ) {
+// do_print_message("Bitmap saved as: %s\n", filename.c_str());
+ } else {
+ g_warning("Bitmap failed to save to: %s", filename.c_str());
+ return 1;
+ }
+ } 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);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * Perform a PDF/PS/EPS export
+ *
+ * \param doc Document to export.
+ * \param filename File to write to.
+ * \param mime MIME type to export as.
+ */
+int
+InkFileExportCmd::do_export_ps_pdf(SPDocument* doc, std::string filename, std::string mime_type)
+{
+ // Check if we support mime type.
+ Inkscape::Extension::DB::OutputList o;
+ Inkscape::Extension::db.get_output_list(o);
+ Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
+ while (i != o.end() && strcmp( (*i)->get_mimetype(), mime_type.c_str() ) != 0) {
+ i++;
+ }
+
+ if (i == o.end()) {
+ std::cerr << "InkFileExportCmd::do_export_ps_pdf: Could not find an extension to export to MIME type: " << mime_type << std::endl;
+ return 1;
+ }
+
+ // Export only object with given id.
+ if (!export_id.empty()) {
+ SPObject *o = doc->getObjectById(export_id);
+ if (o == nullptr) {
+ g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", export_id);
+ return 1;
+ }
+ (*i)->set_param_string ("exportId", export_id.c_str());
+ } else {
+ (*i)->set_param_string ("exportId", "");
+ }
+
+ // Set export area.
+ if (export_area_page && export_area_drawing) {
+ g_warning ("You cannot use --export-area-page and --export-area-drawing at the same time; only the former will take effect.");
+ export_area_drawing = false;
+ }
+
+ if (export_area_drawing) {
+ (*i)->set_param_optiongroup ("area", "drawing");
+ }
+
+ if (export_area_page) {
+ if (export_type == "eps") {
+ g_warning ("EPS cannot have its bounding box extend beyond its content, so if your drawing is smaller than the page, --export-area-page will clip it to drawing.");
+ }
+ (*i)->set_param_optiongroup ("area", "page");
+ }
+
+ if (!export_area_drawing && !export_area_page && export_id.empty()) {
+ // neither is set, set page as default for ps/pdf and drawing for eps
+ if (export_type == "eps") {
+ try {
+ (*i)->set_param_optiongroup("area", "drawing");
+ } catch (...) {}
+ }
+ }
+
+ // Set export options.
+ if (export_text_to_path) {
+ (*i)->set_param_optiongroup("textToPath", "paths");
+ } else if (export_latex) {
+ (*i)->set_param_optiongroup("textToPath", "LaTeX");
+ } else {
+ (*i)->set_param_optiongroup("textToPath", "embed");
+ }
+
+ if (export_ignore_filters) {
+ (*i)->set_param_bool("blurToBitmap", false);
+ } else {
+ (*i)->set_param_bool("blurToBitmap", true);
+
+ gdouble dpi = 96.0;
+ if (export_dpi) {
+ dpi = export_dpi;
+ if ((dpi < 1) || (dpi > 10000.0)) {
+ g_warning("DPI value %d out of range [1 - 10000]. Using 96 dpi instead.", export_dpi);
+ dpi = 96;
+ }
+ }
+
+ (*i)->set_param_int("resolution", (int) dpi);
+ }
+
+ (*i)->set_param_float("bleed", export_margin);
+
+ // handle --export-pdf-version
+ if (mime_type == "application/pdf") {
+ bool set_export_pdf_version_fail = true;
+ const gchar *pdfver_param_name = "PDFversion";
+ if (!export_pdf_level.empty()) {
+ // combine "PDF " and the given command line
+ std::string version_gui_string = std::string("PDF ") + export_pdf_level;
+ try{
+ // first, check if the given pdf version is selectable in the ComboBox
+ if((*i)->get_param_enum_contains("PDFversion", version_gui_string.c_str())) {
+ (*i)->set_param_enum(pdfver_param_name, version_gui_string.c_str());
+ set_export_pdf_version_fail=false;
+ } else {
+ g_warning("Desired PDF export version \"%s\" not supported! Hint: input one of the versions found in the pdf export dialog e.g. \"1.4\".",
+ export_pdf_level);
+ }
+ } catch (...) {
+ // can be thrown along the way:
+ // throw Extension::param_not_exist();
+ // throw Extension::param_not_enum_param();
+ g_warning("Parameter or Enum \"%s\" might not exist", pdfver_param_name);
+ }
+ }
+
+ // set default pdf export version to 1.4, also if something went wrong
+ if(set_export_pdf_version_fail) {
+ (*i)->set_param_enum(pdfver_param_name, "PDF 1.4");
+ }
+ }
+
+ if (mime_type == "image/x-postscript" || mime_type == "image/x-e-postscript") {
+ if ( export_ps_level < 2 || export_ps_level > 3 ) {
+ g_warning("Only supported PostScript levels are 2 and 3."
+ " Defaulting to 2.");
+ export_ps_level = 2;
+ }
+
+ (*i)->set_param_enum("PSlevel", (export_ps_level == 3)
+ ? "PostScript level 3" : "PostScript level 2");
+ }
+
+ try {
+ (*i)->save(doc, filename.c_str());
+ } catch(...) {
+ std::cerr << "Failed to save PS/EPS/PDF to: " << filename << std::endl;
+ }
+ return 0;
+}
+
+/**
+ * Export a document to EMF or WMF
+ *
+ * \param doc Document to export.
+ * \param filename to export to.
+ * \param mime MIME type to export as (should be "image/x-emf" or "image/x-wmf")
+ */
+int
+InkFileExportCmd::do_export_win_metafile(SPDocument* doc, std::string filename, std::string mime_type)
+{
+ // Check if we support mime type.
+ Inkscape::Extension::DB::OutputList o;
+ Inkscape::Extension::db.get_output_list(o);
+ Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
+ while (i != o.end() && strcmp( (*i)->get_mimetype(), mime_type.c_str() ) != 0) {
+ i++;
+ }
+
+ if (i == o.end())
+ {
+ std::cerr << "InkFileExportCmd::do_export_win_metafile_common: Could not find an extension to export to MIME type: " << mime_type << std::endl;
+ return 1;
+ }
+
+ (*i)->save(doc, filename.c_str());
+ return 0;
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/io/file-export-cmd.h b/src/io/file-export-cmd.h
new file mode 100644
index 000000000..0f7dd994b
--- /dev/null
+++ b/src/io/file-export-cmd.h
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * File export from the command line. This code use to be in main.cpp. It should be
+ * replaced by shared code (Gio::Actions?) for export from the file dialog.
+ *
+ * Copyright (C) 2018 Tavmjong Bah
+ *
+ * The contents of this file may be used under the GNU General Public License Version 2 or later.
+ *
+ */
+
+#ifndef INK_FILE_EXPORT_CMD_H
+#define INK_FILE_EXPORT_CMD_H
+
+#include <iostream>
+#include <gtkmm.h>
+
+class SPDocument;
+
+class InkFileExportCmd {
+
+public:
+ InkFileExportCmd();
+
+ void do_export(SPDocument* doc, std::string filename_in="");
+
+private:
+
+ std::string get_filename_out(std::string filename_in="");
+ int do_export_svg( SPDocument* doc, std::string filename_out);
+ int do_export_png( SPDocument* doc, std::string filename_out);
+ int do_export_ps_pdf(SPDocument* doc, std::string filename_out, std::string mime_type);
+ int do_export_win_metafile(SPDocument* doc, std::string filename_out, std::string mime_type);
+
+public:
+ // Should be private, but this is just temporary code (I hope!).
+
+ bool over_write;
+
+ // One-to-one correspondence with command line options
+ std::string export_filename; // Only if one file is processed!
+
+ Glib::ustring export_type;
+ bool export_overwrite;
+
+ Glib::ustring export_area;
+ bool export_area_drawing;
+ bool export_area_page;
+ int export_margin;
+ bool export_area_snap;
+ int export_width;
+ int export_height;
+
+ int export_dpi;
+ bool export_ignore_filters;
+ bool export_text_to_path;
+ int export_ps_level;
+ Glib::ustring export_pdf_level;
+ bool export_latex;
+ Glib::ustring export_id;
+ bool export_id_only;
+ bool export_use_hints;
+ Glib::ustring export_background;
+ double export_background_opacity;
+ bool export_plain_svg;
+};
+
+#endif // INK_FILE_EXPORT_CMD_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/io/file.cpp b/src/io/file.cpp
new file mode 100644
index 000000000..3505f018d
--- /dev/null
+++ b/src/io/file.cpp
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * File operations (independent of GUI)
+ *
+ * Copyright (C) 2018 Tavmjong Bah
+ *
+ * The contents of this file may be used under the GNU General Public License Version 2 or later.
+ *
+ */
+
+#include <iostream>
+#include <gtkmm.h>
+
+#include "file.h"
+
+#include "document.h"
+
+#include "extension/system.h" // Extension::open()
+#include "extension/extension.h"
+#include "extension/db.h"
+#include "extension/output.h"
+#include "extension/input.h"
+
+// SPDocument*
+// ink_file_new(const std::string &Template)
+// {
+// SPDocument *doc = SPDocument::createNewDoc( Template, true, true );
+// return doc;
+// }
+
+
+SPDocument*
+ink_file_open(const Glib::RefPtr<Gio::File>& file)
+{
+
+ SPDocument *doc = nullptr;
+
+ std::string path = file->get_path();
+
+ try {
+ doc = Inkscape::Extension::open(nullptr, path.c_str());
+ } catch (Inkscape::Extension::Input::no_extension_found &e) {
+ doc = nullptr;
+ } catch (Inkscape::Extension::Input::open_failed &e) {
+ doc = nullptr;
+ }
+
+ // Try to open explicitly as SVG.
+ if (doc == nullptr) {
+ try {
+ doc = Inkscape::Extension::open(Inkscape::Extension::db.get(SP_MODULE_KEY_INPUT_SVG), path.c_str());
+ } catch (Inkscape::Extension::Input::no_extension_found &e) {
+ doc = nullptr;
+ } catch (Inkscape::Extension::Input::open_failed &e) {
+ doc = nullptr;
+ }
+ }
+ if (doc == nullptr) {
+ std::cerr << "ink_file_open: '" << path << "' cannot be opened!" << std::endl;
+ }
+
+ return doc;
+}
+
diff --git a/src/io/file.h b/src/io/file.h
new file mode 100644
index 000000000..e1b91adcd
--- /dev/null
+++ b/src/io/file.h
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * File operations (independent of GUI)
+ *
+ * Copyright (C) 2018 Tavmjong Bah
+ *
+ * The contents of this file may be used under the GNU General Public License Version 2 or later.
+ *
+ */
+
+#ifndef INK_FILE_IO_H
+#define INK_FILE_IO_H
+
+class SPDocument;
+
+//SPDocument* ink_file_new(const std::string &template = nullptr);
+SPDocument* ink_file_open(const Glib::RefPtr<Gio::File>& file = Glib::RefPtr<Gio::File>());
+
+// To do:
+// ink_file_save()
+// ink_file_export()
+// ink_file_import()
+
+
+
+#endif // INK_FILE_IO_H
diff --git a/src/main.cpp b/src/main.cpp
deleted file mode 100644
index 0f6269611..000000000
--- a/src/main.cpp
+++ /dev/null
@@ -1,2251 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Inkscape - an ambitious vector drawing program
- *
- * Authors:
- * Lauris Kaplinski <lauris@kaplinski.com>
- * Frank Felfe <innerspace@iname.com>
- * Davide Puricelli <evo@debian.org>
- * Mitsuru Oka <oka326@parkcity.ne.jp>
- * Masatake YAMATO <jet@gyve.org>
- * F.J.Franklin <F.J.Franklin@sheffield.ac.uk>
- * Michael Meeks <michael@helixcode.com>
- * Chema Celorio <chema@celorio.com>
- * Pawel Palucha
- * Bryce Harrington <bryce@bryceharrington.org>
- * ... and various people who have worked with various projects
- * Jon A. Cruz <jon@oncruz.org>
- * Abhishek Sharma
- * Marc Jeanmougin
- *
- * Copyright (C) 1999-2004 authors
- * Copyright (C) 2001-2002 Ximian, Inc.
- *
- * Released under GNU GPL v2+, read the file 'COPYING' for more information.
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-// This has to be included prior to anything that includes setjmp.h, it croaks otherwise
-#include <png.h>
-
-#include <cstring>
-
-#include <popt.h>
-#ifndef POPT_TABLEEND
-#define POPT_TABLEEND { NULL, '\0', 0, 0, 0, NULL, NULL }
-#endif /* Not def: POPT_TABLEEND */
-
-#include <libxml/tree.h>
-
-#include "ui/widget/panel.h" // This has to be the first to include <glib.h> because of Glibmm's dependence on a deprecated feature...
-
-#include <glibmm/i18n.h>
-#include <glibmm/convert.h>
-#include <glibmm/fileutils.h>
-#include <glibmm/miscutils.h>
-#include <glibmm/main.h>
-#include <gtkmm/main.h>
-#include <gtkmm/window.h>
-#include <gdkmm/screen.h>
-
-#include <cerrno>
-
-#ifdef _WIN32
-#include <windows.h>
-#include "io/registrytool.h"
-#endif // _WIN32
-
-#include "inkscape.h"
-#include "inkscape-version.h"
-
-#include "color.h"
-#include "document.h"
-#include "file.h"
-#include "layer-model.h"
-#include "path-chemistry.h"
-#include "path-prefix.h"
-#include "print.h"
-#include "selection-chemistry.h"
-#include "selection.h"
-#include "text-editing.h"
-#include "verbs.h"
-
-#include "debug/logger.h"
-#include "debug/log-display-config.h"
-
-#include "extension/extension.h"
-#include "extension/db.h"
-#include "extension/output.h"
-#include "extension/input.h"
-#include "extension/init.h"
-// Not ideal, but there doesn't appear to be a nicer system in place for
-// passing command-line parameters to extensions before initialization...
-#ifdef WITH_DBUS
-#include "extension/dbus/dbus-init.h"
-#endif // WITH_DBUS
-
-#include "helper/action-context.h"
-#include "helper/png-write.h"
-#ifdef ENABLE_NLS
-#include "helper/gettext.h"
-#endif
-
-#include "inkgc/gc-core.h"
-
-#include "io/resource.h"
-#include "io/sys.h"
-
-#include "object/object-set.h"
-#include "object/sp-guide.h"
-#include "object/sp-root.h"
-#include "object/sp-namedview.h"
-#include "object/sp-text.h"
-#include "object/sp-flowtext.h"
-
-#include "ui/interface.h"
-
-#include "svg/svg.h"
-#include "svg/svg-color.h"
-#include "svg/stringstream.h"
-
-#include "xml/repr.h"
-
-#include "main-cmdlineact.h"
-#include "main-cmdlinexact.h"
-
-
-enum {
- SP_ARG_NONE,
- SP_ARG_NOGUI,
- SP_ARG_GUI,
- SP_ARG_FILE,
- SP_ARG_XVERBS,
- SP_ARG_PRINT,
- SP_ARG_EXPORT_PNG,
- SP_ARG_EXPORT_DPI,
- SP_ARG_EXPORT_AREA,
- SP_ARG_EXPORT_AREA_DRAWING,
- SP_ARG_EXPORT_AREA_PAGE,
- SP_ARG_EXPORT_MARGIN,
- SP_ARG_EXPORT_AREA_SNAP,
- SP_ARG_EXPORT_WIDTH,
- SP_ARG_EXPORT_HEIGHT,
- SP_ARG_EXPORT_ID,
- SP_ARG_EXPORT_ID_ONLY,
- SP_ARG_EXPORT_USE_HINTS,
- SP_ARG_EXPORT_BACKGROUND,
- SP_ARG_EXPORT_BACKGROUND_OPACITY,
- SP_ARG_EXPORT_SVG,
- SP_ARG_EXPORT_INKSCAPE_SVG,
- SP_ARG_EXPORT_PS,
- SP_ARG_EXPORT_EPS,
- SP_ARG_EXPORT_PS_LEVEL,
- SP_ARG_EXPORT_PDF,
- SP_ARG_EXPORT_PDF_VERSION,
- SP_ARG_EXPORT_LATEX,
- SP_ARG_EXPORT_EMF,
- SP_ARG_EXPORT_WMF,
- SP_ARG_EXPORT_XAML,
- SP_ARG_EXPORT_TEXT_TO_PATH,
- SP_ARG_EXPORT_IGNORE_FILTERS,
- SP_ARG_PDF_PAGE,
- SP_ARG_EXTENSIONDIR,
- SP_ARG_QUERY_X,
- SP_ARG_QUERY_Y,
- SP_ARG_QUERY_WIDTH,
- SP_ARG_QUERY_HEIGHT,
- SP_ARG_QUERY_ALL,
- SP_ARG_QUERY_ID,
- SP_ARG_SHELL,
- SP_ARG_VERSION,
- SP_ARG_VACUUM_DEFS,
- SP_ARG_NO_CONVERT_TEXT_BASELINE_SPACING,
- SP_ARG_CONVERT_DPI_METHOD,
-#ifdef WITH_DBUS
- SP_ARG_DBUS_LISTEN,
- SP_ARG_DBUS_NAME,
-#endif // WITH_DBUS
- SP_ARG_VERB_LIST,
- SP_ARG_VERB,
- SP_ARG_SELECT,
- SP_ARG_LAST
-};
-
-int sp_main_gui(int argc, char const **argv);
-int sp_main_console(int argc, char const **argv);
-static int do_export_png(SPDocument *doc);
-static int do_export_svg(SPDocument* doc);
-static int do_export_ps_pdf(SPDocument* doc, gchar const* uri, char const *mime);
-static int do_export_emf(SPDocument* doc, gchar const* uri, char const *mime);
-static int do_export_wmf(SPDocument* doc, gchar const* uri, char const *mime);
-static int do_export_xaml(SPDocument* doc, gchar const* uri, char const *mime);
-static int do_export_win_metafile_common(SPDocument* doc, gchar const* uri, char const *mime);
-static void do_query_dimension (SPDocument *doc, bool extent, Geom::Dim2 const axis, const gchar *id);
-static void do_query_all (SPDocument *doc);
-static void do_query_all_recurse (SPObject *o);
-static void do_print_message(const char *message, ...);
-static void detect_pipe_in_filename(const char *filename);
-
-static gchar *sp_global_printer = nullptr;
-static gchar *sp_export_png = nullptr;
-static gchar *sp_export_dpi = nullptr;
-static gchar *sp_export_area = nullptr;
-static gboolean sp_export_area_drawing = FALSE;
-static gboolean sp_export_area_page = FALSE;
-static gchar *sp_export_margin = nullptr;
-static gboolean sp_export_latex = FALSE;
-static gchar *sp_export_width = nullptr;
-static gchar *sp_export_height = nullptr;
-static gchar *sp_export_id = nullptr;
-static gchar *sp_export_background = nullptr;
-static gchar *sp_export_background_opacity = nullptr;
-static gboolean sp_export_area_snap = FALSE;
-static gboolean sp_export_use_hints = FALSE;
-static gboolean sp_export_id_only = FALSE;
-static gchar *sp_export_svg = nullptr;
-static gchar *sp_export_inkscape_svg = nullptr;
-static gchar *sp_export_ps = nullptr;
-static gchar *sp_export_eps = nullptr;
-static gint sp_export_ps_level = 3;
-static gchar *sp_export_pdf = nullptr;
-static gchar *sp_export_pdf_version = nullptr;
-static gchar *sp_export_emf = nullptr;
-static gchar *sp_export_wmf = nullptr;
-static gchar *sp_export_xaml = nullptr;
-static gboolean sp_export_text_to_path = FALSE;
-static gboolean sp_export_ignore_filters = FALSE;
-static gboolean sp_export_font = FALSE;
-static gint sp_pdf_page = 1;
-static gboolean sp_query_x = FALSE;
-static gboolean sp_query_y = FALSE;
-static gboolean sp_query_width = FALSE;
-static gboolean sp_query_height = FALSE;
-static gboolean sp_query_all = FALSE;
-static gchar *sp_query_id = nullptr;
-static gboolean sp_shell = FALSE;
-static gboolean sp_vacuum_defs = FALSE;
-#ifdef WITH_DBUS
-static gboolean sp_dbus_listen = FALSE;
-static gchar *sp_dbus_name = NULL;
-#endif // WITH_DBUS
-static gchar *sp_export_png_utf8 = nullptr;
-static gchar *sp_export_svg_utf8 = nullptr;
-static gchar *sp_export_inkscape_svg_utf8 = nullptr;
-static gchar *sp_global_printer_utf8 = nullptr;
-static gboolean sp_writingToPipe = FALSE;
-
-#ifdef WITH_YAML
-static gchar *sp_xverbs_yaml_utf8 = nullptr;
-static gchar *sp_xverbs_yaml = nullptr;
-#endif // WITH_YAML
-
-/**
- * Reset variables to default values.
- */
-static void resetCommandlineGlobals() {
- sp_global_printer = nullptr;
- sp_export_png = nullptr;
- sp_export_dpi = nullptr;
- sp_export_area = nullptr;
- sp_export_area_drawing = FALSE;
- sp_export_area_page = FALSE;
- sp_export_margin = nullptr;
- sp_export_latex = FALSE;
- sp_export_width = nullptr;
- sp_export_height = nullptr;
- sp_export_id = nullptr;
- sp_export_background = nullptr;
- sp_export_background_opacity = nullptr;
- sp_export_area_snap = FALSE;
- sp_export_use_hints = FALSE;
- sp_export_id_only = FALSE;
- sp_export_svg = nullptr;
- sp_export_inkscape_svg = nullptr;
- sp_export_ps = nullptr;
- sp_export_eps = nullptr;
- sp_export_ps_level = 3;
- sp_export_pdf = nullptr;
- sp_export_pdf_version = nullptr;
- sp_export_emf = nullptr;
- sp_export_wmf = nullptr;
- sp_export_xaml = nullptr;
- sp_export_text_to_path = FALSE;
- sp_export_ignore_filters = FALSE;
- sp_export_font = FALSE;
- sp_pdf_page = 1;
- sp_query_x = FALSE;
- sp_query_y = FALSE;
- sp_query_width = FALSE;
- sp_query_height = FALSE;
- sp_query_all = FALSE;
- sp_query_id = nullptr;
- sp_vacuum_defs = FALSE;
- sp_no_convert_text_baseline_spacing = FALSE;
- sp_file_convert_dpi_method_commandline = -1;
-#ifdef WITH_DBUS
- sp_dbus_listen = FALSE;
- sp_dbus_name = NULL;
-#endif // WITH_DBUS
-
- sp_export_png_utf8 = nullptr;
- sp_export_svg_utf8 = nullptr;
- sp_export_inkscape_svg_utf8 = nullptr;
- sp_global_printer_utf8 = nullptr;
-}
-
-#ifdef _WIN32
-static bool replaceArgs( int& argc, char**& argv );
-#endif
-static std::vector<gchar *> sp_process_args(poptContext ctx);
-struct poptOption options[] = {
- {"version", 'V',
- POPT_ARG_NONE, nullptr, SP_ARG_VERSION,
- N_("Print the Inkscape version number"),
- nullptr},
-
- {"without-gui", 'z',
- POPT_ARG_NONE, nullptr, SP_ARG_NOGUI,
- N_("Do not use X server (only process files from console)"),
- nullptr},
-
- {"with-gui", 'g',
- POPT_ARG_NONE, nullptr, SP_ARG_GUI,
- N_("Try to use X server (even if $DISPLAY is not set)"),
- nullptr},
-
- {"file", 'f',
- POPT_ARG_STRING, nullptr, SP_ARG_FILE,
- N_("Open specified document(s) (option string may be excluded)"),
- N_("FILENAME")},
-
-#ifdef WITH_YAML
- {"xverbs", 0,
- POPT_ARG_STRING, &sp_xverbs_yaml, SP_ARG_XVERBS,
- N_("xverbs command"),
- N_("XVERBS_FILENAME")},
-#endif // WITH_YAML
-
- {"print", 'p',
- POPT_ARG_STRING, &sp_global_printer, SP_ARG_PRINT,
- N_("Print document(s) to specified output file (use '| program' for pipe)"),
- N_("FILENAME")},
-
- {"export-png", 'e',
- POPT_ARG_STRING, &sp_export_png, SP_ARG_EXPORT_PNG,
- N_("Export document to a PNG file"),
- N_("FILENAME")},
-
- {"export-dpi", 'd',
- POPT_ARG_STRING, &sp_export_dpi, SP_ARG_EXPORT_DPI,
- N_("Resolution for exporting to bitmap and for rasterization of filters in PS/EPS/PDF (default 96)"),
- N_("DPI")},
-
- {"export-area", 'a',
- POPT_ARG_STRING, &sp_export_area, SP_ARG_EXPORT_AREA,
- N_("Exported area in SVG user units (default is the page; 0,0 is lower-left corner)"),
- N_("x0:y0:x1:y1")},
-
- {"export-area-drawing", 'D',
- POPT_ARG_NONE, &sp_export_area_drawing, SP_ARG_EXPORT_AREA_DRAWING,
- N_("Exported area is the entire drawing (not page)"),
- nullptr},
-
- {"export-area-page", 'C',
- POPT_ARG_NONE, &sp_export_area_page, SP_ARG_EXPORT_AREA_PAGE,
- N_("Exported area is the entire page"),
- nullptr},
-
- {"export-margin", 0,
- POPT_ARG_STRING, &sp_export_margin, SP_ARG_EXPORT_MARGIN,
- N_("Sets margin around exported area (default 0) in units of page size for SVG and mm for PS/EPS/PDF"),
- N_("VALUE")},
-
- {"export-area-snap", 0,
- POPT_ARG_NONE, &sp_export_area_snap, SP_ARG_EXPORT_AREA_SNAP,
- N_("Snap the bitmap export area outwards to the nearest integer values (in SVG user units)"),
- nullptr},
-
- {"export-width", 'w',
- POPT_ARG_STRING, &sp_export_width, SP_ARG_EXPORT_WIDTH,
- N_("The width of exported bitmap in pixels (overrides export-dpi)"),
- N_("WIDTH")},
-
- {"export-height", 'h',
- POPT_ARG_STRING, &sp_export_height, SP_ARG_EXPORT_HEIGHT,
- N_("The height of exported bitmap in pixels (overrides export-dpi)"),
- N_("HEIGHT")},
-
- {"export-id", 'i',
- POPT_ARG_STRING, &sp_export_id, SP_ARG_EXPORT_ID,
- N_("The ID of the object to export"),
- N_("ID")},
-
- {"export-id-only", 'j',
- POPT_ARG_NONE, &sp_export_id_only, SP_ARG_EXPORT_ID_ONLY,
- // TRANSLATORS: this means: "Only export the object whose id is given in --export-id".
- // See "man inkscape" for details.
- N_("Export just the object with export-id, hide all others (only with export-id)"),
- nullptr},
-
- {"export-use-hints", 't',
- POPT_ARG_NONE, &sp_export_use_hints, SP_ARG_EXPORT_USE_HINTS,
- N_("Use stored filename and DPI hints when exporting (only with export-id)"),
- nullptr},
-
- {"export-background", 'b',
- POPT_ARG_STRING, &sp_export_background, SP_ARG_EXPORT_BACKGROUND,
- N_("Background color of exported bitmap (any SVG-supported color string)"),
- N_("COLOR")},
-
- {"export-background-opacity", 'y',
- POPT_ARG_STRING, &sp_export_background_opacity, SP_ARG_EXPORT_BACKGROUND_OPACITY,
- N_("Background opacity of exported bitmap (either 0.0 to 1.0, or 1 to 255)"),
- N_("VALUE")},
-
- {"export-inkscape-svg", 0,
- POPT_ARG_STRING, &sp_export_inkscape_svg, SP_ARG_EXPORT_INKSCAPE_SVG,
- N_("Export document to an inkscape SVG file (similar to save as.)"),
- N_("FILENAME")},
- {"export-plain-svg", 'l',
- POPT_ARG_STRING, &sp_export_svg, SP_ARG_EXPORT_SVG,
- N_("Export document to plain SVG file (no sodipodi or inkscape namespaces)"),
- N_("FILENAME")},
-
- {"export-ps", 'P',
- POPT_ARG_STRING, &sp_export_ps, SP_ARG_EXPORT_PS,
- N_("Export document to a PS file"),
- N_("FILENAME")},
-
- {"export-eps", 'E',
- POPT_ARG_STRING, &sp_export_eps, SP_ARG_EXPORT_EPS,
- N_("Export document to an EPS file"),
- N_("FILENAME")},
-
- {"export-ps-level", 0,
- POPT_ARG_INT, &sp_export_ps_level, SP_ARG_EXPORT_PS_LEVEL,
- N_("Choose the PostScript Level used to export. Possible choices are"
- " 2 and 3 (the default)"),
- N_("PS Level")},
-
- {"export-pdf", 'A',
- POPT_ARG_STRING, &sp_export_pdf, SP_ARG_EXPORT_PDF,
- N_("Export document to a PDF file"),
- N_("FILENAME")},
-
- {"export-pdf-version", 0,
- POPT_ARG_STRING, &sp_export_pdf_version, SP_ARG_EXPORT_PDF_VERSION,
- // TRANSLATORS: "--export-pdf-version" is an Inkscape command line option; see "inkscape --help"
- N_("Export PDF to given version. (hint: make sure to input a version found in the PDF export dialog, e.g. \"1.4\" which is PDF-a conformant)"),
- N_("PDF_VERSION")},
-
- {"export-latex", 0,
- POPT_ARG_NONE, &sp_export_latex, SP_ARG_EXPORT_LATEX,
- N_("Export PDF/PS/EPS without text. Besides the PDF/PS/EPS, a LaTeX file is exported, putting the text on top of the PDF/PS/EPS file. Include the result in LaTeX like: \\input{latexfile.tex}"),
- nullptr},
-
- {"export-emf", 'M',
- POPT_ARG_STRING, &sp_export_emf, SP_ARG_EXPORT_EMF,
- N_("Export document to an Enhanced Metafile (EMF) File"),
- N_("FILENAME")},
-
- {"export-wmf", 'm',
- POPT_ARG_STRING, &sp_export_wmf, SP_ARG_EXPORT_WMF,
- N_("Export document to a Windows Metafile (WMF) File"),
- N_("FILENAME")},
-
- {"export-xaml", 0,
- POPT_ARG_STRING, &sp_export_xaml, SP_ARG_EXPORT_XAML,
- N_("Export document to a eXtensible Application Markup Language (XAML) File"),
- N_("FILENAME")},
-
- {"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 (PS, EPS, PDF, SVG)"),
- nullptr},
-
- {"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)"),
- nullptr},
-
- {"pdf-page", 0,
- POPT_ARG_INT, &sp_pdf_page, SP_ARG_PDF_PAGE,
- N_("PDF page to import"),
- N_("PAGE")},
-
- {"query-x", 'X',
- POPT_ARG_NONE, &sp_query_x, SP_ARG_QUERY_X,
- // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
- N_("Query the X coordinate of the drawing or, if specified, of the object with --query-id"),
- nullptr},
-
- {"query-y", 'Y',
- POPT_ARG_NONE, &sp_query_y, SP_ARG_QUERY_Y,
- // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
- N_("Query the Y coordinate of the drawing or, if specified, of the object with --query-id"),
- nullptr},
-
- {"query-width", 'W',
- POPT_ARG_NONE, &sp_query_width, SP_ARG_QUERY_WIDTH,
- // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
- N_("Query the width of the drawing or, if specified, of the object with --query-id"),
- nullptr},
-
- {"query-height", 'H',
- POPT_ARG_NONE, &sp_query_height, SP_ARG_QUERY_HEIGHT,
- // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
- N_("Query the height of the drawing or, if specified, of the object with --query-id"),
- nullptr},
-
- {"query-all", 'S',
- POPT_ARG_NONE, &sp_query_all, SP_ARG_QUERY_ALL,
- N_("List id,x,y,w,h for all objects"),
- nullptr},
-
- {"query-id", 'I',
- POPT_ARG_STRING, &sp_query_id, SP_ARG_QUERY_ID,
- N_("The ID of the object whose dimensions are queried"),
- N_("ID")},
-
- {"extension-directory", 'x',
- POPT_ARG_NONE, nullptr, SP_ARG_EXTENSIONDIR,
- // TRANSLATORS: this option makes Inkscape print the name (path) of the extension directory
- N_("Print out the extension directory and exit"),
- nullptr},
-
- {"vacuum-defs", 0,
- POPT_ARG_NONE, &sp_vacuum_defs, SP_ARG_VACUUM_DEFS,
- N_("Remove unused definitions from the defs section(s) of the document"),
- nullptr},
-
-#ifdef WITH_DBUS
- {"dbus-listen", 0,
- POPT_ARG_NONE, &sp_dbus_listen, SP_ARG_DBUS_LISTEN,
- N_("Enter a listening loop for D-Bus messages in console mode"),
- NULL},
-
- {"dbus-name", 0,
- POPT_ARG_STRING, &sp_dbus_name, SP_ARG_DBUS_NAME,
- N_("Specify the D-Bus bus name to listen for messages on (default is org.inkscape)"),
- N_("BUS-NAME")},
-#endif // WITH_DBUS
-
- {"verb-list", 0,
- POPT_ARG_NONE, nullptr, SP_ARG_VERB_LIST,
- N_("List the IDs of all the verbs in Inkscape"),
- nullptr},
-
- {"verb", 0,
- POPT_ARG_STRING, nullptr, SP_ARG_VERB,
- N_("Verb to call when Inkscape opens."),
- N_("VERB-ID")},
-
- {"select", 0,
- POPT_ARG_STRING, nullptr, SP_ARG_SELECT,
- N_("Object ID to select when Inkscape opens."),
- N_("OBJECT-ID")},
-
- {"shell", 0,
- POPT_ARG_NONE, &sp_shell, SP_ARG_SHELL,
- N_("Start Inkscape in interactive shell mode."),
- nullptr},
-
- {"no-convert-text-baseline-spacing", 0,
- POPT_ARG_NONE, &sp_no_convert_text_baseline_spacing, SP_ARG_NO_CONVERT_TEXT_BASELINE_SPACING,
- N_("Do not fix legacy (pre-0.92) files' text baseline spacing on opening."),
- nullptr},
-
- {"convert-dpi-method", 0,
- POPT_ARG_STRING, nullptr, SP_ARG_CONVERT_DPI_METHOD,
- N_("Method used to convert pre-.92 document dpi, if needed. ([none|scale-viewbox|scale-document])"),
- "[...]"},
-
- POPT_AUTOHELP POPT_TABLEEND
-};
-
-static bool needToRecodeParams = true;
-gchar * blankParam = g_strdup("");
-
-
-
-#ifdef _WIN32
-
-/**
- * Set up the PATH, INKSCAPE_LOCALEDIR and PYTHONPATH environment
- * variables on Windows
- * @param exe Inkscape executable directory in UTF-8
- */
-static void _win32_set_inkscape_env(gchar const *exe)
-{
- // add inkscape directory to DLL search path so dynamically linked extension modules find their libraries
- wchar_t *exe_w = (wchar_t *)g_utf8_to_utf16(exe, -1, NULL, NULL, NULL);
- SetDllDirectoryW(exe_w);
- g_free(exe_w);
-
- // add inkscape directory to PATH
- gchar const *path = g_getenv("PATH");
- gchar *new_path;
- if (path) {
- new_path = g_strdup_printf("%s;%s", exe, path);
- } else {
- new_path = g_strdup(exe);
- }
- g_setenv("PATH", new_path, TRUE);
- g_free(new_path);
-
- // INKSCAPE_LOCALEDIR is needed by Python/Gettext
- gchar *localepath = g_build_filename(exe, PACKAGE_LOCALE_DIR, NULL);
- g_setenv("INKSCAPE_LOCALEDIR", localepath, TRUE);
- g_free(localepath);
-
- // prevent "please insert disk" messages. fixes bug #950781
- SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
-}
-#endif
-
-static void set_extensions_env()
-{
- gchar *pythonpath = get_extensions_path();
- g_setenv("PYTHONPATH", pythonpath, TRUE);
- g_free(pythonpath);
- // printf("PYTHONPATH = %s\n", g_getenv("PYTHONPATH"));
-}
-
-
-/**
- * This is the classic main() entry point of the program, though on some
- * architectures it might be called by something else.
- */
-int
-main(int argc, char **argv)
-{
-#ifdef ENABLE_NLS
- // Native Language Support
- Inkscape::initialize_gettext();
-#endif
-
-#ifdef _WIN32
- gchar *datadir = g_win32_get_package_installation_directory_of_module(NULL);
- _win32_set_inkscape_env(datadir);
- g_free(datadir);
-
- // Don't touch the registry (works fine without it) for Inkscape Portable
- gchar const *val = g_getenv("INKSCAPE_PORTABLE_PROFILE_DIR");
- if (!val) {
- RegistryTool rt;
- rt.setPathInfo();
- }
-#endif
-
- set_extensions_env();
-
- // Checks libxml version is compatible with version software is compiled against
- LIBXML_TEST_VERSION
-
- // Garbage Collector
- Inkscape::GC::init();
-
- Inkscape::Debug::Logger::init();
-
- bool use_gui;
-
-#if !defined(_WIN32) && !defined(GDK_WINDOWING_QUARTZ)
- use_gui = (g_getenv("DISPLAY") != nullptr);
-#else
- use_gui = true;
-#endif
- /* Test whether with/without GUI is forced */
- for (int i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "-z")
- || !strcmp(argv[i], "--without-gui")
- || !strcmp(argv[i], "-p")
- || !strncmp(argv[i], "--print", 7)
- || !strcmp(argv[i], "-e")
- || !strncmp(argv[i], "--export-png", 12)
- || !strcmp(argv[i], "-l")
- || !strncmp(argv[i], "--export-plain-svg", 18)
- || !strncmp(argv[i], "--export-inkscape-svg", 21)
- || !strcmp(argv[i], "-i")
- || !strncmp(argv[i], "--export-area-drawing", 21)
- || !strcmp(argv[i], "-D")
- || !strncmp(argv[i], "--export-area-page", 18)
- || !strcmp(argv[i], "-C")
- || !strncmp(argv[i], "--export-id", 11)
- || !strcmp(argv[i], "-P")
- || !strncmp(argv[i], "--export-ps", 11)
- || !strcmp(argv[i], "-E")
- || !strncmp(argv[i], "--export-eps", 12)
- || !strcmp(argv[i], "-A")
- || !strncmp(argv[i], "--export-pdf", 12)
- || !strncmp(argv[i], "--export-latex", 14)
- || !strcmp(argv[i], "-M")
- || !strncmp(argv[i], "--export-emf", 12)
- || !strcmp(argv[i], "-m")
- || !strncmp(argv[i], "--export-wmf", 12)
- || !strncmp(argv[i], "--export-xaml", 13)
- || !strcmp(argv[i], "-W")
- || !strncmp(argv[i], "--query-width", 13)
- || !strcmp(argv[i], "-H")
- || !strncmp(argv[i], "--query-height", 14)
- || !strcmp(argv[i], "-S")
- || !strncmp(argv[i], "--query-all", 11)
- || !strcmp(argv[i], "-X")
- || !strncmp(argv[i], "--query-x", 9)
- || !strcmp(argv[i], "-Y")
- || !strncmp(argv[i], "--query-y", 9)
- || !strcmp(argv[i], "--vacuum-defs")
-#ifdef WITH_DBUS
- || !strcmp(argv[i], "--dbus-listen")
-#endif // WITH_DBUS
- || !strcmp(argv[i], "--shell")
- )
- {
- /* main_console handles any exports -- not the gui */
- use_gui = false;
- break;
- } else if (!strcmp(argv[i], "-g") || !strcmp(argv[i], "--with-gui")) {
- use_gui = true;
- break;
- }
- }
-
-#ifdef _WIN32
- {
- // If the call fails, we'll need to convert charsets
- needToRecodeParams = !replaceArgs( argc, argv );
- }
-#endif // _WIN32
-
- int retcode;
-
- if (use_gui) {
- retcode = sp_main_gui(argc, (const char **) argv);
- } else {
- retcode = sp_main_console(argc, (const char **) argv);
- }
-
- return retcode;
-}
-
-
-
-
-static void fixupSingleFilename( gchar **orig, gchar **spare )
-{
- if ( orig && *orig && **orig ) {
- GError *error = nullptr;
- gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(*orig, -1, nullptr, nullptr, &error);
- if ( newFileName )
- {
- *orig = newFileName;
- if ( spare ) {
- *spare = newFileName;
- }
-// g_message("Set a replacement fixup");
- }
- }
-}
-
-
-
-static void fixupFilenameEncoding( std::vector<gchar*> &filenames)
-{
- for (unsigned int i=0; i<filenames.size(); ++i) {
- gchar *fn = filenames[i];
- gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(fn, -1, nullptr, nullptr, nullptr);
- if ( newFileName ) {
- g_free( fn );
- filenames[i] = newFileName;
- }
- }
-}
-
-static int sp_common_main( int argc, char const **argv, std::vector<gchar*> *flDest )
-{
-#ifdef ENABLE_NLS
- // Temporarily switch gettext encoding to locale, so that help messages can be output properly.
- Inkscape::bind_textdomain_codeset_console();
-#endif
-
- poptContext ctx = poptGetContext(nullptr, argc, argv, options, 0);
- poptSetOtherOptionHelp(ctx, _("[OPTIONS...] [FILE...]\n\nAvailable options:"));
- g_return_val_if_fail(ctx != nullptr, 1);
-
- /* Collect own arguments */
- std::vector<gchar*> fl = sp_process_args(ctx);
- poptFreeContext(ctx);
-
-#ifdef ENABLE_NLS
- // Now switch gettext back to UTF-8 (for GUI)
- Inkscape::bind_textdomain_codeset_utf8();
-#endif
-
- // Now let's see if the file list still holds up
- if ( needToRecodeParams )
- {
- fixupFilenameEncoding( fl );
- }
-
- // Check the globals for filename-fixup
- if ( needToRecodeParams )
- {
- fixupSingleFilename( &sp_export_png, &sp_export_png_utf8 );
- fixupSingleFilename( &sp_export_svg, &sp_export_svg_utf8 );
- fixupSingleFilename( &sp_export_inkscape_svg, &sp_export_inkscape_svg_utf8 );
- fixupSingleFilename( &sp_global_printer, &sp_global_printer_utf8 );
-#ifdef WITH_YAML
- fixupSingleFilename( &sp_xverbs_yaml, &sp_xverbs_yaml_utf8 );
-#endif // WITH_YAML
- }
- else
- {
- if ( sp_export_png )
- sp_export_png_utf8 = g_strdup( sp_export_png );
- if ( sp_export_svg )
- sp_export_svg_utf8 = g_strdup( sp_export_svg );
- if ( sp_export_inkscape_svg )
- sp_export_inkscape_svg_utf8 = g_strdup( sp_export_inkscape_svg );
- if ( sp_global_printer )
- sp_global_printer_utf8 = g_strdup( sp_global_printer );
-#ifdef WITH_YAML
- if ( sp_xverbs_yaml )
- sp_xverbs_yaml_utf8 = g_strdup( sp_xverbs_yaml );
-#endif // WITH_YAML
- }
-
- detect_pipe_in_filename( sp_export_png );
- detect_pipe_in_filename( sp_export_svg );
- detect_pipe_in_filename( sp_export_pdf );
- detect_pipe_in_filename( sp_export_ps );
- detect_pipe_in_filename( sp_export_eps );
-
-#ifdef WITH_DBUS
- // Before initializing extensions, we must set the DBus bus name if required
- if (sp_dbus_name != NULL) {
- Inkscape::Extension::Dbus::dbus_set_bus_name(sp_dbus_name);
- }
-#endif
-
- // Return the list if wanted, else free it up.
- if ( flDest ) {
- flDest->insert(flDest->end(),fl.begin(),fl.end());
- } else {
- for (auto i:fl) {
- g_free(i);
- }
- }
- return 0;
-}
-
-namespace Inkscape {
-namespace UI {
-namespace Tools {
-
-guint get_latin_keyval(GdkEventKey const* event, guint *consumed_modifiers = nullptr);
-
-}
-}
-}
-
-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 */
- {
- GdkModifierType mapping=(GdkModifierType)INKSCAPE.mapalt();
- switch (event->type) {
- case GDK_MOTION_NOTIFY:
- if(event->motion.state & mapping) {
- event->motion.state|=GDK_MOD1_MASK;
- }
- break;
- case GDK_BUTTON_PRESS:
- if(event->button.state & mapping) {
- event->button.state|=GDK_MOD1_MASK;
- }
- break;
- case GDK_KEY_PRESS:
- if(event->key.state & mapping) {
- event->key.state|=GDK_MOD1_MASK;
- }
- break;
- default:
- 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 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 = Inkscape::UI::Tools::get_latin_keyval(&event->key);
- if (keyval == GDK_KEY_Alt_L) altL_pressed = TRUE;
- if (keyval == GDK_KEY_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 = Inkscape::UI::Tools::get_latin_keyval(&event->key);
- if (keyval == GDK_KEY_Alt_L) altL_pressed = FALSE;
- if (keyval == GDK_KEY_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);
-}
-
-int
-sp_main_gui(int argc, char const **argv)
-{
- Gtk::Main main_instance (&argc, const_cast<char ***>(&argv));
-
- std::vector<gchar *> fl;
- int retVal = sp_common_main( argc, argv, &fl );
- g_return_val_if_fail(retVal == 0, 1);
-
- gdk_event_handler_set((GdkEventFunc)snooper, nullptr, nullptr);
- Inkscape::Debug::log_display_config();
-
- // Set default window icon. Obeys the theme.
- Gtk::Window::set_default_icon_name("inkscape");
- Inkscape::UI::Widget::Panel::prep();
-
- bool create_new = true;
-
- /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
- Inkscape::Application::create(argv[0], true);
- INKSCAPE.set_pdf_page(sp_pdf_page);
-
- for (auto i:fl) {
- if (sp_file_open(i,nullptr)) {
- create_new=false;
- }
- }
- if (create_new) {
- sp_file_new_default();
- }
-
- Glib::signal_idle().connect(sigc::ptr_fun(&Inkscape::CmdLineAction::idle));
- main_instance.run();
-
-#ifdef _WIN32
- //We might not need anything here
- //sp_win32_finish(); <-- this is a NOP func
-#endif
-
- return 0;
-}
-
-/**
- * Process file list
- */
-static int sp_process_file_list(std::vector<gchar*> fl)
-{
- int retVal = 0;
-#ifdef WITH_DBUS
- if (fl.empty()) {
- // If we've been asked to listen for D-Bus messages, enter a main loop here
- // The main loop may be exited by calling "exit" on the D-Bus application interface.
- if (sp_dbus_listen) {
- Gtk::Main main_dbus_loop(0, NULL);
- main_dbus_loop.run();
- }
- }
-#endif // WITH_DBUS
-
- for (auto filename:fl) {
-
- SPDocument *doc = nullptr;
- try {
- doc = Inkscape::Extension::open(nullptr, filename);
- } catch (Inkscape::Extension::Input::no_extension_found &e) {
- doc = nullptr;
- } catch (Inkscape::Extension::Input::open_failed &e) {
- doc = nullptr;
- }
-
- if (doc == nullptr) {
- try {
- doc = Inkscape::Extension::open(Inkscape::Extension::db.get(SP_MODULE_KEY_INPUT_SVG), filename);
- } catch (Inkscape::Extension::Input::no_extension_found &e) {
- doc = nullptr;
- } catch (Inkscape::Extension::Input::open_failed &e) {
- doc = nullptr;
- }
- }
- if (doc == nullptr) {
- g_warning("Specified document %s cannot be opened (does not exist or not a valid SVG file)", filename);
- retVal++;
- } else {
-
- INKSCAPE.add_document(doc);
-
- if (sp_vacuum_defs) {
- doc->vacuumDocument();
- }
-
- // Execute command-line actions (selections and verbs) using our local models
- bool has_performed_actions = Inkscape::CmdLineAction::doList(INKSCAPE.active_action_context());
-
-#ifdef WITH_DBUS
- // If we've been asked to listen for D-Bus messages, enter a main loop here
- // The main loop may be exited by calling "exit" on the D-Bus application interface.
- if (sp_dbus_listen) {
- Gtk::Main main_dbus_loop(0, NULL);
- main_dbus_loop.run();
- }
-#endif // WITH_DBUS
-
- if (!sp_export_svg && !sp_export_inkscape_svg && (sp_vacuum_defs || has_performed_actions)) {
- // save under the name given in the command line
- Inkscape::Extension::save(Inkscape::Extension::db.get("org.inkscape.output.svg.inkscape"), doc, filename, false,
- false, false, Inkscape::Extension::FILE_SAVE_METHOD_INKSCAPE_SVG);
- }
-
- if (sp_global_printer) {
- sp_print_document_to_file(doc, sp_global_printer);
- }
- if (sp_export_png || (sp_export_id && sp_export_use_hints)) {
- retVal |= do_export_png(doc);
- }
- if (sp_export_svg || sp_export_inkscape_svg) {
- retVal |= do_export_svg(doc);
- }
- if (sp_export_ps) {
- retVal |= do_export_ps_pdf(doc, sp_export_ps, "image/x-postscript");
- }
- if (sp_export_eps) {
- retVal |= do_export_ps_pdf(doc, sp_export_eps, "image/x-e-postscript");
- }
- if (sp_export_pdf) {
- retVal |= do_export_ps_pdf(doc, sp_export_pdf, "application/pdf");
- }
- if (sp_export_emf) {
- retVal |= do_export_emf(doc, sp_export_emf, "image/x-emf");
- }
- if (sp_export_wmf) {
- retVal |= do_export_wmf(doc, sp_export_wmf, "image/x-wmf");
- }
- if (sp_export_xaml) {
- retVal |= do_export_xaml(doc, sp_export_xaml, "text/xml+xaml");
- }
- if (sp_query_all) {
- do_query_all (doc);
- } else if (sp_query_width || sp_query_height) {
- 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? Geom::X : Geom::Y, sp_query_id);
- }
-
- INKSCAPE.remove_document(doc);
-
- delete doc;
- }
- }
- return retVal;
-}
-
-/**
- * Run the application as an interactive shell, parsing command lines from stdin
- * Returns -1 on error.
- */
-static int sp_main_shell(char const* command_name)
-{
- int retval = 0;
- Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- const unsigned int buffer_size = 4096;
- gchar *command_line = g_strnfill(buffer_size, 0);
- g_strlcpy(command_line, command_name, buffer_size);
- gsize offset = g_strlcat(command_line, " ", buffer_size);
- gsize sizeLeft = buffer_size - offset;
- gchar *useme = command_line + offset;
-
- fprintf(stdout, "Inkscape %s interactive shell mode. Type 'quit' to quit.\n", Inkscape::version_string);
- fflush(stdout);
- char* linedata = nullptr;
- do {
- fprintf(stdout, ">");
- fflush(stdout);
- if ((linedata = fgets(useme, sizeLeft, stdin))) {
- size_t len = strlen(useme);
- if ( (len >= sizeLeft - 1) || (useme[len - 1] != '\n') ) {
- fprintf(stdout, "ERROR: Command line too long\n");
- // Consume rest of line
- retval = -1; // If the while loop completes, this remains -1
- while (fgets(useme, sizeLeft, stdin) && retval) {
- len = strlen(command_line);
- if ( (len < buffer_size) && (command_line[len-1] == '\n') ) {
- retval = 0;
- }
- }
- } else {
- useme[--len] = '\0'; // Strip newline
- if (useme[len - 1] == '\r') {
- useme[--len] = '\0';
- }
- if ( strcmp(useme, "quit") == 0 ) {
- // Time to quit
- fflush(stdout);
- linedata = nullptr; // mark for exit
- } else if ( len < 1 ) {
- // blank string. Do nothing.
- } else {
- GError* parseError = nullptr;
- gchar** argv = nullptr;
- gint argc = 0;
- if ( g_shell_parse_argv(command_line, &argc, &argv, &parseError) ) {
- poptContext ctx = poptGetContext(nullptr, argc, const_cast<const gchar**>(argv), options, 0);
- poptSetOtherOptionHelp(ctx, _("[OPTIONS...] [FILE...]\n\nAvailable options:"));
- if ( ctx ) {
- std::vector<gchar *> fl = sp_process_args(ctx);
- INKSCAPE.set_pdf_page(sp_pdf_page);
- if (sp_process_file_list(fl)) {
- retval = -1;
- }
- poptFreeContext(ctx);
- } else {
- retval = 1; // not sure why. But this was the previous return value
- }
- resetCommandlineGlobals();
- g_strfreev(argv);
- } else {
- g_warning("Cannot parse commandline: %s", useme);
- retval = -1;
- }
- }
- }
- } // if (linedata...
- } while (linedata && (retval == 0));
-
- g_free(command_line);
- return retval;
-}
-
-int sp_main_console(int argc, char const **argv)
-{
- /* We are started in text mode */
-Inkscape::Preferences *prefs = Inkscape::Preferences::get();
-#if !GLIB_CHECK_VERSION(2,36,0)
- /* Do this g_type_init(), so that we can use Xft/Freetype2 (Pango)
- * in a non-Gtk environment. Used in libnrtype's
- * FontInstance.cpp and FontFactory.cpp.
- * http://mail.gnome.org/archives/gtk-list/2003-December/msg00063.html
- */
- g_type_init();
-#endif
-
- char **argv2 = const_cast<char **>(argv);
- gtk_init_check( &argc, &argv2 );
-
- std::vector<gchar*> fl;
- int retVal = sp_common_main( argc, argv, &fl );
- g_return_val_if_fail(retVal == 0, 1);
-
- if (fl.empty() && !sp_shell
-#ifdef WITH_DBUS
- && !sp_dbus_listen
-#endif // WITH_DBUS
- ) {
- do_print_message("Nothing to do!\n");
- exit(0);
- }
-
- Inkscape::Application::create(argv[0], false);
- INKSCAPE.set_pdf_page(sp_pdf_page);
-
- if (sp_shell) {
- int retVal = sp_main_shell(argv[0]); // Run as interactive shell
- exit((retVal < 0) ? 1 : 0);
- } else {
- int retVal = sp_process_file_list(fl); // Normal command line invocation
- if (retVal){
- exit(1);
- }
- }
- return 0;
-}
-
-static void
-do_query_dimension (SPDocument *doc, bool extent, Geom::Dim2 const axis, const gchar *id)
-{
- SPObject *o = nullptr;
-
- if (id) {
- o = doc->getObjectById(id);
- if (o) {
- if (!SP_IS_ITEM (o)) {
- g_warning("Object with id=\"%s\" is not a visible item. Cannot query dimensions.", id);
- return;
- }
- } else {
- g_warning("Object with id=\"%s\" is not found. Cannot query dimensions.", id);
- return;
- }
- } else {
- o = doc->getRoot();
- }
-
- if (o) {
- doc->ensureUpToDate();
- SPItem *item = ((SPItem *) o);
-
- // visual bbox in document coords for scripting
- Geom::OptRect area = item->documentVisualBounds();
- if (area) {
- Inkscape::SVGOStringStream os;
- if (extent) {
- os << area->dimensions()[axis];
- } else {
- os << area->min()[axis];
- }
- do_print_message ("%s", os.str().c_str());
- } else {
- do_print_message("0");
- }
- }
-}
-
-static void do_query_all(SPDocument *doc)
-{
- SPObject *o = doc->getRoot();
-
- if (o) {
- doc->ensureUpToDate();
- do_query_all_recurse(o);
- }
-}
-
-static void
-do_query_all_recurse (SPObject *o)
-{
- SPItem *item = ((SPItem *) o);
- if (o->getId() && SP_IS_ITEM(item)) {
- Geom::OptRect area = item->documentVisualBounds();
- if (area) {
- Inkscape::SVGOStringStream os;
- os << o->getId();
- os << "," << area->min()[Geom::X];
- os << "," << area->min()[Geom::Y];
- os << "," << area->dimensions()[Geom::X];
- os << "," << area->dimensions()[Geom::Y];
- do_print_message ("%s\n", os.str().c_str());
- }
- }
-
- for(auto& child: o->children) {
- do_query_all_recurse (&child);
- }
-}
-
-/**
- * Perform a PNG export
- *
- * \param doc Document to export.
- */
-
-static int do_export_png(SPDocument *doc)
-{
- Glib::ustring filename;
- bool filename_from_hint = false;
- gdouble dpi = 0.0;
-
- if (sp_export_use_hints && (!sp_export_id && !sp_export_area_drawing)) {
- g_warning ("--export-use-hints can only be used with --export-id or --export-area-drawing; ignored.");
- }
-
- std::vector<SPItem*> items;
-
- Geom::Rect area;
- if (sp_export_id || sp_export_area_drawing) {
-
- SPObject *o = nullptr;
- SPObject *o_area = nullptr;
- if (sp_export_id && sp_export_area_drawing) {
- o = doc->getObjectById(sp_export_id);
- o_area = doc->getRoot();
- } else if (sp_export_id) {
- o = doc->getObjectById(sp_export_id);
- o_area = o;
- } else if (sp_export_area_drawing) {
- o = doc->getRoot();
- o_area = o;
- }
-
- if (o) {
- if (!SP_IS_ITEM (o)) {
- g_warning("Object with id=\"%s\" is not a visible item. Nothing exported.", sp_export_id);
- return 1;
- }
-
- items.push_back(SP_ITEM(o));
-
- if (sp_export_id_only) {
- do_print_message("Exporting only object with id=\"%s\"; all other objects hidden\n", sp_export_id);
- }
-
- if (sp_export_use_hints) {
-
- // retrieve export filename hint
- const gchar *fn_hint = o->getRepr()->attribute("inkscape:export-filename");
- if (fn_hint) {
- if (sp_export_png) {
- g_warning ("Using export filename from the command line (--export-png). Filename hint %s is ignored.", fn_hint);
- filename = sp_export_png;
- } else {
- filename = fn_hint;
- filename_from_hint = true;
- }
- } else {
- g_warning ("Export filename hint not found for the object.");
- filename = sp_export_png;
- }
-
- // retrieve export dpi hints
- const gchar *dpi_hint = o->getRepr()->attribute("inkscape:export-xdpi"); // only xdpi, ydpi is always the same now
- if (dpi_hint) {
- if (sp_export_dpi || sp_export_width || sp_export_height) {
- g_warning ("Using bitmap dimensions from the command line (--export-dpi, --export-width, or --export-height). DPI hint %s is ignored.", dpi_hint);
- } else {
- dpi = atof(dpi_hint);
- }
- } else {
- g_warning ("Export DPI hint not found for the object.");
- }
-
- }
-
- // write object bbox to area
- doc->ensureUpToDate();
- Geom::OptRect areaMaybe = static_cast<SPItem *>(o_area)->desktopVisualBounds();
- if (areaMaybe) {
- area = *areaMaybe;
- } else {
- g_warning("Unable to determine a valid bounding box. Nothing exported.");
- return 1;
- }
- } else {
- g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
- return 1;
- }
- }
-
- if (sp_export_area) {
- /* Try to parse area (given in SVG pixels) */
- 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 1;
- }
- area = Geom::Rect(Geom::Interval(x0,x1), Geom::Interval(y0,y1));
- } else if (sp_export_area_page || !(sp_export_id || sp_export_area_drawing)) {
- /* Export the whole page: note: Inkscape uses 'page' in all menus and dialogs, not 'canvas' */
- doc->ensureUpToDate();
- Geom::Point origin(doc->getRoot()->x.computed, doc->getRoot()->y.computed);
- area = Geom::Rect(origin, origin + doc->getDimensions());
- }
-
- // set filename and dpi from options, if not yet set from the hints
- if (filename.empty()) {
- if (!sp_export_png || sp_export_png[0] == '\0') {
- g_warning ("No export filename given and no filename hint. Nothing exported.");
- return 1;
- }
- filename = sp_export_png;
- }
-
- if (sp_export_dpi && dpi == 0.0) {
- dpi = atof(sp_export_dpi);
- if ((dpi < 0.1) || (dpi > 10000.0)) {
- g_warning("DPI value %s out of range [0.1 - 10000.0]. Nothing exported.", sp_export_dpi);
- return 1;
- }
- do_print_message("DPI: %g\n", dpi);
- }
-
- if (sp_export_area_snap) {
- area = area.roundOutwards();
- }
-
- // default dpi
- if (dpi == 0.0) {
- dpi = Inkscape::Util::Quantity::convert(1, "in", "px");
- }
-
- unsigned long int width = 0;
- unsigned long int height = 0;
-
- if (sp_export_width) {
- errno=0;
- width = strtoul(sp_export_width, nullptr, 0);
- if ((width < 1) || (width > PNG_UINT_31_MAX) || (errno == ERANGE) ) {
- g_warning("Export width %lu out of range (1 - %lu). Nothing exported.", width, (unsigned long int)PNG_UINT_31_MAX);
- return 1;
- }
- dpi = (gdouble) Inkscape::Util::Quantity::convert(width, "in", "px") / area.width();
- }
-
- if (sp_export_height) {
- errno=0;
- height = strtoul(sp_export_height, nullptr, 0);
- if ((height < 1) || (height > PNG_UINT_31_MAX)) {
- g_warning("Export height %lu out of range (1 - %lu). Nothing exported.", height, (unsigned long int)PNG_UINT_31_MAX);
- return 1;
- }
- dpi = (gdouble) Inkscape::Util::Quantity::convert(height, "in", "px") / area.height();
- }
-
- if (!sp_export_width) {
- width = (unsigned long int) (Inkscape::Util::Quantity::convert(area.width(), "px", "in") * dpi + 0.5);
- }
-
- if (!sp_export_height) {
- height = (unsigned long int) (Inkscape::Util::Quantity::convert(area.height(), "px", "in") * dpi + 0.5);
- }
-
- guint32 bgcolor = 0x00000000;
- if (sp_export_background) {
- // override the page color
- bgcolor = sp_svg_read_color(sp_export_background, 0xffffff00);
- bgcolor |= 0xff; // default is no opacity
- } else {
- // read from namedview
- Inkscape::XML::Node *nv = sp_repr_lookup_name (doc->rroot, "sodipodi:namedview");
- if (nv && nv->attribute("pagecolor")){
- bgcolor = sp_svg_read_color(nv->attribute("pagecolor"), 0xffffff00);
- }
- if (nv && nv->attribute("inkscape:pageopacity")){
- double opacity = 1.0;
- sp_repr_get_double (nv, "inkscape:pageopacity", &opacity);
- bgcolor |= SP_COLOR_F_TO_U(opacity);
- }
- }
-
- if (sp_export_background_opacity) {
- // override opacity
- gfloat value;
- if (sp_svg_number_read_f (sp_export_background_opacity, &value)) {
- if (value > 1.0) {
- value = CLAMP (value, 1.0f, 255.0f);
- bgcolor &= (guint32) 0xffffff00;
- bgcolor |= (guint32) floor(value);
- } else {
- value = CLAMP (value, 0.0f, 1.0f);
- bgcolor &= (guint32) 0xffffff00;
- bgcolor |= SP_COLOR_F_TO_U(value);
- }
- }
- }
-
- Glib::ustring path;
- if (filename_from_hint) {
- //Make relative paths go from the document location, if possible:
- if (!Glib::path_is_absolute(filename) && doc->getURI()) {
- Glib::ustring dirname = Glib::path_get_dirname(doc->getURI());
- if (!dirname.empty()) {
- path = Glib::build_filename(dirname, filename);
- }
- }
- if (path.empty()) {
- path = filename;
- }
- } else {
- path = filename;
- }
-
- //check if specified directory exists
- if (!Inkscape::IO::file_directory_exists(filename.c_str())) {
- g_warning("File path \"%s\" includes directory that doesn't exist.\n", filename.c_str());
- return 1;
- } else {
- do_print_message("Background RRGGBBAA: %08x\n", bgcolor);
-
- do_print_message("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);
-
- reverse(items.begin(),items.end());
-
- if ((width >= 1) && (height >= 1) && (width <= PNG_UINT_31_MAX) && (height <= PNG_UINT_31_MAX)) {
- if( sp_export_png_file(doc, path.c_str(), area, width, height, dpi,
- dpi, bgcolor, nullptr, nullptr, true, sp_export_id_only ? items : std::vector<SPItem*>()) == 1 ) {
- do_print_message("Bitmap saved as: %s\n", filename.c_str());
- } else {
- g_warning("Bitmap failed to save to: %s", filename.c_str());
- return 1;
- }
- } 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);
- return 1;
- }
- }
-
- return 0;
-}
-
-/**
- * Perform an SVG export
- *
- * \param doc Document to export.
- */
-
-static int do_export_svg(SPDocument* doc)
-{
- if (sp_export_text_to_path) {
- std::vector<SPItem*> items;
- SPRoot *root = doc->getRoot();
- doc->ensureUpToDate();
- for (auto& iter: root->children) {
- SPItem* item = (SPItem*) &iter;
- if (! (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item) || SP_IS_GROUP(item))) {
- continue;
- }
-
- te_update_layout_now_recursive(item);
- items.push_back(item);
- }
-
- std::vector<SPItem*> selected;
- std::vector<Inkscape::XML::Node*> to_select;
-
- sp_item_list_to_curves(items, selected, to_select);
-
- }
- if (sp_export_margin) {
- gdouble margin = g_ascii_strtod(sp_export_margin, nullptr);
- doc->ensureUpToDate();
- SPNamedView *nv;
- Inkscape::XML::Node *nv_repr;
- if ((nv = sp_document_namedview(doc, nullptr)) && (nv_repr = nv->getRepr())) {
- sp_repr_set_svg_double(nv_repr, "fit-margin-top", margin);
- sp_repr_set_svg_double(nv_repr, "fit-margin-left", margin);
- sp_repr_set_svg_double(nv_repr, "fit-margin-right", margin);
- sp_repr_set_svg_double(nv_repr, "fit-margin-bottom", margin);
- }
- }
- if(sp_export_area_drawing) {
- fit_canvas_to_drawing(doc, sp_export_margin ? true : false);
- }
- if(sp_export_id) {
- doc->ensureUpToDate();
-
- // "crop" the document to the specified object, cleaning as we go.
- SPObject *obj = doc->getObjectById(sp_export_id);
- if (sp_export_id_only) {
- // If -j then remove all other objects to complete the "crop"
- doc->getRoot()->cropToObject(obj);
- }
- Inkscape::ObjectSet s(doc);
- s.set(obj);
- if (!sp_export_area_page) {
- s.fitCanvas(sp_export_margin ? true : false);
- }
- }
-
- int ret = 0;
- if (sp_export_svg) {
- try {
- Inkscape::Extension::save(Inkscape::Extension::db.get("org.inkscape.output.svg.plain"), doc, sp_export_svg, false,
- false, false, Inkscape::Extension::FILE_SAVE_METHOD_SAVE_COPY);
- } catch (Inkscape::Extension::Output::save_failed &e) {
- g_warning("Failed to save plain SVG to: %s", sp_export_svg);
- ret = 1;
- }
- }
- if (sp_export_inkscape_svg) {
- // Export as inkscape SVG.
- try {
- Inkscape::Extension::save(Inkscape::Extension::db.get("org.inkscape.output.svg.inkscape"), doc, sp_export_inkscape_svg, false,
- false, false, Inkscape::Extension::FILE_SAVE_METHOD_INKSCAPE_SVG);
- } catch (Inkscape::Extension::Output::save_failed &e) {
- g_warning("Failed to save Inkscape SVG to: %s", sp_export_inkscape_svg);
- ret = 1;
- }
- }
- return ret;
-}
-
-/**
- * Perform a PDF/PS/EPS export
- *
- * \param doc Document to export.
- * \param uri URI to export to.
- * \param mime MIME type to export as.
- */
-
-static int do_export_ps_pdf(SPDocument* doc, gchar const* uri, char const* mime)
-{
- Inkscape::Extension::DB::OutputList o;
- Inkscape::Extension::db.get_output_list(o);
- Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
- while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
- i++;
- }
-
- if (i == o.end())
- {
- g_warning ("Could not find an extension to export to MIME type %s.", mime);
- return 1;
- }
-
- if (sp_export_id) {
- SPObject *o = doc->getObjectById(sp_export_id);
- if (o == nullptr) {
- g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
- return 1;
- }
- (*i)->set_param_string ("exportId", sp_export_id);
- } else {
- (*i)->set_param_string ("exportId", "");
- }
-
- if (sp_export_area_page && sp_export_area_drawing) {
- g_warning ("You cannot use --export-area-page and --export-area-drawing at the same time; only the former will take effect.");
- sp_export_area_drawing = false;
- }
-
- if (sp_export_area_drawing) {
- (*i)->set_param_optiongroup ("area", "drawing");
- }
-
- if (sp_export_area_page) {
- if (sp_export_eps) {
- g_warning ("EPS cannot have its bounding box extend beyond its content, so if your drawing is smaller than the page, --export-area-page will clip it to drawing.");
- }
- (*i)->set_param_optiongroup ("area", "page");
- }
-
- if (!sp_export_area_drawing && !sp_export_area_page && !sp_export_id) {
- // neither is set, set page as default for ps/pdf and drawing for eps
- if (sp_export_eps) {
- try {
- (*i)->set_param_optiongroup("area", "drawing");
- } catch (...) {}
- }
- }
-
- if (sp_export_text_to_path) {
- (*i)->set_param_optiongroup("textToPath", "paths");
- } else if (sp_export_latex) {
- (*i)->set_param_optiongroup("textToPath", "LaTeX");
- } else {
- (*i)->set_param_optiongroup("textToPath", "embed");
- }
-
- if (sp_export_ignore_filters) {
- (*i)->set_param_bool("blurToBitmap", FALSE);
- } else {
- (*i)->set_param_bool("blurToBitmap", TRUE);
-
- gdouble dpi = 96.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 96 dpi instead.", sp_export_dpi);
- dpi = 96;
- }
- }
-
- (*i)->set_param_int("resolution", (int) dpi);
- }
-
- // if no bleed/margin is given, set to 0 (otherwise it takes the value last used from the UI)
- float margin = 0.;
- if (sp_export_margin) {
- margin = g_ascii_strtod(sp_export_margin, nullptr);
- }
- (*i)->set_param_float("bleed", margin);
-
- // handle --export-pdf-version
- if (g_strcmp0(mime, "application/pdf") == 0) {
- bool set_export_pdf_version_fail=true;
- const gchar *pdfver_param_name="PDFversion";
- if(sp_export_pdf_version) {
- // combine "PDF " and the given command line
- std::string version_gui_string=std::string("PDF ")+sp_export_pdf_version;
- try{
- // first, check if the given pdf version is selectable in the ComboBox
- if((*i)->get_param_enum_contains("PDFversion", version_gui_string.c_str())) {
- (*i)->set_param_enum(pdfver_param_name, version_gui_string.c_str());
- set_export_pdf_version_fail=false;
- } else {
- g_warning("Desired PDF export version \"%s\" not supported! Hint: input one of the versions found in the pdf export dialog e.g. \"1.4\".",
- sp_export_pdf_version);
- }
- } catch (...) {
- // can be thrown along the way:
- // throw Extension::param_not_exist();
- // throw Extension::param_not_enum_param();
- g_warning("Parameter or Enum \"%s\" might not exist",pdfver_param_name);
- }
- }
-
- // set default pdf export version to 1.4, also if something went wrong
- if(set_export_pdf_version_fail) {
- (*i)->set_param_enum(pdfver_param_name, "PDF 1.4");
- }
- }
-
- if(!uri || uri[0] == '\0') {
- g_warning ("No export filename given. Nothing exported.");
- return 0;
- }
-
- //check if specified directory exists
- if (!Inkscape::IO::file_directory_exists(uri)) {
- g_warning("File path \"%s\" includes directory that doesn't exist.\n", uri);
- return 1;
- }
-
- if ( g_strcmp0(mime, "image/x-postscript") == 0
- || g_strcmp0(mime, "image/x-e-postscript") == 0 ) {
- if ( sp_export_ps_level < 2 || sp_export_ps_level > 3 ) {
- g_warning("Only supported PostScript levels are 2 and 3."
- " Defaulting to 2.");
- sp_export_ps_level = 2;
- }
-
- (*i)->set_param_enum("PSlevel", (sp_export_ps_level == 3)
- ? "PostScript level 3" : "PostScript level 2");
- }
-
- try {
- (*i)->save(doc, uri);
- } catch(...) {
- g_warning("Failed to save pdf to: %s", uri);
- }
- return 0;
-}
-
-/**
- * Export a document to EMF or WMF
- *
- * \param doc Document to export.
- * \param uri URI to export to.
- * \param mime MIME type to export as (should be "image/x-emf" or "image/x-wmf")
- */
-
-static int do_export_win_metafile_common(SPDocument* doc, gchar const* uri, char const* mime)
-{
- Inkscape::Extension::DB::OutputList o;
- Inkscape::Extension::db.get_output_list(o);
- Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
- while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
- i++;
- }
-
- if (i == o.end())
- {
- g_warning ("Could not find an extension to export to MIME type %s.", mime);
- return 1;
- }
-
- //check if specified directory exists
- if (!Inkscape::IO::file_directory_exists(uri)){
- g_warning("File path \"%s\" includes directory that doesn't exist.\n",
- uri);
- return 1;
- }
-
- (*i)->save(doc, uri);
- return 0;
-}
-
-/**
- * Export a document to EMF
- *
- * \param doc Document to export.
- * \param uri URI to export to.
- * \param mime MIME type to export as (should be "image/x-emf")
- */
-
-static int do_export_emf(SPDocument* doc, gchar const* uri, char const* mime)
-{
- if(!uri || uri[0] == '\0') {
- g_warning("No filename provided for emf export.");
- return 0;
- }
- return do_export_win_metafile_common(doc, uri, mime);
-}
-
-/**
- * Export a document to WMF
- *
- * \param doc Document to export.
- * \param uri URI to export to.
- * \param mime MIME type to export as (should be "image/x-wmf")
- */
-
-static int do_export_wmf(SPDocument* doc, gchar const* uri, char const* mime)
-{
- if(!uri || uri[0] == '\0') {
- g_warning("No filename provided for wmf export.");
- return 0;
- }
- return do_export_win_metafile_common(doc, uri, mime);
-}
-
-/**
- * Export a document to XAML
- *
- * \param doc Document to export.
- * \param uri URI to export to.
- * \param mime MIME type to export as (should be "text/xml+xaml)
- */
-
-static int do_export_xaml(SPDocument* doc, gchar const* uri, char const* mime)
-{
- if(!uri || uri[0] == '\0') {
- g_warning("No filename provided for xaml export.");
- return 0;
- }
- return do_export_win_metafile_common(doc, uri, mime);
-}
-
-#ifdef _WIN32
-bool replaceArgs( int& argc, char**& argv )
-{
- bool worked = false;
-
-#ifdef REPLACEARGS_DEBUG
- MessageBoxA( NULL, "GetCommandLineW() getting called", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
-#endif // REPLACEARGS_DEBUG
-
- wchar_t* line = GetCommandLineW();
- if ( line )
- {
-#ifdef REPLACEARGS_DEBUG
- {
- gchar* utf8Line = g_utf16_to_utf8( (gunichar2*)line, -1, NULL, NULL, NULL );
- if ( utf8Line )
- {
- gchar *safe = Inkscape::IO::sanitizeString(utf8Line);
- {
- char tmp[strlen(safe) + 32];
- snprintf( tmp, sizeof(tmp), "GetCommandLineW() = '%s'", safe );
- MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
- }
- }
- }
-#endif // REPLACEARGS_DEBUG
-
- int numArgs = 0;
- wchar_t** parsed = CommandLineToArgvW( line, &numArgs );
-
-#ifdef REPLACEARGS_ANSI
-// test code for trying things on Win95/98/ME
- if ( !parsed )
- {
-#ifdef REPLACEARGS_DEBUG
- MessageBoxA( NULL, "Unable to process command-line. Faking it", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
-#endif // REPLACEARGS_DEBUG
- int lineLen = wcslen(line) + 1;
- wchar_t* lineDup = new wchar_t[lineLen];
- wcsncpy( lineDup, line, lineLen );
-
- int pos = 0;
- bool inQuotes = false;
- bool inWhitespace = true;
- std::vector<int> places;
- while ( lineDup[pos] )
- {
- if ( inQuotes )
- {
- if ( lineDup[pos] == L'"' )
- {
- inQuotes = false;
- }
- }
- else if ( lineDup[pos] == L'"' )
- {
- inQuotes = true;
- inWhitespace = false;
- places.push_back(pos);
- }
- else if ( lineDup[pos] == L' ' || lineDup[pos] == L'\t' )
- {
- if ( !inWhitespace )
- {
- inWhitespace = true;
- lineDup[pos] = 0;
- }
- }
- else if ( inWhitespace && (lineDup[pos] != L' ' && lineDup[pos] != L'\t') )
- {
- inWhitespace = false;
- places.push_back(pos);
- }
- else
- {
- // consume
- }
- pos++;
- }
-#ifdef REPLACEARGS_DEBUG
- {
- char tmp[256];
- snprintf( tmp, sizeof(tmp), "Counted %d args", places.size() );
- MessageBoxA( NULL, tmp, "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
- }
-#endif // REPLACEARGS_DEBUG
-
- wchar_t** block = new wchar_t*[places.size()];
- int i = 0;
- for ( std::vector<int>::iterator it = places.begin(); it != places.end(); it++ )
- {
- block[i++] = &lineDup[*it];
- }
- parsed = block;
- numArgs = places.size();
- }
-#endif // REPLACEARGS_ANSI
-
- if ( parsed )
- {
- std::vector<wchar_t*>expandedArgs;
- if ( numArgs > 0 )
- {
- expandedArgs.push_back( parsed[0] );
- }
-
- for ( int i1 = 1; i1 < numArgs; i1++ )
- {
- bool wildcarded = (wcschr(parsed[i1], L'?') != NULL) || (wcschr(parsed[i1], L'*') != NULL);
- wildcarded &= parsed[i1][0] != L'"';
- wildcarded &= parsed[i1][0] != L'-';
- if ( wildcarded )
- {
-#ifdef REPLACEARGS_ANSI
- WIN32_FIND_DATAA data;
-#else
- WIN32_FIND_DATAW data;
-#endif // REPLACEARGS_ANSI
-
- memset((void *)&data, 0, sizeof(data));
-
- int baseLen = wcslen(parsed[i1]) + 2;
- wchar_t* base = new wchar_t[baseLen];
- wcsncpy( base, parsed[i1], baseLen );
- wchar_t* last = wcsrchr( base, L'\\' );
- if ( last )
- {
- last[1] = 0;
- }
- else
- {
- base[0] = 0;
- }
- baseLen = wcslen( base );
-
-#ifdef REPLACEARGS_ANSI
- char target[MAX_PATH];
- if ( WideCharToMultiByte( CP_ACP, 0, parsed[i1], -1, target, sizeof(target), NULL, NULL) )
- {
- HANDLE hf = FindFirstFileA( target, &data );
-#else
- HANDLE hf = FindFirstFileW( parsed[i1], &data );
-#endif // REPLACEARGS_ANSI
- if ( hf != INVALID_HANDLE_VALUE )
- {
- BOOL found = TRUE;
- do
- {
-#ifdef REPLACEARGS_ANSI
- int howMany = MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, NULL, 0 );
- if ( howMany > 0 )
- {
- howMany += baseLen;
- wchar_t* tmp = new wchar_t[howMany + 1];
- wcsncpy( tmp, base, howMany + 1 );
- MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, tmp + baseLen, howMany + 1 - baseLen );
- expandedArgs.push_back( tmp );
- found = FindNextFileA( hf, &data );
- }
-#else
- int howMany = wcslen(data.cFileName) + baseLen;
- wchar_t* tmp = new wchar_t[howMany + 1];
- wcsncpy( tmp, base, howMany + 1 );
- wcsncat( tmp, data.cFileName, howMany + 1 );
- expandedArgs.push_back( tmp );
- found = FindNextFileW( hf, &data );
-#endif // REPLACEARGS_ANSI
- } while ( found );
-
- FindClose( hf );
- }
- else
- {
- expandedArgs.push_back( parsed[i1] );
- }
-#ifdef REPLACEARGS_ANSI
- }
-#endif // REPLACEARGS_ANSI
-
- delete[] base;
- }
- else
- {
- expandedArgs.push_back( parsed[i1] );
- }
- }
-
- {
- wchar_t** block = new wchar_t*[expandedArgs.size()];
- int iz = 0;
- for ( std::vector<wchar_t*>::iterator it = expandedArgs.begin(); it != expandedArgs.end(); it++ )
- {
- block[iz++] = *it;
- }
- parsed = block;
- numArgs = expandedArgs.size();
- }
-
- std::vector<gchar*> newArgs;
- for ( int i = 0; i < numArgs; i++ )
- {
- gchar* replacement = g_utf16_to_utf8( (gunichar2*)parsed[i], -1, NULL, NULL, NULL );
- if ( replacement )
- {
-#ifdef REPLACEARGS_DEBUG
- gchar *safe2 = Inkscape::IO::sanitizeString(replacement);
-
- if ( safe2 )
- {
- {
- char tmp[1024];
- snprintf( tmp, sizeof(tmp), " [%2d] = '%s'", i, safe2 );
- MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
- }
- g_free( safe2 );
- }
-#endif // REPLACEARGS_DEBUG
-
- newArgs.push_back( replacement );
- }
- else
- {
- newArgs.push_back( blankParam );
- }
- }
-
- // Now push our munged params to be the new argv and argc
- {
- char** block = new char*[newArgs.size()];
- int iz = 0;
- for ( std::vector<char*>::iterator it = newArgs.begin(); it != newArgs.end(); it++ )
- {
- block[iz++] = *it;
- }
- argv = block;
- argc = newArgs.size();
- worked = true;
- }
- }
-#ifdef REPLACEARGS_DEBUG
- else
- {
- MessageBoxA( NULL, "Unable to process command-line", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
- }
-#endif // REPLACEARGS_DEBUG
- }
-#ifdef REPLACEARGS_DEBUG
- else
- {
- {
- MessageBoxA( NULL, "Unable to fetch result from GetCommandLineW()", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
- }
-
- char* line2 = GetCommandLineA();
- if ( line2 )
- {
- gchar *safe = Inkscape::IO::sanitizeString(line2);
- {
- {
- char tmp[strlen(safe) + 32];
- snprintf( tmp, sizeof(tmp), "GetCommandLineA() = '%s'", safe );
- MessageBoxA( NULL, tmp, "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
- }
- }
- }
- else
- {
- MessageBoxA( NULL, "Unable to fetch result from GetCommandLineA()", "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
- }
- }
-#endif // REPLACEARGS_DEBUG
-
- return worked;
-}
-#endif // _WIN32
-
-static std::vector<gchar *>
-sp_process_args(poptContext ctx)
-{
- std::vector<gchar *> fl;
-
- gint a;
- while ((a = poptGetNextOpt(ctx)) != -1) {
- switch (a) {
- case SP_ARG_FILE: {
- gchar const *fn = poptGetOptArg(ctx);
- if (fn != nullptr) {
- fl.push_back(g_strdup(fn));
- }
- break;
- }
-#ifdef WITH_YAML
- case SP_ARG_XVERBS: {
- gchar const *fn = poptGetOptArg(ctx);
- if (fn != nullptr) {
- sp_xverbs_yaml = g_strdup(fn);
- Inkscape::CmdLineXAction::createActionsFromYAML((const char *)sp_xverbs_yaml);
- }
- break;
- }
-#endif // WITH_YAML
- case SP_ARG_VERSION: {
- printf("Inkscape %s\n", Inkscape::version_string);
- exit(0);
- break;
- }
- case SP_ARG_EXTENSIONDIR: {
- printf("%s\n", INKSCAPE_EXTENSIONDIR);
- exit(0);
- break;
- }
- case SP_ARG_VERB_LIST: {
- // This really shouldn't go here, we should init the app.
- // But, since we're just exiting in this path, there is
- // no harm, and this is really a better place to put
- // everything else.
- Inkscape::Extension::init();
- Inkscape::Verb::list();
- exit(0);
- break;
- }
- case SP_ARG_VERB:
- case SP_ARG_SELECT: {
- gchar const *arg = poptGetOptArg(ctx);
- if (arg != nullptr) {
- // printf("Adding in: %s\n", arg);
- new Inkscape::CmdLineAction((a == SP_ARG_VERB), arg);
- }
- break;
- }
- case SP_ARG_CONVERT_DPI_METHOD: {
- gchar const *arg = poptGetOptArg(ctx);
- if (arg != nullptr) {
- if (!strcmp(arg,"none")) {
- sp_file_convert_dpi_method_commandline = FILE_DPI_UNCHANGED;
- } else if (!strcmp(arg,"scale-viewbox")) {
- sp_file_convert_dpi_method_commandline = FILE_DPI_VIEWBOX_SCALED;
- } else if (!strcmp(arg,"scale-document")) {
- sp_file_convert_dpi_method_commandline = FILE_DPI_DOCUMENT_SCALED;
- } else {
- g_warning("Invalid update option");
- }
- }
- break;
- }
- case POPT_ERROR_BADOPT: {
- g_warning ("Invalid option %s", poptBadOption(ctx, 0));
- exit(1);
- break;
- }
- default: {
- break;
- }
- }
- }
-
- gchar const ** const args = poptGetArgs(ctx);
- if (args != nullptr) {
- for (unsigned i = 0; args[i] != nullptr; i++) {
- fl.push_back(g_strdup(args[i]));
- }
- }
-
- return fl;
-}
-
-/**
- * Print a message for the user to the terminal
- *
- * If inkscape is run as part of a pipe all messages to standard output
- * are redirected to standard error.
- *
- * \param message Message to print.
- */
-
-static void do_print_message(const char *message, ...)
-{
- va_list args;
-
- va_start(args, message);
- gchar *msg = g_strdup_vprintf(message, args);
-
- if (sp_writingToPipe)
- g_printerr("%s", msg);
- else
- g_print("%s", msg);
-
- g_free(msg);
- va_end(args);
-}
-
-/**
- * Checks if a given filename is meant to be a pipe
- *
- * In case it is a pipe the variable sp_writingToPipe is set.
- *
- * \param filename Filename to check for a pipe.
- */
-
-static void detect_pipe_in_filename(const char *filename)
-{
- if (g_strcmp0(filename, "-") == 0) {
- sp_writingToPipe = TRUE;
- }
-}
-
-/*
- Local Variables:
- mode:c++
- c-file-style:"stroustrup"
- c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
- indent-tabs-mode:nil
- fill-column:99
- End:
-*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :