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