diff options
| author | MenTaLguY <mental@rydia.net> | 2006-01-16 02:36:01 +0000 |
|---|---|---|
| committer | mental <mental@users.sourceforge.net> | 2006-01-16 02:36:01 +0000 |
| commit | 179fa413b047bede6e32109e2ce82437c5fb8d34 (patch) | |
| tree | a5a6ac2c1708bd02288fbd8edb2ff500ff2e0916 /src/extension/internal | |
| download | inkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.tar.gz inkscape-179fa413b047bede6e32109e2ce82437c5fb8d34.zip | |
moving trunk for module inkscape
(bzr r1)
Diffstat (limited to 'src/extension/internal')
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__ */ |
