Code

r10814@tres: ted | 2006-01-29 14:02:54 -0800
[inkscape.git] / src / main.cpp
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  */
25 // Putting the following in main.cpp appears a natural choice.
27 /** \mainpage The Inkscape Source Code Documentation
28  * While the standard doxygen documentation can be accessed through the links
29  * in the header, the following documents are additionally available to the
30  * interested reader.
31  *
32  * \section groups Main directory documentation
33  * Inkscape's classes and files in the main directory can be grouped into
34  * the following categories:
35  *
36  * - \subpage ObjectTree - inkscape's SVG canvas
37  * - \subpage Tools - the tools UI
38  * - \subpage UI - inkscape's user interface
39  * - \subpage XmlTree - XML backbone of the document
40  * - \subpage Rendering - rendering and buffering
41  * - \subpage OtherServices - what doesn't fit in the above
42  *
43  * See also the <a href="dirs.html">other directories</a> until doxygen
44  * allows setting links to those doc files.
45  *
46  * \section extlinks Links to external documentation
47  *
48  * \subsection liblinks External documentation on libraries used in inkscape
49  *
50  * <a href="http://www.gtkmm.org/gtkmm2/docs/">Gtkmm</a>
51  * <a href="http://www.gtkmm.org/gtkmm2/docs/reference/html/dir_000003.html">atkmm</a>
52  * <a href="http://www.gtkmm.org/gtkmm2/docs/reference/html/dir_000009.html">gdkmm</a>
53  * <a href="http://www.gtkmm.org/gtkmm2/docs/reference/html/dir_000007.html">pangomm</a>
54  * <a href="http://libsigc.sourceforge.net/libsigc1_2/reference/html/modules.html">libsigc++</a>
55  * <a href="http://www.gtk.org/api/">GTK+</a>
56  * <a href="http://developer.gnome.org/doc/API/2.0/gdk-pixbuf/index.html">gdk-pixbuf</a>
57  * <a href="http://developer.gnome.org/doc/API/2.0/gobject/index.html">GObject</a>
58  * <a href="http://developer.gnome.org/doc/API/2.0/atk/index.html">atk</a>
59  * <a href="http://developer.gnome.org/doc/API/2.0/pango/index.html">pango</a>
60  * <a href="http://developer.gnome.org/doc/API/2.0/gnome-vfs-2.0/">GnomeVFS</a>
61  * <a href="http://libsigc.sourceforge.net/libsigc2/docs/index.html">libsigc</a>
62  * <a href="http://developer.gnome.org/doc/API/2.0/ORBit/index.html">ORBit</a>
63  * <a href="http://developer.gnome.org/doc/API/2.0/libbonobo/index.html">bonobo</a>
64  * <a href="http://developer.gnome.org/doc/API/2.0/bonobo-activation/index.html">bonobo-activation</a>
65  * <a href="http://xmlsoft.org/XSLT/html/libxslt-lib.html#LIBXSLT-LIB">libxslt</a>
66  * <a href="http://xmlsoft.org/html/index.html">libxml2</a>
67  *
68  * \subsection stdlinks External standards documentation
69  *
70  * <a href="http://www.w3.org/TR/SVG/">SVG1.1</a>
71  * <a href="http://www.w3.org/TR/SVG12/">SVG1.2</a>
72  * <a href="http://www.w3.org/TR/SVGMobile/">SVGMobile</a>
73  * <a href="http://www.w3.org/Graphics/SVG/Test/">SVGTest</a>
74  * <a href="http://www.libpng.org/pub/png/">PNG</a>
75  * <a href="http://www.w3.org/TR/xslt">XSLT</a>
76  * <a href="http://partners.adobe.com/public/developer/ps/index_specs.html">PS</a>
77  * <a href="http://developer.gnome.org/projects/gup/hig/">Gnome-HIG</a>
78  */
80 /** \page ObjectTree Object Tree Classes and Files
81  * Inkscape::ObjectHierarchy [\ref object-hierarchy.cpp, \ref object-hierarchy.h]
82  * - SPObject [\ref sp-object.cpp, \ref sp-object.h, \ref object-edit.cpp, \ref sp-object-repr.cpp]
83  *   - SPDefs [\ref sp-defs.cpp, \ref sp-defs.h]
84  *   - SPFlowline [\ref sp-flowdiv.cpp, \ref sp-flowdiv.h]
85  *   - SPFlowregionbreak [\ref sp-flowdiv.cpp, \ref sp-flowdiv.h]
86  *   - SPGuide [\ref sp-guide.cpp, \ref sp-guide.h]
87  *   - SPItem [\ref sp-item.cpp, \ref sp-item.h, \ref sp-item-notify-moveto.cpp, \ref sp-item-rm-unsatisfied-cns.cpp, \ref sp-item-transform.cpp, \ref sp-item-update-cns.cpp, ]
88  *     - SPFlowdiv [\ref sp-flowdiv.cpp, \ref sp-flowdiv.h]
89  *     - SPFlowpara [\ref sp-flowdiv.cpp, \ref sp-flowdiv.h]
90  *     - SPFlowregion [\ref sp-flowregion.cpp, \ref sp-flowregion.h]
91  *     - SPFlowregionExclude [\ref sp-flowregion.cpp, \ref sp-flowregion.h]
92  *     - SPFlowtext [\ref sp-flowtext.cpp, \ref sp-flowtext.h]
93  *     - SPFlowtspan [\ref sp-flowdiv.cpp, \ref sp-flowdiv.h]
94  *     - SPGroup [\ref sp-item-group.cpp, \ref sp-item-group.h]
95  *       - SPAnchor [\ref sp-anchor.cpp, \ref sp-anchor.h]
96  *       - SPMarker [\ref sp-marker.cpp, \ref sp-marker.h]
97  *       - SPRoot [\ref sp-root.cpp, \ref sp-root.h]
98  *       - SPSymbol [\ref sp-symbol.cpp, \ref sp-symbol.h]
99  *     - SPImage [\ref sp-image.cpp, \ref sp-image.h]
100  *     - SPShape [\ref sp-shape.cpp, \ref sp-shape.h, \ref marker-status.cpp]
101  *       - SPGenericEllipse [\ref sp-ellipse.cpp, \ref sp-ellipse.h]
102  *         - SPArc
103  *         - SPCircle
104  *         - SPEllipse
105  *       - SPLine [\ref sp-line.cpp, \ref sp-line.h]
106  *       - SPOffset [\ref sp-offset.cpp, \ref sp-offset.h]
107  *       - SPPath [\ref sp-path.cpp, \ref sp-path.h, \ref path-chemistry.cpp, \ref nodepath.cpp, \ref nodepath.h, \ref splivarot.cpp]
108  *       - SPPolygon [\ref sp-polygon.cpp, \ref sp-polygon.h]
109  *         - SPStar [\ref sp-star.cpp, \ref sp-star.h]
110  *       - SPPolyLine [\ref sp-polyline.cpp, \ref sp-polyline.h]
111  *       - SPRect [\ref sp-rect.cpp, \ref sp-rect.h]
112  *       - SPSpiral [\ref sp-spiral.cpp, \ref sp-spiral.h]
113  *     - SPText [\ref sp-text.cpp, \ref sp-text.h, \ref text-chemistry.cpp, \ref text-editing.cpp]
114  *     - SPTextPath [\ref sp-tspan.cpp, \ref sp-tspan.h]
115  *     - SPTSpan [\ref sp-tspan.cpp, \ref sp-tspan.h]
116  *     - SPUse [\ref sp-use.cpp, \ref sp-use.h]
117  *   - SPMetadata [\ref sp-metadata.cpp, \ref sp-metadata.h]
118  *   - SPObjectGroup [\ref sp-object-group.cpp, \ref sp-object-group.h]
119  *     - SPClipPath [\ref sp-clippath.cpp, \ref sp-clippath.h]
120  *     - SPMask [\ref sp-mask.cpp, \ref sp-mask.h]
121  *     - SPNamedView [\ref sp-namedview.cpp, \ref sp-namedview.h]
122  *   - SPPaintServer [\ref sp-paint-server.cpp, \ref sp-paint-server.h]
123  *     - SPGradient [\ref sp-gradient.cpp, \ref sp-gradient.h, \ref gradient-chemistry.cpp, \ref sp-gradient-reference.h, \ref sp-gradient-spread.h, \ref sp-gradient-units.h, \ref sp-gradient-vector.h]
124  *       - SPLinearGradient
125  *       - SPRadialGradient
126  *     - SPPattern [\ref sp-pattern.cpp, \ref sp-pattern.h]
127  *   - SPSkeleton [\ref sp-skeleton.cpp, \ref sp-skeleton.h]
128  *   - SPStop [\ref sp-stop.h]
129  *   - SPString [\ref sp-string.cpp, \ref sp-string.h]
130  *   - SPStyleElem [\ref sp-style-elem.cpp, \ref sp-style-elem.h]
131  *
132  */
133 /** \page Tools Tools Related Classes and Files
134  *
135  * SelCue [\ref selcue.cpp, \ref selcue.h, \ref rubberband.cpp]
136  * Inkscape::Selection [\ref selection.cpp, \ref selection.h, \ref selection-chemistry.cpp]
137  * SPSelTrans [\ref seltrans.cpp, \ref seltrans.h]
138  *
139  * \section Event Context Class Hierarchy
140  *
141  *- SPEventContext[\ref event-context.cpp, \ref event-context.h]
142  * - SPArcContext [\ref arc-context.cpp, \ref arc-context.h]
143  * - SPDrawContext [\ref draw-context.cpp, \ref draw-context.h]
144  *   - SPPenContext [\ref pen-context.cpp, \ref pen-context.h]
145  *   - SPPencilContext [\ref pencil-context.cpp, \ref pencil-context.h]
146  *   - SPConnectorContext [\ref connector-context.cpp, \ref connector-context.h, \ref sp-conn-end.cpp, \ref sp-conn-end-pair.cpp]
147  * - SPGradientContext [\ref gradient-context.cpp, \ref gradient-context.h, \ref gradient-drag.cpp, \ref gradient-toolbar.cpp]
148  * - SPRectContext [\ref rect-context.cpp, \ref rect-context.h]
149  * - SPSelectContext [\ref select-context.cpp, \ref select-context.h]
150  * - SPSpiralContext [\ref spiral-context.cpp, \ref spiral-context.h]
151  * - SPStarContext [\ref star-context.cpp, \ref star-context.h]
152  *
153  * SPNodeContext [\ref node-context.cpp, \ref node-context.h]
154  *
155  * SPZoomContext [\ref zoom-context.cpp, \ref zoom-context.h]
156  *
157  * SPDynaDrawContext [\ref dyna-draw-context.cpp, \ref dyna-draw-context.h]
158  *
159  * SPDropperContext [\ref dropper-context.cpp, \ref dropper-context.h]
160  */
161 /** \page UI User Interface Classes and Files
162  *
163  * - Inkscape::UI::View::View [\ref ui/view/view.cpp, \ref ui/view/view.h]
164  *   - Inkscape::UI::View::Edit [\ref ui/view/edit.cpp, \ref ui/view/edit.h]
165  *   - SPDesktop [\ref desktop.cpp, \ref desktop-affine.cpp, \ref desktop-events.cpp, \ref desktop-handles.cpp, \ref desktop-style.cpp, \ref desktop.h, \ref desktop-affine.h, \ref desktop-events.h, \ref desktop-handles.h, \ref desktop-style.h]
166  *   - SPSVGView [\ref svg-view.cpp, \ref svg-view.h]
167  *
168  * SPDesktopWidget [\ref desktop-widget.h] SPSVGSPViewWidget [\ref svg-view.cpp]
169  * SPDocument [\ref document.cpp, \ref document.h]
170  *
171  * SPDrawAnchor [\ref draw-anchor.cpp, \ref draw-anchor.h]
172  * SPKnot [\ref knot.cpp, \ref knot.h, \ref knot-enums.h]
173  * SPKnotHolder [\ref knotholder.cpp, \ref knotholder.h, \ref knot-holder-entity.h]
174  *
175  * [\ref layer-fns.cpp, \ref selection-describer.h]
176  * Inkscape::MessageContext [\ref message-context.h]
177  * Inkscape::MessageStack [\ref message-stack.h, \ref message.h]
178  *
179  * Snapper, GridSnapper, GuideSnapper [\ref snap.cpp, \ref snap.h]
180  *
181  * SPGuide [\ref sp-guide.cpp, \ref sp-guide.h, \ref satisfied-guide-cns.cpp, \ref sp-guide-attachment.h, \ref sp-guide-constraint.h]
182  *
183  * [\ref help.cpp] [\ref inkscape.cpp] [\ref inkscape-stock.cpp]
184  * [\ref interface.cpp, \ref memeq.h] [\ref main.cpp, \ref winmain.cpp]
185  * [\ref menus-skeleton.h, \ref preferences-skeleton.h]
186  * [\ref object-ui.cpp] [\ref select-toolbar.cpp] [\ref shortcuts.cpp]
187  * [\ref sp-cursor.cpp] [\ref text-edit.cpp] [\ref toolbox.cpp, \ref ui/widget/toolbox.cpp]
188  * Inkscape::Verb [\ref verbs.h]
189  *
190  */
191 /** \page XmlTree CSS/XML Tree Classes and Files
192  *
193  * SPStyle [\ref style.cpp, \ref style.h]
194  * Media [\ref media.cpp, \ref media.h]
195  * [\ref attributes.cpp, \ref attributes.h]
196  *
197  * - Inkscape::URIReference [\ref uri-references.cpp, \ref uri-references.h]
198  *   - SPClipPathReference [\ref sp-clippath.h]
199  *   - SPGradientReference [\ref sp-gradient-reference.h]
200  *   - SPMarkerReference [\ref sp-marker.h]
201  *   - SPMaskReference [\ref sp-mask.h]
202  *   - SPUseReference [\ref sp-use-reference.h]
203  *     - SPUsePath
204  */
205 /** \page Rendering Rendering Related Classes and Files
206  *
207  * SPColor [\ref color.cpp, \ref color.h, \ref color-rgba.h]
208  * [\ref geom.cpp] [\ref isnan.h] [\ref mod360.cpp]
209  */
210 /** \page OtherServices Classes and Files From Other Services
211  * [\ref inkview.cpp, \ref slideshow.cpp] [\ref sp-animation.cpp]
212  *
213  * Inkscape::GC
214  *
215  * [\ref sp-metrics.cpp, \ref sp-metrics.h]
216  *
217  * [\ref prefs-utils.cpp] [\ref print.cpp]
218  *
219  * - Inkscape::GZipBuffer [\ref streams-gzip.h]
220  * - Inkscape::JarBuffer [\ref streams-jar.h]
221  * - Inkscape::ZlibBuffer [\ref streams-zlib.h]
222  * - Inkscape::URIHandle [\ref streams-handles.h]
223  *   - Inkscape::FileHandle
224  * [\ref dir-util.cpp] [\ref file.cpp]
225  * Inkscape::URI [\ref uri.h, \ref extract-uri.cpp, \ref uri-references.cpp]
226  * Inkscape::BadURIException [\ref bad-uri-exception.h]
227  *
228  * Inkscape::Whiteboard::UndoStackObserver [\ref undo-stack-observer.cpp, \ref composite-undo-stack-observer.cpp]
229  * [\ref document-undo.cpp]
230  *
231  * {\ref dialogs/} [\ref approx-equal.h] [\ref decimal-round.h] [\ref enums.h] [\ref unit-constants.h]
232  */
234 #ifdef HAVE_CONFIG_H
235 # include "config.h"
236 #endif
237 #include "path-prefix.h"
239 #include <gtk/gtkmessagedialog.h>
241 #ifdef HAVE_IEEEFP_H
242 #include <ieeefp.h>
243 #endif
244 #include <string.h>
245 #include <locale.h>
247 #include <popt.h>
248 #ifndef POPT_TABLEEND
249 #define POPT_TABLEEND { NULL, '\0', 0, 0, 0, NULL, NULL }
250 #endif /* Not def: POPT_TABLEEND */
252 #include <libxml/tree.h>
253 #include <glib-object.h>
254 #include <gtk/gtkmain.h>
255 #include <gtk/gtksignal.h>
256 #include <gtk/gtkwindow.h>
257 #include <gtk/gtkbox.h>
259 #include <gtk/gtkmain.h>
261 #include "gc-core.h"
263 #include "macros.h"
264 #include "file.h"
265 #include "document.h"
266 #include "sp-object.h"
267 #include "interface.h"
268 #include "print.h"
269 #include "slideshow.h"
270 #include "color.h"
271 #include "sp-item.h"
272 #include "sp-root.h"
273 #include "unit-constants.h"
275 #include "svg/svg.h"
276 #include "svg/stringstream.h"
278 #include "inkscape-private.h"
279 #include "inkscape-stock.h"
280 #include "inkscape_version.h"
282 #include "sp-namedview.h"
283 #include "sp-guide.h"
284 #include "sp-object-repr.h"
285 #include "xml/repr.h"
287 #include "io/sys.h"
289 #include "debug/logger.h"
291 #include <extension/extension.h>
292 #include <extension/system.h>
293 #include <extension/db.h>
294 #include <extension/output.h>
296 #ifdef WIN32
297 //#define REPLACEARGS_ANSI
298 //#define REPLACEARGS_DEBUG
300 #include "registrytool.h"
302 #include "extension/internal/win32.h"
303 using Inkscape::Extension::Internal::PrintWin32;
305 #endif // WIN32
307 #include "extension/init.h"
309 #include <glibmm/i18n.h>
310 #include <gtkmm/main.h>
312 #ifndef HAVE_BIND_TEXTDOMAIN_CODESET
313 #define bind_textdomain_codeset(p,c)
314 #endif
316 #include "application/application.h"
318 enum {
319     SP_ARG_NONE,
320     SP_ARG_NOGUI,
321     SP_ARG_GUI,
322     SP_ARG_FILE,
323     SP_ARG_PRINT,
324     SP_ARG_EXPORT_PNG,
325     SP_ARG_EXPORT_DPI,
326     SP_ARG_EXPORT_AREA,
327     SP_ARG_EXPORT_AREA_DRAWING,
328     SP_ARG_EXPORT_AREA_SNAP,
329     SP_ARG_EXPORT_WIDTH,
330     SP_ARG_EXPORT_HEIGHT,
331     SP_ARG_EXPORT_ID,
332     SP_ARG_EXPORT_ID_ONLY,
333     SP_ARG_EXPORT_USE_HINTS,
334     SP_ARG_EXPORT_BACKGROUND,
335     SP_ARG_EXPORT_BACKGROUND_OPACITY,
336     SP_ARG_EXPORT_SVG,
337     SP_ARG_EXPORT_PS,
338     SP_ARG_EXPORT_EPS,
339     SP_ARG_EXPORT_TEXT_TO_PATH,
340     SP_ARG_EXPORT_BBOX_PAGE,
341     SP_ARG_EXTENSIONDIR,
342     SP_ARG_SLIDESHOW,
343     SP_ARG_QUERY_X,
344     SP_ARG_QUERY_Y,
345     SP_ARG_QUERY_WIDTH,
346     SP_ARG_QUERY_HEIGHT,
347     SP_ARG_QUERY_ID,
348     SP_ARG_VERSION,
349     SP_ARG_NEW_GUI,
350     SP_ARG_VACUUM_DEFS,
351     SP_ARG_LAST
352 };
354 int sp_main_gui(int argc, char const **argv);
355 int sp_main_console(int argc, char const **argv);
356 static void sp_do_export_png(SPDocument *doc);
357 static void do_export_ps(SPDocument* doc, gchar const* uri, char const *mime);
358 static void do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gchar *id);
361 static gchar *sp_global_printer = NULL;
362 static gboolean sp_global_slideshow = FALSE;
363 static gchar *sp_export_png = NULL;
364 static gchar *sp_export_dpi = NULL;
365 static gchar *sp_export_area = NULL;
366 static gboolean sp_export_area_drawing = FALSE;
367 static gchar *sp_export_width = NULL;
368 static gchar *sp_export_height = NULL;
369 static gchar *sp_export_id = NULL;
370 static gchar *sp_export_background = NULL;
371 static gchar *sp_export_background_opacity = NULL;
372 static gboolean sp_export_area_snap = FALSE;
373 static gboolean sp_export_use_hints = FALSE;
374 static gboolean sp_export_id_only = FALSE;
375 static gchar *sp_export_svg = NULL;
376 static gchar *sp_export_ps = NULL;
377 static gchar *sp_export_eps = NULL;
378 static gboolean sp_export_text_to_path = FALSE;
379 static gboolean sp_export_bbox_page = FALSE;
380 static gboolean sp_query_x = FALSE;
381 static gboolean sp_query_y = FALSE;
382 static gboolean sp_query_width = FALSE;
383 static gboolean sp_query_height = FALSE;
384 static gchar *sp_query_id = NULL;
385 static int sp_new_gui = FALSE;
386 static gboolean sp_vacuum_defs = FALSE;
388 static gchar *sp_export_png_utf8 = NULL;
389 static gchar *sp_export_svg_utf8 = NULL;
390 static gchar *sp_global_printer_utf8 = NULL;
392 #ifdef WIN32
393 static bool replaceArgs( int& argc, char**& argv );
394 #endif
395 static GSList *sp_process_args(poptContext ctx);
396 struct poptOption options[] = {
397     {"version", 'V',
398      POPT_ARG_NONE, NULL, SP_ARG_VERSION,
399      N_("Print the Inkscape version number"),
400      NULL},
402     {"without-gui", 'z',
403      POPT_ARG_NONE, NULL, SP_ARG_NOGUI,
404      N_("Do not use X server (only process files from console)"),
405      NULL},
407     {"with-gui", 'g',
408      POPT_ARG_NONE, NULL, SP_ARG_GUI,
409      N_("Try to use X server (even if $DISPLAY is not set)"),
410      NULL},
412     {"file", 'f',
413      POPT_ARG_STRING, NULL, SP_ARG_FILE,
414      N_("Open specified document(s) (option string may be excluded)"),
415      N_("FILENAME")},
417     {"print", 'p',
418      POPT_ARG_STRING, &sp_global_printer, SP_ARG_PRINT,
419      N_("Print document(s) to specified output file (use '| program' for pipe)"),
420      N_("FILENAME")},
422     {"export-png", 'e',
423      POPT_ARG_STRING, &sp_export_png, SP_ARG_EXPORT_PNG,
424      N_("Export document to a PNG file"),
425      N_("FILENAME")},
427     {"export-dpi", 'd',
428      POPT_ARG_STRING, &sp_export_dpi, SP_ARG_EXPORT_DPI,
429      N_("The resolution used for exporting SVG into bitmap (default 90)"),
430      N_("DPI")},
432     {"export-area", 'a',
433      POPT_ARG_STRING, &sp_export_area, SP_ARG_EXPORT_AREA,
434      N_("Exported area in SVG user units (default is the canvas; 0,0 is lower-left corner)"),
435      N_("x0:y0:x1:y1")},
437     {"export-area-drawing", 'D',
438      POPT_ARG_NONE, &sp_export_area_drawing, SP_ARG_EXPORT_AREA_DRAWING,
439      N_("Exported area is the entire drawing (not canvas)"),
440      NULL},
442     {"export-area-snap", 0,
443      POPT_ARG_NONE, &sp_export_area_snap, SP_ARG_EXPORT_AREA_SNAP,
444      N_("Snap the bitmap export area outwards to the nearest integer values (in SVG user units)"),
445      NULL},
447     {"export-width", 'w',
448      POPT_ARG_STRING, &sp_export_width, SP_ARG_EXPORT_WIDTH,
449      N_("The width of exported bitmap in pixels (overrides export-dpi)"),
450      N_("WIDTH")},
452     {"export-height", 'h',
453      POPT_ARG_STRING, &sp_export_height, SP_ARG_EXPORT_HEIGHT,
454      N_("The height of exported bitmap in pixels (overrides export-dpi)"),
455      N_("HEIGHT")},
457     {"export-id", 'i',
458      POPT_ARG_STRING, &sp_export_id, SP_ARG_EXPORT_ID,
459      N_("The ID of the object to export (overrides export-area)"),
460      N_("ID")},
462     {"export-id-only", 'j',
463      POPT_ARG_NONE, &sp_export_id_only, SP_ARG_EXPORT_ID_ONLY,
464      // TRANSLATORS: this means: "Only export the object whose id is given in --export-id".
465      //  See "man inkscape" for details.
466      N_("Export just the object with export-id, hide all others (only with export-id)"),
467      NULL},
469     {"export-use-hints", 't',
470      POPT_ARG_NONE, &sp_export_use_hints, SP_ARG_EXPORT_USE_HINTS,
471      N_("Use stored filename and DPI hints when exporting (only with export-id)"),
472      NULL},
474     {"export-background", 'b',
475      POPT_ARG_STRING, &sp_export_background, SP_ARG_EXPORT_BACKGROUND,
476      N_("Background color of exported bitmap (any SVG-supported color string)"),
477      N_("COLOR")},
479     {"export-background-opacity", 'y',
480      POPT_ARG_STRING, &sp_export_background_opacity, SP_ARG_EXPORT_BACKGROUND_OPACITY,
481      N_("Background opacity of exported bitmap (either 0.0 to 1.0, or 1 to 255)"),
482      N_("VALUE")},
484     {"export-plain-svg", 'l',
485      POPT_ARG_STRING, &sp_export_svg, SP_ARG_EXPORT_SVG,
486      N_("Export document to plain SVG file (no sodipodi or inkscape namespaces)"),
487      N_("FILENAME")},
489     {"export-ps", 'P',
490      POPT_ARG_STRING, &sp_export_ps, SP_ARG_EXPORT_PS,
491      N_("Export document to a PS file"),
492      N_("FILENAME")},
494     {"export-eps", 'E',
495      POPT_ARG_STRING, &sp_export_eps, SP_ARG_EXPORT_EPS,
496      N_("Export document to an EPS file"),
497      N_("FILENAME")},
499     {"export-text-to-path", 'T',
500      POPT_ARG_NONE, &sp_export_text_to_path, SP_ARG_EXPORT_TEXT_TO_PATH,
501      N_("Convert text object to paths on export (EPS)"),
502      NULL},
504     {"export-bbox-page", 'B',
505      POPT_ARG_NONE, &sp_export_bbox_page, SP_ARG_EXPORT_BBOX_PAGE,
506      N_("Export files with the bounding box set to the page size (EPS)"),
507      NULL},
509     {"query-x", 'X',
510      POPT_ARG_NONE, &sp_query_x, SP_ARG_QUERY_X,
511      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
512      N_("Query the X coordinate of the drawing or, if specified, of the object with --query-id"),
513      NULL},
515     {"query-y", 'Y',
516      POPT_ARG_NONE, &sp_query_y, SP_ARG_QUERY_Y,
517      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
518      N_("Query the Y coordinate of the drawing or, if specified, of the object with --query-id"),
519      NULL},
521     {"query-width", 'W',
522      POPT_ARG_NONE, &sp_query_width, SP_ARG_QUERY_WIDTH,
523      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
524      N_("Query the width of the drawing or, if specified, of the object with --query-id"),
525      NULL},
527     {"query-height", 'H',
528      POPT_ARG_NONE, &sp_query_height, SP_ARG_QUERY_HEIGHT,
529      // TRANSLATORS: "--query-id" is an Inkscape command line option; see "inkscape --help"
530      N_("Query the height of the drawing or, if specified, of the object with --query-id"),
531      NULL},
533     {"query-id", 'I',
534      POPT_ARG_STRING, &sp_query_id, SP_ARG_QUERY_ID,
535      N_("The ID of the object whose dimensions are queried"),
536      N_("ID")},
538     {"extension-directory", 'x',
539      POPT_ARG_NONE, NULL, SP_ARG_EXTENSIONDIR,
540      // TRANSLATORS: this option makes Inkscape print the name (path) of the extension directory
541      N_("Print out the extension directory and exit"),
542      NULL},
544     {"slideshow", 's',
545      POPT_ARG_NONE, &sp_global_slideshow, SP_ARG_SLIDESHOW,
546      N_("Show given files one-by-one, switch to next on any key/mouse event"),
547      NULL},
549     {"new-gui", 'G',
550      POPT_ARG_NONE, &sp_new_gui, SP_ARG_NEW_GUI,
551      N_("Use the new Gtkmm GUI interface"),
552      NULL},
554     {"vacuum-defs", 0,
555      POPT_ARG_NONE, &sp_vacuum_defs, SP_ARG_VACUUM_DEFS,
556      N_("Remove unused definitions from the defs section(s) of the document"),
557      NULL},
559     POPT_AUTOHELP POPT_TABLEEND
560 };
562 static bool needToRecodeParams = true;
563 gchar* blankParam = "";
565 int
566 main(int argc, char **argv)
568 #ifdef HAVE_FPSETMASK
569     /* This is inherited from Sodipodi code, where it was in #ifdef __FreeBSD__.  It's probably
570        safe to remove: the default mask is already 0 in C99, and in current FreeBSD according to
571        the fenv man page on www.freebsd.org, and in glibc according to (libc)FP Exceptions. */
572     fpsetmask(fpgetmask() & ~(FP_X_DZ | FP_X_INV));
573 #endif
575 #ifdef ENABLE_NLS
576 #ifdef WIN32
577     RegistryTool rt;
578     rt.setPathInfo();
579     gchar *pathBuf = g_strconcat(g_path_get_dirname(argv[0]), "\\", PACKAGE_LOCALE_DIR, NULL);
580     bindtextdomain(GETTEXT_PACKAGE, pathBuf);
581     g_free(pathBuf);
582 #else
583 #ifdef ENABLE_BINRELOC
584     bindtextdomain(GETTEXT_PACKAGE, BR_LOCALEDIR(""));
585 #else
586     bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
587 #endif
588 #endif
589 #endif
591     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
593 #ifdef ENABLE_NLS
594     textdomain(GETTEXT_PACKAGE);
595 #endif
597     LIBXML_TEST_VERSION
599     Inkscape::GC::init();
601     Inkscape::Debug::Logger::init();
603     gboolean use_gui;
604 #ifndef WIN32
605     use_gui = (getenv("DISPLAY") != NULL);
606 #else
607     /*
608       Set the current directory to the directory of the
609       executable.  This seems redundant, but is needed for
610       when inkscape.exe is executed from another directory.
611       We use relative paths on win32.
612       HKCR\svgfile\shell\open\command is a good example
613     */
614     /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
615     char *homedir = g_path_get_dirname(argv[0]);
616     SetCurrentDirectory(homedir);
617     g_free(homedir);
619     use_gui = TRUE;
620 #endif
621     /* Test whether with/without GUI is forced */
622     for (int i = 1; i < argc; i++) {
623         if (!strcmp(argv[i], "-z")
624             || !strcmp(argv[i], "--without-gui")
625             || !strcmp(argv[i], "-p")
626             || !strncmp(argv[i], "--print", 7)
627             || !strcmp(argv[i], "-e")
628             || !strncmp(argv[i], "--export-png", 12)
629             || !strcmp(argv[i], "-l")
630             || !strncmp(argv[i], "--export-plain-svg", 12)
631             || !strcmp(argv[i], "-i")
632             || !strncmp(argv[i], "--export-area-drawing", 21)
633             || !strcmp(argv[i], "-D")
634             || !strncmp(argv[i], "--export-id", 12)
635             || !strcmp(argv[i], "-P")
636             || !strncmp(argv[i], "--export-ps", 11)
637             || !strcmp(argv[i], "-E")
638             || !strncmp(argv[i], "--export-eps", 12)
639             || !strcmp(argv[i], "-W")
640             || !strncmp(argv[i], "--query-width", 13)
641             || !strcmp(argv[i], "-H")
642             || !strncmp(argv[i], "--query-height", 14)
643             || !strcmp(argv[i], "-X")
644             || !strncmp(argv[i], "--query-x", 13)
645             || !strcmp(argv[i], "-Y")
646             || !strncmp(argv[i], "--query-y", 14)
647             || !strcmp(argv[i], "--vacuum-defs")
648            )
649         {
650             /* main_console handles any exports -- not the gui */
651             use_gui = FALSE;
652             break;
653         } else if (!strcmp(argv[i], "-g") || !strcmp(argv[i], "--with-gui")) {
654             use_gui = TRUE;
655             break;
656         } else if (!strcmp(argv[i], "-G") || !strcmp(argv[i], "--new-gui")) {
657             sp_new_gui = TRUE;
658             break;
659         }
660     }
662 #ifdef WIN32
663 #ifndef REPLACEARGS_ANSI
664     if ( PrintWin32::is_os_wide() )
665 #endif // REPLACEARGS_ANSI
666     {
667         // If the call fails, we'll need to convert charsets
668         needToRecodeParams = !replaceArgs( argc, argv );
669     }
670 #endif // WIN32
672     /// \todo  Should this be a static object (see inkscape.cpp)?
673     Inkscape::NSApplication::Application app(argc, argv, use_gui, sp_new_gui);
675     return app.run();
678 void fixupSingleFilename( gchar **orig, gchar **spare )
680     if ( orig && *orig && **orig ) {
681         GError *error = NULL;
682         gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(*orig, -1, NULL, NULL, &error);
683         if ( newFileName )
684         {
685             *orig = newFileName;
686             if ( spare ) {
687                 *spare = newFileName;
688             }
689 //             g_message("Set a replacement fixup");
690         }
691     }
694 GSList *fixupFilenameEncoding( GSList* fl )
696     GSList *newFl = NULL;
697     while ( fl ) {
698         gchar *fn = static_cast<gchar*>(fl->data);
699         fl = g_slist_remove( fl, fl->data );
700         gchar *newFileName = Inkscape::IO::locale_to_utf8_fallback(fn, -1, NULL, NULL, NULL);
701         if ( newFileName ) {
703             if ( 0 )
704             {
705                 gchar *safeFn = Inkscape::IO::sanitizeString(fn);
706                 gchar *safeNewFn = Inkscape::IO::sanitizeString(newFileName);
707                 GtkWidget *w = gtk_message_dialog_new( NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
708                                                        "Note: Converted '%s' to '%s'", safeFn, safeNewFn );
709                 gtk_dialog_run (GTK_DIALOG (w));
710                 gtk_widget_destroy (w);
711                 g_free(safeNewFn);
712                 g_free(safeFn);
713             }
715             g_free( fn );
716             fn = newFileName;
717             newFileName = 0;
718         }
719         else
720             if ( 0 )
721         {
722             gchar *safeFn = Inkscape::IO::sanitizeString(fn);
723             GtkWidget *w = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "Error: Unable to convert '%s'", safeFn );
724             gtk_dialog_run (GTK_DIALOG (w));
725             gtk_widget_destroy (w);
726             g_free(safeFn);
727         }
728         newFl = g_slist_append( newFl, fn );
729     }
730     return newFl;
733 int sp_common_main( int argc, char const **argv, GSList **flDest )
735     /// \todo fixme: Move these to some centralized location (Lauris)
736     sp_object_type_register("sodipodi:namedview", SP_TYPE_NAMEDVIEW);
737     sp_object_type_register("sodipodi:guide", SP_TYPE_GUIDE);
740     // temporarily switch gettext encoding to locale, so that help messages can be output properly
741     gchar const *charset;
742     g_get_charset(&charset);
744     bind_textdomain_codeset(GETTEXT_PACKAGE, charset);
746     poptContext ctx = poptGetContext(NULL, argc, argv, options, 0);
747     poptSetOtherOptionHelp(ctx, _("[OPTIONS...] [FILE...]\n\nAvailable options:"));
748     g_return_val_if_fail(ctx != NULL, 1);
750     /* Collect own arguments */
751     GSList *fl = sp_process_args(ctx);
752     poptFreeContext(ctx);
754     // now switch gettext back to UTF-8 (for GUI)
755     bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
757     // Now let's see if the file list still holds up
758     if ( needToRecodeParams )
759     {
760         fl = fixupFilenameEncoding( fl );
761     }
763     // Check the globals for filename-fixup
764     if ( needToRecodeParams )
765     {
766         fixupSingleFilename( &sp_export_png, &sp_export_png_utf8 );
767         fixupSingleFilename( &sp_export_svg, &sp_export_svg_utf8 );
768         fixupSingleFilename( &sp_global_printer, &sp_global_printer_utf8 );
769     }
770     else
771     {
772         if ( sp_export_png )
773             sp_export_png_utf8 = g_strdup( sp_export_png );
774         if ( sp_export_svg )
775             sp_export_svg_utf8 = g_strdup( sp_export_svg );
776         if ( sp_global_printer )
777             sp_global_printer_utf8 = g_strdup( sp_global_printer );
778     }
780     // Return the list if wanted, else free it up.
781     if ( flDest ) {
782         *flDest = fl;
783         fl = 0;
784     } else {
785         while ( fl ) {
786             g_free( fl->data );
787             fl = g_slist_remove( fl, fl->data );
788         }
789     }
790     return 0;
793 int
794 sp_main_gui(int argc, char const **argv)
796     Gtk::Main main_instance (&argc, const_cast<char ***>(&argv));
798     GSList *fl = NULL;
799     int retVal = sp_common_main( argc, argv, &fl );
800     g_return_val_if_fail(retVal == 0, 1);
802     inkscape_gtk_stock_init();
804     /* Set default icon */
805     gchar *filename = (gchar *) g_build_filename (INKSCAPE_APPICONDIR, "inkscape.png", NULL);
806     if (Inkscape::IO::file_test(filename, (GFileTest)(G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_SYMLINK))) {
807         gtk_window_set_default_icon_from_file(filename, NULL);
808     }
809     g_free (filename);
810     filename = 0;
812     if (!sp_global_slideshow) {
813         gboolean create_new = TRUE;
815         /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
816         inkscape_application_init(argv[0], true);
818         while (fl) {
819             if (sp_file_open((gchar *)fl->data,NULL)) {
820                 create_new=FALSE;
821             }
822             fl = g_slist_remove(fl, fl->data);
823         }
824         if (create_new) {
825             sp_file_new_default();
826         }
827     } else {
828         if (fl) {
829             GtkWidget *ss;
830             /// \todo FIXME BROKEN - non-UTF-8 sneaks in here.
831             inkscape_application_init(argv[0], true);
832             ss = sp_slideshow_new(fl);
833             if (ss) gtk_widget_show(ss);
834         } else {
835             g_warning ("No slides to display");
836             exit(0);
837         }
838     }
840     main_instance.run();
842 #ifdef WIN32
843     //We might not need anything here
844     //sp_win32_finish(); <-- this is a NOP func
845 #endif
847     return 0;
850 int
851 sp_main_console(int argc, char const **argv)
853     /* We are started in text mode */
855     /* Do this g_type_init(), so that we can use Xft/Freetype2 (Pango)
856      * in a non-Gtk environment.  Used in libnrtype's
857      * FontInstance.cpp and FontFactory.cpp.
858      * http://mail.gnome.org/archives/gtk-list/2003-December/msg00063.html
859      */
860     g_type_init();
861     char **argv2 = const_cast<char **>(argv);
862     gtk_init_check( &argc, &argv2 );
863     //setlocale(LC_ALL, "");
865     GSList *fl = NULL;
866     int retVal = sp_common_main( argc, argv, &fl );
867     g_return_val_if_fail(retVal == 0, 1);
869     if (fl == NULL) {
870         g_print("Nothing to do!\n");
871         exit(0);
872     }
874     inkscape_application_init(argv[0], false);
876     while (fl) {
877         SPDocument *doc;
879         doc = Inkscape::Extension::open(NULL, (gchar *)fl->data);
880         if (doc == NULL) {
881             doc = Inkscape::Extension::open(Inkscape::Extension::db.get(SP_MODULE_KEY_INPUT_SVG), (gchar *)fl->data);
882         }
883         if (doc == NULL) {
884             g_warning("Specified document %s cannot be opened (is it valid SVG file?)", (gchar *) fl->data);
885         } else {
886             if (sp_vacuum_defs) {
887                 vacuum_document(doc);
888             }
889             if (sp_vacuum_defs && !sp_export_svg) {
890                 // save under the name given in the command line
891                 sp_repr_save_file(doc->rdoc, (gchar *)fl->data, SP_SVG_NS_URI);
892             }
893             if (sp_global_printer) {
894                 sp_print_document_to_file(doc, sp_global_printer);
895             }
896             if (sp_export_png || sp_export_id || sp_export_area_drawing) {
897                 sp_do_export_png(doc);
898             }
899             if (sp_export_svg) {
900                 Inkscape::XML::Document *rdoc;
901                 Inkscape::XML::Node *repr;
902                 rdoc = sp_repr_document_new("svg:svg");
903                 repr = rdoc->root();
904                 repr = sp_document_root(doc)->updateRepr(repr, SP_OBJECT_WRITE_BUILD);
905                 sp_repr_save_file(repr->document(), sp_export_svg, SP_SVG_NS_URI);
906             }
907             if (sp_export_ps) {
908                 do_export_ps(doc, sp_export_ps, "image/x-postscript");
909             }
910             if (sp_export_eps) {
911                 do_export_ps(doc, sp_export_eps, "image/x-e-postscript");
912             }
913             if (sp_query_width || sp_query_height) {
914                 do_query_dimension (doc, true, sp_query_width? NR::X : NR::Y, sp_query_id);
915             } else if (sp_query_x || sp_query_y) {
916                 do_query_dimension (doc, false, sp_query_x? NR::X : NR::Y, sp_query_id);
917             }
918         }
919         fl = g_slist_remove(fl, fl->data);
920     }
922     inkscape_unref();
924     return 0;
927 static void
928 do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gchar *id)
930     SPObject *o = NULL;
932     if (id) {
933         o = doc->getObjectById(id);
934         if (o) {
935             if (!SP_IS_ITEM (o)) {
936                 g_warning("Object with id=\"%s\" is not a visible item. Cannot query dimensions.", id);
937                 return;
938             }
939         } else {
940             g_warning("Object with id=\"%s\" is not found. Cannot query dimensions.", id);
941             return;
942         }
943     } else {
944         o = SP_DOCUMENT_ROOT(doc);
945     }
947     if (o) {
948         sp_document_ensure_up_to_date (doc);
949         NR::Rect area = sp_item_bbox_desktop((SPItem *) o);
951         Inkscape::SVGOStringStream os;
952         if (extent) {
953             os << area.extent(axis);
954         } else {
955             os << area.min()[axis];
956         }
957         g_print ("%s\n", os.str().c_str());
958     }
962 static void
963 sp_do_export_png(SPDocument *doc)
965     const gchar *filename = NULL;
966     gdouble dpi = 0.0;
968     if (sp_export_use_hints && (!sp_export_id && !sp_export_area_drawing)) {
969         g_warning ("--export-use-hints can only be used with --export-id or --export-area-drawing; ignored.");
970     }
972     GSList *items = NULL;
974     NRRect area;
975     if (sp_export_id || sp_export_area_drawing) {
977         SPObject *o = NULL;
978         if (sp_export_id) {
979             o = doc->getObjectById(sp_export_id);
980         } else if (sp_export_area_drawing) {
981             o = SP_DOCUMENT_ROOT (doc);
982         }
984         if (o) {
985             if (!SP_IS_ITEM (o)) {
986                 g_warning("Object with id=\"%s\" is not a visible item. Nothing exported.", sp_export_id);
987                 return;
988             }
989             if (sp_export_area) {
990                 g_warning ("Object with id=\"%s\" is being exported; --export-area is ignored.", sp_export_id);
991             }
993             items = g_slist_prepend (items, SP_ITEM(o));
995             if (sp_export_id_only) {
996                 g_print("Exporting only object with id=\"%s\"; all other objects hidden\n", sp_export_id);
997             }
999             if (sp_export_use_hints) {
1001                 // retrieve export filename hint
1002                 const gchar *fn_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-filename");
1003                 if (fn_hint) {
1004                     if (sp_export_png) {
1005                         g_warning ("Using export filename from the command line (--export-png). Filename hint %s is ignored.", fn_hint);
1006                         filename = sp_export_png;
1007                     } else {
1008                         filename = fn_hint;
1009                     }
1010                 } else {
1011                     g_warning ("Export filename hint not found for the object.");
1012                     filename = sp_export_png;
1013                 }
1015                 // retrieve export dpi hints
1016                 const gchar *dpi_hint = SP_OBJECT_REPR(o)->attribute("inkscape:export-xdpi"); // only xdpi, ydpi is always the same now
1017                 if (dpi_hint) {
1018                     if (sp_export_dpi || sp_export_width || sp_export_height) {
1019                         g_warning ("Using bitmap dimensions from the command line (--export-dpi, --export-width, or --export-height). DPI hint %s is ignored.", dpi_hint);
1020                     } else {
1021                         dpi = atof(dpi_hint);
1022                     }
1023                 } else {
1024                     g_warning ("Export DPI hint not found for the object.");
1025                 }
1027             }
1029             // write object bbox to area
1030             sp_document_ensure_up_to_date (doc);
1031             sp_item_invoke_bbox((SPItem *) o, &area, sp_item_i2r_affine((SPItem *) o), TRUE);
1032         } else {
1033             g_warning("Object with id=\"%s\" was not found in the document. Nothing exported.", sp_export_id);
1034             return;
1035         }
1036     } else if (sp_export_area) {
1037         /* Try to parse area (given in SVG pixels) */
1038         if (!sscanf(sp_export_area, "%lg:%lg:%lg:%lg", &area.x0, &area.y0, &area.x1, &area.y1) == 4) {
1039             g_warning("Cannot parse export area '%s'; use 'x0:y0:x1:y1'. Nothing exported.", sp_export_area);
1040             return;
1041         }
1042         if ((area.x0 >= area.x1) || (area.y0 >= area.y1)) {
1043             g_warning("Export area '%s' has negative width or height. Nothing exported.", sp_export_area);
1044             return;
1045         }
1046     } else {
1047         /* Export the whole canvas */
1048         sp_document_ensure_up_to_date (doc);
1049         area.x0 = SP_ROOT(doc->root)->x.computed;
1050         area.y0 = SP_ROOT(doc->root)->y.computed;
1051         area.x1 = area.x0 + sp_document_width (doc);
1052         area.y1 = area.y0 + sp_document_height (doc);
1053     }
1055     // set filename and dpi from options, if not yet set from the hints
1056     if (!filename) {
1057         if (!sp_export_png) {
1058             g_warning ("No export filename given and no filename hint. Nothing exported.");
1059             return;
1060         }
1061         filename = sp_export_png;
1062     }
1064     if (sp_export_dpi && dpi == 0.0) {
1065         dpi = atof(sp_export_dpi);
1066         if ((dpi < 0.1) || (dpi > 10000.0)) {
1067             g_warning("DPI value %s out of range [0.1 - 10000.0]. Nothing exported.", sp_export_dpi);
1068             return;
1069         }
1070         g_print("DPI: %g\n", dpi);
1071     }
1073     if (sp_export_area_snap) {
1074         area.x0 = std::floor (area.x0);
1075         area.y0 = std::floor (area.y0);
1076         area.x1 = std::ceil (area.x1);
1077         area.y1 = std::ceil (area.y1);
1078     }
1080     // default dpi
1081     if (dpi == 0.0)
1082         dpi = PX_PER_IN;
1084     gint width = 0;
1085     gint height = 0;
1087     if (sp_export_width) {
1088         width = atoi(sp_export_width);
1089         if ((width < 1) || (width > 65536)) {
1090             g_warning("Export width %d out of range (1 - 65536). Nothing exported.", width);
1091             return;
1092         }
1093         dpi = (gdouble) width * PX_PER_IN / (area.x1 - area.x0);
1094     }
1096     if (sp_export_height) {
1097         height = atoi(sp_export_height);
1098         if ((height < 1) || (height > 65536)) {
1099             g_warning("Export height %d out of range (1 - 65536). Nothing exported.", width);
1100             return;
1101         }
1102         dpi = (gdouble) height * PX_PER_IN / (area.y1 - area.y0);
1103     }
1105     if (!sp_export_width) {
1106         width = (gint) ((area.x1 - area.x0) * dpi / PX_PER_IN + 0.5);
1107     }
1109     if (!sp_export_height) {
1110         height = (gint) ((area.y1 - area.y0) * dpi / PX_PER_IN + 0.5);
1111     }
1113     guint32 bgcolor = 0x00000000;
1114     if (sp_export_background) {
1115         // override the page color
1116         bgcolor = sp_svg_read_color(sp_export_background, 0xffffff00);
1117         bgcolor |= 0xff; // default is no opacity
1118     } else {
1119         // read from namedview
1120         Inkscape::XML::Node *nv = sp_repr_lookup_name (doc->rroot, "sodipodi:namedview");
1121         if (nv && nv->attribute("pagecolor"))
1122             bgcolor = sp_svg_read_color(nv->attribute("pagecolor"), 0xffffff00);
1123         if (nv && nv->attribute("inkscape:pageopacity"))
1124             bgcolor |= SP_COLOR_F_TO_U(sp_repr_get_double_attribute (nv, "inkscape:pageopacity", 1.0));
1125     }
1127     if (sp_export_background_opacity) {
1128         // override opacity
1129         gfloat value;
1130         if (sp_svg_number_read_f (sp_export_background_opacity, &value)) {
1131             if (value > 1.0) {
1132                 value = CLAMP (value, 1.0f, 255.0f);
1133                 bgcolor &= (guint32) 0xffffff00;
1134                 bgcolor |= (guint32) floor(value);
1135             } else {
1136                 value = CLAMP (value, 0.0f, 1.0f);
1137                 bgcolor &= (guint32) 0xffffff00;
1138                 bgcolor |= SP_COLOR_F_TO_U(value);
1139             }
1140         }
1141     }
1143     g_print("Background RRGGBBAA: %08x\n", bgcolor);
1145     g_print("Area %g:%g:%g:%g exported to %d x %d pixels (%g dpi)\n", area.x0, area.y0, area.x1, area.y1, width, height, dpi);
1147     g_print("Bitmap saved as: %s\n", filename);
1149     if ((width >= 1) && (height >= 1) && (width < 65536) && (height < 65536)) {
1150         sp_export_png_file(doc, filename, area.x0, area.y0, area.x1, area.y1, width, height, bgcolor, NULL, NULL, true, sp_export_id_only ? items : NULL);
1151     } else {
1152         g_warning("Calculated bitmap dimensions %d %d are out of range (1 - 65535). Nothing exported.", width, height);
1153     }
1155     g_slist_free (items);
1159 /**
1160  *  Perform an export of either PS or EPS.
1161  *
1162  *  \param doc Document to export.
1163  *  \param uri URI to export to.
1164  *  \param mime MIME type to export as.
1165  */
1167 static void do_export_ps(SPDocument* doc, gchar const* uri, char const* mime)
1169     /** \todo
1170      * FIXME: I've no idea if this is the `proper' way to do this.
1171      * If anyone feels qualified to say that it is, perhaps they
1172      * could remove this comment.
1173      */
1175     Inkscape::Extension::DB::OutputList o;
1176     Inkscape::Extension::db.get_output_list(o);
1177     Inkscape::Extension::DB::OutputList::const_iterator i = o.begin();
1178     while (i != o.end() && strcmp( (*i)->get_mimetype(), mime ) != 0) {
1179         i++;
1180     }
1182     if (i == o.end())
1183     {
1184         g_warning ("Could not find an extension to export this file.");
1185         return;
1186     }
1188     bool old_text_to_path = false;
1189     bool old_bbox_page = false;
1191     try {
1192         old_text_to_path = (*i)->get_param_bool("textToPath");
1193         (*i)->set_param_bool("textToPath", sp_export_text_to_path);
1194     }
1195     catch (...) {
1196         g_warning ("Could not set export-text-to-path option for this export.");
1197     }
1199     try {
1200         old_bbox_page = (*i)->get_param_bool("pageBoundingBox");
1201         (*i)->set_param_bool("pageBoundingBox", sp_export_bbox_page);
1202     }
1203     catch (...) {
1204         g_warning ("Could not set export-bbox-page option for this export.");
1205     }
1207     (*i)->save(doc, uri);
1209     try {
1210         (*i)->set_param_bool("textToPath", old_text_to_path);
1211         (*i)->set_param_bool("pageBoundingBox", old_bbox_page);
1212     }
1213     catch (...) {
1215     }
1218 #ifdef WIN32
1219 bool replaceArgs( int& argc, char**& argv )
1221     bool worked = false;
1223 #ifdef REPLACEARGS_DEBUG
1224     MessageBoxA( NULL, "GetCommandLineW() getting called", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1225 #endif // REPLACEARGS_DEBUG
1227     wchar_t* line = GetCommandLineW();
1228     if ( line )
1229     {
1230 #ifdef REPLACEARGS_DEBUG
1231         {
1232             gchar* utf8Line = g_utf16_to_utf8( (gunichar2*)line, -1, NULL, NULL, NULL );
1233             if ( utf8Line )
1234             {
1235                 gchar *safe = Inkscape::IO::sanitizeString(utf8Line);
1236                 {
1237                     char tmp[strlen(safe) + 32];
1238                     snprintf( tmp, sizeof(tmp), "GetCommandLineW() = '%s'", safe );
1239                     MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1240                 }
1241             }
1242         }
1243 #endif // REPLACEARGS_DEBUG
1245         int numArgs = 0;
1246         wchar_t** parsed = CommandLineToArgvW( line, &numArgs );
1248 #ifdef REPLACEARGS_ANSI
1249 // test code for trying things on Win95/98/ME
1250         if ( !parsed )
1251         {
1252 #ifdef REPLACEARGS_DEBUG
1253             MessageBoxA( NULL, "Unable to process command-line. Faking it", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1254 #endif // REPLACEARGS_DEBUG
1255             int lineLen = wcslen(line) + 1;
1256             wchar_t* lineDup = new wchar_t[lineLen];
1257             wcsncpy( lineDup, line, lineLen );
1259             int pos = 0;
1260             bool inQuotes = false;
1261             bool inWhitespace = true;
1262             std::vector<int> places;
1263             while ( lineDup[pos] )
1264             {
1265                 if ( inQuotes )
1266                 {
1267                     if ( lineDup[pos] == L'"' )
1268                     {
1269                         inQuotes = false;
1270                     }
1271                 }
1272                 else if ( lineDup[pos] == L'"' )
1273                 {
1274                     inQuotes = true;
1275                     inWhitespace = false;
1276                     places.push_back(pos);
1277                 }
1278                 else if ( lineDup[pos] == L' ' || lineDup[pos] == L'\t' )
1279                 {
1280                     if ( !inWhitespace )
1281                     {
1282                         inWhitespace = true;
1283                         lineDup[pos] = 0;
1284                     }
1285                 }
1286                 else if ( inWhitespace && (lineDup[pos] != L' ' && lineDup[pos] != L'\t') )
1287                 {
1288                     inWhitespace = false;
1289                     places.push_back(pos);
1290                 }
1291                 else
1292                 {
1293                     // consume
1294                 }
1295                 pos++;
1296             }
1297 #ifdef REPLACEARGS_DEBUG
1298             {
1299                 char tmp[256];
1300                 snprintf( tmp, sizeof(tmp), "Counted %d args", places.size() );
1301                 MessageBoxA( NULL, tmp, "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1302             }
1303 #endif // REPLACEARGS_DEBUG
1305             wchar_t** block = new wchar_t*[places.size()];
1306             int i = 0;
1307             for ( std::vector<int>::iterator it = places.begin(); it != places.end(); it++ )
1308             {
1309                 block[i++] = &lineDup[*it];
1310             }
1311             parsed = block;
1312             numArgs = places.size();
1313         }
1314 #endif // REPLACEARGS_ANSI
1316         if ( parsed )
1317         {
1318             std::vector<wchar_t*>expandedArgs;
1319             if ( numArgs > 0 )
1320             {
1321                 expandedArgs.push_back( parsed[0] );
1322             }
1324             for ( int i1 = 1; i1 < numArgs; i1++ )
1325             {
1326                 bool wildcarded = (wcschr(parsed[i1], L'?') != NULL) || (wcschr(parsed[i1], L'*') != NULL);
1327                 wildcarded &= parsed[i1][0] != L'"';
1328                 wildcarded &= parsed[i1][0] != L'-';
1329                 if ( wildcarded )
1330                 {
1331 #ifdef REPLACEARGS_ANSI
1332                     WIN32_FIND_DATAA data = {0};
1333 #else
1334                     WIN32_FIND_DATAW data = {0};
1335 #endif // REPLACEARGS_ANSI
1337                     int baseLen = wcslen(parsed[i1]) + 2;
1338                     wchar_t* base = new wchar_t[baseLen];
1339                     wcsncpy( base, parsed[i1], baseLen );
1340                     wchar_t* last = wcsrchr( base, L'\\' );
1341                     if ( last )
1342                     {
1343                         last[1] = 0;
1344                     }
1345                     else
1346                     {
1347                         base[0] = 0;
1348                     }
1349                     baseLen = wcslen( base );
1351 #ifdef REPLACEARGS_ANSI
1352                     char target[MAX_PATH];
1353                     if ( WideCharToMultiByte( CP_ACP, 0, parsed[i1], -1, target, sizeof(target), NULL, NULL) )
1354                     {
1355                         HANDLE hf = FindFirstFileA( target, &data );
1356 #else
1357                         HANDLE hf = FindFirstFileW( parsed[i1], &data );
1358 #endif // REPLACEARGS_ANSI
1359                         if ( hf != INVALID_HANDLE_VALUE )
1360                         {
1361                             BOOL found = TRUE;
1362                             do
1363                             {
1364 #ifdef REPLACEARGS_ANSI
1365                                 int howMany = MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, NULL, 0 );
1366                                 if ( howMany > 0 )
1367                                 {
1368                                     howMany += baseLen;
1369                                     wchar_t* tmp = new wchar_t[howMany + 1];
1370                                     wcsncpy( tmp, base, howMany + 1 );
1371                                     MultiByteToWideChar( CP_ACP, 0, data.cFileName, -1, tmp + baseLen, howMany + 1 - baseLen );
1372                                     expandedArgs.push_back( tmp );
1373                                     found = FindNextFileA( hf, &data );
1374                                 }
1375 #else
1376                                 int howMany = wcslen(data.cFileName) + baseLen;
1377                                 wchar_t* tmp = new wchar_t[howMany + 1];
1378                                 wcsncpy( tmp, base, howMany + 1 );
1379                                 wcsncat( tmp, data.cFileName, howMany + 1 );
1380                                 expandedArgs.push_back( tmp );
1381                                 found = FindNextFileW( hf, &data );
1382 #endif // REPLACEARGS_ANSI
1383                             } while ( found );
1385                             FindClose( hf );
1386                         }
1387                         else
1388                         {
1389                             expandedArgs.push_back( parsed[i1] );
1390                         }
1391 #ifdef REPLACEARGS_ANSI
1392                     }
1393 #endif // REPLACEARGS_ANSI
1395                     delete[] base;
1396                 }
1397                 else
1398                 {
1399                     expandedArgs.push_back( parsed[i1] );
1400                 }
1401             }
1403             {
1404                 wchar_t** block = new wchar_t*[expandedArgs.size()];
1405                 int iz = 0;
1406                 for ( std::vector<wchar_t*>::iterator it = expandedArgs.begin(); it != expandedArgs.end(); it++ )
1407                 {
1408                     block[iz++] = *it;
1409                 }
1410                 parsed = block;
1411                 numArgs = expandedArgs.size();
1412             }
1414             std::vector<gchar*> newArgs;
1415             for ( int i = 0; i < numArgs; i++ )
1416             {
1417                 gchar* replacement = g_utf16_to_utf8( (gunichar2*)parsed[i], -1, NULL, NULL, NULL );
1418                 if ( replacement )
1419                 {
1420 #ifdef REPLACEARGS_DEBUG
1421                     gchar *safe2 = Inkscape::IO::sanitizeString(replacement);
1423                     if ( safe2 )
1424                     {
1425                         {
1426                             char tmp[1024];
1427                             snprintf( tmp, sizeof(tmp), "    [%2d] = '%s'", i, safe2 );
1428                             MessageBoxA( NULL, tmp, "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1429                         }
1430                         g_free( safe2 );
1431                     }
1432 #endif // REPLACEARGS_DEBUG
1434                     newArgs.push_back( replacement );
1435                 }
1436                 else
1437                 {
1438                     newArgs.push_back( blankParam );
1439                 }
1440             }
1442             // Now push our munged params to be the new argv and argc
1443             {
1444                 char** block = new char*[newArgs.size()];
1445                 int iz = 0;
1446                 for ( std::vector<char*>::iterator it = newArgs.begin(); it != newArgs.end(); it++ )
1447                 {
1448                     block[iz++] = *it;
1449                 }
1450                 argv = block;
1451                 argc = newArgs.size();
1452                 worked = true;
1453             }
1454         }
1455 #ifdef REPLACEARGS_DEBUG
1456         else
1457         {
1458             MessageBoxA( NULL, "Unable to process command-line", "CommandLineToArgvW", MB_OK | MB_ICONINFORMATION );
1459         }
1460 #endif // REPLACEARGS_DEBUG
1461     }
1462 #ifdef REPLACEARGS_DEBUG
1463     else
1464     {
1465         {
1466             MessageBoxA( NULL,  "Unable to fetch result from GetCommandLineW()", "GetCommandLineW", MB_OK | MB_ICONINFORMATION );
1467         }
1469         char* line2 = GetCommandLineA();
1470         if ( line2 )
1471         {
1472             gchar *safe = Inkscape::IO::sanitizeString(line2);
1473             {
1474                 {
1475                     char tmp[strlen(safe) + 32];
1476                     snprintf( tmp, sizeof(tmp), "GetCommandLineA() = '%s'", safe );
1477                     MessageBoxA( NULL, tmp, "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1478                 }
1479             }
1480         }
1481         else
1482         {
1483             MessageBoxA( NULL, "Unable to fetch result from GetCommandLineA()", "GetCommandLineA", MB_OK | MB_ICONINFORMATION );
1484         }
1485     }
1486 #endif // REPLACEARGS_DEBUG
1488     return worked;
1490 #endif // WIN32
1492 static GSList *
1493 sp_process_args(poptContext ctx)
1495     GSList *fl = NULL;
1497     gint a;
1498     while ((a = poptGetNextOpt(ctx)) >= 0) {
1499         switch (a) {
1500             case SP_ARG_FILE: {
1501                 gchar const *fn = poptGetOptArg(ctx);
1502                 if (fn != NULL) {
1503                     fl = g_slist_append(fl, g_strdup(fn));
1504                 }
1505                 break;
1506             }
1507             case SP_ARG_VERSION: {
1508                 printf("Inkscape %s (%s)\n", INKSCAPE_VERSION, __DATE__);
1509                 exit(0);
1510                 break;
1511             }
1512             case SP_ARG_EXTENSIONDIR: {
1513                 printf("%s\n", INKSCAPE_EXTENSIONDIR);
1514                 exit(0);
1515                 break;
1516             }
1517             default: {
1518                 break;
1519             }
1520         }
1521     }
1523     gchar const ** const args = poptGetArgs(ctx);
1524     if (args != NULL) {
1525         for (unsigned i = 0; args[i] != NULL; i++) {
1526             fl = g_slist_append(fl, g_strdup(args[i]));
1527         }
1528     }
1530     return fl;
1534 /*
1535   Local Variables:
1536   mode:c++
1537   c-file-style:"stroustrup"
1538   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1539   indent-tabs-mode:nil
1540   fill-column:99
1541   End:
1542 */
1543 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :