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