summaryrefslogtreecommitdiffstats
path: root/src/extension/internal
diff options
context:
space:
mode:
authorMenTaLguY <mental@rydia.net>2006-01-16 02:36:01 +0000
committermental <mental@users.sourceforge.net>2006-01-16 02:36:01 +0000
commit179fa413b047bede6e32109e2ce82437c5fb8d34 (patch)
treea5a6ac2c1708bd02288fbd8edb2ff500ff2e0916 /src/extension/internal
downloadinkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.tar.gz
inkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.zip
moving trunk for module inkscape
(bzr r1)
Diffstat (limited to 'src/extension/internal')
-rw-r--r--src/extension/internal/.cvsignore5
-rw-r--r--src/extension/internal/Makefile_insert42
-rw-r--r--src/extension/internal/bluredge.cpp157
-rw-r--r--src/extension/internal/bluredge.h43
-rw-r--r--src/extension/internal/eps-out.cpp108
-rw-r--r--src/extension/internal/eps-out.h47
-rw-r--r--src/extension/internal/gdkpixbuf-input.cpp176
-rw-r--r--src/extension/internal/gdkpixbuf-input.h31
-rw-r--r--src/extension/internal/gimpgrad.cpp233
-rw-r--r--src/extension/internal/gimpgrad.h49
-rw-r--r--src/extension/internal/gnome.cpp443
-rw-r--r--src/extension/internal/gnome.h58
-rw-r--r--src/extension/internal/grid.cpp272
-rw-r--r--src/extension/internal/grid.h43
-rw-r--r--src/extension/internal/latex-pstricks-out.cpp128
-rw-r--r--src/extension/internal/latex-pstricks-out.h49
-rw-r--r--src/extension/internal/latex-pstricks.cpp362
-rw-r--r--src/extension/internal/latex-pstricks.h70
-rw-r--r--src/extension/internal/makefile.in17
-rw-r--r--src/extension/internal/pov-out.cpp482
-rw-r--r--src/extension/internal/pov-out.h52
-rw-r--r--src/extension/internal/ps-out.cpp94
-rw-r--r--src/extension/internal/ps-out.h45
-rw-r--r--src/extension/internal/ps.cpp1264
-rw-r--r--src/extension/internal/ps.h108
-rw-r--r--src/extension/internal/svg.cpp248
-rw-r--r--src/extension/internal/svg.h48
-rw-r--r--src/extension/internal/svgz.cpp99
-rw-r--r--src/extension/internal/svgz.h41
-rw-r--r--src/extension/internal/win32.cpp499
-rw-r--r--src/extension/internal/win32.h91
31 files changed, 5404 insertions, 0 deletions
diff --git a/src/extension/internal/.cvsignore b/src/extension/internal/.cvsignore
new file mode 100644
index 000000000..e8014d011
--- /dev/null
+++ b/src/extension/internal/.cvsignore
@@ -0,0 +1,5 @@
+Makefile
+Makefile.in
+.deps
+makefile
+.dirstamp
diff --git a/src/extension/internal/Makefile_insert b/src/extension/internal/Makefile_insert
new file mode 100644
index 000000000..c6c7aefe2
--- /dev/null
+++ b/src/extension/internal/Makefile_insert
@@ -0,0 +1,42 @@
+## Makefile.am fragment sourced by src/Makefile.am.
+
+extension/internal/all: extension/internal/libinternal.a
+
+extension/internal/clean:
+ rm -f extension/internal/libinternal.a $(extension_internal_libinternal_OBJECTS)
+
+if USE_GNOME_PRINT
+extension_internal_gnome_print_sources = \
+ extension/internal/gnome.cpp \
+ extension/internal/gnome.h
+endif
+
+extension_internal_libinternal_a_SOURCES = \
+ extension/internal/bluredge.h \
+ extension/internal/bluredge.cpp \
+ extension/internal/grid.h \
+ extension/internal/grid.cpp \
+\
+ extension/internal/gimpgrad.h \
+ extension/internal/gimpgrad.cpp \
+ extension/internal/svg.h \
+ extension/internal/svg.cpp \
+ extension/internal/svgz.h \
+ extension/internal/svgz.cpp \
+ extension/internal/ps.h \
+ extension/internal/ps.cpp \
+ extension/internal/ps-out.h \
+ extension/internal/ps-out.cpp \
+ extension/internal/eps-out.h \
+ extension/internal/eps-out.cpp \
+ extension/internal/gdkpixbuf-input.h \
+ extension/internal/gdkpixbuf-input.cpp \
+ extension/internal/pov-out.cpp \
+ extension/internal/pov-out.h \
+ extension/internal/latex-pstricks.cpp \
+ extension/internal/latex-pstricks.h \
+ extension/internal/latex-pstricks-out.cpp \
+ extension/internal/latex-pstricks-out.h \
+\
+ $(extension_internal_gnome_print_sources)
+
diff --git a/src/extension/internal/bluredge.cpp b/src/extension/internal/bluredge.cpp
new file mode 100644
index 000000000..3f230439a
--- /dev/null
+++ b/src/extension/internal/bluredge.cpp
@@ -0,0 +1,157 @@
+/**
+ \file bluredge.cpp
+
+ A plug-in to add an effect to blur the edges of an object.
+*/
+/*
+ * Authors:
+ * Ted Gould <ted@gould.cx>
+ *
+ * Copyright (C) 2005 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "desktop.h"
+#include "selection.h"
+#include "helper/action.h"
+#include "prefs-utils.h"
+#include "path-chemistry.h"
+#include "sp-item.h"
+
+#include "util/glib-list-iterators.h"
+
+#include "extension/effect.h"
+#include "extension/system.h"
+
+
+#include "bluredge.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+
+/**
+ \brief A function to allocated anything -- just an example here
+ \param module Unused
+ \return Whether the load was sucessful
+*/
+bool
+BlurEdge::load (Inkscape::Extension::Extension *module)
+{
+ // std::cout << "Hey, I'm Blur Edge, I'm loading!" << std::endl;
+ return TRUE;
+}
+
+/**
+ \brief This actually blurs the edge.
+ \param module The effect that was called (unused)
+ \param document What should be edited.
+*/
+void
+BlurEdge::effect (Inkscape::Extension::Effect *module, Inkscape::UI::View::View *document)
+{
+ Inkscape::Selection * selection = ((SPDesktop *)document)->selection;
+
+ float width = module->get_param_float("blur-width");
+ int steps = module->get_param_int("num-steps");
+
+ double old_offset = prefs_get_double_attribute("options.defaultoffsetwidth", "value", 1.0);
+
+ using Inkscape::Util::GSListConstIterator;
+ // TODO need to properly refcount the items, at least
+ std::list<SPItem *> items;
+ items.insert<GSListConstIterator<SPItem *> >(items.end(), selection->itemList(), NULL);
+ selection->clear();
+
+ std::list<SPItem *> new_items;
+ for(std::list<SPItem *>::iterator item = items.begin();
+ item != items.end(); item++) {
+ SPItem * spitem = *item;
+
+ Inkscape::XML::Node * new_items[steps];
+ Inkscape::XML::Node * new_group = sp_repr_new("svg:g");
+ (SP_OBJECT_REPR(spitem)->parent())->appendChild(new_group);
+ /** \todo Need to figure out how to get from XML::Node to SPItem */
+ /* new_items.push_back(); */
+
+ double orig_opacity = sp_repr_css_double_property(sp_repr_css_attr(SP_OBJECT_REPR(spitem), "style"), "opacity", 1.0);
+ char opacity_string[64];
+ g_ascii_formatd(opacity_string, sizeof(opacity_string), "%f",
+ orig_opacity / (steps));
+
+ for (int i = 0; i < steps; i++) {
+ double offset = (width / (float)(steps - 1) * (float)i) - (width / 2.0);
+
+ new_items[i] = (SP_OBJECT_REPR(spitem))->duplicate();
+
+ SPCSSAttr * css = sp_repr_css_attr(new_items[i], "style");
+ sp_repr_css_set_property(css, "opacity", opacity_string);
+ sp_repr_css_change(new_items[i], css, "style");
+
+ new_group->appendChild(new_items[i]);
+ selection->add(new_items[i]);
+ sp_selected_path_to_curves();
+
+ if (offset < 0.0) {
+ /* Doing an inset here folks */
+ offset *= -1.0;
+ prefs_set_double_attribute("options.defaultoffsetwidth", "value", offset);
+ sp_action_perform(Inkscape::Verb::get(SP_VERB_SELECTION_INSET)->get_action(document), NULL);
+ } else if (offset == 0.0) {
+ } else {
+ prefs_set_double_attribute("options.defaultoffsetwidth", "value", offset);
+ sp_action_perform(Inkscape::Verb::get(SP_VERB_SELECTION_OFFSET)->get_action(document), NULL);
+ }
+
+ selection->clear();
+ }
+
+ }
+
+ prefs_set_double_attribute("options.defaultoffsetwidth", "value", old_offset);
+
+ selection->clear();
+ selection->add(items.begin(), items.end());
+ selection->add(new_items.begin(), new_items.end());
+
+ return;
+}
+
+Gtk::Widget *
+BlurEdge::prefs_effect(Inkscape::Extension::Effect * module, Inkscape::UI::View::View * view)
+{
+ return module->autogui();
+}
+
+void
+BlurEdge::init (void)
+{
+ Inkscape::Extension::build_from_mem(
+ "<inkscape-extension>\n"
+ "<name>Blur Edge</name>\n"
+ "<id>org.inkscape.effect.bluredge</id>\n"
+ "<param name=\"blur-width\" gui-text=\"Blur Width\" type=\"float\" min=\"1.0\" max=\"50.0\">1.0</param>\n"
+ "<param name=\"num-steps\" gui-text=\"Number of Steps\" type=\"int\" min=\"5\" max=\"100\">11</param>\n"
+ "<effect>\n"
+ "<object-type>all</object-type>\n"
+ "</effect>\n"
+ "</inkscape-extension>\n" , new BlurEdge());
+ return;
+}
+
+}; /* namespace Internal */
+}; /* namespace Extension */
+}; /* namespace Inkscape */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/extension/internal/bluredge.h b/src/extension/internal/bluredge.h
new file mode 100644
index 000000000..a442f570e
--- /dev/null
+++ b/src/extension/internal/bluredge.h
@@ -0,0 +1,43 @@
+/*
+ * Authors:
+ * Ted Gould <ted@gould.cx>
+ *
+ * Copyright (C) 2005 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "extension/extension-forward.h"
+#include "extension/implementation/implementation.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+/** \brief Implementation class of the GIMP gradient plugin. This mostly
+ just creates a namespace for the GIMP gradient plugin today.
+*/
+class BlurEdge : public Inkscape::Extension::Implementation::Implementation {
+
+public:
+ bool load(Inkscape::Extension::Extension *module);
+ void effect(Inkscape::Extension::Effect *module, Inkscape::UI::View::View *document);
+ Gtk::Widget * prefs_effect(Inkscape::Extension::Effect * module, Inkscape::UI::View::View * view);
+
+ static void init (void);
+};
+
+}; /* namespace Internal */
+}; /* namespace Extension */
+}; /* namespace Inkscape */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/extension/internal/eps-out.cpp b/src/extension/internal/eps-out.cpp
new file mode 100644
index 000000000..849f9cfa4
--- /dev/null
+++ b/src/extension/internal/eps-out.cpp
@@ -0,0 +1,108 @@
+/*
+ * Authors:
+ * Ted Gould <ted@gould.cx>
+ *
+ * Copyright (C) 2004 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include "eps-out.h"
+#include <print.h>
+#include "extension/system.h"
+#include "extension/db.h"
+#include "extension/output.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+bool
+EpsOutput::check (Inkscape::Extension::Extension * module)
+{
+ if (NULL == Inkscape::Extension::db.get(SP_MODULE_KEY_PRINT_PS))
+ return FALSE;
+
+ return TRUE;
+}
+
+/**
+ \brief This function calls the print system with the filename
+ \param mod unused
+ \param doc Document to be saved
+ \param uri Filename to save to (probably will end in .eps)
+
+ The most interesting thing that this function does is just attach
+ an '>' on the front of the filename. This is the syntax used to
+ tell the printing system to save to file.
+*/
+void
+EpsOutput::save (Inkscape::Extension::Output *mod, SPDocument *doc, const gchar *uri)
+{
+ gchar * final_name;
+ Inkscape::Extension::Extension * ext;
+
+ ext = Inkscape::Extension::db.get(SP_MODULE_KEY_PRINT_PS);
+ if (ext == NULL)
+ return;
+
+ bool old_pageBoundingBox = ext->get_param_bool("pageBoundingBox");
+ bool new_val = mod->get_param_bool("pageBoundingBox");
+ ext->set_param_bool("pageBoundingBox", new_val);
+
+ bool old_textToPath = ext->get_param_bool("textToPath");
+ new_val = mod->get_param_bool("textToPath");
+ ext->set_param_bool("textToPath", new_val);
+
+ final_name = g_strdup_printf("> %s", uri);
+ sp_print_document_to_file(doc, final_name);
+ g_free(final_name);
+
+ ext->set_param_bool("pageBoundingBox", old_pageBoundingBox);
+ ext->set_param_bool("textToPath", old_textToPath);
+
+ return;
+}
+
+/**
+ \brief A function allocate a copy of this function.
+
+ This is the definition of postscript out. This function just
+ calls the extension system with the memory allocated XML that
+ describes the data.
+*/
+void
+EpsOutput::init (void)
+{
+ Inkscape::Extension::build_from_mem(
+ "<inkscape-extension>\n"
+ "<name>Encapsulated Postscript Output</name>\n"
+ "<id>org.inkscape.output.eps</id>\n"
+ "<param name=\"pageBoundingBox\" type=\"boolean\" gui-text=\"Make bounding box around full page\">FALSE</param>\n"
+ "<param name=\"textToPath\" type=\"boolean\" gui-text=\"Convert text to path\">TRUE</param>\n"
+ "<output>\n"
+ "<extension>.eps</extension>\n"
+ "<mimetype>image/x-e-postscript</mimetype>\n"
+ "<filetypename>Encapsulated Postscript (*.eps)</filetypename>\n"
+ "<filetypetooltip>Encapsulated Postscript File</filetypetooltip>\n"
+ "</output>\n"
+ "</inkscape-extension>", new EpsOutput());
+
+ return;
+}
+
+} } } /* namespace Inkscape, Extension, Implementation */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/extension/internal/eps-out.h b/src/extension/internal/eps-out.h
new file mode 100644
index 000000000..41a6c1f5c
--- /dev/null
+++ b/src/extension/internal/eps-out.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * Authors:
+ * Ted Gould <ted@gould.cx>
+ *
+ * Copyright (C) 2004 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef EXTENSION_INTERNAL_EPS_OUT_H
+#define EXTENSION_INTERNAL_EPS_OUT_H
+
+#include <gtk/gtkdialog.h>
+#include <gtk/gtkwidget.h>
+
+#include "extension/implementation/implementation.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+class EpsOutput : Inkscape::Extension::Implementation::Implementation {
+public:
+ bool check(Inkscape::Extension::Extension *module);
+
+ void save(Inkscape::Extension::Output *mod,
+ SPDocument *doc,
+ gchar const *uri);
+
+ static void init(void);
+};
+
+} } } /* namespace Inkscape, Extension, Implementation */
+
+#endif /* EXTENSION_INTERNAL_EPS_OUT_H */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/extension/internal/gdkpixbuf-input.cpp b/src/extension/internal/gdkpixbuf-input.cpp
new file mode 100644
index 000000000..ee9fc4086
--- /dev/null
+++ b/src/extension/internal/gdkpixbuf-input.cpp
@@ -0,0 +1,176 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include "document-private.h"
+#include <dir-util.h>
+#include "prefs-utils.h"
+#include "extension/system.h"
+#include "gdkpixbuf-input.h"
+
+namespace Inkscape {
+
+namespace IO {
+GdkPixbuf* pixbuf_new_from_file( char const *utf8name, GError **error );
+}
+
+namespace Extension {
+namespace Internal {
+
+SPDocument *
+GdkpixbufInput::open(Inkscape::Extension::Input *mod, char const *uri)
+{
+ SPDocument *doc = sp_document_new(NULL, TRUE, TRUE);
+ sp_document_set_undo_sensitive(doc, FALSE); // no need to undo in this temporary document
+ GdkPixbuf *pb = Inkscape::IO::pixbuf_new_from_file( uri, NULL );
+ Inkscape::XML::Node *rdoc = sp_document_repr_root(doc);
+ gchar const *docbase = rdoc->attribute("sodipodi:docbase");
+ gchar const *relname = sp_relative_path_from_path(uri, docbase);
+
+ if (pb) { /* We are readable */
+ Inkscape::XML::Node *repr = NULL;
+
+ double width = gdk_pixbuf_get_width(pb);
+ double height = gdk_pixbuf_get_height(pb);
+ gchar const *str = gdk_pixbuf_get_option( pb, "Inkscape::DpiX" );
+ if ( str )
+ {
+ gint dpi = atoi(str);
+ if ( dpi > 0 && dpi != 72 )
+ {
+ double scale = 72.0 / (double)dpi;
+ width *= scale;
+ }
+ }
+ str = gdk_pixbuf_get_option( pb, "Inkscape::DpiY" );
+ if ( str )
+ {
+ gint dpi = atoi(str);
+ if ( dpi > 0 && dpi != 72 )
+ {
+ double scale = 72.0 / (double)dpi;
+ height *= scale;
+ }
+ }
+
+ if (prefs_get_int_attribute("options.importbitmapsasimages", "value", 1) == 1) {
+ // import as <image>
+ repr = sp_repr_new("svg:image");
+ repr->setAttribute("xlink:href", relname);
+ repr->setAttribute("sodipodi:absref", uri);
+
+ sp_repr_set_svg_double(repr, "width", width);
+ sp_repr_set_svg_double(repr, "height", height);
+
+ } else {
+ // import as pattern-filled rect
+ Inkscape::XML::Node *pat = sp_repr_new("svg:pattern");
+ pat->setAttribute("inkscape:collect", "always");
+ pat->setAttribute("patternUnits", "userSpaceOnUse");
+ sp_repr_set_svg_double(pat, "width", width);
+ sp_repr_set_svg_double(pat, "height", height);
+ SP_OBJECT_REPR(SP_DOCUMENT_DEFS(doc))->appendChild(pat);
+ gchar const *pat_id = pat->attribute("id");
+ SPObject *pat_object = doc->getObjectById(pat_id);
+
+ Inkscape::XML::Node *im = sp_repr_new("svg:image");
+ im->setAttribute("xlink:href", relname);
+ im->setAttribute("sodipodi:absref", uri);
+ sp_repr_set_svg_double(im, "width", width);
+ sp_repr_set_svg_double(im, "height", height);
+ SP_OBJECT_REPR(pat_object)->addChild(im, NULL);
+
+ repr = sp_repr_new("svg:rect");
+ repr->setAttribute("style", g_strdup_printf("stroke:none;fill:url(#%s)", pat_id));
+ sp_repr_set_svg_double(repr, "width", width);
+ sp_repr_set_svg_double(repr, "height", height);
+ }
+
+ SP_DOCUMENT_ROOT(doc)->appendChildRepr(repr);
+ Inkscape::GC::release(repr);
+ gdk_pixbuf_unref(pb);
+ // restore undo, as now this document may be shown to the user if a bitmap was opened
+ sp_document_set_undo_sensitive(doc, TRUE);
+ } else {
+ printf("GdkPixbuf loader failed\n");
+ }
+
+ return doc;
+}
+
+
+void
+GdkpixbufInput::init(void)
+{
+ GSList * formatlist, * formatlisthead;
+
+ /* \todo I'm not sure if I need to free this list */
+ for (formatlist = formatlisthead = gdk_pixbuf_get_formats();
+ formatlist != NULL;
+ formatlist = g_slist_next(formatlist)) {
+
+ GdkPixbufFormat *pixformat = (GdkPixbufFormat *)formatlist->data;
+
+ gchar *name = gdk_pixbuf_format_get_name(pixformat);
+ gchar *description = gdk_pixbuf_format_get_description(pixformat);
+ gchar **extensions = gdk_pixbuf_format_get_extensions(pixformat);
+ gchar **mimetypes = gdk_pixbuf_format_get_mime_types(pixformat);
+
+ for (int i = 0; extensions[i] != NULL; i++) {
+ for (int j = 0; mimetypes[j] != NULL; j++) {
+
+ /* thanks but no thanks, we'll handle SVG extensions... */
+ if (strcmp(extensions[i], "svg") == 0) {
+ continue;
+ }
+ if (strcmp(extensions[i], "svgz") == 0) {
+ continue;
+ }
+ if (strcmp(extensions[i], "svg.gz") == 0) {
+ continue;
+ }
+
+ gchar *xmlString = g_strdup_printf(
+ "<inkscape-extension>\n"
+ "<name>%s GDK pixbuf Input</name>\n"
+ "<id>org.inkscape.input.gdkpixbuf.%s</id>\n"
+ "<input>\n"
+ "<extension>.%s</extension>\n"
+ "<mimetype>%s</mimetype>\n"
+ "<filetypename>%s (*.%s)</filetypename>\n"
+ "<filetypetooltip>%s</filetypetooltip>\n"
+ "</input>\n"
+ "</inkscape-extension>",
+ name,
+ extensions[i],
+ extensions[i],
+ mimetypes[j],
+ name,
+ extensions[i],
+ description
+ );
+
+ Inkscape::Extension::build_from_mem(xmlString, new GdkpixbufInput());
+ g_free(xmlString);
+ }}
+
+ g_free(name);
+ g_free(description);
+ g_strfreev(mimetypes);
+ g_strfreev(extensions);
+ }
+
+ g_slist_free(formatlisthead);
+}
+
+} } } /* namespace Inkscape, Extension, Implementation */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/extension/internal/gdkpixbuf-input.h b/src/extension/internal/gdkpixbuf-input.h
new file mode 100644
index 000000000..9d5e6ccf7
--- /dev/null
+++ b/src/extension/internal/gdkpixbuf-input.h
@@ -0,0 +1,31 @@
+#ifndef INKSCAPE_EXTENSION_INTERNAL_GDKPIXBUF_INPUT_H
+#define INKSCAPE_EXTENSION_INTERNAL_GDKPIXBUF_INPUT_H
+
+#include "extension/implementation/implementation.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+class GdkpixbufInput : Inkscape::Extension::Implementation::Implementation {
+public:
+ SPDocument *open(Inkscape::Extension::Input *mod,
+ gchar const *uri);
+ static void init();
+};
+
+} } } /* namespace Inkscape, Extension, Implementation */
+
+
+#endif /* INKSCAPE_EXTENSION_INTERNAL_GDKPIXBUF_INPUT_H */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/extension/internal/gimpgrad.cpp b/src/extension/internal/gimpgrad.cpp
new file mode 100644
index 000000000..9560c5df6
--- /dev/null
+++ b/src/extension/internal/gimpgrad.cpp
@@ -0,0 +1,233 @@
+/** \file
+ * Inkscape::Extension::Internal::GimpGrad implementation
+ */
+
+/*
+ * Authors:
+ * Ted Gould <ted@gould.cx>
+ *
+ * Copyright (C) 2004-2005 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <color-rgba.h>
+#include "io/sys.h"
+#include "extension/system.h"
+
+#include "gimpgrad.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+/**
+ \brief A function to allocated anything -- just an example here
+ \param module Unused
+ \return Whether the load was sucessful
+*/
+bool
+GimpGrad::load (Inkscape::Extension::Extension *module)
+{
+ // std::cout << "Hey, I'm loading!\n" << std::endl;
+ return TRUE;
+}
+
+/**
+ \brief A function to remove what was allocated
+ \param module Unused
+ \return None
+*/
+void
+GimpGrad::unload (Inkscape::Extension::Extension *module)
+{
+ // std::cout << "Nooo! I'm being unloaded!" << std::endl;
+ return;
+}
+
+/**
+ \brief A function to turn a color into a gradient stop
+ \param in_color The color for the stop
+ \param location Where the stop is placed in the gradient
+ \return The text that is the stop. Full SVG containing the element.
+
+ This function encapsulates all of the translation of the ColorRGBA
+ and the location into the gradient. It is really pretty simple except
+ that the ColorRGBA is in floats that are 0 to 1 and the SVG wants
+ hex values from 0 to 255 for color. Otherwise mostly this is just
+ turning the values into strings and returning it.
+*/
+Glib::ustring
+GimpGrad::new_stop (ColorRGBA in_color, float location)
+{
+ char temp_string[25];
+ Glib::ustring mystring("<stop style=\"stop-color:#");
+
+ for (int i = 0; i < 3; i++) {
+ unsigned char temp;
+
+ temp = (unsigned char)(in_color[i] * 255.0);
+
+ sprintf(temp_string, "%2.2X", temp);
+ mystring += temp_string;
+ }
+
+ mystring += ";stop-opacity:";
+ sprintf(temp_string, "%1.8f", in_color[3]);
+ mystring += temp_string;
+ mystring += ";\" offset=\"";
+ sprintf(temp_string, "%1.8f", location);
+ mystring += temp_string;
+ mystring += "\"/>\n";
+ return mystring;
+}
+
+/**
+ \brief Actually open the gradient and turn it into an SPDocument
+ \param module The input module being used
+ \param filename The filename of the gradient to be opened
+ \return A Document with the gradient in it.
+
+ GIMP gradients are pretty simple (atleast the newer format, this
+ function does not handle the old one yet). They start out with
+ the like "GIMP Gradient", then name it, and tell how many entries
+ there are. This function currently ignores the name and the number
+ of entries just reading until it fails.
+
+ The other small piece of trickery here is that GIMP gradients define
+ a left possition, right possition and middle possition. SVG gradients
+ have no middle possition in them. In order to handle this case the
+ left and right colors are averaged in a linear manner and the middle
+ possition is used for that color.
+
+ That is another point, the GIMP gradients support many different types
+ of gradients -- linear being the most simple. This plugin assumes
+ that they are all linear. Most GIMP gradients are done this way,
+ but it is possible to encounter more complex ones -- which won't be
+ handled correctly.
+
+ The one optimization that this plugin makes that if the right side
+ of the previous segment is the same color as the left side of the
+ current segment, then the second one is dropped. This is often
+ done in GIMP gradients and they are not necissary in SVG.
+
+ What this function does is build up an SVG document with a single
+ linear gradient in it with all the stops of the colors in the GIMP
+ gradient that is passed in. This document is then turned into a
+ document using the \c sp_document_from_mem. That is then returned
+ to Inkscape.
+*/
+SPDocument *
+GimpGrad::open (Inkscape::Extension::Input *module, gchar const *filename)
+{
+ FILE * gradient;
+ // std::cout << "Open filename: " << filename << std::endl;
+
+ Inkscape::IO::dump_fopen_call(filename, "I");
+ gradient = Inkscape::IO::fopen_utf8name(filename, "r");
+ if (gradient == NULL) return NULL;
+
+ char tempstr[1024];
+ if (fgets(tempstr, 1024, gradient) == 0) {
+ // std::cout << "Seems that the read failed" << std::endl;
+ fclose(gradient);
+ return NULL;
+ }
+
+ if (!strcmp(tempstr, "GIMP Gradient")) {
+ // std::cout << "This doesn't appear to be a GIMP gradient" << std::endl;
+ fclose(gradient);
+ return NULL;
+ }
+
+ if (fgets(tempstr, 1024, gradient) == 0) {
+ // std::cout << "Seems that the second read failed" << std::endl;
+ fclose(gradient);
+ return NULL;
+ }
+
+ if (fgets(tempstr, 1024, gradient) == 0) {
+ // std::cout << "Seems that the third read failed" << std::endl;
+ fclose(gradient);
+ return NULL;
+ }
+
+ ColorRGBA last_color(-1.0, -1.0, -1.0, -1.0);
+ float lastlocation = -1.0;
+ Glib::ustring outsvg("<svg><defs><linearGradient>\n");
+ while (fgets(tempstr, 1024, gradient) != 0) {
+ float left, middle, right;
+ float temp_color[4];
+ int type;
+ int color;
+ gchar * end;
+
+ left = g_ascii_strtod(tempstr, &end);
+ middle = g_ascii_strtod(end, &end);
+ right = g_ascii_strtod(end, &end);
+
+ for (int i = 0; i < 4; i++) {
+ temp_color[i] = g_ascii_strtod(end, &end);
+ }
+ ColorRGBA leftcolor(temp_color[0], temp_color[1], temp_color[2], temp_color[3]);
+
+ for (int i = 0; i < 4; i++) {
+ temp_color[i] = g_ascii_strtod(end, &end);
+ }
+ ColorRGBA rightcolor(temp_color[0], temp_color[1], temp_color[2], temp_color[3]);
+
+ sscanf(end, "%d %d", &type, &color);
+
+ if (!(last_color == leftcolor) || left != lastlocation) {
+ outsvg += new_stop(leftcolor, left);
+ }
+ outsvg += new_stop(leftcolor.average(rightcolor), middle);
+ outsvg += new_stop(rightcolor, right);
+
+ last_color = rightcolor;
+ lastlocation = right;
+ }
+
+ outsvg += "</linearGradient></defs></svg>";
+
+ // std::cout << "SVG Output: " << outsvg << std::endl;
+
+ fclose(gradient);
+
+ return sp_document_new_from_mem(outsvg.c_str(), outsvg.length(), TRUE);
+}
+
+void
+GimpGrad::init (void)
+{
+ Inkscape::Extension::build_from_mem(
+ "<inkscape-extension>\n"
+ "<name>GIMP Gradients</name>\n"
+ "<id>org.inkscape.input.gimpgrad</id>\n"
+ "<dependency type=\"plugin\" location=\"plugins\">gimpgrad</dependency>\n"
+ "<input>\n"
+ "<extension>.ggr</extension>\n"
+ "<mimetype>application/x-gimp-gradient</mimetype>\n"
+ "<filetypename>GIMP Gradient (*.ggr)</filetypename>\n"
+ "<filetypetooltip>Gradients used in GIMP</filetypetooltip>\n"
+ "</input>\n"
+ "</inkscape-extension>\n", new GimpGrad());
+ return;
+}
+
+} } } /* namespace Internal; Extension; Inkscape */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/extension/internal/gimpgrad.h b/src/extension/internal/gimpgrad.h
new file mode 100644
index 000000000..0d0698e67
--- /dev/null
+++ b/src/extension/internal/gimpgrad.h
@@ -0,0 +1,49 @@
+/** \file
+ *
+ * Implementation class of the GIMP gradient plugin.
+ *
+ * Authors:
+ * Ted Gould <ted@gould.cx>
+ *
+ * Copyright (C) 2004-2005 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <glibmm/ustring.h>
+
+#include "extension/implementation/implementation.h"
+#include "extension/extension-forward.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+/** \brief Implementation class of the GIMP gradient plugin. This mostly
+ just creates a namespace for the GIMP gradient plugin today.
+*/
+class GimpGrad : public Inkscape::Extension::Implementation::Implementation {
+private:
+ Glib::ustring new_stop (ColorRGBA in_color, float location);
+
+public:
+ bool load(Inkscape::Extension::Extension *module);
+ void unload(Inkscape::Extension::Extension *module);
+ SPDocument *open(Inkscape::Extension::Input *module, gchar const *filename);
+
+ static void init (void);
+};
+
+
+} } } /* namespace Internal; Extension; Inkscape */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/extension/internal/gnome.cpp b/src/extension/internal/gnome.cpp
new file mode 100644
index 000000000..d81dfa95e
--- /dev/null
+++ b/src/extension/internal/gnome.cpp
@@ -0,0 +1,443 @@
+#define __SP_GNOME_C__
+
+/*
+ * Gnome stuff
+ *
+ * Author:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ * Ted Gould <ted@gould.cx>
+ *
+ *
+ * Copyright (C) 2005 Authors
+ *
+ * Lauris: This code is in public domain
+ * Ted: This code is under the GNU GPL
+ */
+
+/* Gnome Print */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+
+#include "libnr/n-art-bpath.h"
+#include "libnr/nr-rect.h"
+#include "libnr/nr-matrix.h"
+#include "libnr/nr-matrix-fns.h"
+#include "libnr/nr-path.h"
+#include "libnr/nr-pixblock.h"
+#include "display/canvas-bpath.h"
+
+#include <glib.h>
+#include <gtk/gtkdialog.h>
+#include <gtk/gtkbox.h>
+#include <gtk/gtkstock.h>
+
+#if OLDGnome
+#include <libgnomeprint/gnome-print-master.h>
+#include <libgnomeprintui/gnome-print-master-preview.h>
+#endif
+
+#include <glibmm/i18n.h>
+#include "enums.h"
+#include "document.h"
+#include "style.h"
+#include "sp-paint-server.h"
+
+#include "gnome.h"
+
+#include "extension/extension.h"
+#include "extension/system.h"
+
+static ArtBpath *nr_artpath_to_art_bpath(NArtBpath const *s);
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+PrintGNOME::PrintGNOME (void)
+{
+ /* Nothing here */
+}
+
+PrintGNOME::~PrintGNOME (void)
+{
+ return;
+}
+
+unsigned int
+PrintGNOME::setup (Inkscape::Extension::Print *mod)
+{
+ GnomePrintConfig *config;
+#if OLDGnome
+ GtkWidget *dlg, *vbox, *sel;
+#endif
+
+ config = gnome_print_config_default ();
+#if OLDGnome
+ dlg = gtk_dialog_new_with_buttons (_("Select printer"), NULL,
+ GTK_DIALOG_MODAL,
+ GTK_STOCK_PRINT,
+ GTK_RESPONSE_OK,
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL,
+ NULL);
+
+ vbox = GTK_DIALOG (dlg)->vbox;
+ gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
+
+ sel = gnome_printer_selector_new (config);
+ gtk_widget_show (sel);
+ gtk_box_pack_start (GTK_BOX (vbox), sel, TRUE, TRUE, 0);
+
+ btn = gtk_dialog_run (GTK_DIALOG (dlg));
+ gtk_widget_destroy (dlg);
+ if (btn != GTK_RESPONSE_OK) return FALSE;
+#endif
+ _gpc = gnome_print_context_new (config);
+ gnome_print_config_unref (config);
+
+ return TRUE;
+}
+
+unsigned int
+PrintGNOME::set_preview (Inkscape::Extension::Print *mod)
+{
+#if OLDGnome
+ SPPrintContext ctx;
+ GnomePrintContext *gpc;
+ GnomePrintMaster *gpm;
+ GtkWidget *gpmp;
+ gchar *title;
+
+
+ gpm = gnome_print_master_new();
+ _gpc = gnome_print_master_get_context (gpm);
+
+ g_return_if_fail (gpm != NULL);
+ g_return_if_fail (gpc != NULL);
+
+ /* Print document */
+ gnome_print_beginpage (gpc, SP_DOCUMENT_NAME (doc));
+ gnome_print_translate (gpc, 0.0, sp_document_height (doc));
+ /* From desktop points to document pixels */
+ gnome_print_scale (gpc, 0.8, -0.8);
+ sp_item_invoke_print (SP_ITEM (sp_document_root (doc)), &ctx);
+ gnome_print_showpage (gpc);
+ gnome_print_context_close (gpc);
+
+ title = g_strdup_printf (_("Inkscape: Print Preview"));
+ gpmp = gnome_print_master_preview_new (gpm, title);
+
+ gtk_widget_show (GTK_WIDGET(gpmp));
+
+ gnome_print_master_close (gpm);
+
+ g_free (title);
+#endif
+ return 0;
+}
+
+unsigned int
+PrintGNOME::begin (Inkscape::Extension::Print *mod, SPDocument *doc)
+{
+ gnome_print_beginpage (_gpc, (const guchar *)SP_DOCUMENT_NAME (doc));
+ gnome_print_translate (_gpc, 0.0, sp_document_height (doc));
+ /* From desktop points to document pixels */
+ gnome_print_scale (_gpc, 0.8, -0.8);
+
+ return 0;
+}
+
+unsigned int
+PrintGNOME::finish (Inkscape::Extension::Print *mod)
+{
+ gnome_print_showpage (_gpc);
+ gnome_print_context_close (_gpc);
+
+ return 0;
+}
+
+unsigned int
+PrintGNOME::bind (Inkscape::Extension::Print *mod, const NRMatrix *transform, float opacity)
+{
+ gdouble t[6];
+
+ gnome_print_gsave(_gpc);
+
+ t[0] = transform->c[0];
+ t[1] = transform->c[1];
+ t[2] = transform->c[2];
+ t[3] = transform->c[3];
+ t[4] = transform->c[4];
+ t[5] = transform->c[5];
+
+ gnome_print_concat (_gpc, t);
+
+ /* fixme: Opacity? (lauris) */
+
+ return 0;
+}
+
+unsigned int
+PrintGNOME::release (Inkscape::Extension::Print *mod)
+{
+ gnome_print_grestore (_gpc);
+ return 0;
+}
+
+unsigned int PrintGNOME::comment (Inkscape::Extension::Print * module,
+ const char * comment)
+{
+ // ignore comment
+ return 0;
+}
+
+unsigned int
+PrintGNOME::fill(Inkscape::Extension::Print *mod,
+ NRBPath const *bpath, NRMatrix const *ctm, SPStyle const *style,
+ NRRect const *pbox, NRRect const *dbox, NRRect const *bbox)
+{
+ gdouble t[6];
+
+ /* CTM is for information purposes only */
+ /* We expect user coordinate system to be set up already */
+
+ t[0] = ctm->c[0];
+ t[1] = ctm->c[1];
+ t[2] = ctm->c[2];
+ t[3] = ctm->c[3];
+ t[4] = ctm->c[4];
+ t[5] = ctm->c[5];
+
+ if (style->fill.type == SP_PAINT_TYPE_COLOR) {
+ float rgb[3], opacity;
+ sp_color_get_rgb_floatv (&style->fill.value.color, rgb);
+ gnome_print_setrgbcolor (_gpc, rgb[0], rgb[1], rgb[2]);
+
+ /* fixme: */
+ opacity = SP_SCALE24_TO_FLOAT (style->fill_opacity.value) * SP_SCALE24_TO_FLOAT (style->opacity.value);
+ gnome_print_setopacity (_gpc, opacity);
+
+ ArtBpath * apath = nr_artpath_to_art_bpath(bpath->path);
+ gnome_print_bpath (_gpc, apath, FALSE);
+ g_free(apath);
+
+ if (style->fill_rule.value == SP_WIND_RULE_EVENODD) {
+ gnome_print_eofill (_gpc);
+ } else {
+ gnome_print_fill (_gpc);
+ }
+ } else if (style->fill.type == SP_PAINT_TYPE_PAINTSERVER) {
+ SPPainter *painter;
+ NRRect dpbox;
+
+ /* fixme: */
+ dpbox.x0 = pbox->x0;
+ dpbox.y0 = pbox->y0;
+ dpbox.x1 = pbox->x1;
+ dpbox.y1 = pbox->y1;
+ painter = sp_paint_server_painter_new(SP_STYLE_FILL_SERVER(style),
+ // FIXME: the second matrix below must be the parent (context) transform.
+ // I don't know what it must be for gnome-print. --bb
+ ctm, NR::identity(),
+ &dpbox);
+ if (painter) {
+ NRRect cbox;
+ NRRectL ibox;
+ NRMatrix d2i;
+ double dd2i[6];
+ int x, y;
+
+ nr_rect_d_intersect (&cbox, dbox, bbox);
+ ibox.x0 = (long) cbox.x0;
+ ibox.y0 = (long) cbox.y0;
+ ibox.x1 = (long) (cbox.x1 + 0.9999);
+ ibox.y1 = (long) (cbox.y1 + 0.9999);
+
+ nr_matrix_invert (&d2i, ctm);
+
+ gnome_print_gsave (_gpc);
+
+ ArtBpath * apath = nr_artpath_to_art_bpath(bpath->path);
+ gnome_print_bpath (_gpc, apath, FALSE);
+ g_free(apath);
+
+ if (style->fill_rule.value == SP_WIND_RULE_EVENODD) {
+ gnome_print_eoclip (_gpc);
+ } else {
+ gnome_print_clip (_gpc);
+ }
+ dd2i[0] = d2i.c[0];
+ dd2i[1] = d2i.c[1];
+ dd2i[2] = d2i.c[2];
+ dd2i[3] = d2i.c[3];
+ dd2i[4] = d2i.c[4];
+ dd2i[5] = d2i.c[5];
+ gnome_print_concat (_gpc, dd2i);
+ /* Now we are in desktop coordinates */
+ for (y = ibox.y0; y < ibox.y1; y+= 64) {
+ for (x = ibox.x0; x < ibox.x1; x+= 64) {
+ NRPixBlock pb;
+ nr_pixblock_setup_fast (&pb, NR_PIXBLOCK_MODE_R8G8B8A8N, x, y, x + 64, y + 64, TRUE);
+ painter->fill (painter, &pb);
+ gnome_print_gsave (_gpc);
+ gnome_print_translate (_gpc, x, y + 64);
+ gnome_print_scale (_gpc, 64, -64);
+ gnome_print_rgbaimage (_gpc, NR_PIXBLOCK_PX (&pb), 64, 64, pb.rs);
+ gnome_print_grestore (_gpc);
+ nr_pixblock_release (&pb);
+ }
+ }
+ gnome_print_grestore (_gpc);
+ sp_painter_free (painter);
+ }
+ }
+
+ return 0;
+}
+
+unsigned int
+PrintGNOME::stroke (Inkscape::Extension::Print *mod, const NRBPath *bpath, const NRMatrix *ctm, const SPStyle *style,
+ const NRRect *pbox, const NRRect *dbox, const NRRect *bbox)
+{
+ gdouble t[6];
+
+ /* CTM is for information purposes only */
+ /* We expect user coordinate system to be set up already */
+
+ t[0] = ctm->c[0];
+ t[1] = ctm->c[1];
+ t[2] = ctm->c[2];
+ t[3] = ctm->c[3];
+ t[4] = ctm->c[4];
+ t[5] = ctm->c[5];
+
+ if (style->stroke.type == SP_PAINT_TYPE_COLOR) {
+ float rgb[3], opacity;
+ sp_color_get_rgb_floatv (&style->stroke.value.color, rgb);
+ gnome_print_setrgbcolor (_gpc, rgb[0], rgb[1], rgb[2]);
+
+ /* fixme: */
+ opacity = SP_SCALE24_TO_FLOAT (style->stroke_opacity.value) * SP_SCALE24_TO_FLOAT (style->opacity.value);
+ gnome_print_setopacity (_gpc, opacity);
+
+ if (style->stroke_dash.n_dash > 0) {
+ gnome_print_setdash (_gpc, style->stroke_dash.n_dash, style->stroke_dash.dash, style->stroke_dash.offset);
+ } else {
+ gnome_print_setdash (_gpc, 0, NULL, 0.0);
+ }
+
+ gnome_print_setlinewidth (_gpc, style->stroke_width.computed);
+ gnome_print_setlinejoin (_gpc, style->stroke_linejoin.computed);
+ gnome_print_setlinecap (_gpc, style->stroke_linecap.computed);
+
+ ArtBpath * apath = nr_artpath_to_art_bpath(bpath->path);
+ gnome_print_bpath (_gpc, apath, FALSE);
+ g_free(apath);
+
+ gnome_print_stroke (_gpc);
+ }
+
+ return 0;
+}
+
+unsigned int
+PrintGNOME::image (Inkscape::Extension::Print *mod, unsigned char *px, unsigned int w, unsigned int h, unsigned int rs,
+ const NRMatrix *transform, const SPStyle *style)
+{
+ gdouble t[6];
+
+ t[0] = transform->c[0];
+ t[1] = transform->c[1];
+ t[2] = transform->c[2];
+ t[3] = transform->c[3];
+ t[4] = transform->c[4];
+ t[5] = transform->c[5];
+
+ gnome_print_gsave (_gpc);
+
+ gnome_print_concat (_gpc, t);
+
+ if (style->opacity.value != SP_SCALE24_MAX) {
+ guchar *dpx, *d, *s;
+ guint x, y;
+ guint32 alpha;
+ alpha = (guint32) floor (SP_SCALE24_TO_FLOAT (style->opacity.value) * 255.9999);
+ dpx = g_new (guchar, w * h * 4);
+ for (y = 0; y < h; y++) {
+ s = px + y * rs;
+ d = dpx + y * w * 4;
+ memcpy (d, s, w * 4);
+ for (x = 0; x < w; x++) {
+ d[3] = (s[3] * alpha) / 255;
+ s += 4;
+ d += 4;
+ }
+ }
+ gnome_print_rgbaimage (_gpc, dpx, w, h, w * 4);
+ g_free (dpx);
+ } else {
+ gnome_print_rgbaimage (_gpc, px, w, h, rs);
+ }
+
+ gnome_print_grestore (_gpc);
+
+ return 0;
+}
+
+void
+PrintGNOME::init (void)
+{
+ Inkscape::Extension::Extension * ext;
+
+ /* SVG in */
+ ext = Inkscape::Extension::build_from_mem(
+ "<inkscape-extension>\n"
+ "<name>GNOME Print</name>\n"
+ "<id>" SP_MODULE_KEY_PRINT_GNOME "</id>\n"
+ "<print/>\n"
+ "</inkscape-extension>", new PrintGNOME());
+
+ return;
+}
+
+} /* namespace Internal */
+} /* namespace Extension */
+} /* namespace Inkscape */
+
+
+// Remember to free the result!
+static ArtBpath *
+nr_artpath_to_art_bpath(NArtBpath const *s)
+{
+ int i;
+ if (!s) {
+ return NULL;
+ }
+
+ i = 0;
+ while (s[i].code != NR_END) i += 1;
+
+ ArtBpath* d = nr_new (ArtBpath, i + 1);
+
+ i = 0;
+ while (s[i].code != NR_END) {
+ d[i].code = (ArtPathcode)s[i].code;
+ if (s[i].code == NR_CURVETO) {
+ d[i].x1 = s[i].x1;
+ d[i].y1 = s[i].y1;
+ d[i].x2 = s[i].x2;
+ d[i].y2 = s[i].y2;
+ }
+ d[i].x3 = s[i].x3;
+ d[i].y3 = s[i].y3;
+ i += 1;
+ }
+ d[i].code = ART_END;
+
+ return d;
+}
+
diff --git a/src/extension/internal/gnome.h b/src/extension/internal/gnome.h
new file mode 100644
index 000000000..1a1ff55f2
--- /dev/null
+++ b/src/extension/internal/gnome.h
@@ -0,0 +1,58 @@
+#ifndef __INKSCAPE_EXTENSION_INTERNAL_PRINT_GNOME_H__
+#define __INKSCAPE_EXTENSION_INTERNAL_PRINT_GNOME_H__
+
+/*
+ * Gnome stuff
+ *
+ * Author:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ * Ted Gould <ted@gould.cx>
+ *
+ * Lauris: This code is in public domain
+ * Ted: This code is under the GNU GPL
+ */
+
+#include <config.h>
+
+#include <libgnomeprint/gnome-print.h>
+
+#include "extension/implementation/implementation.h"
+#include "extension/extension.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+class PrintGNOME : public Inkscape::Extension::Implementation::Implementation {
+ GnomePrintContext * _gpc;
+
+public:
+ PrintGNOME (void);
+ virtual ~PrintGNOME (void);
+
+ /* Print functions */
+ virtual unsigned int setup (Inkscape::Extension::Print * module);
+ virtual unsigned int set_preview (Inkscape::Extension::Print * module);
+
+ virtual unsigned int begin (Inkscape::Extension::Print * module, SPDocument *doc);
+ virtual unsigned int finish (Inkscape::Extension::Print * module);
+
+ /* Rendering methods */
+ virtual unsigned int bind (Inkscape::Extension::Print * module, const NRMatrix *transform, float opacity);
+ virtual unsigned int release (Inkscape::Extension::Print * module);
+ virtual unsigned int fill (Inkscape::Extension::Print * module, const NRBPath *bpath, const NRMatrix *ctm, const SPStyle *style,
+ const NRRect *pbox, const NRRect *dbox, const NRRect *bbox);
+ virtual unsigned int stroke (Inkscape::Extension::Print * module, const NRBPath *bpath, const NRMatrix *transform, const SPStyle *style,
+ const NRRect *pbox, const NRRect *dbox, const NRRect *bbox);
+ virtual unsigned int image (Inkscape::Extension::Print * module, unsigned char *px, unsigned int w, unsigned int h, unsigned int rs,
+ const NRMatrix *transform, const SPStyle *style);
+ virtual unsigned int comment(Inkscape::Extension::Print *module, const char * comment);
+
+ static void init (void);
+};
+
+} /* namespace Internal */
+} /* namespace Extension */
+} /* namespace Inkscape */
+
+#endif /* __INKSCAPE_EXTENSION_INTERNAL_PRINT_GNOME_H__ */
diff --git a/src/extension/internal/grid.cpp b/src/extension/internal/grid.cpp
new file mode 100644
index 000000000..f74c652aa
--- /dev/null
+++ b/src/extension/internal/grid.cpp
@@ -0,0 +1,272 @@
+/**
+ \file grid.cpp
+
+ A plug-in to add a grid creation effect into Inkscape.
+*/
+/*
+ * Authors:
+ * Ted Gould <ted@gould.cx>
+ *
+ * Copyright (C) 2004-2005 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <gtkmm/box.h>
+#include <gtkmm/adjustment.h>
+#include <gtkmm/spinbutton.h>
+
+#include "desktop.h"
+#include "selection.h"
+#include "sp-object.h"
+
+#include "extension/effect.h"
+#include "extension/system.h"
+
+
+#include "grid.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+/**
+ \brief A function to allocated anything -- just an example here
+ \param module Unused
+ \return Whether the load was sucessful
+*/
+bool
+Grid::load (Inkscape::Extension::Extension *module)
+{
+ // std::cout << "Hey, I'm Grid, I'm loading!" << std::endl;
+ return TRUE;
+}
+
+/**
+ \brief This actually draws the grid.
+ \param module The effect that was called (unused)
+ \param document What should be edited.
+*/
+void
+Grid::effect (Inkscape::Extension::Effect *module, Inkscape::UI::View::View *document)
+{
+ Inkscape::Selection * selection = ((SPDesktop *)document)->selection;
+
+ NR::Rect bounding_area = NR::Rect(NR::Point(0,0), NR::Point(100,100));
+ if (selection->isEmpty()) {
+ /* get page size */
+ SPDocument * doc = document->doc();
+ bounding_area = NR::Rect(NR::Point(0,0),
+ NR::Point(sp_document_width(doc),
+ sp_document_height(doc)));
+ } else {
+ bounding_area = selection->bounds();
+
+ gdouble doc_height = sp_document_height(document->doc());
+ NR::Rect temprec = NR::Rect(NR::Point(bounding_area.min()[NR::X], doc_height - bounding_area.min()[NR::Y]),
+ NR::Point(bounding_area.max()[NR::X], doc_height - bounding_area.max()[NR::Y]));
+
+ bounding_area = temprec;
+ }
+
+
+ float xspacing = module->get_param_float("xspacing");
+ float yspacing = module->get_param_float("yspacing");
+ float line_width = module->get_param_float("lineWidth");
+ float xoffset = module->get_param_float("xoffset");
+ float yoffset = module->get_param_float("yoffset");
+
+ // std::cout << "Spacing: " << spacing;
+ // std::cout << " Line Width: " << line_width;
+ // std::cout << " Offset: " << offset << std::endl;
+
+ Glib::ustring path_data;
+
+ for (NR::Point start_point = bounding_area.min();
+ start_point[NR::X] + xoffset <= (bounding_area.max())[NR::X];
+ start_point[NR::X] += xspacing) {
+ NR::Point end_point = start_point;
+ end_point[NR::Y] = (bounding_area.max())[NR::Y];
+ gchar floatstring[64];
+
+ path_data += "M ";
+ sprintf(floatstring, "%f", start_point[NR::X] + xoffset);
+ path_data += floatstring;
+ path_data += " ";
+ sprintf(floatstring, "%f", start_point[NR::Y]);
+ path_data += floatstring;
+ path_data += " L ";
+ sprintf(floatstring, "%f", end_point[NR::X] + xoffset);
+ path_data += floatstring;
+ path_data += " ";
+ sprintf(floatstring, "%f", end_point[NR::Y]);
+ path_data += floatstring;
+ path_data += " ";
+ }
+
+ for (NR::Point start_point = bounding_area.min();
+ start_point[NR::Y] + yoffset <= (bounding_area.max())[NR::Y];
+ start_point[NR::Y] += yspacing) {
+ NR::Point end_point = start_point;
+ end_point[NR::X] = (bounding_area.max())[NR::X];
+ gchar floatstring[64];
+
+ path_data += "M ";
+ sprintf(floatstring, "%f", start_point[NR::X]);
+ path_data += floatstring;
+ path_data += " ";
+ sprintf(floatstring, "%f", start_point[NR::Y] + yoffset);
+ path_data += floatstring;
+ path_data += " L ";
+ sprintf(floatstring, "%f", end_point[NR::X]);
+ path_data += floatstring;
+ path_data += " ";
+ sprintf(floatstring, "%f", end_point[NR::Y] + yoffset);
+ path_data += floatstring;
+ path_data += " ";
+ }
+
+ // std::cout << "Path Data: " << path_data << std::endl;
+
+ Inkscape::XML::Node * current_layer = ((SPDesktop *)document)->currentLayer()->repr;
+ Inkscape::XML::Node * path = sp_repr_new("svg:path");
+
+ path->setAttribute("d", path_data.c_str());
+
+ Glib::ustring style("fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000");
+ style += ";stroke-width:";
+ gchar floatstring[64];
+ sprintf(floatstring, "%f", line_width);
+ style += floatstring;
+ style += "pt";
+ path->setAttribute("style", style.c_str());
+
+ // Glib::ustring transform("scale(1.25 1.25)");
+ // path->setAttribute("transform", transform.c_str());
+
+ current_layer->appendChild(path);
+
+ return;
+}
+
+/** \brief A class to make an adjustment that uses Extension params */
+class PrefAdjustment : public Gtk::Adjustment {
+ /** Extension that this relates to */
+ Inkscape::Extension::Extension * _ext;
+ /** The string which represents the parameter */
+ char * _pref;
+public:
+ /** \brief Make the adjustment using an extension and the string
+ describing the parameter. */
+ PrefAdjustment(Inkscape::Extension::Extension * ext, char * pref) :
+ Gtk::Adjustment(0.0, 0.0, 10.0, 0.1), _ext(ext), _pref(pref) {
+ this->set_value(_ext->get_param_float(_pref));
+ this->signal_value_changed().connect(sigc::mem_fun(this, &PrefAdjustment::val_changed));
+ return;
+ };
+
+ void val_changed (void);
+}; /* class PrefAdjustment */
+
+/** \brief A function to respond to the value_changed signal from the
+ adjustment.
+
+ This function just grabs the value from the adjustment and writes
+ it to the parameter. Very simple, but yet beautiful.
+*/
+void
+PrefAdjustment::val_changed (void)
+{
+ // std::cout << "Value Changed to: " << this->get_value() << std::endl;
+ _ext->set_param_float(_pref, this->get_value());
+ return;
+}
+
+/** \brief A function to get the prefences for the grid
+ \param moudule Module which holds the params
+ \param view Unused today - may get style information in the future.
+
+ This function builds a VBox, and puts it into a Gtk::Plug. This way
+ the native window pointer can be pulled out and returned up to be
+ stuck in a Gtk::Socket further up the call stack. In the Vbox there
+ are several Hboxes, each one being a spin button to adjust a particular
+ parameter. The names of the parameters and the labels are all
+ stored in the arrays in the middle of the function. This makes
+ the code very generic. This will probably have to change if someone
+ wants to make this dialog look nicer.
+*/
+Gtk::Widget *
+Grid::prefs_effect(Inkscape::Extension::Effect *module, Inkscape::UI::View::View * view)
+{
+ Gtk::VBox * vbox;
+ vbox = new Gtk::VBox();
+
+#define NUM_PREFERENCES 5
+ char * labels[NUM_PREFERENCES] = {N_("Line Width"),
+ N_("Horizontal Spacing"),
+ N_("Vertical Spacing"),
+ N_("Horizontal Offset"),
+ N_("Vertical Offset")};
+ char * prefs[NUM_PREFERENCES] = {"lineWidth",
+ "xspacing",
+ "yspacing",
+ "xoffset",
+ "yoffset"};
+
+ for (int i = 0; i < NUM_PREFERENCES; i++) {
+ Gtk::HBox * hbox = new Gtk::HBox();
+
+ Gtk::Label * label = new Gtk::Label(_(labels[i]), Gtk::ALIGN_LEFT);
+ label->show();
+ hbox->pack_start(*label, true, true);
+
+ PrefAdjustment * pref = new PrefAdjustment(module, prefs[i]);
+
+ Gtk::SpinButton * spin = new Gtk::SpinButton(*pref, 0.1, 1);
+ spin->show();
+ hbox->pack_start(*spin, false, false);
+
+ hbox->show();
+
+ vbox->pack_start(*hbox, true, true);
+ }
+#undef NUM_PREFERENCES
+
+ vbox->show();
+
+ return vbox;
+}
+
+void
+Grid::init (void)
+{
+ Inkscape::Extension::build_from_mem(
+ "<inkscape-extension>\n"
+ "<name>Grid</name>\n"
+ "<id>org.inkscape.effect.grid</id>\n"
+ "<param name=\"lineWidth\" type=\"float\">1.0</param>\n"
+ "<param name=\"xspacing\" type=\"float\">10.0</param>\n"
+ "<param name=\"yspacing\" type=\"float\">10.0</param>\n"
+ "<param name=\"xoffset\" type=\"float\">5.0</param>\n"
+ "<param name=\"yoffset\" type=\"float\">5.0</param>\n"
+ "<effect>\n"
+ "<object-type>all</object-type>\n"
+ "</effect>\n"
+ "</inkscape-extension>\n", new Grid());
+ return;
+}
+
+}; /* namespace Internal */
+}; /* namespace Extension */
+}; /* namespace Inkscape */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/extension/internal/grid.h b/src/extension/internal/grid.h
new file mode 100644
index 000000000..41ac56356
--- /dev/null
+++ b/src/extension/internal/grid.h
@@ -0,0 +1,43 @@
+/*
+ * Authors:
+ * Ted Gould <ted@gould.cx>
+ *
+ * Copyright (C) 2004-2005 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "extension/implementation/implementation.h"
+#include "extension/extension-forward.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+/** \brief Implementation class of the GIMP gradient plugin. This mostly
+ just creates a namespace for the GIMP gradient plugin today.
+*/
+class Grid : public Inkscape::Extension::Implementation::Implementation {
+
+public:
+ bool load(Inkscape::Extension::Extension *module);
+ void effect(Inkscape::Extension::Effect *module, Inkscape::UI::View::View *document);
+ Gtk::Widget * prefs_effect(Inkscape::Extension::Effect *module, Inkscape::UI::View::View * view);
+
+ static void init (void);
+};
+
+}; /* namespace Internal */
+}; /* namespace Extension */
+}; /* namespace Inkscape */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/extension/internal/latex-pstricks-out.cpp b/src/extension/internal/latex-pstricks-out.cpp
new file mode 100644
index 000000000..d9db73fe6
--- /dev/null
+++ b/src/extension/internal/latex-pstricks-out.cpp
@@ -0,0 +1,128 @@
+/*
+ * Authors:
+ * Michael Forbes <miforbes@mbhs.edu>
+ *
+ * Copyright (C) 2004 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include "latex-pstricks-out.h"
+#include "sp-path.h"
+#include <print.h>
+#include "extension/system.h"
+#include "extension/print.h"
+#include "extension/db.h"
+#include "display/nr-arena.h"
+#include "display/nr-arena-item.h"
+
+
+
+
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+LatexOutput::LatexOutput (void) // The null constructor
+{
+ return;
+}
+
+LatexOutput::~LatexOutput (void) //The destructor
+{
+ return;
+}
+
+bool
+LatexOutput::check (Inkscape::Extension::Extension * module)
+{
+ if (NULL == Inkscape::Extension::db.get("org.inkscape.print.latex"))
+ return FALSE;
+ return TRUE;
+}
+
+
+void
+LatexOutput::save (Inkscape::Extension::Output *mod2, SPDocument *doc, const gchar *uri)
+{
+ Inkscape::Extension::Print *mod;
+ SPPrintContext context;
+ const gchar * oldconst;
+ gchar * oldoutput;
+ unsigned int ret;
+
+ sp_document_ensure_up_to_date (doc);
+
+ mod = Inkscape::Extension::get_print(SP_MODULE_KEY_PRINT_LATEX);
+ oldconst = mod->get_param_string("destination");
+ oldoutput = g_strdup(oldconst);
+ mod->set_param_string("destination", (gchar *)uri);
+
+ /* Start */
+ context.module = mod;
+ /* fixme: This has to go into module constructor somehow */
+ /* Create new arena */
+ mod->base = SP_ITEM (sp_document_root (doc));
+ mod->arena = NRArena::create();
+ mod->dkey = sp_item_display_key_new (1);
+ mod->root = sp_item_invoke_show (mod->base, mod->arena, mod->dkey, SP_ITEM_SHOW_DISPLAY);
+ /* Print document */
+ ret = mod->begin (doc);
+ sp_item_invoke_print (mod->base, &context);
+ ret = mod->finish ();
+ /* Release arena */
+ sp_item_invoke_hide (mod->base, mod->dkey);
+ mod->base = NULL;
+ nr_arena_item_unref (mod->root);
+ mod->root = NULL;
+ nr_object_unref ((NRObject *) mod->arena);
+ mod->arena = NULL;
+ /* end */
+
+ mod->set_param_string("destination", oldoutput);
+ g_free(oldoutput);
+
+ return;
+}
+
+/**
+ \brief A function allocate a copy of this function.
+
+ This is the definition of postscript out. This function just
+ calls the extension system with the memory allocated XML that
+ describes the data.
+*/
+void
+LatexOutput::init (void)
+{
+ Inkscape::Extension::build_from_mem(
+ "<inkscape-extension>\n"
+ "<name>LaTeX Output</name>\n"
+ "<id>org.inkscape.output.latex</id>\n"
+ "<output>\n"
+ "<extension>.tex</extension>\n"
+ "<mimetype>text/plain</mimetype>\n"
+ "<filetypename>LaTeX With PSTricks macros (*.tex)</filetypename>\n"
+ "<filetypetooltip>LaTeX PSTricks File</filetypetooltip>\n"
+ "</output>\n"
+ "</inkscape-extension>", new LatexOutput());
+
+ return;
+}
+
+} } } /* namespace Inkscape, Extension, Implementation */
+
+/*
+ Local Variables:
+ mode:cpp
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/extension/internal/latex-pstricks-out.h b/src/extension/internal/latex-pstricks-out.h
new file mode 100644
index 000000000..8e544d5b4
--- /dev/null
+++ b/src/extension/internal/latex-pstricks-out.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * Authors:
+ * Michael Forbes <miforbes-inkscape@mbhs.edu>
+ *
+ * Copyright (C) 2004 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef EXTENSION_INTERNAL_LATEX_OUT_H
+#define EXTENSION_INTERNAL_LATEX_OUT_H
+
+#include "extension/implementation/implementation.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+class LatexOutput : Inkscape::Extension::Implementation::Implementation { //This is a derived class
+
+public:
+ LatexOutput(); // Empty constructor
+
+ virtual ~LatexOutput();//Destructor
+
+ bool check(Inkscape::Extension::Extension *module); //Can this module load (always yes for now)
+
+ void save(Inkscape::Extension::Output *mod, // Save the given document to the given filename
+ SPDocument *doc,
+ gchar const *uri);
+
+ static void init(void);//Initialize the class
+};
+
+} } } /* namespace Inkscape, Extension, Implementation */
+
+#endif /* EXTENSION_INTERNAL_LATEX_OUT_H */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/extension/internal/latex-pstricks.cpp b/src/extension/internal/latex-pstricks.cpp
new file mode 100644
index 000000000..90a2128b6
--- /dev/null
+++ b/src/extension/internal/latex-pstricks.cpp
@@ -0,0 +1,362 @@
+#define __SP_LATEX_C__
+
+/*
+ * LaTeX Printing
+ *
+ * Author:
+ * Michael Forbes <miforbes@mbhs.edu>
+ *
+ * Copyright (C) 2004 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+
+#include <signal.h>
+#include <errno.h>
+
+#include "libnr/n-art-bpath.h"
+#include "sp-item.h"
+
+
+#include "style.h"
+
+#include "latex-pstricks.h"
+
+#include <unit-constants.h>
+
+#include "extension/system.h"
+#include "extension/print.h"
+
+#include "io/sys.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+PrintLatex::PrintLatex (void): _stream(NULL)
+{
+}
+
+PrintLatex::~PrintLatex (void)
+{
+ if (_stream) fclose(_stream);
+
+ /* restore default signal handling for SIGPIPE */
+#if !defined(_WIN32) && !defined(__WIN32__)
+ (void) signal(SIGPIPE, SIG_DFL);
+#endif
+ return;
+}
+
+unsigned int
+PrintLatex::setup (Inkscape::Extension::Print *mod)
+{
+ return TRUE;
+}
+
+unsigned int
+PrintLatex::begin (Inkscape::Extension::Print *mod, SPDocument *doc)
+{
+ Inkscape::SVGOStringStream os;
+ int res;
+ FILE *osf, *osp;
+ const gchar * fn;
+
+ fn = mod->get_param_string("destination");
+
+ osf = NULL;
+ osp = NULL;
+
+ gsize bytesRead = 0;
+ gsize bytesWritten = 0;
+ GError* error = NULL;
+ gchar* local_fn = g_filename_from_utf8( fn,
+ -1, &bytesRead, &bytesWritten, &error);
+ fn = local_fn;
+
+ /* TODO: Replace the below fprintf's with something that does the right thing whether in
+ * gui or batch mode (e.g. --print=blah). Consider throwing an exception: currently one of
+ * the callers (sp_print_document_to_file, "ret = mod->begin(doc)") wrongly ignores the
+ * return code.
+ */
+ if (fn != NULL) {
+ while (isspace(*fn)) fn += 1;
+ Inkscape::IO::dump_fopen_call(fn, "K");
+ osf = Inkscape::IO::fopen_utf8name(fn, "w+");
+ if (!osf) {
+ fprintf(stderr, "inkscape: fopen(%s): %s\n",
+ fn, strerror(errno));
+ return 0;
+ }
+ _stream = osf;
+ }
+
+ g_free(local_fn);
+
+ if (_stream) {
+ /* fixme: this is kinda icky */
+#if !defined(_WIN32) && !defined(__WIN32__)
+ (void) signal(SIGPIPE, SIG_IGN);
+#endif
+ }
+
+ res = fprintf(_stream, "%%LaTeX with PSTricks extensions\n");
+ /* flush this to test output stream as early as possible */
+ if (fflush(_stream)) {
+ /*g_print("caught error in sp_module_print_plain_begin\n");*/
+ if (ferror(_stream)) {
+ g_print("Error %d on output stream: %s\n", errno,
+ g_strerror(errno));
+ }
+ g_print("Printing failed\n");
+ /* fixme: should use pclose() for pipes */
+ fclose(_stream);
+ _stream = NULL;
+ fflush(stdout);
+ return 0;
+ }
+
+ // width and height in pt
+ _width = sp_document_width(doc) * PT_PER_PX;
+ _height = sp_document_height(doc) * PT_PER_PX;
+
+ NRRect d;
+ bool pageLandscape;
+ // printf("Page Bounding Box: %s\n", pageBoundingBox ? "TRUE" : "FALSE");
+/* if (pageBoundingBox) {
+ d.x0 = d.y0 = 0;
+ d.x1 = ceil(_width);
+ d.y1 = ceil(_height);
+ } else */{ // no bounding boxes for now
+ SPItem* doc_item = SP_ITEM(sp_document_root(doc));
+ sp_item_invoke_bbox(doc_item, &d, sp_item_i2r_affine(doc_item), TRUE);
+ // convert from px to pt
+ d.x0 *= PT_PER_PX;
+ d.x1 *= PT_PER_PX;
+ d.y0 *= PT_PER_PX;
+ d.y1 *= PT_PER_PX;
+ }
+
+
+ if (res >= 0) {
+
+ os << "%%Creator: " << PACKAGE_STRING << "\n";
+ os << "%%Please note this file requires PSTricks extensions\n";
+
+ // 2004 Dec 10, BFC:
+ // The point of the following code is (1) to do the thing that's expected by users
+ // who have done File>New>A4_landscape or ...letter_landscape (i.e., rotate
+ // the output), while (2) not messing up users who simply want their output wider
+ // than it is tall (e.g., small figures for inclusion in LaTeX).
+ // The original patch by WQ only had the w>h condition.
+ {
+ double w = (d.x1 - d.x0); // width and height of bounding box, in pt
+ double h = (d.y1 - d.y0);
+ pageLandscape = (
+ (w > 0. && h > 0.) // empty documents fail this sanity check, have w<0, h<0
+ && (w > h) // implies, but does not prove, the user wanted landscape
+ && (w > 600) // approximate maximum printable width of an A4
+ )
+ ? true : false;
+ }
+
+ if (pageLandscape) {
+ os << "\\rotate{90}\n";
+ }
+
+ os << "\\psset{xunit=.5pt,yunit=.5pt,runit=.5pt}\n";
+ // from now on we can output px, but they will be treated as pt
+
+ os << "\\begin{pspicture}(" << sp_document_width(doc) << "," << sp_document_height(doc) << ")\n";
+ }
+
+ return fprintf(_stream, "%s", os.str().c_str());
+}
+
+unsigned int
+PrintLatex::finish (Inkscape::Extension::Print *mod)
+{
+ int res;
+
+ if (!_stream) return 0;
+
+ res = fprintf(_stream, "\\end{pspicture}\n");
+
+ /* Flush stream to be sure. */
+ (void) fflush(_stream);
+
+ fclose(_stream);
+ _stream = NULL;
+ return 0;
+}
+
+unsigned int PrintLatex::comment (Inkscape::Extension::Print * module,
+ const char * comment)
+{
+ if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned.
+
+ return fprintf(_stream, "%%! %s\n",comment);
+}
+
+unsigned int
+PrintLatex::fill(Inkscape::Extension::Print *mod,
+ NRBPath const *bpath, NRMatrix const *transform, SPStyle const *style,
+ NRRect const *pbox, NRRect const *dbox, NRRect const *bbox)
+{
+ if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned.
+
+ if (style->fill.type == SP_PAINT_TYPE_COLOR) {
+ Inkscape::SVGOStringStream os;
+ float rgb[3];
+
+ sp_color_get_rgb_floatv(&style->fill.value.color, rgb);
+ os << "{\n\\newrgbcolor{curcolor}{" << rgb[0] << " " << rgb[1] << " " << rgb[2] << "}\n";
+
+ os << "\\pscustom[fillstyle=solid,fillcolor=curcolor]\n{\n";
+
+ print_bpath(os, bpath->path, transform);
+
+ os << "}\n}\n";
+
+ fprintf(_stream, "%s", os.str().c_str());
+ }
+
+ return 0;
+}
+
+unsigned int
+PrintLatex::stroke (Inkscape::Extension::Print *mod, const NRBPath *bpath, const NRMatrix *transform, const SPStyle *style,
+ const NRRect *pbox, const NRRect *dbox, const NRRect *bbox)
+{
+ if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned.
+
+ if (style->stroke.type == SP_PAINT_TYPE_COLOR) {
+ Inkscape::SVGOStringStream os;
+ float rgb[3];
+
+ sp_color_get_rgb_floatv(&style->stroke.value.color, rgb);
+ os << "{\n\\newrgbcolor{curcolor}{" << rgb[0] << " " << rgb[1] << " " << rgb[2] << "}\n";
+
+ os << "\\pscustom[linewidth=" << style->stroke_width.computed<< ",linecolor=curcolor";
+
+ if (style->stroke_dasharray_set &&
+ style->stroke_dash.n_dash &&
+ style->stroke_dash.dash) {
+ int i;
+ os << ",linestyle=dashed,dash=";
+ for (i = 0; i < style->stroke_dash.n_dash; i++) {
+ if ((i)) {
+ os << " ";
+ }
+ os << style->stroke_dash.dash[i];
+ }
+ }
+
+ os <<"]\n{\n";
+
+ print_bpath(os, bpath->path, transform);
+
+ os << "}\n}\n";
+
+ fprintf(_stream, "%s", os.str().c_str());
+ }
+
+ return 0;
+}
+
+void
+PrintLatex::print_bpath(SVGOStringStream &os, const NArtBpath *bp, const NRMatrix *transform)
+{
+ unsigned int closed;
+ NR::Matrix tf=*transform;
+
+
+ os << "\\newpath\n";
+ closed = FALSE;
+ while (bp->code != NR_END) {
+ using NR::X;
+ using NR::Y;
+ NR::Point const p1(bp->c(1) * tf);
+ NR::Point const p2(bp->c(2) * tf);
+ NR::Point const p3(bp->c(3) * tf);
+ double const x1 = p1[X], y1 = p1[Y];
+ double const x2 = p2[X], y2 = p2[Y];
+ double const x3 = p3[X], y3 = p3[Y];
+
+ switch (bp->code) {
+ case NR_MOVETO:
+ if (closed) {
+ os << "\\closepath\n";
+ }
+ closed = TRUE;
+ os << "\\moveto(" << x3 << "," << y3 << ")\n";
+ break;
+ case NR_MOVETO_OPEN:
+ if (closed) {
+ os << "\\closepath\n";
+ }
+ closed = FALSE;
+ os << "\\moveto(" << x3 << "," << y3 << ")\n";
+ break;
+ case NR_LINETO:
+ os << "\\lineto(" << x3 << "," << y3 << ")\n";
+ break;
+ case NR_CURVETO:
+ os << "\\curveto(" << x1 << "," << y1 << ")("
+ << x2 << "," << y2 << ")("
+ << x3 << "," << y3 << ")\n";
+ break;
+ default:
+ break;
+ }
+ bp += 1;
+ }
+ if (closed) {
+ os << "\\closepath\n";
+ }
+}
+
+bool
+PrintLatex::textToPath(Inkscape::Extension::Print * ext)
+{
+ return ext->get_param_bool("textToPath");
+}
+
+void
+PrintLatex::init (void)
+{
+ Inkscape::Extension::Extension * ext;
+
+ /* SVG in */
+ ext = Inkscape::Extension::build_from_mem(
+ "<inkscape-extension>\n"
+ "<name>LaTeX Print</name>\n"
+ "<id>" SP_MODULE_KEY_PRINT_LATEX "</id>\n"
+ "<param name=\"destination\" type=\"string\"></param>\n"
+ "<param name=\"textToPath\" type=\"boolean\">TRUE</param>\n"
+ "<print/>\n"
+ "</inkscape-extension>", new PrintLatex());
+
+ return;
+}
+
+} /* namespace Internal */
+} /* namespace Extension */
+} /* namespace Inkscape */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
+
diff --git a/src/extension/internal/latex-pstricks.h b/src/extension/internal/latex-pstricks.h
new file mode 100644
index 000000000..9238fe606
--- /dev/null
+++ b/src/extension/internal/latex-pstricks.h
@@ -0,0 +1,70 @@
+#ifndef __INKSCAPE_EXTENSION_INTERNAL_PRINT_LATEX_H__
+#define __INKSCAPE_EXTENSION_INTERNAL_PRINT_LATEX_H__
+
+/*
+ * LaTeX Printing
+ *
+ * Author:
+ * Michael Forbes <miforbes@mbhs.edu>
+ *
+ * Copyright (C) 2004 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <config.h>
+
+#include "extension/implementation/implementation.h"
+#include "extension/extension.h"
+
+#include "svg/stringstream.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+class PrintLatex : public Inkscape::Extension::Implementation::Implementation {
+
+ float _width;
+ float _height;
+ FILE * _stream;
+
+ void print_bpath (SVGOStringStream &os, const NArtBpath *bp, const NRMatrix *transform);
+
+public:
+ PrintLatex (void);
+ virtual ~PrintLatex (void);
+
+ /* Print functions */
+ virtual unsigned int setup (Inkscape::Extension::Print * module);
+
+ virtual unsigned int begin (Inkscape::Extension::Print * module, SPDocument *doc);
+ virtual unsigned int finish (Inkscape::Extension::Print * module);
+
+ /* Rendering methods */
+ virtual unsigned int fill (Inkscape::Extension::Print * module, const NRBPath *bpath, const NRMatrix *ctm, const SPStyle *style,
+ const NRRect *pbox, const NRRect *dbox, const NRRect *bbox);
+ virtual unsigned int stroke (Inkscape::Extension::Print * module, const NRBPath *bpath, const NRMatrix *transform, const SPStyle *style,
+ const NRRect *pbox, const NRRect *dbox, const NRRect *bbox);
+ virtual unsigned int comment(Inkscape::Extension::Print *module, const char * comment);
+ bool textToPath (Inkscape::Extension::Print * ext);
+
+ static void init (void);
+};
+
+} /* namespace Internal */
+} /* namespace Extension */
+} /* namespace Inkscape */
+
+#endif /* __INKSCAPE_EXTENSION_INTERNAL_PRINT_LATEX */
+
+/*
+ Local Variables:
+ mode:cpp
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/extension/internal/makefile.in b/src/extension/internal/makefile.in
new file mode 100644
index 000000000..e727234ed
--- /dev/null
+++ b/src/extension/internal/makefile.in
@@ -0,0 +1,17 @@
+# Convenience stub makefile to call the real Makefile.
+
+@SET_MAKE@
+
+# Explicit so that it's the default rule.
+all:
+ cd ../.. && $(MAKE) extension/internal/all
+
+clean %.a %.o:
+ cd ../.. && $(MAKE) extension/internal/$@
+
+.PHONY: all clean
+
+OBJEXT = @OBJEXT@
+
+.SUFFIXES:
+.SUFFIXES: .a .$(OBJEXT)
diff --git a/src/extension/internal/pov-out.cpp b/src/extension/internal/pov-out.cpp
new file mode 100644
index 000000000..29d6d48d5
--- /dev/null
+++ b/src/extension/internal/pov-out.cpp
@@ -0,0 +1,482 @@
+/*
+ * A simple utility for exporting Inkscape svg Shapes as PovRay bezier
+ * prisms. Note that this is output-only, and would thus seem to be
+ * better placed as an 'export' rather than 'output'. However, Export
+ * handles all or partial documents, while this outputs ALL shapes in
+ * the current SVG document.
+ *
+ * For information on the PovRay file format, see:
+ * http://www.povray.org
+ *
+ * Authors:
+ * Bob Jamison <rjamison@titan.com>
+ *
+ * Copyright (C) 2004 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include "pov-out.h"
+#include "inkscape.h"
+#include "sp-path.h"
+#include <style.h>
+#include "display/curve.h"
+#include "libnr/n-art-bpath.h"
+#include "extension/system.h"
+
+
+
+#include "io/sys.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+
+
+static const char *
+dstr(gchar *sbuffer, double d)
+{
+ return (const char *)g_ascii_formatd(sbuffer,
+ G_ASCII_DTOSTR_BUF_SIZE, "%.8g", (gdouble)d);
+
+}
+
+
+/**
+ * Make sure that we are in the database
+ */
+bool
+PovOutput::check (Inkscape::Extension::Extension *module)
+{
+ /* We don't need a Key
+ if (NULL == Inkscape::Extension::db.get(SP_MODULE_KEY_OUTPUT_POV))
+ return FALSE;
+ */
+
+ return TRUE;
+}
+
+
+
+
+/**
+ * This function searches the Repr tree recursively from the given node,
+ * and adds refs to all nodes with the given name, to the result vector
+ */
+static void
+findElementsByTagName(std::vector<Inkscape::XML::Node *> &results,
+ Inkscape::XML::Node *node,
+ char const *name)
+{
+ if ( !name
+ || strcmp(node->name(), name) == 0 ) {
+ results.push_back(node);
+ }
+
+ for (Inkscape::XML::Node *child = node->firstChild() ; child ; child = child->next())
+ findElementsByTagName( results, child, name );
+
+}
+
+
+/**
+ * used for saving information about shapes
+ */
+class PovShapeInfo
+{
+public:
+ PovShapeInfo()
+ {}
+ virtual ~PovShapeInfo()
+ {}
+ std::string id;
+ std::string color;
+};
+
+
+
+static double
+effective_opacity(SPItem const *item)
+{
+ double ret = 1.0;
+ for (SPObject const *obj = item; obj; obj = obj->parent) {
+ SPStyle const *const style = SP_OBJECT_STYLE(obj);
+ g_return_val_if_fail(style, ret);
+ ret *= SP_SCALE24_TO_FLOAT(style->opacity.value);
+ }
+ return ret;
+}
+
+
+/**
+ * Saves the <paths> of an Inkscape SVG file as PovRay spline definitions
+*/
+void
+PovOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *uri)
+{
+ std::vector<Inkscape::XML::Node *>results;
+ //findElementsByTagName(results, SP_ACTIVE_DOCUMENT->rroot, "path");
+ findElementsByTagName(results, SP_ACTIVE_DOCUMENT->rroot, NULL);//Check all nodes
+ if (results.size() == 0)
+ return;
+ Inkscape::IO::dump_fopen_call(uri, "L");
+ FILE *f = Inkscape::IO::fopen_utf8name(uri, "w");
+ if (!f)
+ return;
+
+ time_t tim = time(NULL);
+ fprintf(f, "/*#################################################\n");
+ fprintf(f, "### This PovRay document was generated by Inkscape\n");
+ fprintf(f, "### http://www.inkscape.org\n");
+ fprintf(f, "### Created: %s", ctime(&tim));
+ fprintf(f, "##################################################*/\n\n\n");
+
+ std::vector<PovShapeInfo>povShapes; //A list for saving information about the shapes
+
+ //we only need 8 for printf() calls that call dstr() 8 times
+ gchar s1[G_ASCII_DTOSTR_BUF_SIZE + 1];
+ gchar s2[G_ASCII_DTOSTR_BUF_SIZE + 1];
+ gchar s3[G_ASCII_DTOSTR_BUF_SIZE + 1];
+ gchar s4[G_ASCII_DTOSTR_BUF_SIZE + 1];
+ gchar s5[G_ASCII_DTOSTR_BUF_SIZE + 1];
+ gchar s6[G_ASCII_DTOSTR_BUF_SIZE + 1];
+ gchar s7[G_ASCII_DTOSTR_BUF_SIZE + 1];
+ gchar s8[G_ASCII_DTOSTR_BUF_SIZE + 1];
+
+ double bignum = 1000000.0;
+ double minx = bignum;
+ double maxx = -bignum;
+ double miny = bignum;
+ double maxy = -bignum;
+
+
+
+ unsigned indx;
+ for (indx = 0; indx < results.size() ; indx++)
+ {
+ //### Fetch the object from the repr info
+ Inkscape::XML::Node *rpath = results[indx];
+ gchar *id = (gchar *)rpath->attribute("id");
+ SPObject *reprobj = SP_ACTIVE_DOCUMENT->getObjectByRepr(rpath);
+ if (!reprobj)
+ continue;
+
+ //### Get the transform of the item
+ if (!SP_IS_ITEM(reprobj))
+ {
+ continue;
+ }
+ SPItem *item = SP_ITEM(reprobj);
+ NR::Matrix tf = sp_item_i2d_affine(item);
+
+ //### Get the Shape
+ if (!SP_IS_SHAPE(reprobj))//Bulia's suggestion. Allow all shapes
+ {
+ continue;
+ }
+ SPShape *shape = SP_SHAPE(reprobj);
+ SPCurve *curve = shape->curve;
+ if (sp_curve_empty(curve))
+ continue;
+
+ PovShapeInfo shapeInfo;
+
+ shapeInfo.id = id;
+ shapeInfo.color = "";
+
+ //Try to get the fill color of the shape
+ SPStyle *style = SP_OBJECT_STYLE(shape);
+ /* fixme: Handle other fill types, even if this means translating gradients to a single
+ flat colour. */
+ if (style && (style->fill.type == SP_PAINT_TYPE_COLOR)) {
+ // see color.h for how to parse SPColor
+ float rgb[3];
+ sp_color_get_rgb_floatv(&style->fill.value.color, rgb);
+ double const dopacity = ( SP_SCALE24_TO_FLOAT(style->fill_opacity.value)
+ * effective_opacity(shape) );
+ //gchar *str = g_strdup_printf("rgbf < %1.3f, %1.3f, %1.3f %1.3f>",
+ // rgb[0], rgb[1], rgb[2], 1.0 - dopacity);
+ gchar *str = g_strdup_printf("rgbf < %s, %s, %s %s>",
+ dstr(s1, rgb[0]), dstr(s2, rgb[1]), dstr(s3, rgb[2]), dstr(s4, 1.0 - dopacity));
+
+ shapeInfo.color += str;
+ g_free(str);
+ }
+
+ povShapes.push_back(shapeInfo); //passed all tests. save the info
+
+ int curveNr;
+
+ //Count the NR_CURVETOs/LINETOs
+ int segmentCount=0;
+ NArtBpath *bp = curve->bpath;
+ for (curveNr=0 ; curveNr<curve->length ; curveNr++, bp++)
+ if (bp->code == NR_CURVETO || bp->code == NR_LINETO)
+ segmentCount++;
+
+ bp = curve->bpath;
+ double cminx = bignum;
+ double cmaxx = -bignum;
+ double cminy = bignum;
+ double cmaxy = -bignum;
+ double lastx = 0.0;
+ double lasty = 0.0;
+
+ fprintf(f, "/*##############################################\n");
+ fprintf(f, "### PRISM: %s\n", id);
+ fprintf(f, "##############################################*/\n");
+ fprintf(f, "#declare %s = prism {\n", id);
+ fprintf(f, " linear_sweep\n");
+ fprintf(f, " bezier_spline\n");
+ fprintf(f, " 1.0, //top\n");
+ fprintf(f, " 0.0, //bottom\n");
+ fprintf(f, " %d, //nr points\n", segmentCount * 4);
+ int segmentNr = 0;
+ for (bp = curve->bpath, curveNr=0 ; curveNr<curve->length ; curveNr++, bp++) {
+ using NR::X;
+ using NR::Y;
+ NR::Point const p1(bp->c(1) * tf);
+ NR::Point const p2(bp->c(2) * tf);
+ NR::Point const p3(bp->c(3) * tf);
+ double const x1 = p1[X], y1 = p1[Y];
+ double const x2 = p2[X], y2 = p2[Y];
+ double const x3 = p3[X], y3 = p3[Y];
+
+ switch (bp->code) {
+ case NR_MOVETO:
+ case NR_MOVETO_OPEN:
+ //fprintf(f, "moveto: %f %f\n", bp->x3, bp->y3);
+ break;
+ case NR_CURVETO:
+
+ //fprintf(f, " /*%4d*/ <%f, %f>, <%f, %f>, <%f,%f>, <%f,%f>",
+ // segmentNr++, lastx, lasty, x1, y1, x2, y2, x3, y3);
+ fprintf(f, " /*%4d*/ <%s, %s>, <%s, %s>, <%s,%s>, <%s,%s>",
+ segmentNr++,
+ dstr(s1, lastx), dstr(s2, lasty),
+ dstr(s3, x1), dstr(s4, y1),
+ dstr(s5, x2), dstr(s6, y2),
+ dstr(s7, x3), dstr(s8, y3));
+
+ if (segmentNr < segmentCount)
+ fprintf(f, ",\n");
+ else
+ fprintf(f, "\n");
+
+ if (lastx < cminx)
+ cminx = lastx;
+ if (lastx > cmaxx)
+ cmaxx = lastx;
+ if (lasty < cminy)
+ cminy = lasty;
+ if (lasty > cmaxy)
+ cmaxy = lasty;
+ break;
+ case NR_LINETO:
+
+ //fprintf(f, " /*%4d*/ <%f, %f>, <%f, %f>, <%f,%f>, <%f,%f>",
+ // segmentNr++, lastx, lasty, lastx, lasty, x3, y3, x3, y3);
+ fprintf(f, " /*%4d*/ <%s, %s>, <%s, %s>, <%s,%s>, <%s,%s>",
+ segmentNr++,
+ dstr(s1, lastx), dstr(s2, lasty),
+ dstr(s3, lastx), dstr(s4, lasty),
+ dstr(s5, x3), dstr(s6, y3),
+ dstr(s7, x3), dstr(s8, y3));
+
+ if (segmentNr < segmentCount)
+ fprintf(f, ",\n");
+ else
+ fprintf(f, "\n");
+
+ //fprintf(f, "lineto\n");
+ if (lastx < cminx)
+ cminx = lastx;
+ if (lastx > cmaxx)
+ cmaxx = lastx;
+ if (lasty < cminy)
+ cminy = lasty;
+ if (lasty > cmaxy)
+ cmaxy = lasty;
+ break;
+ case NR_END:
+ //fprintf(f, "end\n");
+ break;
+ }
+ lastx = x3;
+ lasty = y3;
+ }
+ fprintf(f, "}\n");
+ /*
+ fprintf(f, "#declare %s_MIN_X = %4.3f;\n", id, cminx);
+ fprintf(f, "#declare %s_CENTER_X = %4.3f;\n", id, (cmaxx+cminx)/2.0);
+ fprintf(f, "#declare %s_MAX_X = %4.3f;\n", id, cmaxx);
+ fprintf(f, "#declare %s_WIDTH = %4.3f;\n", id, cmaxx-cminx);
+ fprintf(f, "#declare %s_MIN_Y = %4.3f;\n", id, cminy);
+ fprintf(f, "#declare %s_CENTER_Y = %4.3f;\n", id, (cmaxy+cminy)/2.0);
+ fprintf(f, "#declare %s_MAX_Y = %4.3f;\n", id, cmaxy);
+ fprintf(f, "#declare %s_HEIGHT = %4.3f;\n", id, cmaxy-cminy);
+ */
+ fprintf(f, "#declare %s_MIN_X = %s;\n", id, dstr(s1, cminx));
+ fprintf(f, "#declare %s_CENTER_X = %s;\n", id, dstr(s1, (cmaxx+cminx)/2.0));
+ fprintf(f, "#declare %s_MAX_X = %s;\n", id, dstr(s1, cmaxx));
+ fprintf(f, "#declare %s_WIDTH = %s;\n", id, dstr(s1, cmaxx-cminx));
+ fprintf(f, "#declare %s_MIN_Y = %s;\n", id, dstr(s1, cminy));
+ fprintf(f, "#declare %s_CENTER_Y = %s;\n", id, dstr(s1, (cmaxy+cminy)/2.0));
+ fprintf(f, "#declare %s_MAX_Y = %s;\n", id, dstr(s1, cmaxy));
+ fprintf(f, "#declare %s_HEIGHT = %s;\n", id, dstr(s1, cmaxy-cminy));
+ if (shapeInfo.color.length()>0)
+ fprintf(f, "#declare %s_COLOR = %s;\n",
+ id, shapeInfo.color.c_str());
+ fprintf(f, "/*##############################################\n");
+ fprintf(f, "### end %s\n", id);
+ fprintf(f, "##############################################*/\n\n\n\n");
+ if (cminx < minx)
+ minx = cminx;
+ if (cmaxx > maxx)
+ maxx = cmaxx;
+ if (cminy < miny)
+ miny = cminy;
+ if (cmaxy > maxy)
+ maxy = cmaxy;
+
+
+ }//for
+
+
+
+ //## Let's make a union of all of the Shapes
+ if (!povShapes.empty()) {
+ char const *id = "AllShapes";
+ fprintf(f, "/*##############################################\n");
+ fprintf(f, "### UNION OF ALL SHAPES IN DOCUMENT\n");
+ fprintf(f, "##############################################*/\n");
+ fprintf(f, "\n\n");
+ fprintf(f, "/**\n");
+ fprintf(f, " * Allow the user to redefine the finish{}\n");
+ fprintf(f, " * by declaring it before #including this file\n");
+ fprintf(f, " */\n");
+ fprintf(f, "#ifndef (%s_Finish)\n", id);
+ fprintf(f, "#declare %s_Finish = finish {\n", id);
+ fprintf(f, " phong 0.5\n");
+ fprintf(f, " reflection 0.3\n");
+ fprintf(f, " specular 0.5\n");
+ fprintf(f, "}\n");
+ fprintf(f, "#end\n");
+ fprintf(f, "\n\n");
+ fprintf(f, "#declare %s = union {\n", id);
+ for (unsigned i = 0 ; i < povShapes.size() ; i++) {
+ fprintf(f, " object { %s\n", povShapes[i].id.c_str());
+ fprintf(f, " texture { \n");
+ if (povShapes[i].color.length()>0)
+ fprintf(f, " pigment { %s }\n", povShapes[i].color.c_str());
+ else
+ fprintf(f, " pigment { rgb <0,0,0> }\n");
+ fprintf(f, " finish { %s_Finish }\n", id);
+ fprintf(f, " } \n");
+ fprintf(f, " } \n");
+ }
+ fprintf(f, "}\n\n\n\n");
+
+
+ double zinc = 0.2 / (double)povShapes.size();
+ fprintf(f, "/*#### Same union, but with Z-diffs (actually Y in pov) ####*/\n");
+ fprintf(f, "\n\n");
+ fprintf(f, "/**\n");
+ fprintf(f, " * Allow the user to redefine the Z-Increment\n");
+ fprintf(f, " */\n");
+ fprintf(f, "#ifndef (AllShapes_Z_Increment)\n");
+ fprintf(f, "#declare AllShapes_Z_Increment = %s;\n", dstr(s1, zinc));
+ fprintf(f, "#end\n");
+ fprintf(f, "\n");
+ fprintf(f, "#declare AllShapes_Z_Scale = 1.0;\n");
+ fprintf(f, "\n\n");
+ fprintf(f, "#declare %s_Z = union {\n", id);
+ for (unsigned i = 0 ; i < povShapes.size() ; i++) {
+ fprintf(f, " object { %s\n", povShapes[i].id.c_str());
+ fprintf(f, " texture { \n");
+ if (povShapes[i].color.length()>0)
+ fprintf(f, " pigment { %s }\n", povShapes[i].color.c_str());
+ else
+ fprintf(f, " pigment { rgb <0,0,0> }\n");
+ fprintf(f, " finish { %s_Finish }\n", id);
+ fprintf(f, " } \n");
+ fprintf(f, " scale <1, %s_Z_Scale, 1>\n", id);
+ fprintf(f, " } \n");
+ fprintf(f, "#declare %s_Z_Scale = %s_Z_Scale + %s_Z_Increment;\n\n",
+ id, id, id);
+ }
+
+ fprintf(f, "}\n");
+ /*
+ fprintf(f, "#declare %s_MIN_X = %4.3f;\n", id, minx);
+ fprintf(f, "#declare %s_CENTER_X = %4.3f;\n", id, (maxx+minx)/2.0);
+ fprintf(f, "#declare %s_MAX_X = %4.3f;\n", id, maxx);
+ fprintf(f, "#declare %s_WIDTH = %4.3f;\n", id, maxx-minx);
+ fprintf(f, "#declare %s_MIN_Y = %4.3f;\n", id, miny);
+ fprintf(f, "#declare %s_CENTER_Y = %4.3f;\n", id, (maxy+miny)/2.0);
+ fprintf(f, "#declare %s_MAX_Y = %4.3f;\n", id, maxy);
+ fprintf(f, "#declare %s_HEIGHT = %4.3f;\n", id, maxy-miny);
+ */
+ fprintf(f, "#declare %s_MIN_X = %s;\n", id, dstr(s1, minx));
+ fprintf(f, "#declare %s_CENTER_X = %s;\n", id, dstr(s1, (maxx+minx)/2.0));
+ fprintf(f, "#declare %s_MAX_X = %s;\n", id, dstr(s1, maxx));
+ fprintf(f, "#declare %s_WIDTH = %s;\n", id, dstr(s1, maxx-minx));
+ fprintf(f, "#declare %s_MIN_Y = %s;\n", id, dstr(s1, miny));
+ fprintf(f, "#declare %s_CENTER_Y = %s;\n", id, dstr(s1, (maxy+miny)/2.0));
+ fprintf(f, "#declare %s_MAX_Y = %s;\n", id, dstr(s1, maxy));
+ fprintf(f, "#declare %s_HEIGHT = %s;\n", id, dstr(s1, maxy-miny));
+ fprintf(f, "/*##############################################\n");
+ fprintf(f, "### end %s\n", id);
+ fprintf(f, "##############################################*/\n\n\n\n");
+ }
+
+ //All done
+ fclose(f);
+}
+
+/**
+ * This is the definition of PovRay output. This function just
+ * calls the extension system with the memory allocated XML that
+ * describes the data.
+*/
+void
+PovOutput::init()
+{
+ Inkscape::Extension::build_from_mem(
+ "<inkscape-extension>\n"
+ "<name>PovRay Output</name>\n"
+ "<id>org.inkscape.output.pov</id>\n"
+ "<output>\n"
+ "<extension>.pov</extension>\n"
+ "<mimetype>text/x-povray-script</mimetype>\n"
+ "<filetypename>PovRay (*.pov) (export splines)</filetypename>\n"
+ "<filetypetooltip>PovRay Raytracer File</filetypetooltip>\n"
+ "</output>\n"
+ "</inkscape-extension>",
+ new PovOutput());
+}
+
+
+
+
+
+} //namespace Internal
+} //namespace Extension
+} //namespace Inkscape
+
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/extension/internal/pov-out.h b/src/extension/internal/pov-out.h
new file mode 100644
index 000000000..7e71d121c
--- /dev/null
+++ b/src/extension/internal/pov-out.h
@@ -0,0 +1,52 @@
+/*
+ * A simple utility for exporting Inkscape svg Shapes as PovRay bezier
+ * prisms. Note that this is output-only, and would thus seem to be
+ * better placed as an 'export' rather than 'output'. However, Export
+ * handles all or partial documents, while this outputs ALL shapes in
+ * the current SVG document.
+ *
+ * Authors:
+ * Bob Jamison <rjamison@titan.com>
+ *
+ * Copyright (C) 2004 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef EXTENSION_INTERNAL_POV_OUT_H
+#define EXTENSION_INTERNAL_POV_OUT_H
+
+#include <glib.h>
+#include "extension/implementation/implementation.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+class PovOutput : public Inkscape::Extension::Implementation::Implementation
+{
+
+ public:
+
+ bool check (Inkscape::Extension::Extension * module);
+
+ void save (Inkscape::Extension::Output *mod,
+ SPDocument *doc,
+ const gchar *uri);
+
+ static void init (void);
+
+
+};
+
+
+
+
+} //namespace Internal
+} //namespace Extension
+} //namespace Inkscape
+
+
+
+#endif /* EXTENSION_INTERNAL_POV_OUT_H */
+
diff --git a/src/extension/internal/ps-out.cpp b/src/extension/internal/ps-out.cpp
new file mode 100644
index 000000000..a41b90007
--- /dev/null
+++ b/src/extension/internal/ps-out.cpp
@@ -0,0 +1,94 @@
+/*
+ * A quick hack to use the print output to write out a file. This
+ * then makes 'save as...' Postscript.
+ *
+ * Authors:
+ * Ted Gould <ted@gould.cx>
+ *
+ * Copyright (C) 2004 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include "ps-out.h"
+#include <print.h>
+#include "extension/system.h"
+#include "extension/db.h"
+#include "extension/output.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+bool
+PsOutput::check (Inkscape::Extension::Extension * module)
+{
+ if (NULL == Inkscape::Extension::db.get(SP_MODULE_KEY_PRINT_PS))
+ return FALSE;
+
+ return TRUE;
+}
+
+/**
+ \brief This function calls the print system with the filename
+ \param mod unused
+ \param doc Document to be saved
+ \param uri Filename to save to (probably will end in .ps)
+
+ The most interesting thing that this function does is just attach
+ an '>' on the front of the filename. This is the syntax used to
+ tell the printing system to save to file.
+*/
+void
+PsOutput::save (Inkscape::Extension::Output *mod, SPDocument *doc, const gchar *uri)
+{
+ Inkscape::Extension::Extension * ext;
+
+ ext = Inkscape::Extension::db.get(SP_MODULE_KEY_PRINT_PS);
+ if (ext == NULL)
+ return;
+
+ bool old_textToPath = ext->get_param_bool("textToPath");
+ bool new_val = mod->get_param_bool("textToPath");
+ ext->set_param_bool("textToPath", new_val);
+
+ gchar * final_name;
+ final_name = g_strdup_printf("> %s", uri);
+ sp_print_document_to_file(doc, final_name);
+ g_free(final_name);
+
+ ext->set_param_bool("textToPath", old_textToPath);
+
+ return;
+}
+
+/**
+ \brief A function allocate a copy of this function.
+
+ This is the definition of postscript out. This function just
+ calls the extension system with the memory allocated XML that
+ describes the data.
+*/
+void
+PsOutput::init (void)
+{
+ Inkscape::Extension::build_from_mem(
+ "<inkscape-extension>\n"
+ "<name>Postscript Output</name>\n"
+ "<id>org.inkscape.output.ps</id>\n"
+ "<param name=\"textToPath\" gui-text=\"Text to Path\" type=\"boolean\">true</param>\n"
+ "<output>\n"
+ "<extension>.ps</extension>\n"
+ "<mimetype>image/x-postscript</mimetype>\n"
+ "<filetypename>Postscript (*.ps)</filetypename>\n"
+ "<filetypetooltip>Postscript File</filetypetooltip>\n"
+ "</output>\n"
+ "</inkscape-extension>", new PsOutput());
+
+ return;
+}
+
+} } } /* namespace Inkscape, Extension, Implementation */
diff --git a/src/extension/internal/ps-out.h b/src/extension/internal/ps-out.h
new file mode 100644
index 000000000..592f3d70e
--- /dev/null
+++ b/src/extension/internal/ps-out.h
@@ -0,0 +1,45 @@
+/*
+ * A quick hack to use the print output to write out a file. This
+ * then makes 'save as...' Postscript.
+ *
+ * Authors:
+ * Ted Gould <ted@gould.cx>
+ *
+ * Copyright (C) 2004 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef EXTENSION_INTERNAL_PS_OUT_H
+#define EXTENSION_INTERNAL_PS_OUT_H
+
+#include "extension/implementation/implementation.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+class PsOutput : Inkscape::Extension::Implementation::Implementation {
+
+public:
+ bool check(Inkscape::Extension::Extension *module);
+ void save(Inkscape::Extension::Output *mod,
+ SPDocument *doc,
+ gchar const *uri);
+ static void init();
+};
+
+} } } /* namespace Inkscape, Extension, Implementation */
+
+#endif /* !EXTENSION_INTERNAL_PS_OUT_H */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/extension/internal/ps.cpp b/src/extension/internal/ps.cpp
new file mode 100644
index 000000000..2b3103f40
--- /dev/null
+++ b/src/extension/internal/ps.cpp
@@ -0,0 +1,1264 @@
+#define __SP_PS_C__
+
+/** \file
+ * PostScript printing.
+ */
+/*
+ * Authors:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ * bulia byak <buliabyak@users.sf.net>
+ *
+ * Basic printing code, EXCEPT image and
+ * ascii85 filter is in public domain
+ *
+ * Image printing and Ascii85 filter:
+ *
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ * Copyright (C) 1997-98 Peter Kirchgessner
+ * George White <aa056@chebucto.ns.ca>
+ * Austin Donnelly <austin@gimp.org>
+ *
+ * Licensed under GNU GPL
+ */
+
+/* Plain Print */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <signal.h>
+#include <errno.h>
+
+#include <libnr/n-art-bpath.h>
+
+#include <gtk/gtkstock.h>
+#include <gtk/gtkvbox.h>
+#include <gtk/gtkframe.h>
+#include <gtk/gtkradiobutton.h>
+#include <gtk/gtkcombo.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtktooltips.h>
+
+#include <glibmm/i18n.h>
+#include "display/nr-arena-item.h"
+#include "display/canvas-bpath.h"
+#include "sp-item.h"
+#include "style.h"
+#include "sp-linear-gradient.h"
+#include "sp-radial-gradient.h"
+
+#include "libnrtype/font-instance.h"
+#include "libnrtype/font-style-to-pos.h"
+
+#include <unit-constants.h>
+
+#include "ps.h"
+#include "extension/system.h"
+#include "extension/print.h"
+
+#include "io/sys.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+PrintPS::PrintPS() :
+ _stream(NULL),
+ _dpi(72),
+ _bitmap(false)
+{
+}
+
+PrintPS::~PrintPS(void)
+{
+ /* fixme: should really use pclose for popen'd streams */
+ if (_stream) fclose(_stream);
+
+ /* restore default signal handling for SIGPIPE */
+#if !defined(_WIN32) && !defined(__WIN32__)
+ (void) signal(SIGPIPE, SIG_DFL);
+#endif
+
+ return;
+}
+
+unsigned int
+PrintPS::setup(Inkscape::Extension::Print * mod)
+{
+ static gchar const *const pdr[] = {"72", "75", "100", "144", "150", "200", "300", "360", "600", "1200", "2400", NULL};
+
+#ifdef TED
+ Inkscape::XML::Node *repr = ((SPModule *) mod)->repr;
+#endif
+
+ unsigned int ret = FALSE;
+
+ /* Create dialog */
+ GtkTooltips *tt = gtk_tooltips_new();
+ g_object_ref((GObject *) tt);
+ gtk_object_sink((GtkObject *) tt);
+
+ GtkWidget *dlg = gtk_dialog_new_with_buttons(_("Print Destination"),
+// SP_DT_WIDGET(SP_ACTIVE_DESKTOP)->window,
+ NULL,
+ (GtkDialogFlags) (GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_DESTROY_WITH_PARENT),
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL,
+ GTK_STOCK_PRINT,
+ GTK_RESPONSE_OK,
+ NULL);
+
+ gtk_dialog_set_default_response(GTK_DIALOG(dlg), GTK_RESPONSE_OK);
+
+ GtkWidget *vbox = GTK_DIALOG(dlg)->vbox;
+ gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
+ /* Print properties frame */
+ GtkWidget *f = gtk_frame_new(_("Print properties"));
+ gtk_box_pack_start(GTK_BOX(vbox), f, FALSE, FALSE, 4);
+ GtkWidget *vb = gtk_vbox_new(FALSE, 4);
+ gtk_container_add(GTK_CONTAINER(f), vb);
+ gtk_container_set_border_width(GTK_CONTAINER(vb), 4);
+ /* Print type */
+ bool const p2bm = mod->get_param_bool("bitmap");
+ GtkWidget *rb = gtk_radio_button_new_with_label(NULL, _("Print using PostScript operators"));
+ gtk_tooltips_set_tip((GtkTooltips *) tt, rb,
+ _("Use PostScript vector operators. The resulting image is usually smaller "
+ "in file size and can be arbitrarily scaled, but alpha transparency "
+ "and patterns will be lost."), NULL);
+ if (!p2bm) gtk_toggle_button_set_active((GtkToggleButton *) rb, TRUE);
+ gtk_box_pack_start(GTK_BOX(vb), rb, FALSE, FALSE, 0);
+ rb = gtk_radio_button_new_with_label(gtk_radio_button_get_group((GtkRadioButton *) rb), _("Print as bitmap"));
+ gtk_tooltips_set_tip((GtkTooltips *) tt, rb,
+ _("Print everything as bitmap. The resulting image is usually larger "
+ "in file size and cannot be arbitrarily scaled without quality loss, "
+ "but all objects will be rendered exactly as displayed."), NULL);
+ if (p2bm) gtk_toggle_button_set_active((GtkToggleButton *) rb, TRUE);
+ gtk_box_pack_start(GTK_BOX(vb), rb, FALSE, FALSE, 0);
+ /* Resolution */
+ GtkWidget *hb = gtk_hbox_new(FALSE, 4);
+ gtk_box_pack_start(GTK_BOX(vb), hb, FALSE, FALSE, 0);
+ GtkWidget *combo = gtk_combo_new();
+ gtk_combo_set_value_in_list(GTK_COMBO(combo), FALSE, FALSE);
+ gtk_combo_set_use_arrows(GTK_COMBO(combo), TRUE);
+ gtk_combo_set_use_arrows_always(GTK_COMBO(combo), TRUE);
+ gtk_widget_set_size_request(combo, 64, -1);
+ gtk_tooltips_set_tip((GtkTooltips *) tt, GTK_COMBO(combo)->entry,
+ _("Preferred resolution (dots per inch) of bitmap"), NULL);
+ /* Setup strings */
+ GList *sl = NULL;
+ for (unsigned i = 0; pdr[i] != NULL; i++) {
+ sl = g_list_prepend(sl, (gpointer) pdr[i]);
+ }
+ sl = g_list_reverse(sl);
+ gtk_combo_set_popdown_strings(GTK_COMBO(combo), sl);
+ g_list_free(sl);
+ if (1) {
+ gchar const *val = mod->get_param_string("resolution");
+ gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(combo)->entry), val);
+ }
+ gtk_box_pack_end(GTK_BOX(hb), combo, FALSE, FALSE, 0);
+ GtkWidget *l = gtk_label_new(_("Resolution:"));
+ gtk_box_pack_end(GTK_BOX(hb), l, FALSE, FALSE, 0);
+
+ /* Print destination frame */
+ f = gtk_frame_new(_("Print destination"));
+ gtk_box_pack_start(GTK_BOX(vbox), f, FALSE, FALSE, 4);
+ vb = gtk_vbox_new(FALSE, 4);
+ gtk_container_add(GTK_CONTAINER(f), vb);
+ gtk_container_set_border_width(GTK_CONTAINER(vb), 4);
+
+ l = gtk_label_new(_("Printer name (as given by lpstat -p);\n"
+ "leave empty to use the system default printer.\n"
+ "Use '> filename' to print to file.\n"
+ "Use '| prog arg...' to pipe to a program."));
+ gtk_box_pack_start(GTK_BOX(vb), l, FALSE, FALSE, 0);
+
+ GtkWidget *e = gtk_entry_new();
+ if (1) {
+ gchar const *val = mod->get_param_string("destination");
+ gtk_entry_set_text(GTK_ENTRY(e), ( val != NULL
+ ? val
+ : "" ));
+ }
+ gtk_box_pack_start(GTK_BOX(vb), e, FALSE, FALSE, 0);
+
+ // pressing enter in the destination field is the same as clicking Print:
+ gtk_entry_set_activates_default(GTK_ENTRY(e), TRUE);
+
+ gtk_widget_show_all(vbox);
+
+ int const response = gtk_dialog_run(GTK_DIALOG(dlg));
+
+ g_object_unref((GObject *) tt);
+
+ if (response == GTK_RESPONSE_OK) {
+ gchar const *fn;
+ char const *sstr;
+
+ _bitmap = gtk_toggle_button_get_active((GtkToggleButton *) rb);
+ sstr = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo)->entry));
+ _dpi = (unsigned int) MAX((int)(atof(sstr)), 1);
+ /* Arrgh, have to do something */
+ fn = gtk_entry_get_text(GTK_ENTRY(e));
+ /* skip leading whitespace, bug #1068483 */
+ while (fn && *fn==' ') { fn++; }
+ /* g_print("Printing to %s\n", fn); */
+
+ mod->set_param_bool("bitmap", _bitmap);
+ mod->set_param_string("resolution", (gchar *)sstr);
+ mod->set_param_string("destination", (gchar *)fn);
+ ret = TRUE;
+ }
+
+ gtk_widget_destroy(dlg);
+
+ return ret;
+}
+
+unsigned int
+PrintPS::begin(Inkscape::Extension::Print *mod, SPDocument *doc)
+{
+ gboolean epsexport = false;
+
+ _latin1_encoded_fonts.clear();
+ _newlatin1font_proc_defined = false;
+
+ FILE *osf = NULL;
+ FILE *osp = NULL;
+
+ gsize bytesRead = 0;
+ gsize bytesWritten = 0;
+ GError *error = NULL;
+ gchar const *utf8_fn = mod->get_param_string("destination");
+ gchar *local_fn = g_filename_from_utf8( utf8_fn,
+ -1, &bytesRead, &bytesWritten, &error);
+ gchar const *fn = local_fn;
+
+ /* TODO: Replace the below fprintf's with something that does the right thing whether in
+ * gui or batch mode (e.g. --print=blah). Consider throwing an exception: currently one of
+ * the callers (sp_print_document_to_file, "ret = mod->begin(doc)") wrongly ignores the
+ * return code.
+ */
+ if (fn != NULL) {
+ if (*fn == '|') {
+ fn += 1;
+ while (isspace(*fn)) fn += 1;
+#ifndef WIN32
+ osp = popen(fn, "w");
+#else
+ osp = _popen(fn, "w");
+#endif
+ if (!osp) {
+ fprintf(stderr, "inkscape: popen(%s): %s\n",
+ fn, strerror(errno));
+ return 0;
+ }
+ _stream = osp;
+ } else if (*fn == '>') {
+ fn += 1;
+ epsexport = g_str_has_suffix(fn,".eps");
+ while (isspace(*fn)) fn += 1;
+ Inkscape::IO::dump_fopen_call(fn, "K");
+ osf = Inkscape::IO::fopen_utf8name(fn, "w+");
+ if (!osf) {
+ fprintf(stderr, "inkscape: fopen(%s): %s\n",
+ fn, strerror(errno));
+ return 0;
+ }
+ _stream = osf;
+ } else {
+ /* put cwd stuff in here */
+ gchar *qn = ( *fn
+ ? g_strdup_printf("lpr -P %s", fn) /* FIXME: quote fn */
+ : g_strdup("lpr") );
+#ifndef WIN32
+ osp = popen(qn, "w");
+#else
+ osp = _popen(qn, "w");
+#endif
+ if (!osp) {
+ fprintf(stderr, "inkscape: popen(%s): %s\n",
+ qn, strerror(errno));
+ return 0;
+ }
+ g_free(qn);
+ _stream = osp;
+ }
+ }
+
+ g_free(local_fn);
+
+ if (_stream) {
+ /* fixme: this is kinda icky */
+#if !defined(_WIN32) && !defined(__WIN32__)
+ (void) signal(SIGPIPE, SIG_IGN);
+#endif
+ }
+
+ int const res = fprintf(_stream, ( epsexport
+ ? "%%!PS-Adobe-3.0 EPSF-3.0\n"
+ : "%%!PS-Adobe-3.0\n" ));
+ /* flush this to test output stream as early as possible */
+ if (fflush(_stream)) {
+ /*g_print("caught error in sp_module_print_plain_begin\n");*/
+ if (ferror(_stream)) {
+ g_print("Error %d on output stream: %s\n", errno,
+ g_strerror(errno));
+ }
+ g_print("Printing failed\n");
+ /* fixme: should use pclose() for pipes */
+ fclose(_stream);
+ _stream = NULL;
+ fflush(stdout);
+ return 0;
+ }
+
+ // width and height in pt
+ _width = sp_document_width(doc) * PT_PER_PX;
+ _height = sp_document_height(doc) * PT_PER_PX;
+
+ NRRect d;
+ bool pageBoundingBox;
+ bool pageLandscape;
+ pageBoundingBox = mod->get_param_bool("pageBoundingBox");
+ // printf("Page Bounding Box: %s\n", pageBoundingBox ? "TRUE" : "FALSE");
+ if (pageBoundingBox) {
+ d.x0 = d.y0 = 0;
+ d.x1 = ceil(_width);
+ d.y1 = ceil(_height);
+ } else {
+ SPItem* doc_item = SP_ITEM(sp_document_root(doc));
+ sp_item_invoke_bbox(doc_item, &d, sp_item_i2r_affine(doc_item), TRUE);
+ // convert from px to pt
+ d.x0 *= PT_PER_PX;
+ d.x1 *= PT_PER_PX;
+ d.y0 *= PT_PER_PX;
+ d.y1 *= PT_PER_PX;
+ }
+
+ Inkscape::SVGOStringStream os;
+ if (res >= 0) {
+
+ os << "%%Creator: " << PACKAGE_STRING << "\n";
+ // This will become problematic if inkscape gains the
+ // ability to handle multi paged documents. If this is
+ // the case the %%Orientation: comments should be
+ // renamed to %%PageOrientation: and moved to the
+ // respective pages.
+ os << "%%Pages: 1\n";
+
+ // 2004 Dec 10, BFC:
+ // The point of the following code is (1) to do the thing that's expected by users
+ // who have done File>New>A4_landscape or ...letter_landscape (i.e., rotate
+ // the output), while (2) not messing up users who simply want their output wider
+ // than it is tall (e.g., small figures for inclusion in LaTeX).
+ // The original patch by WQ only had the w>h condition.
+ {
+ double w = (d.x1 - d.x0); // width and height of bounding box, in pt
+ double h = (d.y1 - d.y0);
+ pageLandscape = (
+ (w > 0. && h > 0.) // empty documents fail this sanity check, have w<0, h<0
+ && (w > h) // implies, but does not prove, the user wanted landscape
+ && (w > 600) // approximate maximum printable width of an A4
+ && (!epsexport) // eps should always be portrait
+ )
+ ? true : false;
+ }
+
+ if (pageLandscape) {
+ os << "%%Orientation: Landscape\n";
+ os << "%%BoundingBox: " << (int) (_height - d.y1) << " "
+ << (int) d.x0 << " "
+ << (int) ceil(_height - d.y0) << " "
+ << (int) ceil(d.x1) << "\n";
+ // According to Mike Sweet (the author of CUPS)
+ // HiResBoundingBox is only appropriate
+ // for EPS files. This means that we should
+ // distinguish if we export to ps or eps here.
+ // FIXME: I couldn't find HiResBoundingBox in the PS
+ // reference manual, so I guess we should skip
+ // it.
+ os << "%%HiResBoundingBox: " << (_height - d.y1) << " "
+ << d.x0 << " "
+ << (_height - d.y0) << " "
+ << d.x1 << "\n";
+ } else {
+ os << "%%Orientation: Portrait\n";
+ os << "%%BoundingBox: " << (int) d.x0 << " "
+ << (int) d.y0 << " "
+ << (int) ceil(d.x1) << " "
+ << (int) ceil(d.y1) << "\n";
+ os << "%%HiResBoundingBox: " << d.x0 << " "
+ << d.y0 << " "
+ << d.x1 << " "
+ << d.y1 << "\n";
+ }
+
+ os << "%%EndComments\n";
+ // This will become problematic if we print multi paged documents:
+ os << "%%Page: 1 1\n";
+
+ if (pageLandscape) {
+ os << "90 rotate\n";
+ if (_bitmap) {
+ os << "0 " << (int) -ceil(_height) << " translate\n";
+ }
+ } else {
+ if (!_bitmap) {
+ os << "0 " << (int) ceil(_height) << " translate\n";
+ }
+ }
+
+ if (!_bitmap) {
+ os << PT_PER_PX << " " << -PT_PER_PX << " scale\n";
+ // from now on we can output px, but they will be treated as pt
+ }
+ }
+
+ /* FIXME: This function is declared to return unsigned, whereas fprintf returns a signed int *
+ * that can be zero if the first fprintf failed (os is empty) or "negative" (i.e. very positive
+ * in unsigned int interpretation) if the first fprintf failed but this one succeeds, or
+ * positive if both succeed. */
+ return fprintf(_stream, "%s", os.str().c_str());
+}
+
+unsigned int
+PrintPS::finish(Inkscape::Extension::Print *mod)
+{
+ if (!_stream) return 0;
+
+ if (_bitmap) {
+ double const dots_per_pt = _dpi / PT_PER_IN;
+
+ double const x0 = 0.0;
+ double const y0 = 0.0;
+ double const x1 = x0 + _width;
+ double const y1 = y0 + _height;
+
+ /* Bitmap width/height in bitmap dots. */
+ int const width = (int) (_width * dots_per_pt + 0.5);
+ int const height = (int) (_height * dots_per_pt + 0.5);
+
+ NRMatrix affine;
+ affine.c[0] = width / ((x1 - x0) * PX_PER_PT);
+ affine.c[1] = 0.0;
+ affine.c[2] = 0.0;
+ affine.c[3] = height / ((y1 - y0) * PX_PER_PT);
+ affine.c[4] = -affine.c[0] * x0;
+ affine.c[5] = -affine.c[3] * y0;
+
+ nr_arena_item_set_transform(mod->root, &affine);
+
+ guchar *const px = nr_new(guchar, 4 * width * 64);
+
+ for (int y = 0; y < height; y += 64) {
+ /* Set area of interest. */
+ NRRectL bbox;
+ bbox.x0 = 0;
+ bbox.y0 = y;
+ bbox.x1 = width;
+ bbox.y1 = MIN(height, y + 64);
+
+ /* Update to renderable state. */
+ NRGC gc(NULL);
+ nr_matrix_set_identity(&gc.transform);
+ nr_arena_item_invoke_update(mod->root, &bbox, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE);
+ /* Render */
+ /* This should take guchar* instead of unsigned char*) */
+ NRPixBlock pb;
+ nr_pixblock_setup_extern(&pb, NR_PIXBLOCK_MODE_R8G8B8A8N,
+ bbox.x0, bbox.y0, bbox.x1, bbox.y1,
+ (guchar*)px, 4 * width, FALSE, FALSE);
+ memset(px, 0xff, 4 * width * 64);
+ nr_arena_item_invoke_render(mod->root, &bbox, &pb, 0);
+ /* Blitter goes here */
+ NRMatrix imgt;
+ imgt.c[0] = (bbox.x1 - bbox.x0) / dots_per_pt;
+ imgt.c[1] = 0.0;
+ imgt.c[2] = 0.0;
+ imgt.c[3] = (bbox.y1 - bbox.y0) / dots_per_pt;
+ imgt.c[4] = 0.0;
+ imgt.c[5] = _height - y / dots_per_pt - (bbox.y1 - bbox.y0) / dots_per_pt;
+
+ print_image(_stream, px, bbox.x1 - bbox.x0, bbox.y1 - bbox.y0, 4 * width, &imgt);
+ }
+
+ nr_free(px);
+ }
+
+ int const res = fprintf(_stream, "showpage\n");
+
+ /* Flush stream to be sure. */
+ (void) fflush(_stream);
+
+ /* fixme: should really use pclose for popen'd streams */
+ fclose(_stream);
+ _stream = 0;
+ _latin1_encoded_fonts.clear();
+
+ return res;
+}
+
+unsigned int
+PrintPS::bind(Inkscape::Extension::Print *mod, NRMatrix const *transform, float opacity)
+{
+ if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned.
+ if (_bitmap) return 0;
+
+ Inkscape::SVGOStringStream os;
+ os << "gsave [" << transform->c[0] << " "
+ << transform->c[1] << " "
+ << transform->c[2] << " "
+ << transform->c[3] << " "
+ << transform->c[4] << " "
+ << transform->c[5] << "] concat\n";
+
+ return fprintf(_stream, "%s", os.str().c_str());
+}
+
+unsigned int
+PrintPS::release(Inkscape::Extension::Print *mod)
+{
+ if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned.
+ if (_bitmap) return 0;
+
+ return fprintf(_stream, "grestore\n");
+}
+
+unsigned int
+PrintPS::comment(Inkscape::Extension::Print *mod, char const *comment)
+{
+ if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned.
+ if (_bitmap) return 0;
+
+ return fprintf(_stream, "%%! %s\n",comment);
+}
+
+void
+PrintPS::print_fill_style(SVGOStringStream &os, SPStyle const *const style, NRRect const *pbox)
+{
+ g_return_if_fail( style->fill.type == SP_PAINT_TYPE_COLOR
+ || ( style->fill.type == SP_PAINT_TYPE_PAINTSERVER
+ && SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style)) ) );
+
+ if (style->fill.type == SP_PAINT_TYPE_COLOR) {
+ float rgb[3];
+ sp_color_get_rgb_floatv(&style->fill.value.color, rgb);
+
+ os << rgb[0] << " " << rgb[1] << " " << rgb[2] << " setrgbcolor\n";
+
+ } else {
+ g_assert( style->fill.type == SP_PAINT_TYPE_PAINTSERVER
+ && SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style)) );
+
+ if (SP_IS_LINEARGRADIENT(SP_STYLE_FILL_SERVER(style))) {
+
+ SPLinearGradient *lg = SP_LINEARGRADIENT(SP_STYLE_FILL_SERVER(style));
+ NR::Point p1 (lg->x1.computed, lg->y1.computed);
+ NR::Point p2 (lg->x2.computed, lg->y2.computed);
+ if (pbox && SP_GRADIENT(lg)->units == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) {
+ // convert to userspace
+ NR::Matrix bbox2user(pbox->x1 - pbox->x0, 0, 0, pbox->y1 - pbox->y0, pbox->x0, pbox->y0);
+ p1 *= bbox2user;
+ p2 *= bbox2user;
+ }
+
+ os << "<<\n/ShadingType 2\n/ColorSpace /DeviceRGB\n";
+ os << "/Coords [" << p1[NR::X] << " " << p1[NR::Y] << " " << p2[NR::X] << " " << p2[NR::Y] <<"]\n";
+ os << "/Extend [true true]\n";
+ os << "/Domain [0 1]\n";
+ os << "/Function <<\n/FunctionType 3\n/Functions\n[\n";
+
+ sp_gradient_ensure_vector(SP_GRADIENT(lg)); // when exporting from commandline, vector is not built
+ for (unsigned i = 0; i + 1 < lg->vector.stops.size(); i++) {
+ float rgb[3];
+ sp_color_get_rgb_floatv(&lg->vector.stops[i].color, rgb);
+ os << "<<\n/FunctionType 2\n/Domain [0 1]\n";
+ os << "/C0 [" << rgb[0] << " " << rgb[1] << " " << rgb[2] << "]\n";
+ sp_color_get_rgb_floatv(&lg->vector.stops[i+1].color, rgb);
+ os << "/C1 [" << rgb[0] << " " << rgb[1] << " " << rgb[2] << "]\n";
+ os << "/N 1\n>>\n";
+ }
+ os << "]\n/Domain [0 1]\n";
+ os << "/Bounds [ ";
+ for (unsigned i = 0; i + 2 < lg->vector.stops.size(); i++) {
+ os << lg->vector.stops[i+1].offset <<" ";
+ }
+ os << "]\n";
+ os << "/Encode [ ";
+ for (unsigned i = 0; i + 1 < lg->vector.stops.size(); i++) {
+ os << "0 1 ";
+ }
+ os << "]\n";
+ os << ">>\n>>\n";
+
+ } else if (SP_IS_RADIALGRADIENT(SP_STYLE_FILL_SERVER(style))) {
+
+ SPRadialGradient *rg = SP_RADIALGRADIENT(SP_STYLE_FILL_SERVER(style));
+ NR::Point c(rg->cx.computed, rg->cy.computed);
+ NR::Point f(rg->fx.computed, rg->fy.computed);
+ double r = rg->r.computed;
+ if (pbox && SP_GRADIENT(rg)->units == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) {
+ // convert to userspace
+ NR::Matrix const bbox2user(pbox->x1 - pbox->x0, 0,
+ 0, pbox->y1 - pbox->y0,
+ pbox->x0, pbox->y0);
+ c *= bbox2user;
+ f *= bbox2user;
+ r *= bbox2user.expansion();
+ }
+
+ os << "<<\n/ShadingType 3\n/ColorSpace /DeviceRGB\n";
+ os << "/Coords ["<< f[NR::X] <<" "<< f[NR::Y] <<" 0 "<< c[NR::X] <<" "<< c[NR::Y] <<" "<< r <<"]\n";
+ os << "/Extend [true true]\n";
+ os << "/Domain [0 1]\n";
+ os << "/Function <<\n/FunctionType 3\n/Functions\n[\n";
+
+ sp_gradient_ensure_vector(SP_GRADIENT(rg)); // when exporting from commandline, vector is not built
+ for (unsigned i = 0; i + 1 < rg->vector.stops.size(); i++) {
+ float rgb[3];
+ sp_color_get_rgb_floatv(&rg->vector.stops[i].color, rgb);
+ os << "<<\n/FunctionType 2\n/Domain [0 1]\n";
+ os << "/C0 [" << rgb[0] << " " << rgb[1] << " " << rgb[2] << "]\n";
+ sp_color_get_rgb_floatv(&rg->vector.stops[i+1].color, rgb);
+ os << "/C1 [" << rgb[0] << " " << rgb[1] << " " << rgb[2] << "]\n";
+ os << "/N 1\n>>\n";
+ }
+ os << "]\n/Domain [0 1]\n";
+ os << "/Bounds [ ";
+ for (unsigned i = 0; i + 2 < rg->vector.stops.size(); i++) {
+ os << rg->vector.stops[i+1].offset << " ";
+ }
+ os << "]\n";
+ os << "/Encode [ ";
+ for (unsigned i = 0; i + 1 < rg->vector.stops.size(); i++) {
+ os << "0 1 ";
+ }
+ os << "]\n";
+ os << ">>\n>>\n";
+ }
+ }
+}
+
+void
+PrintPS::print_stroke_style(SVGOStringStream &os, SPStyle const *style)
+{
+ float rgb[3];
+ sp_color_get_rgb_floatv(&style->stroke.value.color, rgb);
+
+ os << rgb[0] << " " << rgb[1] << " " << rgb[2] << " setrgbcolor\n";
+
+ // There are rare cases in which for a solid line stroke_dasharray_set is true. To avoid
+ // invalid PS-lines such as "[0.0000000 0.0000000] 0.0000000 setdash", which should be "[] 0 setdash",
+ // we first check if all components of stroke_dash.dash are 0.
+ bool LineSolid = true;
+ if (style->stroke_dasharray_set &&
+ style->stroke_dash.n_dash &&
+ style->stroke_dash.dash )
+ {
+ int i = 0;
+ while (LineSolid && (i < style->stroke_dash.n_dash)) {
+ i++;
+ if (style->stroke_dash.dash[i] > 0.00000001)
+ LineSolid = false;
+ }
+ if (!LineSolid) {
+ os << "[";
+ for (i = 0; i < style->stroke_dash.n_dash; i++) {
+ if (i > 0) {
+ os << " ";
+ }
+ os << style->stroke_dash.dash[i];
+ }
+ os << "] " << style->stroke_dash.offset << " setdash\n";
+ } else {
+ os << "[] 0 setdash\n";
+ }
+ } else {
+ os << "[] 0 setdash\n";
+ }
+
+ os << style->stroke_width.computed << " setlinewidth\n";
+ os << style->stroke_linejoin.computed << " setlinejoin\n";
+ os << style->stroke_linecap.computed << " setlinecap\n";
+}
+
+
+unsigned int
+PrintPS::fill(Inkscape::Extension::Print *mod, NRBPath const *bpath, NRMatrix const *ctm, SPStyle const *const style,
+ NRRect const *pbox, NRRect const *dbox, NRRect const *bbox)
+{
+ if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned.
+ if (_bitmap) return 0;
+
+ if ( style->fill.type == SP_PAINT_TYPE_COLOR
+ || ( style->fill.type == SP_PAINT_TYPE_PAINTSERVER
+ && SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style)) ) )
+ {
+ Inkscape::SVGOStringStream os;
+
+ os << "gsave\n";
+
+ print_fill_style(os, style, pbox);
+
+ print_bpath(os, bpath->path);
+
+ if (style->fill_rule.value == SP_WIND_RULE_EVENODD) {
+ if (style->fill.type == SP_PAINT_TYPE_COLOR) {
+ os << "eofill\n";
+ } else {
+ g_assert( style->fill.type == SP_PAINT_TYPE_PAINTSERVER
+ && SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style)) );
+ SPGradient const *g = SP_GRADIENT(SP_STYLE_FILL_SERVER(style));
+ os << "eoclip\n";
+ if (g->gradientTransform_set) {
+ os << "gsave [" << g->gradientTransform[0] << " " << g->gradientTransform[1]
+ << " " << g->gradientTransform[2] << " " << g->gradientTransform[3]
+ << " " << g->gradientTransform[4] << " " << g->gradientTransform[5] << "] concat\n";
+ }
+ os << "shfill\n";
+ if (g->gradientTransform_set) {
+ os << "grestore\n";
+ }
+ }
+ } else {
+ if (style->fill.type == SP_PAINT_TYPE_COLOR) {
+ os << "fill\n";
+ } else {
+ g_assert( style->fill.type == SP_PAINT_TYPE_PAINTSERVER
+ && SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style)) );
+ SPGradient const *g = SP_GRADIENT(SP_STYLE_FILL_SERVER(style));
+ os << "clip\n";
+ if (g->gradientTransform_set) {
+ os << "gsave [" << g->gradientTransform[0] << " " << g->gradientTransform[1]
+ << " " << g->gradientTransform[2] << " " << g->gradientTransform[3]
+ << " " << g->gradientTransform[4] << " " << g->gradientTransform[5] << "] concat\n";
+ }
+ os << "shfill\n";
+ if (g->gradientTransform_set) {
+ os << "grestore\n";
+ }
+ }
+ }
+
+ os << "grestore\n";
+
+ fprintf(_stream, "%s", os.str().c_str());
+ }
+
+ return 0;
+}
+
+
+unsigned int
+PrintPS::stroke(Inkscape::Extension::Print *mod, NRBPath const *bpath, NRMatrix const *ctm, SPStyle const *style,
+ NRRect const *pbox, NRRect const *dbox, NRRect const *bbox)
+{
+ if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned.
+ if (_bitmap) return 0;
+
+ if (style->stroke.type == SP_PAINT_TYPE_COLOR) {
+ Inkscape::SVGOStringStream os;
+
+ print_stroke_style(os, style);
+
+ print_bpath(os, bpath->path);
+
+ os << "stroke\n";
+
+ fprintf(_stream, "%s", os.str().c_str());
+ }
+
+ return 0;
+}
+
+unsigned int
+PrintPS::image(Inkscape::Extension::Print *mod, guchar *px, unsigned int w, unsigned int h, unsigned int rs,
+ NRMatrix const *transform, SPStyle const *style)
+{
+ if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned.
+ if (_bitmap) return 0;
+
+ return print_image(_stream, px, w, h, rs, transform);
+#if 0
+ fprintf(_stream, "gsave\n");
+ fprintf(_stream, "/rowdata %d string def\n", 3 * w);
+ fprintf(_stream, "[%g %g %g %g %g %g] concat\n",
+ transform->c[0],
+ transform->c[1],
+ transform->c[2],
+ transform->c[3],
+ transform->c[4],
+ transform->c[5]);
+ fprintf(_stream, "%d %d 8 [%d 0 0 -%d 0 %d]\n", w, h, w, h, h);
+ fprintf(_stream, "{currentfile rowdata readhexstring pop}\n");
+ fprintf(_stream, "false 3 colorimage\n");
+
+ for (unsigned int r = 0; r < h; r++) {
+ guchar *s;
+ unsigned int c0, c1, c;
+ s = px + r * rs;
+ for (c0 = 0; c0 < w; c0 += 24) {
+ c1 = MIN(w, c0 + 24);
+ for (c = c0; c < c1; c++) {
+ static char const xtab[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
+ fputc(xtab[s[0] >> 4], _stream);
+ fputc(xtab[s[0] & 0xf], _stream);
+ fputc(xtab[s[1] >> 4], _stream);
+ fputc(xtab[s[1] & 0xf], _stream);
+ fputc(xtab[s[2] >> 4], _stream);
+ fputc(xtab[s[2] & 0xf], _stream);
+ s += 4;
+ }
+ fputs("\n", _stream);
+ }
+ }
+
+ fprintf(_stream, "grestore\n");
+
+ return 0;
+#endif
+}
+
+char const *
+PrintPS::PSFontName(SPStyle const *style)
+{
+ font_instance *tf = (font_factory::Default())->Face(style->text->font_family.value, font_style_to_pos(*style));
+
+ char const *n;
+ char name_buf[256];
+
+ if (tf) {
+ tf->PSName(name_buf, sizeof(name_buf));
+ n = name_buf;
+ tf->Unref();
+ } else {
+ // this system does not have this font, so just use the name from SVG in the hope that PS interpreter will make sense of it
+ bool i = (style->font_style.value == SP_CSS_FONT_STYLE_ITALIC);
+ bool o = (style->font_style.value == SP_CSS_FONT_STYLE_OBLIQUE);
+ bool b = (style->font_weight.value == SP_CSS_FONT_WEIGHT_BOLD) ||
+ (style->font_weight.value >= SP_CSS_FONT_WEIGHT_500 && style->font_weight.value <= SP_CSS_FONT_WEIGHT_900);
+
+ n = g_strdup_printf("%s%s%s%s",
+ g_strdelimit(style->text->font_family.value, " ", '-'),
+ (b || i || o) ? "-" : "",
+ (b) ? "Bold" : "",
+ (i) ? "Italic" : ((o) ? "Oblique" : "") );
+ }
+
+ return g_strdup(n);
+}
+
+
+unsigned int
+PrintPS::text(Inkscape::Extension::Print *mod, char const *text, NR::Point p,
+ SPStyle const *const style)
+{
+ if (!_stream) return 0; // XXX: fixme, returning -1 as unsigned.
+ if (_bitmap) return 0;
+
+ Inkscape::SVGOStringStream os;
+
+ // Escape chars
+ Inkscape::SVGOStringStream escaped_text;
+ escaped_text << std::oct;
+ for (gchar const *p_text = text ; *p_text ; p_text = g_utf8_next_char(p_text)) {
+ gunichar const c = g_utf8_get_char(p_text);
+ if (c == '\\' || c == ')' || c == '(')
+ escaped_text << '\\' << static_cast<char>(c);
+ else if (c >= 0x80)
+ escaped_text << '\\' << c;
+ else
+ escaped_text << static_cast<char>(c);
+ }
+
+ os << "gsave\n";
+
+ // set font
+ char const *fn = PSFontName(style);
+ if (_latin1_encoded_fonts.find(fn) == _latin1_encoded_fonts.end()) {
+ if (!_newlatin1font_proc_defined) {
+ // input: newfontname, existingfontname
+ // output: new font object, also defined to newfontname
+ os << "/newlatin1font " // name of the proc
+ "{findfont dup length dict copy " // load the font and create a copy of it
+ "dup /Encoding ISOLatin1Encoding put " // change the encoding in the copy
+ "definefont} def\n"; // create the new font and leave it on the stack, define the proc
+ _newlatin1font_proc_defined = true;
+ }
+ os << "/" << fn << "-ISOLatin1 /" << fn << " newlatin1font\n";
+ _latin1_encoded_fonts.insert(fn);
+ } else
+ os << "/" << fn << "-ISOLatin1 findfont\n";
+ os << style->font_size.computed << " scalefont\n";
+ os << "setfont\n";
+ g_free((void *) fn);
+
+ if ( style->fill.type == SP_PAINT_TYPE_COLOR
+ || ( style->fill.type == SP_PAINT_TYPE_PAINTSERVER
+ && SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style)) ) )
+ {
+ // set fill style
+ print_fill_style(os, style, NULL);
+ // FIXME: we don't know the pbox of text, so have to pass NULL. This means gradients with
+ // bbox units won't work with text. However userspace gradients don't work with text either
+ // (text is black) for some reason.
+
+ os << "newpath\n";
+ os << p[NR::X] << " " << p[NR::Y] << " moveto\n";
+ os << "(" << escaped_text.str() << ") show\n";
+ }
+
+ if (style->stroke.type == SP_PAINT_TYPE_COLOR) {
+
+ // set stroke style
+ print_stroke_style(os, style);
+
+ // paint stroke
+ os << "newpath\n";
+ os << p[NR::X] << " " << p[NR::Y] << " moveto\n";
+ os << "(" << escaped_text.str() << ") false charpath stroke\n";
+ }
+
+ os << "grestore\n";
+
+ fprintf(_stream, "%s", os.str().c_str());
+
+ return 0;
+}
+
+
+
+/* PostScript helpers */
+
+void
+PrintPS::print_bpath(SVGOStringStream &os, NArtBpath const *bp)
+{
+ os << "newpath\n";
+ bool closed = false;
+ while (bp->code != NR_END) {
+ switch (bp->code) {
+ case NR_MOVETO:
+ if (closed) {
+ os << "closepath\n";
+ }
+ closed = true;
+ os << bp->x3 << " " << bp->y3 << " moveto\n";
+ break;
+ case NR_MOVETO_OPEN:
+ if (closed) {
+ os << "closepath\n";
+ }
+ closed = false;
+ os << bp->x3 << " " << bp->y3 << " moveto\n";
+ break;
+ case NR_LINETO:
+ os << bp->x3 << " " << bp->y3 << " lineto\n";
+ break;
+ case NR_CURVETO:
+ os << bp->x1 << " " << bp->y1 << " "
+ << bp->x2 << " " << bp->y2 << " "
+ << bp->x3 << " " << bp->y3 << " curveto\n";
+ break;
+ default:
+ break;
+ }
+ bp += 1;
+ }
+ if (closed) {
+ os << "closepath\n";
+ }
+}
+
+/* The following code is licensed under GNU GPL.
+** The packbits, ascii85 and imaging printing code
+** is from the gimp's postscript.c.
+*/
+
+/**
+* \param nin Number of bytes of source data.
+* \param src Source data.
+* \param nout Number of output bytes.
+* \param dst Buffer for output.
+*/
+void
+PrintPS::compress_packbits(int nin,
+ guchar *src,
+ int *nout,
+ guchar *dst)
+
+{
+ register guchar c;
+ int nrepeat, nliteral;
+ guchar *run_start;
+ guchar *start_dst = dst;
+ guchar *last_literal = NULL;
+
+ for (;;) {
+ if (nin <= 0) break;
+
+ run_start = src;
+ c = *run_start;
+
+ /* Search repeat bytes */
+ if ((nin > 1) && (c == src[1])) {
+ nrepeat = 1;
+ nin -= 2;
+ src += 2;
+ while ((nin > 0) && (c == *src)) {
+ nrepeat++;
+ src++;
+ nin--;
+ if (nrepeat == 127) break; /* Maximum repeat */
+ }
+
+ /* Add two-byte repeat to last literal run ? */
+ if ( (nrepeat == 1)
+ && (last_literal != NULL) && (((*last_literal)+1)+2 <= 128) )
+ {
+ *last_literal += 2;
+ *(dst++) = c;
+ *(dst++) = c;
+ continue;
+ }
+
+ /* Add repeat run */
+ *(dst++) = (guchar)((-nrepeat) & 0xff);
+ *(dst++) = c;
+ last_literal = NULL;
+ continue;
+ }
+ /* Search literal bytes */
+ nliteral = 1;
+ nin--;
+ src++;
+
+ for (;;) {
+ if (nin <= 0) break;
+
+ if ((nin >= 2) && (src[0] == src[1])) /* A two byte repeat ? */
+ break;
+
+ nliteral++;
+ nin--;
+ src++;
+ if (nliteral == 128) break; /* Maximum literal run */
+ }
+
+ /* Could be added to last literal run ? */
+ if ((last_literal != NULL) && (((*last_literal)+1)+nliteral <= 128)) {
+ *last_literal += nliteral;
+ } else {
+ last_literal = dst;
+ *(dst++) = (guchar)(nliteral-1);
+ }
+ while (nliteral-- > 0) *(dst++) = *(run_start++);
+ }
+ *nout = dst - start_dst;
+}
+
+void
+PrintPS::ascii85_init(void)
+{
+ ascii85_len = 0;
+ ascii85_linewidth = 0;
+}
+
+void
+PrintPS::ascii85_flush(SVGOStringStream &os)
+{
+ char c[5];
+ bool const zero_case = (ascii85_buf == 0);
+ static int const max_linewidth = 75;
+
+ for (int i = 4; i >= 0; i--) {
+ c[i] = (ascii85_buf % 85) + '!';
+ ascii85_buf /= 85;
+ }
+ /* check for special case: "!!!!!" becomes "z", but only if not
+ * at end of data. */
+ if (zero_case && (ascii85_len == 4)) {
+ if (ascii85_linewidth >= max_linewidth) {
+ os << '\n';
+ ascii85_linewidth = 0;
+ }
+ os << 'z';
+ ascii85_linewidth++;
+ } else {
+ for (int i = 0; i < ascii85_len+1; i++) {
+ if ((ascii85_linewidth >= max_linewidth) && (c[i] != '%')) {
+ os << '\n';
+ ascii85_linewidth = 0;
+ }
+ os << c[i];
+ ascii85_linewidth++;
+ }
+ }
+
+ ascii85_len = 0;
+ ascii85_buf = 0;
+}
+
+inline void
+PrintPS::ascii85_out(guchar byte, SVGOStringStream &os)
+{
+ if (ascii85_len == 4)
+ ascii85_flush(os);
+
+ ascii85_buf <<= 8;
+ ascii85_buf |= byte;
+ ascii85_len++;
+}
+
+void
+PrintPS::ascii85_nout(int n, guchar *uptr, SVGOStringStream &os)
+{
+ while (n-- > 0) {
+ ascii85_out(*uptr, os);
+ uptr++;
+ }
+}
+
+void
+PrintPS::ascii85_done(SVGOStringStream &os)
+{
+ if (ascii85_len) {
+ /* zero any unfilled buffer portion, then flush */
+ ascii85_buf <<= (8 * (4-ascii85_len));
+ ascii85_flush(os);
+ }
+
+ os << "~>\n";
+}
+
+unsigned int
+PrintPS::print_image(FILE *ofp, guchar *px, unsigned int width, unsigned int height, unsigned int rs,
+ NRMatrix const *transform)
+{
+ Inkscape::SVGOStringStream os;
+
+ os << "gsave\n";
+ os << "[" << transform->c[0] << " "
+ << transform->c[1] << " "
+ << transform->c[2] << " "
+ << transform->c[3] << " "
+ << transform->c[4] << " "
+ << transform->c[5] << "] concat\n";
+ os << width << " " << height << " 8 ["
+ << width << " 0 0 -" << height << " 0 " << height << "]\n";
+
+
+ /* Write read image procedure */
+ os << "% Strings to hold RGB-samples per scanline\n";
+ os << "/rstr " << width << " string def\n";
+ os << "/gstr " << width << " string def\n";
+ os << "/bstr " << width << " string def\n";
+ os << "{currentfile /ASCII85Decode filter /RunLengthDecode filter rstr readstring pop}\n";
+ os << "{currentfile /ASCII85Decode filter /RunLengthDecode filter gstr readstring pop}\n";
+ os << "{currentfile /ASCII85Decode filter /RunLengthDecode filter bstr readstring pop}\n";
+ os << "true 3\n";
+
+ /* Allocate buffer for packbits data. Worst case: Less than 1% increase */
+ guchar *const packb = (guchar *)g_malloc((width * 105)/100+2);
+ guchar *const plane = (guchar *)g_malloc(width);
+
+ /* ps_begin_data(ofp); */
+ os << "colorimage\n";
+
+/*#define GET_RGB_TILE(begin) \
+ * {int scan_lines; \
+ * scan_lines = (i+tile_height-1 < height) ? tile_height : (height-i); \
+ * gimp_pixel_rgn_get_rect(&pixel_rgn, begin, 0, i, width, scan_lines); \
+ * src = begin; }
+ */
+
+ for (unsigned i = 0; i < height; i++) {
+ /* if ((i % tile_height) == 0) GET_RGB_TILE(data); */ /* Get more data */
+ guchar const *const src = px + i * rs;
+
+ /* Iterate over RGB */
+ for (int rgb = 0; rgb < 3; rgb++) {
+ guchar const *src_ptr = src + rgb;
+ guchar *plane_ptr = plane;
+ for (unsigned j = 0; j < width; j++) {
+ *(plane_ptr++) = *src_ptr;
+ src_ptr += 4;
+ }
+
+ int nout;
+ compress_packbits(width, plane, &nout, packb);
+
+ ascii85_init();
+ ascii85_nout(nout, packb, os);
+ ascii85_out(128, os); /* Write EOD of RunLengthDecode filter */
+ ascii85_done(os);
+ }
+ }
+ /* ps_end_data(ofp); */
+
+#if 0
+ fprintf(ofp, "showpage\n");
+ g_free(data);
+#endif
+
+ g_free(packb);
+ g_free(plane);
+
+#if 0
+ if (ferror(ofp)) {
+ g_message(_("write error occurred"));
+ return (FALSE);
+ }
+#endif
+
+ os << "grestore\n";
+
+ fprintf(ofp, "%s", os.str().c_str());
+
+ return 0;
+//#undef GET_RGB_TILE
+}
+
+bool
+PrintPS::textToPath(Inkscape::Extension::Print * ext)
+{
+ return ext->get_param_bool("textToPath");
+}
+
+void
+PrintPS::init(void)
+{
+ /* SVG in */
+ (void) Inkscape::Extension::build_from_mem(
+ "<inkscape-extension>\n"
+ "<name>Postscript Print</name>\n"
+ "<id>" SP_MODULE_KEY_PRINT_PS "</id>\n"
+ "<param name=\"bitmap\" type=\"boolean\">FALSE</param>\n"
+ "<param name=\"resolution\" type=\"string\">72</param>\n"
+ "<param name=\"destination\" type=\"string\"></param>\n"
+ "<param name=\"pageBoundingBox\" type=\"boolean\">TRUE</param>\n"
+ "<param name=\"textToPath\" type=\"boolean\">TRUE</param>\n"
+ "<print/>\n"
+ "</inkscape-extension>", new PrintPS());
+}
+
+
+} /* namespace Internal */
+} /* namespace Extension */
+} /* namespace Inkscape */
+
+/* End of GNU GPL code */
+
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/extension/internal/ps.h b/src/extension/internal/ps.h
new file mode 100644
index 000000000..eb07dc9bd
--- /dev/null
+++ b/src/extension/internal/ps.h
@@ -0,0 +1,108 @@
+#ifndef EXTENSION_INTERNAL_PS_H_SEEN
+#define EXTENSION_INTERNAL_PS_H_SEEN
+
+/** \file
+ * Declaration of PrintPS, the internal module used to do Postscript Printing.
+ */
+/*
+ * Authors:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ * Ted Gould <ted@gould.cx>
+ *
+ * Lauris' original code is in the public domain.
+ * Ted's changes are licensed under the GNU GPL.
+ */
+
+#include <config.h>
+#include "extension/extension.h"
+#include "extension/implementation/implementation.h"
+#include <set>
+#include <string>
+
+#include "libnr/nr-path.h"
+
+#include "svg/stringstream.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+class PrintPS : public Inkscape::Extension::Implementation::Implementation {
+ float _width;
+ float _height;
+ FILE *_stream;
+ unsigned short _dpi;
+ bool _bitmap;
+ std::set<std::string> _latin1_encoded_fonts;
+ bool _newlatin1font_proc_defined;
+
+ void print_bpath(SVGOStringStream &os, NArtBpath const *bp);
+
+ void print_fill_style(SVGOStringStream &os, SPStyle const *style, NRRect const *pbox);
+ void print_stroke_style(SVGOStringStream &os, SPStyle const *style);
+
+ char const *PSFontName(SPStyle const *style);
+
+ unsigned int print_image(FILE *ofp, guchar *px, unsigned int width, unsigned int height, unsigned int rs,
+ NRMatrix const *transform);
+ void compress_packbits(int nin, guchar *src, int *nout, guchar *dst);
+
+ /* ASCII 85 variables */
+ guint32 ascii85_buf;
+ int ascii85_len;
+ int ascii85_linewidth;
+ /* ASCII 85 Functions */
+ void ascii85_init(void);
+ void ascii85_flush(SVGOStringStream &os);
+ inline void ascii85_out(guchar byte, SVGOStringStream &os);
+ void ascii85_nout(int n, guchar *uptr, SVGOStringStream &os);
+ void ascii85_done(SVGOStringStream &os);
+
+
+public:
+ PrintPS(void);
+ virtual ~PrintPS(void);
+
+ /* Print functions */
+ virtual unsigned int setup(Inkscape::Extension::Print *module);
+ /*
+ virtual unsigned int set_preview(Inkscape::Extension::Print *module);
+ */
+
+ virtual unsigned int begin(Inkscape::Extension::Print *module, SPDocument *doc);
+ virtual unsigned int finish(Inkscape::Extension::Print *module);
+
+ /* Rendering methods */
+ virtual unsigned int bind(Inkscape::Extension::Print *module, NRMatrix const *transform, float opacity);
+ virtual unsigned int release(Inkscape::Extension::Print *module);
+ virtual unsigned int comment(Inkscape::Extension::Print *module, char const *comment);
+ virtual unsigned int fill(Inkscape::Extension::Print *module, NRBPath const *bpath, NRMatrix const *ctm, SPStyle const *style,
+ NRRect const *pbox, NRRect const *dbox, NRRect const *bbox);
+ virtual unsigned int stroke(Inkscape::Extension::Print *module, NRBPath const *bpath, NRMatrix const *transform, SPStyle const *style,
+ NRRect const *pbox, NRRect const *dbox, NRRect const *bbox);
+ virtual unsigned int image(Inkscape::Extension::Print *module, unsigned char *px, unsigned int w, unsigned int h, unsigned int rs,
+ NRMatrix const *transform, SPStyle const *style);
+ virtual unsigned int text(Inkscape::Extension::Print *module, char const *text,
+ NR::Point p, SPStyle const *style);
+
+ bool textToPath(Inkscape::Extension::Print *ext);
+ static void init(void);
+};
+
+} /* namespace Internal */
+} /* namespace Extension */
+} /* namespace Inkscape */
+
+
+#endif /* !EXTENSION_INTERNAL_PS_H_SEEN */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
diff --git a/src/extension/internal/svg.cpp b/src/extension/internal/svg.cpp
new file mode 100644
index 000000000..e6d02b62d
--- /dev/null
+++ b/src/extension/internal/svg.cpp
@@ -0,0 +1,248 @@
+/*
+ * This is the code that moves all of the SVG loading and saving into
+ * the module format. Really Inkscape is built to handle these formats
+ * internally, so this is just calling those internal functions.
+ *
+ * Authors:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ * Ted Gould <ted@gould.cx>
+ *
+ * Copyright (C) 2002-2003 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include "sp-object.h"
+#include "svg.h"
+#include "file.h"
+#include "extension/system.h"
+#include "extension/output.h"
+
+#ifdef WITH_GNOME_VFS
+# include <libgnomevfs/gnome-vfs.h>
+#endif
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+/**
+ \return None
+ \brief What would an SVG editor be without loading/saving SVG
+ files. This function sets that up.
+
+ For each module there is a call to Inkscape::Extension::build_from_mem
+ with a rather large XML file passed in. This is a constant string
+ that describes the module. At the end of this call a module is
+ returned that is basically filled out. The one thing that it doesn't
+ have is the key function for the operation. And that is linked at
+ the end of each call.
+*/
+void
+Svg::init(void)
+{
+ Inkscape::Extension::Extension * ext;
+
+ /* SVG in */
+ ext = Inkscape::Extension::build_from_mem(
+ "<inkscape-extension>\n"
+ "<name>SVG Input</name>\n"
+ "<id>" SP_MODULE_KEY_INPUT_SVG "</id>\n"
+ "<input>\n"
+ "<extension>.svg</extension>\n"
+ "<mimetype>image/x-svg</mimetype>\n"
+ "<filetypename>Scalable Vector Graphic (*.svg)</filetypename>\n"
+ "<filetypetooltip>Inkscape native file format and W3C standard</filetypetooltip>\n"
+ "<output_extension>" SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE "</output_extension>\n"
+ "</input>\n"
+ "</inkscape-extension>", new Svg());
+
+ /* SVG out Inkscape */
+ ext = Inkscape::Extension::build_from_mem(
+ "<inkscape-extension>\n"
+ "<name>SVG Output Inkscape</name>\n"
+ "<id>" SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE "</id>\n"
+ "<output>\n"
+ "<extension>.svg</extension>\n"
+ "<mimetype>image/x-svg</mimetype>\n"
+ "<filetypename>Inkscape SVG (*.svg)</filetypename>\n"
+ "<filetypetooltip>SVG format with Inkscape extensions</filetypetooltip>\n"
+ "<dataloss>FALSE</dataloss>\n"
+ "</output>\n"
+ "</inkscape-extension>", new Svg());
+
+ /* SVG out */
+ ext = Inkscape::Extension::build_from_mem(
+ "<inkscape-extension>\n"
+ "<name>SVG Output</name>\n"
+ "<id>" SP_MODULE_KEY_OUTPUT_SVG "</id>\n"
+ "<output>\n"
+ "<extension>.svg</extension>\n"
+ "<mimetype>image/x-svg</mimetype>\n"
+ "<filetypename>Plain SVG (*.svg)</filetypename>\n"
+ "<filetypetooltip>Scalable Vector Graphics format as defined by the W3C</filetypetooltip>\n"
+ "</output>\n"
+ "</inkscape-extension>", new Svg());
+
+#ifdef WITH_GNOME_VFS
+ gnome_vfs_init();
+#endif
+
+
+ return;
+}
+
+
+#ifdef WITH_GNOME_VFS
+#define BUF_SIZE 8192
+
+gchar *
+_load_uri (const gchar *uri)
+{
+ GnomeVFSHandle *handle = NULL;
+ GnomeVFSFileSize bytes_read;
+ gchar buffer[BUF_SIZE] = "";
+ gchar *doc = NULL;
+ gchar *new_doc = NULL;
+
+ gsize bytesRead = 0;
+ gsize bytesWritten = 0;
+ GError* error = NULL;
+ gchar* uri_local = g_filename_from_utf8( uri, -1, &bytesRead, &bytesWritten, &error);
+
+ if ( uri_local == NULL ) {
+ g_warning( "Error converting filename to locale encoding.");
+ }
+
+ GnomeVFSResult result = gnome_vfs_open (&handle, uri_local, GNOME_VFS_OPEN_READ);
+
+ if (result != GNOME_VFS_OK) {
+ g_warning(gnome_vfs_result_to_string(result));
+ }
+
+ while (result == GNOME_VFS_OK) {
+ result = gnome_vfs_read (handle, buffer, BUF_SIZE, &bytes_read);
+ buffer[bytes_read] = '\0';
+
+ if (doc == NULL) {
+ doc = g_strndup(buffer, bytes_read);
+ } else {
+ new_doc = g_strconcat(doc, buffer, NULL);
+ g_free(doc);
+ doc = new_doc;
+ }
+ }
+
+ return doc;
+}
+#endif
+
+
+/**
+ \return A new document just for you!
+ \brief This function takes in a filename of a SVG document and
+ turns it into a SPDocument.
+ \param mod Module to use
+ \param uri The path to the file (UTF-8)
+
+ This function is really simple, it just calls sp_document_new...
+*/
+SPDocument *
+Svg::open (Inkscape::Extension::Input *mod, const gchar *uri)
+{
+#ifdef WITH_GNOME_VFS
+ if (gnome_vfs_uri_is_local(gnome_vfs_uri_new(uri))) {
+ // Use built-in loader instead of VFS for this
+ return sp_document_new(uri, TRUE);
+ }
+ gchar * buffer = _load_uri(uri);
+ if (buffer == NULL) {
+ g_warning("Error: Could not open file '%s' with VFS\n", uri);
+ return NULL;
+ }
+ SPDocument * doc = sp_document_new_from_mem(buffer, strlen(buffer), 1);
+
+ g_free(buffer);
+ return doc;
+#else
+ return sp_document_new (uri, TRUE);
+#endif
+}
+
+/**
+ \return None
+ \brief This is the function that does all of the SVG saves in
+ Inkscape. It detects whether it should do a Inkscape
+ namespace save internally.
+ \param mod Extension to use.
+ \param doc Document to save.
+ \param uri The filename to save the file to.
+
+ This function first checks it's parameters, and makes sure that
+ we're getting good data. It also checks the module ID of the
+ incoming module to figure out if this is save should include
+ the Inkscape namespace stuff or not. The result of that comparison
+ is stored in the spns variable.
+
+ If there is not to be Inkscape name spaces a new document is created
+ without. (I think, I'm not sure on this code)
+
+ All of the internally referenced imageins are also set to relative
+ paths in the file. And the file is saved.
+
+ This really needs to be fleshed out more, but I don't quite understand
+ all of this code. I just stole it.
+*/
+void
+Svg::save (Inkscape::Extension::Output *mod, SPDocument *doc, const gchar *uri)
+{
+ g_return_if_fail(doc != NULL);
+ g_return_if_fail(uri != NULL);
+
+ gchar *save_path = g_path_get_dirname (uri);
+
+ gboolean const spns = (!mod->get_id()
+ || !strcmp (mod->get_id(), SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE)
+ || !strcmp (mod->get_id(), SP_MODULE_KEY_OUTPUT_SVGZ_INKSCAPE));
+
+ Inkscape::XML::Document *rdoc = NULL;
+ Inkscape::XML::Node *repr = NULL;
+ if (spns) {
+ repr = sp_document_repr_root (doc);
+ } else {
+ rdoc = sp_repr_document_new ("svg:svg");
+ repr = sp_repr_document_root (rdoc);
+ repr = sp_document_root (doc)->updateRepr(repr, SP_OBJECT_WRITE_BUILD);
+ }
+
+ Inkscape::IO::fixupHrefs( doc, save_path, spns );
+
+ gboolean const s = sp_repr_save_file (sp_repr_document (repr), uri, SP_SVG_NS_URI);
+ if (s == FALSE) {
+ throw Inkscape::Extension::Output::save_failed();
+ }
+
+ if (!spns) {
+ Inkscape::GC::release(rdoc);
+ }
+
+ g_free(save_path);
+
+ return;
+}
+
+} } } /* namespace inkscape, module, implementation */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/extension/internal/svg.h b/src/extension/internal/svg.h
new file mode 100644
index 000000000..de75f0021
--- /dev/null
+++ b/src/extension/internal/svg.h
@@ -0,0 +1,48 @@
+/*
+ * This is the code that moves all of the SVG loading and saving into
+ * the module format. Really Sodipodi is built to handle these formats
+ * internally, so this is just calling those internal functions.
+ *
+ * Authors:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ * Ted Gould <ted@gould.cx>
+ *
+ * Copyright (C) 2002-2003 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef __SVG_H__
+#define __SVG_H__
+
+#include "../implementation/implementation.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+class Svg : public Inkscape::Extension::Implementation::Implementation {
+
+public:
+ virtual void save( Inkscape::Extension::Output *mod,
+ SPDocument *doc,
+ const gchar *uri );
+ virtual SPDocument *open( Inkscape::Extension::Input *mod,
+ const gchar *uri );
+ static void init( void );
+
+};
+
+} } } /* namespace Inkscape, Extension, Implementation */
+#endif /* __SVG_H__ */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/extension/internal/svgz.cpp b/src/extension/internal/svgz.cpp
new file mode 100644
index 000000000..d56ac31b2
--- /dev/null
+++ b/src/extension/internal/svgz.cpp
@@ -0,0 +1,99 @@
+/*
+ * Code to handle compressed SVG loading and saving. Almost identical to svg
+ * routines, but separated for simpler extension maintenance.
+ *
+ * Authors:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ * Ted Gould <ted@gould.cx>
+ * Jon A. Cruz <jon@joncruz.org>
+ *
+ * Copyright (C) 2002-2005 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include "svgz.h"
+#include "extension/system.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+/**
+ \return None
+ \brief What would an SVG editor be without loading/saving SVG
+ files. This function sets that up.
+
+ For each module there is a call to Inkscape::Extension::build_from_mem
+ with a rather large XML file passed in. This is a constant string
+ that describes the module. At the end of this call a module is
+ returned that is basically filled out. The one thing that it doesn't
+ have is the key function for the operation. And that is linked at
+ the end of each call.
+*/
+void
+Svgz::init(void)
+{
+ Inkscape::Extension::Extension * ext;
+
+ /* SVGZ in */
+ ext = Inkscape::Extension::build_from_mem(
+ "<inkscape-extension>\n"
+ "<name>SVGZ Input</name>\n"
+ "<id>" SP_MODULE_KEY_INPUT_SVGZ "</id>\n"
+ "<dependency type=\"extension\">" SP_MODULE_KEY_INPUT_SVG "</dependency>\n"
+ "<input>\n"
+ "<extension>.svgz</extension>\n"
+ "<mimetype>image/x-svgz</mimetype>\n"
+ "<filetypename>Compressed Inkscape SVG (*.svgz)</filetypename>\n"
+ "<filetypetooltip>SVG file format compressed with GZip</filetypetooltip>\n"
+ "<output_extension>" SP_MODULE_KEY_OUTPUT_SVGZ_INKSCAPE "</output_extension>\n"
+ "</input>\n"
+ "</inkscape-extension>", new Svgz());
+
+ /* SVGZ out Inkscape */
+ ext = Inkscape::Extension::build_from_mem(
+ "<inkscape-extension>\n"
+ "<name>SVGZ Output</name>\n"
+ "<id>" SP_MODULE_KEY_OUTPUT_SVGZ_INKSCAPE "</id>\n"
+ "<output>\n"
+ "<extension>.svgz</extension>\n"
+ "<mimetype>image/x-svgz</mimetype>\n"
+ "<filetypename>Compressed Inkscape SVG (*.svgz)</filetypename>\n"
+ "<filetypetooltip>Inkscape's native file format compressed with GZip</filetypetooltip>\n"
+ "<dataloss>FALSE</dataloss>\n"
+ "</output>\n"
+ "</inkscape-extension>", new Svgz());
+
+ /* SVGZ out */
+ ext = Inkscape::Extension::build_from_mem(
+ "<inkscape-extension>\n"
+ "<name>SVGZ Output</name>\n"
+ "<id>" SP_MODULE_KEY_OUTPUT_SVGZ "</id>\n"
+ "<output>\n"
+ "<extension>.svgz</extension>\n"
+ "<mimetype>image/x-svgz</mimetype>\n"
+ "<filetypename>Compressed plain SVG (*.svgz)</filetypename>\n"
+ "<filetypetooltip>Scalable Vector Graphics format compressed with GZip</filetypetooltip>\n"
+ "</output>\n"
+ "</inkscape-extension>\n", new Svgz());
+
+ return;
+}
+
+
+} } } // namespace inkscape, module, implementation
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/extension/internal/svgz.h b/src/extension/internal/svgz.h
new file mode 100644
index 000000000..ba348f887
--- /dev/null
+++ b/src/extension/internal/svgz.h
@@ -0,0 +1,41 @@
+/*
+ * Code to handle compressed SVG loading and saving. Almost identical to svg
+ * routines, but separated for simpler extension maintenance.
+ *
+ * Authors:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ * Ted Gould <ted@gould.cx>
+ * Jon A. Cruz <jon@joncruz.org>
+ *
+ * Copyright (C) 2002-2005 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_SVGZ_H
+#define SEEN_SVGZ_H
+
+#include "svg.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+class Svgz : public Svg {
+public:
+ static void init( void );
+};
+
+} } } // namespace Inkscape, Extension, Implementation
+#endif // SEEN_SVGZ_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/extension/internal/win32.cpp b/src/extension/internal/win32.cpp
new file mode 100644
index 000000000..7f1774d21
--- /dev/null
+++ b/src/extension/internal/win32.cpp
@@ -0,0 +1,499 @@
+#define __SP_MODULE_WIN32_C__
+
+/*
+ * Windows stuff
+ *
+ * Author:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ *
+ * This code is in public domain
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <libnr/nr-macros.h>
+#include <libnr/nr-matrix.h>
+
+#include "display/nr-arena-item.h"
+#include "display/nr-arena.h"
+#include "document.h"
+
+#include "win32.h"
+#include "system.h"
+#include "extension/print.h"
+#include <gtk/gtk.h>
+
+/* Initialization */
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+static unsigned int SPWin32Modal = FALSE;
+
+/**
+ * Callback function.. not a method
+ */
+static void
+my_gdk_event_handler (GdkEvent *event)
+{
+ if (SPWin32Modal) {
+ /* Win32 widget is modal, filter events */
+ switch (event->type) {
+ case GDK_NOTHING:
+ case GDK_DELETE:
+ case GDK_SCROLL:
+ case GDK_BUTTON_PRESS:
+ case GDK_2BUTTON_PRESS:
+ case GDK_3BUTTON_PRESS:
+ case GDK_BUTTON_RELEASE:
+ case GDK_KEY_PRESS:
+ case GDK_KEY_RELEASE:
+ case GDK_DRAG_STATUS:
+ case GDK_DRAG_ENTER:
+ case GDK_DRAG_LEAVE:
+ case GDK_DRAG_MOTION:
+ case GDK_DROP_START:
+ case GDK_DROP_FINISHED:
+ return;
+ break;
+ default:
+ break;
+ }
+ }
+ gtk_main_do_event (event);
+}
+
+void
+PrintWin32::main_init (int argc, char **argv, const char *name)
+{
+ gdk_event_handler_set ((GdkEventFunc) my_gdk_event_handler, NULL, NULL);
+}
+
+void
+PrintWin32::finish (void)
+{
+}
+
+#define SP_FOREIGN_MAX_ITER 10
+
+
+/**
+ * Callback function.. not a method
+ */
+static VOID CALLBACK
+my_timer (HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
+{
+ int cdown = 0;
+ while ((cdown++ < SP_FOREIGN_MAX_ITER) && gdk_events_pending ()) {
+ gtk_main_iteration_do (FALSE);
+ }
+ gtk_main_iteration_do (FALSE);
+}
+
+
+/* Platform detection */
+
+gboolean
+PrintWin32::is_os_wide()
+{
+ static gboolean initialized = FALSE;
+ static gboolean is_wide = FALSE;
+ static OSVERSIONINFOA osver;
+
+ if ( !initialized )
+ {
+ BOOL result;
+
+ initialized = TRUE;
+
+ memset (&osver, 0, sizeof(OSVERSIONINFOA));
+ osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
+ result = GetVersionExA (&osver);
+ if (result)
+ {
+ if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT)
+ is_wide = TRUE;
+ }
+ // If we can't even call to get the version, fall back to ANSI API
+ }
+
+ return is_wide;
+}
+
+
+/* Printing */
+
+PrintWin32::PrintWin32 (void)
+{
+ /* Nothing here */
+}
+
+
+PrintWin32::~PrintWin32 (void)
+{
+ DeleteDC (_hDC);
+}
+
+
+/**
+ * Callback function.. not a method
+ */
+static UINT_PTR CALLBACK
+print_hook (HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
+{
+#if 0
+ int cdown = 0;
+ while ((cdown++ < SP_FOREIGN_MAX_ITER) && gdk_events_pending ()) {
+ gtk_main_iteration_do (FALSE);
+ }
+ gtk_main_iteration_do (FALSE);
+#endif
+ return 0;
+}
+
+unsigned int
+PrintWin32::setup (Inkscape::Extension::Print *mod)
+{
+ HRESULT res;
+ PRINTDLG pd = {
+ sizeof (PRINTDLG),
+ NULL, /* hwndOwner */
+ NULL, /* hDevMode */
+ NULL, /* hDevNames */
+ NULL, /* hDC */
+ PD_NOPAGENUMS | PD_NOSELECTION | PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE, /* Flags */
+ 1, 1, 1, 1, /* nFromPage, nToPage, nMinPage, nMaxPage */
+ 1, /* nCoies */
+ NULL, /* hInstance */
+ 0, /* lCustData */
+ NULL, NULL, NULL, NULL, NULL, NULL
+ };
+ UINT_PTR timer;
+
+ SPWin32Modal = TRUE;
+ pd.Flags |= PD_ENABLEPRINTHOOK;
+ pd.lpfnPrintHook = print_hook;
+ timer = SetTimer (NULL, 0, 40, my_timer);
+
+ res = PrintDlg (&pd);
+
+ KillTimer (NULL, timer);
+ SPWin32Modal = FALSE;
+
+ if (!res) return FALSE;
+
+ _hDC = pd.hDC;
+
+#if 0
+ caps = GetDeviceCaps (_hDC, RASTERCAPS);
+ if (caps & RC_BANDING) {
+ printf ("needs banding\n");
+ }
+ if (caps & RC_BITBLT) {
+ printf ("does bitblt\n");
+ }
+ if (caps & RC_DIBTODEV) {
+ printf ("does dibtodev\n");
+ }
+ if (caps & RC_STRETCHDIB) {
+ printf ("does stretchdib\n");
+ }
+#endif
+ if (pd.hDevMode) {
+ DEVMODE *devmodep;
+ devmodep = (DEVMODE *)pd.hDevMode;
+ if (devmodep->dmFields & DM_ORIENTATION) {
+ _landscape = (devmodep->dmOrientation == DMORIENT_LANDSCAPE);
+ }
+ }
+
+ return TRUE;
+}
+
+unsigned int
+PrintWin32::begin (Inkscape::Extension::Print *mod, SPDocument *doc)
+{
+ DOCINFO di = {
+ sizeof (DOCINFO),
+ NULL, /* lpszDocName */
+ NULL, /* lpszOutput */
+ NULL, /* lpszDatatype */
+ 0 /* DI_APPBANDING */ /* fwType */
+ };
+ int res;
+
+ _PageWidth = sp_document_width (doc);
+ _PageHeight = sp_document_height (doc);
+
+ di.lpszDocName = SP_DOCUMENT_NAME (doc);
+
+ SPWin32Modal = TRUE;
+
+ res = StartDoc (_hDC, &di);
+ res = StartPage (_hDC);
+
+ SPWin32Modal = FALSE;
+
+ return 0;
+}
+
+unsigned int
+PrintWin32::finish (Inkscape::Extension::Print *mod)
+{
+ int dpiX, dpiY;
+ int pPhysicalWidth, pPhysicalHeight;
+ int pPhysicalOffsetX, pPhysicalOffsetY;
+ int pPrintableWidth, pPrintableHeight;
+ float scalex, scaley;
+ int x0, y0, x1, y1;
+ int width, height;
+ NRMatrix affine;
+ unsigned char *px;
+ int sheight, row;
+ BITMAPINFO bmInfo = {
+ {
+ sizeof (BITMAPINFOHEADER), // bV4Size
+ 64, // biWidth
+ 64, // biHeight
+ 1, // biPlanes
+ 32, // biBitCount
+ BI_RGB, // biCompression
+ 0, // biSizeImage
+ 2835, // biXPelsPerMeter
+ 2835, // biYPelsPerMeter
+ 0, // biClrUsed
+ 0 // biClrImportant
+ },
+ { { 0, 0, 0, 0 } } // bmiColors
+ };
+ //RECT wrect;
+ int res;
+
+ SPWin32Modal = TRUE;
+
+ // Number of pixels per logical inch
+ dpiX = (int) GetDeviceCaps (_hDC, LOGPIXELSX);
+ dpiY = (int) GetDeviceCaps (_hDC, LOGPIXELSY);
+ // Size in pixels of the printable area
+ pPhysicalWidth = GetDeviceCaps (_hDC, PHYSICALWIDTH);
+ pPhysicalHeight = GetDeviceCaps (_hDC, PHYSICALHEIGHT);
+ // Top left corner of prontable area
+ pPhysicalOffsetX = GetDeviceCaps (_hDC, PHYSICALOFFSETX);
+ pPhysicalOffsetY = GetDeviceCaps (_hDC, PHYSICALOFFSETY);
+ // Size in pixels of the printable area
+ pPrintableWidth = GetDeviceCaps (_hDC, HORZRES);
+ pPrintableHeight = GetDeviceCaps (_hDC, VERTRES);
+
+ // Scaling from document to device
+ scalex = dpiX / 72.0;
+ scaley = dpiY / 72.0;
+
+ // We simply map document 0,0 to physical page 0,0
+ affine.c[0] = scalex / 1.25;
+ affine.c[1] = 0.0;
+ affine.c[2] = 0.0;
+ affine.c[3] = scaley / 1.25;
+ affine.c[4] = 0.0;
+ affine.c[5] = 0.0;
+
+ nr_arena_item_set_transform (mod->root, &affine);
+
+ // Calculate printable area in device coordinates
+ x0 = pPhysicalOffsetX;
+ y0 = pPhysicalOffsetY;
+ x1 = x0 + pPrintableWidth;
+ y1 = y0 + pPrintableHeight;
+ x1 = MIN (x1, (int) (_PageWidth * scalex));
+ y1 = MIN (y1, (int) (_PageHeight * scaley));
+
+ width = x1 - x0;
+ height = y1 - y0;
+
+ px = nr_new (unsigned char, 4 * 64 * width);
+ sheight = 64;
+
+ /* Printing goes here */
+ for (row = 0; row < height; row += 64) {
+ NRPixBlock pb;
+ NRRectL bbox;
+ NRGC gc(NULL);
+ int num_rows;
+ int i;
+
+ num_rows = sheight;
+ if ((row + num_rows) > height) num_rows = height - row;
+
+ /* Set area of interest */
+ bbox.x0 = x0;
+ bbox.y0 = y0 + row;
+ bbox.x1 = bbox.x0 + width;
+ bbox.y1 = bbox.y0 + num_rows;
+ /* Update to renderable state */
+ nr_matrix_set_identity (&gc.transform);
+ nr_arena_item_invoke_update (mod->root, &bbox, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_NONE);
+
+ nr_pixblock_setup_extern (&pb, NR_PIXBLOCK_MODE_R8G8B8A8N, bbox.x0, bbox.y0, bbox.x1, bbox.y1, px, 4 * (bbox.x1 - bbox.x0), FALSE, FALSE);
+
+ /* Blitter goes here */
+ bmInfo.bmiHeader.biWidth = bbox.x1 - bbox.x0;
+ bmInfo.bmiHeader.biHeight = -(bbox.y1 - bbox.y0);
+
+ memset (px, 0xff, 4 * num_rows * width);
+ /* Render */
+ nr_arena_item_invoke_render (mod->root, &bbox, &pb, 0);
+
+ /* Swap red and blue channels; we use RGBA, whereas
+ * the Win32 GDI uses BGRx.
+ */
+ for ( i = 0 ; i < num_rows * width ; i++ ) {
+ unsigned char temp=px[i*4];
+ px[i*4] = px[i*4+2];
+ px[i*4+2] = temp;
+ }
+
+ SetStretchBltMode(_hDC, COLORONCOLOR);
+ res = StretchDIBits (_hDC,
+ bbox.x0 - x0, bbox.y0 - y0, bbox.x1 - bbox.x0, bbox.y1 - bbox.y0,
+ 0, 0, bbox.x1 - bbox.x0, bbox.y1 - bbox.y0,
+ px,
+ &bmInfo,
+ DIB_RGB_COLORS,
+ SRCCOPY);
+
+ /* Blitter ends here */
+
+ nr_pixblock_release (&pb);
+ }
+
+ nr_free (px);
+
+ res = EndPage (_hDC);
+ res = EndDoc (_hDC);
+
+ SPWin32Modal = FALSE;
+
+ return 0;
+}
+
+/* File dialogs */
+
+char *
+PrintWin32::get_open_filename (unsigned char *dir, unsigned char *filter, unsigned char *title)
+{
+ char fnbuf[4096] = {0};
+ OPENFILENAME ofn = {
+ sizeof (OPENFILENAME),
+ NULL, /* hwndOwner */
+ NULL, /* hInstance */
+ (const CHAR *)filter, /* lpstrFilter */
+ NULL, /* lpstrCustomFilter */
+ 0, /* nMaxCustFilter */
+ 1, /* nFilterIndex */
+ fnbuf, /* lpstrFile */
+ sizeof (fnbuf), /* nMaxFile */
+ NULL, /* lpstrFileTitle */
+ 0, /* nMaxFileTitle */
+ (const CHAR *)dir, /* lpstrInitialDir */
+ (const CHAR *)title, /* lpstrTitle */
+ OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY, /* Flags */
+ 0, /* nFileOffset */
+ 0, /* nFileExtension */
+ NULL, /* lpstrDefExt */
+ 0, /* lCustData */
+ NULL, /* lpfnHook */
+ NULL /* lpTemplateName */
+ };
+ int retval;
+ UINT_PTR timer;
+
+ SPWin32Modal = TRUE;
+ timer = SetTimer (NULL, 0, 40, my_timer);
+
+ retval = GetOpenFileName (&ofn);
+
+ KillTimer (NULL, timer);
+ SPWin32Modal = FALSE;
+
+ if (!retval) {
+ int errcode;
+ errcode = CommDlgExtendedError();
+ return NULL;
+ }
+ return g_strdup (fnbuf);
+}
+
+char *
+PrintWin32::get_write_filename (unsigned char *dir, unsigned char *filter, unsigned char *title)
+{
+ return NULL;
+}
+
+char *
+PrintWin32::get_save_filename (unsigned char *dir, unsigned int *spns)
+{
+ char fnbuf[4096] = {0};
+ OPENFILENAME ofn = {
+ sizeof (OPENFILENAME),
+ NULL, /* hwndOwner */
+ NULL, /* hInstance */
+ "Inkscape SVG (*.svg)\0*\0Plain SVG (*.svg)\0*\0", /* lpstrFilter */
+ NULL, /* lpstrCustomFilter */
+ 0, /* nMaxCustFilter */
+ 1, /* nFilterIndex */
+ fnbuf, /* lpstrFile */
+ sizeof (fnbuf), /* nMaxFile */
+ NULL, /* lpstrFileTitle */
+ 0, /* nMaxFileTitle */
+ (const CHAR *)dir, /* lpstrInitialDir */
+ "Save document to file", /* lpstrTitle */
+ OFN_HIDEREADONLY, /* Flags */
+ 0, /* nFileOffset */
+ 0, /* nFileExtension */
+ NULL, /* lpstrDefExt */
+ 0, /* lCustData */
+ NULL, /* lpfnHook */
+ NULL /* lpTemplateName */
+ };
+ int retval;
+ UINT_PTR timer;
+
+ SPWin32Modal = TRUE;
+ timer = SetTimer (NULL, 0, 40, my_timer);
+
+ retval = GetSaveFileName (&ofn);
+
+ KillTimer (NULL, timer);
+ SPWin32Modal = FALSE;
+
+ if (!retval) {
+ int errcode;
+ errcode = CommDlgExtendedError();
+ return NULL;
+ }
+ *spns = (ofn.nFilterIndex != 2);
+ return g_strdup (fnbuf);
+}
+
+void
+PrintWin32::init (void)
+{
+ Inkscape::Extension::Extension * ext;
+
+ /* SVG in */
+ ext = Inkscape::Extension::build_from_mem(
+ "<inkscape-extension>\n"
+ "<name>Windows 32-bit Print</name>\n"
+ "<id>" SP_MODULE_KEY_PRINT_WIN32 "</id>\n"
+ "<param name=\"textToPath\" type=\"boolean\">TRUE</param>\n"
+ "<print/>\n"
+ "</inkscape-extension>", new PrintWin32());
+
+ return;
+}
+
+} /* namespace Internal */
+} /* namespace Extension */
+} /* namespace Inkscape */
diff --git a/src/extension/internal/win32.h b/src/extension/internal/win32.h
new file mode 100644
index 000000000..d46b5b2fb
--- /dev/null
+++ b/src/extension/internal/win32.h
@@ -0,0 +1,91 @@
+#ifndef __INKSCAPE_EXTENSION_INTERNAL_PRINT_WIN32_H__
+#define __INKSCAPE_EXTENSION_INTERNAL_PRINT_WIN32_H__
+
+/*
+ * Windows stuff
+ *
+ * Author:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ * Ted Gould <ted@gould.cx>
+ *
+ * Lauris: This code is in public domain
+ * Ted: This code is released under the GNU GPL
+ */
+
+#include <config.h>
+
+#ifndef WIN32
+#error "This file is only usable for Windows"
+#endif
+
+#ifdef DATADIR
+#undef DATADIR
+#endif
+#include <windows.h>
+
+#include "extension/extension.h"
+#include "extension/implementation/implementation.h"
+
+namespace Inkscape {
+namespace Extension {
+namespace Internal {
+
+/* Initialization */
+
+class PrintWin32 : public Inkscape::Extension::Implementation::Implementation {
+ /* Document dimensions */
+ float _PageWidth;
+ float _PageHeight;
+
+ HDC _hDC;
+
+ unsigned int _landscape;
+
+ void main_init (int argc, char **argv, const char *name);
+ void finish (void);
+
+ /* File dialogs */
+ char *get_open_filename (unsigned char *dir, unsigned char *filter, unsigned char *title);
+ char *get_write_filename (unsigned char *dir, unsigned char *filter, unsigned char *title);
+ char *get_save_filename (unsigned char *dir, unsigned int *spns);
+
+ VOID CALLBACK timer (HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
+
+
+public:
+ PrintWin32 (void);
+ virtual ~PrintWin32 (void);
+
+ /* Tell modules about me */
+ static void init (void);
+
+ /* Platform detection */
+ static gboolean is_os_wide();
+
+ /* Print functions */
+ virtual unsigned int setup (Inkscape::Extension::Print * module);
+ //virtual unsigned int set_preview (Inkscape::Extension::Print * module);
+
+ virtual unsigned int begin (Inkscape::Extension::Print * module, SPDocument *doc);
+ virtual unsigned int finish (Inkscape::Extension::Print * module);
+
+ /* Rendering methods */
+ /*
+ virtual unsigned int bind (Inkscape::Extension::Print * module, const NRMatrix *transform, float opacity);
+ virtual unsigned int release (Inkscape::Extension::Print * module);
+ virtual unsigned int comment (Inkscape::Extension::Print * module, const char * comment);
+ virtual unsigned int fill (Inkscape::Extension::Print * module, const NRBPath *bpath, const NRMatrix *ctm, const SPStyle *style,
+ const NRRect *pbox, const NRRect *dbox, const NRRect *bbox);
+ virtual unsigned int stroke (Inkscape::Extension::Print * module, const NRBPath *bpath, const NRMatrix *transform, const SPStyle *style,
+ const NRRect *pbox, const NRRect *dbox, const NRRect *bbox);
+ virtual unsigned int image (Inkscape::Extension::Print * module, unsigned char *px, unsigned int w, unsigned int h, unsigned int rs,
+ const NRMatrix *transform, const SPStyle *style);
+ */
+
+};
+
+} /* namespace Internal */
+} /* namespace Extension */
+} /* namespace Inkscape */
+
+#endif /* __INKSCAPE_EXTENSION_INTERNAL_PRINT_WIN32_H__ */