1 #define __MAIN_C__
3 /** \file
4 * Inkscape - an ambitious vector drawing program
5 *
6 * Authors:
7 * Lauris Kaplinski <lauris@kaplinski.com>
8 * Frank Felfe <innerspace@iname.com>
9 * Davide Puricelli <evo@debian.org>
10 * Mitsuru Oka <oka326@parkcity.ne.jp>
11 * Masatake YAMATO <jet@gyve.org>
12 * F.J.Franklin <F.J.Franklin@sheffield.ac.uk>
13 * Michael Meeks <michael@helixcode.com>
14 * Chema Celorio <chema@celorio.com>
15 * Pawel Palucha
16 * Bryce Harrington <bryce@bryceharrington.com>
17 * ... and various people who have worked with various projects
18 *
19 * Copyright (C) 1999-2004 authors
20 * Copyright (C) 2001-2002 Ximian, Inc.
21 *
22 * Released under GNU GPL, read the file 'COPYING' for more information
23 */
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29 #include "path-prefix.h"
31 #include <gtk/gtkmessagedialog.h>
33 #ifdef HAVE_IEEEFP_H
34 #include <ieeefp.h>
35 #endif
36 #include <cstring>
37 #include <string>
38 #include <locale.h>
40 #include <popt.h>
41 #ifndef POPT_TABLEEND
42 #define POPT_TABLEEND { NULL, '\0', 0, 0, 0, NULL, NULL }
43 #endif /* Not def: POPT_TABLEEND */
45 #include <libxml/tree.h>
46 #include <glib-object.h>
47 #include <gtk/gtkmain.h>
48 #include <gtk/gtksignal.h>
49 #include <gtk/gtkwindow.h>
50 #include <gtk/gtkbox.h>
52 #include "gc-core.h"
54 #include "macros.h"
55 #include "file.h"
56 #include "document.h"
57 #include "sp-object.h"
58 #include "interface.h"
59 #include "print.h"
60 #include "color.h"
61 #include "sp-item.h"
62 #include "sp-root.h"
63 #include "unit-constants.h"
65 #include "svg/svg.h"
66 #include "svg/svg-color.h"
67 #include "svg/stringstream.h"
69 #include "inkscape-private.h"
70 #include "inkscape-stock.h"
71 #include "inkscape_version.h"
73 #include "sp-namedview.h"
74 #include "sp-guide.h"
75 #include "sp-object-repr.h"
76 #include "xml/repr.h"
78 #include "io/sys.h"
80 #include "debug/logger.h"
81 #include "debug/log-display-config.h"
83 #include "helper/png-write.h"
85 #include <extension/extension.h>
86 #include <extension/system.h>
87 #include <extension/db.h>
88 #include <extension/output.h>
90 #ifdef WIN32
91 //#define REPLACEARGS_ANSI
92 //#define REPLACEARGS_DEBUG
94 #include "registrytool.h"
96 #include "extension/internal/win32.h"
97 using Inkscape::Extension::Internal::PrintWin32;
99 #endif // WIN32
101 #include "extension/init.h"
103 #include <glibmm/i18n.h>
104 #include <gtkmm/main.h>
106 #ifndef HAVE_BIND_TEXTDOMAIN_CODESET
107 #define bind_textdomain_codeset(p,c)
108 #endif
110 #include "application/application.h"
112 #include "main-cmdlineact.h"
114 #include <png.h>
115 #include <errno.h>
117 enum {
118 SP_ARG_NONE,
119 SP_ARG_NOGUI,
120 SP_ARG_GUI,
121 SP_ARG_FILE,
122 SP_ARG_PRINT,
123 SP_ARG_EXPORT_PNG,
124 SP_ARG_EXPORT_DPI,
125 SP_ARG_EXPORT_AREA,
126 SP_ARG_EXPORT_AREA_DRAWING,
127 SP_ARG_EXPORT_AREA_CANVAS,
128 SP_ARG_EXPORT_AREA_SNAP,
129 SP_ARG_EXPORT_WIDTH,
130 SP_ARG_EXPORT_HEIGHT,
131 SP_ARG_EXPORT_ID,
132 SP_ARG_EXPORT_ID_ONLY,
133 SP_ARG_EXPORT_USE_HINTS,
134 SP_ARG_EXPORT_BACKGROUND,
135 SP_ARG_EXPORT_BACKGROUND_OPACITY,
136 SP_ARG_EXPORT_SVG,
137 SP_ARG_EXPORT_PS,
138 SP_ARG_EXPORT_EPS,
139 SP_ARG_EXPORT_PDF,
140 #ifdef WIN32
141 SP_ARG_EXPORT_EMF,
142 #endif //WIN32
143 SP_ARG_EXPORT_TEXT_TO_PATH,
144 SP_ARG_EXPORT_FONT,
145 SP_ARG_EXPORT_BBOX_PAGE,
146 SP_ARG_EXTENSIONDIR,
147 SP_ARG_FIT_PAGE_TO_DRAWING,
148 SP_ARG_QUERY_X,
149 SP_ARG_QUERY_Y,
150 SP_ARG_QUERY_WIDTH,
151 SP_ARG_QUERY_HEIGHT,
152 SP_ARG_QUERY_ALL,
153 SP_ARG_QUERY_ID,
154 SP_ARG_SHELL,
155 SP_ARG_VERSION,
156 SP_ARG_VACUUM_DEFS,
157 SP_ARG_VERB_LIST,
158 SP_ARG_VERB,
159 SP_ARG_SELECT,
160 SP_ARG_LAST
161 };
163 int sp_main_gui(int argc, char const **argv);
164 int sp_main_console(int argc, char const **argv);
165 static void sp_do_export_png(SPDocument *doc);
166 static void do_export_ps(SPDocument* doc, gchar const* uri, char const *mime);
167 static void do_export_pdf(SPDocument* doc, gchar const* uri, char const *mime);
168 #ifdef WIN32
169 static void do_export_emf(SPDocument* doc, gchar const* uri, char const *mime);
170 #endif //WIN32
171 static void do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gchar *id);
172 static void do_query_all (SPDocument *doc);
173 static void do_query_all_recurse (SPObject *o);
175 static gchar *sp_global_printer = NULL;
176 static gchar *sp_export_png = NULL;
177 static gchar *sp_export_dpi = NULL;
178 static gchar *sp_export_area = NULL;
179 static gboolean sp_export_area_drawing = FALSE;
180 static gboolean sp_export_area_canvas = FALSE;
181 static gchar *sp_export_width = NULL;
182 static gchar *sp_export_height = NULL;
183 static gchar *sp_export_id = NULL;
184 static gchar *sp_export_background = NULL;
185 static gchar *sp_export_background_opacity = NULL;
186 static gboolean sp_export_area_snap = FALSE;
187 static gboolean sp_export_use_hints = FALSE;
188 static gboolean sp_export_id_only = FALSE;
189 static gchar *sp_export_svg = NULL;
190 static gchar *sp_export_ps = NULL;
191 static gchar *sp_export_eps = NULL;
192 static gchar *sp_export_pdf = NULL;
193 #ifdef WIN32
194 static gchar *sp_export_emf = NULL;
195 #endif //WIN32
196 static gboolean sp_export_text_to_path = FALSE;
197 static gboolean sp_export_font = FALSE;
198 static gboolean sp_export_bbox_page = FALSE;
199 static gboolean sp_query_x = FALSE;
200 static gboolean sp_query_y = FALSE;
201 static gboolean sp_query_width = FALSE;
202 static gboolean sp_query_height = FALSE;
203 static gboolean sp_query_all = FALSE;
204 static gchar *sp_query_id = NULL;
205 static int sp_new_gui = FALSE;
206 static gboolean sp_shell = FALSE;
207 static gboolean sp_vacuum_defs = FALSE;
209 static gchar *sp_export_png_utf8 = NULL;
210 static gchar *sp_export_svg_utf8 = NULL;
211 static gchar *sp_global_printer_utf8 = NULL;
214 /**
215 * Reset variables to default values.
216 */
217 static void resetCommandlineGlobals() {
218 sp_global_printer = NULL;
219 sp_export_png = NULL;
220 sp_export_dpi = NULL;
221 sp_export_area = NULL;
222 sp_export_area_drawing = FALSE;
223 sp_export_area_canvas = FALSE;
224 sp_export_width = NULL;
225 sp_export_height = NULL;
226 sp_export_id = NULL;
227 sp_export_background = NULL;
228 sp_export_background_opacity = NULL;
229 sp_export_area_snap = FALSE;
230 sp_export_use_hints = FALSE;
231 sp_export_id_only = FALSE;
232 sp_export_svg = NULL;
233 sp_export_ps = NULL;
234 sp_export_eps = NULL;
235 sp_export_pdf = NULL;
236 #ifdef WIN32
237 sp_export_emf = NULL;
238 #endif //WIN32
239 sp_export_text_to_path = FALSE;
240 sp_export_font = FALSE;
241 sp_export_bbox_page = FALSE;
242 sp_query_x = FALSE;
243 sp_query_y = FALSE;
244 sp_query_width = FALSE;
245 sp_query_height = FALSE;
246 sp_query_all = FALSE;
247 sp_query_id = NULL;
248 sp_vacuum_defs = FALSE;
250 sp_export_png_utf8 = NULL;
251 sp_export_svg_utf8 = NULL;
252 sp_global_printer_utf8 = NULL;
253 }
255 #ifdef WIN32
256 static bool replaceArgs( int& argc, char**& argv );
257 #endif
258 static GSList *sp_process_args(poptContext ctx);
259 struct poptOption options[] = {
260 {"version", 'V',
261 POPT_ARG_NONE, NULL, SP_ARG_VERSION,
262 N_("Print the Inkscape version number"),
263 NULL},
265 {"without-gui", 'z',
266 POPT_ARG_NONE, NULL, SP_ARG_NOGUI,
267 N_("Do not use X server (only process files from console)"),
268 NULL},
270 {"with-gui", 'g',
271 POPT_ARG_NONE, NULL, SP_ARG_GUI,
272 N_("Try to use X server (even if $DISPLAY is not set)"),
273 NULL},
275 {"file", 'f',
276 POPT_ARG_STRING, NULL, SP_ARG_FILE,
277 N_("Open specified document(s) (option string may be excluded)"),
278 N_("FILENAME")},
280 {"print", 'p',
281 POPT_ARG_STRING, &sp_global_printer, SP_ARG_PRINT,
282 N_("Print document(s) to specified output file (use '| program' for pipe)"),
283 N_("FILENAME")},
285 {"export-png", 'e',
286 POPT_ARG_STRING, &sp_export_png, SP_ARG_EXPORT_PNG,
287 N_("Export document to a PNG file"),
288 N_("FILENAME")},
290 {"export-dpi", 'd',
291 POPT_ARG_STRING, &sp_export_dpi, SP_ARG_EXPORT_DPI,
292 N_("The resolution used for exporting SVG into bitmap (default 90)"),
293 N_("DPI")},
295 {"export-area", 'a',
296 POPT_ARG_STRING, &sp_export_area, SP_ARG_EXPORT_AREA,
297 N_("Exported area in SVG user units (default is the canvas; 0,0 is lower-left corner)"),
298 N_("x0:y0:x1:y1")},
300 {"export-area-drawing", 'D',
301 POPT_ARG_NONE, &sp_export_area_drawing, SP_ARG_EXPORT_AREA_DRAWING,
302 N_("Exported area is the entire drawing (not canvas)"),
303 NULL},
305 {"export-area-canvas", 'C',
306 POPT_ARG_NONE, &sp_export_area_canvas, SP_ARG_EXPORT_AREA_CANVAS,
307 N_("Exported area is the entire canvas"),
308 NULL},
310 {"export-area-snap", 0,
311 POPT_ARG_NONE, &sp_export_area_snap, SP_ARG_EXPORT_AREA_SNAP,
312 N_("Snap the bitmap export area outwards to the nearest integer values (in SVG user units)"),
313 NULL},
315 {"export-width", 'w',
316 POPT_ARG_STRING, &sp_export_width, SP_ARG_EXPORT_WIDTH,
317 N_("The width of exported bitmap in pixels (overrides export-dpi)"),
318 N_("WIDTH")},
320 {"export-height", 'h',
321 POPT_ARG_STRING, &sp_export_height, SP_ARG_EXPORT_HEIGHT,
322 N_("The height of exported bitmap in pixels (overrides export-dpi)"),
323 N_("HEIGHT")},
325 {"export-id", 'i',
326 POPT_ARG_STRING, &sp_export_id, SP_ARG_EXPORT_ID,
327 N_("The ID of the object to export"),
328 N_("ID")},
330 {"export-id-only", 'j',
331 POPT_ARG_NONE, &sp_export_id_only, SP_ARG_EXPORT_ID_ONLY,
332 // TRANSLATORS: this means: "Only export the object whose id is given in --export-id".
333 // See "man inkscape" for details.
334 N_("Export just the object with export-id, hide all others (only with export-id)"),
335 NULL},
337 {"export-use-hints", 't',
338 POPT_ARG_NONE, &sp_export_use_hints, SP_ARG_EXPORT_USE_HINTS,
339 N_("Use stored filename and DPI hints when exporting (only with export-id)"),
340 NULL},
342 {"export-background", 'b',
343 POPT_ARG_STRING, &sp_export_background, SP_ARG_EXPORT_BACKGROUND,
344 N_("Background color of exported bitmap (any SVG-supported color string)"),
345 N_("COLOR")},
347 {"export-background-opacity", 'y',
348 POPT_ARG_STRING, &sp_export_background_opacity, SP_ARG_EXPORT_BACKGROUND_OPACITY,
349 N_("Background opacity of exported bitmap (either 0.0 to 1.0, or 1 to 255)"),
350 N_("VALUE")},
352 {"export-plain-svg", 'l',
353 POPT_ARG_STRING, &sp_export_svg, SP_ARG_EXPORT_SVG,
354 N_("Export document to plain SVG file (no sodipodi or inkscape namespaces)"),
355 N_("FILENAME")},
357 {"export-ps", 'P',
358 POPT_ARG_STRING, &sp_export_ps, SP_ARG_EXPORT_PS,
359 N_("Export document to a PS file"),
360 N_("FILENAME")},
362 {"export-eps", 'E',
363 POPT_ARG_STRING, &sp_export_eps, SP_ARG_EXPORT_EPS,
364 N_("Export document to an EPS file"),
365 N_("FILENAME")},
367 {"export-pdf", 'A',
368 POPT_ARG_STRING, &sp_export_pdf, SP_ARG_EXPORT_PDF,
369 N_("Export document to a PDF file"),
370 N_("FILENAME")},
372 #ifdef WIN32
373 {"export-emf", 'M',
374 POPT_ARG_STRING, &sp_export_emf, SP_ARG_EXPORT_EMF,
375 N_("Export document to an Enhanced Metafile (EMF) File"),
376 N_("FILENAME")},
377 #endif //WIN32
379 {"export-text-to-path", 'T',
380 POPT_ARG_NONE, &sp_export_text_to_path, SP_ARG_EXPORT_TEXT_TO_PATH,
381 N_("Convert text object to paths on export (EPS)"),
382 NULL},
384 {"export-embed-fonts", 'F',
385 POPT_ARG_NONE, &sp_export_font, SP_ARG_EXPORT_FONT,
386 N_("Embed fonts on export (Type 1 only) (EPS)"),
387 NULL},
389 {"export-bbox-page", 'B',
390 POPT_ARG_NONE, &sp_export_bbox_page, SP_ARG_EXPORT_BBOX_PAGE,
391 N_("Export files with the bounding box set to the page size (EPS)"),
392 NULL},
394 {"query-x", 'X',
395 POPT_ARG_NONE, &sp_query_x, SP_ARG_QUERY_X,
396 // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
397 N_("Query the X coordinate of the drawing or, if specified, of the object with --query-id"),
398 NULL},
400 {"query-y", 'Y',
401 POPT_ARG_NONE, &sp_query_y, SP_ARG_QUERY_Y,
402 // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
403 N_("Query the Y coordinate of the drawing or, if specified, of the object with --query-id"),
404 NULL},
406 {"query-width", 'W',
407 POPT_ARG_NONE, &sp_query_width, SP_ARG_QUERY_WIDTH,
408 // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
409 N_("Query the width of the drawing or, if specified, of the object with --query-id"),
410 NULL},
412 {"query-height", 'H',
413 POPT_ARG_NONE, &sp_query_height, SP_ARG_QUERY_HEIGHT,
414 // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
415 N_("Query the height of the drawing or, if specified, of the object with --query-id"),
416 NULL},
418 {"query-all", 'S',
419 POPT_ARG_NONE, &sp_query_all, SP_ARG_QUERY_ALL,
420 N_("List id,x,y,w,h for all objects"),
421 NULL},
423 {"query-id", 'I',
424 POPT_ARG_STRING, &sp_query_id, SP_ARG_QUERY_ID,
425 N_("The ID of the object whose dimensions are queried"),
426 N_("ID")},
428 {"extension-directory", 'x',
429 POPT_ARG_NONE, NULL, SP_ARG_EXTENSIONDIR,
430 // TRANSLATORS: this option makes Inkscape print the name (path) of the extension directory
431 N_("Print out the extension directory and exit"),
432 NULL},
434 {"vacuum-defs", 0,
435 POPT_ARG_NONE, &sp_vacuum_defs, SP_ARG_VACUUM_DEFS,
436 N_("Remove unused definitions from the defs section(s) of the document"),
437 NULL},
439 {"verb-list", 0,
440 POPT_ARG_NONE, NULL, SP_ARG_VERB_LIST,
441 N_("List the IDs of all the verbs in Inkscape"),
442 NULL},
444 {"verb", 0,
445 POPT_ARG_STRING, NULL, SP_ARG_VERB,
446 N_("Verb to call when Inkscape opens."),
447 N_("VERB-ID")},
449 {"select", 0,
450 POPT_ARG_STRING, NULL, SP_ARG_SELECT,
451 N_("Object ID to select when Inkscape opens."),
452 N_("OBJECT-ID")},
454 {"shell", 0,
455 POPT_ARG_NONE, &sp_shell, SP_ARG_SHELL,
456 N_("Start Inkscape in interative shell mode."),
457 NULL},
459 POPT_AUTOHELP POPT_TABLEEND
460 };
462 static bool needToRecodeParams = true;
463 gchar * blankParam = g_strdup("");
467 #ifdef WIN32
469 /**
470 * Return the directory of the .exe that is currently running
471 */
472 static Glib::ustring _win32_getExePath()
473 {
474 char exeName[MAX_PATH+1];
475 GetModuleFileName(NULL, exeName, MAX_PATH);
476 char *slashPos = strrchr(exeName, '\\');
477 if (slashPos)
478 *slashPos = '\0';
479 Glib::ustring s = exeName;
480 return s;
481 }
483 /**
484 * Set up the PATH and PYTHONPATH environment variables on
485 * win32
486 */
487 static int _win32_set_inkscape_env(const Glib::ustring &exePath)
488 {
490 char *oldenv = getenv("PATH");
491 Glib::ustring tmp = "PATH=";
492 tmp += exePath;
493 tmp += ";";
494 tmp += exePath;
495 tmp += "\\python;";
496 tmp += exePath;
497 tmp += "\\python\\Scripts;"; // for uniconv.cmd
498 tmp += exePath;
499 tmp += "\\perl";
500 if(oldenv != NULL) {
501 tmp += ";";
502 tmp += oldenv;
503 }
504 _putenv(tmp.c_str());
506 oldenv = getenv("PYTHONPATH");
507 tmp = "PYTHONPATH=";
508 tmp += exePath;
509 tmp += "\\python;";
510 tmp += exePath;
511 tmp += "\\python\\Lib;";
512 tmp += exePath;
513 tmp += "\\python\\DLLs";
514 if(oldenv != NULL) {
515 tmp += ";";
516 tmp += oldenv;
517 }
518 _putenv(tmp.c_str());
520 return 0;
521 }
522 #endif
526 /**
527 * This is the classic main() entry point of the program, though on some
528 * architectures it might be called by something else.
529 */
530 int
531 main(int argc, char **argv)
532 {
533 #ifdef HAVE_FPSETMASK
534 /* This is inherited from Sodipodi code, where it was in #ifdef __FreeBSD__. It's probably
535 safe to remove: the default mask is already 0 in C99, and in current FreeBSD according to
536 the fenv man page on www.freebsd.org, and in glibc according to (libc)FP Exceptions. */
537 fpsetmask(fpgetmask() & ~(FP_X_DZ | FP_X_INV));
538 #endif
540 #ifdef WIN32
541 /*
542 Set the current directory to the directory of the
543 executable. This seems redundant, but is needed for
544 when inkscape.exe is executed from another directory.
545 We use relative paths on win32.
546 HKCR\svgfile\shell\open\command is a good example
547 */
548 Glib::ustring homedir = _win32_getExePath();
549 SetCurrentDirectory(homedir.c_str());
550 _win32_set_inkscape_env(homedir);
551 RegistryTool rt;
552 rt.setPathInfo();
553 #endif
555 /**
556 * Call bindtextdomain() for various machines's paths
557 */
558 #ifdef ENABLE_NLS
559 #ifdef WIN32
560 Glib::ustring localePath = homedir;
561 localePath += "\\";
562 localePath += PACKAGE_LOCALE_DIR;
563 bindtextdomain(GETTEXT_PACKAGE, localePath.c_str());
564 #else
565 #ifdef ENABLE_BINRELOC
566 bindtextdomain(GETTEXT_PACKAGE, BR_LOCALEDIR(""));
567 #else
568 bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
569 #endif
570 #endif
571 // Allow the user to override the locale directory by setting
572 // the environment variable INKSCAPE_LOCALEDIR.
573 char *inkscape_localedir = getenv("INKSCAPE_LOCALEDIR");
574 if (inkscape_localedir != NULL) {
575 bindtextdomain(GETTEXT_PACKAGE, inkscape_localedir);
576 }
577 #endif
579 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
581 #ifdef ENABLE_NLS
582 textdomain(GETTEXT_PACKAGE);
583 #endif
585 LIBXML_TEST_VERSION
587 Inkscape::GC::init();
589 Inkscape::Debug::Logger::init();
591 gboolean use_gui;
593 #ifndef WIN32
594 use_gui = (getenv("DISPLAY") != NULL);
595 #else
596 use_gui = TRUE;
597 #endif
598 /* Test whether with/without GUI is forced */
599 for (int i = 1; i < argc; i++) {
600 if (!strcmp(argv[i], "-z")
601 || !strcmp(argv[i], "--without-gui")
602 || !strcmp(argv[i], "-p")
603 || !strncmp(argv[i], "--print", 7)
604 || !strcmp(argv[i], "-e")
605 || !strncmp(argv[i], "--export-png", 12)
606 || !strcmp(argv[i], "-l")
607 || !strncmp(argv[i], "--export-plain-svg", 12)
608 || !strcmp(argv[i], "-i")
609 || !strncmp(argv[i], "--export-area-drawing", 21)
610 || !strcmp(argv[i], "-D")
611 || !strncmp(argv[i], "--export-area-canvas", 20)
612 || !strcmp(argv[i], "-C")
613 || !strncmp(argv[i], "--export-id", 12)
614 || !strcmp(argv[i], "-P")
615 || !strncmp(argv[i], "--export-ps", 11)
616 || !strcmp(argv[i], "-E")
617 || !strncmp(argv[i], "--export-eps", 12)
618 || !strcmp(argv[i], "-A")
619 || !strncmp(argv[i], "--export-pdf", 12)
620 #ifdef WIN32
621 || !strcmp(argv[i], "-M")
622 || !strncmp(argv[i], "--export-emf", 12)
623 #endif //WIN32
624 || !strcmp(argv[i], "-W")
625 || !strncmp(argv[i], "--query-width", 13)
626 || !strcmp(argv[i], "-H")
627 || !strncmp(argv[i], "--query-height", 14)
628 || !strcmp(argv[i], "-S")
629 || !strncmp(argv[i], "--query-all", 11)
630 || !strcmp(argv[i], "-X")
631 || !strncmp(argv[i], "--query-x", 13)
632 || !strcmp(argv[i], "-Y")
633 || !strncmp(argv[i], "--query-y", 14)
634 || !strcmp(argv[i], "--vacuum-defs")
635 || !strncmp(argv[i], "--shell", 7)
636 )
637 {
638 /* main_console handles any exports -- not the gui */
639 use_gui = FALSE;
640 break;
641 } else if (!strcmp(argv[i], "-g") || !strcmp(argv[i], "--with-gui")) {
642 use_gui = TRUE;
643 break;
644 }
645 }
647 #ifdef WIN32
648 #ifndef REPLACEARGS_ANSI
649 if ( PrintWin32::is_os_wide() )
650 #endif // REPLACEARGS_ANSI
651 {
652 // If the call fails, we'll need to convert charsets
653 needToRecodeParams = !replaceArgs( argc, argv );
654 }
655 #endif // WIN32
657 /// \todo Should this be a static object (see inkscape.cpp)?
658 Inkscape::NSApplication::Application app(argc, argv, use_gui, sp_new_gui);
660 return app.run();
661 }
666 void fixupSingleFilename( gchar **orig, gchar **spare )
667 {
668 if ( orig && *orig && **orig ) {
669 GError *error = NULL;
670 gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(*orig, -1, NULL, NULL, &error);
671 if ( newFileName )
672 {
673 *orig = newFileName;
674 if ( spare ) {
675 *spare = newFileName;
676 }
677 // g_message("Set a replacement fixup");
678 }
679 }
680 }
684 GSList *fixupFilenameEncoding( GSList* fl )
685 {
686 GSList *newFl = NULL;
687 while ( fl ) {
688 gchar *fn = static_cast<gchar*>(fl->data);
689 fl = g_slist_remove( fl, fl->data );
690 gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(fn, -1, NULL, NULL, NULL);
691 if ( newFileName ) {
693 if ( 0 )
694 {
695 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
696 gchar *safeNewFn = Inkscape::IO::sanitizeString(newFileName);
697 GtkWidget *w = gtk_message_dialog_new( NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
698 "Note: Converted '%s' to '%s'", safeFn, safeNewFn );
699 gtk_dialog_run (GTK_DIALOG (w));
700 gtk_widget_destroy (w);
701 g_free(safeNewFn);
702 g_free(safeFn);
703 }
705 g_free( fn );
706 fn = newFileName;
707 newFileName = 0;
708 }
709 else
710 if ( 0 )
711 {
712 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
713 GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "Error: Unable to convert '%s'", safeFn );
714 gtk_dialog_run (GTK_DIALOG (w));
715 gtk_widget_destroy (w);
716 g_free(safeFn);
717 }
718 newFl = g_slist_append( newFl, fn );
719 }
720 return newFl;
721 }
723 int sp_common_main( int argc, char const **argv, GSList **flDest )
724 {
725 /// \todo fixme: Move these to some centralized location (Lauris)
726 sp_object_type_register("sodipodi:namedview", SP_TYPE_NAMEDVIEW);
727 sp_object_type_register("sodipodi:guide", SP_TYPE_GUIDE);
730 // temporarily switch gettext encoding to locale, so that help messages can be output properly
731 gchar const *charset;
732 g_get_charset(&charset);
734 bind_textdomain_codeset(GETTEXT_PACKAGE, charset);
736 poptContext ctx = poptGetContext(NULL, argc, argv, options, 0);
737 poptSetOtherOptionHelp(ctx, _("[OPTIONS...] [FILE...]\n\nAvailable options:"));
738 g_return_val_if_fail(ctx != NULL, 1);
740 /* Collect own arguments */
741 GSList *fl = sp_process_args(ctx);
742 poptFreeContext(ctx);
744 // now switch gettext back to UTF-8 (for GUI)
745 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
747 // Now let's see if the file list still holds up
748 if ( needToRecodeParams )
749 {
750 fl = fixupFilenameEncoding( fl );
751 }
753 // Check the globals for filename-fixup
754 if ( needToRecodeParams )
755 {
756 fixupSingleFilename( &sp_export_png, &sp_export_png_utf8 );
757 fixupSingleFilename( &sp_export_svg, &sp_export_svg_utf8 );
758 fixupSingleFilename( &sp_global_printer, &sp_global_printer_utf8 );
759 }
760 else
761 {
762 if ( sp_export_png )
763 sp_export_png_utf8 = g_strdup( sp_export_png );
764 if ( sp_export_svg )
765 sp_export_svg_utf8 = g_strdup( sp_export_svg );
766 if ( sp_global_printer )
767 sp_global_printer_utf8 = g_strdup( sp_global_printer );
768 }
770 // Return the list if wanted, else free it up.
771 if ( flDest ) {
772 *flDest = fl;
773 fl = 0;
774 } else {
775 while ( fl ) {
776 g_free( fl->data );
777 fl = g_slist_remove( fl, fl->data );
778 }
779 }
780 return 0;
781 }
783 static void
784 snooper(GdkEvent *event, gpointer /*data*/) {
785 if(inkscape_mapalt()) /* returns the map of the keyboard modifier to map to Alt, zero if no mapping */
786 {
787 GdkModifierType mapping=(GdkModifierType)inkscape_mapalt();
788 switch (event->type) {
789 case GDK_MOTION_NOTIFY:
790 if(event->motion.state & mapping) {
791 event->motion.state|=GDK_MOD1_MASK;
792 }
793 break;
794 case GDK_BUTTON_PRESS:
795 if(event->button.state & mapping) {
796 event->button.state|=GDK_MOD1_MASK;
797 }
798 break;
799 case GDK_KEY_PRESS:
800 if(event->key.state & mapping) {
801 event->key.state|=GDK_MOD1_MASK;
802 }
803 break;
804 default:
805 break;
806 }
807 }
808 gtk_main_do_event (event);
809 }
811 int
812 sp_main_gui(int argc, char const **argv)
813 {
814 Gtk::Main main_instance (&argc, const_cast<char ***>(&argv));
816 GSList *fl = NULL;
817 int retVal = sp_common_main( argc, argv, &fl );
818 g_return_val_if_fail(retVal == 0, 1);
820 inkscape_gtk_stock_init();
822 gdk_event_handler_set((GdkEventFunc)snooper, NULL, NULL);
824 Inkscape::Debug::log_display_config();
826 /* Set default icon */
827 gchar *filename = (gchar *) g_build_filename (INKSCAPE_APPICONDIR, "inkscape.png", NULL);
828 if (Inkscape::IO::file_test(filename, (GFileTest)(G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_SYMLINK))) {
829 gtk_window_set_default_icon_from_file(filename, NULL);
830 }
831 g_free (filename);
832 filename = 0;
834 gboolean create_new = TRUE;
836 /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
837 inkscape_application_init(argv[0], true);
839 while (fl) {
840 if (sp_file_open((gchar *)fl->data,NULL)) {
841 create_new=FALSE;
842 }
843 fl = g_slist_remove(fl, fl->data);
844 }
845 if (create_new) {
846 sp_file_new_default();
847 }
849 Glib::signal_idle().connect(sigc::ptr_fun(&Inkscape::CmdLineAction::idle));
850 main_instance.run();
852 #ifdef WIN32
853 //We might not need anything here
854 //sp_win32_finish(); <-- this is a NOP func
855 #endif
857 return 0;
858 }
860 /**
861 * Process file list
862 */
863 void sp_process_file_list(GSList *fl)
864 {
865 while (fl) {
866 const gchar *filename = (gchar *)fl->data;
867 SPDocument *doc = Inkscape::Extension::open(NULL, filename);
868 if (doc == NULL) {
869 doc = Inkscape::Extension::open(Inkscape::Extension::db.get(SP_MODULE_KEY_INPUT_SVG), filename);
870 }
871 if (doc == NULL) {
872 g_warning("Specified document %s cannot be opened (is it valid SVG file?)", filename);
873 } else {
874 if (sp_vacuum_defs) {
875 vacuum_document(doc);
876 }
877 if (sp_vacuum_defs && !sp_export_svg) {
878 // save under the name given in the command line
879 sp_repr_save_file(doc->rdoc, filename, SP_SVG_NS_URI);
880 }
881 if (sp_global_printer) {
882 sp_print_document_to_file(doc, sp_global_printer);
883 }
884 if (sp_export_png) {
885 sp_do_export_png(doc);
886 }
887 if (sp_export_svg) {
888 Inkscape::XML::Document *rdoc;
889 Inkscape::XML::Node *repr;
890 rdoc = sp_repr_document_new("svg:svg");
891 repr = rdoc->root();
892 repr = sp_document_root(doc)->updateRepr(rdoc, repr, SP_OBJECT_WRITE_BUILD);
893 sp_repr_save_file(repr->document(), sp_export_svg, SP_SVG_NS_URI);
894 }
895 if (sp_export_ps) {
896 do_export_ps(doc, sp_export_ps, "image/x-postscript");
897 }
898 if (sp_export_eps) {
899 do_export_ps(doc, sp_export_eps, "image/x-e-postscript");
900 }
901 if (sp_export_pdf) {
902 do_export_pdf(doc, sp_export_pdf, "application/pdf");
903 }
904 #ifdef WIN32
905 if (sp_export_emf) {
906 do_export_emf(doc, sp_export_emf, "image/x-emf");
907 }
908 #endif //WIN32
909 if (sp_query_all) {
910 do_query_all (doc);
911 } else if (sp_query_width || sp_query_height) {
912 do_query_dimension (doc, true, sp_query_width? NR::X : NR::Y, sp_query_id);
913 } else if (sp_query_x || sp_query_y) {
914 do_query_dimension (doc, false, sp_query_x? NR::X : NR::Y, sp_query_id);
915 }
916 }
917 delete doc; /// \todo: Check the proper way to delete a SPDocument.
918 fl = g_slist_remove(fl, fl->data);
919 }
920 }
922 /**
923 * Run the application as an interactive shell, parsing command lines from stdin
924 * Returns -1 on error.
925 */
926 int sp_main_shell(char const* command_name)
927 {
928 int retval = 0;
930 const unsigned int buffer_size = 4096;
931 gchar *command_line = g_strnfill(buffer_size, 0);
932 g_strlcpy(command_line, command_name, buffer_size);
933 gsize offset = g_strlcat(command_line, " ", buffer_size);
934 gsize sizeLeft = buffer_size - offset;
935 gchar *useme = command_line + offset;
937 fprintf(stdout, "Inkscape %s interactive shell mode. Type 'quit' to quit.\n", INKSCAPE_VERSION);
938 fflush(stdout);
939 char* linedata = 0;
940 do {
941 fprintf(stdout, ">");
942 fflush(stdout);
943 if ((linedata = fgets(useme, sizeLeft, stdin))) {
944 size_t len = strlen(useme);
945 if ( (len >= sizeLeft - 1) || (useme[len - 1] != '\n') ) {
946 fprintf(stdout, "ERROR: Command line too long\n");
947 // Consume rest of line
948 retval = -1; // If the while loop completes, this remains -1
949 while (fgets(useme, sizeLeft, stdin) && retval) {
950 len = strlen(command_line);
951 if ( (len < buffer_size) && (command_line[len-1] == '\n') ) {
952 retval = 0;
953 }
954 }
955 } else {
956 useme[--len] = '\0'; // Strip newline
957 if (useme[len - 1] == '\r') {
958 useme[--len] = '\0';
959 }
960 if ( strcmp(useme, "quit") == 0 ) {
961 // Time to quit
962 fprintf(stdout, "done\n");
963 fflush(stdout);
964 linedata = 0; // mark for exit
965 } else if ( len < 1 ) {
966 // blank string. Do nothing.
967 } else {
968 GError* parseError = 0;
969 gchar** argv = 0;
970 gint argc = 0;
971 if ( g_shell_parse_argv(useme, &argc, &argv, &parseError) ) {
972 poptContext ctx = poptGetContext(NULL, argc, const_cast<const gchar**>(argv), options, 0);
973 poptSetOtherOptionHelp(ctx, _("[OPTIONS...] [FILE...]\n\nAvailable options:"));
974 if ( ctx ) {
975 GSList *fl = sp_process_args(ctx);
976 sp_process_file_list(fl);
977 poptFreeContext(ctx);
978 } else {
979 retval = 1; // not sure why. But this was the previous return value
980 }
981 resetCommandlineGlobals();
982 g_strfreev(argv);
983 } else {
984 g_warning("problem parsing command-line");
985 }
986 }
987 }
988 } // if (linedata...
989 } while (linedata && (retval == 0));
991 g_free(command_line);
992 return retval;
993 }
995 int sp_main_console(int argc, char const **argv)
996 {
997 /* We are started in text mode */
999 /* Do this g_type_init(), so that we can use Xft/Freetype2 (Pango)
1000 * in a non-Gtk environment. Used in libnrtype's
1001 * FontInstance.cpp and FontFactory.cpp.
1002 * http://mail.gnome.org/archives/gtk-list/2003-December/msg00063.html
1003 */
1004 g_type_init();
1005 char **argv2 = const_cast<char **>(argv);
1006 gtk_init_check( &argc, &argv2 );
1007 //setlocale(LC_ALL, "");
1009 GSList *fl = NULL;
1010 int retVal = sp_common_main( argc, argv, &fl );
1011 g_return_val_if_fail(retVal == 0, 1);
1013 if (fl == NULL && !sp_shell) {
1014 g_print("Nothing to do!\n");
1015 exit(0);
1016 }
1018 inkscape_application_init(argv[0], false);
1020 if (sp_shell) {
1021 sp_main_shell(argv[0]); // Run as interactive shell
1022 } else {
1023 sp_process_file_list(fl); // Normal command line invokation
1024 }
1025 inkscape_unref();
1027 return 0;
1028 }
1030 static void
1031 do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gchar *id)
1032 {
1033 SPObject *o = NULL;
1035 if (id) {
1036 o = doc->getObjectById(id);
1037 if (o) {
1038 if (!SP_IS_ITEM (o)) {
1039 g_warning("Object with id=\"%s\" is not a visible item. Cannot query dimensions.", id);
1040 return;
1041 }
1042 } else {
1043 g_warning("Object with id=\"%s\" is not found. Cannot query dimensions.", id);
1044 return;
1045 }
1046 } else {
1047 o = SP_DOCUMENT_ROOT(doc);
1048 }
1050 if (o) {
1051 sp_document_ensure_up_to_date (doc);
1052 SPItem *item = ((SPItem *) o);
1054 // "true" SVG bbox for scripting
1055 boost::optional<NR::Rect> area = item->getBounds(sp_item_i2doc_affine(item));
1056 if (area) {
1057 Inkscape::SVGOStringStream os;
1058 if (extent) {
1059 os << area->extent(axis);
1060 } else {
1061 os << area->min()[axis];
1062 }
1063 g_print ("%s", os.str().c_str());
1064 } else {
1065 g_print("0");
1066 }
1067 }
1068 }
1070 static void
1071 do_query_all (SPDocument *doc)
1072 {
1073 SPObject *o = NULL;
1075 o = SP_DOCUMENT_ROOT(doc);
1077 if (o) {
1078 sp_document_ensure_up_to_date (doc);
1079 do_query_all_recurse(o);
1080 }
1081 }
1083 static void
1084 do_query_all_recurse (SPObject *o)
1085 {
1086 SPItem *item = ((SPItem *) o);
1087 if (o->id && SP_IS_ITEM(item)) {
1088 boost::optional<NR::Rect> area = item->getBounds(sp_item_i2doc_affine(item));
1089 if (area) {
1090 Inkscape::SVGOStringStream os;
1091 os << o->id;
1092 os << "," << area->min()[NR::X];
1093 os << "," << area->min()[NR::Y];
1094 os << "," << area->extent(NR::X);
1095 os << "," << area->extent(NR::Y);
1096 g_print ("%s\n", os.str().c_str());
1097 }
1098 }
1100 SPObject *child = o->children;
1101 while (child) {
1102 do_query_all_recurse (child);
1103 child = child->next;
1104 }
1105 }
1108 static void
1109 sp_do_export_png(SPDocument *doc)
1110 {
1111 const gchar *filename = NULL;
1112 gdouble dpi = 0.0;
1114 if (sp_export_use_hints && (!sp_export_id && !sp_export_area_drawing)) {
1115 g_warning ("--export-use-hints can only be used with --export-id or --export-area-drawing; ignored.");
1116 }
1118 GSList *items = NULL;
1120 NRRect area;
1121 if (sp_export_id || sp_export_area_drawing) {
1123 SPObject *o = NULL;
1124 SPObject *o_area = NULL;
1125 if (sp_export_id && sp_export_area_drawing) {
1126 o = doc->getObjectById(sp_export_id);
1127 o_area = SP_DOCUMENT_ROOT (doc);
1128 } else if (sp_export_id) {
1129 o = doc->getObjectById(sp_export_id);
1130 o_area = o;
1131 } else if (sp_export_area_drawing) {
1132 o = SP_DOCUMENT_ROOT (doc);
1133 o_area = o;
1134 }
1136 if (o) {
1137 if (!SP_IS_ITEM (o)) {
1138 g_warning("Object with id=\"%s\" is not a visible item. Nothing exported.", sp_export_id);
1139 return;
1140 }
1142 items = g_slist_prepend (items, SP_ITEM(o));
1144 if (sp_export_id_only) {
1145 g_print("Exporting only object with id=\"%s\"; all other objects hidden\n", sp_export_id);
1146 }
1148 if (sp_export_use_hints) {
1150 // retrieve export filename hint
1151 const gchar *fn_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-filename");
1152 if (fn_hint) {
1153 if (sp_export_png) {
1154 g_warning ("Using export filename from the command line (--export-png). Filename hint %s is ignored.", fn_hint);
1155 filename = sp_export_png;
1156 } else {
1157 filename = fn_hint;
1158 }
1159 } else {
1160 g_warning ("Export filename hint not found for the object.");
1161 filename = sp_export_png;
1162 }
1164 // retrieve export dpi hints
1165 const gchar *dpi_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-xdpi"); // only xdpi, ydpi is always the same now
1166 if (dpi_hint) {
1167 if (sp_export_dpi || sp_export_width || sp_export_height) {
1168 g_warning ("Using bitmap dimensions from the command line (--export-dpi, --export-width, or --export-height). DPI hint %s is ignored.", dpi_hint);
1169 } else {
1170 dpi = atof(dpi_hint);
1171 }
1172 } else {
1173 g_warning ("Export DPI hint not found for the object.");
1174 }
1176 }
1178 // write object bbox to area
1179 sp_document_ensure_up_to_date (doc);
1180 sp_item_invoke_bbox((SPItem *) o_area, &area, sp_item_i2r_affine((SPItem *) o_area), TRUE);
1181 } else {
1182 g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
1183 return;
1184 }
1185 }
1187 if (sp_export_area) {
1188 /* Try to parse area (given in SVG pixels) */
1189 if (!sscanf(sp_export_area, "%lg:%lg:%lg:%lg", &area.x0, &area.y0, &area.x1, &area.y1) == 4) {
1190 g_warning("Cannot parse export area '%s'; use 'x0:y0:x1:y1'. Nothing exported.", sp_export_area);
1191 return;
1192 }
1193 if ((area.x0 >= area.x1) || (area.y0 >= area.y1)) {
1194 g_warning("Export area '%s' has negative width or height. Nothing exported.", sp_export_area);
1195 return;
1196 }
1197 } else if (sp_export_area_canvas || !(sp_export_id || sp_export_area_drawing)) {
1198 /* Export the whole canvas */
1199 sp_document_ensure_up_to_date (doc);
1200 area.x0 = SP_ROOT(doc->root)->x.computed;
1201 area.y0 = SP_ROOT(doc->root)->y.computed;
1202 area.x1 = area.x0 + sp_document_width (doc);
1203 area.y1 = area.y0 + sp_document_height (doc);
1204 }
1206 // set filename and dpi from options, if not yet set from the hints
1207 if (!filename) {
1208 if (!sp_export_png) {
1209 g_warning ("No export filename given and no filename hint. Nothing exported.");
1210 return;
1211 }
1212 filename = sp_export_png;
1213 }
1215 if (sp_export_dpi && dpi == 0.0) {
1216 dpi = atof(sp_export_dpi);
1217 if ((dpi < 0.1) || (dpi > 10000.0)) {
1218 g_warning("DPI value %s out of range [0.1 - 10000.0]. Nothing exported.", sp_export_dpi);
1219 return;
1220 }
1221 g_print("DPI: %g\n", dpi);
1222 }
1224 if (sp_export_area_snap) {
1225 area.x0 = std::floor (area.x0);
1226 area.y0 = std::floor (area.y0);
1227 area.x1 = std::ceil (area.x1);
1228 area.y1 = std::ceil (area.y1);
1229 }
1231 // default dpi
1232 if (dpi == 0.0)
1233 dpi = PX_PER_IN;
1235 unsigned long int width = 0;
1236 unsigned long int height = 0;
1238 if (sp_export_width) {
1239 errno=0;
1240 width = strtoul(sp_export_width, NULL, 0);
1241 if ((width < 1) || (width > PNG_UINT_31_MAX) || (errno == ERANGE) ) {
1242 g_warning("Export width %lu out of range (1 - %lu). Nothing exported.", width, (unsigned long int)PNG_UINT_31_MAX);
1243 return;
1244 }
1245 dpi = (gdouble) width * PX_PER_IN / (area.x1 - area.x0);
1246 }
1248 if (sp_export_height) {
1249 errno=0;
1250 height = strtoul(sp_export_height, NULL, 0);
1251 if ((height < 1) || (height > PNG_UINT_31_MAX)) {
1252 g_warning("Export height %lu out of range (1 - %lu). Nothing exported.", height, (unsigned long int)PNG_UINT_31_MAX);
1253 return;
1254 }
1255 dpi = (gdouble) height * PX_PER_IN / (area.y1 - area.y0);
1256 }
1258 if (!sp_export_width) {
1259 width = (unsigned long int) ((area.x1 - area.x0) * dpi / PX_PER_IN + 0.5);
1260 }
1262 if (!sp_export_height) {
1263 height = (unsigned long int) ((area.y1 - area.y0) * dpi / PX_PER_IN + 0.5);
1264 }
1266 guint32 bgcolor = 0x00000000;
1267 if (sp_export_background) {
1268 // override the page color
1269 bgcolor = sp_svg_read_color(sp_export_background, 0xffffff00);
1270 bgcolor |= 0xff; // default is no opacity
1271 } else {
1272 // read from namedview
1273 Inkscape::XML::Node *nv = sp_repr_lookup_name (doc->rroot, "sodipodi:namedview");
1274 if (nv && nv->attribute("pagecolor"))
1275 bgcolor = sp_svg_read_color(nv->attribute("pagecolor"), 0xffffff00);
1276 if (nv && nv->attribute("inkscape:pageopacity"))
1277 bgcolor |= SP_COLOR_F_TO_U(sp_repr_get_double_attribute (nv, "inkscape:pageopacity", 1.0));
1278 }
1280 if (sp_export_background_opacity) {
1281 // override opacity
1282 gfloat value;
1283 if (sp_svg_number_read_f (sp_export_background_opacity, &value)) {
1284 if (value > 1.0) {
1285 value = CLAMP (value, 1.0f, 255.0f);
1286 bgcolor &= (guint32) 0xffffff00;
1287 bgcolor |= (guint32) floor(value);
1288 } else {
1289 value = CLAMP (value, 0.0f, 1.0f);
1290 bgcolor &= (guint32) 0xffffff00;
1291 bgcolor |= SP_COLOR_F_TO_U(value);
1292 }
1293 }
1294 }
1296 g_print("Background RRGGBBAA: %08x\n", bgcolor);
1298 g_print("Area %g:%g:%g:%g exported to %lu x %lu pixels (%g dpi)\n", area.x0, area.y0, area.x1, area.y1, width, height, dpi);
1300 g_print("Bitmap saved as: %s\n", filename);
1302 if ((width >= 1) && (height >= 1) && (width <= PNG_UINT_31_MAX) && (height <= PNG_UINT_31_MAX)) {
1303 sp_export_png_file(doc, filename, area.x0, area.y0, area.x1, area.y1, width, height, dpi, dpi, bgcolor, NULL, NULL, true, sp_export_id_only ? items : NULL);
1304 } else {
1305 g_warning("Calculated bitmap dimensions %lu %lu are out of range (1 - %lu). Nothing exported.", width, height, (unsigned long int)PNG_UINT_31_MAX);
1306 }
1308 g_slist_free (items);
1309 }
1312 /**
1313 * Perform an export of either PS or EPS.
1314 *
1315 * \param doc Document to export.
1316 * \param uri URI to export to.
1317 * \param mime MIME type to export as.
1318 */
1320 static void do_export_ps(SPDocument* doc, gchar const* uri, char const* mime)
1321 {
1322 Inkscape::Extension::DB::OutputList o;
1323 Inkscape::Extension::db.get_output_list(o);
1324 Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1325 while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1326 i++;
1327 }
1329 if (i == o.end())
1330 {
1331 g_warning ("Could not find an extension to export to MIME type %s.", mime);
1332 return;
1333 }
1335 bool old_text_to_path = false;
1336 bool old_font_embedded = false;
1337 bool old_bbox_page = false;
1339 try {
1340 old_text_to_path = (*i)->get_param_bool("textToPath");
1341 (*i)->set_param_bool("textToPath", sp_export_text_to_path);
1342 }
1343 catch (...) {
1344 g_warning ("Could not set export-text-to-path option for this export.");
1345 }
1347 try {
1348 old_font_embedded = (*i)->get_param_bool("fontEmbedded");
1349 (*i)->set_param_bool("fontEmbedded", sp_export_font);
1350 }
1351 catch (...) {
1352 g_warning ("Could not set export-font option for this export.");
1353 }
1355 try {
1356 old_bbox_page = (*i)->get_param_bool("pageBoundingBox");
1357 (*i)->set_param_bool("pageBoundingBox", sp_export_bbox_page);
1358 }
1359 catch (...) {
1360 g_warning ("Could not set export-bbox-page option for this export.");
1361 }
1363 (*i)->save(doc, uri);
1365 try {
1366 (*i)->set_param_bool("textToPath", old_text_to_path);
1367 (*i)->set_param_bool("fontEmbedded", old_font_embedded);
1368 (*i)->set_param_bool("pageBoundingBox", old_bbox_page);
1369 }
1370 catch (...) {
1372 }
1373 }
1375 /**
1376 * Perform a PDF export
1377 *
1378 * \param doc Document to export.
1379 * \param uri URI to export to.
1380 * \param mime MIME type to export as.
1381 */
1383 static void do_export_pdf(SPDocument* doc, gchar const* uri, char const* mime)
1384 {
1385 Inkscape::Extension::DB::OutputList o;
1386 Inkscape::Extension::db.get_output_list(o);
1387 Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1388 while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1389 i++;
1390 }
1392 if (i == o.end())
1393 {
1394 g_warning ("Could not find an extension to export to MIME type %s.", mime);
1395 return;
1396 }
1398 if (sp_export_id) {
1399 SPObject *o = doc->getObjectById(sp_export_id);
1400 if (o == NULL) {
1401 g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
1402 return;
1403 }
1404 (*i)->set_param_string ("exportId", sp_export_id);
1405 } else {
1406 (*i)->set_param_string ("exportId", "");
1407 }
1409 if (sp_export_area_drawing) {
1410 (*i)->set_param_bool ("exportDrawing", TRUE);
1411 } else {
1412 (*i)->set_param_bool ("exportDrawing", FALSE);
1413 }
1415 if (sp_export_area_canvas) {
1416 (*i)->set_param_bool ("exportCanvas", TRUE);
1417 } else {
1418 (*i)->set_param_bool ("exportCanvas", FALSE);
1419 }
1421 if (sp_export_text_to_path) {
1422 (*i)->set_param_bool("textToPath", TRUE);
1423 } else {
1424 (*i)->set_param_bool("textToPath", FALSE);
1425 }
1427 (*i)->save(doc, uri);
1428 }
1430 #ifdef WIN32
1431 /**
1432 * Export a document to EMF
1433 *
1434 * \param doc Document to export.
1435 * \param uri URI to export to.
1436 * \param mime MIME type to export as (should be "image/x-emf")
1437 */
1439 static void do_export_emf(SPDocument* doc, gchar const* uri, char const* mime)
1440 {
1441 Inkscape::Extension::DB::OutputList o;
1442 Inkscape::Extension::db.get_output_list(o);
1443 Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1444 while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1445 i++;
1446 }
1448 if (i == o.end())
1449 {
1450 g_warning ("Could not find an extension to export to MIME type %s.", mime);
1451 return;
1452 }
1454 (*i)->save(doc, uri);
1455 }
1456 #endif //WIN32
1458 #ifdef WIN32
1459 bool replaceArgs( int& argc, char**& argv )
1460 {
1461 bool worked = false;
1463 #ifdef REPLACEARGS_DEBUG
1464 MessageBoxA( NULL, "GetCommandLineW() getting called", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1465 #endif // REPLACEARGS_DEBUG
1467 wchar_t* line = GetCommandLineW();
1468 if ( line )
1469 {
1470 #ifdef REPLACEARGS_DEBUG
1471 {
1472 gchar* utf8Line = g_utf16_to_utf8( (gunichar2*)line, -1, NULL, NULL, NULL );
1473 if ( utf8Line )
1474 {
1475 gchar *safe = Inkscape::IO::sanitizeString(utf8Line);
1476 {
1477 char tmp[strlen(safe) + 32];
1478 snprintf( tmp, sizeof(tmp), "GetCommandLineW() = '%s'", safe );
1479 MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1480 }
1481 }
1482 }
1483 #endif // REPLACEARGS_DEBUG
1485 int numArgs = 0;
1486 wchar_t** parsed = CommandLineToArgvW( line, &numArgs );
1488 #ifdef REPLACEARGS_ANSI
1489 // test code for trying things on Win95/98/ME
1490 if ( !parsed )
1491 {
1492 #ifdef REPLACEARGS_DEBUG
1493 MessageBoxA( NULL, "Unable to process command-line. Faking it", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1494 #endif // REPLACEARGS_DEBUG
1495 int lineLen = wcslen(line) + 1;
1496 wchar_t* lineDup = new wchar_t[lineLen];
1497 wcsncpy( lineDup, line, lineLen );
1499 int pos = 0;
1500 bool inQuotes = false;
1501 bool inWhitespace = true;
1502 std::vector<int> places;
1503 while ( lineDup[pos] )
1504 {
1505 if ( inQuotes )
1506 {
1507 if ( lineDup[pos] == L'"' )
1508 {
1509 inQuotes = false;
1510 }
1511 }
1512 else if ( lineDup[pos] == L'"' )
1513 {
1514 inQuotes = true;
1515 inWhitespace = false;
1516 places.push_back(pos);
1517 }
1518 else if ( lineDup[pos] == L' ' || lineDup[pos] == L'\t' )
1519 {
1520 if ( !inWhitespace )
1521 {
1522 inWhitespace = true;
1523 lineDup[pos] = 0;
1524 }
1525 }
1526 else if ( inWhitespace && (lineDup[pos] != L' ' && lineDup[pos] != L'\t') )
1527 {
1528 inWhitespace = false;
1529 places.push_back(pos);
1530 }
1531 else
1532 {
1533 // consume
1534 }
1535 pos++;
1536 }
1537 #ifdef REPLACEARGS_DEBUG
1538 {
1539 char tmp[256];
1540 snprintf( tmp, sizeof(tmp), "Counted %d args", places.size() );
1541 MessageBoxA( NULL, tmp, "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1542 }
1543 #endif // REPLACEARGS_DEBUG
1545 wchar_t** block = new wchar_t*[places.size()];
1546 int i = 0;
1547 for ( std::vector<int>::iterator it = places.begin(); it != places.end(); it++ )
1548 {
1549 block[i++] = &lineDup[*it];
1550 }
1551 parsed = block;
1552 numArgs = places.size();
1553 }
1554 #endif // REPLACEARGS_ANSI
1556 if ( parsed )
1557 {
1558 std::vector<wchar_t*>expandedArgs;
1559 if ( numArgs > 0 )
1560 {
1561 expandedArgs.push_back( parsed[0] );
1562 }
1564 for ( int i1 = 1; i1 < numArgs; i1++ )
1565 {
1566 bool wildcarded = (wcschr(parsed[i1], L'?') != NULL) || (wcschr(parsed[i1], L'*') != NULL);
1567 wildcarded &= parsed[i1][0] != L'"';
1568 wildcarded &= parsed[i1][0] != L'-';
1569 if ( wildcarded )
1570 {
1571 #ifdef REPLACEARGS_ANSI
1572 WIN32_FIND_DATAA data;
1573 #else
1574 WIN32_FIND_DATAW data;
1575 #endif // REPLACEARGS_ANSI
1577 memset((void *)&data, 0, sizeof(data));
1579 int baseLen = wcslen(parsed[i1]) + 2;
1580 wchar_t* base = new wchar_t[baseLen];
1581 wcsncpy( base, parsed[i1], baseLen );
1582 wchar_t* last = wcsrchr( base, L'\\' );
1583 if ( last )
1584 {
1585 last[1] = 0;
1586 }
1587 else
1588 {
1589 base[0] = 0;
1590 }
1591 baseLen = wcslen( base );
1593 #ifdef REPLACEARGS_ANSI
1594 char target[MAX_PATH];
1595 if ( WideCharToMultiByte( CP_ACP, 0, parsed[i1], -1, target, sizeof(target), NULL, NULL) )
1596 {
1597 HANDLE hf = FindFirstFileA( target, &data );
1598 #else
1599 HANDLE hf = FindFirstFileW( parsed[i1], &data );
1600 #endif // REPLACEARGS_ANSI
1601 if ( hf != INVALID_HANDLE_VALUE )
1602 {
1603 BOOL found = TRUE;
1604 do
1605 {
1606 #ifdef REPLACEARGS_ANSI
1607 int howMany = MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, NULL, 0 );
1608 if ( howMany > 0 )
1609 {
1610 howMany += baseLen;
1611 wchar_t* tmp = new wchar_t[howMany + 1];
1612 wcsncpy( tmp, base, howMany + 1 );
1613 MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, tmp + baseLen, howMany + 1 - baseLen );
1614 expandedArgs.push_back( tmp );
1615 found = FindNextFileA( hf, &data );
1616 }
1617 #else
1618 int howMany = wcslen(data.cFileName) + baseLen;
1619 wchar_t* tmp = new wchar_t[howMany + 1];
1620 wcsncpy( tmp, base, howMany + 1 );
1621 wcsncat( tmp, data.cFileName, howMany + 1 );
1622 expandedArgs.push_back( tmp );
1623 found = FindNextFileW( hf, &data );
1624 #endif // REPLACEARGS_ANSI
1625 } while ( found );
1627 FindClose( hf );
1628 }
1629 else
1630 {
1631 expandedArgs.push_back( parsed[i1] );
1632 }
1633 #ifdef REPLACEARGS_ANSI
1634 }
1635 #endif // REPLACEARGS_ANSI
1637 delete[] base;
1638 }
1639 else
1640 {
1641 expandedArgs.push_back( parsed[i1] );
1642 }
1643 }
1645 {
1646 wchar_t** block = new wchar_t*[expandedArgs.size()];
1647 int iz = 0;
1648 for ( std::vector<wchar_t*>::iterator it = expandedArgs.begin(); it != expandedArgs.end(); it++ )
1649 {
1650 block[iz++] = *it;
1651 }
1652 parsed = block;
1653 numArgs = expandedArgs.size();
1654 }
1656 std::vector<gchar*> newArgs;
1657 for ( int i = 0; i < numArgs; i++ )
1658 {
1659 gchar* replacement = g_utf16_to_utf8( (gunichar2*)parsed[i], -1, NULL, NULL, NULL );
1660 if ( replacement )
1661 {
1662 #ifdef REPLACEARGS_DEBUG
1663 gchar *safe2 = Inkscape::IO::sanitizeString(replacement);
1665 if ( safe2 )
1666 {
1667 {
1668 char tmp[1024];
1669 snprintf( tmp, sizeof(tmp), " [%2d] = '%s'", i, safe2 );
1670 MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1671 }
1672 g_free( safe2 );
1673 }
1674 #endif // REPLACEARGS_DEBUG
1676 newArgs.push_back( replacement );
1677 }
1678 else
1679 {
1680 newArgs.push_back( blankParam );
1681 }
1682 }
1684 // Now push our munged params to be the new argv and argc
1685 {
1686 char** block = new char*[newArgs.size()];
1687 int iz = 0;
1688 for ( std::vector<char*>::iterator it = newArgs.begin(); it != newArgs.end(); it++ )
1689 {
1690 block[iz++] = *it;
1691 }
1692 argv = block;
1693 argc = newArgs.size();
1694 worked = true;
1695 }
1696 }
1697 #ifdef REPLACEARGS_DEBUG
1698 else
1699 {
1700 MessageBoxA( NULL, "Unable to process command-line", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1701 }
1702 #endif // REPLACEARGS_DEBUG
1703 }
1704 #ifdef REPLACEARGS_DEBUG
1705 else
1706 {
1707 {
1708 MessageBoxA( NULL, "Unable to fetch result from GetCommandLineW()", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1709 }
1711 char* line2 = GetCommandLineA();
1712 if ( line2 )
1713 {
1714 gchar *safe = Inkscape::IO::sanitizeString(line2);
1715 {
1716 {
1717 char tmp[strlen(safe) + 32];
1718 snprintf( tmp, sizeof(tmp), "GetCommandLineA() = '%s'", safe );
1719 MessageBoxA( NULL, tmp, "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1720 }
1721 }
1722 }
1723 else
1724 {
1725 MessageBoxA( NULL, "Unable to fetch result from GetCommandLineA()", "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1726 }
1727 }
1728 #endif // REPLACEARGS_DEBUG
1730 return worked;
1731 }
1732 #endif // WIN32
1734 static GSList *
1735 sp_process_args(poptContext ctx)
1736 {
1737 GSList *fl = NULL;
1739 gint a;
1740 while ((a = poptGetNextOpt(ctx)) >= 0) {
1741 switch (a) {
1742 case SP_ARG_FILE: {
1743 gchar const *fn = poptGetOptArg(ctx);
1744 if (fn != NULL) {
1745 fl = g_slist_append(fl, g_strdup(fn));
1746 }
1747 break;
1748 }
1749 case SP_ARG_VERSION: {
1750 printf("Inkscape %s (%s)\n", INKSCAPE_VERSION, __DATE__);
1751 exit(0);
1752 break;
1753 }
1754 case SP_ARG_EXTENSIONDIR: {
1755 printf("%s\n", INKSCAPE_EXTENSIONDIR);
1756 exit(0);
1757 break;
1758 }
1759 case SP_ARG_VERB_LIST: {
1760 // This really shouldn't go here, we should init the app.
1761 // But, since we're just exiting in this path, there is
1762 // no harm, and this is really a better place to put
1763 // everything else.
1764 Inkscape::Extension::init();
1765 Inkscape::Verb::list();
1766 exit(0);
1767 break;
1768 }
1769 case SP_ARG_VERB:
1770 case SP_ARG_SELECT: {
1771 gchar const *arg = poptGetOptArg(ctx);
1772 if (arg != NULL) {
1773 // printf("Adding in: %s\n", arg);
1774 new Inkscape::CmdLineAction((a == SP_ARG_VERB), arg);
1775 }
1776 break;
1777 }
1778 default: {
1779 break;
1780 }
1781 }
1782 }
1784 gchar const ** const args = poptGetArgs(ctx);
1785 if (args != NULL) {
1786 for (unsigned i = 0; args[i] != NULL; i++) {
1787 fl = g_slist_append(fl, g_strdup(args[i]));
1788 }
1789 }
1791 return fl;
1792 }
1795 /*
1796 Local Variables:
1797 mode:c++
1798 c-file-style:"stroustrup"
1799 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1800 indent-tabs-mode:nil
1801 fill-column:99
1802 End:
1803 */
1804 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :