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