Code

Require a pageBox in the constructor for GfxState so that we do not always need to...
[inkscape.git] / src / extension / internal / pov-out.cpp
index 8e224b4dcad5eedaab80fc5eb39c20f8c1be1908..7318fa78457873bbcaa21388f5cbeb33c333ab6d 100644 (file)
@@ -32,6 +32,7 @@
 
 #include <string>
 #include <stdio.h>
+#include <stdarg.h>
 
 
 namespace Inkscape
@@ -41,7 +42,13 @@ namespace Extension
 namespace Internal
 {
 
-typedef std::string String;
+
+
+
+//########################################################################
+//# U T I L I T Y
+//########################################################################
+
 
 
 /**
@@ -63,30 +70,6 @@ findElementsByTagName(std::vector<Inkscape::XML::Node *> &results,
 }
 
 
-/**
- * used for saving information about shapes
- */
-class PovShapeInfo
-{
-public:
-    PovShapeInfo()
-        {}
-    PovShapeInfo(const PovShapeInfo &other)
-        { assign(other); }
-    PovShapeInfo operator=(const PovShapeInfo &other)
-        { assign(other); return *this; }
-    virtual ~PovShapeInfo()
-        {}
-    String id;
-    String color;
-
-private:
-    void assign(const PovShapeInfo &other)
-        {
-        id    = other.id;
-        color = other.color;
-        }
-};
 
 
 
@@ -104,6 +87,9 @@ effective_opacity(SPItem const *item)
 }
 
 
+
+
+
 //########################################################################
 //# OUTPUT FORMATTING
 //########################################################################
@@ -129,128 +115,174 @@ static const char *dstr(double d)
 
 
 
-static String vec2Str(double a, double b)
+
+
+/**
+ *  Output data to the buffer, printf()-style
+ */
+void PovOutput::out(char *fmt, ...)
 {
-    String str;
-    str.append("<");
-    str.append(dstr(a));
-    str.append(", ");
-    str.append(dstr(b));
-    str.append(">");
-    return str;
+    va_list args;
+    va_start(args, fmt);
+    gchar * output = g_strdup_vprintf(fmt, args);
+    va_end(args);
+    outbuf.append(output);
+    g_free(output);
 }
 
-/*
-static String vec3Str(double a, double b, double c)
+
+
+
+
+
+
+/**
+ *  Output a 3d vector
+ */
+void PovOutput::vec2(double a, double b)
 {
-    String str;
-    str.append("<");
-    str.append(dstr(a));
-    str.append(", ");
-    str.append(dstr(b));
-    str.append(", ");
-    str.append(dstr(c));
-    str.append(">");
-    return str;
+    outbuf.append("<");
+    outbuf.append(dstr(a));
+    outbuf.append(", ");
+    outbuf.append(dstr(b));
+    outbuf.append(">");
 }
-*/
 
-static String vec4Str(double a, double b, double c, double d)
+
+
+/**
+ * Output a 3d vector
+ */
+void PovOutput::vec3(double a, double b, double c)
 {
-    String str;
-    str.append("<");
-    str.append(dstr(a));
-    str.append(", ");
-    str.append(dstr(b));
-    str.append(", ");
-    str.append(dstr(c));
-    str.append(", ");
-    str.append(dstr(d));
-    str.append(">");
-    return str;
+    outbuf.append("<");
+    outbuf.append(dstr(a));
+    outbuf.append(", ");
+    outbuf.append(dstr(b));
+    outbuf.append(", ");
+    outbuf.append(dstr(c));
+    outbuf.append(">");
 }
 
 
-static String formatRgbf(double r, double g, double b, double f)
+
+/**
+ *  Output a v4d ector
+ */
+void PovOutput::vec4(double a, double b, double c, double d)
+{
+    outbuf.append("<");
+    outbuf.append(dstr(a));
+    outbuf.append(", ");
+    outbuf.append(dstr(b));
+    outbuf.append(", ");
+    outbuf.append(dstr(c));
+    outbuf.append(", ");
+    outbuf.append(dstr(d));
+    outbuf.append(">");
+}
+
+
+/**
+ *  Output an rgbf color vector
+ */
+void PovOutput::rgbf(double r, double g, double b, double f)
 {
     //"rgbf < %1.3f, %1.3f, %1.3f %1.3f>"
-    String str;
-    str.append("rgbf ");
-    str.append(vec4Str(r, g, b, f));
-    return str;
+    outbuf.append("rgbf ");
+    vec4(r, g, b, f);
 }
 
-static String formatSeg(int segNr, double a0, double a1,
+
+
+/**
+ *  Output one bezier's start, start-control, end-control, and end nodes
+ */
+void PovOutput::segment(int segNr, double a0, double a1,
                             double b0, double b1,
                             double c0, double c1,
                             double d0, double d1)
 {
     //"    /*%4d*/ <%f, %f>, <%f, %f>, <%f,%f>, <%f,%f>"
-    String str;
     char buf[32];
     snprintf(buf, 31, "    /*%4d*/ ", segNr);
-    str.append(buf);
-    str.append(vec2Str(a0, a1));
-    str.append(", ");
-    str.append(vec2Str(b0, b1));
-    str.append(", ");
-    str.append(vec2Str(c0, c1));
-    str.append(", ");
-    str.append(vec2Str(d0, d1));
-    return str;
+    outbuf.append(buf);
+    vec2(a0, a1);
+    outbuf.append(", ");
+    vec2(b0, b1);
+    outbuf.append(", ");
+    vec2(c0, c1);
+    outbuf.append(", ");
+    vec2(d0, d1);
 }
 
 
 
 
 
+/**
+ * Output the file header
+ */
+void PovOutput::doHeader()
+{
+    time_t tim = time(NULL);
+    out("/*###################################################################\n");
+    out("### This PovRay document was generated by Inkscape\n");
+    out("### http://www.inkscape.org\n");
+    out("### Created: %s", ctime(&tim));
+    out("### Version: %s\n", VERSION);
+    out("#####################################################################\n");
+    out("### NOTES:\n");
+    out("### ============\n");
+    out("### POVRay information can be found at\n");
+    out("### http://www.povray.org\n");
+    out("###\n");
+    out("### The 'AllShapes' objects at the bottom are provided as a\n");
+    out("### preview of how the output would look in a trace.  However,\n");
+    out("### the main intent of this file is to provide the individual\n");
+    out("### shapes for inclusion in a POV project.\n");
+    out("###\n");
+    out("### For an example of how to use this file, look at\n");
+    out("### share/examples/istest.pov\n");
+    out("###################################################################*/\n");
+    out("\n\n");
+    out("/*###################################################################\n");
+    out("##   Exports in this file\n");
+    out("##==========================\n");
+    out("##    Shapes   : %d\n", nrShapes);
+    out("##    Segments : %d\n", nrSegments);
+    out("##    Nodes    : %d\n", nrNodes);
+    out("###################################################################*/\n");
+    out("\n\n\n");
+}
 
-//########################################################################
-//# M A I N    O U T P U T
-//########################################################################
 
 
 /**
- * Saves the <paths> of an Inkscape SVG file as PovRay spline definitions
-*/
-void
-PovOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *uri)
+ *  Output the file footer
+ */
+void PovOutput::doTail()
+{
+    out("\n\n");
+    out("/*###################################################################\n");
+    out("### E N D    F I L E\n");
+    out("###################################################################*/\n");
+    out("\n\n");
+}
+
+
+
+/**
+ *  Output the curve data to buffer
+ */
+void PovOutput::doCurves(SPDocument *doc)
 {
     std::vector<Inkscape::XML::Node *>results;
     //findElementsByTagName(results, SP_ACTIVE_DOCUMENT->rroot, "path");
-    findElementsByTagName(results, SP_ACTIVE_DOCUMENT->rroot, NULL);//Check all nodes
+    findElementsByTagName(results, SP_ACTIVE_DOCUMENT->rroot, NULL);
     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, "### Version: %s\n", VERSION);
-    fprintf(f, "#####################################################################\n");
-    fprintf(f, "### NOTES:\n");
-    fprintf(f, "### ============\n");
-    fprintf(f, "### POVRay information can be found at\n");
-    fprintf(f, "### http://www.povray.org\n");
-    fprintf(f, "###\n");
-    fprintf(f, "### The 'AllShapes' objects at the bottom are provided as a\n");
-    fprintf(f, "### preview of how the output would look in a trace.  However,\n");
-    fprintf(f, "### the main intent of this file is to provide the individual\n");
-    fprintf(f, "### shapes for inclusion in a POV project.\n");
-    fprintf(f, "###\n");
-    fprintf(f, "### For an example of how to use this file, look at\n");
-    fprintf(f, "### share/examples/istest.pov\n");
-    fprintf(f, "####################################################################*/\n\n\n");
-
-    //A list for saving information about the shapes
-    std::vector<PovShapeInfo>povShapes;
-
     double bignum = 1000000.0;
     double minx  =  bignum;
     double maxx  = -bignum;
@@ -285,6 +317,8 @@ PovOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *
         SPCurve *curve = shape->curve;
         if (sp_curve_empty(curve))
             continue;
+            
+        nrShapes++;
 
         PovShapeInfo shapeInfo;
         shapeInfo.id    = id;
@@ -303,7 +337,12 @@ PovOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *
                                       * 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);
-            shapeInfo.color += formatRgbf(rgb[0], rgb[1], rgb[2], 1.0 - dopacity);
+            String rgbf = "rgbf <";
+            rgbf.append(dstr(rgb[0]));         rgbf.append(", ");
+            rgbf.append(dstr(rgb[1]));         rgbf.append(", ");
+            rgbf.append(dstr(rgb[2]));         rgbf.append(", ");
+            rgbf.append(dstr(1.0 - dopacity)); rgbf.append(">");
+            shapeInfo.color += rgbf;
             }
 
         povShapes.push_back(shapeInfo); //passed all tests.  save the info
@@ -324,17 +363,20 @@ PovOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *
         double lastx  = 0.0;
         double lasty  = 0.0;
 
-        fprintf(f, "/*###################################################\n");
-        fprintf(f, "### PRISM:  %s\n", id.c_str());
-        fprintf(f, "###################################################*/\n");
-        fprintf(f, "#declare %s = prism {\n", id.c_str());
-        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);
+        out("/*###################################################\n");
+        out("### PRISM:  %s\n", id.c_str());
+        out("###################################################*/\n");
+        out("#declare %s = prism {\n", id.c_str());
+        out("    linear_sweep\n");
+        out("    bezier_spline\n");
+        out("    1.0, //top\n");
+        out("    0.0, //bottom\n");
+        out("    %d //nr points\n", segmentCount * 4);
         int segmentNr = 0;
         bp = SP_CURVE_BPATH(curve);
+        
+        nrSegments += curveLength;
+
         for (int curveNr=0 ; curveNr < curveLength ; curveNr++)
             {
             using NR::X;
@@ -358,14 +400,14 @@ PovOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *
                     {
                     //fprintf(f, "    /*%4d*/ <%f, %f>, <%f, %f>, <%f,%f>, <%f,%f>",
                     //        segmentNr++, lastx, lasty, x1, y1, x2, y2, x3, y3);
-                    String seg = formatSeg(segmentNr++,
-                               lastx, lasty, x1, y1, x2, y2, x3, y3);
-                    fprintf(f, "%s", seg.c_str());
+                    segment(segmentNr++,
+                          lastx, lasty, x1, y1, x2, y2, x3, y3);
+                    nrNodes += 8;
 
                     if (segmentNr < segmentCount)
-                        fprintf(f, ",\n");
+                        out(",\n");
                     else
-                        fprintf(f, "\n");
+                        out("\n");
 
                     if (lastx < cminx)
                         cminx = lastx;
@@ -381,14 +423,14 @@ PovOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *
                     {
                     //fprintf(f, "    /*%4d*/ <%f, %f>, <%f, %f>, <%f,%f>, <%f,%f>",
                     //        segmentNr++, lastx, lasty, lastx, lasty, x3, y3, x3, y3);
-                    String seg = formatSeg(segmentNr++,
-                               lastx, lasty, lastx, lasty, x3, y3, x3, y3);
-                    fprintf(f, "%s", seg.c_str());
+                    segment(segmentNr++,
+                         lastx, lasty, lastx, lasty, x3, y3, x3, y3);
+                    nrNodes += 8;
 
                     if (segmentNr < segmentCount)
-                        fprintf(f, ",\n");
+                        out(",\n");
                     else
-                        fprintf(f, "\n");
+                        out("\n");
 
                     //fprintf(f, "lineto\n");
                     if (lastx < cminx)
@@ -411,25 +453,25 @@ PovOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *
             lasty = y3;
             bp++;
             }
-        fprintf(f, "}\n");
+        out("}\n");
 
 
            char *pfx = (char *)id.c_str();
 
-        fprintf(f, "#declare %s_MIN_X    = %s;\n", pfx, dstr(cminx));
-        fprintf(f, "#declare %s_CENTER_X = %s;\n", pfx, dstr((cmaxx+cminx)/2.0));
-        fprintf(f, "#declare %s_MAX_X    = %s;\n", pfx, dstr(cmaxx));
-        fprintf(f, "#declare %s_WIDTH    = %s;\n", pfx, dstr(cmaxx-cminx));
-        fprintf(f, "#declare %s_MIN_Y    = %s;\n", pfx, dstr(cminy));
-        fprintf(f, "#declare %s_CENTER_Y = %s;\n", pfx, dstr((cmaxy+cminy)/2.0));
-        fprintf(f, "#declare %s_MAX_Y    = %s;\n", pfx, dstr(cmaxy));
-        fprintf(f, "#declare %s_HEIGHT   = %s;\n", pfx, dstr(cmaxy-cminy));
+        out("#declare %s_MIN_X    = %s;\n", pfx, dstr(cminx));
+        out("#declare %s_CENTER_X = %s;\n", pfx, dstr((cmaxx+cminx)/2.0));
+        out("#declare %s_MAX_X    = %s;\n", pfx, dstr(cmaxx));
+        out("#declare %s_WIDTH    = %s;\n", pfx, dstr(cmaxx-cminx));
+        out("#declare %s_MIN_Y    = %s;\n", pfx, dstr(cminy));
+        out("#declare %s_CENTER_Y = %s;\n", pfx, dstr((cmaxy+cminy)/2.0));
+        out("#declare %s_MAX_Y    = %s;\n", pfx, dstr(cmaxy));
+        out("#declare %s_HEIGHT   = %s;\n", pfx, dstr(cmaxy-cminy));
         if (shapeInfo.color.length()>0)
-            fprintf(f, "#declare %s_COLOR    = %s;\n",
+            out("#declare %s_COLOR    = %s;\n",
                     pfx, shapeInfo.color.c_str());
-        fprintf(f, "/*###################################################\n");
-        fprintf(f, "### end %s\n", id.c_str());
-        fprintf(f, "###################################################*/\n\n\n\n");
+        out("/*###################################################\n");
+        out("### end %s\n", id.c_str());
+        out("###################################################*/\n\n\n\n");
         if (cminx < minx)
             minx = cminx;
         if (cmaxx > maxx)
@@ -448,84 +490,143 @@ PovOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *
         {
         String id = "AllShapes";
         char *pfx = (char *)id.c_str();
-        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", pfx);
-        fprintf(f, "#declare %s_Finish = finish {\n", pfx);
-        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.c_str());
+        out("/*###################################################\n");
+        out("### UNION OF ALL SHAPES IN DOCUMENT\n");
+        out("###################################################*/\n");
+        out("\n\n");
+        out("/**\n");
+        out(" * Allow the user to redefine the finish{}\n");
+        out(" * by declaring it before #including this file\n");
+        out(" */\n");
+        out("#ifndef (%s_Finish)\n", pfx);
+        out("#declare %s_Finish = finish {\n", pfx);
+        out("    phong 0.5\n");
+        out("    reflection 0.3\n");
+        out("    specular 0.5\n");
+        out("}\n");
+        out("#end\n");
+        out("\n\n");
+        out("#declare %s = union {\n", id.c_str());
         for (unsigned i = 0 ; i < povShapes.size() ; i++)
             {
-            fprintf(f, "    object { %s\n", povShapes[i].id.c_str());
-            fprintf(f, "        texture { \n");
+            out("    object { %s\n", povShapes[i].id.c_str());
+            out("        texture { \n");
             if (povShapes[i].color.length()>0)
-                fprintf(f, "            pigment { %s }\n", povShapes[i].color.c_str());
+                out("            pigment { %s }\n", povShapes[i].color.c_str());
             else
-                fprintf(f, "            pigment { rgb <0,0,0> }\n");
-            fprintf(f, "            finish { %s_Finish }\n", pfx);
-            fprintf(f, "            } \n");
-            fprintf(f, "        } \n");
+                out("            pigment { rgb <0,0,0> }\n");
+            out("            finish { %s_Finish }\n", pfx);
+            out("            } \n");
+            out("        } \n");
             }
-        fprintf(f, "}\n\n\n\n");
+        out("}\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(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", pfx);
+        out("/*#### Same union, but with Z-diffs (actually Y in pov) ####*/\n");
+        out("\n\n");
+        out("/**\n");
+        out(" * Allow the user to redefine the Z-Increment\n");
+        out(" */\n");
+        out("#ifndef (AllShapes_Z_Increment)\n");
+        out("#declare AllShapes_Z_Increment = %s;\n", dstr(zinc));
+        out("#end\n");
+        out("\n");
+        out("#declare AllShapes_Z_Scale = 1.0;\n");
+        out("\n\n");
+        out("#declare %s_Z = union {\n", pfx);
 
         for (unsigned i = 0 ; i < povShapes.size() ; i++)
             {
-            fprintf(f, "    object { %s\n", povShapes[i].id.c_str());
-            fprintf(f, "        texture { \n");
+            out("    object { %s\n", povShapes[i].id.c_str());
+            out("        texture { \n");
             if (povShapes[i].color.length()>0)
-                fprintf(f, "            pigment { %s }\n", povShapes[i].color.c_str());
+                out("            pigment { %s }\n", povShapes[i].color.c_str());
             else
-                fprintf(f, "            pigment { rgb <0,0,0> }\n");
-            fprintf(f, "            finish { %s_Finish }\n", pfx);
-            fprintf(f, "            } \n");
-            fprintf(f, "        scale <1, %s_Z_Scale, 1>\n", pfx);
-            fprintf(f, "        } \n");
-            fprintf(f, "#declare %s_Z_Scale = %s_Z_Scale + %s_Z_Increment;\n\n",
+                out("            pigment { rgb <0,0,0> }\n");
+            out("            finish { %s_Finish }\n", pfx);
+            out("            } \n");
+            out("        scale <1, %s_Z_Scale, 1>\n", pfx);
+            out("        } \n");
+            out("#declare %s_Z_Scale = %s_Z_Scale + %s_Z_Increment;\n\n",
                     pfx, pfx, pfx);
             }
 
-        fprintf(f, "}\n");
-
-        fprintf(f, "#declare %s_MIN_X    = %s;\n", pfx, dstr(minx));
-        fprintf(f, "#declare %s_CENTER_X = %s;\n", pfx, dstr((maxx+minx)/2.0));
-        fprintf(f, "#declare %s_MAX_X    = %s;\n", pfx, dstr(maxx));
-        fprintf(f, "#declare %s_WIDTH    = %s;\n", pfx, dstr(maxx-minx));
-        fprintf(f, "#declare %s_MIN_Y    = %s;\n", pfx, dstr(miny));
-        fprintf(f, "#declare %s_CENTER_Y = %s;\n", pfx, dstr((maxy+miny)/2.0));
-        fprintf(f, "#declare %s_MAX_Y    = %s;\n", pfx, dstr(maxy));
-        fprintf(f, "#declare %s_HEIGHT   = %s;\n", pfx, dstr(maxy-miny));
-        fprintf(f, "/*##############################################\n");
-        fprintf(f, "### end %s\n", id.c_str());
-        fprintf(f, "##############################################*/\n\n\n\n");
+        out("}\n");
+
+        out("#declare %s_MIN_X    = %s;\n", pfx, dstr(minx));
+        out("#declare %s_CENTER_X = %s;\n", pfx, dstr((maxx+minx)/2.0));
+        out("#declare %s_MAX_X    = %s;\n", pfx, dstr(maxx));
+        out("#declare %s_WIDTH    = %s;\n", pfx, dstr(maxx-minx));
+        out("#declare %s_MIN_Y    = %s;\n", pfx, dstr(miny));
+        out("#declare %s_CENTER_Y = %s;\n", pfx, dstr((maxy+miny)/2.0));
+        out("#declare %s_MAX_Y    = %s;\n", pfx, dstr(maxy));
+        out("#declare %s_HEIGHT   = %s;\n", pfx, dstr(maxy-miny));
+        out("/*##############################################\n");
+        out("### end %s\n", id.c_str());
+        out("##############################################*/\n");
+        out("\n\n");
         }
 
-    //All done
+}
+
+
+
+
+//########################################################################
+//# M A I N    O U T P U T
+//########################################################################
+
+
+
+/**
+ *  Set values back to initial state
+ */
+void PovOutput::reset()
+{
+    nrNodes    = 0;
+    nrSegments = 0;
+    nrShapes   = 0;
+    outbuf.clear();
+    povShapes.clear();
+}
+
+
+
+/**
+ * Saves the <paths> of an Inkscape SVG file as PovRay spline definitions
+ */
+void PovOutput::saveDocument(SPDocument *doc, gchar const *uri)
+{
+    reset();
+
+    //###### SAVE IN POV FORMAT TO BUFFER
+    //# Lets do the curves first, to get the stats
+    doCurves(doc);
+    String curveBuf = outbuf;
+    outbuf.clear();
+
+    doHeader();
+    
+    outbuf.append(curveBuf);
+    
+    doTail();
+
+
+
+
+    //###### WRITE TO FILE
+    Inkscape::IO::dump_fopen_call(uri, "L");
+    FILE *f = Inkscape::IO::fopen_utf8name(uri, "w");
+    if (!f)
+        return;
+
+    for (String::iterator iter = outbuf.begin() ; iter!=outbuf.end(); iter++)
+        {
+        int ch = *iter;
+        fputc(ch, f);
+        }
+        
     fclose(f);
 }
 
@@ -542,6 +643,18 @@ PovOutput::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *
 
 
 
+/**
+ * API call to save document
+*/
+void
+PovOutput::save(Inkscape::Extension::Output *mod,
+                        SPDocument *doc, gchar const *uri)
+{
+    saveDocument(doc, uri);
+}
+
+
+
 /**
  * Make sure that we are in the database
  */
@@ -583,9 +696,9 @@ PovOutput::init()
 
 
 
-}  //namespace Internal
-}  //namespace Extension
-}  //namespace Inkscape
+}  // namespace Internal
+}  // namespace Extension
+}  // namespace Inkscape
 
 
 /*