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)
567 {
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();
676 }
678 void fixupSingleFilename( gchar **orig, gchar **spare )
679 {
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 }
692 }
694 GSList *fixupFilenameEncoding( GSList* fl )
695 {
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;
731 }
733 int sp_common_main( int argc, char const **argv, GSList **flDest )
734 {
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;
791 }
793 int
794 sp_main_gui(int argc, char const **argv)
795 {
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;
848 }
850 int
851 sp_main_console(int argc, char const **argv)
852 {
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;
925 }
927 static void
928 do_query_dimension (SPDocument *doc, bool extent, NR::Dim2 const axis, const gchar *id)
929 {
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 }
959 }
962 static void
963 sp_do_export_png(SPDocument *doc)
964 {
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);
1156 }
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)
1168 {
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 }
1216 }
1218 #ifdef WIN32
1219 bool replaceArgs( int& argc, char**& argv )
1220 {
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;
1489 }
1490 #endif // WIN32
1492 static GSList *
1493 sp_process_args(poptContext ctx)
1494 {
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;
1531 }
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 :