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 }
917 delete doc;
918 }
919 fl = g_slist_remove(fl, fl->data);
920 }
921 }
923 /**
924 * Run the application as an interactive shell, parsing command lines from stdin
925 * Returns -1 on error.
926 */
927 int sp_main_shell(char const* command_name)
928 {
929 int retval = 0;
931 const unsigned int buffer_size = 4096;
932 gchar *command_line = g_strnfill(buffer_size, 0);
933 g_strlcpy(command_line, command_name, buffer_size);
934 gsize offset = g_strlcat(command_line, " ", buffer_size);
935 gsize sizeLeft = buffer_size - offset;
936 gchar *useme = command_line + offset;
938 fprintf(stdout, "Inkscape %s interactive shell mode. Type 'quit' to quit.\n", INKSCAPE_VERSION);
939 fflush(stdout);
940 char* linedata = 0;
941 do {
942 fprintf(stdout, ">");
943 fflush(stdout);
944 if ((linedata = fgets(useme, sizeLeft, stdin))) {
945 size_t len = strlen(useme);
946 if ( (len >= sizeLeft - 1) || (useme[len - 1] != '\n') ) {
947 fprintf(stdout, "ERROR: Command line too long\n");
948 // Consume rest of line
949 retval = -1; // If the while loop completes, this remains -1
950 while (fgets(useme, sizeLeft, stdin) && retval) {
951 len = strlen(command_line);
952 if ( (len < buffer_size) && (command_line[len-1] == '\n') ) {
953 retval = 0;
954 }
955 }
956 } else {
957 useme[--len] = '\0'; // Strip newline
958 if (useme[len - 1] == '\r') {
959 useme[--len] = '\0';
960 }
961 if ( strcmp(useme, "quit") == 0 ) {
962 // Time to quit
963 fflush(stdout);
964 linedata = 0; // mark for exit
965 } else if ( len < 1 ) {
966 // blank string. Do nothing.
967 } else {
968 GError* parseError = 0;
969 gchar** argv = 0;
970 gint argc = 0;
971 if ( g_shell_parse_argv(command_line, &argc, &argv, &parseError) ) {
972 poptContext ctx = poptGetContext(NULL, argc, const_cast<const gchar**>(argv), options, 0);
973 poptSetOtherOptionHelp(ctx, _("[OPTIONS...] [FILE...]\n\nAvailable options:"));
974 if ( ctx ) {
975 GSList *fl = sp_process_args(ctx);
976 sp_process_file_list(fl);
977 poptFreeContext(ctx);
978 } else {
979 retval = 1; // not sure why. But this was the previous return value
980 }
981 resetCommandlineGlobals();
982 g_strfreev(argv);
983 } else {
984 g_warning("problem parsing commandline: %s", useme);
985 }
986 }
987 }
988 } // if (linedata...
989 } while (linedata && (retval == 0));
991 g_free(command_line);
992 return retval;
993 }
995 int sp_main_console(int argc, char const **argv)
996 {
997 /* We are started in text mode */
999 /* Do this g_type_init(), so that we can use Xft/Freetype2 (Pango)
1000 * in a non-Gtk environment. Used in libnrtype's
1001 * FontInstance.cpp and FontFactory.cpp.
1002 * http://mail.gnome.org/archives/gtk-list/2003-December/msg00063.html
1003 */
1004 g_type_init();
1005 char **argv2 = const_cast<char **>(argv);
1006 gtk_init_check( &argc, &argv2 );
1007 //setlocale(LC_ALL, "");
1009 GSList *fl = NULL;
1010 int retVal = sp_common_main( argc, argv, &fl );
1011 g_return_val_if_fail(retVal == 0, 1);
1013 if (fl == NULL && !sp_shell) {
1014 g_print("Nothing to do!\n");
1015 exit(0);
1016 }
1018 inkscape_application_init(argv[0], false);
1020 if (sp_shell) {
1021 sp_main_shell(argv[0]); // Run as interactive shell
1022 exit(0);
1023 } else {
1024 sp_process_file_list(fl); // Normal command line invokation
1025 }
1026 inkscape_unref();
1028 return 0;
1029 }
1031 static void
1032 do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gchar *id)
1033 {
1034 SPObject *o = NULL;
1036 if (id) {
1037 o = doc->getObjectById(id);
1038 if (o) {
1039 if (!SP_IS_ITEM (o)) {
1040 g_warning("Object with id=\"%s\" is not a visible item. Cannot query dimensions.", id);
1041 return;
1042 }
1043 } else {
1044 g_warning("Object with id=\"%s\" is not found. Cannot query dimensions.", id);
1045 return;
1046 }
1047 } else {
1048 o = SP_DOCUMENT_ROOT(doc);
1049 }
1051 if (o) {
1052 sp_document_ensure_up_to_date (doc);
1053 SPItem *item = ((SPItem *) o);
1055 // "true" SVG bbox for scripting
1056 boost::optional<Geom::Rect> area = item->getBounds(sp_item_i2doc_affine(item));
1057 if (area) {
1058 Inkscape::SVGOStringStream os;
1059 if (extent) {
1060 os << area->dimensions()[axis];
1061 } else {
1062 os << area->min()[axis];
1063 }
1064 g_print ("%s", os.str().c_str());
1065 } else {
1066 g_print("0");
1067 }
1068 }
1069 }
1071 static void
1072 do_query_all (SPDocument *doc)
1073 {
1074 SPObject *o = NULL;
1076 o = SP_DOCUMENT_ROOT(doc);
1078 if (o) {
1079 sp_document_ensure_up_to_date (doc);
1080 do_query_all_recurse(o);
1081 }
1082 }
1084 static void
1085 do_query_all_recurse (SPObject *o)
1086 {
1087 SPItem *item = ((SPItem *) o);
1088 if (o->id && SP_IS_ITEM(item)) {
1089 boost::optional<Geom::Rect> area = item->getBounds(sp_item_i2doc_affine(item));
1090 if (area) {
1091 Inkscape::SVGOStringStream os;
1092 os << o->id;
1093 os << "," << area->min()[Geom::X];
1094 os << "," << area->min()[Geom::Y];
1095 os << "," << area->dimensions()[Geom::X];
1096 os << "," << area->dimensions()[Geom::Y];
1097 g_print ("%s\n", os.str().c_str());
1098 }
1099 }
1101 SPObject *child = o->children;
1102 while (child) {
1103 do_query_all_recurse (child);
1104 child = child->next;
1105 }
1106 }
1109 static void
1110 sp_do_export_png(SPDocument *doc)
1111 {
1112 const gchar *filename = NULL;
1113 gdouble dpi = 0.0;
1115 if (sp_export_use_hints && (!sp_export_id && !sp_export_area_drawing)) {
1116 g_warning ("--export-use-hints can only be used with --export-id or --export-area-drawing; ignored.");
1117 }
1119 GSList *items = NULL;
1121 NRRect area;
1122 if (sp_export_id || sp_export_area_drawing) {
1124 SPObject *o = NULL;
1125 SPObject *o_area = NULL;
1126 if (sp_export_id && sp_export_area_drawing) {
1127 o = doc->getObjectById(sp_export_id);
1128 o_area = SP_DOCUMENT_ROOT (doc);
1129 } else if (sp_export_id) {
1130 o = doc->getObjectById(sp_export_id);
1131 o_area = o;
1132 } else if (sp_export_area_drawing) {
1133 o = SP_DOCUMENT_ROOT (doc);
1134 o_area = o;
1135 }
1137 if (o) {
1138 if (!SP_IS_ITEM (o)) {
1139 g_warning("Object with id=\"%s\" is not a visible item. Nothing exported.", sp_export_id);
1140 return;
1141 }
1143 items = g_slist_prepend (items, SP_ITEM(o));
1145 if (sp_export_id_only) {
1146 g_print("Exporting only object with id=\"%s\"; all other objects hidden\n", sp_export_id);
1147 }
1149 if (sp_export_use_hints) {
1151 // retrieve export filename hint
1152 const gchar *fn_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-filename");
1153 if (fn_hint) {
1154 if (sp_export_png) {
1155 g_warning ("Using export filename from the command line (--export-png). Filename hint %s is ignored.", fn_hint);
1156 filename = sp_export_png;
1157 } else {
1158 filename = fn_hint;
1159 }
1160 } else {
1161 g_warning ("Export filename hint not found for the object.");
1162 filename = sp_export_png;
1163 }
1165 // retrieve export dpi hints
1166 const gchar *dpi_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-xdpi"); // only xdpi, ydpi is always the same now
1167 if (dpi_hint) {
1168 if (sp_export_dpi || sp_export_width || sp_export_height) {
1169 g_warning ("Using bitmap dimensions from the command line (--export-dpi, --export-width, or --export-height). DPI hint %s is ignored.", dpi_hint);
1170 } else {
1171 dpi = atof(dpi_hint);
1172 }
1173 } else {
1174 g_warning ("Export DPI hint not found for the object.");
1175 }
1177 }
1179 // write object bbox to area
1180 sp_document_ensure_up_to_date (doc);
1181 boost::optional<Geom::Rect> areaMaybe;
1182 sp_item_invoke_bbox((SPItem *) o_area, areaMaybe, sp_item_i2r_affine((SPItem *) o_area), TRUE);
1183 if (areaMaybe) {
1184 area = NRRect(areaMaybe);
1185 } else {
1186 g_warning("Unable to determine a valid bounding box. Nothing exported.");
1187 return;
1188 }
1189 } else {
1190 g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
1191 return;
1192 }
1193 }
1195 if (sp_export_area) {
1196 /* Try to parse area (given in SVG pixels) */
1197 if (!sscanf(sp_export_area, "%lg:%lg:%lg:%lg", &area.x0, &area.y0, &area.x1, &area.y1) == 4) {
1198 g_warning("Cannot parse export area '%s'; use 'x0:y0:x1:y1'. Nothing exported.", sp_export_area);
1199 return;
1200 }
1201 if ((area.x0 >= area.x1) || (area.y0 >= area.y1)) {
1202 g_warning("Export area '%s' has negative width or height. Nothing exported.", sp_export_area);
1203 return;
1204 }
1205 } else if (sp_export_area_canvas || !(sp_export_id || sp_export_area_drawing)) {
1206 /* Export the whole canvas */
1207 sp_document_ensure_up_to_date (doc);
1208 area.x0 = SP_ROOT(doc->root)->x.computed;
1209 area.y0 = SP_ROOT(doc->root)->y.computed;
1210 area.x1 = area.x0 + sp_document_width (doc);
1211 area.y1 = area.y0 + sp_document_height (doc);
1212 }
1214 // set filename and dpi from options, if not yet set from the hints
1215 if (!filename) {
1216 if (!sp_export_png) {
1217 g_warning ("No export filename given and no filename hint. Nothing exported.");
1218 return;
1219 }
1220 filename = sp_export_png;
1221 }
1223 if (sp_export_dpi && dpi == 0.0) {
1224 dpi = atof(sp_export_dpi);
1225 if ((dpi < 0.1) || (dpi > 10000.0)) {
1226 g_warning("DPI value %s out of range [0.1 - 10000.0]. Nothing exported.", sp_export_dpi);
1227 return;
1228 }
1229 g_print("DPI: %g\n", dpi);
1230 }
1232 if (sp_export_area_snap) {
1233 area.x0 = std::floor (area.x0);
1234 area.y0 = std::floor (area.y0);
1235 area.x1 = std::ceil (area.x1);
1236 area.y1 = std::ceil (area.y1);
1237 }
1239 // default dpi
1240 if (dpi == 0.0) {
1241 dpi = PX_PER_IN;
1242 }
1244 unsigned long int width = 0;
1245 unsigned long int height = 0;
1247 if (sp_export_width) {
1248 errno=0;
1249 width = strtoul(sp_export_width, NULL, 0);
1250 if ((width < 1) || (width > PNG_UINT_31_MAX) || (errno == ERANGE) ) {
1251 g_warning("Export width %lu out of range (1 - %lu). Nothing exported.", width, (unsigned long int)PNG_UINT_31_MAX);
1252 return;
1253 }
1254 dpi = (gdouble) width * PX_PER_IN / (area.x1 - area.x0);
1255 }
1257 if (sp_export_height) {
1258 errno=0;
1259 height = strtoul(sp_export_height, NULL, 0);
1260 if ((height < 1) || (height > PNG_UINT_31_MAX)) {
1261 g_warning("Export height %lu out of range (1 - %lu). Nothing exported.", height, (unsigned long int)PNG_UINT_31_MAX);
1262 return;
1263 }
1264 dpi = (gdouble) height * PX_PER_IN / (area.y1 - area.y0);
1265 }
1267 if (!sp_export_width) {
1268 width = (unsigned long int) ((area.x1 - area.x0) * dpi / PX_PER_IN + 0.5);
1269 }
1271 if (!sp_export_height) {
1272 height = (unsigned long int) ((area.y1 - area.y0) * dpi / PX_PER_IN + 0.5);
1273 }
1275 guint32 bgcolor = 0x00000000;
1276 if (sp_export_background) {
1277 // override the page color
1278 bgcolor = sp_svg_read_color(sp_export_background, 0xffffff00);
1279 bgcolor |= 0xff; // default is no opacity
1280 } else {
1281 // read from namedview
1282 Inkscape::XML::Node *nv = sp_repr_lookup_name (doc->rroot, "sodipodi:namedview");
1283 if (nv && nv->attribute("pagecolor"))
1284 bgcolor = sp_svg_read_color(nv->attribute("pagecolor"), 0xffffff00);
1285 if (nv && nv->attribute("inkscape:pageopacity"))
1286 bgcolor |= SP_COLOR_F_TO_U(sp_repr_get_double_attribute (nv, "inkscape:pageopacity", 1.0));
1287 }
1289 if (sp_export_background_opacity) {
1290 // override opacity
1291 gfloat value;
1292 if (sp_svg_number_read_f (sp_export_background_opacity, &value)) {
1293 if (value > 1.0) {
1294 value = CLAMP (value, 1.0f, 255.0f);
1295 bgcolor &= (guint32) 0xffffff00;
1296 bgcolor |= (guint32) floor(value);
1297 } else {
1298 value = CLAMP (value, 0.0f, 1.0f);
1299 bgcolor &= (guint32) 0xffffff00;
1300 bgcolor |= SP_COLOR_F_TO_U(value);
1301 }
1302 }
1303 }
1305 g_print("Background RRGGBBAA: %08x\n", bgcolor);
1307 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);
1309 g_print("Bitmap saved as: %s\n", filename);
1311 if ((width >= 1) && (height >= 1) && (width <= PNG_UINT_31_MAX) && (height <= PNG_UINT_31_MAX)) {
1312 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);
1313 } else {
1314 g_warning("Calculated bitmap dimensions %lu %lu are out of range (1 - %lu). Nothing exported.", width, height, (unsigned long int)PNG_UINT_31_MAX);
1315 }
1317 g_slist_free (items);
1318 }
1321 /**
1322 * Perform an export of either PS or EPS.
1323 *
1324 * \param doc Document to export.
1325 * \param uri URI to export to.
1326 * \param mime MIME type to export as.
1327 */
1329 static void do_export_ps(SPDocument* doc, gchar const* uri, char const* mime)
1330 {
1331 Inkscape::Extension::DB::OutputList o;
1332 Inkscape::Extension::db.get_output_list(o);
1333 Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1334 while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1335 i++;
1336 }
1338 if (i == o.end())
1339 {
1340 g_warning ("Could not find an extension to export to MIME type %s.", mime);
1341 return;
1342 }
1344 bool old_text_to_path = false;
1345 bool old_font_embedded = false;
1346 bool old_bbox_page = false;
1348 try {
1349 old_text_to_path = (*i)->get_param_bool("textToPath");
1350 (*i)->set_param_bool("textToPath", sp_export_text_to_path);
1351 }
1352 catch (...) {
1353 g_warning ("Could not set export-text-to-path option for this export.");
1354 }
1356 try {
1357 old_font_embedded = (*i)->get_param_bool("fontEmbedded");
1358 (*i)->set_param_bool("fontEmbedded", sp_export_font);
1359 }
1360 catch (...) {
1361 g_warning ("Could not set export-font option for this export.");
1362 }
1364 try {
1365 old_bbox_page = (*i)->get_param_bool("pageBoundingBox");
1366 (*i)->set_param_bool("pageBoundingBox", sp_export_bbox_page);
1367 }
1368 catch (...) {
1369 g_warning ("Could not set export-bbox-page option for this export.");
1370 }
1372 (*i)->save(doc, uri);
1374 try {
1375 (*i)->set_param_bool("textToPath", old_text_to_path);
1376 (*i)->set_param_bool("fontEmbedded", old_font_embedded);
1377 (*i)->set_param_bool("pageBoundingBox", old_bbox_page);
1378 }
1379 catch (...) {
1381 }
1382 }
1384 /**
1385 * Perform a PDF export
1386 *
1387 * \param doc Document to export.
1388 * \param uri URI to export to.
1389 * \param mime MIME type to export as.
1390 */
1392 static void do_export_pdf(SPDocument* doc, gchar const* uri, char const* mime)
1393 {
1394 Inkscape::Extension::DB::OutputList o;
1395 Inkscape::Extension::db.get_output_list(o);
1396 Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1397 while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1398 i++;
1399 }
1401 if (i == o.end())
1402 {
1403 g_warning ("Could not find an extension to export to MIME type %s.", mime);
1404 return;
1405 }
1407 if (sp_export_id) {
1408 SPObject *o = doc->getObjectById(sp_export_id);
1409 if (o == NULL) {
1410 g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
1411 return;
1412 }
1413 (*i)->set_param_string ("exportId", sp_export_id);
1414 } else {
1415 (*i)->set_param_string ("exportId", "");
1416 }
1418 if (sp_export_area_drawing) {
1419 (*i)->set_param_bool ("exportDrawing", TRUE);
1420 } else {
1421 (*i)->set_param_bool ("exportDrawing", FALSE);
1422 }
1424 if (sp_export_area_canvas) {
1425 (*i)->set_param_bool ("exportCanvas", TRUE);
1426 } else {
1427 (*i)->set_param_bool ("exportCanvas", FALSE);
1428 }
1430 if (sp_export_text_to_path) {
1431 (*i)->set_param_bool("textToPath", TRUE);
1432 } else {
1433 (*i)->set_param_bool("textToPath", FALSE);
1434 }
1436 (*i)->save(doc, uri);
1437 }
1439 #ifdef WIN32
1440 /**
1441 * Export a document to EMF
1442 *
1443 * \param doc Document to export.
1444 * \param uri URI to export to.
1445 * \param mime MIME type to export as (should be "image/x-emf")
1446 */
1448 static void do_export_emf(SPDocument* doc, gchar const* uri, char const* mime)
1449 {
1450 Inkscape::Extension::DB::OutputList o;
1451 Inkscape::Extension::db.get_output_list(o);
1452 Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1453 while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1454 i++;
1455 }
1457 if (i == o.end())
1458 {
1459 g_warning ("Could not find an extension to export to MIME type %s.", mime);
1460 return;
1461 }
1463 (*i)->save(doc, uri);
1464 }
1465 #endif //WIN32
1467 #ifdef WIN32
1468 bool replaceArgs( int& argc, char**& argv )
1469 {
1470 bool worked = false;
1472 #ifdef REPLACEARGS_DEBUG
1473 MessageBoxA( NULL, "GetCommandLineW() getting called", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1474 #endif // REPLACEARGS_DEBUG
1476 wchar_t* line = GetCommandLineW();
1477 if ( line )
1478 {
1479 #ifdef REPLACEARGS_DEBUG
1480 {
1481 gchar* utf8Line = g_utf16_to_utf8( (gunichar2*)line, -1, NULL, NULL, NULL );
1482 if ( utf8Line )
1483 {
1484 gchar *safe = Inkscape::IO::sanitizeString(utf8Line);
1485 {
1486 char tmp[strlen(safe) + 32];
1487 snprintf( tmp, sizeof(tmp), "GetCommandLineW() = '%s'", safe );
1488 MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1489 }
1490 }
1491 }
1492 #endif // REPLACEARGS_DEBUG
1494 int numArgs = 0;
1495 wchar_t** parsed = CommandLineToArgvW( line, &numArgs );
1497 #ifdef REPLACEARGS_ANSI
1498 // test code for trying things on Win95/98/ME
1499 if ( !parsed )
1500 {
1501 #ifdef REPLACEARGS_DEBUG
1502 MessageBoxA( NULL, "Unable to process command-line. Faking it", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1503 #endif // REPLACEARGS_DEBUG
1504 int lineLen = wcslen(line) + 1;
1505 wchar_t* lineDup = new wchar_t[lineLen];
1506 wcsncpy( lineDup, line, lineLen );
1508 int pos = 0;
1509 bool inQuotes = false;
1510 bool inWhitespace = true;
1511 std::vector<int> places;
1512 while ( lineDup[pos] )
1513 {
1514 if ( inQuotes )
1515 {
1516 if ( lineDup[pos] == L'"' )
1517 {
1518 inQuotes = false;
1519 }
1520 }
1521 else if ( lineDup[pos] == L'"' )
1522 {
1523 inQuotes = true;
1524 inWhitespace = false;
1525 places.push_back(pos);
1526 }
1527 else if ( lineDup[pos] == L' ' || lineDup[pos] == L'\t' )
1528 {
1529 if ( !inWhitespace )
1530 {
1531 inWhitespace = true;
1532 lineDup[pos] = 0;
1533 }
1534 }
1535 else if ( inWhitespace && (lineDup[pos] != L' ' && lineDup[pos] != L'\t') )
1536 {
1537 inWhitespace = false;
1538 places.push_back(pos);
1539 }
1540 else
1541 {
1542 // consume
1543 }
1544 pos++;
1545 }
1546 #ifdef REPLACEARGS_DEBUG
1547 {
1548 char tmp[256];
1549 snprintf( tmp, sizeof(tmp), "Counted %d args", places.size() );
1550 MessageBoxA( NULL, tmp, "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1551 }
1552 #endif // REPLACEARGS_DEBUG
1554 wchar_t** block = new wchar_t*[places.size()];
1555 int i = 0;
1556 for ( std::vector<int>::iterator it = places.begin(); it != places.end(); it++ )
1557 {
1558 block[i++] = &lineDup[*it];
1559 }
1560 parsed = block;
1561 numArgs = places.size();
1562 }
1563 #endif // REPLACEARGS_ANSI
1565 if ( parsed )
1566 {
1567 std::vector<wchar_t*>expandedArgs;
1568 if ( numArgs > 0 )
1569 {
1570 expandedArgs.push_back( parsed[0] );
1571 }
1573 for ( int i1 = 1; i1 < numArgs; i1++ )
1574 {
1575 bool wildcarded = (wcschr(parsed[i1], L'?') != NULL) || (wcschr(parsed[i1], L'*') != NULL);
1576 wildcarded &= parsed[i1][0] != L'"';
1577 wildcarded &= parsed[i1][0] != L'-';
1578 if ( wildcarded )
1579 {
1580 #ifdef REPLACEARGS_ANSI
1581 WIN32_FIND_DATAA data;
1582 #else
1583 WIN32_FIND_DATAW data;
1584 #endif // REPLACEARGS_ANSI
1586 memset((void *)&data, 0, sizeof(data));
1588 int baseLen = wcslen(parsed[i1]) + 2;
1589 wchar_t* base = new wchar_t[baseLen];
1590 wcsncpy( base, parsed[i1], baseLen );
1591 wchar_t* last = wcsrchr( base, L'\\' );
1592 if ( last )
1593 {
1594 last[1] = 0;
1595 }
1596 else
1597 {
1598 base[0] = 0;
1599 }
1600 baseLen = wcslen( base );
1602 #ifdef REPLACEARGS_ANSI
1603 char target[MAX_PATH];
1604 if ( WideCharToMultiByte( CP_ACP, 0, parsed[i1], -1, target, sizeof(target), NULL, NULL) )
1605 {
1606 HANDLE hf = FindFirstFileA( target, &data );
1607 #else
1608 HANDLE hf = FindFirstFileW( parsed[i1], &data );
1609 #endif // REPLACEARGS_ANSI
1610 if ( hf != INVALID_HANDLE_VALUE )
1611 {
1612 BOOL found = TRUE;
1613 do
1614 {
1615 #ifdef REPLACEARGS_ANSI
1616 int howMany = MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, NULL, 0 );
1617 if ( howMany > 0 )
1618 {
1619 howMany += baseLen;
1620 wchar_t* tmp = new wchar_t[howMany + 1];
1621 wcsncpy( tmp, base, howMany + 1 );
1622 MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, tmp + baseLen, howMany + 1 - baseLen );
1623 expandedArgs.push_back( tmp );
1624 found = FindNextFileA( hf, &data );
1625 }
1626 #else
1627 int howMany = wcslen(data.cFileName) + baseLen;
1628 wchar_t* tmp = new wchar_t[howMany + 1];
1629 wcsncpy( tmp, base, howMany + 1 );
1630 wcsncat( tmp, data.cFileName, howMany + 1 );
1631 expandedArgs.push_back( tmp );
1632 found = FindNextFileW( hf, &data );
1633 #endif // REPLACEARGS_ANSI
1634 } while ( found );
1636 FindClose( hf );
1637 }
1638 else
1639 {
1640 expandedArgs.push_back( parsed[i1] );
1641 }
1642 #ifdef REPLACEARGS_ANSI
1643 }
1644 #endif // REPLACEARGS_ANSI
1646 delete[] base;
1647 }
1648 else
1649 {
1650 expandedArgs.push_back( parsed[i1] );
1651 }
1652 }
1654 {
1655 wchar_t** block = new wchar_t*[expandedArgs.size()];
1656 int iz = 0;
1657 for ( std::vector<wchar_t*>::iterator it = expandedArgs.begin(); it != expandedArgs.end(); it++ )
1658 {
1659 block[iz++] = *it;
1660 }
1661 parsed = block;
1662 numArgs = expandedArgs.size();
1663 }
1665 std::vector<gchar*> newArgs;
1666 for ( int i = 0; i < numArgs; i++ )
1667 {
1668 gchar* replacement = g_utf16_to_utf8( (gunichar2*)parsed[i], -1, NULL, NULL, NULL );
1669 if ( replacement )
1670 {
1671 #ifdef REPLACEARGS_DEBUG
1672 gchar *safe2 = Inkscape::IO::sanitizeString(replacement);
1674 if ( safe2 )
1675 {
1676 {
1677 char tmp[1024];
1678 snprintf( tmp, sizeof(tmp), " [%2d] = '%s'", i, safe2 );
1679 MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1680 }
1681 g_free( safe2 );
1682 }
1683 #endif // REPLACEARGS_DEBUG
1685 newArgs.push_back( replacement );
1686 }
1687 else
1688 {
1689 newArgs.push_back( blankParam );
1690 }
1691 }
1693 // Now push our munged params to be the new argv and argc
1694 {
1695 char** block = new char*[newArgs.size()];
1696 int iz = 0;
1697 for ( std::vector<char*>::iterator it = newArgs.begin(); it != newArgs.end(); it++ )
1698 {
1699 block[iz++] = *it;
1700 }
1701 argv = block;
1702 argc = newArgs.size();
1703 worked = true;
1704 }
1705 }
1706 #ifdef REPLACEARGS_DEBUG
1707 else
1708 {
1709 MessageBoxA( NULL, "Unable to process command-line", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1710 }
1711 #endif // REPLACEARGS_DEBUG
1712 }
1713 #ifdef REPLACEARGS_DEBUG
1714 else
1715 {
1716 {
1717 MessageBoxA( NULL, "Unable to fetch result from GetCommandLineW()", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1718 }
1720 char* line2 = GetCommandLineA();
1721 if ( line2 )
1722 {
1723 gchar *safe = Inkscape::IO::sanitizeString(line2);
1724 {
1725 {
1726 char tmp[strlen(safe) + 32];
1727 snprintf( tmp, sizeof(tmp), "GetCommandLineA() = '%s'", safe );
1728 MessageBoxA( NULL, tmp, "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1729 }
1730 }
1731 }
1732 else
1733 {
1734 MessageBoxA( NULL, "Unable to fetch result from GetCommandLineA()", "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1735 }
1736 }
1737 #endif // REPLACEARGS_DEBUG
1739 return worked;
1740 }
1741 #endif // WIN32
1743 static GSList *
1744 sp_process_args(poptContext ctx)
1745 {
1746 GSList *fl = NULL;
1748 gint a;
1749 while ((a = poptGetNextOpt(ctx)) >= 0) {
1750 switch (a) {
1751 case SP_ARG_FILE: {
1752 gchar const *fn = poptGetOptArg(ctx);
1753 if (fn != NULL) {
1754 fl = g_slist_append(fl, g_strdup(fn));
1755 }
1756 break;
1757 }
1758 case SP_ARG_VERSION: {
1759 printf("Inkscape %s (%s)\n", INKSCAPE_VERSION, __DATE__);
1760 exit(0);
1761 break;
1762 }
1763 case SP_ARG_EXTENSIONDIR: {
1764 printf("%s\n", INKSCAPE_EXTENSIONDIR);
1765 exit(0);
1766 break;
1767 }
1768 case SP_ARG_VERB_LIST: {
1769 // This really shouldn't go here, we should init the app.
1770 // But, since we're just exiting in this path, there is
1771 // no harm, and this is really a better place to put
1772 // everything else.
1773 Inkscape::Extension::init();
1774 Inkscape::Verb::list();
1775 exit(0);
1776 break;
1777 }
1778 case SP_ARG_VERB:
1779 case SP_ARG_SELECT: {
1780 gchar const *arg = poptGetOptArg(ctx);
1781 if (arg != NULL) {
1782 // printf("Adding in: %s\n", arg);
1783 new Inkscape::CmdLineAction((a == SP_ARG_VERB), arg);
1784 }
1785 break;
1786 }
1787 default: {
1788 break;
1789 }
1790 }
1791 }
1793 gchar const ** const args = poptGetArgs(ctx);
1794 if (args != NULL) {
1795 for (unsigned i = 0; args[i] != NULL; i++) {
1796 fl = g_slist_append(fl, g_strdup(args[i]));
1797 }
1798 }
1800 return fl;
1801 }
1804 /*
1805 Local Variables:
1806 mode:c++
1807 c-file-style:"stroustrup"
1808 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1809 indent-tabs-mode:nil
1810 fill-column:99
1811 End:
1812 */
1813 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :